[6.2.6][技术优化] 将卡顿日志转成在链路日志中存储

This commit is contained in:
renwj
2023-12-22 17:42:33 +08:00
parent 5256f4597f
commit acdcde8caf
5 changed files with 41 additions and 217 deletions

View File

@@ -5,11 +5,12 @@ import android.os.SystemClock;
import com.google.auto.service.AutoService;
import com.mogo.core.lancetx.compiler.lib.generator.Type;
import com.mogo.core.lancetx.compiler.lib.hook.IHookInvoker;
import com.mogo.eagle.core.data.deva.chain.ChainConstant;
import com.mogo.eagle.core.function.api.devatools.block.IMoGoBlockProvider;
import com.mogo.eagle.core.function.api.devatools.perf.IMoGoCpuUsageProvider;
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager;
import com.mogo.eagle.core.function.main.ARouterUtils;
import com.mogo.eagle.core.utilcode.util.VLogUtils;
import com.zhjt.service.chain.ChainLog;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
@@ -170,8 +171,8 @@ public class HookInvokerImpl implements IHookInvoker {
String s = builder.toString();
VLogUtils.w("HookHandler", "Junk Detected:" + builder, 4096);
// linkedLog(type, builder.toString());
//VLogUtils.w("HookHandler", "Junk Detected:" + builder, 4096);
linkedLog(type, builder.toString());
if (flag) {
extra.setLength(0);
}
@@ -248,7 +249,7 @@ public class HookInvokerImpl implements IHookInvoker {
}
if (holder != null) {
if (sb.length() > 0) {
sb.append("##holder::").append(holder);
sb.append("##holder::").append(holder.getName());
} else {
sb.append("holder::").append(holder);
}
@@ -287,19 +288,19 @@ public class HookInvokerImpl implements IHookInvoker {
}
}
// private void linkedLog(Type type, String msg) {
// try {
// linkedLogInternal(type,msg);
// } catch (Throwable t) {
// t.printStackTrace();
// }
// }
//
// @ChainLog(
// linkChainLog = ChainConstant.CHAIN_TYPE_ANR_LEAK,
// linkCode = ChainConstant.CHAIN_SOURCE_HMI,
// nodeAliasCode = ChainConstant.CHAIN_CODE_MAIN_BLOCK,
// paramIndexes = { 0, 1 }
// )
// private void linkedLogInternal(Type type, String msg) {}
private void linkedLog(Type type, String msg) {
try {
linkedLogInternal(type,msg);
} catch (Throwable t) {
t.printStackTrace();
}
}
@ChainLog(
linkChainLog = ChainConstant.CHAIN_TYPE_ANR_LEAK,
linkCode = ChainConstant.CHAIN_SOURCE_HMI,
nodeAliasCode = ChainConstant.CHAIN_CODE_MAIN_BLOCK,
paramIndexes = { 0, 1 }
)
private void linkedLogInternal(Type type, String msg) {}
}

View File

@@ -9,40 +9,21 @@ import com.knightboost.lancet.api.annotations.TargetClass
import com.knightboost.lancet.api.annotations.TargetMethod
import com.knightboost.lancet.api.annotations.Weaver
import com.mogo.eagle.core.block.runtime.message.Message
import com.mogo.eagle.core.block.runtime.utils.TimeUtils.Companion.now
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
import java.util.concurrent.ConcurrentHashMap
@Weaver
@Group("main_block_check")
class UiPostLancet {
internal data class ActionWrapper(var action: Runnable): Runnable {
override fun run() {
val start = now()
try {
action.run()
} finally {
CallerDevaToolsManager.block()?.takeIf {
it.hasInit()
}?.recorder()?.recycle(Message.acquire(handler = null, action = action, duration = now() - start))
}
}
}
companion object {
private val map by lazy { ConcurrentHashMap<Runnable, ActionWrapper>() }
@JvmStatic
@TargetClass(value = "android.app.Activity", scope = Scope.ALL)
@TargetMethod(methodName = "runOnUiThread")
@ReplaceInvoke
fun runOnUiThreadOfActivity(activity: Activity, action: Runnable) {
try {
activity.runOnUiThread(ActionWrapper(action).also { map[action] = it })
activity.runOnUiThread(action)
} finally {
CallerDevaToolsManager.block()?.takeIf {
it.hasInit()
@@ -55,22 +36,8 @@ class UiPostLancet {
@TargetMethod(methodName = "post")
@ReplaceInvoke
fun post(view: View, action: Runnable): Boolean {
return try {
view.post(ActionWrapper(action).also { map[action] = it })
} finally {
CallerDevaToolsManager.block()?.takeIf {
it.hasInit()
}?.recorder()?.insert(Message.acquire(handler = null, action = action, extra = mapOf(view.javaClass.name to "post")))
}
}
@JvmStatic
@TargetClass(value = "android.view.View", scope = Scope.ALL)
@TargetMethod(methodName = "postDelayed")
@ReplaceInvoke
fun postDelayed(view: View, action: Runnable, delayMillis: Long): Boolean {
return try {
view.postDelayed(ActionWrapper(action).also { map[action] = it }, delayMillis)
view.post(action)
} finally {
CallerDevaToolsManager.block()?.takeIf {
it.hasInit()
@@ -78,20 +45,32 @@ class UiPostLancet {
}
}
@JvmStatic
@TargetClass(value = "android.view.View", scope = Scope.ALL)
@TargetMethod(methodName = "postDelayed")
@ReplaceInvoke
fun postDelayed(view: View, action: Runnable, delayMillis: Long): Boolean {
return try {
view.postDelayed(action, delayMillis)
} finally {
CallerDevaToolsManager.block()?.takeIf {
it.hasInit()
}?.recorder()?.insert(Message.acquire(handler = null, action = action, delay = delayMillis, extra = mapOf(view.javaClass.name to "postDelayed")))
}
}
@JvmStatic
@TargetClass(value = "android.view.View", scope = Scope.ALL)
@TargetMethod(methodName = "removeCallbacks")
@ReplaceInvoke
fun removeCallbacks(view: View, action: Runnable): Boolean {
return try {
view.removeCallbacks(map.remove(action))
view.removeCallbacks(action)
} finally {
CallerDevaToolsManager.block()?.takeIf {
it.hasInit()
}?.recorder()?.remove(Message.acquire(handler = null, action = action, extra = mapOf(view.javaClass.name to "removeCallbacks")))
}
}
}
}

View File

@@ -1,142 +0,0 @@
package com.mogo.launcher.lancet
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.view.View
import androidx.annotation.*
import androidx.core.view.ViewCompat
import androidx.fragment.app.*
import androidx.lifecycle.*
import androidx.lifecycle.Lifecycle.Event
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import com.knightboost.lancet.api.*
import com.knightboost.lancet.api.Scope.LEAF
import com.knightboost.lancet.api.annotations.*
import com.knightboost.lancet.api.annotations.Weaver
import com.mogo.eagle.core.utilcode.kotlin.*
import io.netty.util.internal.ConcurrentSet
import java.lang.ref.*
import java.lang.reflect.Modifier
import java.util.concurrent.ConcurrentHashMap
@Keep
@Weaver
@Group("memory_leak")
class MemoryLeakFix {
@NameRegex("(com\\.zhidao|com\\.elegant|com\\.zhidaoauto|com\\.zhjt|com\\.mogo(?!(\\.thread\\.ext|\\.launcher\\.lancet))).*")
@Insert(mayCreateSuper = true)
@ImplementedInterface("java.lang.Runnable", scope = LEAF)
@TargetMethod(methodName = "run")
fun runProxy() {
if (AccessSyntheticUtils.isTargetAlive(This.get())) {
Origin.callVoid()
}
}
}
internal class AccessSyntheticUtils {
companion object {
private val fields = ConcurrentHashMap<String, WeakReference<Any>>()
private val observers = ConcurrentSet<String>()
// true: 代表要执行原来的run方法体
// false: 代表不执行原来的run方法体
@JvmStatic
fun isTargetAlive(obj: Any): Boolean {
try {
val clazz = obj.javaClass
if (!clazz.isAnonymousClass) {
return true
}
val key = clazz.name
return (fields[key] ?: clazz.declaredFields.find {
it.isSynthetic &&
((it.modifiers and Modifier.STATIC) == 0) &&
(View::class.java.isAssignableFrom(it.type) or
Context::class.java.isAssignableFrom(it.type) or
Fragment::class.java.isAssignableFrom(it.type) or
android.app.Fragment::class.java.isAssignableFrom(it.type) or
Dialog::class.java.isAssignableFrom(it.type)
)
}?.let {
it.isAccessible = true
val wf = WeakReference(it.get(obj), ReferenceQueue())
fields[key] = wf
wf
})?.also {
if (it.isEnqueued) {
//对像被垃圾回收了
fields.remove(key)
}
}?.get()?.let { t ->
var lifecycle: Lifecycle? = null
val ret = when (t) {
is View -> {
lifecycle = t.lifecycleOwner.lifecycle
t.parent == null || ViewCompat.isAttachedToWindow(t)
}
is Activity -> {
lifecycle = t.findViewById<View>(android.R.id.content)?.lifecycleOwner?.lifecycle
!t.isFinishing && !t.isDestroyed
}
is Fragment -> {
lifecycle = t.lifecycle
!t.isDetached
}
is android.app.Fragment -> {
lifecycle = t.view?.lifecycleOwner?.lifecycle
!t.isDetached
}
is Dialog -> {
t.window?.decorView?.let {
v ->
lifecycle = v.lifecycleOwner.lifecycle
ViewCompat.isAttachedToWindow(v)
} ?: false
}
else -> {
true
}
}
if (!ret) {
assignFinalFieldNull(obj, t.javaClass)
} else {
val l = lifecycle
if (l != null && !observers.contains(key)) {
observers.add(key)
l.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Event) {
if (event == ON_DESTROY) {
assignFinalFieldNull(obj, t.javaClass)
observers.remove(key)
}
}
})
}
}
ret
} ?: true
} catch (ignore: Throwable) { }
return true
}
@JvmStatic
private fun assignFinalFieldNull(obj: Any, fieldType: Class<*>) {
try {
obj.javaClass.declaredFields.find {
it.isSynthetic &&
((it.modifiers and Modifier.STATIC) == 0) && it.type == fieldType
}?.also {
it.isAccessible = true
it.set(obj, null)
}
} catch (t: Throwable) {
t.printStackTrace()
}
}
}
}

View File

@@ -13,27 +13,22 @@ import com.mogo.eagle.core.block.runtime.report.*
import com.mogo.eagle.core.function.api.devatools.block.*
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
import com.mogo.eagle.core.utilcode.util.GsonUtils
import com.mogo.eagle.core.utilcode.util.VLogUtils
import java.util.concurrent.TimeUnit.SECONDS
internal class MoGoBlockProviderImpl: IMoGoBlockProvider, IBlockListener {
companion object {
private const val TAG = "BLOCK_REPORT"
}
@Volatile
private var hasInit = false
// private val linkedLog by lazy { MainBlockLinkedLog() }
private val linkedLog by lazy { MainBlockLinkedLog() }
override fun init(ctx: Context) {
BlockDetector.init(BlockMetrics.Builder()
.context(ctx)
.multiplier(1.2f)
.multiplier(2.0f)
.isDebug(false)
.period(5, SECONDS)
.junkRateThreshold(0.2f)
.junkRateThreshold(0.6f)
.recorder(null, 500, 500)
.build())
hasInit = true
@@ -69,12 +64,7 @@ internal class MoGoBlockProviderImpl: IMoGoBlockProvider, IBlockListener {
}
}
}
val msg = GsonUtils.toJson(map)
try {
VLogUtils.w(TAG, msg)
} catch (t: Throwable) {
Log.e(TAG, "onDumped error", t)
}
linkedLog.record(GsonUtils.toJson(map))
}
})
}

View File

@@ -14,13 +14,9 @@ LancetX {
]
}
weaveGroup {
crash_fix {
enable true
}
memory_leak {
enable true
}
textview_opt {
enable true
}