android 开发之activity 启动流程《一》

前言

本篇文章更多的是记录自己研究的结果,因此可能有一些地方介绍的未必足够细致,还请包涵。

一、客户端startActivity

    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        startActivityForResult(intent, -1);
    }
}

两个重载方法,都调用了 startActivityForResult 方法,

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
 //跳转到Instrumentation执行
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
       xxx
}

  mParent 表示这 当现在的Activity 没有父Activity。mParent代表的是ActivityGroup, 最开始用来在一个界面中嵌入多个    子Activity,但是在API13中已经废弃了,Google推荐我们用Fragment来代替ActivityGroup。所以这里不需要关注mParent。

Instrumentation这个类,每个Activity都持有一个Instrumentation对象的一个引用,每个进程中只会存在一个Instrumentation对象,当startActivityForResult方法调用后实际还是调用了mInstrumentation.execStartActivity()。Instrumentation对象是在Activity的attach方法中初始化。

mMainThread 是 ActivityThread 也就是我们常说的主线程,mMainThread.getApplicationThread() ApplicationThread 是ActivityThread 的内部类。

ApplicationThread  是个Binder 对象,也可以看成是一个服务端,后面这个对象会传递给ActivityManagerService(AMS),AMS 会收到一个ApplicationThread  的客户端,这样就相当于AMS 持有了应用应用程序的客户端。后续AMS可以通过这个客户端返回启动页面的结果。

android 提供的Binder系统可以实现跨进程调用以及传递数据,这其中可以传递一类特殊的对象也就是Binder 对象,假如将一个匿名Binder 服务端传给另一端,,另一端后收到一个相应的客户端,这个是Binder 系统实现的,有感兴趣的朋友可以查阅相关资料。

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
           //使用AMS的代理与AMS通信启动页面,会把检查的结果result返回回来。
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
 //处理各种异常,如ActivityNotFound  
//result是AMS的检查结果.
//这里仅仅是发起启动,实际AMS启动页面是异步执行的?
//后续开启页面的步骤有AMS发起
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
        }
        return null;
    }
ActivityMonitor这个类只是google为了自动测试所添加的一个类,可以说是一个工具类,这里不分析相关代码。
ActivityManagerNative.getDefault()返回的是IActivityManager 对象,可以看做是ActivityManagerService 的客户端。ActivityManagerService  的startActivity会对将要启动的页面作一系列的检查,并把检查结果返回。

我们先看看checkStartActivityResult

/** @hide */
public static void checkStartActivityResult(int res, Object intent) {
    if (!ActivityManager.isStartResultFatalError(res)) {
        return;
    }

    switch (res) {
        case ActivityManager.START_INTENT_NOT_RESOLVED:
        case ActivityManager.START_CLASS_NOT_FOUND:
            if (intent instanceof Intent && ((Intent)intent).getComponent() 
!= null)
//,如果 Activity 没有在 AndroidMainfest.xml 注册,将会抛出此异常。
                throw new ActivityNotFoundException(
                        "Unable to find explicit activity class "
                        + ((Intent)intent).getComponent().toShortString()
                        + "; have you declared this activity in your 
AndroidManifest.xml?");
            throw new ActivityNotFoundException(
                    "No Activity found to handle " + intent);
  	 //没有权限打开对应的页面
        case ActivityManager.START_PERMISSION_DENIED:
            throw new SecurityException("Not allowed to start activity "
                    + intent);
        case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
            throw new AndroidRuntimeException(
                    "FORWARD_RESULT_FLAG used while also requesting a result");
        case ActivityManager.START_NOT_ACTIVITY:
            throw new IllegalArgumentException(
                    "PendingIntent is not an activity");
        case ActivityManager.START_NOT_VOICE_COMPATIBLE:
            throw new SecurityException(
                    "Starting under voice control not allowed for: " + intent);
        case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
            throw new IllegalStateException(
                    "Session calling startVoiceActivity does not match active session");
        case ActivityManager.START_VOICE_HIDDEN_SESSION:
            throw new IllegalStateException(
                    "Cannot start voice activity on a hidden session");
        case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
            throw new IllegalStateException(
                    "Session calling startAssistantActivity does not match active session");
        case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
            throw new IllegalStateException(
                    "Cannot start assistant activity on a hidden session");
        case ActivityManager.START_CANCELED:
            throw new AndroidRuntimeException("Activity could not be started for "
                    + intent);
        default:
            throw new AndroidRuntimeException("Unknown error code "
                    + res + " when starting " + intent);
    }
}

可以看到常见的ActivityNotFoundException 异常。

二、AMS 之startActivity

前面分析了第一阶段APP 启动页面的部分,下面看看AMS 在收到页面的请求的时候是如何处理的。

     @Override
        public int startActivity(IBinder whoThread, String callingPackage,
                Intent intent, String resolvedType, Bundle options) {
            checkCaller();

            int callingUser = UserHandle.getCallingUserId();
            TaskRecord tr;
            IApplicationThread appThread;
            synchronized (ActivityManagerService.this) {
                tr = recentTaskForIdLocked(mTaskId);
                if (tr == null) {
                    throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                }
                appThread = ApplicationThreadNative.asInterface(whoThread);
                if (appThread == null) {
                    throw new IllegalArgumentException("Bad app thread " + appThread);
                }
            }
            return mStackSupervisor.startActivityMayWait(appThread, -1, callingPackage, intent,
                    resolvedType, null, null, null, null, 0, 0, null, null,
                    null, options, callingUser, null, tr);
        }

  假设是在app 内部启动另一个一面,appThread  就是前文提到的ApplicationThread 的客户端。

mStackSupervisor 是 ActivityStackSupervisor类型,是用来管理ActivityStack,而ActivityStack 是用来管理TaskRecord,TaskRecord 也就是我们所说的页面栈, 用来保存启动的Activity.
    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 config,
                                   Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask)
    {
        // Refuse possible leaked file descriptors
        //禁止通过intent传递File
        if (intent != null && intent.hasFileDescriptors()) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        boolean componentSpecified = intent.getComponent() != null;

        // Don't modify the client's object!
        intent = new Intent(intent);

        // 查找对应的页面是不是存在,一般是解析配置文件
        ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
                profilerInfo, userId);

        ActivityContainer container = (ActivityContainer)iContainer;
        synchronized (mService) {
            final int realCallingPid = Binder.getCallingPid();
            final int realCallingUid = Binder.getCallingUid();
            int callingPid;
            if (callingUid >= 0) {
                callingPid = -1;
            } else if (caller == null) {
                callingPid = realCallingPid;
                callingUid = realCallingUid;
            } else {
                callingPid = callingUid = -1;
            }

            final ActivityStack stack;
            if (container == null || container.mStack.isOnHomeDisplay()) {
                stack = getFocusedStack();
            } else {
                stack = container.mStack;
            }
            stack.mConfigWillChange = config != null
                    && mService.mConfiguration.diff(config) != 0;
            
            final long origId = Binder.clearCallingIdentity();

            if (aInfo != null &&
                    (aInfo.applicationInfo.flags& ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
                   //mHeavyWeightProcess 见下面
                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
                    if (mService.mHeavyWeightProcess != null &&
                            (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
                                    !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
                    }
                }
            }
           //调用startActivityLocked

            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options,
                    componentSpecified, null, container, inTask);

            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

首先做了一个检查,禁止通过intent 传递File。其次检查了要启动的页面是不是重量级进程,如果解析的ActivityInfo不为空,且ApplicationInfo有ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE标记,意味着调用者App是属于heavy-weight process,如果现在有另一个heavy-weight process正在运行,则需要进行一些额外的处理,然后进入到startActivityLocked方法。

若App有ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE标记,App就可视为heavy-weight process,该标记可以在AndroidManifest.xml中设置,它是用于声明App是否享受系统提供的Activity状态保存/恢复功能的。对于用户app而言在解析的时候会忽略掉这个表示,因此用户app 无法成为重量级进程,此处不再进一步介绍。

    final int startActivityLocked(IApplicationThread caller,
                                  Intent intent, String resolvedType, ActivityInfo aInfo,
                                  IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                                  IBinder resultTo, String resultWho, int requestCode,
                                  int callingPid, int callingUid, String callingPackage,
                                  int realCallingPid, int realCallingUid, int startFlags, Bundle options,
                                  boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,
                                  TaskRecord inTask) {
        int err = ActivityManager.START_SUCCESS;

        ProcessRecord callerApp = null;
        if (caller != null) {
            //查找调用者的是否存在,一般都是存在的
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }

        if (err == ActivityManager.START_SUCCESS) {
            //获取到userId
            final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
        }

        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            sourceRecord = isInAnyStackLocked(resultTo);
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }
        ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;

        final int launchFlags = intent.getFlags();

        //处理FLAG_ACTIVITY_FORWARD_RESULT
        if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            // Transfer the result target from the source activity to the new
            // one being started, including any failures.
            if (requestCode >= 0) {
                ActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            }
            resultRecord = sourceRecord.resultTo;
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
            }
            if (sourceRecord.launchedFromUid == callingUid) {
                callingPackage = sourceRecord.launchedFromPackage;
            }
        }
        //处理voiceSession
        if (err == ActivityManager.START_SUCCESS && sourceRecord != null
                && sourceRecord.task.voiceSession != null) {
            if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                    && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
                try {
                    if (!AppGlobals.getPackageManager().activitySupportsIntent(
                            intent.getComponent(), intent, resolvedType)) {
                        err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                    }
                } catch (RemoteException e) {
                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                }
            }
        }

        if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
            // If the caller is starting a new voice session, just make sure the target
            // is actually allowing it to run this way.
            try {
                //判断被打开的页面是否支持语音操作
                if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
                        intent, resolvedType)) {
                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                }
            } catch (RemoteException e) {
                err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
            }
        }

        if (err != ActivityManager.START_SUCCESS) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(-1,
                        resultRecord, resultWho, requestCode,
                        Activity.RESULT_CANCELED, null);
            }
            ActivityOptions.abort(options);
            return err;
        }

        //检查是否有START_ANY_ACTIVITY权限
        //
        final int startAnyPerm = mService.checkPermission(
                START_ANY_ACTIVITY, callingPid, callingUid);
        //检查被打开页面需要的权限
        final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
                callingUid, aInfo.applicationInfo.uid, aInfo.exported);
        //两个权限都没有
        if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(-1,
                        resultRecord, resultWho, requestCode,
                        Activity.RESULT_CANCELED, null);
            }
            throw new SecurityException(msg);
        }

        //防火墙
        boolean abort = !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                callingPid, resolvedType, aInfo.applicationInfo);

        if (mService.mController != null) {
            try {
                // The Intent we give to the watcher has the extra data
                // stripped off, since it can contain private information.
                Intent watchIntent = intent.cloneFilter();
                abort |= !mService.mController.activityStarting(watchIntent,
                        aInfo.applicationInfo.packageName);
            } catch (RemoteException e) {
                mService.mController = null;
            }
        }

        if (abort) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                        Activity.RESULT_CANCELED, null);
            }
            // We pretend to the caller that it was really started, but
            // they will just get a cancel result.
            ActivityOptions.abort(options);
            return ActivityManager.START_SUCCESS;
        }

        //新建ActivityRecord
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, this, container, options);
        if (outActivity != null) {
            outActivity[0] = r;
        }

        final ActivityStack stack = getFocusedStack();

        //删除部分代码
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);

        if (err < 0) {
            notifyActivityDrawnForKeyguard();
        }
        return err;
    }

1 首先通过getRecordForAppLocked 查询调用者的进程是否还存在

2 FLAG_ACTIVITY_FORWARD_RESULT

FLAG_ACTIVITY_FORWARD_RESULT 与多个Activity的值传递有关。例如ActivityA到达ActivityB再到达ActivityC,我们希望ActivityC将值直接传递给ActivityA。此时在ActivityB 启动ActivityC的时候可以使用这个Flag.

3 voiceSession 表示语音控制,例如通过语音启动某个页面,启动的前提是目标页面支持语音启动。

<activity           
    android:name="com.example.android.voicecamera.TakePictureActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.VOICE" />
    </intent-filter>
</activity>

需要注意的是我们必须要特别的添加android.intent.category.VOICEandroid.intent.category.DEFAULT 这两个category。否则不能成功地被语音交互API调用。

4  权限检查

START_ANY_ACTIVITY 是系统的权限,有了这个权限之后开启activity会避免很多的检查,例如跳过activity自定义的权限

5  防火墙

Intent Firewall,于安卓 4.4.2 (API 19) 中引入,是安卓框架的一个组件,可基于 xml 配置文件中的规则来过滤 intent。 

例如程序A 通过Intent 打开程序B的某个页面,系统会将这个Intent 与Intent Firewall 目录下的规则进行匹配,如果是一个通行规则那么正常打开如果是阻挡规则那么禁止打开。

执行完上面的检查之后会创建一个对应的ActivityRecord,用于标示要打开的页面,之后调用到startActivityUncheckedLocked。

    final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
                                           IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
                                           boolean doResume, Bundle options, TaskRecord inTask) {
        final Intent intent = r.intent;
        final int callingUid = r.launchedFromUid;


        //第一个参数r 表示要启动的页面
        //第二个参事sourceRecord 表示接受结果的页面


        final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
        final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
        final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;

        int launchFlags = intent.getFlags();
        //第一部分
        //FLAG_ACTIVITY_NEW_DOCUMENT 不能与SingleInstance或者SingleTask 一起使用。
        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
                (launchSingleInstance || launchSingleTask)) {
            // We have a conflict between the Intent and the Activity manifest, manifest wins.
            Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
                    "\"singleInstance\" or \"singleTask\"");
            launchFlags &=
                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
        } else {
            switch (r.info.documentLaunchMode) {
                case ActivityInfo.DOCUMENT_LAUNCH_NONE:
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
                    launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
                    break;
            }
            // FLAG_ACTIVITY_NEW_DOCUMENT 与FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 是同一个值,表示清除栈里面所有的页面
            //然后新打开的页面作为栈的第一个页面

            //FLAG_ACTIVITY_MULTIPLE_TASK 表示一定要新建一个栈,可能会导致一个页面运行在多个Task 里面
            //例如一个singleTask 页面,当第一个打开这个页面的使用运行在A 里面当我们在历史任务里面恢复运行同时
            //又设置了FLAG_ACTIVITY_MULTIPLE_TASK,此时系统会将这个页面移动到新建的栈B 里面。
            //android 官方不建议用户使用这个这段
        }

        final boolean launchTaskBehind = r.mLaunchTaskBehind
                && !launchSingleTask && !launchSingleInstance
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;

        if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            // A页面启动B 页面,但是A,B 两个页面不在同一个Task 里面,此时两者不同传递数据。
            //大家可以查询Activity.RESULT_CANCELED 搜索更多相关知识
            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
            r.resultTo.task.stack.sendActivityResultLocked(-1,
                    r.resultTo, r.resultWho, r.requestCode,
                    Activity.RESULT_CANCELED, null);
            r.resultTo = null;
        }

        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        }

        // If we are actually going to launch in to a new task, there are some cases where
        // we further want to do multiple task.
        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            if (launchTaskBehind
                    || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
                launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
            }
        }

        //FLAG_ACTIVITY_PREVIOUS_IS_TOP
        //即 A---> B --->C,若B启动C时用了这个标志位,那在启动时B并不会被当作栈顶的Activity,
        // 而是用A做栈顶来启动C。此过程中B充当一个跳转页面。
        ActivityRecord notTop =
                (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;

        // If the onlyIfNeeded flag is set, then we can do this if the activity
        // being launched is the same as the one making the call...  or, as
        // a special case, if we do not know the caller then we count the
        // current top activity as the caller.
        if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
            //如果调用者和被启动的是一个,那么就没有必要去进行重复的步骤了
            ActivityRecord checkedCaller = sourceRecord;
            if (checkedCaller == null) {
                checkedCaller = getFocusedStack().topRunningNonDelayedActivityLocked(notTop);
            }
            if (!checkedCaller.realActivity.equals(r.realActivity)) {
                // Caller is not the same as launcher, so always needed.
                startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
            }
        }

        boolean addingToTask = false;
        TaskRecord reuseTask = null;

        // If the caller is not coming from another activity, but has given us an
        // explicit task into which they would like us to launch the new activity,
        // then let's see about doing that.
        // 此处inTaks 是null,因此不进入这个分支
        if (sourceRecord == null && inTask != null && inTask.stack != null) {
            //删除部分代码
        } else {
            inTask = null;
        }

        //启动这没有指定具体的Task
        if (inTask == null) {
            //sourceRecord 为启动者
            if (sourceRecord == null) {
                // This activity is not being started from another...  in this
                // case we -always- start a new task.
                if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
                    //没有启动者的时候
                    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                            "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
                }
            } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                // 假设B 启动A 页面,B 页面是单例模式,那么被启动的页面A不可以与B在同一个栈里面
                //因此添加上FLAG_ACTIVITY_NEW_TASK
                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            } else if (launchSingleInstance || launchSingleTask) {
                // 被启动页面是单例或者是SingleTask
                //注释一
                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            }
        }

        ActivityInfo newTaskInfo = null;
        Intent newTaskIntent = null;
        ActivityStack sourceStack;
        if (sourceRecord != null) {
            if (sourceRecord.finishing) {
                  //删除部分代码,
                //启动者自身已经结束
            } else {
                sourceStack = sourceRecord.task.stack;
            }
        } else {
            sourceStack = null;
        }

        boolean movedHome = false;
        ActivityStack targetStack;

        intent.setFlags(launchFlags);


        //根据前面代码控制当被启动页面是SingleInstance或者是SingleTask 的时候会launchFlags自动加上FLAG_ACTIVITY_NEW_TASK,
        //也即是被启动页面是SingleInstance或者是SingleTask 模式且没有设置FLAG_ACTIVITY_MULTIPLE_TASK那么会进入这个分支。
        if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || launchSingleInstance || launchSingleTask) {
            //这里主要是查找SingleInstance或者是SingleTask 页面之前有没有启动过,如果启动过
            //就需要复用之前启动的页面。
            if (inTask == null && r.resultTo == null) {
                //SingleInstance模式调用findActivityLocked
                //SingleTask 调用findTaskLocked
                ActivityRecord intentActivity = !launchSingleInstance ?
                        findTaskLocked(r) : findActivityLocked(intent, r.info);
                if (intentActivity != null) {
                    //找到了目标页面
                    if (isLockTaskModeViolation(intentActivity.task)) {
                        showLockTaskToast();
                        Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                        return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
                    }
                    if (r.task == null) {
                        //设置所处的栈
                        r.task = intentActivity.task;
                    }
                    targetStack = intentActivity.task.stack;
                    targetStack.mLastPausedActivity = null;
                    //ActivityStack 移动到前台
                    targetStack.moveToFront();
                    if (intentActivity.task.intent == null) {
                        // This task was started because of movement of
                        // the activity based on affinity...  now that we
                        // are actually launching it, we can assign the
                        // base intent.
                        intentActivity.task.setIntent(r);
                    }
                    // If the target task is not in the front, then we need
                    // to bring it to the front...  except...  well, with
                    // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
                    // to have the same behavior as if a new instance was
                    // being started, which means not bringing it to the front
                    // if the caller is not itself in the front.
                    final ActivityStack lastStack = getLastStack();
                    //curTop 可以看成当前在显示的页面
                    ActivityRecord curTop = lastStack == null?
                            null : lastStack.topRunningNonDelayedActivityLocked(notTop);
                    //当前显示的页面与要启动的页面不在同一个栈里面
                    if (curTop != null && (curTop.task != intentActivity.task ||
                            curTop.task != lastStack.topTask())) {
                        //添加FLAG_ACTIVITY_BROUGHT_TO_FRONT
                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                        if (sourceRecord == null || (sourceStack.topActivity() != null &&
                                sourceStack.topActivity().task == sourceRecord.task)) {
                            // We really do want to push this one into the
                            // user's face, right now.
                            if (launchTaskBehind && sourceRecord != null) {
                                intentActivity.setTaskToAffiliateWith(sourceRecord.task);
                            }
                            movedHome = true;
                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
                            if ((launchFlags &
                                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                // Caller wants to appear on home activity.
                                intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                            }
                            options = null;
                        }
                    }
                    // If the caller has requested that the target task be
                    // reset, then do so.
                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                        intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
                    }
                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
                        // We don't need to start a new activity, and
                        // the client said not to do anything if that
                        // is the case, so this is it!  And for paranoia, make
                        // sure we have correctly resumed the top activity.
                        if (doResume) {
                            resumeTopActivitiesLocked(targetStack, null, options);
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                    }
                    if ((launchFlags &
                            (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
                            == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
                        // FLAG_ACTIVITY_NEW_TASK 表示先查找对应的Task 是否存在,不存在就创建。
                        //FLAG_ACTIVITY_CLEAR_TASK 表示清除对应的Task。
                        //例如通过FLAG_ACTIVITY_CLEAR_TASK 启动一个SingleTask的页面就可能进入这个分支
                        //此时会将Task 里面的页面全部清除在启动SingleTask 页面。
                        reuseTask = intentActivity.task;
                        //清除Task
                        reuseTask.performClearTaskLocked();
                        reuseTask.setIntent(r);
                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
                            || launchSingleInstance || launchSingleTask) {
                        //这个分支类似FLAG_ACTIVITY_CLEAR_TASK

                        //找到
                        ActivityRecord top =
                                intentActivity.task.performClearTaskLocked(r, launchFlags);
                        if (top != null) {
                            if (top.frontOfTask) {
                                // Activity aliases may mean we use different
                                // intents for the top activity, so make sure
                                // the task now has the identity of the new
                                // intent.
                                top.task.setIntent(r);
                            }
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
                                    r, top.task);
                            //调用newIntent 方法
                            top.deliverNewIntentLocked(callingUid, r.intent);
                        } else {
                            // A special case: we need to
                            // start the activity because it is not currently
                            // running, and the caller has asked to clear the
                            // current task to have this activity at the top.
                            addingToTask = true;
                            // Now pretend like this activity is being started
                            // by the top of its task, so it is put in the
                            // right place.
                            sourceRecord = intentActivity;
                        }
                    } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
                        // 处理自己启动自己的问题,例如单例页面A 某一个点击事件又启动自己
                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
                                && intentActivity.realActivity.equals(r.realActivity)) {
                            if (intentActivity.frontOfTask) {
                                intentActivity.task.setIntent(r);
                            }
                            //调用onNewIntent方法
                            intentActivity.deliverNewIntentLocked(callingUid, r.intent);
                        } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
                            // In this case we are launching the root activity
                            // of the task, but with a different intent.  We
                            // should start a new instance on top.
                            addingToTask = true;
                            sourceRecord = intentActivity;
                        }
                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
                        // 例如App 当先显示的页面B,B 下面还有一个页面A,此时收到一个通知,点击通知打卡A。
                        //我们希望的是打开B 下面的那个A而不是重新打开一个A 页面(A 是standard 模式页面),
                        //此时就可以通过FLAG_ACTIVITY_RESET_TASK_IF_NEEDED与FLAG_ACTIVITY_NEW_TASK 组合实现。
                        //FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 会将目标页面移到前台
                        addingToTask = true;
                        sourceRecord = intentActivity;
                    } else if (!intentActivity.task.rootWasReset) {
                       //没研究
                        intentActivity.task.setIntent(r);
                    }
                    if (!addingToTask && reuseTask == null) {
                       // 调用生命周期,此处doResume为true
                        if (doResume) {
                  //SingleTask 与SingInstance 模式会执行到此处,执行页面的生命周期,
                            //显示页面
                            targetStack.resumeTopActivityLocked(null, options);
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_TASK_TO_FRONT;
                    }
      
                }
            }
        }
        

如上为第一部分

首先处理了页面的documentLaunchMode,documentLaunchMode与launchMode 的作用差不多,只是使用的场景有些区别。当某个App 进入后台之后通过历史任务恢复显示该App的时候此时会用到documentLaunchMode,用于决定新打开的页面要不要新建一个Task.

android 开发之activity 启动流程《一》

 documentLaunchMode 可以在xml 里面配置。

在第一部分与第二部分之间的代码不做过多介绍,大家可以看注释。

下面看第二部分,第二部分与页面的复用有关系,也就是在启动一个页面的时候会首先查找目标页面是否存在,如果存在就直接显示这个页面而不再创建一个新的页面。

首先所有的页面复用都必须带有FLAG_ACTIVITY_NEW_TASK 标签。对于SingleInstance与SingleTask 页面,系统会自动自动添加上这个flag( 注释一位置),对于通过FLAG_ACTIVITY_CLEAR_TASK与FLAG_ACTIVITY_CLEAR_TOP 一般需要主动与FLAG_ACTIVITY_NEW_TASK结合使用才能达到复用的效果。

下面我们 关于复用页面的查找逻辑

 ActivityRecord intentActivity = !launchSingleInstance ?
                        findTaskLocked(r) : findActivityLocked(intent, r.info);

 如果被启动页面是SingleTask 页面会调用findTaskLocked 方法

    ActivityRecord findTaskLocked(ActivityRecord r) {
        if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r);
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!r.isApplicationActivity() && !stack.isHomeStack()) {
                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack);
                    continue;
                }
                if (!stack.mActivityContainer.isEligibleForNewTasks()) {
                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
                            stack);
                    continue;
                }
                //这是核心
                final ActivityRecord ar = stack.findTaskLocked(r);
                if (ar != null) {
                    return ar;
                }
            }
        }
        if (DEBUG_TASKS) Slog.d(TAG, "No task found");
        return null;
    }
ActivityDisplay 表示的显示屏,一般情况下就只有一个默认的手机显示屏。这里主要是遍历所有的ActivityStack 调用stack.findTaskLocked(r); ActivityStack 内部可能包含多个Task,findTaskLocked 就是查找到对应的Task,一般就是比较Task的Affinity,如果没有指定的话默认就是我们App的包名。这里就是查找对应的Task 是否存在,如果存在就取出这个Task里面的第一个页面。有想了解更多的可以自己看看stack.findTaskLocked(r) 方法。
<activity
            android:name="com.will.testdemo.launchmode.B"
            android:launchMode="singleTask"
            android:taskAffinity="com.will.testdemo.task1">
        </activity>

如果是单例模式则会调用findActivityLocked

    ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info);
                if (ar != null) {
                    return ar;
                }
            }
        }
        return null;
    }
findActivityLocked 就比较简单了就是遍历所有的ActivityRecord,查询单例页面之前是否打开过。

下面我们接着往下看startActivityUncheckedLocked

        //第三部分


        //检查包名
        if (r.packageName != null) {
            // If the activity being launched is the same as the one currently
            // at the top, then we need to check if it should only be launched
            // once.
            ActivityStack topStack = getFocusedStack();
            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
            if (top != null && r.resultTo == null) {
                //当前显示的页面与要启动的页面是一样的此时需要处理singleTop
                if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                    if (top.app != null && top.app.thread != null) {
                        if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                                || launchSingleTop || launchSingleTask) {
                            //输出日志
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
                                    top.task);
                            // For paranoia, make sure we have correctly
                            // resumed the top activity.
                            topStack.mLastPausedActivity = null;
                            if (doResume) {
                                resumeTopActivitiesLocked();
                            }
                            ActivityOptions.abort(options);
                            if ((startFlags& ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
                                // We don't need to start a new activity, and
                                // the client said not to do anything if that
                                // is the case, so this is it!
                                //当前显示页面与要开启的页面一致,并且启动模式是singleTop,singleTask,singleInstane,
                                //此时当使用START_FLAG_ONLY_IF_NEEDED ,就连onNewIntent都不会走。
                                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                            }
                            top.deliverNewIntentLocked(callingUid, r.intent);
                            //走newIntent.
                            return ActivityManager.START_DELIVERED_TO_TOP;
                        }
                    }
                }
            }

        } else {
            if (r.resultTo != null) {
                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
                        r.requestCode, Activity.RESULT_CANCELED, null);
            }
            ActivityOptions.abort(options);
            //没有找到要显示的页面
            return ActivityManager.START_CLASS_NOT_FOUND;
        }


        //往下走表示要打开的页面是存在的

        boolean newTask = false;
        boolean keepCurTransition = false;

        //launchTaskBehind 表示是否是后台启动
        TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord != null ?
                sourceRecord.task : null;



        // addingToTask的值初始化为false,大多数时候就是false 。
        //例如第一次打开SingleTask页面的时候,其对应的Task 已经存在的了,但是Task 里面还没有
        //这个页面,此时addingToTask就会变为true,参见前面SingleTask与SingleInstance 的处理
        //r.resultTo==null 表示不是调用startActivityForResult 开启页面。
        if (r.resultTo == null && inTask == null && !addingToTask
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            if (isLockTaskModeViolation(reuseTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            newTask = true;
            //
            targetStack = adjustStackFocus(r, newTask);
            if (!launchTaskBehind) {
                targetStack.moveToFront();
            }
            //reuseTask 表示可以复用的Task,表示具有new_task以及clear_task的flag,这个时候可以复用。
            //addingToTask 为false,reuseTask为null的时候才会创建一个新的Task
            if (reuseTask == null) {
                //设置了Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK的时候
                //reuseTask 可能非空。
                //新创建一个task,例如第一次打开SingleInstance 页面或者自定义TaskAffinity的页面
                r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                        newTaskInfo != null ? newTaskInfo : r.info,
                        newTaskIntent != null ? newTaskIntent : intent,
                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                        taskToAffiliate);
                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
                        r.task);
            } else {
                //设置要启动的页面所在的task
                r.setTask(reuseTask, taskToAffiliate);
            }
            if (!movedHome) {
                if ((launchFlags &
                        (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
                        == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
                    // Caller wants to appear on home activity, so before starting
                    // their own activity we will bring home to the front.
                    r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                }
            }

            //这个分支中启动页面与被启动页面很大可能不是在同一个Task里面,
            //一般要么创建一个新的Task 或者指定一个reuseTask, reuseTask 与启动页面一般也不再同一个Task 里面
        } else if (sourceRecord != null) {
            //sourceRecord 表示启动一个新页面的页面,一般就是当前显示页面。
            //走进这里的分支是不需要创建新的Task的,都是加入到sourceRecord页面所在的Task,

            //sourceRecord是存在的,有的时候sourceRecord是不存在的例如系统启动桌面的时候
            //standard模式的页面会走这个分支。
            //进入这里addingToTask 有可能true有可能是false
            final TaskRecord sourceTask = sourceRecord.task;
            if (isLockTaskModeViolation(sourceTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            targetStack = sourceTask.stack;
            //ActivityStack进入前台
            targetStack.moveToFront();
            final TaskRecord topTask = targetStack.topTask();
            if (topTask != sourceTask) {
                //目标页面所在的RecordStack进入前台
                targetStack.moveTaskToFrontLocked(sourceTask, r, options);
            } else {
                mWindowManager.moveTaskToTop(topTask.taskId);
            }
            //例如通过startActivityForResult 开启页面也就是r.resultTo 非空就有可能进入这个分支
            if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
                // In this case, we are adding the activity to an existing
                // task, but the caller has asked to clear that task if the
                // activity is already running.
                //看看上一部分处理FLAG_ACTIVITY_CLEAR_TOP的代码,
                // 处理FLAG_ACTIVITY_CLEAR_TOP,清理task 返回的就是要打开的页面。
                ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);
                keepCurTransition = true;
                if (top != null) {
                    //输出日志
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
                    //执行onNewIntent
                    top.deliverNewIntentLocked(callingUid, r.intent);
                    // For paranoia, make sure we have correctly
                    // resumed the top activity.
                    targetStack.mLastPausedActivity = null;
                    if (doResume) {
                        targetStack.resumeTopActivityLocked(null);
                    }
                    ActivityOptions.abort(options);
                    return ActivityManager.START_DELIVERED_TO_TOP;
                }
            } else if (!addingToTask &&
                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
                // In this case, we are launching an activity in our own task
                // that may already be running somewhere in the history, and
                // we want to shuffle it to the front of the stack if so.
                final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);
                //如果栈中已经存在某Activity,启动该Activity而不重新创建实例,只是将该Activity移到栈顶并显示。
                if (top != null) {
                    final TaskRecord task = top.task;
                    task.moveActivityToFrontLocked(top);
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
                    top.updateOptionsLocked(options);
                    //调用onNewIntent
                    top.deliverNewIntentLocked(callingUid, r.intent);
                    targetStack.mLastPausedActivity = null;
                    if (doResume) {
                        targetStack.resumeTopActivityLocked(null);
                    }
                    return ActivityManager.START_DELIVERED_TO_TOP;
                }
                //
            }
            // An existing activity is starting this new activity, so we want
            // to keep the new one in the same task as the one that is starting
            // it.
            // 新开启的页面所在的task跟sourceRecord页面在一个task
            //例如第一个打开SingleTask 页面,同时
            r.setTask(sourceTask, null);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in existing task " + r.task + " from source " + sourceRecord);

            //这个分支中启动页面与被启动页面一定是在同一个Task里面

        } else if (inTask != null) {
             //通常情况下inTask 就是null,
            //这个应该是从历史任务里面恢复任务的时候执行的分支,但是没有验证。
            if (isLockTaskModeViolation(inTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            //目标所在的ActivityStack 就是用户指定的RecordTask所在的ActivityStack
            targetStack = inTask.stack;
            targetStack.moveTaskToFrontLocked(inTask, r, options);
            //进入前台
            targetStack.moveToFront();
            mWindowManager.moveTaskToTop(inTask.taskId);

            // Check whether we should actually launch the new activity in to the task,
            // or just reuse the current activity on top.
            ActivityRecord top = inTask.getTopActivity();
            if (top != null && top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                        || launchSingleTop || launchSingleTask) {
                    //老套路,处理launchSingleTop launchSingleTask 以及FLAG_ACTIVITY_SINGLE_TOP
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
                        // We don't need to start a new activity, and
                        // the client said not to do anything if that
                        // is the case, so this is it!
                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                    }
                    //执行onNewIntent
                    top.deliverNewIntentLocked(callingUid, r.intent);
                    return ActivityManager.START_DELIVERED_TO_TOP;
                }
            }

            if (!addingToTask) {
                // We don't actually want to have this activity added to the task, so just
                // stop here but still tell the caller that we consumed the intent.
                ActivityOptions.abort(options);
                return ActivityManager.START_TASK_TO_FRONT;
            }

            r.setTask(inTask, null);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in explicit task " + r.task);

        } else {
            // This not being started from an existing activity, and not part
            // of a new task...  just put it in the top task, though these days
            // this case should never happen.
            //这种情形不会发生
            targetStack = adjustStackFocus(r, newTask);
            targetStack.moveToFront();
            ActivityRecord prev = targetStack.topActivity();
            r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
                    r.info, intent, null, null, true), null);
            mWindowManager.moveTaskToTop(r.task.taskId);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in new guessed " + r.task);
        }
        //
        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
                intent, r.getUriPermissionsLocked(), r.userId);

        if (sourceRecord != null && sourceRecord.isRecentsActivity()) {
            r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
        }
        if (newTask) {
            //日志
            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
        }
        //输出日志
        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
        targetStack.mLastPausedActivity = null;
        //真正的开启页面,也就是onCreate,onStart以及onResume的执行。
        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
        if (!launchTaskBehind) {
            // Don't set focus on an activity that's going to the back.
            mService.setFocusedActivityLocked(r);
        }
        return ActivityManager.START_SUCCESS;

第三部分主要分为四个部分,也就是下面四个分支。


        if (r.resultTo == null && inTask == null && !addingToTask
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        //分支一
  
        } else if (sourceRecord != null) {
        //分支二


        } else if (inTask != null) {
        //分支三


        } else {
         //分支四
   
        }

我们先看第一个分支的条件,r.resultTo == null 表示用户不是通过startActivityForResult 启动的页面,因为startActivityForResult 被启动的页面必须与启动页面处于同一个Task 里面;

第二个条件inTask == null一般都是成立的。

第三个条件!addingToTask,a.startActivity(b), 假设存放B页面的Task 已经存在了也就是addToTask 为true,那么这个时候只需要讲过b页面添加到对应的Task 里面就可以了,不需要在创建一个新的Task。例如有两个TaskAffinity的都是“testTaskAffinity”的SingleTask 页面M,N,在启动M的时候会j进入第一个分支,创建一个名为testTaskAffinity 的Task,当启动N页面的时候由于对应的Task 已经存在,此时就不会进入第一个分支,而是进入第二个分支,直接将页面N加入到对应的Task 就可以了。

第二个分支 条件sourceRecord!=null 表示启动页面非空,例如.startActivity(b) 这里的sourceRecord一般就是页面a,因此这个条件大多是成立的。

第三个分支不死很清楚会在什么时候执行,猜测是在通过历史任务恢复执行App的时候会进入这个分支。

第四个分支,这个分支不可能进入。

targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options); 的执行逻辑放到下一篇来讲。


至此startActivityUncheckedLocked 就分析完了,其主要处理的就是页面的复用与对应的Task的创建与选择。

上一篇:从0到1学习安卓逆向 | 02编写一个简简单单的注册程序


下一篇:腾讯T2手把手教你!我在美团Android研发岗工作的那5年,经典好文