插件化中Activity的加载

    xiaoxiao2021-03-25  138

    插件化中Activity的加载

    前面一系列的文章中我们介绍了Android系统资源加载流程,最后引出插件化中资源加载的方法,完成了『资源动态加载』这一大块的介绍。本系列文章将重点介绍『代码动态加载』,拿最熟悉的Activity来开刀。

    基础知识

    Activity虽然是一个Java对象,可以使用ClassLoader加载出它的实体,但是由于Activity生命周期管理是由系统框架完成的,为了更好的分析如何加载插件中的Activity以及让它“活”起来,我们有必要了解两方面的知识:

    Activity启动流程Activity生命周期回调流程

    Activity启动流程

    Activity的启动流程大致分三个阶段:

    应用程序进程内启动Activity操作AMS进程内部处理应用程序进程内创建Activity(可能是一个新的进程)

    我们将按照这个顺序来分析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方法。

    AMS进程内部处理

    启动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的。

    应用程序进程内创建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生命周期回调大概分为两种,一种是在创建了Activity后直接回调的,例如onCreate、onResume。另一种是在进行一系列操作以后回调的,如onPause、onStop等。在这里我们重点分析后者,因为后者通常是在AMS进程中发起回调,我们要关系的是AMS是如何找到对应的Activity并执行回调。

    Activity中onPause生命周期的回调

    这里我们拿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的加载和启动。

    转载请注明原文地址: https://ju.6miu.com/read-3047.html

    最新回复(0)