Activity的启动过程分析

作者: tmp_zhao | 来源:发表于2016-03-27 22:43 被阅读690次

    缘起

    我们在平时开发中都知道通过这样的代码就可以启动一个act,如下Context.startActivity(intent),但是你偶尔有没有想过它内部是如何实现的,或者说系统究竟干了哪些事情,怎么这个act就显示在用户面前呢?作为一个资深工程师我觉得你起码应该想过这个问题,下面我们一起来梳理下整个流程,以下分析基于6.0源码。

    在开始之前我还想啰嗦几句,其实启动一个act的过程,是一个标准的Android IPC过程,也就是通过Binder机制实现的跨进程通信,先预告下,后面慢慢细说。

    过程分析

    1. 一般我们都是通过调用Activity.startActivity(intent)来启动一个act的,紧接着它会调用其内部的startActivityForResult(intent, -1, null )方法,注意这里的requestCode==-1,因为我们不需要返回result;
    2. 接下来调用到了Instrumentation.execStartActivity()方法,它最终调用了如下代码:
      execStartActivity()方法
    3. 上面的ActivityManagerNative.getDefault().startActivity实际通过Binder机制调到了
      另一个进程中的AMS.startActivity方法,代码如下:
      server/am/ActivityManagerService.java
      接下来在AMS这边的调用流程这里简要罗列下,具体实现细节可以参考源码,流程如下:
    ActivityStackSupervisor.startActivityMayWait -->    
    ActivityStackSupervisor.startActivityLocked -->
    ActivityStackSupervisor.startActivityUncheckedLocked -->
    ActivityStack.resumeTopActivitiesLocked -->
    ActivityStack.resumeTopActivityInnerLocked -->
    ActivityStackSupervisor.startSpecificActivityLocked -->
    ActivityStackSupervisor.realStartActivityLocked
    

    最终在ActivityStackSupervisor.realStartActivityLocked里有这样的代码:

    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                        new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                        task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                        newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
    

    这段代码很关键,这里app.thread的类型为android.app.IApplicationThread,其源码大概是这个样子:

    IApplicationThread.java
    1. IApplicationThread的真正实现者就是客户端进程中ActivityThread的内部类ApplicationThread,我们去看眼其实现:


      ApplicationThread实现

      绕了一个大圈子,activity的启动流程终于又回到客户端进程了,我们看下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 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);
            }
    

    可以看到代码主要是用传进来的参数构造了一个ActivityClientRecord实例,然后发送了一个LAUNCH_ACTIVITY的msg;

    1. 对此消息的处理实质是调用了ActivityThread.handleLaunchActivity方法,代码如下:
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();
            mSomeActivitiesChanged = true;
    
            if (r.profilerInfo != null) {
                mProfiler.setProfiler(r.profilerInfo);
                mProfiler.startProfiling();
            }
    
            // Make sure we are running with the most recent config.
            handleConfigurationChanged(null, null);
    
            if (localLOGV) Slog.v(
                TAG, "Handling launch of " + r);
    
            // Initialize before creating the activity
            WindowManagerGlobal.initialize();
    
            Activity a = performLaunchActivity(r, customIntent);
    
            if (a != null) {
                r.createdConfig = new Configuration(mConfiguration);
                Bundle oldState = r.state;
                handleResumeActivity(r.token, false, r.isForward,
                        !r.activity.mFinished && !r.startsNotResumed);
    
                if (!r.activity.mFinished && r.startsNotResumed) {
                    // The activity manager actually wants this one to start out
                    // paused, because it needs to be visible but isn't in the
                    // foreground.  We accomplish this by going through the
                    // normal startup (because activities expect to go through
                    // onResume() the first time they run, before their window
                    // is displayed), and then pausing it.  However, in this case
                    // we do -not- need to do the full pause cycle (of freezing
                    // and such) because the activity manager assumes it can just
                    // retain the current state it has.
                    try {
                        r.activity.mCalled = false;
                        mInstrumentation.callActivityOnPause(r.activity);
                        // We need to keep around the original state, in case
                        // we need to be created again.  But we only do this
                        // for pre-Honeycomb apps, which always save their state
                        // when pausing, so we can not have them save their state
                        // when restarting from a paused state.  For HC and later,
                        // we want to (and can) let the state be saved as the normal
                        // part of stopping the activity.
                        if (r.isPreHoneycomb()) {
                            r.state = oldState;
                        }
                        if (!r.activity.mCalled) {
                            throw new SuperNotCalledException(
                                "Activity " + r.intent.getComponent().toShortString() +
                                " did not call through to super.onPause()");
                        }
    
                    } catch (SuperNotCalledException e) {
                        throw e;
    
                    } catch (Exception e) {
                        if (!mInstrumentation.onException(r.activity, e)) {
                            throw new RuntimeException(
                                    "Unable to pause activity "
                                    + r.intent.getComponent().toShortString()
                                    + ": " + e.toString(), e);
                        }
                    }
                    r.paused = true;
                }
            } else {
                // If there was an error, for any reason, tell the activity
                // manager to stop us.
                try {
                    ActivityManagerNative.getDefault()
                        .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
                } catch (RemoteException ex) {
                    // Ignore
                }
            }
        }
    

    通过其源码我们发现,它又将重任交给了performLaunchActivity方法,这个方法主要做了以下几件事情:
    1. 从ActivityClientRecord中获取待启动act的组件信息;
    2. 通过Instrumentation.newActivity方法使用ClassLoader创建act对象;
    3. 通过LoadedApk.makeApplication方法创建Application对象,注意如果已经有Application对象的话是不会再次创建的;
    4. 创建ComtextImpl对象,并调用Activity.attach方法完成一些重要数据的初始化操作;
    5. 最终调用Activity.onCreate()方法;

    至此,act的整个启动流程就走完了。

    总结

    平时对于我们开发人员来说,可能还是最后这块客户端部分的代码比较
    有用,非常有助于我们的理解,特别是对performLaunchActivity的源码,有空的话还需要细细品味啊。

    注:关于这里第5步更详细的文章见这里ActivityThread.handleLaunchActivity方法分析

    相关文章

      网友评论

      本文标题:Activity的启动过程分析

      本文链接:https://www.haomeiwen.com/subject/noahlttx.html