Android Activity的启动过程

2018-11-15  本文已影响0人  ZuYuan

在文章开始之前说一下,这篇文章会涉及到一些跨进程的知识,对这方面不了解的可以先去看一下有关于Binder的文章。

Activity的启动流程

在讲之前,我们先了解下几个类:

  • ActivityThread :内含main() 函数,是一个应用的入口,当前线程也就是我们的主线程。
  • ApplacationThread: ActivityThread 的内部类,它继承自IApplicationThread.StubIApplicationThread.Stub 是生成的AIDL文件中的一个继承自Binder的抽象内部类。很明显,ApplicationThtread对象即是是一个Binder对象,并且它是在应用进程中实例的。
  • ActivityManagerService: 同ApplicationThread类似,它也是继承自Binder,不过区别在于AMS的实例化是在系统进程中进行的。

我们接下来从Activity 的 startActivity() 出发跟着源码走上一遍:

Activity中startActivity()最终实现的还是startActivityForResult()中去,我们看一下这个方法:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    if (mParent == null) {
        //处理下传递给下一个活动的数据,因为这里是用户传递的数据,所以不作讨论。
        options = transferSpringboardActivityOptions(options);
        //启动活动再从这里执行
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, o  ptions);
        //启动另外一个活动返回得到的结果
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            mStartedActivity = true;
        }
         //为子窗口考虑清理/刷新其他事件源及事件
        cancelInputsAndStartExitTransition(options);
    } 

    ...
}

这里提一下mParent这个对象,它现在已经被弃用了。简单说来,在原来没有Fragment的时候,活动是可以附着在它的父活动上的,这个mParent就是一个子活动的父活动对象,我们在这里只需要关注mParent == null 的逻辑。
接下来我们又遇到了Instrumentation这个类,我们要稍微讲解一下这个类,因为它在之后的流程中也是非常重要的。在官方给出的注释中有说到,它是在应用程序的所有代码在加载之前被实例的。在源码中Activity中出现的mInstrumentation在它的attach()方法(初始调用方法)中被赋值,我们再去到调用attach()方法的ActivityThread类中去找mInstrumentation,发现它就是在ActivityThread中绑定Application的时候就通过反射实例了出来,即一个应用程序绑定了一个Instrumentation对象。 Instrumentation的强大作用就是跟踪Application和Activity的生命周期,我们启动一个活动需要通过执行它的execStartActivity()方法来实现。
我们再来看这个方法中传入放入参数,原方法是这样execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options):

  • who: 活动开始的上下文。
  • contextHread: 活动开始的上下文的主线,Binder对象,这里是IApplicationThread接口对象。
  • token: Activity 的 令牌 ,它出自于ActivityClientRecord(客户端的活动记录),通过令牌token,就可以确保activity在不同层次都可以保持一一对应的关系。
  • target: 传入的是当前Activity对象,即是当前活动在启动另一个活动,若当前无活动,那么target应该为空。
  • intent: 执行操作的意图。
  • options: 添加选项。

下面是这个方法的关键部分:

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    try {
        intent.migrateExtraStreamToClipData();
        //做一些要离开当前进程的相关事情
        intent.prepareToLeaveProcess(who);
        //启动活动再从这里进行
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        //检查返回结果,执行报异常(例如活动未注册等异常)等操作
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

我们看下关键部分ActivityManager.getService().startActivity(),这个方法是在ActivityManager中这样执行的:

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                //拿到Binder的代理对象(其它进程的Binder实例在这个进程中的代理对象)
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
        };

IActivityManager是一个AIDL文件,而ActivityManagerService正是继承自这个接口中的Stub类,也就是我们最后拿到了系统进程中的Binder代理对象。也就是说我们接下去已经到了系统进程中去执行启动活动的相应步骤了。

但是在进入系统进程之前,我们再看一下传入的重要参数。whothread是一个非常重要的参数,它是什么?它就是Acivity传入的contextThread参数,它是一个IApplicationThread对象。而IApplicationThread是一个AIDL接口文件,我们找不到这个文件,可是我们可以找到它的实现,IApplicationThread.Stub就是被ApplicationThread给继承的, 这里的IApplicationThread对象也就是一个ApplicationThread对象。我们就可以看见Application 作为一个Binder对象实现了哪些方法:

public final void schedulePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
        int seq = getLifecycleSeq();
        if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
                + " operation received seq: " + seq);
        sendMessage(
                finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                token,
                (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
                configChanges,
                seq);
    }

public final void scheduleStopActivity(IBinder token, boolean showWindow,
            int configChanges) {
    //就不再列举完了
    ......

这些方法是什么,我们看一下,再熟悉不过了,就是发送消息,发送的消息目的什么?执行对活动周期的管理。我们将ApplicationThread对象的代理传递到到系统进程中去,那么目的在于 这些方法在应用进程实现,但是是在系统进程中去触发。

接下来我们就可以再系统进程中去分析了:

在源码跟进之前,我们再介绍几个类,以及它们的关系:

  • ActivityStater: 可以理解为它将启动Activity的逻辑收集在一个类中(并非创建Activity那个启动)。
  • ActivityRecord:一个Activity对应一个ActivityRecord,它几乎包含着一个Activity的所有信息,同时它还含有AMS的引用,还有一些binder的应用,在系统进程中可以说它就代表着一个Atcivity
  • TaskRecord:它的内部维护了一个ArraList<ActivityRecord>,用来储存并管理多个ActivityRecord。
  • ActivityTask:包含一堆Activity 的状态以及对一堆Activity 的管理(它是对TaskRecord的管理),内部维护了一个ArrayList<TaskRecord>,用来管理TaskRecord。
  • ActivityStackSupervisor:ActivityStackSupervisor内部有两个不同的ActivityStack对象:mHomeStack、mFocusedStack,用来管理不同的任务。ActivityStackSupervisor内部包含了创建ActivityStack对象的方法。AMS初始化时会创建一个ActivityStackSupervisor对象。

高能预警:接下来的源码太多了,因此我们就只跟着关键代码走,将主线拉通。

我们先到ActivityManagerService中的startActivity()方法中去看,在这个方法里面是直接执行了mActivityStarter.startActivityMayWait()用一个ActivityStart对象去执行,接下来我们看一下在ActivityStarter中是如何执行的:

final int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult,
        Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
        TaskRecord inTask, String reason) {

    synchronized (mService) {
        //主线从这里执行下去
        final ActivityRecord[] outRecord = new ActivityRecord[1];
        int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor,
                resultTo, resultWho, requestCode, callingPid,
                callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, outRecord, inTask,
                reason);
        return res;
    }
}

在省略了一大段代码后来到了startActivityLocked()方法中:

//关键代码
mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
            aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
            callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
            options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
            inTask);

然后再去到startActivity()方法中:在startActivity()方法的末尾有一句关键代码

  ....

 doPendingActivityLaunchesLocked(false);, 
 return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
            options, inTask, outActivity);   

我们再点进去看,实质上又调用了另外一个重载的startActivity()方法,我们接着进去看,发现关键代码是

result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, doResume, options, inTask, outActivity);    

接着走,关键代码是

  mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);   

接下来就到了ActivityStackSupervisor中去执行逻辑了。 我们还是要稍微关注一下该方法的参数,实质上mTargetStack 是一个ActivityStack对象,也就是我们的目标活动栈,mStartActivity则是一个ActivityRecord对象,也就是我们的目标Activity,这个方法中的关键代码 :

return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); 

target是ActivityRecord对象。

接下来就到了ActivityStack中去执行逻辑了。resumeTopActivityUncheckedLocked()方法中的关键代码:

result = resumeTopActivityInnerLocked(prev, options);  

进入resumeTopActivityInnerLocked()方法,我们找到关键的一句代码:

mStackSupervisor.startSpecificActivityLocked(next, true, false);

我们再次回到ActivityStackSupervisor中去。关键代码:

realStartActivityLocked(r, app, andResume, checkConfig);

接下来,到最后执行的方法了:

/**
 * @param r: 目标Acivity
 * @param app: 目标进程
 */
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {

     //此处省略n行代码...
     app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                        System.identityHashCode(r), r.info,
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, !andResume,
                        mService.isNextTransitionForward(), profilerInfo);

    //此处省略n行代码...
}

app.thread对象我们应该记得,它是一个IApplicationThread对象,也就是我们对应的ApplicationThread(Binder)对象,那么这里调用的便是应用进程里的Binder(ApplicationThread)代理对象,我们要回到应用进程中去了。调用的scheduleLaunchActivity()方法中,r指的是ActivityRecord对象,这里重点提r.token,这是上面提及的Activity 的“令牌”,便于在ActivityThread中找到目标Activity。

接下来就比较轻松了,我们直接到ActivityThread中的ApplicationThread中去看如何对活动进行的操作。
我们找到scheduleLaunchActivity()方法:

@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中去
        ActivityClientRecord r = new ActivityClientRecord();

        r.token = token;
        r.ident = ident;
        ...

        updatePendingConfiguration(curConfig);

        //H继承于Handler,也是ActivityThread的内部类
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }

为什么在这里使用了sendMessage()呢?这里复习一下Binder的知识,因为ApplicationThread作为一个Binder对象,它封装了自己的线程池,这里实现的方法则是在应用进程中的主线程中实例的Binder 的Binder线程池中实现的,因此我们需要使用H(Hnadler)来进行同步操作。
H类中,代码还是很简单的,主要是下面的格式:

private class H extends Handler {
    public static final int LAUNCH_ACTIVITY         = 100;
    public static final int PAUSE_ACTIVITY          = 101;
    ...
    
    String codeToString(int code) {
        if (DEBUG_MESSAGES) {
            switch (code) {
                case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
                case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY";
                ...
        }
        return Integer.toString(code);
    }

    public void handleMessage(Message msg) {
        if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
        switch (msg.what) {
            case STOP_ACTIVITY_HIDE: {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
                SomeArgs args = (SomeArgs) msg.obj;
                handleStopActivity((IBinder) args.arg1, false, args.argi2, args.argi3);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            } break;
            case:{
                ...
            }
            ...
        }
     //回收对象
    Object obj = msg.obj;
        if (obj instanceof SomeArgs) {
            ((SomeArgs) obj).recycle();
        }
    }
}

在它之中设置了许多标记位,就是根据相应的消息来调用ActivityThread中的对应的方法。我们找到H.LAUNCH_ACTIVITY对应的handleLaunchActivity()方法:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    
    ...
    //关键代码,启动一个Activity
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
        //onResunme() 显示到前台
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

        if (!r.activity.mFinished && r.startsNotResumed) {
            //如果需要则暂停,一般很少遇见
            performPauseActivityIfNeeded(r, reason);

            if (r.isPreHoneycomb()) {
                r.state = oldState;
            }
        } else {    
            //活动未加载出来,一般是出了错误
            try {
                ActivityManager.getService()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }
}

最关键的就是performLaunchActivity(r, customIntent);这个方法,启动一个Atcivity,我们去看一下究竟是如何启动的一个Activity:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    //保存一些信息,应用包名、综合信息
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    //包含应用报名和目标活动的类对象
    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(
            mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if (r.activityInfo.targetActivity != null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }

    //上下文对象
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        //创建活动实例
        //实质上是调用cl.loadClass(className).newInstance();
        java.lang.ClassLoader cl = appContext.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);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
        if (localLOGV) Slog.v(
                TAG, r + ": app=" + app
                + ", appName=" + app.getPackageName()
                + ", pkg=" + r.packageInfo.getPackageName()
                + ", comp=" + r.intent.getComponent().toShortString()
                + ", dir=" + r.packageInfo.getAppDir());

        if (activity != null) {
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
                config.updateFrom(r.overrideConfig);
            }
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            //删除原来的Window
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            appContext.setOuterContext(activity);
            //建立和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, r.configCallback);

            //...

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        //...
    }

    return activity;
}

这个方法的重要作用就是实例一个Activity,与该Activiy建立联系,在attach()方法传入的参数中,this代表的就是当前的ActivityThread,也就是我们的主线程(main函数实现),app就是指上面拿到的Application对象,这里的r.appToken不是ApplicationThread对象,是在ActivityThread中的内部类对象,这个类保存了ActivityRecord(activity)弱引用对象。并且在attach()方法的实现中,新创建了一个PhoneWindow(Window实现类)对象,这里传入了一个Window对象,根据原来的Window,创建一个新的Window。最后返回我们的目标Activity对象。

到这里,Activity的启动就告一段落了,虽然后面的分析基本没有代码细节可言,我们很多地方也是无法分析的,但是我们拉通了总线。

总结:我们使用startActivity()来启动另外一个活动,但在应用进程中是无法直接启动活动的,我们需要向系统进行请求,因此我们通过AMS(Binder)到系统进程中去请求,系统进程在给我们做好了一系列工作(ActivityRecord的记录等),再通过ApplicationThread(Binder)回到应用进程中执行对活动的操作,最终仍然是在ActivityThread中实现的,通过类加载器实例出我们的Activity,配置好Window,然后显示Activity。

拓展:

AMS(ActivityManagerService):
它是Android内核三大核心功能之一,它是贯穿Android 系统组件的核心服务,负责Android 四大组件的启动、切换、调度以及应用进程的管理和调度工作。
应用程序的启动:
先说Launcher:它就是桌面App,可以通过它启动其它的应用程序。
大体启动流程:

  1. Launcher通过Binder进程间通信机制通知ActivityManagerService,
    它要启动一个Activity。

  2. ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态。

  3. Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行。

  4. ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,以便以后ActivityManagerService能够通过这个Binder对象和它进行通信。

  5. ActivityManagerService通过Binder进程间通信机制通知ActivityThread,
    现在一切准备就绪,它可以真正执行Activity的启动操作了。

上一篇下一篇

猜你喜欢

热点阅读