参考博文
http://www.tuicool.com/articles/EjEJNrJ
http://m.w2bc.com/article/126583
AMS对startActivity请求处理及返回过程
根据上一章的分析了解了调用startActivity(),终于把数据和要开启Activity的请求发送到了AMS了,接下来分析在AMS中的处理过程和重新回到app进程。
1、在AMS中处理的过程
AMS中处理startActivity的过程比较复杂,主要涉及了ActivityManagerService、ActivityStackSupervisor、ActivityStack、PackageManagerService、WindowManagerService等几个类。
在ActivityManagerService中,startActivity先是调用了startActivityAsUser(注意,第一个参数caller就是app在服务端的代理ApplicationThreadProxy,它是一个Binder对象,实现了IApplicationThread。):
public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId()); }
然后在startActivityAsUser中调用了ActivityStackSupervisor的startActivityMayWait。
public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) { ...... return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, null, null, bOptions, false, userId, null, null); }
转到ActivityStackSupervisor中后,又在它和ActivityStack之间来回调用了许多次,主要是进行栈和Task的管理、解析Activity的信息,准备窗口的切换之类的工作,最后回到了ActivityStackSupervisor中,调用realStartActivityLocked函数。
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { ...... app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo); }
在realStartActivityLocked函数中,app是ProcessRecord类型,app.thread是IApplicationThread类型,也就是从客户端的代理ApplicationThreadProxy,在这儿调用了它的scheduleLaunchActivity方法,接下来就是回到app的进程空间里的过程。
2、AMS回到app进程
再回顾一下AMS和app之间交互原理图:
ActivityThread的类图结构:
ApplicationThreadProxy中scheduleLaunchActivity方法:
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException { ...... mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); }
在该方法中调用IBinder的transact发出命令,然后由ApplicationThread的代理ApplicationThreadNative的onTransact来处理:
@Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { ...... case SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION: { ...... scheduleLaunchActivity(intent, b, ident, info, curConfig, overrideConfig, compatInfo, referrer, voiceInteractor, procState, state, persistentState, ri, pi, notResumed, isForward, profilerInfo); return true; }}
ApplicationThreadNative的onTransact函数会调用scheduleLaunchActivity,其具体实现在ApplicationThread中:
private class ApplicationThread extends ApplicationThreadNative { ...... @Override public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) { updateProcessState(procState, false); ActivityClientRecord r = new ActivityClientRecord(); r.token = token; r.ident = ident; r.intent = intent; r.referrer = referrer; r.voiceInteractor = voiceInteractor; r.activityInfo = info; r.compatInfo = compatInfo; r.state = state; r.persistentState = persistentState; r.pendingResults = pendingResults; r.pendingIntents = pendingNewIntents; r.startsNotResumed = notResumed; r.isForward = isForward; r.profilerInfo = profilerInfo; r.overrideConfig = overrideConfig; updatePendingConfiguration(curConfig); sendMessage(H.LAUNCH_ACTIVITY, r); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
ApplicationThread是ActivityThread里的一个内部类,它的scheduleLaunchActivity的实现就是发一个LAUNCH_ACTIVITY类型的message到ActivityThread中的一个handler上。
private class H extends Handler { public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case LAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); final ActivityClientRecord r = (ActivityClientRecord) msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; ...... } }
H类继承自Handler也是Activity Thread的内部类,重写了handleMessage(Message msg)方法。根据标识LAUNCH_ACTIVITY调用了handleLaunchActivity()方法,handleLaunchActivity里调用了performLaunchActivity:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) { ...... Activity a = performLaunchActivity(r, customIntent); }
performLaunchActivity中又用到了Instrumentation类,调它的newActivity函数构造出activity对象。newActivity函数很简单,直接用classLoader加载了Activity类,然后用反射调它的构造函数newInstance出activity实例:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); if (r.state != null) { r.state.setClassLoader(cl); } }
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return (Activity)cl.loadClass(className).newInstance(); }
然后再回到performLaunchActivity中,在通过newActivity得到activity的实例后,接下来就该调用它的生命周期函数onCreate了,照旧还是通过Instrumentation来完成,调用它的callActivityOnCreate函数。
activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); }
在callActivityOnCreate里会调用Activity的performCreate函数,它里面调用的就是我们熟悉的onCreate了。
final void performCreate(Bundle icicle, PersistableBundle persistentState) { restoreHasCurrentPermissionRequest(icicle); onCreate(icicle, persistentState); mActivityTransitionState.readState(icicle); performCreateCommon(); }
app到AMS过程时序图:
总结:到此为止,startActivity的整个流程就结束了,从整个完整流程可以看出,Instrumentation这个类是startActivity整个过程中的必经之路,无论是从app到AMS,还是从AMS回到app都会经过它,所以它就是Hook对象。并且它是ActivityThread里的一个成员mInstrumentation,所以我们在客户端进程中可以通过反射拿到ActivityThread对象,也可以拿到mInstrumentation。
在早期版本中,作者hook的是newActivity,最新版本将其改为对handler.callback进行hook。为什么?
通过请教作者,他给我的答复是:“提前hook时机,可以减少“善后”工作,handler是跑到App进程最开始的地方,到了newActivity实际上有很多事已经被做掉了,需要再通过反射来重置一些参数,比如Resources,这意味着一件事你实际上做了两次。所以越早处理越好。”
Small中对StartActivity的返回处理解析
根据以上原理分析我们知道ActivityThread中的内部类H继承自handler处理主线程消息对列(MessageQueue)中的Message。因为Android的UI操作是由handler机制进行的,所以在Activity的创建需要通过H类处理。Small框架在对AMS到app的过程进行Hook的就是H类。具体在ApkBundleLauncher实现如下:
public void setUp(Context context) { ...... field = activityThreadClass.getDeclaredField("mH"); field.setAccessible(true); Handler ah = (Handler) field.get(thread); field = Handler.class.getDeclaredField("mCallback"); field.setAccessible(true); field.set(ah, new ActivityThreadHandlerCallback()); }
由以上可知Small主要改变了H类中mCallback成员变量的值。
为什么要这样做呢?
根据handler源码解析可知,Handler内部是通过执行dispatchMessage方法以实现对Message的处理的,Handler的dispatchMessage的源码如下:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}
我们来分析下这段代码:
1.首先会判断msg.callback存不存在,如果msg.callback存在,这种情况下会执行handleCallback(msg), handleCallback源码如下:
private static void handleCallback(Message message) { message.callback.run();}
2.如果msg.callback就是null,代码继续往下执行,接着我们会判断Handler的成员字段mCallback存不存在。mCallback是Hanlder.Callback类型的,我们在上面提到过,在Handler的构造函数中我们可以传递Hanlder.Callback类型的对象,该对象需要实现handleMessage方法,如果我们在构造函数中传递了该Callback对象,那么我们就会让Callback的handleMessage方法来处理Message。
3.如果我们在构造函数中没有传入Callback类型的对象,那么mCallback就为null,那么我们会调用Handler自身的hanldeMessage方法,该方法默认是个空方法,我们需要自己是重写实现该方法。
综上,我们可以看到Handler提供了三种途径处理Message,而且处理有前后优先级之分:首先尝试让postXXX中传递的Runnable执行,其次尝试让Handler构造函数中传入的Callback的handleMessage方法处理,最后才是让Handler自身的handleMessage方法处理Message。
因此Small对mCallback进行hook实现的就是第二种处理方式,ActivityThreadHandlerCallback中具体代码如下:
private static class ActivityThreadHandlerCallback implements Handler.Callback { private static final int LAUNCH_ACTIVITY = 100; @Override public boolean handleMessage(Message msg) { if (msg.what != LAUNCH_ACTIVITY) return false; Object r = msg.obj; Intent intent = ReflectAccelerator.getIntent(r); String targetClass = unwrapIntent(intent); if (targetClass == null) return false; ActivityInfo targetInfo = sLoadedActivities.get(targetClass); ReflectAccelerator.setActivityInfo(r, targetInfo); return false; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
代码分析可知,handleMessage方法中主要
是将msg.obj中存根的activityInfo中变成插件类对应的activityInfo,以供后续实例Activity和调用onCreate时使用。
重点:
重写的mCallback.handleMessage(msg)返回的是false,为什么要这样做呢?
这样做的目的是为了实现在handler里dispatchMessage方法中对Message的处理除了执行了第二种方式,还接着执行第三种方式。这样做为了实现对源码的轻度hook来达到将存根Activity替换为插件Activity的过程。
unwrapIntent()方法解析:
private static String unwrapIntent(Intent intent) { Set<String> categories = intent.getCategories(); if (categories == null) return null; Iterator<String> it = categories.iterator(); while (it.hasNext()) { String category = it.next(); if (category.charAt(0) == REDIRECT_FLAG) { return category.substring(1); } } return null; }
app的生命周期调用最后都是由Instrumentation来执行,所以Small框架中定义的InstrumentationWrapper也对其中的callActivityOnCreate,callActivityOnStop,callActivityOnDestroy等方法进行了重写,具体如下:
callActivityOnCreate()方法解析:
@Override /**为插件准备资源*/ public void callActivityOnCreate(Activity activity, android.os.Bundle icicle) { do { if (sLoadedActivities == null) break; ActivityInfo ai = sLoadedActivities.get(activity.getClass().getName()); if (ai == null) break; applyActivityInfo(activity, ai); } while (false); sHostInstrumentation.callActivityOnCreate(activity, icicle); if (sBundleInstrumentation != null) { try { Field f = Activity.class.getDeclaredField("mInstrumentation"); f.setAccessible(true); Object instrumentation = f.get(activity); if (instrumentation != sBundleInstrumentation) { f.set(activity, sBundleInstrumentation); } } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
applyActivityInfo()方法解析:
/** * 申请的插件Activity信息是与插件的AndroidManifest.xml里面一样 * @param activity * @param ai */ private static void applyActivityInfo(Activity activity, ActivityInfo ai) { Window window = activity.getWindow(); window.setSoftInputMode(ai.softInputMode); activity.setRequestedOrientation(ai.screenOrientation); }
callActivityOnStop方法解析:
@Override public void callActivityOnStop(Activity activity) { sHostInstrumentation.callActivityOnStop(activity); if (!Small.isUpgrading()) return; ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); List<RunningAppProcessInfo> processes = am.getRunningAppProcesses(); if (processes == null) return; String pkg = activity.getApplicationContext().getPackageName(); final List<RunningAppProcessInfo> currentAppProcesses = new ArrayList<>(processes.size()); for (RunningAppProcessInfo p : processes) { if (p.pkgList == null) continue; boolean match = false; int N = p.pkgList.length; for (int i = 0; i < N; i++) { if (p.pkgList[i].equals(pkg)) { match = true; break; } } if (!match) continue; currentAppProcesses.add(p); } if (currentAppProcesses.isEmpty()) return; RunningAppProcessInfo currentProcess = currentAppProcesses.get(0); if (currentProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) return; new Thread() { @Override public void run() { try { sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } for (RunningAppProcessInfo p : currentAppProcesses) { android.os.Process.killProcess(p.pid); } } }.start(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
callActivityOnDestroy()方法解析:
@Override public void callActivityOnDestroy(Activity activity) { do { if (sLoadedActivities == null) break; String realClazz = activity.getClass().getName(); ActivityInfo ai = sLoadedActivities.get(realClazz); if (ai == null) break; inqueueStubActivity(ai, realClazz); } while (false); sHostInstrumentation.callActivityOnDestroy(activity); }
在调用到callActivityOnDestroy时,需要将存根activity与真实activity解绑,主要通过inqueueStubActivity方法实现:
private void inqueueStubActivity(ActivityInfo ai, String realActivityClazz) { if (ai.launchMode == ActivityInfo.LAUNCH_MULTIPLE) return; if (mStubQueue == null) return; int countForMode = STUB_ACTIVITIES_COUNT; int offset = (ai.launchMode - 1) * countForMode; for (int i = 0; i < countForMode; i++) { String stubClazz = mStubQueue[i + offset]; if (stubClazz != null && stubClazz.equals(realActivityClazz)) { mStubQueue[i + offset] = null; break; } } }
从ActivityInfo获取launchMode,通过启动模式和插件Activity类名找到对存根Activity对应的mStubQueue数组位置并将其赋值为null,这样就实现了解绑。
**
关键问题:**
参考博客
1、由于我们欺骗了 AMS , AMS 应该只知道 StubActivity 的存在,它压根儿就不知道TargetActivity是什么,为什么它能正确完成对TargetActivity生命周期的回调呢?
一切的秘密在 token 里面。 AMS 与 ActivityThread 之间对于Activity的生命周期的交互,并没有直接使用Activity对象进行交互,而是使用一个token来标识,这个token是binder对象,因此可以方便地跨进程传递。Activity里面有一个成员变量 mToken 代表的就是它,token可以唯一地标识一个Activity对象,它在Activity的 attach 方法里面初始化;
在 AMS 处理Activity的任务栈的时候,使用这个token标记Activity,因此在Small里面, AMS 进程里面的token对应的是StubActivity,也就是 AMS 还在傻乎乎地操作StubActivity(关于这一点,你可以dump出任务栈的信息,可以观察到dump出的确实是StubActivity)。但是在我们App进程里面,token对应的却是TargetActivity!因此,在ActivityThread执行回调的时候,能正确地回调到TargetActivity相应的方法。
2、为什么App进程里面,token对应的是TargetActivity呢?
回到代码,ActivityClientRecord是在 mActivities 里面取出来的,确实是根据token取;那么这个token是什么时候添加进去的呢?我们看performLaunchActivity就完成明白了:它通过classloader加载了TargetActivity,然后完成一切操作之后把这个activity添加进了 mActivities !另外,在这个方法里面我们还能看到对Ativity attact 方法的调用,它传递给了新创建的Activity一个token对象,而这个token是在ActivityClientRecord构造函数里面初始化的。
至此我们已经可以确认,通过这种方式启动的Activity有它自己完整而独立的生命周期!
最后总结:至此,我们对Small框架中解决“Activity注册和生命周期问题”,从原理和代码两方面做了一个全面的分析。这个过程中,我弄懂了Android的activity启动流程,领会了Small框架怎么通过轻度hook实现对Android插件化的。写了这两篇博文,希望对你有帮助。