diff --git a/app/build.gradle b/app/build.gradle index 52431d9da7..ae17181e1d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -214,9 +214,10 @@ dependencies { implementation rootProject.ext.dependencies.android_start_up implementation rootProject.ext.dependencies.lancetx_runtime implementation rootProject.ext.dependencies.lancetx_compiler_lib - //kapt rootProject.ext.dependencies.lancetx_compiler + implementation rootProject.ext.dependencies.handler_proxy_runtime + kapt rootProject.ext.dependencies.lancetx_compiler - //annotationProcessor rootProject.ext.dependencies.lancetx_compiler + annotationProcessor rootProject.ext.dependencies.lancetx_compiler annotationProcessor rootProject.ext.dependencies.google_auto_service kapt rootProject.ext.dependencies.google_auto_service compileOnly rootProject.ext.dependencies.google_auto_service diff --git a/app/matrixTrace/blackMethodList.txt b/app/matrixTrace/blackMethodList.txt index 0f2637b691..1aeba2171b 100644 --- a/app/matrixTrace/blackMethodList.txt +++ b/app/matrixTrace/blackMethodList.txt @@ -5,6 +5,7 @@ -keeppackage com/knightboost/lancet/api/synchronized_lock/ -keeppackage com/mogo/core/lancetx/compiler/lib/ -keeppackage com/mogo/eagle/core/lancetx/generated/ +-keeppackage com/mogo/eagle/core/handler/ -keeppackage com/mogo/launcher/lancet/jank/ -keeppackage com/rousetime/android_startup/ -keeppackage com/mogo/systrace/ @@ -22,4 +23,5 @@ -keepclass com.mogo.commons.AbsMogoApplication -keepclass com.bytedance.apm.agent.v2.instrumentation.AppAgent -keepclass com.mogo.eagle.core.utilcode.util.ProcessUtils --keepclass com.mogo.eagle.core.utilcode.mogo.AppLaunchTimeUtils \ No newline at end of file +-keepclass com.mogo.eagle.core.utilcode.mogo.AppLaunchTimeUtils +-keepclass com.mogo.eagle.core.function.main.ARouterUtils \ No newline at end of file diff --git a/app/src/main/java/com/mogo/launcher/lancet/jank/AsyncHandlerReflectLancet.java b/app/src/main/java/com/mogo/launcher/lancet/jank/AsyncHandlerReflectLancet.java deleted file mode 100644 index c8d9a89439..0000000000 --- a/app/src/main/java/com/mogo/launcher/lancet/jank/AsyncHandlerReflectLancet.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.mogo.launcher.lancet.jank; - -import android.os.Build; -import android.os.Handler; -import android.os.Looper; - -import androidx.annotation.Keep; - -import com.knightboost.lancet.api.Scope; -import com.knightboost.lancet.api.annotations.Group; -import com.knightboost.lancet.api.annotations.ReplaceInvoke; -import com.knightboost.lancet.api.annotations.TargetClass; -import com.knightboost.lancet.api.annotations.TargetMethod; -import com.knightboost.lancet.api.annotations.Weaver; - -import java.lang.ref.WeakReference; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.concurrent.CopyOnWriteArraySet; - - -@Keep -@Weaver -@Group("main_block_check") -public class AsyncHandlerReflectLancet { - - - @TargetClass(value = "java.lang.reflect.Method",scope = Scope.SELF) - @TargetMethod(methodName = "invoke") - @ReplaceInvoke - public static Object hookMethodInvoke(Method method, Object obj, Object... args) throws InvocationTargetException, IllegalAccessException { - Object ret = method.invoke(obj, args); - if (ret instanceof Handler && "createAsync".equals(method.getName())) { - CopyOnWriteArraySet> asyncHandlers = MainBlockCheck.Companion.getAsyncHandlers(); - asyncHandlers.add(new WeakReference<>((Handler) ret)); - } - return ret; - } - - - @TargetClass(value = "android.os.Handler",scope = Scope.SELF) - @TargetMethod(methodName = "createAsync") - @ReplaceInvoke(isStatic = true) - public static Handler createAsync(Looper looper) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - Handler handler = Handler.createAsync(looper); - CopyOnWriteArraySet> asyncHandlers = MainBlockCheck.Companion.getAsyncHandlers(); - asyncHandlers.add(new WeakReference<>(handler)); - return handler; - } else { - return new Handler(looper); - } - } - - @TargetClass(value = "android.os.Handler",scope = Scope.SELF) - @TargetMethod(methodName = "createAsync") - @ReplaceInvoke(isStatic = true) - public static Handler createAsync(Looper looper, Handler.Callback callback) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - Handler handler = Handler.createAsync(looper, callback); - CopyOnWriteArraySet> asyncHandlers = MainBlockCheck.Companion.getAsyncHandlers(); - asyncHandlers.add(new WeakReference<>(handler)); - return handler; - } else { - return new Handler(looper, callback); - } - } -} diff --git a/app/src/main/java/com/mogo/launcher/lancet/jank/MainBlockCheck.kt b/app/src/main/java/com/mogo/launcher/lancet/jank/MainBlockCheck.kt deleted file mode 100644 index a6e52577db..0000000000 --- a/app/src/main/java/com/mogo/launcher/lancet/jank/MainBlockCheck.kt +++ /dev/null @@ -1,705 +0,0 @@ -package com.mogo.launcher.lancet.jank - -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.* -import androidx.annotation.* -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 -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.Runnable -import java.lang.ref.WeakReference -import java.util.concurrent.* -import java.util.concurrent.locks.ReentrantReadWriteLock -import kotlin.concurrent.withLock -import com.mogo.eagle.core.block.runtime.message.Message as Holder - -@Keep -@Weaver -@Group("main_block_check") -class MainBlockCheck { - - companion object { - - private const val TAG = "MAIN_BLOCK_CHECK" - - private val handlerTokens by lazy { ConcurrentHashMap>() } - - private val pool by lazy { Pools.SimplePool(50) } - - private val actions by lazy { ConcurrentHashMap() } - - private val lock by lazy { ReentrantReadWriteLock() } - - val asyncHandlers by lazy { CopyOnWriteArraySet>() } - - private val handlers by lazy { ConcurrentHashMap() } - - private val handlerWhats by lazy { ConcurrentHashMap>() } - - 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() - } - } - - - @JvmStatic - fun getRecorder(): IMessageRecorder? { - val block = CallerDevaToolsManager.block() - if (block == null || !block.hasInit()) { - return null - } - return block.recorder() - } - - @JvmStatic val callback by lazy { - Callback { msg -> - val enclose = msg.obj as? Holder - if (enclose == null) { - Log.w(TAG, "--- handleMessage --- 1 ---") - return@Callback true - } - - if (!enclose.isValid()) { - Log.w(TAG, "--- handleMessage --- 2 ---:$enclose") - return@Callback true - } - val h = enclose.handler - val action = enclose.action - val oldMsg = enclose.origin - val oldObj = enclose.obj - val start = now() - try { - if (action != null) { - action.run() - } else { - if (oldMsg == null) { - h?.dispatchMessage(msg) - } else { - 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, "msg: $enclose", t) - throw t - } finally { - 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(main, callback) - } - - @JvmStatic val HANDLER by lazy { - Handler(main, callback) - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "post") - @ReplaceInvoke - fun handlerPost(handler: Handler, action: Runnable): Boolean { - if (main != handler.looper) { - return handler.post(action) - } - 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) { - getRecorder()?.insert(holder) - } else { - actions.remove(action) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "postDelayed") - @ReplaceInvoke - fun handlerPostDelay(handler: Handler, action: Runnable, delayMillis: Long): Boolean { - if (main != handler.looper) { - return handler.postDelayed(action, 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) { - getRecorder()?.insert(holder) - } else { - actions.remove(action) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "postDelayed") - @ReplaceInvoke - fun handlerPostDelayWithToken(handler: Handler, action: Runnable, token: Any?, delayMillis: Long): Boolean { - if (main != handler.looper) { - return HandlerCompat.postDelayed(handler, 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) { - getRecorder()?.insert(holder) - } else { - actions.remove(action) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "postAtFrontOfQueue") - @ReplaceInvoke - fun handlerPostAtFrontOfQueue(handler: Handler, action: Runnable): Boolean { - if (main != handler.looper) { - return handler.postAtFrontOfQueue(action) - } - 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) { - getRecorder()?.insert(holder) - } else { - actions.remove(action) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "postAtTime") - @ReplaceInvoke - fun handlerPostAtTime(handler: Handler, action: Runnable, uptimeMillis: Long): Boolean { - if (main != handler.looper) { - return handler.postAtTime(action, uptimeMillis) - } - val delta = uptimeMillis - SystemClock.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) { - getRecorder()?.insert(holder) - } else { - actions.remove(action) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "postAtTime") - @ReplaceInvoke - fun handlerPostAtTimeWithToken(handler: Handler, action: Runnable, token: Any?, uptimeMillis: Long): Boolean { - if (main != handler.looper) { - return handler.postAtTime(action, uptimeMillis) - } - val delta = uptimeMillis - SystemClock.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) { - getRecorder()?.insert(holder) - } else { - actions.remove(action) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "sendEmptyMessage") - @ReplaceInvoke - fun handlerSendEmptyMessage(handler: Handler, what: Int): Boolean { - if (main != handler.looper) { - return handler.sendEmptyMessage(what) - } - 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) { - handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(what) - getRecorder()?.insert(holder) - } else { - handlerTokens[tokenKey]?.remove(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 (main != handler.looper) { - return handler.sendEmptyMessageAtTime(what, uptimeMillis) - } - 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) { - handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(what) - getRecorder()?.insert(holder) - } else { - handlerTokens[tokenKey]?.remove(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 (main != handler.looper) { - return handler.sendEmptyMessageDelayed(what, delayMillis) - } - 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) { - handlerWhats.getOrPut(key) { CopyOnWriteArraySet() }.add(what) - getRecorder()?.insert(holder) - } else { - handlerTokens[tokenKey]?.remove(holder) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "sendMessage") - @ReplaceInvoke - fun handlerSendMessage(handler: Handler, msg: Message): Boolean { - if (main != handler.looper) { - return handler.sendMessage(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) { - 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) - } - if (inserted) { - 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 = "sendMessageAtTime") - @ReplaceInvoke - fun handlerSendMessageAtTime(handler: Handler, msg: Message, uptimeMillis: Long): Boolean { - if (main != handler.looper) { - return handler.sendMessageAtTime(msg, uptimeMillis) - } - val tokenKey = generateKey(handler, msg.what) - val key = handler.hashCode() - val isAsync = handlers.getOrPut(key) { computeIsAsyncHandler(handler) } - val action = msg.callback - val delta = uptimeMillis - SystemClock.uptimeMillis() - 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) - } - if (inserted) { - 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 = "sendMessageAtFrontOfQueue") - @ReplaceInvoke - fun handlerSendMessageAtFrontOfQueue(handler: Handler, msg: Message): Boolean { - if (main != handler.looper) { - return handler.sendMessageAtFrontOfQueue(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) { - 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) - } - if (inserted) { - 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 runOnUiThreadOfActivity(activity: Activity, action: Runnable) { - val holder = Holder.acquire(null, action = action) - try { - activity.runOnUiThread(acquireAction(holder, action)) - } finally { - getRecorder()?.insert(holder) - } - } - - @JvmStatic - @TargetClass(value = "android.view.View", scope = ALL) - @TargetMethod(methodName = "post") - @ReplaceInvoke - 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) { - getRecorder()?.insert(holder) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.view.View", scope = ALL) - @TargetMethod(methodName = "postDelayed") - @ReplaceInvoke - 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) { - getRecorder()?.insert(holder) - } - return inserted - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "removeCallbacks") - @ReplaceInvoke - fun handlerRemoveCallbacks(handler: Handler, action: Runnable) { - if (main != handler.looper) { - return handler.removeCallbacks(action) - } - val existed = actions.remove(action) - if (existed != null) { - try { - handler.removeCallbacks(existed) - } finally { - getRecorder()?.remove(existed.msg) - } - } - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "removeCallbacks") - @ReplaceInvoke - fun handlerRemoveCallbacksWithToken(handler: Handler, action: Runnable, token: Any?) { - if (main != handler.looper) { - return handler.removeCallbacks(action, token) - } - val existed = actions.remove(action) - if (existed != null) { - try { - handler.removeCallbacks(existed, token) - } finally { - getRecorder()?.remove(existed.msg) - } - } - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "removeMessages") - @ReplaceInvoke - fun handlerRemoveMessages(handler: Handler, what: Int) { - if (main != handler.looper) { - return handler.removeMessages(what) - } - val newHandler = getHandler(handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }) - val tokens = handlerTokens.remove(generateKey(handler, what)) - if (!tokens.isNullOrEmpty()) { - val snapshot = ArrayList(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 exist = actions.remove(action) - if (exist != null) { - try { - return view.removeCallbacks(exist) - } finally { - getRecorder()?.remove(exist.msg) - } - } - return false - } - - @JvmStatic - @TargetClass(value = "android.os.Handler", scope = ALL) - @TargetMethod(methodName = "removeMessages") - @ReplaceInvoke - fun handlerRemoveMessagesWithToken(handler: Handler, what: Int, token: Any?) { - if (main != handler.looper) { - return handler.removeMessages(what, token) - } - val newHandler = getHandler(handlers.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }) - val tokens = handlerTokens.remove(generateKey(handler, what)) - if (!tokens.isNullOrEmpty()) { - val snapshot = ArrayList(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 - } - - private fun getHandler(isAsync: Boolean): Handler { - return if (isAsync) { - ASYNC_HANDLER - } else { - HANDLER - } - } - } - - @TargetClass(value = "android.app.Activity", scope = LEAF) - @Insert(mayCreateSuper = true) - @TargetMethod(methodName = "onCreate") - fun proxyActivityOnCreate(savedInstanceState: Bundle?) { - try { - Origin.callVoid() - } finally { - CallerDevaToolsManager.block()?.monitor((This.get() as Activity).window) - } - } - - - @TargetClass(value = "android.app.Activity", scope = LEAF) - @Insert(mayCreateSuper = true) - @TargetMethod(methodName = "onResume") - fun proxyActivityOnResume() { - try { - Origin.callVoid() - } finally { - CallerDevaToolsManager.block()?.resume((This.get() as Activity).window) - } - } - - @TargetClass(value = "android.app.Activity", scope = LEAF) - @Insert(mayCreateSuper = true) - @TargetMethod(methodName = "onPause") - fun proxyActivityOnPause() { - try { - Origin.callVoid() - } finally { - CallerDevaToolsManager.block()?.pause((This.get() as Activity).window) - } - } - - @TargetClass(value = "android.app.Activity", scope = LEAF) - @Insert(mayCreateSuper = true) - @TargetMethod(methodName = "onDestroy") - fun proxyActivityOnDestroy() { - try { - Origin.callVoid() - } finally { - CallerDevaToolsManager.block()?.pop((This.get() as Activity).window) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/mogo/launcher/lancet/jank/compiler/JankPointAutoGenerator.java b/app/src/main/java/com/mogo/launcher/lancet/jank/compiler/JankPointAutoGenerator.java index 57a886fb69..45456f0781 100644 --- a/app/src/main/java/com/mogo/launcher/lancet/jank/compiler/JankPointAutoGenerator.java +++ b/app/src/main/java/com/mogo/launcher/lancet/jank/compiler/JankPointAutoGenerator.java @@ -8,6 +8,7 @@ import android.app.Service; import android.content.BroadcastReceiver; import android.content.ContentProvider; import android.content.pm.PackageManager; +import android.opengl.GLSurfaceView; import android.os.SystemClock; import android.view.View; import android.view.ViewManager; @@ -29,18 +30,14 @@ class JankPointAutoGenerator { @LancetXGenerator( group = "main_block_check", type = Type.IPC, - hookAllPublicMethods = true, - excludeHookMethodNames = { "toString", "hashCode" }, - excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" } + hookAllPublicMethods = true ) private ActivityManager am; @LancetXGenerator( group = "main_block_check", type = Type.IPC, - hookAllPublicMethods = true, - excludeHookMethodNames = { "toString", "hashCode" }, - excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" } + hookAllPublicMethods = true ) private PackageManager pm; @@ -51,8 +48,28 @@ class JankPointAutoGenerator { hookAllPublicMethods = true, scope = Scope.LEAF, hookType = HookType.AROUND, - excludeHookMethodNames = { "runOnUiThread", "toString", "hashCode", "onPictureInPictureUiStateChanged", "enterPictureInPictureMode", "setPictureInPictureParams" }, - excludeHookMethodDescs = { "(Ljava/lang/Runnable;)V", "()Ljava/lang/String;", "()I", "(Landroid/app/PictureInPictureUiState;)V", "(Landroid/app/PictureInPictureParams;)Z", "(Landroid/app/PictureInPictureParams;)V" } + onlyHookMethodNames = { + "onCreate", + "onStart", + "onResume", + "onPause", + "onStop", + "onDestroy", + "onWindowFocusChanged", + "dispatchKeyEvent", + "dispatchTouchEvent" + }, + onlyHookMethodDescs = { + "(Landroid/os/Bundle;)V", + "()V", + "()V", + "()V", + "()V", + "()V", + "(Z)V", + "(Landroid/view/KeyEvent;)Z", + "(Landroid/view/MotionEvent;)Z" + } ) private Activity activity; @@ -63,8 +80,12 @@ class JankPointAutoGenerator { hookType = HookType.AROUND, hookAllPublicMethods = true, scope = Scope.LEAF, - excludeHookMethodNames = { "toString", "hashCode" }, - excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" } + onlyHookMethodNames = { + "onReceive" + }, + onlyHookMethodDescs = { + "(Landroid/content/Context;Landroid/content/Intent;)V" + } ) private BroadcastReceiver receiver; @@ -75,8 +96,26 @@ class JankPointAutoGenerator { hookType = HookType.AROUND, hookAllPublicMethods = true, scope = Scope.LEAF, - excludeHookMethodNames = { "toString", "hashCode" }, - excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" } + onlyHookMethodNames = { + "attachInfo", + "onCreate", + "query", + "getType", + "insert", + "update", + "delete", + "openFile" + }, + onlyHookMethodDescs = { + "(Landroid/content/Context;Landroid/content/pm/ProviderInfo;)V", + "()Z", + "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;", + "(Landroid/net/Uri;)Ljava/lang/String;", + "(Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;", + "(Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I", + "(Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I", + "(Landroid/net/Uri;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;" + } ) private ContentProvider provider; @@ -87,8 +126,32 @@ class JankPointAutoGenerator { mayCreateSuper = true, hookType = HookType.AROUND, scope = Scope.LEAF, - excludeHookMethodNames = { "toString", "hashCode" }, - excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" } + onlyHookMethodNames = { + "onCreate", + "onStart", + "onStartCommand", + "onDestroy", + "onConfigurationChanged", + "onLowMemory", + "onTrimMemory", + "onBind", + "onUnbind", + "onRebind", + "onTaskRemoved" + }, + onlyHookMethodDescs = { + "()V", + "(Landroid/content/Intent;I)V", + "(Landroid/content/Intent;II)I", + "()V", + "(Landroid/content/res/Configuration;)V", + "()V", + "(I)V", + "(Landroid/content/Intent;)Landroid/os/IBinder;", + "(Landroid/content/Intent;)Z", + "(Landroid/content/Intent;)V", + "(Landroid/content/Intent;)V", + } ) private Service service; @@ -106,8 +169,24 @@ class JankPointAutoGenerator { group = "main_block_check", type = Type.SLEEP, scope = Scope.ALL, - onlyHookMethodNames = { "sleep", "sleep"}, - onlyHookMethodDescs = { "(J)V", "(JI)V"} + onlyHookMethodNames = { + "sleep", + "sleep", + "join", + "join", + "join", + "getStackTrace", + "getAllStackTraces" + }, + onlyHookMethodDescs = { + "(J)V", + "(JI)V", + "(J)V", + "(JI)V", + "()V", + "()[Ljava/lang/StackTraceElement;", + "()Ljava/util/Map;" + } ) private Thread thread; @@ -118,9 +197,7 @@ class JankPointAutoGenerator { hookType = HookType.AROUND, scope = Scope.LEAF, mayCreateSuper = true, - hookAllPublicMethods = true, - excludeHookMethodNames = { "toString", "hashCode" }, - excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" } + hookAllPublicMethods = true ) private ISynchronizedLockHooker synchronizedLock; @@ -129,9 +206,7 @@ class JankPointAutoGenerator { group = "main_block_check", type = Type.PARK, scope = Scope.ALL, - hookAllPublicMethods = true, - excludeHookMethodNames = { "unpark", "getBlocker", "toString", "hashCode" }, - excludeHookMethodDescs = { "(Ljava/lang/Thread;)V", "(Ljava/lang/Thread;)Ljava/lang/Object;", "()Ljava/lang/String;", "()I"} + hookAllPublicMethods = true ) private LockSupport park; @@ -165,9 +240,44 @@ class JankPointAutoGenerator { hookType = HookType.AROUND, mayCreateSuper = true, hookAllPublicMethods = true, - excludeHookMethodNames = { "toString", "hashCode" }, - excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" } - + onlyHookMethodNames = { + "onAttach", + "onCreate", + "onCreateView", + "onViewCreated", + "onActivityCreated", + "onViewStateRestored", + "onStart", + "onResume", + "onSaveInstanceState", + "onConfigurationChanged", + "onPause", + "onStop", + "onLowMemory", + "onTrimMemory", + "onDestroyView", + "onDestroy", + "onDetach", + }, + onlyHookMethodDescs = { + "(Landroid/content/Context;)V", + "(Landroid/os/Bundle;)", + "(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;Landroid/os/Bundle;)Landroid/view/View;", + "(Landroid/view/View;Landroid/os/Bundle;)V", + "(Landroid/os/Bundle;)V", + "(Landroid/os/Bundle;)V", + "()V", + "()V", + "(Landroid/os/Bundle;)V", + "(Landroid/content/res/Configuration;)V", + "()V", + "()V", + "()V", + "(I)V", + "()V", + "()V", + "()V", + } ) private Fragment systemFragment; @@ -178,8 +288,42 @@ class JankPointAutoGenerator { hookType = HookType.AROUND, mayCreateSuper = true, hookAllPublicMethods = true, - excludeHookMethodNames = { "toString", "hashCode" }, - excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" } + onlyHookMethodNames = { + "onAttach", + "onCreate", + "onCreateView", + "onViewCreated", + "onActivityCreated", + "onViewStateRestored", + "onStart", + "onResume", + "onSaveInstanceState", + "onConfigurationChanged", + "onPause", + "onStop", + "onLowMemory", + "onDestroyView", + "onDestroy", + "onDetach", + }, + onlyHookMethodDescs = { + "(Landroid/content/Context;)V", + "(Landroid/os/Bundle;)", + "(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;Landroid/os/Bundle;)Landroid/view/View;", + "(Landroid/view/View;Landroid/os/Bundle;)V", + "(Landroid/os/Bundle;)V", + "(Landroid/os/Bundle;)V", + "()V", + "()V", + "(Landroid/os/Bundle;)V", + "(Landroid/content/res/Configuration;)V", + "()V", + "()V", + "()V", + "()V", + "()V", + "()V", + } ) private androidx.fragment.app.Fragment androidxFragment; @@ -234,4 +378,20 @@ class JankPointAutoGenerator { } ) private ViewManager manager; + + + @LancetXGenerator( + group = "main_block_check", + type = Type.OTHER, + scope = Scope.LEAF, + mayCreateSuper = true, + hookType = HookType.AROUND, + onlyHookMethodNames = { + "onDrawFrame" + }, + onlyHookMethodDescs = { + "(Ljavax/microedition/khronos/opengles/GL10;)V" + } + ) + private GLSurfaceView.Renderer renderer; } diff --git a/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HandlerHookerImpl.kt b/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HandlerHookerImpl.kt new file mode 100644 index 0000000000..d2f6b9fbaa --- /dev/null +++ b/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HandlerHookerImpl.kt @@ -0,0 +1,146 @@ +package com.mogo.launcher.lancet.jank.spi + +import android.os.Handler +import android.os.Looper +import android.os.Message +import android.os.SystemClock +import com.google.auto.service.AutoService +import com.mogo.eagle.core.block.runtime.config.recorder.IMessageRecorder +import com.mogo.eagle.core.block.runtime.utils.TimeUtils.Companion.now +import com.mogo.eagle.core.function.api.devatools.perf.IMoGoCpuUsageProvider +import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager +import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager.block +import com.mogo.eagle.core.function.main.ARouterUtils +import com.mogo.eagle.core.handler.loader.IHandlerHooker +import com.mogo.eagle.core.block.runtime.message.Message as Msg + +@AutoService(IHandlerHooker::class) +class HandlerHookerImpl : IHandlerHooker { + + private val mainLooper = Looper.getMainLooper() + + private var recorder: IMessageRecorder? = null + + private var usage: IMoGoCpuUsageProvider? = null + + private var dispatchTime = 0L + + override fun onMessageDispatchAfter(msg: Message) { + if (msg.target.looper != mainLooper) { + return + } + if (dispatchTime <= 0) { + return + } + val duration = now() - dispatchTime + checkIfNeed(msg.target)?.recycle(Msg.acquire(msg.target, msg = msg, duration = duration, elapsed = SystemClock.uptimeMillis() - msg.`when`, enqueue = msg.`when`)) + } + + override fun onMessageDispatchBefore(msg: Message) { + if (msg.target.looper != mainLooper) { + return + } + dispatchTime = now() + } + + override fun onRemoveCallbacks(handler: Handler, action: Runnable) { + checkIfNeed(handler)?.remove(Msg.acquire(handler, action = action)) + } + + override fun onRemoveCallbacksAndMessages(handler: Handler, token: Any?) { + checkIfNeed(handler)?.remove(Msg.acquire(handler, obj = token)) + } + + override fun onRemoveCallbacksWithToken(handler: Handler, action: Runnable, token: Any?) { + checkIfNeed(handler)?.remove(Msg.acquire(handler, action = action, obj = token)) + } + + override fun onRemoveMessages(handler: Handler, what: Int) { + checkIfNeed(handler)?.remove(Msg.acquire(handler, what = what)) + } + + override fun onRemoveMessages(handler: Handler, what: Int, obj: Any?) { + checkIfNeed(handler)?.remove(Msg.acquire(handler, what = what, obj = obj)) + } + + override fun onPost(handler: Handler, action: Runnable) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, action = action)) + } + + override fun onPostAtFrontQueue(handler: Handler, action: Runnable) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, action = action)) + } + + override fun onPostAtTime(handler: Handler, action: Runnable, token: Any?, uptimeMillis: Long) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, action = action, obj = token, delay = uptimeMillis - SystemClock.uptimeMillis())) + } + + override fun onPostAtTime(handler: Handler, action: Runnable, uptimeMillis: Long) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, action = action, delay = uptimeMillis - SystemClock.uptimeMillis())) + } + + override fun onPostDelayed(handler: Handler, action: Runnable, token: Any?, delayMillis: Long) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, action = action, obj = token, delay = delayMillis)) + } + + override fun onPostDelayed(handler: Handler, action: Runnable, delayMillis: Long) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, action = action, delay = delayMillis)) + } + + + override fun onSendEmptyMessage(handler: Handler, what: Int) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, what = what)) + } + + override fun onSendEmptyMessageAtTime(handler: Handler, what: Int, uptimeMillis: Long) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, what = what, delay = uptimeMillis - SystemClock.uptimeMillis())) + } + + override fun onSendEmptyMessageDelayed(handler: Handler, what: Int, delayMillis: Long) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, what = what, delay = delayMillis)) + } + + override fun onSendMessage(handler: Handler, msg: Message) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, msg, what = msg.what)) + } + + override fun onSendMessageAtFrontOfQueue(handler: Handler, msg: Message) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, msg, what = msg.what)) + } + + override fun onSendMessageAtTime(handler: Handler, msg: Message, uptimeMillis: Long) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, msg = msg, delay = uptimeMillis - SystemClock.uptimeMillis())) + } + + override fun onSendMessageDelayed(handler: Handler, msg: Message, delayMillis: Long) { + checkIfNeed(handler)?.insert(Msg.acquire(handler, msg = msg, delay = delayMillis)) + } + + private fun checkIfNeed(handler: Handler?): IMessageRecorder? { + var usage = this.usage + if (usage == null && ARouterUtils.isInit.get()) { + usage = CallerDevaToolsManager.usage() + this.usage = usage + } + if (handler != null) { + if (handler.looper != mainLooper) { + usage?.updateOtherThreadTime() + } else { + usage?.updateMainThreadTime() + } + } + if (handler != null && handler.looper != mainLooper) { + return null + } + if (recorder == null) { + val hasInit = ARouterUtils.isInit.get() + if (hasInit && recorder == null) { + val block = block() + if (block != null && block.hasInit()) { + recorder = block.recorder() + } + } + } + return recorder + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HookHandler.java b/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HookHandler.java deleted file mode 100644 index 48c4aacbec..0000000000 --- a/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HookHandler.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.mogo.launcher.lancet.jank.spi; -import android.os.Looper; -import android.os.SystemClock; -import android.util.Log; -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.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - - -@AutoService(IHookInvoker.class) -public class HookHandler implements IHookInvoker { - - private final Looper mainLooper = Looper.getMainLooper(); - - - private final AtomicLong startTime = new AtomicLong(0L); - - private final AtomicLong syncLockStartTime = new AtomicLong(0L); - - private final ThreadLocal message = new ThreadLocal<>(); - - private final ThreadLocal monitor = new ThreadLocal<>(); - - private final AtomicReference 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(); - if (elapsedTime >= 10) { - StringBuilder builder = message.get(); - if (builder == null) { - builder = new StringBuilder(); - message.set(builder); - } - if (builder.length() > 0) { - builder.setLength(0); - } - builder - .append(type) - .append("#") - .append(caller == null ? "caller is null" : caller.getClass().getSimpleName()) - .append("#") - .append(methodName); - if (objects.length > 0) { - builder.append("#("); - } - for (Object o : objects) { - if (o == null) { - continue; - } - builder.append(o.getClass().getSimpleName()) - .append(","); - } - - if (objects.length > 0) { - 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) { - 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); - 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); - } - } - } - } - - @Override - public void o(@NonNull Type type, Object caller, @NonNull String methodName, @NonNull Object... objects) { - if (type != Type.SYNCHRONIZED_LOCK && Looper.myLooper() == mainLooper) { - long startTime = this.startTime.get(); - if (startTime > 0) { - long delta = SystemClock.elapsedRealtime() - startTime; - if (delta >= 10) { - StringBuilder builder = message.get(); - if (builder == null) { - builder = new StringBuilder(); - message.set(builder); - } - if (builder.length() > 0) { - builder.setLength(0); - } - builder - .append(type) - .append("#") - .append(caller == null ? "caller is null" : caller.getClass().getSimpleName()) - .append("#") - .append(methodName); - if (objects.length > 0) { - builder.append("#("); - } - for (Object o : objects) { - if (o == null) { - continue; - } - builder.append(o.getClass().getSimpleName()) - .append(","); - } - - if (objects.length > 0) { - 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) { - 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); - - 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) {} -} diff --git a/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HookInvokerImpl.java b/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HookInvokerImpl.java new file mode 100644 index 0000000000..677dc966ab --- /dev/null +++ b/app/src/main/java/com/mogo/launcher/lancet/jank/spi/HookInvokerImpl.java @@ -0,0 +1,277 @@ +package com.mogo.launcher.lancet.jank.spi; +import android.app.Activity; +import android.os.Looper; +import android.os.SystemClock; +import android.util.Log; +import com.google.auto.service.AutoService; +import com.mogo.core.lancetx.compiler.lib.generator.Type; +import com.mogo.core.lancetx.compiler.lib.hook.IHookInvoker; +import com.mogo.eagle.core.data.deva.chain.ChainConstant; +import com.mogo.eagle.core.function.api.devatools.block.IMoGoBlockProvider; +import com.mogo.eagle.core.function.api.devatools.perf.IMoGoCpuUsageProvider; +import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager; +import com.mogo.eagle.core.function.main.ARouterUtils; +import com.zhjt.service.chain.ChainLog; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + + +@AutoService(IHookInvoker.class) +public class HookInvokerImpl implements IHookInvoker { + + private final Looper mainLooper = Looper.getMainLooper(); + + private final ThreadLocal startTime = new ThreadLocal<>(); + private final AtomicLong syncLockStartTime = new AtomicLong(0L); + + private final ThreadLocal message = new ThreadLocal<>(); + + private final ThreadLocal monitor = new ThreadLocal<>(); + + private final AtomicReference holder = new AtomicReference<>(); + + private String holderDesc = null; + + private volatile IMoGoCpuUsageProvider provider; + + private volatile boolean getProviderRequested = false; + + private final long logThreshold = 5; //日志打印阈值 + + private final long dumpStackThreshold = 20; // dump堆栈阈值 + + + // 切记: 请勿在此方法中调用其它模块类中的api,可能会出现StackOverFlowException + @Override + public void i(Type type, Object caller,String methodName, Object... objects) { + startTime.set(SystemClock.elapsedRealtime()); + boolean isMainThread = false; + if (mainLooper == Looper.myLooper()) { + isMainThread = true; + if (type == Type.SYNCHRONIZED_LOCK) { + handleSynchronizedLock(Looper.myLooper() == mainLooper, caller, methodName, objects); + } + } + + if (!getProviderRequested && provider == null && mainLooper != Looper.myLooper() && ARouterUtils.isInit.get()) { + getProviderRequested = true; + new Thread(() -> { + try { + provider = CallerDevaToolsManager.INSTANCE.usage(); + } finally { + getProviderRequested = false; + } + }, "getProvider").start(); + } + + if (provider != null) { + if (isMainThread) { + provider.updateMainThreadTime(); + } else { + provider.updateOtherThreadTime(); + } + } + } + + // 切记: 请勿在此方法中调用其它模块类中的api,可能会出现StackOverFlowException + @Override + public void o(Type type, Object caller,String methodName, Object... objects) { + long now = SystemClock.elapsedRealtime(); + Long old = startTime.get(); + long cost = now - (old == null ? now : old); + if (mainLooper == Looper.myLooper() && type != Type.SYNCHRONIZED_LOCK) { + handleCostTimeRecord(type, caller, methodName, cost, objects); + } + if (mainLooper == Looper.myLooper() && type == Type.ACTIVITY) { + handleActivity((Activity) caller, methodName); + } + + if (provider != null) { + if (mainLooper == Looper.myLooper()) { + provider.updateMainThreadTime(); + } else { + provider.updateOtherThreadTime(); + } + } + } + + private void handleCostTimeRecord(Type type, Object caller, String methodName, long cost, Object... args) { + if (cost >= logThreshold) { + StringBuilder builder = message.get(); + if (builder == null) { + builder = new StringBuilder(); + message.set(builder); + } + if (builder.length() > 0) { + builder.setLength(0); + } + builder + .append(type) + .append("#") + .append(caller == null ? "caller is null" : caller.getClass().getSimpleName()) + .append("#") + .append(methodName); + if (args.length > 0) { + builder.append("#("); + } + for (Object o : args) { + if (o == null) { + continue; + } + builder.append(o.getClass().getSimpleName()) + .append(","); + } + + if (args.length > 0) { + builder.setLength(builder.length() - 1); + builder.append(")"); + } + + builder.append("#").append(cost); + if (cost >= dumpStackThreshold) { + builder.append("\n"); + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + for (StackTraceElement trace: stackTrace) { + 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); + linkedLog(type, builder.toString()); + } + } + + + private void handleActivity(Activity caller, String methodName) { + if ("onCreate".equals(methodName)) { + IMoGoBlockProvider block = CallerDevaToolsManager.INSTANCE.block(); + if (block != null && block.hasInit()) { + block.monitor(caller.getWindow()); + } + } + if ("onResume".equals(methodName)) { + IMoGoBlockProvider block = CallerDevaToolsManager.INSTANCE.block(); + if (block != null && block.hasInit()) { + block.resume(caller.getWindow()); + } + } + + if ("onPause".equals(methodName)) { + IMoGoBlockProvider block = CallerDevaToolsManager.INSTANCE.block(); + if (block != null && block.hasInit()) { + block.pause(caller.getWindow()); + } + } + + if ("onDestroy".equals(methodName)) { + IMoGoBlockProvider block = CallerDevaToolsManager.INSTANCE.block(); + if (block != null && block.hasInit()) { + block.pop(caller.getWindow()); + } + } + } + + private void handleSynchronizedLock(boolean isMainThread,Object caller, String methodName, Object [] objects) { + if (isMainThread) { + 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(); + if (elapsedTime >= logThreshold) { + StringBuilder builder = message.get(); + if (builder == null) { + builder = new StringBuilder(); + message.set(builder); + } + if (builder.length() > 0) { + builder.setLength(0); + } + builder + .append(Type.SYNCHRONIZED_LOCK) + .append("#") + .append(caller == null ? "caller is null" : caller.getClass().getSimpleName()) + .append("#") + .append(methodName); + if (objects.length > 0) { + builder.append("#("); + } + for (Object o : objects) { + if (o == null) { + continue; + } + builder.append(o.getClass().getSimpleName()) + .append(","); + } + + if (objects.length > 0) { + 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); + } + + if (elapsedTime >= dumpStackThreshold) { + builder.append("\n"); + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + for (StackTraceElement trace: stackTrace) { + 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); + linkedLog(Type.SYNCHRONIZED_LOCK, builder.toString()); + } + } + if ("onMonitorExit".equals(methodName)) { + this.monitor.remove(); + holderDesc = null; + } + } else { + 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); + } + } + } + + 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) {} +} diff --git a/app/src/main/java/com/mogo/launcher/lancet/jank/ui/UiPostLancet.kt b/app/src/main/java/com/mogo/launcher/lancet/jank/ui/UiPostLancet.kt new file mode 100644 index 0000000000..335759b243 --- /dev/null +++ b/app/src/main/java/com/mogo/launcher/lancet/jank/ui/UiPostLancet.kt @@ -0,0 +1,97 @@ +package com.mogo.launcher.lancet.jank.ui + +import android.app.Activity +import android.view.View +import com.knightboost.lancet.api.Scope +import com.knightboost.lancet.api.annotations.Group +import com.knightboost.lancet.api.annotations.ReplaceInvoke +import com.knightboost.lancet.api.annotations.TargetClass +import com.knightboost.lancet.api.annotations.TargetMethod +import com.knightboost.lancet.api.annotations.Weaver +import com.mogo.eagle.core.block.runtime.message.Message +import com.mogo.eagle.core.block.runtime.utils.TimeUtils.Companion.now +import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager +import java.util.concurrent.ConcurrentHashMap + +@Weaver +@Group("main_block_check") +class UiPostLancet { + + + internal data class ActionWrapper(var action: Runnable): Runnable { + + override fun run() { + val start = now() + try { + action.run() + } finally { + CallerDevaToolsManager.block()?.takeIf { + it.hasInit() + }?.recorder()?.recycle(Message.acquire(handler = null, action = action, duration = now() - start)) + } + } + } + + companion object { + + private val map by lazy { ConcurrentHashMap() } + + @JvmStatic + @TargetClass(value = "android.app.Activity", scope = Scope.ALL) + @TargetMethod(methodName = "runOnUiThread") + @ReplaceInvoke + fun runOnUiThreadOfActivity(activity: Activity, action: Runnable) { + try { + activity.runOnUiThread(ActionWrapper(action).also { map[action] = it }) + } finally { + CallerDevaToolsManager.block()?.takeIf { + it.hasInit() + }?.recorder()?.insert(Message.acquire(handler = null, action = action, extra = mapOf(activity.javaClass.name to "runOnUiThread"))) + } + } + + @JvmStatic + @TargetClass(value = "android.view.View", scope = Scope.ALL) + @TargetMethod(methodName = "post") + @ReplaceInvoke + fun post(view: View, action: Runnable): Boolean { + return try { + view.post(ActionWrapper(action).also { map[action] = it }) + } finally { + CallerDevaToolsManager.block()?.takeIf { + it.hasInit() + }?.recorder()?.insert(Message.acquire(handler = null, action = action, extra = mapOf(view.javaClass.name to "post"))) + } + } + + @JvmStatic + @TargetClass(value = "android.view.View", scope = Scope.ALL) + @TargetMethod(methodName = "postDelayed") + @ReplaceInvoke + fun postDelayed(view: View, action: Runnable, delayMillis: Long): Boolean { + return try { + view.postDelayed(action, delayMillis) + } finally { + CallerDevaToolsManager.block()?.takeIf { + it.hasInit() + }?.recorder()?.insert(Message.acquire(handler = null, action = action, extra = mapOf(view.javaClass.name to "post"))) + } + } + + @JvmStatic + @TargetClass(value = "android.view.View", scope = Scope.ALL) + @TargetMethod(methodName = "removeCallbacks") + @ReplaceInvoke + fun removeCallbacks(view: View, action: Runnable): Boolean { + return try { + view.removeCallbacks(map.remove(action)) + } finally { + CallerDevaToolsManager.block()?.takeIf { + it.hasInit() + }?.recorder()?.remove(Message.acquire(handler = null, action = action, extra = mapOf(view.javaClass.name to "removeCallbacks"))) + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/mogo/launcher/startup/ARouterStartUp.kt b/app/src/main/java/com/mogo/launcher/startup/ARouterStartUp.kt index 0c54a60ac9..5017d5a312 100644 --- a/app/src/main/java/com/mogo/launcher/startup/ARouterStartUp.kt +++ b/app/src/main/java/com/mogo/launcher/startup/ARouterStartUp.kt @@ -3,12 +3,14 @@ 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.function.main.ARouterUtils import com.mogo.eagle.core.utilcode.util.AppUtils import com.mogo.eagle.core.utilcode.util.CleanUtils import java.lang.Exception object ARouterStartUp { + + @JvmStatic fun init(app: Application) { try { @@ -18,7 +20,7 @@ object ARouterStartUp { } // 初始化 arouter ARouter.init(app) - ThreadOptInitializer.aRouterInit.set(true) + ARouterUtils.isInit.set(true) } catch (e: Exception) { e.printStackTrace() // 由于ARouter会在SP_AROUTER_CACHE.xml缓存路由表,如果出现了被删除的情况会报错,这里清除下就好了 diff --git a/build.gradle b/build.gradle index 94bf975c04..e620a0c70a 100644 --- a/build.gradle +++ b/build.gradle @@ -34,10 +34,11 @@ buildscript { classpath "com.mogo.cloud:systrace:${plugin_version}" classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.18' classpath "com.mogo.sticky:service:${plugin_version}" - classpath "io.github.knight-zxw:lancet-plugin:10.50.0" + classpath "io.github.knight-zxw:lancet-plugin:10.60.0" classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.15.0" classpath 'com.mogo.cloud:matrix:1.0.2' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513' + classpath 'com.mogo.eagle.core.handler.proxy:plugin:1.0.0' // classpath 'com.bytedance.btrace:rhea-gradle-plugin:2.0.0' } // 遇无法更新依赖情况(针对Snapshot无法刷新)然后sync project即可,刷新完成注释该代码 diff --git a/config.gradle b/config.gradle index 3bf1982323..6807d55a7d 100644 --- a/config.gradle +++ b/config.gradle @@ -209,9 +209,9 @@ ext { //========================= LancetX =================== lancetx_runtime : "io.github.knight-zxw:lancet-runtime:10.50.0", - lancetx_compiler : "com.mogo.eagle.core.lancetx:compiler:1.0.0", + lancetx_compiler : "com.mogo.eagle.core.lancetx:compiler:1.0.5", - lancetx_compiler_lib : "com.mogo.eagle.core.lancetx:runtime:1.0.0", + lancetx_compiler_lib : "com.mogo.eagle.core.lancetx:runtime:1.0.5", //========================= autosize ====================== androidautoSize : 'com.github.JessYanCoding:AndroidAutoSize:v1.2.1', @@ -228,10 +228,13 @@ ext { passport_secret : "com.zhidaoauto:sdk-java:1.0.5-SNAPSHOT", // 主线程卡顿监测 - block_detector : "com.mogo.eagle.core.block:runtime:10.50.0", + block_detector : "com.mogo.eagle.core.block:runtime:10.60.0", //======================== google auto-service =============== - google_auto_service : "com.google.auto.service:auto-service:1.0-rc7" + google_auto_service : "com.google.auto.service:auto-service:1.0-rc7", + + //======================== handler-proxy-runtime ============== + handler_proxy_runtime : "com.mogo.eagle.core.handler.proxy:runtime:1.0.0" ] android = [ fLauncherApplicationId : "com.mogo.launcher.f", diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/block/MoGoBlockProviderImpl.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/block/MoGoBlockProviderImpl.kt index f5f9ae659f..dcabab0c30 100644 --- a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/block/MoGoBlockProviderImpl.kt +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/block/MoGoBlockProviderImpl.kt @@ -52,13 +52,13 @@ internal class MoGoBlockProviderImpl: IMoGoBlockProvider, IBlockListener { map["pending"] = data[1] ?: emptyList() val cpu = CallerDevaToolsManager.usage()?.dump() if (!cpu.isNullOrEmpty()) { - val mainThreadCpuUsage = cpu.remove("MainThreadCpuUsage") - val processLaunchedTime = cpu.remove("ProcessLaunchedTime") - if (mainThreadCpuUsage != null && processLaunchedTime != null) { - linkedLog.recordCpuUsage(LinkedHashMap().also { - it["MainThread"] = "${ mainThreadCpuUsage * 1.0f * 100 / processLaunchedTime }%" + val mainThreadUsage = cpu.remove("MainThreadUsage") + val processUsage = cpu.remove("ProcessUsage") + if (mainThreadUsage != null && processUsage != null) { + linkedLog.recordCpuUsage(LinkedHashMap().also { itx -> + itx["MainThread"] = "${ "%.2f".format(mainThreadUsage * 1.0f * 100 / processUsage) }% ($mainThreadUsage, $processUsage)" cpu.entries.sortedByDescending { it.value }.forEach { sorted -> - it[sorted.key] = "${ sorted.value * 1.0f * 100 / processLaunchedTime }%" + itx[sorted.key] = "${ "%.2f".format(sorted.value * 1.0f * 100 / processUsage) }% (${sorted.value}, $processUsage)" } }) } diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/perf/MoGoCpuUsageProviderImpl.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/perf/MoGoCpuUsageProviderImpl.kt index 20bcee5eb8..7fbe285425 100644 --- a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/perf/MoGoCpuUsageProviderImpl.kt +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/perf/MoGoCpuUsageProviderImpl.kt @@ -1,5 +1,7 @@ package com.zhjt.mogo_core_function_devatools.perf +import android.os.Debug +import android.os.Looper import android.os.SystemClock import com.mogo.eagle.core.function.api.devatools.perf.IMoGoCpuUsageProvider import java.util.concurrent.locks.ReentrantLock @@ -11,53 +13,67 @@ internal class MoGoCpuUsageProviderImpl: IMoGoCpuUsageProvider { private var mainThreadStartTime : Long = 0L - private var mainThreadLastTime: Long = 0L - private var mainThreadCpuUsage: Long = 0L private val maxSize = 500 - private val map by lazy { LinkedHashMap(0, 0.75f, true) } + private val map = LinkedHashMap(0, 0.75f, true) - private val lock by lazy { ReentrantLock() } + private val lock = ReentrantLock() - private val builder by lazy { ThreadLocal() } + private val builder = ThreadLocal() - override fun onProcessLaunched(time: Long) { - processLaunchTime = time + private val otherThreadLastTime = ThreadLocal() + + private val mainLooper = Looper.getMainLooper() + + override fun onProcessLaunched() { + processLaunchTime = SystemClock.elapsedRealtime() } - override fun startMainThreadTime(time: Long) { - mainThreadStartTime = time + override fun onMainThreadLaunched() { + mainThreadStartTime = Debug.threadCpuTimeNanos() / 1000_000 } - override fun updateMainThreadTime(time: Long) { - if (mainThreadLastTime == 0L) { - mainThreadLastTime = mainThreadStartTime + override fun updateMainThreadTime() { + if (Looper.myLooper() != mainLooper) { + return } - val delta = time - mainThreadLastTime - if (delta > 0) { - mainThreadCpuUsage += delta + if (mainThreadStartTime > 0) { + mainThreadCpuUsage = (Debug.threadCpuTimeNanos() / 1000_000 - mainThreadStartTime) } - mainThreadLastTime = time } - override fun incrementOtherThreadUsage(group: String, t: Thread, usage: Long) { - var builder = builder.get() - if (builder == null) { - builder = StringBuilder(128) - this.builder.set(builder) - } - if (builder.isNotEmpty()) { - builder.setLength(0) - } - builder.append(group).append("@@").append(t.name) - lock.withLock { - while (map.size > maxSize) { - val toEvict = map.entries.iterator().next() - map.remove(toEvict.key) + override fun updateOtherThreadTime() { + var last = otherThreadLastTime.get() + val now = Debug.threadCpuTimeNanos() / 1000_000 + try { + if (last == null) { + last = now + otherThreadLastTime.set(last) } - map[builder.toString()] = map.getOrPut(builder.toString()) { 0 } + usage + val duration = now - last + if (duration < 1) { + return + } + var builder = builder.get() + if (builder == null) { + builder = StringBuilder(128) + this.builder.set(builder) + } + if (builder.isNotEmpty()) { + builder.setLength(0) + } + builder.append(Thread.currentThread().name) + lock.withLock { + while (map.size > maxSize) { + val toEvict = map.entries.iterator().next() + map.remove(toEvict.key) + } + map[builder.toString()] = map.getOrPut(builder.toString()) { 0 } + duration + } + } finally { + otherThreadLastTime.set(now) } } @@ -66,8 +82,8 @@ internal class MoGoCpuUsageProviderImpl: IMoGoCpuUsageProvider { if (map.isNotEmpty()) { val iterator = map.entries.iterator() val rst = LinkedHashMap() - rst["MainThreadCpuUsage"] = mainThreadCpuUsage - rst["ProcessLaunchedTime"] = SystemClock.elapsedRealtimeNanos() - processLaunchTime + rst["MainThreadUsage"] = mainThreadCpuUsage + rst["ProcessUsage"] = SystemClock.elapsedRealtime() - processLaunchTime while (iterator.hasNext()) { val next = iterator.next() rst[next.key] = next.value diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/ARouterUtils.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/ARouterUtils.kt new file mode 100644 index 0000000000..a165c47964 --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/ARouterUtils.kt @@ -0,0 +1,12 @@ +package com.mogo.eagle.core.function.main + +import java.util.concurrent.atomic.AtomicBoolean + +class ARouterUtils { + + companion object { + + @JvmField + var isInit = AtomicBoolean(false) + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/threadopt/ThreadOptInitializer.java b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/threadopt/ThreadOptInitializer.java index 645feaa97a..9e6b9470ab 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/threadopt/ThreadOptInitializer.java +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/threadopt/ThreadOptInitializer.java @@ -1,26 +1,23 @@ package com.mogo.eagle.core.function.main.threadopt; -import android.os.Debug; import android.os.Looper; -import android.os.SystemClock; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.os.HandlerCompat; import com.mogo.eagle.core.function.api.devatools.perf.IMoGoCpuUsageProvider; import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager; +import com.mogo.eagle.core.function.main.ARouterUtils; import com.mogo.thread.opt.core.ThreadManager; import com.mogo.thread.opt.core.annotation.Keep; import com.mogo.thread.opt.core.config.ThreadConfig; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; @Keep public class ThreadOptInitializer { - public static final AtomicBoolean aRouterInit = new AtomicBoolean(false); - private static final ThreadConfig.TaskExecuteListener listener = new ThreadConfig.TaskExecuteListener() { @@ -38,29 +35,29 @@ public class ThreadOptInitializer { @Override public void onExecutorBefore(@NonNull ThreadConfig.TaskType taskType, @Nullable Object task, @Nullable String desc) { - if (!recorded && aRouterInit.get()) { + if (!recorded && ARouterUtils.isInit.get()) { IMoGoCpuUsageProvider usage = CallerDevaToolsManager.INSTANCE.usage(); if (usage != null) { recorded = true; - HandlerCompat.createAsync(Looper.getMainLooper()).post(() -> usage.startMainThreadTime(Debug.threadCpuTimeNanos())); - usage.onProcessLaunched(SystemClock.elapsedRealtimeNanos()); + HandlerCompat.createAsync(Looper.getMainLooper()).post(usage::onMainThreadLaunched); + usage.onProcessLaunched(); } } + if (recorded) { - start.set(Debug.threadCpuTimeNanos()); + IMoGoCpuUsageProvider usage = CallerDevaToolsManager.INSTANCE.usage(); + if (usage != null) { + usage.updateOtherThreadTime(); + } } } @Override public void onExecutorAfter(@NonNull ThreadConfig.TaskType taskType, @Nullable Object task, @Nullable String desc) { if (recorded) { - Long start = this.start.get(); - if (start != null && start > 0) { - long delta = Debug.threadCpuTimeNanos() - start; - IMoGoCpuUsageProvider usage = CallerDevaToolsManager.INSTANCE.usage(); - if (usage != null && desc != null) { - usage.incrementOtherThreadUsage(desc, Thread.currentThread(), delta); - } + IMoGoCpuUsageProvider usage = CallerDevaToolsManager.INSTANCE.usage(); + if (usage != null) { + usage.updateOtherThreadTime(); } } } diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/devatools/perf/IMoGoCpuUsageProvider.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/devatools/perf/IMoGoCpuUsageProvider.kt index 3de0c9ecac..882146acd9 100644 --- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/devatools/perf/IMoGoCpuUsageProvider.kt +++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/devatools/perf/IMoGoCpuUsageProvider.kt @@ -2,13 +2,13 @@ package com.mogo.eagle.core.function.api.devatools.perf interface IMoGoCpuUsageProvider { - fun onProcessLaunched(time: Long) + fun onProcessLaunched() - fun startMainThreadTime(time: Long) + fun onMainThreadLaunched() - fun updateMainThreadTime(time: Long) + fun updateMainThreadTime() - fun incrementOtherThreadUsage(group: String, t: Thread, usage: Long) + fun updateOtherThreadTime() fun dump(): LinkedHashMap } \ No newline at end of file diff --git a/gradle/bytex/bytex.gradle b/gradle/bytex/bytex.gradle index 30ea6cdc3a..daa366db18 100644 --- a/gradle/bytex/bytex.gradle +++ b/gradle/bytex/bytex.gradle @@ -17,5 +17,6 @@ if (!isAndroidTest) { apply from: rootProject.file('gradle/bytex/bytex_apm.gradle') apply from: rootProject.file('gradle/bytex/bytex_systrace.gradle') apply from: rootProject.file('gradle/bytex/bytex_matrix.gradle') + apply from: rootProject.file('gradle/bytex/bytex_handler_proxy.gradle') // apply from: rootProject.file('gradle/bytex/bytex_btrace.gradle') } diff --git a/gradle/bytex/bytex_handler_proxy.gradle b/gradle/bytex/bytex_handler_proxy.gradle new file mode 100644 index 0000000000..92326cd4c2 --- /dev/null +++ b/gradle/bytex/bytex_handler_proxy.gradle @@ -0,0 +1,6 @@ +apply plugin: 'bytex.handler_proxy' +handler_proxy { + enable true + enableInDebug true +} + diff --git a/gradle/bytex/bytex_lancetx.gradle b/gradle/bytex/bytex_lancetx.gradle index 1398fce20b..8512a00458 100644 --- a/gradle/bytex/bytex_lancetx.gradle +++ b/gradle/bytex/bytex_lancetx.gradle @@ -2,8 +2,13 @@ apply plugin: 'LancetX' LancetX { enable true enableInDebug true + blackList = [ + "com.mogo.launcher.lancet.jank", + "com.mogo.thread.opt.core", + "com.zhjt.mogo_core_function_devatools.perf" + ] synchronizedLock { - enabled false + enabled true blackList = [ "okio.AsyncTimeout\$Watchdog" ] @@ -23,7 +28,7 @@ LancetX { enable true } main_block_check { - enable false + enable true } } }