Merge branch 'release_robotaxi-d_231031_6.2.0.2' into 6.2.0_merge_master
# Conflicts: # OCH/sweeper/driver/src/main/java/com/mogo/och/sweeper/cloud/fragment/BaseSweeperCloudTabFragment.java # OCH/sweeper/driver/src/main/java/com/mogo/och/sweeper/cloud/model/SweeperCloudTaskModel.java # OCH/sweeper/driver/src/main/java/com/mogo/och/sweeper/operate/model/SweeperOperateTaskModel.java # OCH/sweeper/sweeper/build.gradle # OCH/sweeper/sweeper/src/main/java/com/mogo/och/sweeper/SweeperProvider.java # OCH/sweeper/sweeper/src/main/java/com/mogo/och/sweeper/view/BusArcView.java # app/script/functions/och.gradle # app/src/main/java/com/mogo/launcher/startup/ConfigStartUp.kt # core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/SOPSettingView.kt # core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_sop_setting.xml # core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml # core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/config/FunctionBuildConfig.kt
This commit is contained in:
@@ -0,0 +1,415 @@
|
||||
package com.mogo.launcher.lancet.jank.compiler;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Fragment;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.SystemClock;
|
||||
import android.view.View;
|
||||
import android.view.ViewManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.knightboost.lancet.api.synchronized_lock.ISynchronizedLockHooker;
|
||||
import com.mogo.core.lancetx.compiler.lib.annotations.LancetXGenerator;
|
||||
import com.mogo.core.lancetx.compiler.lib.generator.HookType;
|
||||
import com.mogo.core.lancetx.compiler.lib.generator.Scope;
|
||||
import com.mogo.core.lancetx.compiler.lib.generator.Type;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
class JankPointAutoGenerator {
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.IPC,
|
||||
hookAllPublicMethods = true
|
||||
)
|
||||
private ActivityManager am;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.IPC,
|
||||
hookAllPublicMethods = true
|
||||
)
|
||||
private PackageManager pm;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.IPC,
|
||||
hookAllPublicMethods = true
|
||||
)
|
||||
private ConnectivityManager cm;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.ACTIVITY,
|
||||
mayCreateSuper = true,
|
||||
hookAllPublicMethods = true,
|
||||
scope = Scope.LEAF,
|
||||
hookType = HookType.AROUND,
|
||||
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;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.BROADCAST_RECEIVER,
|
||||
mayCreateSuper = true,
|
||||
hookType = HookType.AROUND,
|
||||
hookAllPublicMethods = true,
|
||||
scope = Scope.LEAF,
|
||||
onlyHookMethodNames = {
|
||||
"onReceive"
|
||||
},
|
||||
onlyHookMethodDescs = {
|
||||
"(Landroid/content/Context;Landroid/content/Intent;)V"
|
||||
}
|
||||
)
|
||||
private BroadcastReceiver receiver;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.CONTENT_PROVIDER,
|
||||
mayCreateSuper = true,
|
||||
hookType = HookType.AROUND,
|
||||
hookAllPublicMethods = true,
|
||||
scope = Scope.LEAF,
|
||||
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;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.SERVICE,
|
||||
hookAllPublicMethods = true,
|
||||
mayCreateSuper = true,
|
||||
hookType = HookType.AROUND,
|
||||
scope = Scope.LEAF,
|
||||
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;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.AQS_LOCK,
|
||||
hookAllPublicMethods = true,
|
||||
scope = Scope.ALL,
|
||||
excludeHookMethodNames = { "toString", "hashCode" },
|
||||
excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" }
|
||||
)
|
||||
private Lock lock;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.SLEEP,
|
||||
scope = Scope.ALL,
|
||||
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;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.SYNCHRONIZED_LOCK,
|
||||
hookType = HookType.AROUND,
|
||||
scope = Scope.LEAF,
|
||||
mayCreateSuper = true,
|
||||
hookAllPublicMethods = true
|
||||
)
|
||||
private ISynchronizedLockHooker synchronizedLock;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.PARK,
|
||||
scope = Scope.ALL,
|
||||
hookAllPublicMethods = true
|
||||
)
|
||||
private LockSupport park;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.SLEEP,
|
||||
scope = Scope.ALL,
|
||||
onlyHookMethodNames = { "sleep" },
|
||||
onlyHookMethodDescs = { "(J)V" }
|
||||
)
|
||||
private SystemClock systemClockSleep;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.VIEW,
|
||||
scope = Scope.LEAF,
|
||||
hookType = HookType.AROUND,
|
||||
mayCreateSuper = true,
|
||||
onlyHookMethodNames = { "onMeasure", "onLayout", "onDraw", "draw" },
|
||||
onlyHookMethodDescs = { "(II)V", "(ZIIII)V", "(Landroid/graphics/Canvas;)V", "(Landroid/graphics/Canvas;)V" }
|
||||
)
|
||||
private View view;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.FRAGMENT,
|
||||
scope = Scope.LEAF,
|
||||
hookType = HookType.AROUND,
|
||||
mayCreateSuper = true,
|
||||
hookAllPublicMethods = true,
|
||||
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;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.FRAGMENT,
|
||||
scope = Scope.LEAF,
|
||||
hookType = HookType.AROUND,
|
||||
mayCreateSuper = true,
|
||||
hookAllPublicMethods = true,
|
||||
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;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.IO,
|
||||
scope = Scope.ALL,
|
||||
hookType = HookType.REPLACE_INVOKE,
|
||||
hookAllPublicMethods = true,
|
||||
excludeHookMethodNames = { "toString", "hashCode", "compareTo", "compareTo" },
|
||||
excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" , "(Ljava/io/File;)I", "(Ljava/lang/Object;)I" }
|
||||
)
|
||||
private File file;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.IO,
|
||||
scope = Scope.ALL,
|
||||
hookType = HookType.REPLACE_INVOKE,
|
||||
hookAllPublicMethods = true,
|
||||
excludeHookMethodNames = { "toString", "hashCode" },
|
||||
excludeHookMethodDescs = { "()Ljava/lang/String;", "()I" }
|
||||
)
|
||||
private InputStream is;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.IPC,
|
||||
scope = Scope.ALL,
|
||||
hookType = HookType.REPLACE_INVOKE,
|
||||
hookAllPublicMethods = true,
|
||||
onlyHookMethodNames = { "show" },
|
||||
onlyHookMethodDescs = { "()V" }
|
||||
)
|
||||
private Toast toast;
|
||||
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.IPC,
|
||||
scope = Scope.ALL,
|
||||
hookType = HookType.REPLACE_INVOKE,
|
||||
hookAllPublicMethods = true,
|
||||
onlyHookMethodNames = { "addView", "updateViewLayout", "removeView" },
|
||||
onlyHookMethodDescs = {
|
||||
"(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V",
|
||||
"(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V",
|
||||
"(Landroid/view/View;)V"
|
||||
}
|
||||
)
|
||||
private ViewManager manager;
|
||||
|
||||
|
||||
@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;
|
||||
|
||||
@LancetXGenerator(
|
||||
group = "main_block_check",
|
||||
type = Type.IO,
|
||||
scope = Scope.SELF,
|
||||
hookType = HookType.REPLACE_INVOKE,
|
||||
hookAllPublicMethods = true
|
||||
)
|
||||
private BitmapFactory factory;
|
||||
}
|
||||
@@ -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, enqueue = uptimeMillis))
|
||||
}
|
||||
|
||||
override fun onPostAtTime(handler: Handler, action: Runnable, uptimeMillis: Long) {
|
||||
checkIfNeed(handler)?.insert(Msg.acquire(handler, action = action, enqueue = 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, enqueue = 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, enqueue = 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
package com.mogo.launcher.lancet.jank.spi;
|
||||
import android.app.Activity;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import com.apm.insight.log.VLog;
|
||||
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.AtomicReference;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
|
||||
@AutoService(IHookInvoker.class)
|
||||
public class HookInvokerImpl implements IHookInvoker {
|
||||
|
||||
private final Looper mainLooper = Looper.getMainLooper();
|
||||
|
||||
private final ThreadLocal<Long> startTime = new ThreadLocal<>();
|
||||
|
||||
private final ThreadLocal<StringBuilder> message = new ThreadLocal<>();
|
||||
|
||||
private final ThreadLocal<Object> monitor = new ThreadLocal<>();
|
||||
|
||||
private final AtomicReference<Thread> holder = new AtomicReference<>();
|
||||
|
||||
private final StringBuilder extra = new StringBuilder();
|
||||
|
||||
private volatile IMoGoCpuUsageProvider provider;
|
||||
|
||||
private volatile boolean getProviderRequested = false;
|
||||
|
||||
private volatile boolean isCanDump = false; // 是否可以Dump堆栈,加此标记位是防止应用启动过程中,由于dump主线程堆栈导致启动耗时
|
||||
|
||||
// 切记: 请勿在此方法中调用其它模块类中的api,可能会出现StackOverFlowException
|
||||
@Override
|
||||
public void i(Type type, Object caller,String methodName, Object... objects) {
|
||||
startTime.set(SystemClock.elapsedRealtime());
|
||||
boolean isMainThread = mainLooper == Looper.myLooper();
|
||||
if (type == Type.SYNCHRONIZED_LOCK) {
|
||||
handleSynchronizedLock(isMainThread, caller, methodName, objects);
|
||||
}
|
||||
if (type == Type.AQS_LOCK) {
|
||||
handleAqsLockEnterBefore(isMainThread, 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... args) {
|
||||
long now = SystemClock.elapsedRealtime();
|
||||
Long old = startTime.get();
|
||||
long cost = now - (old == null ? now : old);
|
||||
boolean isMainThread = mainLooper == Looper.myLooper();
|
||||
if (isMainThread && type != Type.SYNCHRONIZED_LOCK) {
|
||||
handleCostTimeRecord(type, null, caller, methodName, cost, args);
|
||||
}
|
||||
if (isMainThread && type == Type.ACTIVITY) {
|
||||
handleActivity((Activity) caller, methodName, args);
|
||||
}
|
||||
if (type == Type.AQS_LOCK) {
|
||||
handleAqsLockEnterAfter(isMainThread, caller, methodName, args);
|
||||
}
|
||||
if (provider != null) {
|
||||
if (isMainThread) {
|
||||
provider.updateMainThreadTime();
|
||||
} else {
|
||||
provider.updateOtherThreadTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAqsLockEnterBefore(boolean isMainThread, Object caller, String methodName, Object[] objects) {
|
||||
if (isMainThread && caller instanceof Lock) {
|
||||
if ("lock".equals(methodName) || "lockInterruptibly".equals(methodName)) {
|
||||
if (extra.length() > 0) {
|
||||
extra.setLength(0);
|
||||
}
|
||||
extra.append(caller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAqsLockEnterAfter(boolean isMainThread, Object caller, String methodName, Object[] objects) {
|
||||
if (isMainThread && caller instanceof Lock) {
|
||||
if ("lock".equals(methodName) || "lockInterruptibly".equals(methodName)) {
|
||||
Long start = startTime.get();
|
||||
if (start != null) {
|
||||
long dur = SystemClock.elapsedRealtime() - start;
|
||||
handleCostTimeRecord(Type.AQS_LOCK, extra, caller, methodName, dur, objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCostTimeRecord(Type type, StringBuilder extra, Object caller, String methodName, long cost, Object... args) {
|
||||
//日志打印阈值
|
||||
long logThreshold = 5;
|
||||
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().getName())
|
||||
.append("#")
|
||||
.append(methodName);
|
||||
if (args.length > 0) {
|
||||
builder.append("#(");
|
||||
}
|
||||
for (Object o : args) {
|
||||
if (o == null) {
|
||||
continue;
|
||||
}
|
||||
builder.append(o.getClass().getName())
|
||||
.append(",");
|
||||
}
|
||||
|
||||
if (args.length > 0) {
|
||||
builder.setLength(builder.length() - 1);
|
||||
builder.append(")");
|
||||
}
|
||||
|
||||
builder.append("#").append(cost);
|
||||
boolean flag = false;
|
||||
if (extra != null && extra.length() > 0) {
|
||||
builder.append("#");
|
||||
builder.append(extra);
|
||||
flag = true;
|
||||
}
|
||||
// dump堆栈阈值
|
||||
long dumpStackThreshold = 20;
|
||||
if (cost >= dumpStackThreshold && isCanDump) {
|
||||
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);
|
||||
}
|
||||
|
||||
VLog.w("HookHandler", "Junk Detected:" + builder);
|
||||
// linkedLog(type, builder.toString());
|
||||
if (flag) {
|
||||
extra.setLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleActivity(Activity caller, String methodName, Object... args) {
|
||||
if ("onCreate".equals(methodName)) {
|
||||
try {
|
||||
IMoGoBlockProvider block = CallerDevaToolsManager.INSTANCE.block();
|
||||
if (block != null && block.hasInit()) {
|
||||
block.monitor(caller.getWindow());
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ("onResume".equals(methodName)) {
|
||||
try {
|
||||
IMoGoBlockProvider block = CallerDevaToolsManager.INSTANCE.block();
|
||||
if (block != null && block.hasInit()) {
|
||||
block.resume(caller.getWindow());
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if ("onWindowFocusChanged".equals(methodName)) {
|
||||
if (args.length > 0) {
|
||||
boolean hasFocus = (boolean)args[0];
|
||||
if (hasFocus && !isCanDump) {
|
||||
isCanDump = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("onPause".equals(methodName)) {
|
||||
try {
|
||||
IMoGoBlockProvider block = CallerDevaToolsManager.INSTANCE.block();
|
||||
if (block != null && block.hasInit()) {
|
||||
block.pause(caller.getWindow());
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if ("onStop".equals(methodName)) {
|
||||
try {
|
||||
IMoGoBlockProvider block = CallerDevaToolsManager.INSTANCE.block();
|
||||
if (block != null && block.hasInit()) {
|
||||
block.pop(caller.getWindow());
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSynchronizedLock(boolean isMainThread,Object caller, String methodName, Object [] objects) {
|
||||
if (isMainThread) {
|
||||
if ("onMonitorBefore".equals(methodName)) {
|
||||
Object monitor = null;
|
||||
if (objects.length > 0) {
|
||||
this.monitor.set(monitor = objects[0]);
|
||||
}
|
||||
Thread holder = this.holder.get();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (monitor != null) {
|
||||
sb.append("monitor::").append(monitor.getClass().getName());
|
||||
}
|
||||
if (holder != null) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("##holder::").append(holder);
|
||||
} else {
|
||||
sb.append("holder::").append(holder);
|
||||
}
|
||||
}
|
||||
if (extra.length() > 0) {
|
||||
extra.setLength(0);
|
||||
}
|
||||
extra.append(sb);
|
||||
}
|
||||
if ("onMonitorEnter".equals(methodName)) {
|
||||
Long startTime = this.startTime.get();
|
||||
if (startTime == null) {
|
||||
return;
|
||||
}
|
||||
long cost = SystemClock.elapsedRealtime() - startTime;
|
||||
handleCostTimeRecord(Type.SYNCHRONIZED_LOCK, extra, caller, methodName, cost, objects);
|
||||
}
|
||||
if ("onMonitorExit".equals(methodName)) {
|
||||
this.monitor.remove();
|
||||
}
|
||||
} 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) {}
|
||||
}
|
||||
@@ -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<Runnable, ActionWrapper>() }
|
||||
|
||||
@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")))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import com.mogo.eagle.core.function.call.startup.CallerStartUpManager;
|
||||
import com.mogo.eagle.core.function.main.MainMoGoApplication;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.LogLevel;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
|
||||
import com.mogo.eagle.core.utilcode.util.SharedPrefs;
|
||||
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr;
|
||||
import com.mogo.launcher.crash.CrashSystem;
|
||||
import com.mogo.launcher.startup.ARouterStartUp;
|
||||
import com.mogo.launcher.startup.ConfigStartUp;
|
||||
@@ -33,7 +33,7 @@ public class MogoApplication extends MainMoGoApplication {
|
||||
private void tryEnableStrictMode() {
|
||||
IStrictModeProvider strict = CallerDevaToolsManager.INSTANCE.strict();
|
||||
if (DebugConfig.isDebug() && strict != null) {
|
||||
boolean enabled = SharedPrefs.getInstance(this).getBoolean("MOGO_STRICT_MODE_ENABLED", false);
|
||||
boolean enabled = SharedPrefsMgr.getInstance(this).getBoolean("MOGO_STRICT_MODE_ENABLED", false);
|
||||
Logger.e("StrictMode", "isEnabled:" + enabled);
|
||||
if (enabled) {
|
||||
strict.enable();
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
package com.mogo.launcher.lancet
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.*
|
||||
import android.view.View
|
||||
import androidx.annotation.*
|
||||
import com.knightboost.lancet.api.*
|
||||
import com.knightboost.lancet.api.Scope.ALL
|
||||
import com.knightboost.lancet.api.annotations.*
|
||||
import com.knightboost.lancet.api.annotations.Weaver
|
||||
import com.mogo.eagle.core.utilcode.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Runnable
|
||||
|
||||
@Keep
|
||||
@Weaver
|
||||
@Group("anr_fix")
|
||||
class ANRFix {
|
||||
|
||||
companion object {
|
||||
|
||||
// @JvmStatic
|
||||
// @TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
// @TargetMethod(methodName = "post")
|
||||
// @ReplaceInvoke
|
||||
// fun handlerPostProxy(handler: Handler, action: Runnable): Boolean {
|
||||
// if (Looper.getMainLooper() != handler.looper) {
|
||||
// return handler.post(action)
|
||||
// }
|
||||
// val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
// handler.removeMessages(what)
|
||||
// val msg = Message.obtain(handler, action)
|
||||
// msg.what = what
|
||||
// return handler.sendMessage(msg)
|
||||
// }
|
||||
//
|
||||
// @JvmStatic
|
||||
// @TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
// @TargetMethod(methodName = "postDelayed")
|
||||
// @ReplaceInvoke
|
||||
// fun handlerPostDelayProxy(handler: Handler, action: Runnable, delayMillis: Long): Boolean {
|
||||
// if (Looper.getMainLooper() != handler.looper) {
|
||||
// return handler.postDelayed(action, delayMillis)
|
||||
// }
|
||||
// val what = ObjectHashCodeUtils.getHashCodeIfNeed(action)
|
||||
// handler.removeMessages(what)
|
||||
// val msg = Message.obtain(handler, action)
|
||||
// msg.what = what
|
||||
// return handler.sendMessageDelayed(msg, delayMillis)
|
||||
// }
|
||||
//
|
||||
// @JvmStatic
|
||||
// @TargetClass(value = "android.app.Activity", scope = ALL)
|
||||
// @TargetMethod(methodName = "post")
|
||||
// @ReplaceInvoke
|
||||
// fun runOnUiThreadOfActivityProxy(activity: Activity, action: Runnable) {
|
||||
// if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
// UiThreadHandler.post(action)
|
||||
// } else {
|
||||
// activity.runOnUiThread(action)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @JvmStatic
|
||||
// @TargetClass(value = "android.view.View", scope = ALL)
|
||||
// @TargetMethod(methodName = "post")
|
||||
// @ReplaceInvoke
|
||||
// fun postOfViewProxy(view: View, action: Runnable): Boolean {
|
||||
// return if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
// UiThreadHandler.post(action)
|
||||
// } else {
|
||||
// view.post(action)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @JvmStatic
|
||||
// @TargetClass(value = "android.view.View", scope = ALL)
|
||||
// @TargetMethod(methodName = "postDelayed")
|
||||
// @ReplaceInvoke
|
||||
// fun postDelayedOfViewProxy(view: View, action: Runnable, delayMillis: Long): Boolean {
|
||||
// return if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
// UiThreadHandler.postDelayed(action, delayMillis)
|
||||
// } else {
|
||||
// view.postDelayed(action, delayMillis)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package com.mogo.launcher.lancet;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
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;
|
||||
|
||||
import kotlin.coroutines.CoroutineContext;
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler;
|
||||
import kotlinx.coroutines.Dispatchers;
|
||||
import kotlinx.coroutines.MainCoroutineDispatcher;
|
||||
|
||||
|
||||
@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<WeakReference<Handler>> 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<WeakReference<Handler>> 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<WeakReference<Handler>> asyncHandlers = MainBlockCheck.Companion.getAsyncHandlers();
|
||||
asyncHandlers.add(new WeakReference<>(handler));
|
||||
return handler;
|
||||
} else {
|
||||
return new Handler(looper, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,802 +0,0 @@
|
||||
package com.mogo.launcher.lancet
|
||||
|
||||
import android.app.*
|
||||
import android.content.*
|
||||
import android.graphics.*
|
||||
import android.os.*
|
||||
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.LinkedList
|
||||
import java.util.concurrent.*
|
||||
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"
|
||||
|
||||
@JvmStatic
|
||||
private val tokens = ConcurrentHashMap<Int, WeakReference<Holder>>(128)
|
||||
|
||||
private val pool by lazy { Executors.newFixedThreadPool(1) }
|
||||
|
||||
val asyncHandlers by lazy { CopyOnWriteArraySet<WeakReference<Handler>>() }
|
||||
|
||||
private val asyncHandlersMap by lazy { ConcurrentHashMap<Int, Boolean>() }
|
||||
|
||||
private val whats by lazy { ConcurrentHashMap<Int, LinkedList<WeakReference<Holder>>>() }
|
||||
|
||||
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<WeakReference<Holder>>() }.add(
|
||||
WeakReference(h)
|
||||
)
|
||||
getRecorder()?.insert(h)
|
||||
}
|
||||
if (type == 1) {
|
||||
val holders = whats.remove(what)?.mapNotNull { it.get() }
|
||||
if (!holders.isNullOrEmpty()) {
|
||||
getRecorder()?.remove(holders)
|
||||
}
|
||||
}
|
||||
if (type == 2 && h != null) {
|
||||
val what = h.what
|
||||
if (what != null) {
|
||||
whats.remove(what)?.removeAll { it.get() == h }
|
||||
}
|
||||
getRecorder()?.recycle(h.id, elapsedTime, duration)
|
||||
}
|
||||
} finally {
|
||||
reset()
|
||||
actionPool.release(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
type = -1
|
||||
what = Int.MIN_VALUE
|
||||
holder = null
|
||||
elapsedTime = -1
|
||||
duration = -1
|
||||
}
|
||||
}
|
||||
|
||||
private val actionPool by lazy { Pools.SynchronizedPool<PoolAction>(500) }
|
||||
|
||||
private fun getAction(): PoolAction = actionPool.acquire() ?: PoolAction(-1, 0, null)
|
||||
|
||||
@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 now = now()
|
||||
val elapsedTime = now - enclose.enqueueTime
|
||||
try {
|
||||
if (action != null) {
|
||||
action.run()
|
||||
} else {
|
||||
if (oldMsg == null) {
|
||||
h?.dispatchMessage(msg)
|
||||
} else {
|
||||
oldMsg.obj = oldObj
|
||||
h?.dispatchMessage(oldMsg)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
val duration = now() - now
|
||||
recycle(enclose, elapsedTime, duration)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic val ASYNC_HANDLER by lazy {
|
||||
HandlerCompat.createAsync(Looper.getMainLooper(), callback)
|
||||
}
|
||||
|
||||
@JvmStatic val HANDLER by lazy {
|
||||
Handler(Looper.getMainLooper(), callback)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "post")
|
||||
@ReplaceInvoke
|
||||
fun handlerPostProxy(handler: Handler, action: Runnable): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.post(action)
|
||||
}
|
||||
val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }
|
||||
val newHandler = getHandler(isAsync)
|
||||
val msg = Message.obtain(newHandler)
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(newHandler, action)
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(newHandler, action = action, isAsync = isAsync)
|
||||
msg.obj = holder
|
||||
val inserted = newHandler.sendMessage(msg)
|
||||
if (inserted) {
|
||||
insert(what, holder)
|
||||
}
|
||||
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)
|
||||
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
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendEmptyMessage")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendEmptyMessage(handler: Handler, what: Int): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendEmptyMessage(what)
|
||||
}
|
||||
val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { 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 inserted = newHandler.sendMessage(msg)
|
||||
if (inserted) {
|
||||
insert(what, holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendEmptyMessageAtTime")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendEmptyMessageAtTime(handler: Handler, what: Int, uptimeMillis: Long): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendEmptyMessageAtTime(what, uptimeMillis)
|
||||
}
|
||||
val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { 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 inserted = newHandler.sendMessageAtTime(msg, uptimeMillis)
|
||||
if (inserted) {
|
||||
insert(what, holder)
|
||||
}
|
||||
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendEmptyMessageDelayed")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendEmptyMessageDelayed(handler: Handler, what: Int, delayMillis: Long): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendEmptyMessageDelayed(what, delayMillis)
|
||||
}
|
||||
val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { 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 inserted = newHandler.sendMessageDelayed(msg, delayMillis)
|
||||
if (inserted) {
|
||||
insert(what, holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendMessage")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendMessage(handler: Handler, msg: Message): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendMessage(msg)
|
||||
}
|
||||
val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }
|
||||
val newHandler = getHandler(isAsync)
|
||||
var newMsg = msg
|
||||
val action = msg.callback
|
||||
if (action != null) {
|
||||
newMsg = Message.obtain(newHandler)
|
||||
newMsg.what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
|
||||
}
|
||||
val obj: Holder = Holder.acquire(handler, originMsg = msg, action = msg.callback, obj = msg.obj, what = msg.what, isAsync = isAsync)
|
||||
val oldObj = msg.obj
|
||||
newMsg.obj = obj
|
||||
if (oldObj != null) {
|
||||
synchronized(tokens) {
|
||||
tokens[oldObj.hashCode()] = WeakReference(obj)
|
||||
}
|
||||
}
|
||||
val inserted = newHandler.sendMessage(newMsg)
|
||||
if (inserted) {
|
||||
insert(newMsg.what, obj)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendMessageAtTime")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendMessageAtTime(handler: Handler, msg: Message, uptimeMillis: Long): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendMessageAtTime(msg, uptimeMillis)
|
||||
}
|
||||
val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }
|
||||
val newHandler = getHandler(isAsync)
|
||||
var newMsg = msg
|
||||
val action = msg.callback
|
||||
if (action != null) {
|
||||
newMsg = Message.obtain(newHandler)
|
||||
newMsg.what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
|
||||
}
|
||||
val delta = uptimeMillis - SystemClock.uptimeMillis()
|
||||
val obj= Holder.acquire(handler, msg, obj = msg.obj, action = msg.callback, what = msg.what, delay = if (delta > 0) delta else 0, isAsync = isAsync)
|
||||
val oldObj = msg.obj
|
||||
newMsg.obj = obj
|
||||
if (oldObj != null) {
|
||||
synchronized(tokens) {
|
||||
tokens[oldObj.hashCode()] = WeakReference(obj)
|
||||
}
|
||||
}
|
||||
val inserted = newHandler.sendMessageAtTime(newMsg, uptimeMillis)
|
||||
if (inserted) {
|
||||
insert(newMsg.what, obj)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "sendMessageAtFrontOfQueue")
|
||||
@ReplaceInvoke
|
||||
fun handlerSendMessageAtFrontOfQueue(handler: Handler, msg: Message): Boolean {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.sendMessageAtFrontOfQueue(msg)
|
||||
}
|
||||
val isAsync = asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }
|
||||
val newHandler = getHandler(isAsync)
|
||||
var newMsg = msg
|
||||
val action = msg.callback
|
||||
if (action != null) {
|
||||
newMsg = Message.obtain(newHandler)
|
||||
newMsg.what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
|
||||
}
|
||||
val obj = Holder.acquire(handler, msg, obj = msg.obj, action = msg.callback, what = msg.what, isAsync = isAsync)
|
||||
val old = msg.obj
|
||||
newMsg.obj = obj
|
||||
if (old != null) {
|
||||
synchronized(tokens) {
|
||||
tokens[old.hashCode()] = WeakReference(obj)
|
||||
}
|
||||
}
|
||||
val inserted = newHandler.sendMessageAtFrontOfQueue(newMsg)
|
||||
if (inserted) {
|
||||
insert(newMsg.what, obj)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.app.Activity", scope = ALL)
|
||||
@TargetMethod(methodName = "post")
|
||||
@ReplaceInvoke
|
||||
fun runOnUiThreadOfActivityProxy(activity: Activity, action: Runnable) {
|
||||
val msg = Message.obtain()
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(activity, action)
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(null, action = action, what = msg.what, extra = mutableMapOf("runOnUiThread" to "${activity.javaClass.simpleName}#${action.javaClass.name}"))
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessage(msg)
|
||||
if (inserted) {
|
||||
insert(what, holder)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.view.View", scope = ALL)
|
||||
@TargetMethod(methodName = "post")
|
||||
@ReplaceInvoke
|
||||
fun postOfViewProxy(view: View, action: Runnable): Boolean {
|
||||
val msg = Message.obtain()
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(view, action)
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(null, action = action, what = what, extra = mutableMapOf("post" to "${view.javaClass.simpleName}#${action.javaClass.name}"))
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessage(msg)
|
||||
if (inserted) {
|
||||
insert(what, holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.view.View", scope = ALL)
|
||||
@TargetMethod(methodName = "postDelayed")
|
||||
@ReplaceInvoke
|
||||
fun postDelayedOfViewProxy(view: View, action: Runnable, delayMillis: Long): Boolean {
|
||||
val msg = Message.obtain()
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(view, action)
|
||||
msg.what = what
|
||||
val holder = Holder.acquire(null, action = action, delay = delayMillis, what = what, extra = mutableMapOf("post" to "${view.javaClass.simpleName}#${action.javaClass.name}"))
|
||||
msg.obj = holder
|
||||
val inserted = HANDLER.sendMessageDelayed(msg, delayMillis)
|
||||
if (inserted) {
|
||||
insert(what, holder)
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "removeCallbacks")
|
||||
@ReplaceInvoke
|
||||
fun handlerRemoveCallbacks(handler: Handler, action: Runnable) {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.removeCallbacks(action)
|
||||
}
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
|
||||
getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what)
|
||||
remove(what)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "removeCallbacks")
|
||||
@ReplaceInvoke
|
||||
fun handlerRemoveCallbacksWithToken(handler: Handler, action: Runnable, token: Any?) {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.removeCallbacks(action, token)
|
||||
}
|
||||
val what = ObjectHashCodeUtils.getHashCodeIfNeed(handler, action)
|
||||
getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what, if (token != null) { synchronized(tokens) { tokens.remove(token.hashCode())?.get() } } else null)
|
||||
remove(what)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "removeMessages")
|
||||
@ReplaceInvoke
|
||||
fun handlerRemoveMessages(handler: Handler, what: Int) {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.removeMessages(what)
|
||||
}
|
||||
getHandler(asyncHandlersMap.getOrPut(handler.hashCode()) { computeIsAsyncHandler(handler) }).removeMessages(what)
|
||||
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
|
||||
@TargetClass(value = "android.os.Handler", scope = ALL)
|
||||
@TargetMethod(methodName = "removeMessages")
|
||||
@ReplaceInvoke
|
||||
fun handlerRemoveMessagesWithToken(handler: Handler, what: Int, token: Any?) {
|
||||
if (Looper.getMainLooper() != handler.looper) {
|
||||
return handler.removeMessages(what, token)
|
||||
}
|
||||
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")
|
||||
fun proxyViewOnMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val holder = Holder.acquire(handler = null, obj = "View[${This.get().javaClass.name}]:onMeasure")
|
||||
pool.execute {
|
||||
getRecorder()?.insert(holder)
|
||||
}
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
pool.execute {
|
||||
getRecorder()?.recycle(holder.id, 0, spend)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.view.View", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onLayout")
|
||||
fun proxyViewOnLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
val holder = Holder.acquire(handler = null, obj = "View[${This.get().javaClass.name}]:onLayout")
|
||||
insert(-1, holder)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@TargetClass(value = "android.view.View", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onDraw")
|
||||
fun proxyViewOnDraw(canvas: Canvas) {
|
||||
val holder = Holder.acquire(handler = null, obj = "View[${This.get().javaClass.name}]:onDraw")
|
||||
insert(-1, holder)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onCreate")
|
||||
fun proxyActivityOnCreate(savedInstanceState: Bundle?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onCreate")
|
||||
insert(-1, holder)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
CallerDevaToolsManager.block()?.monitor((This.get() as Activity).window)
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onStart")
|
||||
fun proxyActivityOnStart() {
|
||||
val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onStart")
|
||||
insert(-1, holder)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onResume")
|
||||
fun proxyActivityOnResume() {
|
||||
val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onResume")
|
||||
insert(-1, holder)
|
||||
val now = now()
|
||||
CallerDevaToolsManager.block()?.resume((This.get() as Activity).window)
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onPause")
|
||||
fun proxyActivityOnPause() {
|
||||
val holder = Holder.acquire(handler = null, obj = "Activity[${This.get().javaClass.name}]:onPause")
|
||||
insert(-1, holder)
|
||||
CallerDevaToolsManager.block()?.pause((This.get() as Activity).window)
|
||||
val now = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - now
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.app.Activity", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onDestroy")
|
||||
fun proxyActivityOnDestroy() {
|
||||
CallerDevaToolsManager.block()?.pop((This.get() as Activity).window)
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "androidx.fragment.app.Fragment", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onCreateView")
|
||||
fun proxyFragmentOnCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Fragment[${This.get().javaClass.name}]:onCreateView")
|
||||
insert(-1, holder)
|
||||
val startTime = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - startTime
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "androidx.fragment.app.Fragment", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onCreate")
|
||||
fun proxyFragmentOnCreate(savedInstanceState: Bundle?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Fragment[${This.get().javaClass.name}]:onCreate")
|
||||
insert(-1, holder)
|
||||
val startTime = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - startTime
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "androidx.fragment.app.Fragment", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onViewCreated")
|
||||
fun proxyFragmentOnViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Fragment[${This.get().javaClass.name}]:onViewCreated")
|
||||
insert(-1, holder)
|
||||
val startTime = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - startTime
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetClass(value = "android.content.BroadcastReceiver", scope = LEAF)
|
||||
@Insert(mayCreateSuper = true)
|
||||
@TargetMethod(methodName = "onReceive")
|
||||
fun proxyBroadcastReceiver(ctx: Context?, intent: Intent?) {
|
||||
val holder = Holder.acquire(handler = null, obj = "Receiver[${This.get().javaClass.name}]:onReceive")
|
||||
insert(-1, holder)
|
||||
val startTime = now()
|
||||
try {
|
||||
Origin.callVoid()
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
} finally {
|
||||
val spend = now() - startTime
|
||||
recycle(holder, 0, spend)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,8 @@ internal class AccessSyntheticUtils {
|
||||
private val fields = ConcurrentHashMap<String, WeakReference<Any>>()
|
||||
private val observers = ConcurrentSet<String>()
|
||||
|
||||
// true: 代表要执行原来的run方法体
|
||||
// false: 代表不执行原来的run方法体
|
||||
@JvmStatic
|
||||
fun isTargetAlive(obj: Any): Boolean {
|
||||
try {
|
||||
@@ -118,9 +120,7 @@ internal class AccessSyntheticUtils {
|
||||
}
|
||||
ret
|
||||
} ?: true
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
}
|
||||
} catch (ignore: Throwable) { }
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +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.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 {
|
||||
@@ -17,6 +20,7 @@ object ARouterStartUp {
|
||||
}
|
||||
// 初始化 arouter
|
||||
ARouter.init(app)
|
||||
ARouterUtils.isInit.set(true)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
// 由于ARouter会在SP_AROUTER_CACHE.xml缓存路由表,如果出现了被删除的情况会报错,这里清除下就好了
|
||||
|
||||
@@ -74,6 +74,9 @@ object ConfigStartUp {
|
||||
FunctionBuildConfig.sweeperDefaultMode = BuildConfig.SWEEPER_DEFAULT_MODE
|
||||
// 清扫车 是否能切换当前业务模式
|
||||
FunctionBuildConfig.sweeperCanSwitchMode = BuildConfig.SWEEPER_CAN_SWITCH_MODE
|
||||
|
||||
// 是否开启卡顿检测
|
||||
FunctionBuildConfig.isSupportJunkDetect = BuildConfig.IS_SUPPORT_JUNK_DETECT
|
||||
}
|
||||
|
||||
private fun initDebugConfig() {
|
||||
|
||||
Reference in New Issue
Block a user