diff --git a/app/src/main/java/com/mogo/launcher/lancet/MainBlockCheck.kt b/app/src/main/java/com/mogo/launcher/lancet/MainBlockCheck.kt index 3a8868bd92..8fd39e4280 100644 --- a/app/src/main/java/com/mogo/launcher/lancet/MainBlockCheck.kt +++ b/app/src/main/java/com/mogo/launcher/lancet/MainBlockCheck.kt @@ -8,8 +8,8 @@ import android.os.Handler.Callback import android.util.* import android.view.* import androidx.annotation.* -import androidx.collection.ArrayMap import androidx.core.os.HandlerCompat +import androidx.core.util.Pools import com.knightboost.lancet.api.* import com.knightboost.lancet.api.Scope.ALL import com.knightboost.lancet.api.Scope.LEAF @@ -36,7 +36,7 @@ class MainBlockCheck { private const val TAG = "MAIN_BLOCK_CHECK" @JvmStatic - private val tokens = ArrayMap(128) + private val tokens = ConcurrentHashMap>(128) private val pool by lazy { Executors.newFixedThreadPool(1) } @@ -44,7 +44,50 @@ class MainBlockCheck { private val asyncHandlersMap by lazy { ConcurrentHashMap() } - private val whats by lazy { ConcurrentHashMap>() } + private val whats by lazy { ConcurrentHashMap>>() } + + private data class PoolAction(var type: Int, var what: Int, var holder: Holder?, var elapsedTime: Long = -1, var duration:Long = -1): Runnable { + + override fun run() { + try { + val h = holder + if (type == 0 && h != null) { + whats.getOrPut(what) { LinkedList>() }.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() + actionPool.release(this) + } + } + + fun reset() { + type = -1 + what = Int.MIN_VALUE + holder = null + elapsedTime = -1 + duration = -1 + } + } + + private val actionPool by lazy { Pools.SynchronizedPool(500) } + + private fun getAction(): PoolAction = actionPool.acquire() ?: PoolAction(-1, 0, null) @JvmStatic fun getRecorder(): IMessageRecorder? { @@ -86,9 +129,7 @@ class MainBlockCheck { } } finally { val duration = now() - now - pool.execute { - getRecorder()?.recycle(enclose.id, elapsedTime, duration) - } + recycle(enclose, elapsedTime, duration) } true } @@ -115,24 +156,135 @@ class MainBlockCheck { val msg = Message.obtain(newHandler) val what = ObjectHashCodeUtils.getHashCodeIfNeed(newHandler, action) msg.what = what - val holder = Holder.acquire(newHandler, action = action, what = msg.what, isAsync = isAsync) + val holder = Holder.acquire(newHandler, action = action, isAsync = isAsync) msg.obj = holder val inserted = newHandler.sendMessage(msg) if (inserted) { - pool.execute { - whats.getOrPut(what) { LinkedList() }.add(holder) - getRecorder()?.insert(holder) - } + insert(what, holder) } return inserted } - private fun getHandler(isAsync: Boolean): Handler { - return if (isAsync) { - ASYNC_HANDLER - } else { - HANDLER + @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 isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { 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) + if (inserted) { + insert(what, holder) + } + return inserted + } + + @JvmStatic + @TargetClass(value = "android.os.Handler", scope = ALL) + @TargetMethod(methodName = "postAtTime") + @ReplaceInvoke + fun handlerPostDelayProxy2(handler: Handler, action: Runnable, token: Any?, delayMillis: Long): Boolean { + if (Looper.getMainLooper() != handler.looper) { + return HandlerCompat.postDelayed(handler, action, token, delayMillis) + } + val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { 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) + if (inserted) { + insert(what, holder) + } + return inserted + } + + @JvmStatic + @TargetClass(value = "android.os.Handler", scope = ALL) + @TargetMethod(methodName = "postAtFrontOfQueue") + @ReplaceInvoke + fun handlerPostAtFrontOfQueueProxy(handler: Handler, action: Runnable): Boolean { + if (Looper.getMainLooper() != handler.looper) { + return handler.postAtFrontOfQueue(action) + } + val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { 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) + if (inserted) { + insert(what, holder) + } + return inserted + } + + @JvmStatic + @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) { + return handler.postAtTime(action, uptimeMillis) + } + val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { 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) + if (inserted) { + insert(what, holder) + } + return inserted + } + + @JvmStatic + @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) { + return handler.postAtTime(action, uptimeMillis) + } + val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { 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) + if (inserted) { + insert(what, holder) + } + return inserted } @JvmStatic @@ -150,10 +302,7 @@ class MainBlockCheck { msg.obj = holder val inserted = newHandler.sendMessage(msg) if (inserted) { - pool.execute { - whats.getOrPut(what) { LinkedList() }.add(holder) - getRecorder()?.insert(holder) - } + insert(what, holder) } return inserted } @@ -174,10 +323,7 @@ class MainBlockCheck { msg.obj = holder val inserted = newHandler.sendMessageAtTime(msg, uptimeMillis) if (inserted) { - pool.execute { - whats.getOrPut(what) { LinkedList() }.add(holder) - getRecorder()?.insert(holder) - } + insert(what, holder) } return inserted @@ -198,10 +344,7 @@ class MainBlockCheck { msg.obj = holder val inserted = newHandler.sendMessageDelayed(msg, delayMillis) if (inserted) { - pool.execute { - whats.getOrPut(what) { LinkedList() }.add(holder) - getRecorder()?.insert(holder) - } + insert(what, holder) } return inserted } @@ -227,15 +370,12 @@ class MainBlockCheck { newMsg.obj = obj if (oldObj != null) { synchronized(tokens) { - tokens[oldObj] = obj + tokens[oldObj.hashCode()] = WeakReference(obj) } } val inserted = newHandler.sendMessage(newMsg) if (inserted) { - pool.execute { - whats.getOrPut(newMsg.what) { LinkedList() }.add(obj) - getRecorder()?.insert(obj) - } + insert(newMsg.what, obj) } return inserted } @@ -262,15 +402,12 @@ class MainBlockCheck { newMsg.obj = obj if (oldObj != null) { synchronized(tokens) { - tokens[oldObj] = obj + tokens[oldObj.hashCode()] = WeakReference(obj) } } val inserted = newHandler.sendMessageAtTime(newMsg, uptimeMillis) if (inserted) { - pool.execute { - whats.getOrPut(newMsg.what) { LinkedList() }.add(obj) - getRecorder()?.insert(obj) - } + insert(newMsg.what, obj) } return inserted } @@ -296,46 +433,16 @@ class MainBlockCheck { newMsg.obj = obj if (old != null) { synchronized(tokens) { - tokens[old] = obj + tokens[old.hashCode()] = WeakReference(obj) } } val inserted = newHandler.sendMessageAtFrontOfQueue(newMsg) if (inserted) { - pool.execute { - whats.getOrPut(newMsg.what) { LinkedList() }.add(obj) - getRecorder()?.insert(obj) - } + insert(newMsg.what, 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 isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) } - val newHandler = getHandler(isAsync) - val msg = Message.obtain(newHandler) - if (isAsync) { - msg.isAsynchronous = true - } - val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action) - msg.what = what - val holder = Holder.acquire(handler, action = action, delay = delayMillis, what = what, isAsync = isAsync) - msg.obj = holder - val inserted = newHandler.sendMessageDelayed(msg, delayMillis) - if (inserted) { - pool.execute { - whats.getOrPut(what) { LinkedList() }.add(holder) - getRecorder()?.insert(holder) - } - } - return inserted - } @JvmStatic @TargetClass(value = "android.app.Activity", scope = ALL) @@ -349,10 +456,7 @@ class MainBlockCheck { msg.obj = holder val inserted = HANDLER.sendMessage(msg) if (inserted) { - pool.execute { - whats.getOrPut(msg.what) { LinkedList() }.add(holder) - getRecorder()?.insert(holder) - } + insert(what, holder) } } @@ -368,10 +472,7 @@ class MainBlockCheck { msg.obj = holder val inserted = HANDLER.sendMessage(msg) if (inserted) { - pool.execute { - whats.getOrPut(msg.what) { LinkedList() }.add(holder) - getRecorder()?.insert(holder) - } + insert(what, holder) } return inserted } @@ -388,15 +489,11 @@ class MainBlockCheck { msg.obj = holder val inserted = HANDLER.sendMessageDelayed(msg, delayMillis) if (inserted) { - pool.execute { - whats.getOrPut(msg.what) { LinkedList() }.add(holder) - getRecorder()?.insert(holder) - } + insert(what, holder) } return inserted } - @JvmStatic @TargetClass(value = "android.os.Handler", scope = ALL) @TargetMethod(methodName = "removeCallbacks") @@ -407,12 +504,7 @@ class MainBlockCheck { } val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action) getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what) - pool.execute { - val holders = whats.remove(what) - if (!holders.isNullOrEmpty()) { - getRecorder()?.remove(holders) - } - } + remove(what) } @JvmStatic @@ -424,13 +516,8 @@ class MainBlockCheck { return handler.removeCallbacks(action, token) } val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action) - getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what, if (token != null) { synchronized(tokens) { tokens.remove(token) } } else null) - pool.execute { - val holders = whats.remove(what) - if (!holders.isNullOrEmpty()) { - getRecorder()?.remove(holders) - } - } + getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what, if (token != null) { synchronized(tokens) { tokens.remove(token.hashCode())?.get() } } else null) + remove(what) } @JvmStatic @@ -442,12 +529,18 @@ class MainBlockCheck { return handler.removeMessages(what) } getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what) - pool.execute { - val holders = whats.remove(what) - if (!holders.isNullOrEmpty()) { - getRecorder()?.remove(holders) - } - } + remove(what) + } + + @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 } @JvmStatic @@ -458,20 +551,49 @@ class MainBlockCheck { if (Looper.getMainLooper() != handler.looper) { return handler.removeMessages(what, token) } - getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what, if (token != null) synchronized(tokens) { tokens.remove(token) } else null) - pool.execute { - val holders = whats.remove(what) - if (!holders.isNullOrEmpty()) { - getRecorder()?.remove(holders) - } - } + getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what, if (token != null) synchronized(tokens) { tokens.remove(token.hashCode())?.get() } else null) + remove(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) + } + + 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) + } + + fun getHandler(isAsync: Boolean): Handler { + return if (isAsync) { + ASYNC_HANDLER + } else { + HANDLER + } + } } + + @TargetClass(value = "android.view.View", scope = LEAF) @Insert(mayCreateSuper = true) @TargetMethod(methodName = "onMeasure") @@ -498,9 +620,7 @@ class MainBlockCheck { @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") - pool.execute { - getRecorder()?.insert(holder) - } + insert(-1, holder) val now = now() try { Origin.callVoid() @@ -508,9 +628,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - now - pool.execute { - getRecorder()?.recycle(holder.id, 0, spend) - } + recycle(holder, 0, spend) } } @@ -520,9 +638,7 @@ class MainBlockCheck { @TargetMethod(methodName = "onDraw") fun proxyViewOnDraw(canvas: Canvas) { val holder = Holder.acquire(handler = null, obj = "View[${This.get().javaClass.name}]:onDraw") - pool.execute { - getRecorder()?.insert(holder) - } + insert(-1, holder) val now = now() try { Origin.callVoid() @@ -530,9 +646,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - now - pool.execute { - getRecorder()?.recycle(holder.id, 0, spend) - } + recycle(holder, 0, spend) } } @@ -541,7 +655,7 @@ class MainBlockCheck { @TargetMethod(methodName = "onCreate") fun proxyActivityOnCreate(savedInstanceState: Bundle?) { val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onCreate") - getRecorder()?.insert(holder) + insert(-1, holder) val now = now() try { Origin.callVoid() @@ -550,7 +664,7 @@ class MainBlockCheck { } finally { val spend = now() - now CallerDevaToolsManager.block()?.monitor((This.get() as Activity).window) - getRecorder()?.recycle(holder.id, 0, spend) + recycle(holder, 0, spend) } } @@ -559,7 +673,7 @@ class MainBlockCheck { @TargetMethod(methodName = "onStart") fun proxyActivityOnStart() { val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onStart") - getRecorder()?.insert(holder) + insert(-1, holder) val now = now() try { Origin.callVoid() @@ -567,7 +681,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - now - getRecorder()?.recycle(holder.id, 0, spend) + recycle(holder, 0, spend) } } @@ -576,7 +690,7 @@ class MainBlockCheck { @TargetMethod(methodName = "onResume") fun proxyActivityOnResume() { val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onResume") - getRecorder()?.insert(holder) + insert(-1, holder) val now = now() CallerDevaToolsManager.block()?.resume((This.get() as Activity).window) try { @@ -585,7 +699,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - now - getRecorder()?.recycle(holder.id, 0, spend) + recycle(holder, 0, spend) } } @@ -594,7 +708,7 @@ class MainBlockCheck { @TargetMethod(methodName = "onPause") fun proxyActivityOnPause() { val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onPause") - getRecorder()?.insert(holder) + insert(-1, holder) CallerDevaToolsManager.block()?.pause((This.get() as Activity).window) val now = now() try { @@ -603,7 +717,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - now - getRecorder()?.recycle(holder.id, 0, spend) + recycle(holder, 0, spend) } } @@ -624,7 +738,7 @@ class MainBlockCheck { @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) + insert(-1, holder) val startTime = now() try { Origin.callVoid() @@ -632,7 +746,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - startTime - getRecorder()?.recycle(holder.id, 0, spend) + recycle(holder, 0, spend) } } @@ -641,7 +755,7 @@ class MainBlockCheck { @TargetMethod(methodName = "onCreate") fun proxyFragmentOnCreate(savedInstanceState: Bundle?) { val holder = Holder.acquire(handler = null, obj = "Fragment[${This.get().javaClass.name}]:onCreate") - getRecorder()?.insert(holder) + insert(-1, holder) val startTime = now() try { Origin.callVoid() @@ -649,7 +763,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - startTime - getRecorder()?.recycle(holder.id, 0, spend) + recycle(holder, 0, spend) } } @@ -658,7 +772,7 @@ class MainBlockCheck { @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) + insert(-1, holder) val startTime = now() try { Origin.callVoid() @@ -666,7 +780,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - startTime - getRecorder()?.recycle(holder.id, 0, spend) + recycle(holder, 0, spend) } } @@ -675,7 +789,7 @@ class MainBlockCheck { @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) + insert(-1, holder) val startTime = now() try { Origin.callVoid() @@ -683,7 +797,7 @@ class MainBlockCheck { throw t } finally { val spend = now() - startTime - getRecorder()?.recycle(holder.id, 0, spend) + recycle(holder, 0, spend) } } } \ No newline at end of file diff --git a/gradle/bytex/bytex_lancetx.gradle b/gradle/bytex/bytex_lancetx.gradle index ca8aa1f7a4..9beadd492d 100644 --- a/gradle/bytex/bytex_lancetx.gradle +++ b/gradle/bytex/bytex_lancetx.gradle @@ -19,7 +19,7 @@ LancetX { enable true } main_block_check { - enable false + enable true } } }