前面一系列的文章中我们介绍了Android系统资源加载流程,最后引出插件化中资源加载的方法,完成了『资源动态加载』这一大块的介绍。本系列文章将重点介绍『代码动态加载』,拿最熟悉的Activity来开刀。
Activity虽然是一个Java对象,可以使用ClassLoader加载出它的实体,但是由于Activity生命周期管理是由系统框架完成的,为了更好的分析如何加载插件中的Activity以及让它“活”起来,我们有必要了解两方面的知识:
Activity启动流程Activity生命周期回调流程Activity的启动流程大致分三个阶段:
应用程序进程内启动Activity操作AMS进程内部处理应用程序进程内创建Activity(可能是一个新的进程)我们将按照这个顺序来分析Activity的启动。
以我们最常见的startActivity作为分析的起点,它最终将调用到startActivityForResult。
1.Activity.startActivityForResult
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { ... Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); ... }startActivityForResult方法只是简单调用了Instrumentation类的execStartActivity方法。但是方法参数要说明一下:
mMainThread.getApplicationThread。得到的是一个类型为ApplicationThread的Binder本地对象,在后面的操作中会将它传给AMS,以便AMS进程和应用程序进程通信。mToken。它是一个IBinder类型的Binder代理对象,指向AMS中类型为ActivityRecord的Binder本地对象。由于AMS中使用ActivityRecord来描述一个Activity,将mToken传给AMS后,AMS就知道由谁启动了新的Activity。2.Instrumentation.execStartActivity
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { ... int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); ... }ActivityManagerNative的getDefault方法获得的是AMS的一个代理对象,其startActivity方法最终将调用到AMS的startActivityAsUser方法。
启动Activity的核心逻辑都在AMS进程内进行,整个逻辑流程十分复杂。但在研究插件化框架原理时,我们不用细致的研究每一块逻辑,因为即使可以看明白所有流程,也无法Hook AMS进程完成操作。所以在这里只是对AMS内处理流程进行简单介绍,如果后面有涉及具体某块逻辑时再详细介绍。
先看一下整个过程的时序图:
简要说明每一步作用。
1.ActivityManagerService.startActivityAsUser
这里我们不去分析用户相关逻辑,这里简单调用ActivityStarter的方法。
2.ActivityStarter.startActivityMayWait
得到代表Intent信息的ResolveInfo对象,代表Activity信息的ActivityInfo对象。调用startActivityLock进行下一步操作。
3.ActivityStarter.startActivityLocked
得到代表调用者进程的ProcessRecord对象,代表调用者Activity的ActivityRecord对象。做权限检查的校验,并创建待启动Activity的ActivityRecord对象。调用startActivityUnchecked进一步处理。
4.ActivityStarter.startActivityUnchecked
获取到任务栈相关的信息,然后调用代表任务栈的ActivityStack的startActivityLocked方法。
5.ActivityStack.startActivityLocked
确定了待启动Activity所属的任务栈,并且将其放入任务栈。然后返回到ActivityStarter的startActivityUnchecked方法中,调用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法进一步操作。
6.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked
直接将操作委托给ActivityStack执行。
7.ActivityStack.resumeTopActivityUncheckedLocked
调用自身resumeTopActivityInnerLocked方法。
8.ActivityStack.resumeTopActivityInnerLocked
这个方法中执行了两个主要的操作:
调用startPausingLocked方法完成前一个Activity的onPause生命周期调用。调用ActivityStackSupervisor的startSpecificActivityLocked方法完成启动Activity。我们在分析Activity生命周期回调时再去分析startPausingLocked方法,现在继续分析启动流程。
9.ActivityStackSupervisor.startSpecificActivityLocked
这个方法中判断待启动Activity所要求的进程是否存在,如果不存在就创建进程。这里我们不分析创建进程流程,继续向下看存在进程情况下的启动流程。
10.ActivityStackSupervisor.realStartActivityLocked
调用应用程序进程内ApplicationThread的scheduleLaunchActivity方法来完成Activity创建和启动。
到这里AMS进程内的操作流程就简单介绍完了,下面来看在在应用程序进程内是如何创建Activity的。
1.ApplicationThread.scheduleLaunchActivity
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, ...) { updateProcessState(procState, false); ActivityClientRecord r = new ActivityClientRecord(); r.token = token; r.activityInfo = info; ... sendMessage(H.LAUNCH_ACTIVITY, r); }首先创建出一个在应用程序进程内表示Activity的对象。与之对应的是在AMS进程内表示Activity的ActivityRecord对象。然后将一些参数赋值给ActivityClientRecord。这里有两个属性需要注意:
token。是一个类型为IBinder的代理对象,指向了AMS中一个ActivityRecord。activityInfo。表示待启动Activity信息。然后调用sendMessage方法,这个方法执行逻辑在ActivityThread类的属性mH上。mH是一个类型为H的Handler对象,其将操作转到应用程序进程主线程内执行。来看一下类H处理逻辑。
2.H.handleMessage
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; } }调用getPackageInfoNoCheck方法得到PackageInfo对象,然后调用handleLaunchActivity方法启动Activity。getPackageInfoNoCheck方法很重要,暂时先不去管,等到分析插件化处理时再来仔细研究它。继续Activity启动流程,下面是handleLaunchActivity方法。
3.ActivityThread.handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) { ... Activity a = performLaunchActivity(r, customIntent); ... }主要是调用performLaunchActivity来启动Activity。
4.ActivityThread.performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; ... ComponentName component = r.intent.getComponent(); ... Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ... } catch (Exception e) { ... } try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); ... if (activity != null) { Context appContext = createBaseContextForActivity(r, activity); ... activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window); ... if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } r.activity = activity; ... } r.paused = true; mActivities.put(r.token, r); } catch (SuperNotCalledException e) { throw e; } return activity; }这个方法很重要,它做了以下几个操作:
拿到加载Activity的ClassLoader。这个ClassLoader是从ActivityClientRecord的packageInfo属性中拿到的,如果有印象可以记起来这个packageInfo是调用getPackageInfoNoCheck方法创建出来的。拿到当前进程中的Application对象。使用ActivityClientRecord中的token等内容创建ContextImpl对象,并且在内部持有待启动Activity的引用。调用Activity的attach方法在其内部保存一些ActivityClientRecord内的属性。调用activity的onCreate方法。将ActivityClientRecord中的activity属性设置为当前activity。以ActivityClientRecord中的token为key,mActivities中添加待启动的activity。这样Activity的启动流程大致就介绍完了,下面来介绍Activity的生命周期回调流程。
Activity生命周期回调大概分为两种,一种是在创建了Activity后直接回调的,例如onCreate、onResume。另一种是在进行一系列操作以后回调的,如onPause、onStop等。在这里我们重点分析后者,因为后者通常是在AMS进程中发起回调,我们要关系的是AMS是如何找到对应的Activity并执行回调。
这里我们拿onPause方法来举例,因为在刚刚分析的Activity启动流程内就涉及了onPause操作。在AMS进程内部处理第八步中我们谈到了,ActivityStack的resumeTopActivityInnerLock方法中调用了startPausingLocked方法完成对前一个Activity的onPause生命周期回调,现在来看一下这个方法。
1.ActivityStack.startPausingLocked
这个方法在AMS进程中运行,不贴代码了,最终调用了以下代码:
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing, userLeaving, prev.configChangeFlags, dontWait);很熟悉的流程,prev.app.thread是前一个Activity所在进程的ApplicationThread。
2.Application.schedulePauseActivity
public final void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport) { sendMessage( finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY, token, (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0), configChanges, seq); }用mH发了消息,看一下消息处理逻辑。
3.mH.handleMessage
public void handleMessage(Message msg) { switch (msg.what) { ... case PAUSE_ACTIVITY: { SomeArgs args = (SomeArgs) msg.obj; handlePauseActivity((IBinder) args.arg1, false, (args.argi1 & USER_LEAVING) != 0, args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3); } break; } }调用handlePauseActivity完成onPause回调。
4.ActivityThread.handlePauseActivity
private void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport, int seq) { ActivityClientRecord r = mActivities.get(token); ... if (r != null) { ... performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity"); ... } }方法很简单,调用了performPauseActivity。
5.ActivityThread.performPauseActivity
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished, boolean saveState, String reason) { ... if (!r.activity.mFinished && saveState) { callCallActivityOnSaveInstanceState(r); } performPauseActivityIfNeeded(r, reason); ... }方法先调用Activity的onSaveInstanceState保存一下状态,然后调用onPause方法。
这样Activity启动流程和生命周期回调流程都简单分析完了,接下来将结合两种不同类型的插件化框架分析插件化中Activity的加载和启动。