[6.2.0][技术优化] 打开监测开关

This commit is contained in:
renwj
2023-11-15 16:48:20 +08:00
parent 9edc1045c4
commit 1dcdac0015
15 changed files with 622 additions and 292 deletions

View File

@@ -4,6 +4,8 @@ import android.app.*
import android.content.*
import android.graphics.*
import android.os.*
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.os.Handler.Callback
import android.util.*
import android.view.*
@@ -21,7 +23,6 @@ import com.mogo.eagle.core.function.call.devatools.*
import com.mogo.eagle.core.utilcode.util.*
import kotlinx.coroutines.Runnable
import java.lang.ref.WeakReference
import java.util.LinkedList
import java.util.concurrent.*
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.withLock
@@ -36,65 +37,61 @@ class MainBlockCheck {
private const val TAG = "MAIN_BLOCK_CHECK"
@JvmStatic
private val tokens = ConcurrentHashMap<Int, WeakReference<Holder>>(128)
private val handlerTokens by lazy { ConcurrentHashMap<String, CopyOnWriteArrayList<Holder>>() }
private val pool by lazy { Executors.newFixedThreadPool(2) }
private val pool by lazy { Pools.SimplePool<ActionWrapper>(50) }
val asyncHandlers by lazy { CopyOnWriteArraySet<WeakReference<Handler>>() }
private val handlersMap by lazy { ConcurrentHashMap<String, Boolean>() }
private val whats by lazy { ConcurrentHashMap<Int, LinkedList<WeakReference<Holder>>>() }
private val actionPool by lazy { Pools.SimplePool<PoolAction>(500) }
private val actions by lazy { ConcurrentHashMap<Runnable, ActionWrapper>() }
private val lock by lazy { ReentrantReadWriteLock() }
private data class PoolAction(var type: Int, var what: Int, var holder: Holder?, var elapsedTime: Long = -1, var duration:Long = -1): Runnable {
val asyncHandlers by lazy { CopyOnWriteArraySet<WeakReference<Handler>>() }
override fun run() {
try {
val h = holder
if (type == 0 && h != null) {
whats.getOrPut(what) { LinkedList<WeakReference<Holder>>() }.add(
WeakReference(h)
)
getRecorder()?.insert(h)
}
if (type == 1) {
val holders = whats.remove(what)?.mapNotNull { it.get() }
if (!holders.isNullOrEmpty()) {
getRecorder()?.remove(holders)
}
}
if (type == 2 && h != null) {
val what = h.what
if (what != null) {
whats.remove(what)?.removeAll { it.get() == h }
}
getRecorder()?.recycle(h.id, elapsedTime, duration)
}
} finally {
reset()
lock.writeLock().withLock {
actionPool.release(this)
}
}
}
private val handlers by lazy { ConcurrentHashMap<Int, Boolean>() }
fun reset() {
type = -1
what = Int.MIN_VALUE
holder = null
elapsedTime = -1
duration = -1
private val handlerWhats by lazy { ConcurrentHashMap<Int, CopyOnWriteArraySet<Int>>() }
private val main by lazy { Looper.getMainLooper() }
private fun acquireAction(msg: Holder, action: Runnable): ActionWrapper {
return lock.readLock().withLock {
val ret = pool.acquire() ?: ActionWrapper(msg, action)
ret.msg = msg
ret.action = action
ret
}
}
private fun releaseAction(wrapper: ActionWrapper) {
lock.writeLock().withLock { pool.release(wrapper) }
}
private data class ActionWrapper(var msg: Holder, var action: Runnable) : Runnable {
override fun run() {
var elapsedTime: Long = 0
var startTime: Long = 0
try {
val expect = msg.enqueueTime + msg.delay
val now = now()
elapsedTime = now - expect
startTime = now()
action.run()
} catch (t: Throwable) {
Log.e(TAG, "msg -> $msg", t)
throw t
} finally {
getRecorder()?.recycle(msg.id, elapsedTime, now() - startTime)
releaseAction(this)
actions.remove(action)
CallerDevaToolsManager.usage()?.updateMainThreadTime(Debug.threadCpuTimeNanos())
}
}
override fun toString(): String {
return action.toString()
}
}
private fun getAction(): PoolAction = lock.readLock().withLock { actionPool.acquire() ?: PoolAction(-1, 0, null) }
@JvmStatic
fun getRecorder(): IMessageRecorder? {
@@ -121,8 +118,7 @@ class MainBlockCheck {
val action = enclose.action
val oldMsg = enclose.origin
val oldObj = enclose.obj
val now = now()
val elapsedTime = now - enclose.enqueueTime
val start = now()
try {
if (action != null) {
action.run()
@@ -133,44 +129,48 @@ class MainBlockCheck {
oldMsg.obj = oldObj
h?.dispatchMessage(oldMsg)
}
if (h != null) {
val key = generateKey(h, msg.what)
handlerTokens[key]?.remove(enclose)
}
}
} catch (t: Throwable) {
Log.e(TAG, "handler: $h -> ${handlersMap[h.toString()]} -> msg: $enclose", t)
Log.e(TAG, "msg: $enclose", t)
throw t
} finally {
val duration = now() - now
recycle(enclose, elapsedTime, duration)
val now = now()
val duration = now - start
val expect = enclose.enqueueTime + enclose.delay
val elapsed = now - expect
getRecorder()?.recycle(enclose.id, elapsed, duration)
CallerDevaToolsManager.usage()?.updateMainThreadTime(Debug.threadCpuTimeNanos())
}
true
}
}
@JvmStatic val ASYNC_HANDLER by lazy {
HandlerCompat.createAsync(Looper.getMainLooper(), callback)
HandlerCompat.createAsync(main, callback)
}
@JvmStatic val HANDLER by lazy {
Handler(Looper.getMainLooper(), callback)
Handler(main, callback)
}
@JvmStatic
@TargetClass(value = "android.os.Handler", scope = ALL)
@TargetMethod(methodName = "post")
@ReplaceInvoke
fun handlerPostProxy(handler: Handler, action: Runnable): Boolean {
if (Looper.getMainLooper() != handler.looper) {
fun handlerPost(handler: Handler, action: Runnable): Boolean {
if (main != handler.looper) {
return handler.post(action)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler)
val what = ObjectHashCodeUtils.getHashCodeIfNeed(newHandler, action)
msg.what = what
val holder = Holder.acquire(newHandler, action = action, isAsync = isAsync)
msg.obj = holder
val inserted = newHandler.sendMessage(msg)
val holder = Holder.acquire(handler, action = action, isAsync = handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) })
val inserted = handler.post(acquireAction(holder, action).also { actions[action] = it })
if (inserted) {
insert(what, holder)
getRecorder()?.insert(holder)
} else {
actions.remove(action)
}
return inserted
}
@@ -179,47 +179,34 @@ class MainBlockCheck {
@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) {
fun handlerPostDelay(handler: Handler, action: Runnable, delayMillis: Long): Boolean {
if (main != handler.looper) {
return handler.postDelayed(action, delayMillis)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler)
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
msg.what = what
val holder = Holder.acquire(handler, action = action, delay = delayMillis, isAsync = isAsync)
msg.obj = holder
val inserted = newHandler.sendMessageDelayed(msg, delayMillis)
val holder = Holder.acquire(handler, action = action, delay = delayMillis, isAsync = handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) })
val inserted = handler.postDelayed(acquireAction(holder, action).also { actions[action] = it }, delayMillis)
if (inserted) {
insert(what, holder)
getRecorder()?.insert(holder)
} else {
actions.remove(action)
}
return inserted
}
@JvmStatic
@TargetClass(value = "android.os.Handler", scope = ALL)
@TargetMethod(methodName = "postAtTime")
@TargetMethod(methodName = "postDelayed")
@ReplaceInvoke
fun handlerPostDelayProxy2(handler: Handler, action: Runnable, token: Any?, delayMillis: Long): Boolean {
if (Looper.getMainLooper() != handler.looper) {
fun handlerPostDelayWithToken(handler: Handler, action: Runnable, token: Any?, delayMillis: Long): Boolean {
if (main != handler.looper) {
return HandlerCompat.postDelayed(handler, action, token, delayMillis)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler)
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
msg.what = what
val holder = Holder.acquire(handler, action = action, delay = delayMillis, obj = token)
msg.obj = holder
if (token != null) {
synchronized(tokens) {
tokens[token.hashCode()] = WeakReference(holder)
}
}
val inserted = HandlerCompat.postDelayed(newHandler, action, token, delayMillis)
val holder = Holder.acquire(handler, isAsync = handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }, action = action, obj = token, delay = delayMillis)
val inserted = HandlerCompat.postDelayed(handler, acquireAction(holder, action).also { actions[action] = it }, token, delayMillis)
if (inserted) {
insert(what, holder)
getRecorder()?.insert(holder)
} else {
actions.remove(action)
}
return inserted
}
@@ -228,20 +215,16 @@ class MainBlockCheck {
@TargetClass(value = "android.os.Handler", scope = ALL)
@TargetMethod(methodName = "postAtFrontOfQueue")
@ReplaceInvoke
fun handlerPostAtFrontOfQueueProxy(handler: Handler, action: Runnable): Boolean {
if (Looper.getMainLooper() != handler.looper) {
fun handlerPostAtFrontOfQueue(handler: Handler, action: Runnable): Boolean {
if (main != handler.looper) {
return handler.postAtFrontOfQueue(action)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler)
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
msg.what = what
val holder = Holder.acquire(handler, action = action)
msg.obj = holder
val inserted = newHandler.sendMessageAtFrontOfQueue(msg)
val holder = Holder.acquire(handler, action = action, isAsync = handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) })
val inserted = handler.postAtFrontOfQueue(acquireAction(holder, action).also { actions[action] = it })
if (inserted) {
insert(what, holder)
getRecorder()?.insert(holder)
} else {
actions.remove(action)
}
return inserted
}
@@ -250,21 +233,17 @@ class MainBlockCheck {
@TargetClass(value = "android.os.Handler", scope = ALL)
@TargetMethod(methodName = "postAtTime")
@ReplaceInvoke
fun handlerPostAtTimeProxy(handler: Handler, action: Runnable, uptimeMillis: Long): Boolean {
if (Looper.getMainLooper() != handler.looper) {
fun handlerPostAtTime(handler: Handler, action: Runnable, uptimeMillis: Long): Boolean {
if (main != handler.looper) {
return handler.postAtTime(action, uptimeMillis)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler)
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
msg.what = what
val delta = uptimeMillis - SystemClock.uptimeMillis()
val holder = Holder.acquire(handler, action = action, delay = if (delta > 0) delta else 0)
msg.obj = holder
val inserted = newHandler.sendMessageAtTime(msg, uptimeMillis)
val holder = Holder.acquire(handler, action = action, delay = if (delta > 0) delta else 0, isAsync = handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) })
val inserted = handler.postAtTime(acquireAction(holder, action), uptimeMillis)
if (inserted) {
insert(what, holder)
getRecorder()?.insert(holder)
} else {
actions.remove(action)
}
return inserted
}
@@ -273,26 +252,17 @@ class MainBlockCheck {
@TargetClass(value = "android.os.Handler", scope = ALL)
@TargetMethod(methodName = "postAtTime")
@ReplaceInvoke
fun handlerPostAtTimeProxy2(handler: Handler, action: Runnable, token: Any?, uptimeMillis: Long): Boolean {
if (Looper.getMainLooper() != handler.looper) {
fun handlerPostAtTimeWithToken(handler: Handler, action: Runnable, token: Any?, uptimeMillis: Long): Boolean {
if (main != handler.looper) {
return handler.postAtTime(action, uptimeMillis)
}
val isAsync = handlersMap.getOrPut(handler.toString() ) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler)
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
msg.what = what
val delta = uptimeMillis - SystemClock.uptimeMillis()
val holder = Holder.acquire(handler, action = action, delay = if (delta > 0) delta else 0, obj = token)
msg.obj = holder
if (token != null) {
synchronized(tokens) {
tokens[token.hashCode()] = WeakReference(holder)
}
}
val inserted = newHandler.sendMessageAtTime(msg, uptimeMillis)
val holder = Holder.acquire(handler, action = action, delay = if (delta > 0) delta else 0, obj = token, isAsync = handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) })
val inserted = handler.postAtTime(acquireAction(holder, action).also { actions[action] = it }, token, uptimeMillis)
if (inserted) {
insert(what, holder)
getRecorder()?.insert(holder)
} else {
actions.remove(action)
}
return inserted
}
@@ -302,17 +272,23 @@ class MainBlockCheck {
@TargetMethod(methodName = "sendEmptyMessage")
@ReplaceInvoke
fun handlerSendEmptyMessage(handler: Handler, what: Int): Boolean {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.sendEmptyMessage(what)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val key = handler.hashCode()
val isAsync = handlers.getOrPut(key) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler, what)
val holder = Holder.acquire(handler, what = what, isAsync = isAsync)
msg.obj = holder
val tokenKey = generateKey(handler, what)
handlerTokens.getOrPut(tokenKey) { CopyOnWriteArrayList() }.add(holder)
val inserted = newHandler.sendMessage(msg)
if (inserted) {
insert(what, holder)
handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(what)
getRecorder()?.insert(holder)
} else {
handlerTokens[tokenKey]?.remove(holder)
}
return inserted
}
@@ -322,18 +298,24 @@ class MainBlockCheck {
@TargetMethod(methodName = "sendEmptyMessageAtTime")
@ReplaceInvoke
fun handlerSendEmptyMessageAtTime(handler: Handler, what: Int, uptimeMillis: Long): Boolean {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.sendEmptyMessageAtTime(what, uptimeMillis)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val key = handler.hashCode()
val isAsync = handlers.getOrPut(key) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler, what)
val delta = uptimeMillis - SystemClock.uptimeMillis()
val holder = Holder.acquire(handler, what = what, delay = if (delta > 0) delta else 0, isAsync = isAsync)
msg.obj = holder
val tokenKey = generateKey(handler, what)
handlerTokens.getOrPut(tokenKey) { CopyOnWriteArrayList() }.add(holder)
val inserted = newHandler.sendMessageAtTime(msg, uptimeMillis)
if (inserted) {
insert(what, holder)
handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(what)
getRecorder()?.insert(holder)
} else {
handlerTokens[tokenKey]?.remove(holder)
}
return inserted
}
@@ -343,17 +325,23 @@ class MainBlockCheck {
@TargetMethod(methodName = "sendEmptyMessageDelayed")
@ReplaceInvoke
fun handlerSendEmptyMessageDelayed(handler: Handler, what: Int, delayMillis: Long): Boolean {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.sendEmptyMessageDelayed(what, delayMillis)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val key = handler.hashCode()
val isAsync = handlers.getOrPut(key) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
val msg = Message.obtain(newHandler, what)
val holder = Holder.acquire(handler, what = what, delay = delayMillis, isAsync = isAsync)
msg.obj = holder
val tokenKey = generateKey(handler, what)
handlerTokens.getOrPut(tokenKey) { CopyOnWriteArrayList() }.add(holder)
val inserted = newHandler.sendMessageDelayed(msg, delayMillis)
if (inserted) {
insert(what, holder)
handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(what)
getRecorder()?.insert(holder)
} else {
handlerTokens[tokenKey]?.remove(holder)
}
return inserted
}
@@ -363,28 +351,34 @@ class MainBlockCheck {
@TargetMethod(methodName = "sendMessage")
@ReplaceInvoke
fun handlerSendMessage(handler: Handler, msg: Message): Boolean {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.sendMessage(msg)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
var newMsg = msg
val tokenKey = generateKey(handler, msg.what)
val key = handler.hashCode()
val isAsync = handlers.getOrPut(key) { computeIsAsyncHandler(handler) }
val action = msg.callback
val holder = Holder.acquire(handler, originMsg = msg, action = msg.callback, obj = msg.obj, what = msg.what, isAsync = isAsync)
val inserted: Boolean
if (action != null) {
newMsg = Message.obtain(newHandler)
newMsg.what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
inserted = handler.post(acquireAction(holder, action).also { actions[action] = it })
} else {
msg.obj = holder
handlerTokens.getOrPut(tokenKey) { CopyOnWriteArrayList() }.add(holder)
val newHandler = getHandler(isAsync)
inserted = newHandler.sendMessage(msg)
}
val obj: Holder = Holder.acquire(handler, originMsg = msg, action = msg.callback, obj = msg.obj, what = msg.what, isAsync = isAsync)
val oldObj = msg.obj
newMsg.obj = obj
if (oldObj != null) {
synchronized(tokens) {
tokens[oldObj.hashCode()] = WeakReference(obj)
}
}
val inserted = newHandler.sendMessage(newMsg)
if (inserted) {
insert(newMsg.what, obj)
if (action == null) {
handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(holder.what)
}
getRecorder()?.insert(holder)
} else {
if (action == null) {
handlerTokens[tokenKey]?.remove(holder)
} else {
actions.remove(action)
}
}
return inserted
}
@@ -394,29 +388,35 @@ class MainBlockCheck {
@TargetMethod(methodName = "sendMessageAtTime")
@ReplaceInvoke
fun handlerSendMessageAtTime(handler: Handler, msg: Message, uptimeMillis: Long): Boolean {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.sendMessageAtTime(msg, uptimeMillis)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
var newMsg = msg
val tokenKey = generateKey(handler, msg.what)
val key = handler.hashCode()
val isAsync = handlers.getOrPut(key) { computeIsAsyncHandler(handler) }
val action = msg.callback
if (action != null) {
newMsg = Message.obtain(newHandler)
newMsg.what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
}
val delta = uptimeMillis - SystemClock.uptimeMillis()
val obj= Holder.acquire(handler, msg, obj = msg.obj, action = msg.callback, what = msg.what, delay = if (delta > 0) delta else 0, isAsync = isAsync)
val oldObj = msg.obj
newMsg.obj = obj
if (oldObj != null) {
synchronized(tokens) {
tokens[oldObj.hashCode()] = WeakReference(obj)
}
val holder = Holder.acquire(handler, originMsg = msg, action = msg.callback, obj = msg.obj, what = msg.what, isAsync = isAsync, delay = if (delta > 0) delta else 0)
val inserted: Boolean
if (action != null) {
inserted = handler.postAtTime(acquireAction(holder, action).also { actions[action] = it }, uptimeMillis)
} else {
msg.obj = holder
handlerTokens.getOrPut(tokenKey) { CopyOnWriteArrayList() }.add(holder)
val newHandler = getHandler(isAsync)
inserted = newHandler.sendMessageAtTime(msg, uptimeMillis)
}
val inserted = newHandler.sendMessageAtTime(newMsg, uptimeMillis)
if (inserted) {
insert(newMsg.what, obj)
if (action == null) {
handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(holder.what)
}
getRecorder()?.insert(holder)
} else {
if (action == null) {
handlerTokens[tokenKey]?.remove(holder)
} else {
actions.remove(action)
}
}
return inserted
}
@@ -426,46 +426,81 @@ class MainBlockCheck {
@TargetMethod(methodName = "sendMessageAtFrontOfQueue")
@ReplaceInvoke
fun handlerSendMessageAtFrontOfQueue(handler: Handler, msg: Message): Boolean {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.sendMessageAtFrontOfQueue(msg)
}
val isAsync = handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }
val newHandler = getHandler(isAsync)
var newMsg = msg
val tokenKey = generateKey(handler, msg.what)
val key = handler.hashCode()
val isAsync = handlers.getOrPut(key) { computeIsAsyncHandler(handler) }
val action = msg.callback
val holder = Holder.acquire(handler, originMsg = msg, action = msg.callback, obj = msg.obj, what = msg.what, isAsync = isAsync)
val inserted: Boolean
if (action != null) {
newMsg = Message.obtain(newHandler)
newMsg.what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
inserted = handler.postAtFrontOfQueue(acquireAction(holder, action).also { actions[action] = it })
} else {
msg.obj = holder
handlerTokens.getOrPut(tokenKey) { CopyOnWriteArrayList() }.add(holder)
val newHandler = getHandler(isAsync)
inserted = newHandler.sendMessageAtFrontOfQueue(msg)
}
val obj = Holder.acquire(handler, msg, obj = msg.obj, action = msg.callback, what = msg.what, isAsync = isAsync)
val old = msg.obj
newMsg.obj = obj
if (old != null) {
synchronized(tokens) {
tokens[old.hashCode()] = WeakReference(obj)
}
}
val inserted = newHandler.sendMessageAtFrontOfQueue(newMsg)
if (inserted) {
insert(newMsg.what, obj)
if (action == null) {
handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(holder.what)
}
getRecorder()?.insert(holder)
} else {
if (action == null) {
handlerTokens[tokenKey]?.remove(holder)
} else {
actions.remove(action)
}
}
return inserted
}
@JvmStatic
@TargetClass(value = "android.os.Handler", scope = ALL)
@TargetMethod(methodName = "hasCallbacks")
@ReplaceInvoke
fun handlerHasCallbacks(handler: Handler, action: Runnable): Boolean {
if (main != handler.looper) {
return if (VERSION.SDK_INT >= VERSION_CODES.Q) {
handler.hasCallbacks(action)
} else {
HandlerCompat.hasCallbacks(handler, action)
}
}
val existed = actions[action]
if (existed != null) {
return HandlerCompat.hasCallbacks(handler, existed)
}
return false
}
@JvmStatic
@TargetClass(value = "android.os.Handler", scope = ALL)
@TargetMethod(methodName = "hasMessages")
@ReplaceInvoke
fun handlerHasMessages(handler: Handler, what: Int): Boolean {
if (main != handler.looper) {
return handler.hasMessages(what)
}
return getHandler(computeIsAsyncHandler(handler)).hasMessages(what)
}
@JvmStatic
@TargetClass(value = "android.app.Activity", scope = ALL)
@TargetMethod(methodName = "post")
@ReplaceInvoke
fun runOnUiThreadOfActivityProxy(activity: Activity, action: Runnable) {
val msg = Message.obtain()
val what = ObjectHashCodeUtils.getHashCodeIfNeed(activity, action)
msg.what = what
val holder = Holder.acquire(null, action = action, what = msg.what, extra = mutableMapOf("runOnUiThread" to "${activity.javaClass.simpleName}#${action.javaClass.name}"))
msg.obj = holder
val inserted = HANDLER.sendMessage(msg)
if (inserted) {
insert(what, holder)
fun runOnUiThreadOfActivity(activity: Activity, action: Runnable) {
val holder = Holder.acquire(null, action = action)
try {
activity.runOnUiThread(acquireAction(holder, action))
} finally {
getRecorder()?.insert(holder)
}
}
@@ -473,15 +508,11 @@ class MainBlockCheck {
@TargetClass(value = "android.view.View", scope = ALL)
@TargetMethod(methodName = "post")
@ReplaceInvoke
fun postOfViewProxy(view: View, action: Runnable): Boolean {
val msg = Message.obtain()
val what = ObjectHashCodeUtils.getHashCodeIfNeed(view, action)
msg.what = what
val holder = Holder.acquire(null, action = action, what = what, extra = mutableMapOf("post" to "${view.javaClass.simpleName}#${action.javaClass.name}"))
msg.obj = holder
val inserted = HANDLER.sendMessage(msg)
fun postOfView(view: View, action: Runnable): Boolean {
val holder = Holder.acquire(null, action = action)
val inserted = view.post(acquireAction(holder, action).also { actions[action] = it })
if (inserted) {
insert(what, holder)
getRecorder()?.insert(holder)
}
return inserted
}
@@ -490,15 +521,11 @@ class MainBlockCheck {
@TargetClass(value = "android.view.View", scope = ALL)
@TargetMethod(methodName = "postDelayed")
@ReplaceInvoke
fun postDelayedOfViewProxy(view: View, action: Runnable, delayMillis: Long): Boolean {
val msg = Message.obtain()
val what = ObjectHashCodeUtils.getHashCodeIfNeed(view, action)
msg.what = what
val holder = Holder.acquire(null, action = action, delay = delayMillis, what = what, extra = mutableMapOf("post" to "${view.javaClass.simpleName}#${action.javaClass.name}"))
msg.obj = holder
val inserted = HANDLER.sendMessageDelayed(msg, delayMillis)
fun postDelayedOfView(view: View, action: Runnable, delayMillis: Long): Boolean {
val holder = Holder.acquire(null, action = action, delay = delayMillis)
val inserted = view.postDelayed(acquireAction(holder, action).also { actions[action] = it }, delayMillis)
if (inserted) {
insert(what, holder)
getRecorder()?.insert(holder)
}
return inserted
}
@@ -508,14 +535,16 @@ class MainBlockCheck {
@TargetMethod(methodName = "removeCallbacks")
@ReplaceInvoke
fun handlerRemoveCallbacks(handler: Handler, action: Runnable) {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.removeCallbacks(action)
}
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
try {
return getHandler(handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }).removeMessages(what)
} finally {
remove(what)
val existed = actions.remove(action)
if (existed != null) {
try {
handler.removeCallbacks(existed)
} finally {
getRecorder()?.remove(existed.msg)
}
}
}
@@ -524,14 +553,17 @@ class MainBlockCheck {
@TargetMethod(methodName = "removeCallbacks")
@ReplaceInvoke
fun handlerRemoveCallbacksWithToken(handler: Handler, action: Runnable, token: Any?) {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.removeCallbacks(action, token)
}
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
getHandler(handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }).removeMessages(what, if (token != null) { synchronized(
tokens
) { tokens.remove(token.hashCode())?.get() } } else null)
remove(what)
val existed = actions.remove(action)
if (existed != null) {
try {
handler.removeCallbacks(existed, token)
} finally {
getRecorder()?.remove(existed.msg)
}
}
}
@JvmStatic
@@ -539,22 +571,55 @@ class MainBlockCheck {
@TargetMethod(methodName = "removeMessages")
@ReplaceInvoke
fun handlerRemoveMessages(handler: Handler, what: Int) {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.removeMessages(what)
}
getHandler(handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }).removeMessages(what)
remove(what)
val newHandler = getHandler(handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) })
val tokens = handlerTokens.remove(generateKey(handler, what))
if (!tokens.isNullOrEmpty()) {
val snapshot = ArrayList<Holder>(tokens)
snapshot.forEach {
newHandler.removeMessages(what, it)
}
getRecorder()?.remove(snapshot)
}
}
@JvmStatic
@TargetClass(value = "android.os.Handler", scope = ALL)
@TargetMethod(methodName = "removeCallbacksAndMessages")
@ReplaceInvoke
fun handlerRemoveCallbacksAndMessages(handler: Handler, token: Any?) {
if (main != handler.looper) {
return handler.removeCallbacksAndMessages(token)
}
handler.removeCallbacksAndMessages(token)
val existed = handlerWhats[handler.hashCode()]
if (!existed.isNullOrEmpty()) {
existed.forEach {what ->
handlerTokens.remove(generateKey(handler, what))?.forEach { msg ->
getHandler(handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what, msg)
}
}
}
}
@JvmStatic
@TargetClass(value = "android.view.View", scope = ALL)
@TargetMethod(methodName = "removeCallbacks")
@ReplaceInvoke
fun viewRemoveCallback(view: View, action: Runnable): Boolean {
val what = ObjectHashCodeUtils.getHashCodeIfNeed(view, action)
HANDLER.removeMessages(what)
remove(what)
return true
val exist = actions.remove(action)
if (exist != null) {
try {
return view.removeCallbacks(exist)
} finally {
getRecorder()?.remove(exist.msg)
}
}
return false
}
@JvmStatic
@@ -562,43 +627,28 @@ class MainBlockCheck {
@TargetMethod(methodName = "removeMessages")
@ReplaceInvoke
fun handlerRemoveMessagesWithToken(handler: Handler, what: Int, token: Any?) {
if (Looper.getMainLooper() != handler.looper) {
if (main != handler.looper) {
return handler.removeMessages(what, token)
}
getHandler(handlersMap.getOrPut(handler.toString()) { computeIsAsyncHandler(handler) }).removeMessages(what, if (token != null) synchronized(
tokens
) { tokens.remove(token.hashCode())?.get() } else null)
remove(what)
val newHandler = getHandler(handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) })
val tokens = handlerTokens.remove(generateKey(handler, what))
if (!tokens.isNullOrEmpty()) {
val snapshot = ArrayList<Holder>(tokens)
snapshot.forEach {
newHandler.removeMessages(what, it)
}
getRecorder()?.remove(snapshot)
}
}
private fun generateKey(handler: Handler, what: Int) : String {
return "${handler.hashCode()}_$what"
}
private fun computeIsAsyncHandler(handler: Handler): Boolean {
return asyncHandlers.find { it.get() === handler } != null
}
fun insert(what: Int, holder: Holder) {
val action = getAction()
action.type = 0
action.what = what
action.holder = holder
pool.execute(action)
}
private fun remove(what: Int) {
val action = getAction()
action.type = 1
action.what = what
pool.execute(action)
}
private fun recycle(holder: Holder, elapsedTime: Long, duration: Long) {
val action = getAction()
action.type = 2
action.holder = holder
action.elapsedTime = elapsedTime
action.duration = duration
pool.execute(action)
}
private fun getHandler(isAsync: Boolean): Handler {
return if (isAsync) {
ASYNC_HANDLER

View File

@@ -10,6 +10,8 @@ import android.content.ContentProvider;
import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.view.View;
import android.view.ViewManager;
import android.widget.Toast;
import com.knightboost.lancet.api.synchronized_lock.ISynchronizedLockHooker;
import com.mogo.core.lancetx.compiler.lib.annotations.LancetXGenerator;
@@ -17,6 +19,8 @@ import com.mogo.core.lancetx.compiler.lib.generator.HookType;
import com.mogo.core.lancetx.compiler.lib.generator.Scope;
import com.mogo.core.lancetx.compiler.lib.generator.Type;
import java.io.File;
import java.io.InputStream;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
@@ -178,4 +182,56 @@ class JankPointAutoGenerator {
excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" }
)
private androidx.fragment.app.Fragment androidxFragment;
@LancetXGenerator(
group = "main_block_check",
type = Type.IO,
scope = Scope.ALL,
hookType = HookType.REPLACE_INVOKE,
hookAllPublicMethods = true,
excludeHookMethodNames = { "toString", "hashCode", "compareTo", "compareTo" },
excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" , "(Ljava/io/File;)I", "(Ljava/lang/Object;)I" }
)
private File file;
@LancetXGenerator(
group = "main_block_check",
type = Type.IO,
scope = Scope.ALL,
hookType = HookType.REPLACE_INVOKE,
hookAllPublicMethods = true,
excludeHookMethodNames = { "toString", "hashCode" },
excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" }
)
private InputStream is;
@LancetXGenerator(
group = "main_block_check",
type = Type.VIEW,
scope = Scope.ALL,
hookType = HookType.REPLACE_INVOKE,
hookAllPublicMethods = true,
onlyHookMethodNames = { "show" },
onlyHookMethodDescs = { "()V" }
)
private Toast toast;
@LancetXGenerator(
group = "main_block_check",
type = Type.VIEW,
scope = Scope.ALL,
hookType = HookType.REPLACE_INVOKE,
hookAllPublicMethods = true,
onlyHookMethodNames = { "addView", "updateViewLayout", "removeView" },
onlyHookMethodDescs = {
"(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V",
"(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V",
"(Landroid/view/View;)V"
}
)
private ViewManager manager;
}

View File

@@ -6,9 +6,9 @@ import androidx.annotation.NonNull;
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.zhjt.service.chain.ChainLog;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
@@ -25,12 +25,25 @@ public class HookHandler implements IHookInvoker {
private final ThreadLocal<StringBuilder> message = new ThreadLocal<>();
private final ThreadLocal<Object> monitor = new ThreadLocal<>();
private final AtomicReference<Thread> holder = new AtomicReference<>();
private String holderDesc = null;
@Override
public void i(@NonNull Type type, Object caller, @NonNull String methodName, @NonNull Object... objects) {
if (Looper.myLooper() == mainLooper) {
if (type == Type.SYNCHRONIZED_LOCK) {
if ("onMonitorBefore".equals(methodName)) {
syncLockStartTime.set(SystemClock.elapsedRealtime());
if (objects.length > 0) {
this.monitor.set(objects[0]);
}
Thread holder = this.holder.get();
if (holder != null) {
holderDesc = holder.toString();
}
}
if ("onMonitorEnter".equals(methodName)) {
long elapsedTime = SystemClock.elapsedRealtime() - syncLockStartTime.get();
@@ -64,25 +77,49 @@ public class HookHandler implements IHookInvoker {
builder.setLength(builder.length() - 1);
builder.append(")");
}
builder.append("#").append(elapsedTime);
Object monitor = this.monitor.get();
if (monitor != null) {
builder.append("#").append(monitor);
}
if (holderDesc != null) {
builder.append("#").append(holderDesc);
}
builder.append("\n");
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement trace: stackTrace) {
if ("dalvik.system.VMStack".equals(trace.getClassName()) && "getThreadStackTrace".equals(trace.getMethodName())) {
continue;
}
if ("java.lang.Thread".equals(trace.getClassName()) && "getStackTrace".equals(trace.getMethodName())) {
continue;
}
builder.append(trace.getClassName()).append("#").append(trace.getMethodName()).append("#").append(trace.getLineNumber()).append("\n");
}
builder.setLength(builder.length() - 1);
Log.w("HookHandler", "jank detected:" + builder);
Log.w("HookHandler", "Jank detected:" + builder);
linkedLog(type, builder.toString());
}
}
if ("onMonitorExit".equals(methodName)) {
this.monitor.remove();
holderDesc = null;
}
} else {
startTime.set(SystemClock.elapsedRealtime());
}
} else {
if (type == Type.SYNCHRONIZED_LOCK) {
if ("onMonitorBefore".equals(methodName)) {
if (objects.length > 0) {
this.monitor.set(objects[0]);
}
}
if ("onMonitorEnter".equals(methodName)) {
holder.set(Thread.currentThread());
}
if ("onMonitorExit".equals(methodName)) {
this.monitor.remove();
holder.set(null);
}
}
}
}
@@ -122,25 +159,38 @@ public class HookHandler implements IHookInvoker {
builder.setLength(builder.length() - 1);
builder.append(")");
}
builder.append("#").append(delta);
if (type == Type.AQS_LOCK) {
builder.append("\n");
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement trace: stackTrace) {
if ("dalvik.system.VMStack".equals(trace.getClassName()) && "getThreadStackTrace".equals(trace.getMethodName())) {
continue;
}
if ("java.lang.Thread".equals(trace.getClassName()) && "getStackTrace".equals(trace.getMethodName())) {
continue;
}
builder.append(trace.getClassName()).append("#").append(trace.getMethodName()).append("#").append(trace.getLineNumber()).append("\n");
}
builder.setLength(builder.length() - 1);
}
Log.w("HookHandler", "jank detected:" + builder);
Log.w("HookHandler", "Jank Detected:" + builder);
linkedLog(type, builder.toString());
}
}
}
}
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

@@ -3,6 +3,7 @@ package com.mogo.launcher.startup
import android.app.Application
import com.alibaba.android.arouter.launcher.ARouter
import com.mogo.commons.debug.DebugConfig
import com.mogo.eagle.core.function.main.threadopt.ThreadOptInitializer
import com.mogo.eagle.core.utilcode.util.AppUtils
import com.mogo.eagle.core.utilcode.util.CleanUtils
import java.lang.Exception
@@ -17,6 +18,7 @@ object ARouterStartUp {
}
// 初始化 arouter
ARouter.init(app)
ThreadOptInitializer.aRouterInit.set(true)
} catch (e: Exception) {
e.printStackTrace()
// 由于ARouter会在SP_AROUTER_CACHE.xml缓存路由表如果出现了被删除的情况会报错这里清除下就好了