[3.4.0][Block] 主线程卡顿检测

This commit is contained in:
renwj
2023-07-25 16:34:23 +08:00
parent c52d83596e
commit f7afd759e8
15 changed files with 748 additions and 3 deletions

View File

@@ -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

View File

@@ -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) {

View 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)
}
}
}

View File

@@ -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",

View File

@@ -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')

View File

@@ -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
}

View File

@@ -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>>) {}
}

View File

@@ -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()
}
}

View File

@@ -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"

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -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

View File

@@ -18,6 +18,9 @@ LancetX {
window_callback {
enable true
}
main_block_check {
enable true
}
}
}