[3.4.0][Block] 主线程卡顿检测
This commit is contained in:
@@ -8,9 +8,10 @@
|
||||
-keeppackage com/elegant/log/
|
||||
-keeppackage org/slf4j/
|
||||
-keeppackage kotlin/
|
||||
-keeppackage androidx/
|
||||
-keepclass com.mogo.eagle.core.function.main.MainMoGoApplication
|
||||
-keepclass com.mogo.commons.AbsMogoApplication
|
||||
-keepclass com.bytedance.apm.agent.v2.instrumentation.AppAgent
|
||||
-keepclass androidx.core.app.CoreComponentFactory
|
||||
# -keepclass androidx.core.app.CoreComponentFactory
|
||||
-keepclass com.mogo.eagle.core.utilcode.util.ProcessUtils
|
||||
-keepclass com.mogo.eagle.core.utilcode.mogo.AppLaunchTimeUtils
|
||||
@@ -27,6 +27,8 @@ class CrashFix {
|
||||
@TargetMethod(methodName = "startService")
|
||||
@ReplaceInvoke
|
||||
fun fixStartServiceCrash(context: Context, intent: Intent): ComponentName? {
|
||||
|
||||
|
||||
return try {
|
||||
context.startService(intent)
|
||||
} catch (t: Throwable) {
|
||||
|
||||
574
app/src/main/java/com/mogo/launcher/lancet/MainBlockCheck.kt
Normal file
574
app/src/main/java/com/mogo/launcher/lancet/MainBlockCheck.kt
Normal file
@@ -0,0 +1,574 @@
|
||||
package com.mogo.launcher.lancet
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Canvas
|
||||
import android.os.*
|
||||
import android.util.*
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.*
|
||||
import androidx.collection.ArrayMap
|
||||
import com.knightboost.lancet.api.*
|
||||
import com.knightboost.lancet.api.Scope.ALL
|
||||
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.block.runtime.config.recorder.*
|
||||
import com.mogo.eagle.core.block.runtime.utils.TimeUtils.Companion.now
|
||||
import com.mogo.eagle.core.function.call.devatools.*
|
||||
import com.mogo.eagle.core.utilcode.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Runnable
|
||||
import java.util.LinkedList
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import com.mogo.eagle.core.block.runtime.message.Message as Holder
|
||||
|
||||
@Keep
|
||||
@Weaver
|
||||
@Group("main_block_check")
|
||||
class MainBlockCheck {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
val tokens = ArrayMap<Any, Holder>(128)
|
||||
|
||||
@JvmStatic
|
||||
val whats by lazy { ConcurrentHashMap<Int, LinkedList<Holder>>() }
|
||||
|
||||
@JvmStatic
|
||||
fun getRecorder(): IMessageRecorder? {
|
||||
val block = CallerDevaToolsManager.block()
|
||||
if (block == null || !block.hasInit()) {
|
||||
return null
|
||||
}
|
||||
return block.recorder()
|
||||
}
|
||||
|
||||
@JvmStatic val HANDLER by lazy {
|
||||
Handler(Looper.getMainLooper()) { msg ->
|
||||
val enclose = msg.obj as? Holder ?: throw AssertionError()
|
||||
enclose.what?.also {
|
||||
whats[it]?.remove(enclose)
|
||||
}
|
||||
val h = enclose.handler
|
||||
val action = enclose.action
|
||||
val oldMsg = enclose.origin
|
||||
val oldObj = enclose.obj
|
||||
val now = now()
|
||||
if (enclose.enqueueTime <= 0) {
|
||||
throw AssertionError("illegal: $enclose")
|
||||
}
|
||||
val elapsedTime = now - enclose.enqueueTime
|
||||
try {
|
||||
if (action != null) {
|
||||
action.run()
|
||||
} else {
|
||||
if (oldMsg == null) {
|
||||
h?.dispatchMessage(msg)
|
||||
} else {
|
||||
oldMsg.obj = oldObj
|
||||
h?.dispatchMessage(oldMsg)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
val duration = now() - now
|
||||
getRecorder()?.recycle(enclose.id, elapsedTime, duration)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "post")
|
||||
@ReplaceInvoke
|
||||
fun handlerPostProxy(handler: Handler, action: Runnable): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.post(action)
|
||||
}
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
val msg = Message.obtain(handler, action)
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(handler, action = action, what = what)
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessage(msg)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(holder)
|
||||
whats.getOrPut(what) { LinkedList() }.add(holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendEmptyMessage")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendEmptyMessage(handler: Handler, what: Int): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendEmptyMessage(what)
|
||||
}
|
||||
val msg = Message.obtain(handler, what)
|
||||
val holder = Holder.acquire(handler, what = what)
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessage(msg)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(holder)
|
||||
whats.getOrPut(what) { LinkedList() }.add(holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendEmptyMessageAtTime")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendEmptyMessageAtTime(handler: Handler, what: Int, uptimeMillis: Long): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendEmptyMessageAtTime(what, uptimeMillis)
|
||||
}
|
||||
val msg = Message.obtain(handler, what)
|
||||
val holder = Holder.acquire(handler, what = what, delay = uptimeMillis - SystemClock.uptimeMillis())
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessageAtTime(msg, uptimeMillis)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(holder)
|
||||
whats.getOrPut(what) { LinkedList() }.add(holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendEmptyMessageDelayed")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendEmptyMessageDelayed(handler: Handler, what: Int, delayMillis: Long): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendEmptyMessageDelayed(what, delayMillis)
|
||||
}
|
||||
val msg = Message.obtain(handler, what)
|
||||
val holder = Holder.acquire(handler, what = what, delay = delayMillis)
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessageDelayed(msg, delayMillis)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(holder)
|
||||
whats.getOrPut(what) { LinkedList() }.add(holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendMessage")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendMessage(handler: Handler, msg: Message): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendMessage(msg)
|
||||
}
|
||||
val obj: Holder = Holder.acquire(handler, msg, obj = msg.obj, what = msg.what)
|
||||
val oldObj = msg.obj
|
||||
msg.obj = obj
|
||||
if (oldObj != null) {
|
||||
synchronized(tokens) {
|
||||
tokens[oldObj] = obj
|
||||
}
|
||||
}
|
||||
val inserted = HANDLER.sendMessage(msg)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(obj)
|
||||
whats.getOrPut(msg.what) { LinkedList() }.add(obj)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendMessageAtTime")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendMessageAtTime(handler: Handler, msg: Message, uptimeMillis: Long): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendMessageAtTime(msg, uptimeMillis)
|
||||
}
|
||||
val obj= Holder.acquire(handler, msg, obj = msg.obj, what = msg.what, delay = uptimeMillis - SystemClock.uptimeMillis())
|
||||
val oldObj = msg.obj
|
||||
msg.obj = obj
|
||||
if (oldObj != null) {
|
||||
synchronized(tokens) {
|
||||
tokens[oldObj] = obj
|
||||
}
|
||||
}
|
||||
val inserted = HANDLER.sendMessageAtTime(msg, uptimeMillis)
|
||||
if (inserted) {
|
||||
whats.getOrPut(msg.what) { LinkedList() }.add(obj)
|
||||
getRecorder()?.insert(obj)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendMessageAtFrontOfQueue")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendMessageAtFrontOfQueue(handler: Handler, msg: Message): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendMessageAtFrontOfQueue(msg)
|
||||
}
|
||||
val obj = Holder.acquire(handler, msg, obj = msg.obj, what = msg.what)
|
||||
val old = msg.obj
|
||||
msg.obj = obj
|
||||
if (old != null) {
|
||||
synchronized(tokens) {
|
||||
tokens[old] = obj
|
||||
}
|
||||
}
|
||||
val inserted = HANDLER.sendMessageAtFrontOfQueue(msg)
|
||||
if (inserted) {
|
||||
whats.getOrPut(msg.what) { LinkedList() }.add(obj)
|
||||
getRecorder()?.insert(obj)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "postDelayed")
|
||||
@ReplaceInvoke
|
||||
fun handlerPostDelayProxy(handler: Handler, action: Runnable, delayMillis: Long): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.postDelayed(action, delayMillis)
|
||||
}
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
val msg = Message.obtain(handler, action)
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(handler, action = action, what = what, delay = delayMillis)
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessageDelayed(msg, delayMillis)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(holder)
|
||||
whats.getOrPut(what) { LinkedList() }.add(holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.app.Activity", scope = ALL)
|
||||
@TargetMethod(methodName = "post")
|
||||
@ReplaceInvoke
|
||||
fun runOnUiThreadOfActivityProxy(activity: Activity, action: Runnable) {
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
val msg = Message.obtain()
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(null, action = action, what = what)
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessage(msg)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(holder)
|
||||
whats.getOrPut(what) { LinkedList() }.add(holder)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.view.View", scope = ALL)
|
||||
@TargetMethod(methodName = "post")
|
||||
@ReplaceInvoke
|
||||
fun postOfViewProxy(view: View, action: Runnable): Boolean {
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
val msg = Message.obtain()
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(null, action = action, what = what)
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessage(msg)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(holder)
|
||||
whats.getOrPut(what) { LinkedList() }.add(holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.view.View", scope = ALL)
|
||||
@TargetMethod(methodName = "postDelayed")
|
||||
@ReplaceInvoke
|
||||
fun postDelayedOfViewProxy(view: View, action: Runnable, delayMillis: Long): Boolean {
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
val msg = Message.obtain()
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(null, action = action, what = what, delay = delayMillis)
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessageDelayed(msg, delayMillis)
|
||||
if (inserted) {
|
||||
getRecorder()?.insert(holder)
|
||||
whats.getOrPut(what) { LinkedList() }.add(holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "removeCallbacks")
|
||||
@ReplaceInvoke
|
||||
fun handlerRemoveCallbacks(handler: Handler, action: Runnable) {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.removeCallbacks(action)
|
||||
}
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
HANDLER.removeMessages(what)
|
||||
val holders = whats.remove(what)
|
||||
if (!holders.isNullOrEmpty()) {
|
||||
getRecorder()?.remove(holders)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "removeCallbacks")
|
||||
@ReplaceInvoke
|
||||
fun handlerRemoveCallbacksWithToken(handler: Handler, action: Runnable, token: Any?) {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.removeCallbacks(action, token)
|
||||
}
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
val holders = whats.remove(what)
|
||||
if (!holders.isNullOrEmpty()) {
|
||||
getRecorder()?.remove(holders)
|
||||
}
|
||||
HANDLER.removeMessages(what, if (token != null) { synchronized(tokens) { tokens.remove(token) } } else null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "removeMessages")
|
||||
@ReplaceInvoke
|
||||
fun handlerRemoveMessages(handler: Handler, what: Int) {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.removeMessages(what)
|
||||
}
|
||||
val holders = whats.remove(what)
|
||||
if (!holders.isNullOrEmpty()) {
|
||||
getRecorder()?.remove(holders)
|
||||
}
|
||||
HANDLER.removeMessages(what)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "removeMessages")
|
||||
@ReplaceInvoke
|
||||
fun handlerRemoveMessagesWithToken(handler: Handler, what: Int, token: Any?) {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.removeMessages(what, token)
|
||||
}
|
||||
val holders = whats.remove(what)
|
||||
if (!holders.isNullOrEmpty()) {
|
||||
getRecorder()?.remove(holders)
|
||||
}
|
||||
HANDLER.removeMessages(what, if (token != null) synchronized(tokens) { tokens.remove(token) } else null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@TargetClass(value = "android.view.View", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onMeasure")
|
||||
fun proxyViewOnMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
getRecorder()?.insert(Holder.acquire(spend, "View[${This.get().javaClass.name}]:onMeasure"))
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.view.View", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onLayout")
|
||||
fun proxyViewOnLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
val holder = Holder.acquire(handler = null, obj = "View[${This.get().javaClass.name}]:onLayout")
|
||||
getRecorder()?.insert(holder)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@TargetClass(value = "android.view.View", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onDraw")
|
||||
fun proxyViewOnDraw(canvas: Canvas) {
|
||||
val holder = Holder.acquire(handler = null, obj = "View[${This.get().javaClass.name}]:onDraw")
|
||||
getRecorder()?.insert(holder)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onCreate")
|
||||
fun proxyActivityOnCreate(savedInstanceState: Bundle?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onCreate")
|
||||
getRecorder()?.insert(holder)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
CallerDevaToolsManager.block()?.monitor((This.get() as Activity).window)
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onStart")
|
||||
fun proxyActivityOnStart() {
|
||||
val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onStart")
|
||||
getRecorder()?.insert(holder)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onResume")
|
||||
fun proxyActivityOnResume() {
|
||||
val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onResume")
|
||||
getRecorder()?.insert(holder)
|
||||
val now = now()
|
||||
CallerDevaToolsManager.block()?.resume((This.get() as Activity).window)
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onPause")
|
||||
fun proxyActivityOnPause() {
|
||||
val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onPause")
|
||||
getRecorder()?.insert(holder)
|
||||
CallerDevaToolsManager.block()?.pause((This.get() as Activity).window)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onDestroy")
|
||||
fun proxyActivityOnDestroy() {
|
||||
CallerDevaToolsManager.block()?.pop((This.get() as Activity).window)
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "androidx.fragment.app.Fragment", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onCreateView")
|
||||
fun proxyFragmentOnCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Fragment[${This.get().javaClass.name}]:onCreateView")
|
||||
getRecorder()?.insert(holder)
|
||||
val startTime = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - startTime
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "androidx.fragment.app.Fragment", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onCreate")
|
||||
fun proxyFragmentOnCreate(savedInstanceState: Bundle?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Fragment[${This.get().javaClass.name}]:onCreate")
|
||||
getRecorder()?.insert(holder)
|
||||
val startTime = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - startTime
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "androidx.fragment.app.Fragment", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onViewCreated")
|
||||
fun proxyFragmentOnViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Fragment[${This.get().javaClass.name}]:onViewCreated")
|
||||
getRecorder()?.insert(holder)
|
||||
val startTime = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - startTime
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.content.BroadcastReceiver", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onReceive")
|
||||
fun proxyBroadcastReceiver(ctx: Context?, intent: Intent?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Receiver[${This.get().javaClass.name}]:onReceive")
|
||||
getRecorder()?.insert(holder)
|
||||
val startTime = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - startTime
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +223,10 @@ ext {
|
||||
log_runtime : "com.mogo.eagle.core.log.record:runtime:1.0.6",
|
||||
|
||||
// 安全证书
|
||||
passport_secret : "com.zhidaoauto:sdk-java:1.0.5-SNAPSHOT"
|
||||
passport_secret : "com.zhidaoauto:sdk-java:1.0.5-SNAPSHOT",
|
||||
|
||||
// 主线程卡顿监测
|
||||
block_detector : "com.mogo.eagle.core.block:runtime:10.0.0"
|
||||
]
|
||||
android = [
|
||||
launcherApplicationId : "com.mogo.launcher",
|
||||
|
||||
@@ -98,6 +98,7 @@ dependencies {
|
||||
implementation group: "com.tencent.matrix", name: "matrix-hooks", version: MATRIX_VERSION, changing: true
|
||||
implementation rootProject.ext.dependencies.weak_network
|
||||
// implementation rootProject.ext.dependencies.btrace
|
||||
api rootProject.ext.dependencies.block_detector
|
||||
|
||||
implementation project(':foudations:mogo-commons')
|
||||
implementation project(':core:mogo-core-utils')
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.mogo.eagle.core.data.deva.scene.SceneTAG
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.function.api.devatools.IDevaToolsProvider
|
||||
import com.mogo.eagle.core.function.api.devatools.apm.*
|
||||
import com.mogo.eagle.core.function.api.devatools.block.*
|
||||
import com.mogo.eagle.core.function.api.devatools.strict.*
|
||||
import com.mogo.eagle.core.function.api.devatools.download.*
|
||||
import com.mogo.eagle.core.function.api.devatools.logcat.*
|
||||
@@ -40,6 +41,7 @@ import com.mogo.weak.network.SdtManager
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.consts.BadCaseConfig
|
||||
import com.zhjt.mogo_core_function_devatools.binding.*
|
||||
import com.zhjt.mogo_core_function_devatools.block.*
|
||||
import com.zhjt.mogo_core_function_devatools.env.EnvChangeManager
|
||||
import com.zhjt.mogo_core_function_devatools.funcconfig.FuncConfigCenter.Companion.bizConfigCenter
|
||||
import com.zhjt.mogo_core_function_devatools.funcconfig.FuncConfigImpl
|
||||
@@ -83,6 +85,8 @@ class DevaToolsProvider : IDevaToolsProvider {
|
||||
|
||||
private val logRecordProvider by lazy { MoGoLogRecordProviderImpl() }
|
||||
|
||||
private val block by lazy { MoGoBlockProviderImpl() }
|
||||
|
||||
@Volatile
|
||||
private var mDockerVersion: String? = null
|
||||
|
||||
@@ -122,6 +126,11 @@ class DevaToolsProvider : IDevaToolsProvider {
|
||||
logRecordProvider.init(it)
|
||||
logRecordProvider.start()
|
||||
}
|
||||
|
||||
mContext?.also {
|
||||
block.init(it)
|
||||
block.start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun checkMonitorDb() {
|
||||
@@ -377,4 +386,6 @@ class DevaToolsProvider : IDevaToolsProvider {
|
||||
override fun mofang(): IMoGoMoFangProvider = mofangProvider
|
||||
|
||||
override fun logRecord(): IMoGoLogRecordProvider = logRecordProvider
|
||||
|
||||
override fun block(): IMoGoBlockProvider = block
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.zhjt.mogo_core_function_devatools.block
|
||||
|
||||
import com.mogo.eagle.core.data.deva.chain.*
|
||||
import com.zhjt.service.chain.*
|
||||
|
||||
internal class MainBlockLinkedLog {
|
||||
|
||||
fun record(extra: Map<String, List<String>>) {
|
||||
try {
|
||||
recordInternal(extra)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@ChainLog(
|
||||
linkChainLog = ChainConstant.CHAIN_TYPE_HMI,
|
||||
linkCode = ChainConstant.CHAIN_SOURCE_HMI,
|
||||
nodeAliasCode = ChainConstant.CHAIN_CODE_MAIN_BLOCK,
|
||||
paramIndexes = [0]
|
||||
)
|
||||
private fun recordInternal(extra: Map<String, List<String>>) {}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.zhjt.mogo_core_function_devatools.block
|
||||
|
||||
import android.content.*
|
||||
import android.util.*
|
||||
import android.view.*
|
||||
import androidx.metrics.performance.*
|
||||
import com.mogo.eagle.core.block.runtime.*
|
||||
import com.mogo.eagle.core.block.runtime.config.*
|
||||
import com.mogo.eagle.core.block.runtime.config.recorder.*
|
||||
import com.mogo.eagle.core.block.runtime.config.recorder.IMessageRecorder.OnDumpListener
|
||||
import com.mogo.eagle.core.block.runtime.listener.*
|
||||
import com.mogo.eagle.core.block.runtime.report.*
|
||||
import com.mogo.eagle.core.function.api.devatools.block.*
|
||||
import java.util.concurrent.TimeUnit.SECONDS
|
||||
|
||||
internal class MoGoBlockProviderImpl: IMoGoBlockProvider, IBlockListener {
|
||||
|
||||
@Volatile
|
||||
private var hasInit = false
|
||||
|
||||
private val linkedLog by lazy { MainBlockLinkedLog() }
|
||||
|
||||
override fun init(ctx: Context) {
|
||||
BlockDetector.init(BlockMetrics.Builder()
|
||||
.context(ctx)
|
||||
.multiplier(2.0f)
|
||||
.isDebug(false)
|
||||
.period(5, SECONDS)
|
||||
.junkRateThreshold(0.8f)
|
||||
.recorder(null, 1000, 512)
|
||||
.build())
|
||||
hasInit = true
|
||||
}
|
||||
|
||||
override fun hasInit(): Boolean {
|
||||
return hasInit
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
BlockDetector.start()
|
||||
BlockDetector.addListener(this)
|
||||
}
|
||||
|
||||
override fun onBlockReport(info: ReportInfo) {
|
||||
Log.d("BLOCK", "--- onBlockReport ---: ${info.frames.size}")
|
||||
val map = mutableMapOf<String, List<String>>()
|
||||
map["frames"] = info.frames.map { "$it" }
|
||||
BlockDetector.recorder().dump(object: OnDumpListener {
|
||||
override fun OnDumped(data: Map<Int, List<String>>) {
|
||||
map["history"] = data[0] ?: emptyList()
|
||||
map["pending"] = data[1] ?: emptyList()
|
||||
linkedLog.record(map)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun monitor(window: Window) {
|
||||
BlockDetector.monitor(window)
|
||||
}
|
||||
|
||||
override fun pause(window: Window) {
|
||||
BlockDetector.pause(window)
|
||||
}
|
||||
|
||||
override fun addState(window: Window, key: String, status: String) {
|
||||
val holder = PerformanceMetricsState.getHolderForHierarchy(window.decorView)
|
||||
holder.state?.putState(key, status)
|
||||
}
|
||||
|
||||
override fun resume(window: Window) {
|
||||
BlockDetector.resume(window)
|
||||
}
|
||||
|
||||
override fun pop(window: Window) {
|
||||
BlockDetector.pop(window)
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
BlockDetector.removeListener(this)
|
||||
BlockDetector.stop()
|
||||
}
|
||||
|
||||
override fun recorder(): IMessageRecorder {
|
||||
|
||||
return BlockDetector.recorder()
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,7 @@ class ChainConstant {
|
||||
const val CHAIN_CODE_INIT_ON_MAP_INIT = "CHAIN_CODE_INIT_ON_MAP_INIT"
|
||||
const val CHAIN_CODE_UPGRADE_APP = "CHAIN_CODE_UPGRADE_APP"
|
||||
const val CHAIN_CODE_MO_FANG_CONNECT = "CHAIN_CODE_MO_FANG_CONNECT"
|
||||
const val CHAIN_CODE_MAIN_BLOCK = "CHAIN_CODE_MAIN_BLOCK"
|
||||
|
||||
const val CHAIN_CODE_CLOUD_INIT = "CHAIN_CODE_CLOUD_INIT"
|
||||
const val CHAIN_CODE_CLOUD_PASSPORT_TOKEN = "CHAIN_CODE_CLOUD_PASSPORT_TOKEN"
|
||||
|
||||
@@ -51,6 +51,8 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.arouter
|
||||
kapt rootProject.ext.dependencies.aroutercompiler
|
||||
|
||||
compileOnly rootProject.ext.dependencies.block_detector
|
||||
|
||||
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
|
||||
compileOnly rootProject.ext.dependencies.mogo_core_data
|
||||
compileOnly rootProject.ext.dependencies.mogomapapi
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.mogo.eagle.core.data.deva.scene.SceneModule
|
||||
import com.mogo.eagle.core.data.deva.scene.SceneTAG
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.function.api.devatools.apm.*
|
||||
import com.mogo.eagle.core.function.api.devatools.block.*
|
||||
import com.mogo.eagle.core.function.api.devatools.strict.*
|
||||
import com.mogo.eagle.core.function.api.devatools.download.*
|
||||
import com.mogo.eagle.core.function.api.devatools.logcat.*
|
||||
@@ -225,4 +226,9 @@ interface IDevaToolsProvider : IProvider {
|
||||
* 日志记录功能
|
||||
*/
|
||||
fun logRecord(): IMoGoLogRecordProvider
|
||||
|
||||
/**
|
||||
* 主线程卡顿监控
|
||||
*/
|
||||
fun block(): IMoGoBlockProvider
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.mogo.eagle.core.function.api.devatools.block
|
||||
|
||||
import android.content.Context
|
||||
import android.view.Window
|
||||
import com.mogo.eagle.core.block.runtime.config.recorder.*
|
||||
|
||||
interface IMoGoBlockProvider {
|
||||
|
||||
fun init(ctx: Context)
|
||||
|
||||
fun hasInit(): Boolean
|
||||
|
||||
fun start()
|
||||
|
||||
fun monitor(window: Window)
|
||||
|
||||
fun pause(window: Window)
|
||||
|
||||
fun resume(window: Window)
|
||||
|
||||
fun pop(window: Window)
|
||||
|
||||
fun addState(window: Window, key: String, status: String)
|
||||
|
||||
fun stop()
|
||||
|
||||
fun recorder(): IMessageRecorder
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import com.mogo.eagle.core.data.deva.scene.SceneTAG
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.function.api.devatools.IDevaToolsProvider
|
||||
import com.mogo.eagle.core.function.api.devatools.apm.*
|
||||
import com.mogo.eagle.core.function.api.devatools.block.*
|
||||
import com.mogo.eagle.core.function.api.devatools.download.*
|
||||
import com.mogo.eagle.core.function.api.devatools.logcat.*
|
||||
import com.mogo.eagle.core.function.api.devatools.mofang.*
|
||||
@@ -264,4 +265,6 @@ object CallerDevaToolsManager {
|
||||
fun mofang(): IMoGoMoFangProvider? = devaToolsProviderApi?.mofang()
|
||||
|
||||
fun logcat(): IMoGoLogRecordProvider? = devaToolsProviderApi?.logRecord()
|
||||
|
||||
fun block(): IMoGoBlockProvider? = devaToolsProviderApi?.block()
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.jvmargs=-Xmx4096m
|
||||
org.gradle.jvmargs=-Xmx6144m
|
||||
#开启gradle缓存
|
||||
org.gradle.caching=true
|
||||
android.enableBuildCache=true
|
||||
|
||||
@@ -18,6 +18,9 @@ LancetX {
|
||||
window_callback {
|
||||
enable true
|
||||
}
|
||||
main_block_check {
|
||||
enable true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user