文章标题

2 篇文章 0 订阅
  @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null);
    }

Ams 是Android 的核心中的核心,负责进程的管理,进程组件管理,进程与进程的交互,进程的监控(耗电,内存),屏幕的管理,并且是wms,pms的控制中心,要想深入全局的掌握android系统的运行逻辑,对ams的理解是不可少的.

但是ams的十分复杂的,尤其是activity的启动,涉及到的falgs十分繁多,各种不同的屏幕模式,如画中画,分屏,freedom模式,以及正常的手机中使用的栈task管理模式,是十分复杂的,这个过程我联系阅读四天都没有完全理解.所以通过这面文章去彻彻底底的搞清楚这个问题.

activity的启动从Activity->ActivityThread的过程十分简单,就不去分析了,直接从AMS的startActivity入手

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}

解释一下这里面的参数,比较多
IApplicationThread caller 调用者的ApplicationThread,是一个binder对象用于和调用者ActivityThread通信
String callingPackage //调用者的包名
Intent intent
String resolvedType  provider中getType返回的值,有些页面可以处理这种uri
IBinder resultTo 接受结果的activitytrecord(binder对象)
String resultWho 用户自定义的字符串,调用完毕会传回去
int requestCode 
int startFlags
ProfilerInfo profilerInfo //统计数据
Bundle bOptions    //其他启动参数 可能是从父activity继承的

  @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null);
    }

android:isolatedProcess
设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(binding and starting)。
enforceNotIsolatedCaller(“startActivity”); 如果进程是沙箱进程则直接抛出安全异常

ActivityStarter

 final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {
        // Refuse possible leaked file descriptors



    }

提醒activity启动用于记录log
根据intent获取 resolveInfo
执行了一段多用户的逻辑,
之后根据resolveInfo 获取争取的ActivityInfo
获取 ActivityOptions options
获取指定的icontainer,这个container是stack的代理,客户端通过container和stack交互

根据container获取stack,如果container==null或者container 指定的栈是在默认的屏幕上,则设置栈为当前的焦点栈,否则就用container的栈.

设置栈的mConfigWillChange 用于跟新栈中的界面
之后处理HeavyWeight进程 这些进程是设置了CANT_SAVE_STATE标志的,AndroidManifest.xml中的Application标签可以声明一个cantSaveState

    属性,设置了该属性的Application将不享受系统提供的状态保存/恢复功能。

    当一个Application退到后台时,系统会为它保存状态,当调度其到前台运行时, 
           将恢复它之前的状态,以保证用户体验的连续性。声明了该属性的Application被称为

   “heavy weight process”。
   下面我们来分析下heavy wight process是如何处理的
 if (aInfo != null &&
                    (aInfo.applicationInfo.privateFlags
                            & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
                // This may be a heavy-weight process!  Check to see if we already
                // have another, different heavy-weight process running.
                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
                    final ProcessRecord heavy = mService.mHeavyWeightProcess;
                    if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid
                            || !heavy.processName.equals(aInfo.processName))) {
                        int appCallingUid = callingUid;
                        if (caller != null) {
                            ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
                            if (callerApp != null) {
                                appCallingUid = callerApp.info.uid;
                            } else {
                                Slog.w(TAG, "Unable to find app for caller " + caller
                                        + " (pid=" + callingPid + ") when starting: "
                                        + intent.toString());
                                ActivityOptions.abort(options);
                                return ActivityManager.START_PERMISSION_DENIED;
                            }
                        }

                        IIntentSender target = mService.getIntentSenderLocked(
                                ActivityManager.INTENT_SENDER_ACTIVITY, "android",
                                appCallingUid, userId, null, null, 0, new Intent[] { intent },
                                new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
                                        | PendingIntent.FLAG_ONE_SHOT, null);

                        Intent newIntent = new Intent();
                        if (requestCode >= 0) {
                            // Caller is requesting a result.
                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
                        }
                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
                                new IntentSender(target));
                        if (heavy.activities.size() > 0) {
                            ActivityRecord hist = heavy.activities.get(0);
                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
                                    hist.packageName);
                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
                                    hist.task.taskId);
                        }
                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
                                aInfo.packageName);
                        newIntent.setFlags(intent.getFlags());
                        newIntent.setClassName("android",
                                HeavyWeightSwitcherActivity.class.getName());
                        intent = newIntent;
                        resolvedType = null;
                        caller = null;
                        callingUid = Binder.getCallingUid();
                        callingPid = Binder.getCallingPid();
                        componentSpecified = true;
                        rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId);
                        aInfo = rInfo != null ? rInfo.activityInfo : null;
                        if (aInfo != null) {
                            aInfo = mService.getActivityInfoForUser(aInfo, userId);
                        }
                    }
                }
            }

1 Activity运行在单独的进程则不处理,获取系统当前的重量级进程,当前重量级进程与调用者进程是同一个进程责不处理
由于系统同时只能管理一个重量级进程,这种情况责产生了多个重量级进程,就会启动HeavyWeightSwitcherActivity,要求用户自己处理,这里就会将原来的activity替换成HeavyWeightSwitcherActivity,在HeavyWeightSwitcherActivity用户选择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);

            Binder.restoreCallingIdentity(origId);

            if (stack.mConfigWillChange) {
                // If the caller also wants to switch to a new configuration,
                // do so now.  This allows a clean switch, as we are waiting
                // for the current activity to pause (so we will not destroy
                // it), and have not yet started the next activity.
                mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                        "updateConfiguration()");
                stack.mConfigWillChange = false;
                if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                        "Updating to new configuration after starting activity.");
                mService.updateConfigurationLocked(config, null, false);
            }

            if (outResult != null) {
                outResult.result = res;
                if (res == ActivityManager.START_SUCCESS) {
                    mSupervisor.mWaitingActivityLaunched.add(outResult);
                    do {
                        try {
                            mService.wait();
                        } catch (InterruptedException e) {
                        }
                    } while (outResult.result != START_TASK_TO_FRONT
                            && !outResult.timeout && outResult.who == null);
                    if (outResult.result == START_TASK_TO_FRONT) {
                        res = START_TASK_TO_FRONT;
                    }
                }
                if (res == START_TASK_TO_FRONT) {
                    ActivityRecord r = stack.topRunningActivityLocked();
                    if (r.nowVisible && r.state == RESUMED) {
                        outResult.timeout = false;
                        outResult.who = new ComponentName(r.info.packageName, r.info.name);
                        outResult.totalTime = 0;
                        outResult.thisTime = 0;
                    } else {
                        outResult.thisTime = SystemClock.uptimeMillis();
                        mSupervisor.mWaitingActivityVisible.add(outResult);
                        do {
                            try {
                                mService.wait();
                            } catch (InterruptedException e) {
                            }
                        } while (!outResult.timeout && outResult.who == null);
                    }
                }
            }

            final ActivityRecord launchedActivity = mReusedActivity != null
                    ? mReusedActivity : outRecord[0];
            mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, launchedActivity);
            return res;

创建了个ActivityRecord 数组,作为传出参数,这种做法很像c语言的指针做传出参数,然后调用启动Activity的函数
这里我们先看一下启动后如何处理 之后就不回来看了。

如果stack.mConfigWillChange =true, 这个值是我们前边赋予的,就是启动Activity传递的参数和栈的参数不同。
检查CHANGE_CONFIGURATION 权限,更新配置,这里不具体分析。

如果启动成功,mservice要等到wait到Activity进入前台,所以调用wait函数等待,直到START_TASK_TO_FRONT或者
超时

 @Override
        public void windowsDrawn() {
            synchronized (mService) {
                ActivityRecord r = tokenToActivityRecordLocked(this);
                if (r != null) {
                    r.windowsDrawnLocked();
                }
            }
        }

当window绘制完成之后会调用ActivityRecord windowsDrawn函数,或者在ams的reportActivityFullyDrawn函数中都会
检查Activity的状态,调用Ams的notify,使Ams继续检查状态。之后就将结果返回给调用程序。

 final int startActivityLocked(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;

        ProcessRecord callerApp = null;
        if (caller != null) {
            callerApp = mService.getRecordForAppLocked(caller);
            ....
        final int launchFlags = intent.getFlags();

        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;
            if (resultRecord != null && !resultRecord.isInStackLocked()) {
                resultRecord = null;
            }
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
            }

     .....
        boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
                resultRecord, resultStack, options);
        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;
            }
        }

        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
        mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid,
                options);
        intent = mInterceptor.mIntent;
        rInfo = mInterceptor.mRInfo;
        aInfo = mInterceptor.mAInfo;
        resolvedType = mInterceptor.mResolvedType;
        inTask = mInterceptor.mInTask;
        callingPid = mInterceptor.mCallingPid;
        callingUid = mInterceptor.mCallingUid;
        options = mInterceptor.mActivityOptions;
        if (abort) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                        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 START_SUCCESS;
        }

        // If permissions need a review before any of the app components can run, we
        // launch the review activity and pass a pending intent to start the activity
        // we are to launching now after the review is completed.
        if ((mService.mPermissionReviewRequired
                || Build.PERMISSIONS_REVIEW_REQUIRED) && aInfo != null) {
            if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                    aInfo.packageName, userId)) {


........
        doPendingActivityLaunchesLocked(false);

        try {
            mService.mWindowManager.deferSurfaceLayout();
            err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                    true, options, inTask);
        } finally {
            mService.mWindowManager.continueSurfaceLayout();
        }
        postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
        return err;
    }
ActivityStarter-> final int startActivityLocked(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) {

首先根据传递进来的ApplicationThread binder对象获取对应的ProcessRecord 然后获取callUid callPid
获取userid 这里是根据应用uid获取的 看来多用户是和进程uid相关的
下面的逻辑就是获取

ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null; 

sourceRecord 代表调用者
resultRecord 代表接受结果的 
一般情况这二者是同一个activity,但是如果调用的时候没有使用

startActivityForResult则resultRecord= null

  ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                    "Will send result to " + resultTo + " " + sourceRecord);
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }

根据resultRecord 找到对应的sourceRecord 如果requestCode>0 并且没有关闭resultRecord== sourceRecord

然后处理 FLAG_ACTIVITY_FORWARD_RESULT 的情况,比如a调用startActivityForResult 启动Activity b,顺序为a->b->c ,比启动b后关闭,要想
接收c setResult的值,需要b 启动c 的时候传递FLAG_ACTIVITY_FORWARD_RESULT 参数 调用startActivity
下面就来看看如何处理这个参数 
首先b->c 不能传递requestcode 否则认为冲突 也就是说b调用c的时候要用startActivity 别用startActivityForResult,或者request= -1
然后把接受b结果的activity设置成resultRecord
移除传递给resultRecord对应result的结果.

下面逻辑
如果找不到Component直接返回
ainfo 找不到直接返回
如果有sourceRecord 且他的voiceSession 也存在.跨应用启动并且有FLAG_ACTIVITY_NEW_TASK标志
或者要启动的Activity部支持语音回话 则直接返回 
voiceSession 应该是语音助手相关的 之后分析

到这里为止 sourceRecord resultRecord都已经解析完了,如果启动有什么不满足的条件就能直接返回
RESULT_CANCELED 给接受结果的activity并返回error

之后就是权限检查和系统拦截逻辑
权限检查部分,主要是检查activity声明的activity和AppOpsService拦截的一些控制列表 还有action需要的
权限 没有权限直接抛出异常

activity action权限直接抛出异常,其他情况终止启动
intent防火墙处理 根据data/system/ifw/ 下配置的规则过滤一些intent
IActivityController 过滤掉一些请求 这部分处理的接口还不少
停止启动不能通过检查的请求

周后处理ephemeral app, 这个不知道干啥的,之后在分析PMS时候再看吧
之后创建 ActivityRecord

如果焦点栈顶的resumeActivity==null, 栈顶之前显示的activity正在做其他操作比如说还没有显示,
或者正在销毁,我们不能马上启动这个新的Activity,如果马上启动显示上会有问题,就放在pendingLunches中 
并返回START_SWITCHES_CANCELED. 之前分析的启动activity返回后AMS会wait, 当这个pendingActivity被真正启动后
就会notify
并且最多只有一个pendingActivity
每次在启动activity都先启动pendingActvity

下面就是巨复杂的一个函数了,这个函数看着没有多少代码,但是其中调用的每个函数都处理了很多逻辑
分支比较多 主要是操作栈和task 我们来理清楚栈和task的关系,分析这个函数一定要要理清头绪

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

        computeLaunchingTaskFlags();

        computeSourceStack();

        mIntent.setFlags(mLaunchFlags);

        mReusedActivity = getReusableIntentActivity();

        final int preferredLaunchStackId =
                (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;

        if (mReusedActivity != null) {
            // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
            // still needs to be a lock task mode violation since the task gets cleared out and
            // the device would otherwise leave the locked task.
            if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task,
                    (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
                mSupervisor.showLockTaskToast();
                Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }

            if (mStartActivity.task == null) {
                mStartActivity.task = mReusedActivity.task;
            }
            if (mReusedActivity.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.
                mReusedActivity.task.setIntent(mStartActivity);
            }

            // This code path leads to delivering a new intent, we want to make sure we schedule it
            // as the first operation, in case the activity will be resumed as a result of later
            // operations.
            if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || mLaunchSingleInstance || mLaunchSingleTask) {
                // In this situation we want to remove all activities from the task up to the one
                // being started. In most cases this means we are resetting the task to its initial
                // state.
                final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
                        mStartActivity, mLaunchFlags);
                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(mStartActivity);
                    }
                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                            mStartActivity.launchedFromPackage);
                }
            }

            mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);

            if ((mStartFlags & 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.
                resumeTargetStackIfNeeded();
                return START_RETURN_INTENT_TO_CALLER;
            }
            setTaskFromIntentActivity(mReusedActivity);

            if (!mAddingToTask && mReuseTask == null) {
                // We didn't do anything...  but it was needed (a.k.a., client don't use that
                // intent!)  And for paranoia, make sure we have correctly resumed the top activity.
                resumeTargetStackIfNeeded();
                return START_TASK_TO_FRONT;
            }
        }

        if (mStartActivity.packageName == null) {
            if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
                mStartActivity.resultTo.task.stack.sendActivityResultLocked(
                        -1, mStartActivity.resultTo, mStartActivity.resultWho,
                        mStartActivity.requestCode, RESULT_CANCELED, null);
            }
            ActivityOptions.abort(mOptions);
            return START_CLASS_NOT_FOUND;
        }

        // 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.
        final ActivityStack topStack = mSupervisor.mFocusedStack;
        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
        final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.realActivity.equals(mStartActivity.realActivity)
                && top.userId == mStartActivity.userId
                && top.app != null && top.app.thread != null
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || mLaunchSingleTop || mLaunchSingleTask);
        if (dontStart) {
            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
            // For paranoia, make sure we have correctly resumed the top activity.
            topStack.mLastPausedActivity = null;
            if (mDoResume) {
                mSupervisor.resumeFocusedStackTopActivityLocked();
            }
            ActivityOptions.abort(mOptions);
            if ((mStartFlags & 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 START_RETURN_INTENT_TO_CALLER;
            }
            top.deliverNewIntentLocked(
                    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);

            // Don't use mStartActivity.task to show the toast. We're not starting a new activity
            // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
            mSupervisor.handleNonResizableTaskIfNeeded(
                    top.task, preferredLaunchStackId, topStack.mStackId);

            return START_DELIVERED_TO_TOP;
        }

        boolean newTask = false;
        final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                ? mSourceRecord.task : null;

        // Should this be considered a new task?
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            setTaskFromReuseOrCreateNewTask(taskToAffiliate);

            if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            if (!mMovedOtherTask) {
                updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
            }
        } else if (mSourceRecord != null) {
            if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }

            final int result = setTaskFromSourceRecord();
            if (result != START_SUCCESS) {
                return result;
            }
        } else if (mInTask != null) {
            // The caller is asking that the new activity be started in an explicit
            // task it has provided to us.
            if (mSupervisor.isLockTaskModeViolation(mInTask)) {
                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }

            final int result = setTaskFromInTask();
            if (result != START_SUCCESS) {
                return result;
            }
        } 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.
            setTaskToCurrentTopOrCreateNewTask();
        }

        mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
                mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);

        if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
            mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
        }
        if (newTask) {
            EventLog.writeEvent(
                    EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
        }
        ActivityStack.logStartActivity(
                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
        mTargetStack.mLastPausedActivity = null;
        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
        if (mDoResume) {
            if (!mLaunchTaskBehind) {
                // TODO(b/26381750): Remove this code after verification that all the decision
                // points above moved targetStack to the front which will also set the focus
                // activity.
                mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
            }
            final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
                // If the activity is not focusable, we can't resume it, but still would like to
                // make sure it becomes visible as it starts (this will also trigger entry
                // animation). An example of this are PIP activities.
                // Also, we don't want to resume activities in a task that currently has an overlay
                // as the starting activity just needs to be in the visible paused state until the
                // over is removed.
                mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                // Go ahead and tell window manager to execute app transition for this activity
                // since the app transition will not be triggered through the resume channel.
                mWindowManager.executeAppTransition();
            } else {
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        } else {
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }
        mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);

        mSupervisor.handleNonResizableTaskIfNeeded(
                mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);

        return START_SUCCESS;
    }
首先reset ActivitStarter状态 包含一下状态
       mStartActivity = null;  正在启动的Activity
        mIntent = null;        intent
        mCallingUid = -1;       callingUid
        mOptions = null;        

        mLaunchSingleTop = false;
        mLaunchSingleInstance = false;
        mLaunchSingleTask = false;
        mLaunchTaskBehind = false; // 通过ActivityOptions.makeTaskLaunchBehind().toBundle() 设置,
           如果设置了这个标志,主要有两个作用1是界面不会显示给用户会出现在最近任务列表.并且在多任务和
           启动它的activity聚合,只对new_document 有效

        mLaunchFlags = 0;   启动标志
        mLaunchBounds = null;  大小,对于freedom 分屏等有用

        mNotTop = null;     //如果设置了 FLAG_ACTIVITY_PREVIOUS_IS_TOP 标志,则默认栈顶的activity是栈顶下一个 什么鬼
        mDoResume = false;   // 是否执行resume   
        mStartFlags = 0;     // 用户启动的是0
        mSourceRecord = null; //调用的activity

        mInTask = null;      //指定的栈

//剩下的都是动态调整的 稍后分析
        mAddingToTask = false;  //是否添加到已经存在的栈里
        mReuseTask = null;  //复用的task,不用重新创建

        mNewTaskInfo = null;
        mNewTaskIntent = null;
        mSourceStack = null;

        mTargetStack = null;   
        mMovedOtherTask = false;
        mMovedToFront = false;
        mNoAnimation = false;  
        mKeepCurTransition = false;
        mAvoidMoveToFront = false;

        mVoiceSession = null;  //语音会话
        mVoiceInteractor = null;

接下来我们就分析

private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
            boolean doResume, int startFlags, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {

1 reset上面总结的状态变量。
2
mLaunchBounds = getOverrideBounds(r, options, inTask);
这个就是类似桌面系统的模式,可以调节activity的大小,目前有两种任务栈是支持调整大小的 ,一种是画中画模式(电视系统),一种是freedom模式(电脑桌面系统),不同模式对应不同的stackid,
目前系统中对应一下几种栈

 /** Invalid stack ID. */
        public static final int INVALID_STACK_ID = -1;

        /** First static stack ID. */
        public static final int FIRST_STATIC_STACK_ID = 0;

        /** Home activity stack ID. */
        public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;

        /** ID of stack where fullscreen activities are normally launched into. */
        public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;  //全屏activity 也是分屏的

        /** ID of stack where freeform/resized activities are normally launched into. */
        public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;

        /** ID of stack that occupies a dedicated region of the screen. */
        public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1; 

        /** ID of stack that always on top (always visible) when it exist. */
        public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;  //画中画

上面如果支持改变大小就从activityOp中获取屏幕大小 设置mLaunchBounds对象。
然后初始化launchMode
lunchFlag
我们看下lunchFlag的初始化

   private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
            boolean launchSingleTask, int launchFlags) {
        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 | 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 &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
                    break;
            }
        }
        return launchFlags;
    }

计算lunchflag要参考lunchMode, 主要是launchSingleInstance 和launchSingleTask。
首先lunchFlags中的FLAG_ACTIVITY_NEW_DOCUMENT和lunchMode,launchSingleInstance是有冲突的,为什么呢,因为
FLAG_ACTIVITY_NEW_DOCUMENT 的主任务和自任务是有关联的,
如果设置了FLAG_ACTIVITY_NEW_DOCUMENT责会在最近任务列表里面显示多个task,但是只有子task全部关闭,才能关闭主task,并且子task也是一个栈里面只有一份。
如果设置了FLAG_ACTIVITY_MULTIPLE_TASK,责可以有多份子task.
所以lunchMode为launchSingleInstance 和 launchSingleTask的,会清掉Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK 标志。
如果没有FLAG_ACTIVITY_NEW_DOCUMENT冲突,就要根据documentLunchMode去设置lunchFlag(也是通过activity的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 &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
                    break;

根据设置的不同设置不同的flag.

然后计算mLaunchTaskBehind
singleTask singleInstance document都是不支LaunchTaskBehind的,因为不应该做到与调用的任务聚合到一块显示在多任务中??还是处于什么原因? 调用newIntent等?不得考证

如果设置了newTask标志,且有result activity,则新启动的activity不能把结果发送给result activity,因为这个activity finish后可能不是result activity

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

设置mUserLeaving 正常页面被切到后台都会调用,设置了

如果用户指定进入哪个栈,并且这个栈目前没有显示在界面上,就将mDoResume = false;
mAvoidMoveToFront = true; 以后避免移动栈,箱单与偷偷的将页面添加到系统中.

FLAG_ACTIVITY_PREVIOUS_IS_TOP 设置了这个启动标志,意思是忽略栈上第一个元素,只在IntentForwarderActivity 中发现使用此标志,根据注释是用于DevicePolicyManager透传用户消息的.

设置inTask
然后判断如果intask不在最近入会列表,可能这个task正在被销毁,因为这里是无锁的,所以要将指定的task设置为null

如果指定了START_FLAG_ONLY_IF_NEEDED flags 注意该标志是在startFlags中
该标志的作用是如果该 activity就在站定不重新启动这个activity,如果该activity不在站定,就把该标志去掉。 该标志应该属于询问性的标志。
之后就是设置有没有动画。

下面来分析
startActivityUnchecked()->computeLaunchingTaskFlags()函数
该函数用于计算lunchFlag

 // 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.
        if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {

注意
!!!!
这种情况是指定启动一个activity到一个新的task中
不是启动于其他Activity,且指定了task,责需要处理逻辑如下
获取baseIntent(最开始导致创建这个task的intent) 和rootActivity,由此可见,指定的Task必须是一个已经完全初始化的正常的Task. 否则直接抛出异常,这种情况应该不会发生,只是开发者确保异常状况的
如果luncmMode是singleTask或者singleInstance的 责该栈必须里面没有元素,并且baseIntent必须与要启动的Activity匹配。 由此可见,指定Task要进行更严格的检查. 因为这里有可能引起复用activity,指定task是不允许复用activity的。

如果栈中没有activity,

if (root == null) {
                final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
                        | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
                mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
                        | (baseIntent.getFlags() & flagsOfInterest);
                mIntent.setFlags(mLaunchFlags);
                mInTask.setIntent(mStartActivity);
                mAddingToTask = true;

要重新设置flag为FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
| FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS
因为要添加一个新的栈中,这个栈是我们自己的,所以重新设置baseIntent和lunchFlag
并且设置task的baseIntent
设置taskFlag 设置
addingToTask=true
如果设置了FLAG_ACTIVITY_NEW_TASK 且栈中有元素,就不添加到指定的栈中 设置mAddingToTask =false
最后如果没有指定 FLAG_ACTIVITY_NEW_TASK 就添加到指定的栈中,不用重新设置lunchFlag.和baseIntent 注意这种情况下lunchMode不能是singleInstance 和singleTask

设置mReuseTask = mInTask;

2 表示1 以外的其他情况,直接将mInTask设置为null,也就是说如果启动来自其他activity责不允许指定inTask,如果要启动的activity是,并且是调用的activity是isFreeform 责可以添加到任何栈中,设置mAddingToTask=true

下面就是在1,2分之后面统一的处理。

这里只处理mInTask ==null的情况,我们要为找到合适的栈做一些设置,有一下三种情况
1 mSourceRecord == null 不是启动自activity要添加FLAG_ACTIVITY_NEW_TASK 标志(没有task)
2 有mSourceRecord!=null &&SourceRecord.lucnmode = LAUNCH_SINGLE_INSTANCE,也要设置FLAG_ACTIVITY_NEW_TASK,因为singleInstance的栈里只能有一个activity
3 mLaunchSingleInstance || mLaunchSingleTask 这种情况都会添加这个标准,如果没有这个标志就会和sourceRecord在一个栈中

计算flags 的分析完了,我们来旅顺task计算de思路,首先setInitialState()函数,只处理好冲突的flag,并赋好值,
computeLaunchingTaskFlags 首先确认task并根据task重新添加需要的flags.

到这里我们初步总结下startFlags lunchFlags 和 lunchMode 和resultto, documentLunchMode的关系

lunchFlags:
如果设置了FLAG_ACTIVITY_NEW_TASK 责不会发送结果给调resultActivity
设置了FLAG_ACTIVITY_NEW_TASK 且设置了mLaunchTaskBehind 或者documentLunchMode为DOCUMENT_LAUNCH_ALWAYS 责要设置FLAG_ACTIVITY_MULTIPLE_TASK 以可以启动多个Task,不会进入之前已经存在的task,由此可见DOCUMENT_LAUNCH_ALWAYS 必然会创建新的task
设置FLAG_ACTIVITY_NO_USER_ACTION 责不会调用activity的生命周期onUserLeaveHint
FLAG_ACTIVITY_PREVIOUS_IS_TOP 责忽略栈顶已经存在的相同的activity. 应该是用于重建自己。 者只是猜测,目前只发现ChooseActivity有用到这个标志。

startFlags
目前只处理了START_FLAG_ONLY_IF_NEEDED 标志,如果要启动的activity不在前台责该标志无效

lunchMode:
singleTask和singleInstance与FLAG_ACTIVITY_NEW_DOCUMENT是冲突的,以lunchMode为准,如果指定task必须添加到一个空的task中,没有指定task则会添加FLAG_ACTIVITY_NEW_TASK 标志

documentLaunchMode:
DOCUMENT_LAUNCH_INTO_EXISTING
DOCUMENT_LAUNCH_ALWAYS
会设置FLAG_ACTIVITY_NEW_DOCUMENT 标志

DOCUMENT_LAUNCH_NEVER
会取消FLAG_ACTIVITY_MULTIPLE_TASK 标志

下一步 计算SourceStack 这一是stack不是task.
private void computeSourceStack() :
sourceReourd==null 或者
sourceReourd 没有关闭责设置mSourceStack 为sourceReourd所在的栈
接下来处理的就是mSourceRecord.finishing的情况,注意这并非是是调用了startActivity函数后又调用finish函数引起的,因为startActivity虽然跨进程调用了AMS,但是传递的flags==0,意味着该函数是阻塞的。
如果没设置FLAG_ACTIVITY_NEW_TASK标志,要添加该标志则添加FLAG_ACTIVITY_NEW_TASK。因为该activity没必要和sourceActivity放在一个task中了。 并设置 mNewTaskInfo = mSourceRecord.info;
mNewTaskIntent = mSourceRecord.task.intent;
为什么要设置这两个参数? 因为应该进入的activity的task已经找不到了,所以要构造一个新的task ,mNewTaskIntent用于设置baseIntent, 用于设置栈的pid,uid。 packge callinguid等信息,注意这里如果已经有了目的task(注意这种情况sourceRecord==null),这两个信息(mNewTaskIntent,mNewTaskIntent)肯定是没用了,因为不需要重新创建task,所以这里的lunchMode 应该不是singleInstance和singleInstant

最后将
mSourceRecord = null;
mSourceStack = null;

这样mSourceStack 也算计算完了,只有sourceReourd还没有关闭的时候存在。

之后重新设置mIntent 的lunchFlags.

startActivityUnchecked()->getReusableIntentActivity()用于获取可重用的activity。

 private ActivityRecord getReusableIntentActivity() {
        // We may want to try to place the new activity in to an existing task.  We always
        // do this if the target activity is singleTask or singleInstance; we will also do
        // this if NEW_TASK has been requested, and there is not an additional qualifier telling
        // us to still place it in a new task: multi task, always doc mode, or being asked to
        // launch this as a new task behind the current one.
        boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || mLaunchSingleInstance || mLaunchSingleTask;
        // If bring to front is requested, and no result is requested and we have not been given
        // an explicit task to launch in to, and we can find a task that was started with this
        // same component, then instead of launching bring that one to the front.
        putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
        ActivityRecord intentActivity = null;
        if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
            final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
            intentActivity = task != null ? task.getTopActivity() : null;
        } else if (putIntoExistingTask) {
            if (mLaunchSingleInstance) {
                // There can be one and only one instance of single instance activity in the
                // history, and it is always in its own unique task, so we do a special search.
               intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
            } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
                // For the launch adjacent case we only want to put the activity in an existing
                // task if the activity already exists in the history.
                intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
                        !mLaunchSingleTask);
            } else {
                // Otherwise find the best task to put the activity in.
                intentActivity = mSupervisor.findTaskLocked(mStartActivity);
            }
        }
        return intentActivity;
    }

这个函数主要首先计算了个putIntoExistingTask变量,意思是是否需要放入存在的Task中
这个变量成立的条件要满如下需求
((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
这几个条件的含义在于设置了FLAG_ACTIVITY_NEW_TASK或并且没有FLAG_ACTIVITY_MULTIPLE_TASK 标志这种情况下 是应该找到一个现有的activity的task作为重用的activity。 或者设置了mLaunchSingleInstance ||mLaunchSingleTask 这两种lunchMode都需要在现有的栈中需要合适的用于复用的activity.

putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
putIntoExistingTask又与等于这几个条件,也很好解释,首先指定了mInTask,这种情况要么lunchMode = mLaunchSingleInstance ||mLaunchSingleTask, mIntask不等于null,那么应该指定了一个不为null,也task中没有activity的task,所以可能要重新创建activity,没有可以复用的activity,对于不是这种lunchMode的activity,如果有resultTo 说明lunchMode必然不是mLaunchSingleInstance ||mLaunchSingleTask,那么也必然没有FLAG_ACTIVITY_NEW_TASK 标志,所以要在sourceRecord的activity上启动该activity,没有sourceRecord责因该重新建立。另外一种情况就是为什么不在mInTask中找到可以复用的呢?因为在一个栈的activity即使设置了FLAG_ACTIVITY_NEW_TASK标志,lunchMode不是mLaunchSingleInstance ||mLaunchSingleTask,也不会发生复用,还是会重新启动一份,不信可以自己试试

好了确定了putIntoExistingTask标志,就要在现有的task中找到合适的mReusedActivity了。

这里首先根据用户指定的taskID去寻找
一切以用户为准

if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
            final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
            intentActivity = task != null ? task.getTopActivity() : null;

这里主要就是找到指定的taskId,并且找到站定的Activity作为复用的activity. 这种情况目前来看只有系统应用可以设置taskId,应该是目的明确的行为。我们没有必要分析的这么细致。

我们主要关注putIntoExistingTask的逻辑 这里有三种情况
1 mLaunchSingleInstance,这种情况整个系统最多只能有一个这种类型的activity,所以不需要匹配intent,只需要找到正确的activity即可。 确切的说是一个用户下,这里我们不分析多用户逻辑。

2 对于有FLAG_ACTIVITY_LAUNCH_ADJACENT这个lunchFlags的

    /**
     * This flag is only used in split-screen multi-window mode. The new activity will be displayed
     * adjacent to the one launching it. This can only be used in conjunction with
     * {@link #FLAG_ACTIVITY_NEW_TASK}. Also, setting {@link #FLAG_ACTIVITY_MULTIPLE_TASK} is
     * required if you want a new instance of an existing activity to be created.
     */
    public static final int FLAG_ACTIVITY_LAUNCH_ADJACENT = 0x00001000;

这个flags只有在多窗口分屏模式下才会设置
要找到一个intent完全匹配的进行复用

3 找到最合适的复用,我们来看看如何找到最合适的:
首先找到最合适的stack
不是applicationActivity也必然不在homeStack中,所以跳过这些
如果stack.mActivityContainer不允许复用activity则跳过
在剩下的栈中去找合适的activityRecord,
stack.findTaskLocked(r, mTmpFindTaskResult);//mTmpFindTaskResult是传出参数。
然后只在每个栈中的task站定找到合适的activity,如果有多个则找到亲和力最匹配的。
注意对于情况3 只是在task最上面的activity中寻找复用的activity. 对于这中情况如果activity不在task顶部责要重新建立activity. 可能读者会疑问singleTask也要重建,是的。

回到startActivityUnchecked 函数,对于mReusedActivity的总结,
当mReusedActivity不为nullde时候有两种情况
1 设置了FLAG_ACTIVITY_LAUNCH_ADJACENT标志 或者mLaunchSingleInstance=true,这种情况mReusedActivity不一定在task顶部
2 其他情况一定是在栈的顶部。

回调startActivityUnchecked()函数,之后又根据mOptions 获得了个优先的stackId,还记得几种stackid的类型吗。
代码到了这里首先处理了mReusedActivity!=null的情况,我们追踪下。
首先判断了一下是否违反task的锁定模式,我们来分析下锁定模式吧。
违反锁定模式弹出的toast

 <string name="lock_to_app_toast" msgid="1420543809500606964">"要取消固定此屏幕,请触摸并按住“返回”按钮。"</string>
    <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"应用处于固定状态:在此设备上不允许退出该模式。"</string>

也就是说设备进入某种固定状态。直到大概的作用就来详细分析下
isLockTaskModeViolation 函数。
http://www.jb51.net/article/92932.htm 这里有篇文章解释了锁定屏幕的功能,就是把用户锁定到一个task上面,不允许切换。
1 当前栈就是task并且没有new_task 或者clear_task标志,责直接返回fasle.
2 通过mLockTaskAuth 判断 几种模式这里也不解释了。

接下来处理

  if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || mLaunchSingleInstance || mLaunchSingleTask) {

这种情况,需要先执行activity的newIntent操作。
这中情况要再mReusedActivity.task找到对应的activity,并清空上面所有的activity.

final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
        int numActivities = mActivities.size();
        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
            ActivityRecord r = mActivities.get(activityNdx);
            if (r.finishing) {
                continue;
            }
            if (r.realActivity.equals(newR.realActivity)) {
                // Here it is!  Now finish everything in front...
                final ActivityRecord ret = r;

                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
                    r = mActivities.get(activityNdx);
                    if (r.finishing) {
                        continue;
                    }
                    ActivityOptions opts = r.takeOptionsLocked();
                    if (opts != null) {
                        ret.updateOptionsLocked(opts);
                    }
                    if (stack != null && stack.finishActivityLocked(
                            r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
                        --activityNdx;
                        --numActivities;
                    }
                }

                // Finally, if this is a normal launch mode (that is, not
                // expecting onNewIntent()), then we will finish the current
                // instance of the activity so a new fresh one can be started.
                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
                    if (!ret.finishing) {
                        if (stack != null) {
                            stack.finishActivityLocked(
                                    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
                        }
                        return null;
                    }
                }

                return ret;
            }
        }

        return null;
    }

这里有种情况需要考虑,就是一个栈上有两个合适的activity,底下的是符合的,这里返回的确实上面的,为什么是这样呢?singleInstance的不用分析,肯定没有问题。那么singleTask和newTask的呢?? 还记得吗,我们在设置reuseActivity的时候找到只是栈顶的元素,但是有这个标志的呢?FLAG_ACTIVITY_LAUNCH_ADJACENT?? 有这个标志且不是 singleTask的要找到最匹配的intent,这里可能是google 的一个bug,或者我忽略了某个条件,如果有明白的读者,希望分享一下。
我们来看看如果清空目标Activity上面的activity。

 if (stack != null && stack.finishActivityLocked(
                            r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
                        --activityNdx;
                        --numActivities;
                    }

finishActivityLocked 函数比较长,就不贴代码了,直接分析一下。
首先
调用ActivityRecord.makeFinishLocked(), 如果这个activity在后台可见则要取消在后台可见,后台可见是通过Activity#requestVisibleBehind 设置的,并且只有stackId为FULLSCREEN_WORKSPACE_STACK_ID的栈,才允许设置改状态
之后将调用task.setFrontOfTask().
这个函数是用于将最上面的activity设置为frontOfTask,因为现在关闭的activity有可能就是frontOfTask,所以要重新设置
如果launchFlag设置了FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 标志,要将这个标志赋予下一个intent.

中断接收KeyDispatch.
adjustFocusedActivityLocked 如果当前栈是焦点栈切当前要关闭的activity是焦点activity,则将下一个activity设置为焦点activity,现在我们要关闭的activity.finsing = true,所以topRunningActivityLocked 返回的是它下面的activity.

这里有分为两种情况
1 // For freeform, docked, and pinned stacks we always keep the focus within the stack as long as there is a running activity in the stack that we can adjust focus to.
这种情况直接将下一个activity设置成焦点activity
2 洽谈情况,有三种可能 nex ==null 或者不是 freeform, docked, and pinned 或者但前的stack不是焦点stack(这种情况不大可能)
这种情况将焦点返回到 下一个task上。

finishActivityResultsLocked(r, resultCode, resultData);
添加resultData到结果列表里面。方便返回给调用activity。
之后

1如果要关闭的activity是mResumedActivity,调用startPausingLocked函数,如果栈已经空了要调用 mStackSupervisor.removeLockedTaskLocked(task);
2 如果activityrecord的r 没有pause 并且是可见的 则 调用finishCurrentActivityLocked()函数
3 啥都不做,坐等pause

那我们就分析分析
startPausingLocked函数
startPausingLocked()
首先前边的activity还没有pause完成 则如果ams不在睡眠,则调用completePauseLocked, 这里先放一放,分析完了finishCurrentActivityLocked 再来分析

去过mResumedActivity ==null 调用 mStackSupervisor.resumeFocusedStackTopActivityLocked();

    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null || r.state != RESUMED) {
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        }
        return false;
    }

这里要做的就是找到最合适的activity进行显示。

调用shedulePauseActiviy,关闭activity。发出计算超时的message.

finishCurrentActivityLocked

重新分析finishActivityLocked函数

1 如果已经处于finish状态则直接返回
2 调用ActivityRecord.makeFinishingLocked函数
将finishing设置为true 如果已经stopped 则pendingOptions.abord

public boolean requestVisibleBehind (boolean visible) add in android 5.0

如果activity希望在被一个半透明的activity覆盖的时候继续显示,就需要在onResume和onPause之间调用这个方法。 如果调用成功,在activity调用onPause后,它将继续显示,并且可以继续在后台播放媒体。

在这个activity重新回到前台时,requestVisibleBehind(boolean visible)的请求就会失效,如果希望下一次继续在后台显示,就需要再次调用这个方法。

仅仅不透明且全屏的activity需要调用这个方法。对于dialog或者半透明的activity,它不起作用。

当这个方法返回false或者onVisibleBehindCanceled()被调用时,这个activity必须停止播放并且释放资源。

如果我们要关闭的activity正在显示在后台播放,则调用mStackSupervisor.requestVisibleBehindLocked(this, false);
回调onVisibleBehindCanceled()函数,并设置状态 只有在全屏的栈中才可以这么做.

之后 如果要关闭的activity设置了FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 标志,则将这个标志转移给后面的activity.
之后调用pauseKeyDispatchingLocked 停止接收key Event.
调用adjustFocusedActivityLocked 计算焦点activity
如果当前栈不是焦点栈,并前当前activity不是焦点activity 则直接返回. 获取topActivity,如果 top!=要关闭的activity,
因为当前要关闭的activity已经是finish== true了,所以这里应该成立, 这是是希望将next设置成焦点.但是有两种情况
1 如果是 freeform, docked, and pinned 模式的task,并前当前栈是是焦点栈,则直接设置新的topActivity为焦点
2其他情况 如果要关闭的activity是task的栈顶activity,并且这个栈是焦点,且task结束后会返回到桌面或者最近任务列表
则获取taskToReturnTo,这个是确定返回到哪里的变量.
如果stack不是全屏的,则计算下一个焦点
// For non-fullscreen stack, we want to move the focus to the next visible
// stack to prevent the home screen from moving to the top and obscuring
// other visible stacks.
if (!mFullscreen
&& adjustFocusToNextFocusableStackLocked(taskToReturnTo, myReason)) {
return;
}
这里如果不是全屏的栈,需要将焦点移动到下一个栈,防止返回到桌面或者最近列表挡住其他可见的栈

adjustFocusToNextFocusableStackLocked
找到名目上的其他焦点栈.然后如果栈上顶部的activity是可见的,就设置这个栈问新的焦点栈.这种情况对应于屏幕上有多个不同类型的栈.
如果不是正常的找到下一个需要显示的栈.

如果上面全屏或者没有下一个正在显示的栈,则将桌面上的栈设置为焦点. 设置返回桌面.
finishActivityResultsLocked(r, resultCode, resultData); 设置activityResult到结果列表

然后判断关闭的activity是否是mResumedActivity 如果是的话 就设置关闭栈(栈已经空了)或者activity的动画
如果mPausingActivity==null则调用startPausingLocked(false, false, null, false);去关闭reuseActivity.
如果栈已经空了 移除栈.

startPausingLocked 这个函数就是为了pause mResumedActivity,并且等待下一个要显示的activity.我们来看一下它的逻辑.

首先判断下当前是否还有正在pause的activity,如果系统没有处于休眠状态,则调用completePauseLocked()

我们来看看这个函数吧completePauseLocked()
这个函数分为两部分,一部分终止mPausingActivity 一部分显示resuming
首先来看看终止部分如何处理
1 将状态设置为PAUSED
然后判断如果已经设置finishing,则调用finishCurrentActivityLocked函数.
我们来分析下finishCurrentActivityLocked 函数 
获取焦点的顶部activity,然后如果mode==FINISH_AFTER_VISIBLE并且要关闭的activity可见,并且顶部的activity不可坚,
注意我们现在要重用的activity已经在焦点栈上了,要关闭的activity应该是不课件的,所以这里条件应该是满足的,将
mStoppingActivities 添加到stoping列表中. 直接返回.
其他情况则mResumedActivity 设置为null,然后设置状态为finish
这里mStoppingActivities 是要关闭的activity列表,会统一处理关闭..

如果不是FINISH_AFTER_VISIBLE 则在这三个列表中移除activity mStackSupervisor.mStoppingActivities.remove(r);
mStackSupervisor.mGoingToSleepActivities.remove(r);
mStackSupervisor.mWaitingVisibleActivities.remove(r);
然后设置 state为FINISHING
Activity的几个状态
enum ActivityState {
INITIALIZING,
RESUMED,
PAUSING,
PAUSED,
STOPPING,
STOPPED,
FINISHING,
DESTROYING,
DESTROYED
} 
这里主要就是关闭activity的逻辑,还是比较复杂的因为和powerManager有关系,然后通如下这些变量去维护状态
/** List of activities that are waiting for a new activity to become visible before completing
* whatever operation they are supposed to do. */
final ArrayList mWaitingVisibleActivities = new ArrayList<>();

/** List of processes waiting to find out about the next visible activity. */
final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible = new ArrayList<>();

/** List of processes waiting to find out about the next launched activity. */
final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched = new ArrayList<>();

/** List of activities that are ready to be stopped, but waiting for the next activity to
 * settle down before doing so. */
final ArrayList<ActivityRecord> mStoppingActivities = new ArrayList<>();

/** List of activities that are ready to be finished, but waiting for the previous activity to
 * settle down before doing so.  It contains ActivityRecord objects. */
final ArrayList<ActivityRecord> mFinishingActivities = new ArrayList<>();

/** List of activities that are in the process of going to sleep. */
final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<>();

/** List of activities whose multi-window mode changed that we need to report to the
 * application */
final ArrayList<ActivityRecord> mMultiWindowModeChangedActivities = new ArrayList<>();

/** List of activities whose picture-in-picture mode changed that we need to report to the
 * application */
final ArrayList<ActivityRecord> mPipModeChangedActivities = new ArrayList<>();

/** Used on user changes */
final ArrayList<UserState> mStartingUsers = new ArrayList<>();

要关闭一个activity,首先要将 mStackSupervisor.mStoppingActivities.remove(r);
mStackSupervisor.mGoingToSleepActivities.remove(r);
mStackSupervisor.mWaitingVisibleActivities.remove(r); 这三个队列中的activity移除.然后如果关闭的是mResumedActivity
要将mResumedActivity设置为null. 将原来的状态设置为ActivityState.FINISHING
如果atcivity原先是不可可见的 或者没有显示出来,或者要求立刻关闭activity,则调用destroyActivityLocked关闭页面.

destroyActivityLocked函数: 直接调用destory并调用一些清理函数
由此可见有两种方式关闭activity,一种是直接调用destory,一种是放在列表中,统一处理.
回到startPausingLocked 中,我们看看这里是如何关闭mResumedActivity的(假设这里mPausingActivity是null的)

调用pause,调用mPausingActivity的destory.

pause和finish都有两种情况,1中是直接关闭,一种放到集合同意处理.

performClearTaskLocked
如果标准模式,没有singleTop 的lunchMode FLAG_ACTIVITY_SINGLE_TOP 则也要关闭mResumeActivity.

final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
mStartActivity, mLaunchFlags); 如果返回的top!=null,并且这时候top已经在task顶部,将task的Intent
更新为mStartActivity的intent,视为新启了task.
然后调用newIntent.

private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity)

这个函数主要设这只目标task和将它移动到顶部.我们来分析下她的逻辑.

如果新的task和当前焦点task不一样
if (curTop != null
&& (curTop.task != intentActivity.task || curTop.task != focusStack.topTask())
&& !mAvoidMoveToFront) {
然后需要切换焦点task为新的task

到这里就处理完成luncmMode 为singleInstance singleTask 和设置有FLAG_ACTIVITY_SINGLE_TOP标志,还有在NET_TASK的且页面就在栈顶的
并且存在可复用activity的启动工作

接下来处理四中情况
1 不能重用sourceRecord的没有合适task的
setTaskFromReuseOrCreateNewTask 分两种 创建和重用

如果可以放在sourceRecord的task中,如果setTaskFromSourceRecord复用了activity 则不需要重新启动,这里大多数情况要重新启动
在intask中启动 

mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions); 我现在已经非常烦躁了

再次分析if (mReusedActivity != null) {的情况

这次我们关注lunchMode = singleTop 和flags的FLAG_ACTIVITY_CLEAR_TOP
首先判断是否为反锁定模式
1设置mStartActivity.task = mReusedActivity.task;
2 if (mReusedActivity.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.
mReusedActivity.task.setIntent(mStartActivity);
}
final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
mStartActivity, mLaunchFlags);

函数的大致思路就是关闭mReusedActivity上面的activity. 如果mReusedActivity是标准activity,则

重新分析getReusableIntentActivity函数,之前分析的有一些误差,findTaskLocked函数有些错误,这个函数只是找到合适的task.
所以mReusedActivity是栈顶合适的栈的栈顶的activity.只是用于找到合适的栈 名字起的不太好.

if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) { 这种情况就要清除合适的栈中存在对应的activity上面
的activity,如果有FLAG_ACTIVITY_CLEAR_TOP而没有FLAG_ACTIVITY_SINGLE_TOP的且ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE,也要清
掉对应的activity 这种情况就和singleTask一样了.

我们来看看如果清除掉上面的activity.

找到栈中activity和要启动的activity一样的.然后调用

stack.finishActivityLocked(
r, Activity.RESULT_CANCELED, null, “clear-task-stack”, false)
进行关闭, 如果已经是finishing状态直接返回

1调用Activity.makeFinishingLocked ,如果要关闭的activity是VisibleBehindActivity,调用相关生命周期函数,
3名更新栈上的VisibleBehindActivity.
4更新task上的frontOfTask,task的栈顶activity这个值为true
5终止该activity的key事件
6 计算focuseActivity 是指这个栈上顶层的activity,这里如果栈不为null,则next就不会为null.
当next不为null的时候
  如果搞关闭的activity是焦点的时候才会重新计算焦点,所以这部分先不去分析.在activity启动了之后再去分析.
7 保存activityResult
8(1) mResumedActivity == r 这种情况一位着关闭的activity是现在可见的activity,可能要做一些动画的处理.
   如果正在关闭的activty为null 也就是mPausingActivity==null 调用 startPausingLocked(false, false, null, false);
  如果task已经null;额 则调用mStackSupervisor.removeLockedTaskLocked(task);
8(2) 不可见的activity 采用finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ?
FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null; 关闭.
 两种的区别在于8(1)需要调用pause函数 8(2)则直接调用destory函数.
  我们来分析下如何确保activity关闭.
  
先来分析startPausingLocked,如果mPausingActivity!=null 并且ams没有睡眠,则调用completePauseLocked(false, resuming); 函数

startPausingLocked 函数比较简单就是为了调用 prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait); 函数.
 有个参数叫dontWait 这个参数不同会采取不同的策略,一种是调用 prev.app.thread.schedulePauseActivity之后需要记录是否超时,另一种是将activity的一种关闭
队列中延时被执行其他生命周期函数.

 对于8(2)这种情况调用finishCurrentActivityLockedh函数,一种是放入队列,一种直接调用destory

9如果top不为null 则直接调用onNewIntent方法
 现在总结下top!=null的三种情况
   1 singleTask
2 singleInstance
3 Intent.FLAG_ACTIVITY_TASK&FLAG_ACTIVITY_CLEAR_TOP&FLAG_ACTIVITY_SINGLE_TOP&lunchmode.standard

private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity)
两种情况需要移动栈
当前栈顶task!=新activity要进入的task, 或者相等但是这个task不是topTask
对于不是clear task的情况,clear task在setTaskFromIntentActivity后面处理.
有两种情况
mMovedOtherTask=true 标示移动过其他task
1(1) 如果没有启动到其他栈上,则将当前task移动到栈顶mTargetStack.moveTaskToFrontLocked
1(2) 如果有栈的切换,则要移动task到其他栈上mSupervisor.moveTaskToStackLocked
2 mTargetStack.moveToFront(“intentActivityFound”);

final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,

再次重新入手
上回书说道处理完成了三种情况

1这三种情况activity都已经启动在已经存在的task中
2并且lunchMode = singleTask | singleInstance
3 lunchFlag= (FLAG_ACTIVITY_CLEAR_TOP &FLAG_ACTIVITY_SINGLE_TOP)

其中满足1&2 或者1&3的 task顶部的activity已经是我们想要的activity了,并且已经执行了
onNewIntent方法,接下来就是start和onResume方法了

private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) 函数
还记得吗reuseActivity只是为了找到对应的task.
1设置mTargetStack 为目的reuseActivity.stack
2 获取焦点stack
3 获取当前焦点stack显示的activity,如果没有则设置为null
4 如果要进入的task不是焦点stack上的topTask 并且mAvoidMoveToFront=flase. 还记得mAvoidMoveToFront吗,悄悄的启动
     if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
mSourceStack.topActivity().task == mSourceRecord.task))
     这里只处理sourceRecord==null和sourceReocrd.task在栈顶的情况,一般从activity启动都是第二种情况

   没有FLAG_ACTIVITY_CLEAR_TASK&FLAG_ACTIVITY_NEW_TASK标志
(1) 获取lunchStack==null 或者 launchStack == mTargetStack 这种情况没有stack的切换,就调用
           mTargetStack.moveTaskToFrontLocked(
intentActivity.task, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, “bringingFoundTaskToFront”);
           
   
  (2) 如果不是在相同的stack上,并且从DOCKED_STACK启动,或者从FULLSCREEN_WORKSPACE_STACK启动 
1 如果尝试已分屏模式启动则需要从lunchStack切换到 task.stack
调用 mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
launchStack.mStackId, ON_TOP, FORCE_FOCUS, “launchToSide”,
ANIMATE);
                2 其他情况 将task移到栈顶.

 mTargetStack.moveTaskToFrontLocked(
intentActivity.task, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, “bringingFoundTaskToFront”); 函数分析,
1 找到栈上的task
2 没有该task则终止动画
3 更新task的appTimeTracker
4 将task插到栈顶 insertTaskAtTop(tr, null);
5 当前用户不能显示,添加task最上面的activity到RecentActivity
6 设置当前栈顶activity为focusedActivity. mService.setFocusedActivityLocked(r, reason);
7 mStackSupervisor.resumeFocusedStackTopActivityLocked();

private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity)
1 如果task是返回到桌面或者最近任务的 则设置后面的task为返回桌面. 如果没有后面的task 设置isLastTaskOverHome = true;
2 计算returnType
static final int APPLICATION_ACTIVITY_TYPE = 0;
static final int HOME_ACTIVITY_TYPE = 1;
static final int RECENTS_ACTIVITY_TYPE = 2;
主要有三种类型,第一种是返回到应用,第二种是返回到桌面,第三种是返回到RECENTS

  (1) 如果是默认的显示器,
task不是桌面tsak,如果我们的stack是从桌面启动的或者topTask!=task
  首先如果isLastTaskOverHome=true 说明后面没有task,所以沿用原来的task(
     这种情况可能不需要移动task,这显然跟topTask!=task是冲突的 ),否则设置成
 APPLICATION_ACTIVITY_TYPE,返回到后面的应用(也就是调用者)

  (2) 不是默认显示器,直接设置task的返回到应用
3 移除task,找到多用户合适的位置插入到栈中
4 updateTaskMovement

boolean setFocusedActivityLocked(ActivityRecord r, String reason)
1 如果r = null 或者r 就是mFocusedActivity 直接返回
2 不能获取焦点 则直接返回
3 设置final ActivityRecord last = mFocusedActivity;mFocusedActivity = r; 
4 设置appTimeTracker
5 voiceInteractor 相关
6 移动stack到上面,设置焦点app
7 applyUpdateLockStateLocked(r); applyUpdateVrModeLocked(r);
8 恢复mDoingSetFocusedActivity  这个值应该是锁定状态的

这里面值得研究的就是
if (mStackSupervisor.moveActivityStackToFront(r, reason + ” setFocusedActivity”)) {
mWindowManager.setFocusedApp(r.appToken, true);
}

resumeTopActivityInnerLocked

我们想象显示一个activity要做什么,首先要pause其他activity 然后执行我们的onResume

上回书说到
1当parent没有显示的时候直接返回
2 取消看不到的starting window
3 当stack上没有activity的时候,显示下一个合适的stack
4 要现实的activity证实当前正在显示的activity,则直接返回
5 prevTask != null && prevTask.stack == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask
这里要关闭prevTask 启动另外的activity有洗面集中情况
(1) prevTask== nexTask 说明没有切换task,应该把要现实的activity设置成frontOfTask
(2) prevTask != topTask 设置prevTask的下一个task的returnType
(3) 不在homeDisplay 直接返回
(4) 但前stack不是home stack 现实homestackTask 为什么呢????

6 如果ams正在休眠,并且mLastPausedActivity == next 并且所有的activity都pause完成 则直接返回
7 如过用户已经关闭 则直接返回
8 将next从stoping goingToSleep waitingVisible队列中移除
9 所有要pauseing的activity没有完成 直接返回
10 mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid); weaklock相关
11 mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause); //pause 所有栈上resumeActivity 已经分析过了 只有一个activity是resume的
12 这里有两种情况 分别是有处于pausing状态的activity,和没有pauseing状态的activity
dontWaitForPause 为会显示toprunning
对于状态1 只是更新进程的lru process的
对于状态2 其他activity已经paused 要resume的activity已经显示责直接返回,这种情况一般是dowait了该activity
我们大多数情况都是处于状态1

13 prev != null && prev != next 确保prev状态 两种情况
(1) 等待显示的activity中不包含next 添加到里面
(2) mWindowManager.setAppVisibility(prev.appToken, false);
14 AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false, next.userId) //设置应用状态,确保不再被认为是停止的

15 mWindowManager.prepareAppTransition(TRANSIT_NONE, false);

16 两种情况 1 top activity 已经started状态 2 没有启动 这是最后一部分工作,流程可能比较长

一 (这种情况activity已经started了)
1 根据某些情况设置 mWindowManager.setAppVisibility(next.appToken, true);
2 next.startLaunchTickingLocked(); 用于计算启动时间
3 设置状态
next.state = ActivityState.RESUMED;
mResumedActivity = next;
next.task.touchActiveTime();
mRecentTasks.addLocked(next.task);
mService.updateLruProcessLocked(next.app, true, null);
updateLRUListLocked(next);
mService.updateOomAdjLocked();
4 调用resumeActivity方法

二 mStackSupervisor.startSpecificActivityLocked(next, true, true);

总结 :这个函数多次检查allPause状态,因为有些pauseing被放置到了队列中执行,
当pause完成后会重新执行resumeTopActivityInnerLocked,然后才会走13以后的状态。 另外一种情况是pause的时候指定了
dowait,那种情况会直接向下执行,并且直接设置状态为stoping,不会关注pauseing状态

startSpecificActivityLocked
获取进程信息
1.如果进程已经存在final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
2. mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
“activity”, r.intent.getComponent(), false, false, true);

先来分析1 realStartActivityLocked
1所有activity没有pause完成,直接返回,因为paused后会重新调用resume
2 doResume 责调用service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
3 更新进程状态
4 设置锁定状态
5 scheduleLaunchActivity

startProcessLocked
1 如果是沙箱进程 设置r.app ==null,不关联app
2如果不是沙箱进程,责进行如下操作
(1)获取app信息如果启动activity从后太启动,责要检查程序是否是bad process,如果是直接返回null
(2)不是后台启动的activity,责从mAppErrors 种移除
3如果已经启动了进程,正在等待进程启动,则 返回,否则的话杀死进程组。
4 赋值 process信息,两种情况1app不存在 2 已经存在
(1)app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
设置沙箱进程的uid, 创建ProcessRecord,设置到mProcessNames中,根据进程名字 uid processinfo管理进程
mIsolatedProcesses用于管理纱箱进程

(2) app.addPackage(info.packageName, info.versionCode, mProcessStats); 增加进程状态信息
5 如果系统没有准备完成,添加app到mProcessesOnHold中 系统启动完成再进行启动 直接返回
6 startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);

startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
1 到了这里必然要重新启动app
2 移除app的超时信息
3 mProcessesOnHold.remove(app); 还记得系统没有启动好放在这里面吗
4 AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
5 设置启动参数,调用Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);

6 发出PROC_START_TIMEOUT_MSG 等待进程attachApplication

//TODO1 分析沙箱进程
//TODO2 分析多用户
//TODO 常驻进程
//TODO 重量级进程
//TODO 分析AppOpsService

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值