Activity启动时发生了什么

前言

平日开发,Activity.startActivity()算是熟面孔,功能无须赘言。但它又像是最熟悉的陌生人,因为仅仅API,是不知道在启动一个Activity时,发生了什么。这也是本文的目的———说清Activity的启动发生的事情。

但开篇并不是从Activity.startActivity()。因为更常见的场景是,点击桌面APP图标,启动了APP。实际上,这是启动了某一APP的“Launcher Activity”,也称根Activity启动。而在同一APP下的其它Activity启动,称为子Activity的启动。

NOTE: 正文处源码版本8.0,源码存有差异,但核心不变。

从AMS角度看Activity

在分析Activity的启动前,先从AMS(ActivityManagerService)的视角看在Activity的存在。AMS是Android最核心的服务之一,主要作用可以理解为管理四大组件、处理应用进程、记录系统运行时状态。Activity作为四大组件之一,自然服从于AMS的管理。在AMS的眼里,并不直接与Activity打交道,而是通过ActivityRecord作为媒介记录了有关于Activity运行数据与状态信息。

仅仅知道ActivityRecord却不够,Activity需要运行在某一进程里。而ProcessRecord则记录了进程的所有信息。通过规整ActivityRecord和ProcessRecord的信息,AMS就可以知道如何运行一个Activity。

从使用一个APP的过程中,自然地认为使用此APP的所有Activity运行应以APP为维度进行关联。在AMS的描述中,和上文的想法是有差异的。AMS更愿意用Task来描述一系列ActivityRecord的聚合关系。


Activity聚合关系 (1).png

ActivityRecord颜色代表所在进程。

Task聚合的ActivityRecord所描述的Activity可以来自不同的进程,因此Task可由不同的APP组成来完成一系列的工作。

示例如下

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FActivity"
            android:launchMode="singleInstance"></activity>
        <activity android:name=".TActivity" />
        <activity
            android:name=".SActivity"
            android:process=":remote" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
task.jpg

图中从Main -> S -> T -> F的顺序启动了Activity, 通过命令

adb shell dumpsys activity | grep packageName

可以看到当前Activity在AMS中的样子,符合第一张图。

  • Main、S、T属于TASK #5791,F属于另一个TASK #5792
  • Main、T、F运行于进程30223,S运行于进程30670

根启动

回到正题。

根启动最常进的场景是从桌面点击了一个APP图标启动到APP的“Launch Activity”,此中,桌面其实是Launcher,并且Launcher也是一个Activity,内聚了其它APP的信息,以方便用户操作。如果手机不使用Launcher的话,那么当你启动手机后,屏幕所呈现的模样,与终端无异。

既然Launcher为Activity,则遵循Activity生命周期,见Launcher.onCreate()

@Override
    protected void onCreate(Bundle savedInstanceState) {
        ......
        if (!mRestoring) {
            if (sPausedFromUserAction) {
                mModel.startLoader(true, -1);
            } else {
                // 开始加载app信息,初始状态sPausedFromUserAction为false
                mModel.startLoader(true, mWorkspace.getCurrentPage());
            }
        }
        ......
    }

通过mModel即LauncherModel开启线程任务LoaderTask向PMS获取各个APP的启动信息,信息保存于LauncherModel.mBgAllAppsList。收集的关键信息如在各Manifest定义的App包名、定义为action为MAIN,category为LAUNCHER的Activity的信息、应用图标等。关联信息并生成桌面图标。

如果对上述过程感兴趣,可查阅
-> Luancher.startLoader()
-> LoaderTask.run()
-> loadAndBindAllApps()
-> loadAllAppsByBatch()
这里点到为止,不做深入。

当Launcher准备各项启动信息,桌面生成了对应的图标后,点击某一图标,开始了一个APP根Activity的启动。

Launcher

    public void onClick(View v) {
        ......
        Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
            ......
            boolean success = startActivitySafely(v, intent, tag);
            ......
        } 
        ......
    }

APP图标点解由Launcher.onClick()接收,之前关联的关键启动信息存于View tag中,这里取出并用以启动。链路为Launcher.startActivitySafely() -> Launcher.startActivity() -> Activity.startActivity(),此过程中会为启动所用的Intent设置FLAG_ACTIVITY_NEW_TASK的标识位。不难理解,当前AMS中并没有关于此APP的相关TASK,理所应当为此次启动新建TASK进行处理。 Launcher本身为Activity,最终以Activity.startActivity()进行启动。

而以Activity.startActivity()启动,不管何种形式,最终到达Activity.startActivityForResult(),如下

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        // 根启动情况下,是没有mParent的    
        if (mParent == null) {
            ......
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);    
            ......
            } 
        // 子Activity启动
        else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } 
            else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

mInstrumentation为Instrumentation,用来监控应用程序和系统之间的交互操作。而mMainThread为ActivityThread,可以看作所说的主线程,但实际上ActivityThread并非线程,只是在ActivityThread.Main()时机,将各类在主线程里使用或于主线程交互的组件做了关联,比如创建了主线程Looper,与AMS通信的ApplicationThread等等。通过这类组件,能完成许多在主线程里完成的事而使ActivityThread看起来像是主线线程。

当系统启动一个应用程序进程时,会向此进程里加载一个ActivityThread,且由该进程启动的Activity组件的父Activity持有。

Activity.mToken为ActivityRecord.Token,之前说过ActivityRecord负责维护Activity的运行状态信息。在当前场景下,有了Launcher所对应的ActivityRecord,AMS自然能知道Launcher的详细信息,以便后续操作。

回到Instrumentation.execStarActivity()

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }

        // 先尝试通过ActivityMonitor拦截启动Activity的操作,并处理一些自己的事务,主要是测试用
        if (mActivityMonitors != null) {
          ......
        }

        // 通过AMS启动Activity
        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;
    }

Instrumentation将启动操作交由AMS启动。获取操作AMS的借由ActivityManager.getService()通过android.utils.Singleton和ServiceManager获取到AMS的代理对象IAcitivityManager。此操作涉及IPC。

通过AMS.startActivity()到达ActivityStarter.startActivityMayWait() , 路径为
AMS.startActivity() -> AMS.startActivityAsUser() -> ActivityStarter.startActivityMayWait()

    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,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {
        // resultTo 是 Activity.mToken , intent含有即将启动的Activity信息

        ......
        // 以intent为引子,从PMS收集Manifest的信息
        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
        ......

        // 收集即将启动的Activity信息
        // Collect information about the target of the Intent.
        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);

        ActivityOptions options = ActivityOptions.fromBundle(bOptions);
        ActivityStackSupervisor.ActivityContainer container =
                (ActivityStackSupervisor.ActivityContainer)iContainer;
        synchronized (mService) {
            ......

            final ActivityStack stack;
            if (container == null || container.mStack.isOnHomeDisplay()) {
                // 根Activity启动会来到这里,之前传来的container为空
                stack = mSupervisor.mFocusedStack;
            } else {
                stack = container.mStack;
            }
            

            if (aInfo != null &&
                    (aInfo.applicationInfo.privateFlags
                            & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
                // 防止有相同进程已经启动了
                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
            ......
            }

            // 这个ActivityRecord将用来记录新启用的Activity
            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, container,
                    inTask, reason);

        ......
    }

首先,以intent为引子,从PMS收集Manifest声明的信息存于ResolveInfo,ResolveInfo包含了Service、Activity、Provider等信息。有了ResolveInfo之后,也就有了ActivityInfo———关于将要启动的Activity的更多信息,包括theme、launchMode、taskAffinity等。

在拥有这些信息之后,还需要检验是否已有相同的进程已经在运行。也可以看到,进程名与包名一致。当前情况下,还没有相应的进程。而outRecord将在后续作为记录要启动的Activity状态信息的ActivityRecord。

链路 -> ActivityStarter.startActivityLocked() -> ActivityStarter.startActivity()

    /** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
        int err = ActivityManager.START_SUCCESS;
        // Pull the optional Ephemeral Installer-only bundle out of the options early.
        final Bundle verificationBundle
                = options != null ? options.popAppVerificationBundle() : null;

        ProcessRecord callerApp = null;
        if (caller != null) {
            // 拿到caller所在进程的ProcessRecord
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                // 拿到pid 和 uid
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller
                        + " (pid=" + callingPid + ") when starting: "
                        + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }
        
        ......
        ActivityRecord sourceRecord = null;     // 来源Activity
        ActivityRecord resultRecord = null;     
        if (resultTo != null) {
            // 从 Activity Stack 获取已经存在的sourceRecord, 根启动对应为launcher的 AR
            sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
            ......
        }
        
        ......
        // 为新启动的Activity拿到AR
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, container, options, sourceRecord);
        if (outActivity != null) {
            outActivity[0] = r;
        }

        ......

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

ProcessRecord用以描述进程,在AMS内部mProcessNames保存了已有进程的信息。当前场景下,拿到了Launcher所在进程的ProcessRecord并记录相关pid与uid,并从Stack中获取Launcher所对应的ActivityRecord。紧接着,为要新开启的Activity创建ActivityRecord以作为此后对此Activity的管理维护依据。

链路ActivityStarter.startActivity() -> ActivityStarter.startActivityUnchecked()

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {

        /**
         * 因为借助ActivityStarter来启动Activity,这里已有必要的数据,将数据关联到ActivityStarter,方便后续处理
         */
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor);

        // 检查标志位 ,以决定是否要新启Task,即是否新建Stack, 满足条件mAddingToTask = true
        computeLaunchingTaskFlags();

        computeSourceStack();

        mIntent.setFlags(mLaunchFlags);

        /**
         * 考虑新启用的Activity singleTask or singleInstance 的启动模式的情况,此时可能已经有AR了 和相应 Task
         */
        ActivityRecord reusedActivity = getReusableIntentActivity();
        
        ......
        // 根启动满足此条件,  根节点的话,不需要知道执行结果,自然resultTo为null
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            // 确保拿到可用的Task
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);
        } 
        ......
        /**
         * 这个函数的意义在于,将Activity放入栈顶,以便之后激活
         */
        mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                mOptions);
        if (mDoResume) {
             mWindowManager.executeAppTransition();
            } else {
                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }
                // 根启动进这里
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        }

在真正地去启动Activity之前,记录一些关键信息存于ActivityStarter成员变量中,在之后可以直接访问。并且,需要考虑Activity的启动模式,通常情况下,一个Activity启动另一个Activity,两个Activity会内聚于同一个Task来处理。但当设置标识为FLAG_ACTIVITY_NEW_TASK时,会为要启动的Activity寻找合适的Task处理。使用“合适”一词说明,Task存在复用的情况,如果没有找到可复用的Task,则新建。

如前文所说,从Launcher启动的根Activity已设置了FLAG_ACTIVITY_NEW_TASK,因此新建了Task进行处理。然后将要启动的Activity放置于栈顶,以为之后激活。

在ActivityStack中,mResumeActivity、mLastPausedActivity、mPausingActivity分别用来记录当前要激活的Activity、上一次被paused的Activity和此次要paused的Activity。

链路ActivityStackSupervisor.resumeFocusedStackTopActivityLocked() -> ActivityStack.resumeTopActivityUncheckedLocked() -> ActivityStack.resumeTopActivityInnerLocked()

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        ......
        // 拿到将要激活的Activity的AR
        final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
        
        ......
        // 如果已经要激活的Activity为mResumedActivity 且状态为RESUMED的话,什么也不做
        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
        ......
        
        // 是否要通知来源Activity pause
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            // 通知Launcher,该进入pause状态了
            pausing |= startPausingLocked(userLeaving, false, next, false);
        }
            return false;
        }
        ......
        
        // 根启动时不会进入到这里,因为next.app为空
        if (next.app != null && next.app.thread != null) {
            ......
                    if (next.newIntents != null) {
                    // 启动activity
                    next.app.thread.scheduleNewIntent(
                            next.newIntents, next.appToken, false /* andPause */);
                }
        } else {
            ......
            // 根节点启动,为activity启动进程
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }
        ......
    }

之前已经将要激活的Activity的ActivityRecord推至栈顶,直接可以从栈顶获取。此时,将要委托ActivityThread去启动Activity,但是,根Activity所需要的进程还没创建,也就没有对应的ActivityThread,需要先创建进程,随后激活Activity。在新建进程前,通知Launcher进入pause状态。

ActivityThread

ActivityThread会伴随APP进程的创建而诞生。在前文所说的ActivityRecord里,ActivityRecord知道Activity运行时所知的各种信息,其中就包括运行所在进程的进程信息描述ProcessRecord。ProcessRecord拥有IApplicationThread实例,当AMS需要对Activity进行操控时,通过需要ApplicationThread的本地Binder——IApplicationThread便能与APP所在进程进行通信。

在ActivityThread中,类名为H的Handler,则接收各种消息信号处理相应的事件。

Launcher进入pause

ActivityStack.startPausingLocked()

    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
            ActivityRecord resuming, boolean pauseImmediately) {
        ......
        // 指向启动来源的Activity
        ActivityRecord prev = mResumedActivity;
        ......
        // 更新,因为mLastPausedActivity表示上一次暂停的Activity
        mLastPausedActivity = prev;
        ......
                if (prev.app != null && prev.app.thread != null) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
            try {
                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                        prev.userId, System.identityHashCode(prev),
                        prev.shortComponentName);
                mService.updateUsageStats(prev, false);
                // 向AT发送通知,让启动来源Activity pause ,有机会执行自己的bussiness
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, pauseImmediately);
            } 
            ......
        } 
    ......
        if (mPausingActivity != null) {
            ......
            else {
                // 发出PAUSE_TIMEOUT_MSG
                schedulePauseTimeout(prev);
                return true;
            }

        }
}

通过IApplicationThread让ActivityThread处理Launcher的Pause事件,让Launcher时机处理自己Pause()时的逻辑,同时,在延迟PAUSE_TIMEOUT_MSG时间后,发出激活新Activity的信息。这样做的原因是因为,在确保旧Activity的onPause()事件完成后,需要AMS启动新的Activity,这也符合我们所知的Activity生命周期规律。由于是进程间异步操作,ActivityStack、AMS不能确切知道旧的Activity完成onPause()的准确时机,因此,AMS决定等待PAUSE_TIMEOUT_MSG时间,如果旧的Activity没有在PAUSE_TIMEOUT_MSG时间内完成onPause(),则被认为没有相应。

PAUSE_TIMEOUT_MSG事件由ActivityStack内部类ActivityStackHandler接收

链路
ActivityStack.activityPausedLocked() -> ActivityStack.completePauseLocked() ->
ActivityStackSupervisor.resumeFocusedStackTopActivityLocked() ->
ActivityStackSupervisor.resumeTopActivityUncheckedLocked() ->
ActivityStack.resumeTopActivityInnerLocked()

再此来到ActivityStack.resumeTopActivityInnerLocked()
第一次来到,是给旧的Activity一个Pause时机
第二次来到,是启动新的Activity

此前的情况是,根Activity的启动,也是第一次来到时,还需要为APP创建新的进程

 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
     ......
     mStackSupervisor.startSpecificActivityLocked(next, true, true);
     ......
 }

ActivityStackSupervisor.startSpecificActivityLocked()

    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        /**
         * 在AMS中,每一个Activity组件都有一个UID和进程名称,UID在安装Activity时PMS分配,
         * 进程名称由android:process属性决定。AMS启动Activity时,首先会以其UID和进程名来检查
         * 进程是否存在,存在则由那个进程启动,否则新建进程再启动
         */
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.getStack().setLaunchTime(r);

        // 子Activity与根Activity运行在同一进程里app和app.thread不再为空
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                // 子Activity在同一进程里启动
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }

        // 冷启动
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

因为没有所需进程,需重新创建进程,也就是常说的冷启动过程。

链路
-> ActivityManagerService.startProcessLocked()
-> ActivityManagerService.startProcessLocked()
-> ActivityManagerService.startProcessLocked()

    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        long startTime = SystemClock.elapsedRealtime();
        if (app.pid > 0 && app.pid != MY_PID) {
            ......
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.remove(app.pid);
                // 发送PROC_START_TIMEOUT_MSG
                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            }
            ......
        }
        ......
    try{
        ......
        else {
                // 启动新的应该进程
                // entryPoint 为 "android.app.ActivityThread"
                // 剩下交给 Zygote 去孵化
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, entryPointArgs);
            }
       ......
        synchronized (mPidsSelfLocked) {
                this.mPidsSelfLocked.put(startResult.pid, app);
                if (isActivityProcess) {
                    // 如果进程不能在PROC_START_TIMEOUT_MSG事件启动,则认为启动超时
                    Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                    msg.obj = app;
                    mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                            ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
                }
            }
    }
    ......

进程启动则交给Zygote孵化,创建了进程,也创建了ActivityThread。 进程创建需要在PROC_START_TIMEOUT_MSG时间内完成,否则认为创建失败,也就没有了后续的过程。

ActivityThread创建则见ActivityThread.main(),此后也就有了用于处理消息的Looper,用于通信的ApplicationThread。此一笔带过。

启动Activity

回到之前的流程,在有了进程,旧Activity已经Pause,已可以启动Activity
ActivityStackSupervisor.resumeTopActivityInnerLocked()
-> ActivityStackSupervisor.startSpecificActivityLocked()
-> ActivityStackSupervisor.realStartActivityLocked()

    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
            ......
        // 记录 ProcessRecord
        r.app = app;
        app.waitingToKill = null;
        r.launchCount++;
        r.lastLaunchTime = SystemClock.uptimeMillis();

        if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);

        int idx = app.activities.indexOf(r);
        if (idx < 0) {
            // 将 activity 加入 activity 组件列表
            app.activities.add(r);
        }
        ......
        try {
            // 调用ActivityThread的scheduleLaunchActivity启动activity
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    // TODO: Have this take the merged configuration instead of separate global and
                    // override configs.
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);
        }
        ......
        
}

为ActivityRecord记录了相关的ProcessRecord信息,再让通过ActivityThread启动Activity

ActivityThread.H.handlerMessage

                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    // 需要加载APK文件,以便访问资源
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    // 加载Activity
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");

链路
ActivityThread.handleLaunchActivity()
ActivityThread.performLaunchActivity()

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            // // 获取Context对象
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            // 功过类加载器创建Activity
            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,没有则创建
            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 = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                // 创建Activity所需的Context
                appContext.setOuterContext(activity);
                // Context与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);
                        
                        ......
                        
                                        int theme = r.activityInfo.getThemeResource();
                // activity主题设置
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                // 调用Activity.onCreate()
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ......
    }

Activity.onCreate() 完成,则意味着Activity已启动。

子Activity的启动

上文描述了根Activity的启动过程,而子Activity的启动大致相同,不同点如下

  • 在ActivityStarter.startActivityUnchecked()为Activity寻找Task时,已有Task
    而无需创建新的Task,除非子Activity设置启动FLAG为FLAG_ACTIVITY_NEW_TASK
  • 子Activity在不同进程里启动时,AMS不会为子Activity创建新的Task,但会在ActivityStackSupervisor.startSpecificActivityLocked()为这个子Activity创建新的进程。

总结

  • Task是一个比进程更高级和抽象的概念,每一个Activity都运行在一个Taks中。Task将一系列相关的Activity组件整合再一起,共同完成一个业务功能。如系统中存在A功能应用进程,包含实现A功能的Activity,在其它APP使用这个功能时,Task保证A的Activity与其运行在一个Task里,如此用户感觉不到应用进程的不同。
  • 启动Activity需考虑所在Task和所处进程情况
  • AMS需保证进程的创建时机可控、Activity的生命周期执行时机可控
  • Activity的启动过程,实际上是AMS以ActivityRecord为信息媒介,以IApplicationThread为通信手段的通信管理过程

小思考

为什么不要在onPause()里执行耗时任务?
新旧Activity在交替时生命周期的执行,AMS和ActivityThread会保证一定的时序性与约束性,但有局限性。onPause()耗时任务认为会影响新Activity,也带来不佳的用户体验。但,用户体验只能算是一部分原因,更重要的原因在于,onPasuse()方法是数据持久化的重要的可靠时机,当发生如内存重启等异常突发情况致使进程突发死亡,那么onStop()、onDestroy()并不能保证是一定会被执行。
仅仅以用户体验为由是不足以说明问题的。可以试验这样的场景:A启动B,B在不同进程,A的onPause()执行耗时任务。在这种场景下,B的onCreate()、onStart()、onResume()远远早于A的onPause(),看不到“影响用户体验”。那么,在这样的场景下,就可以在onPause()里执行耗时任务吗?


参考
UserHandle
Task
Android Launcher 启动 Activity 的工作过程
onPause()方法的特殊性

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容