From ab410067365dc2da0a8fb19c37ee692117e7ce32 Mon Sep 17 00:00:00 2001 From: Omooo <869759698@qq.com> Date: Mon, 27 Apr 2020 09:16:52 +0800 Subject: [PATCH] =?UTF-8?q?Update=20=E5=90=AF=E5=8A=A8=E6=9C=AA=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E7=9A=84=20Activity.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../插件化/启动未注册的 Activity.md | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/blogs/Android/Framework/插件化/启动未注册的 Activity.md b/blogs/Android/Framework/插件化/启动未注册的 Activity.md index 0978c2e..459fee3 100644 --- a/blogs/Android/Framework/插件化/启动未注册的 Activity.md +++ b/blogs/Android/Framework/插件化/启动未注册的 Activity.md @@ -202,7 +202,142 @@ callActivityOnCreate 没有 Intent 参数,所以无法读取之前存放的要 1. AMS 会认为每次要打开的 Activity 都是 SubActivity,那就相当于那些没有在 AndroidManifest 文件里面注册的 Activity 的 LaunchMode 就只能是默认类型,即使设置了 singleTop 或 singleTask,也不会生效。 2. 兼容性问题,目前在 Android 6/7 上可行,但在 Android 7 以上就不行了,因为 AMN 的 gDefault 已经不存在了。 +#### Android 8 适配 +在 Android 8 中,ActivityManagerNative 中已经不存在 gDefault 字段了,转移到了 ActivityManager 类中,但此时这个字段改名为 IActivityManagerSingleton: + +```java + // ActivityManager + private static final Singleton IActivityManagerSingleton = + new Singleton() { + @Override + protected IActivityManager create() { + final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); + final IActivityManager am = IActivityManager.Stub.asInterface(b); + return am; + } + }; +``` + +所以,需要的处理就变成了: + +```java + Object gDefault = null; + + if (android.os.Build.VERSION.SDK_INT <= 25) { + // 获取 AMN 的 gDefault t单例 gDefault,gDefault是静态的 + gDefault = RefInvoke.getStaticFieldObject("android.app.ActivityManagerNative", "gDefault"); + } else { + // 获取 ActivityManager 的单例 IActivityManagerSingleton,它其实就是之前的 gDefault + gDefault = RefInvoke.getStaticFieldObject("android.app.ActivityManager", "IActivityManagerSingleton"); + } +``` + +#### Android 9 适配 + +在 Android 9 之前,我们是 Hook 掉 H 类的 mCallback 对象,拦截 handleMessage 方法,在里面它会根据 msg.what 来判断到底是哪种消息。在 H 类中,定义了几十种消息,比如说 LAUNCH_ACTIVITY 的值是 100,PAUSE_ACTIVITY 的值是 101。从 100-109 都是给 Activity 的生命周期函数准备的。从 110 开始,才是给 Application、Service、ContentProvider、BroadcastReceiver 准备的。 + +但是在 Android 9,它重构了 H 类,把 100 到 109 这十个用于 Activity 的消息,都合并为 159 这个消息,消息名为 EXECUTE_TRANSACTION。 + +为什么要这么改呢?我们知道 Activity 的生命周期图,这其实是一个由 Create、Pause、Resume、Stop、Destory、Restart 组成的状态机。按照设计模式中状态模式的定义,可以把每个状态都定义成一个类,于是便有了如下的类图: + +![](https://i.loli.net/2020/04/27/NgncLAk9jmGlDKY.png) + +就拿 LaunchActivity 来说,在 Android P 之前,是在 H 类的 handleMessage 方法的 switch 分支语句中,编写启动一个 Activity 的逻辑: + +```java + public void handleMessage(Message msg) { + switch (msg.what) { + case LAUNCH_ACTIVITY: { + final ActivityClientRecord r = (ActivityClientRecord) msg.obj; + + r.packageInfo = getPackageInfoNoCheck( + r.activityInfo.applicationInfo, r.compatInfo); + handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); + } break; + } + } +``` + +在 Android P 中,启动 Activity 的这部分逻辑,被转移到了 LaunchActivityItem 类的 execute 方法中: + +```java +public class LaunchActivityItem extends ClientTransactionItem { + + @Override + public void execute(ClientTransactionHandler client, IBinder token, + PendingTransactionActions pendingActions) { + ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, + mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, + mPendingResults, mPendingNewIntents, mIsForward, + mProfilerInfo, client); + client.handleLaunchActivity(r, pendingActions, null /* customIntent */); + } +} +``` + + + +这就导致了我们之前的插件化解决方法,在 Android 9 上是不生效的,因为找不到 100 这个消息。为此我们需要拦截 159 这个消息。拦截后还需要判断这个消息到底是 Launch 还是 Pause 或者是 Resume。 + +关键在于 H 类的 handleMessage 方法的 Message 参数,这个 Message 的 obj 字段,在 Message 是 159 的时候,返回的是 ClientTransaction 类型对象,它内部有一个 mActivityCallbacks 集合: + +```java +public class ClientTransaction implements Parcelable, ObjectPoolItem { + + private List mActivityCallbacks; + +} +``` + +这个 mActivityCallbacks 集合中,存放的是 ClientTransactionItem 的各种子类对象,比如 LaunchActivityItem、DestoryActivityItem。拿到 LaunchActivityItem 类的对象,它内部有一个 mIntent 字段,里面存放的就是要启动的 Activity 名称,在这里进行替换。 + +代码如下: + +```java +class MockClass2 implements Handler.Callback { + + Handler mBase; + + public MockClass2(Handler base) { + mBase = base; + } + + @Override + public boolean handleMessage(Message msg) { + + switch (msg.what) { + // ActivityThread里面 "LAUNCH_ACTIVITY" 这个字段的值是100 + // 本来使用反射的方式获取最好, 这里为了简便直接使用硬编码 + case 100: //for API 28以下 + handleLaunchActivity(msg); + break; + case 159: //for API 28 + handleActivity(msg); + break; + } + + mBase.handleMessage(msg); + return true; + } + + private void handleActivity(Message msg) { + // 这里简单起见,直接取出TargetActivity; + Object obj = msg.obj; + + List mActivityCallbacks = (List) RefInvoke.getFieldObject(obj, "mActivityCallbacks"); + if(mActivityCallbacks.size() > 0) { + String className = "android.app.servertransaction.LaunchActivityItem"; + if(mActivityCallbacks.get(0).getClass().getCanonicalName().equals(className)) { + Object object = mActivityCallbacks.get(0); + Intent intent = (Intent) RefInvoke.getFieldObject(object, "mIntent"); + Intent target = intent.getParcelableExtra(AMSHookHelper.EXTRA_TARGET_INTENT); + intent.setComponent(target.getComponent()); + } + } + } +} +``` #### 参考