startActivity到底发生了什么(二)
启动另外一个应用的MainActivity- <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
复制代码 注意必须设置exported为true才能被另一个进程启动。- val intent = Intent()
- intent.setClassName("io.github.customview", "io.github.customview.activity.MainActivity")
- intent.putExtra("name", "ITGuoKe")
- context.startActivity(intent)
复制代码 启动另一个app的Activity,并传递参数。
app startActivity
context.startActivity(intent)通过多态实际上调用的是Activity的startActivity方法,然后startActivityForResult->Instrumentation.execStartActivity(注意是第四个参数为Activity的重载方法),最后IPC调用ActivityTaskManagerService的startActivity方法ActivityTaskManager.getService().startActivity.
系统服务ActivityTaskManagerService
startActivity -> startActivityAsUser -> getActivityStartController().obtainStarter
查看ActivityStartController的方法obtainStarter的源码如下- ActivityStarter obtainStarter(Intent intent, String reason) {
- return mFactory.obtain().setIntent(intent).setReason(reason);
- }
复制代码 然后查看ActivityStarter的execute的方法源码:- int execute() { // Required for logging ContentOrFileUriEventReported in the finally block. String callerActivityName = null; ActivityRecord launchingRecord = null; try { onExecutionStarted(); if (mRequest.intent != null) { // Refuse possible leaked file descriptors if (mRequest.intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } // Remove existing mismatch flag so it can be properly updated later mRequest.intent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH); } final LaunchingState launchingState; synchronized (mService.mGlobalLock) { final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo); final int callingUid = mRequest.realCallingUid == Request.DEFAULT_REAL_CALLING_UID ? Binder.getCallingUid() : mRequest.realCallingUid; launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching( mRequest.intent, caller, callingUid); callerActivityName = caller != null ? caller.info.name : null; } if (mRequest.intent != null) { mRequest.componentSpecified |= mRequest.intent.getComponent() != null; } // If the caller hasn't already resolved the activity, we're willing // to do so here. If the caller is already holding the WM lock here, // and we need to check dynamic Uri permissions, then we're forced // to assume those permissions are denied to avoid deadlocking. if (mRequest.activityInfo == null) { mRequest.resolveActivity(mSupervisor); } // Add checkpoint for this shutdown or reboot attempt, so we can record the original // intent action and package name. if (mRequest.intent != null) { String intentAction = mRequest.intent.getAction(); String callingPackage = mRequest.callingPackage; if (intentAction != null && callingPackage != null && (Intent.ACTION_REQUEST_SHUTDOWN.equals(intentAction) || Intent.ACTION_SHUTDOWN.equals(intentAction) || Intent.ACTION_REBOOT.equals(intentAction))) { ShutdownCheckPoints.recordCheckPoint(intentAction, callingPackage, null); } } int res = START_CANCELED; synchronized (mService.mGlobalLock) { final boolean globalConfigWillChange = mRequest.globalConfig != null && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0; final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (rootTask != null) { rootTask.mConfigWillChange = globalConfigWillChange; } ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config " + "will change = %b", globalConfigWillChange); final long origId = Binder.clearCallingIdentity(); try { res = resolveToHeavyWeightSwitcherIfNeeded(); if (res != START_SUCCESS) { return res; } res = executeRequest(mRequest); // 1 } finally { Binder.restoreCallingIdentity(origId); mRequest.logMessage.append(" result code=").append(res); Slog.i(TAG, mRequest.logMessage.toString()); mRequest.logMessage.setLength(0); } if (globalConfigWillChange) { // 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.mAmInternal.enforceCallingPermission( android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()"); if (rootTask != null) { rootTask.mConfigWillChange = false; } ProtoLog.v(WM_DEBUG_CONFIGURATION, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> "Updating to new configuration after starting activity."); mService.updateConfigurationLocked(mRequest.globalConfig, null, false); } // The original options may have additional info about metrics. The mOptions is not // used here because it may be cleared in setTargetRootTaskIfNeeded. final ActivityOptions originalOptions = mRequest.activityOptions != null ? mRequest.activityOptions.getOriginalOptions() : null; // Only track the launch time of activity that will be resumed. if (mDoResume || (isStartResultSuccessful(res) <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> && mLastStartActivityRecord.getTask().isVisibleRequested())) { launchingRecord = mLastStartActivityRecord; } // If the new record is the one that started, a new activity has created. final boolean newActivityCreated = mStartActivity == launchingRecord; // Notify ActivityMetricsLogger that the activity has launched. // ActivityMetricsLogger will then wait for the windows to be drawn and populate // WaitResult. mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> newActivityCreated, launchingRecord, originalOptions); if (mRequest.waitResult != null) { mRequest.waitResult.result = res; res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> launchingState); } return getExternalResult(res); } } finally { // Notify UriGrantsManagerService that activity launch completed. Required for logging // the ContentOrFileUriEventReported message. mSupervisor.mService.mUgmInternal.notifyActivityLaunchRequestCompleted( mRequest.hashCode(), // isSuccessfulLaunch launchingRecord != null, // Intent action mRequest.intent != null ? mRequest.intent.getAction() : null, mRequest.realCallingUid, callerActivityName, // Callee UID mRequest.activityInfo != null ? mRequest.activityInfo.applicationInfo.uid : INVALID_UID, // Callee Activity name mRequest.activityInfo != null ? mRequest.activityInfo.name : null, // isStartActivityForResult launchingRecord != null && launchingRecord.resultTo != null); onExecutionComplete(); }}
复制代码 由注释1处的代码可知ActivityStarter的executeRequest源码如下:- private int executeRequest(Request request) { if (TextUtils.isEmpty(request.reason)) { throw new IllegalArgumentException("Need to specify a reason."); } mLastStartReason = request.reason; mLastStartActivityTimeMs = System.currentTimeMillis(); ... final ActivityRecord r = new ActivityRecord.Builder(mService) .setCaller(callerApp) .setLaunchedFromPid(callingPid) .setLaunchedFromUid(callingUid) .setLaunchedFromPackage(callingPackage) .setLaunchedFromFeature(callingFeatureId) .setIntent(intent) .setResolvedType(resolvedType) .setActivityInfo(aInfo) .setConfiguration(mService.getGlobalConfiguration()) .setResultTo(resultRecord) .setResultWho(resultWho) .setRequestCode(requestCode) .setComponentSpecified(request.componentSpecified) .setRootVoiceInteraction(voiceSession != null) .setActivityOptions(checkedOptions) .setSourceRecord(sourceRecord) .build(); mLastStartActivityRecord = r; if (r.appTimeTracker == null && sourceRecord != null) { // If the caller didn't specify an explicit time tracker, we want to continue // tracking under any it has. r.appTimeTracker = sourceRecord.appTimeTracker; } // Only allow app switching to be resumed if activity is not a restricted background // activity and target app is not home process, otherwise any background activity // started in background task can stop home button protection mode. // As the targeted app is not a home process and we don't need to wait for the 2nd // activity to be started to resume app switching, we can just enable app switching // directly. WindowProcessController homeProcess = mService.mHomeProcess; boolean isHomeProcess = homeProcess != null && aInfo.applicationInfo.uid == homeProcess.mUid; if (balVerdict.allows() && !isHomeProcess) { mService.resumeAppSwitches(); } // Only do the create here since startActivityInner can abort. If it doesn't abort, // the requestStart will be sent in handleStartRequest. final Transition newTransition = r.mTransitionController.isShellTransitionsEnabled() ? r.mTransitionController.createAndStartCollecting(TRANSIT_OPEN) : null; // Because startActivity must run immediately, it can get combined with another // transition meaning it is no-longer independent. This is NOT desirable, but is the // only option for the time being. final boolean isIndependent = newTransition != null; final Transition transition = isIndependent ? newTransition : mService.getTransitionController().getCollectingTransition(); // 1 mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> request.voiceInteractor, startFlags, checkedOptions, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid, transition, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> isIndependent); if (request.outActivity != null) { request.outActivity[0] = mLastStartActivityRecord; } return mLastStartActivityResult;}
复制代码 由文档注释可知:
startActivityUnchecked -> startActivityInner
startActivityUnchecked源码如下:
ActivityStarter.java- private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, ActivityOptions options, Task inTask, TaskFragment inTaskFragment, BalVerdict balVerdict, NeededUriGrants intentGrants, int realCallingUid, Transition transition, boolean isIndependentLaunch) { int result = START_CANCELED; final Task startedActivityRootTask; RemoteTransition remoteTransition = r.takeRemoteTransition(); // Create a display snapshot as soon as possible. if (isIndependentLaunch && mRequest.freezeScreen) { final TaskDisplayArea tda = mLaunchParams.hasPreferredTaskDisplayArea() ? mLaunchParams.mPreferredTaskDisplayArea : mRootWindowContainer.getDefaultTaskDisplayArea(); final DisplayContent dc = mRootWindowContainer.getDisplayContentOrCreate( tda.getDisplayId()); if (dc != null) { transition.collect(dc); transition.collectVisibleChange(dc); } } try { mService.deferWindowLayout(); r.mTransitionController.collect(r); try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, startFlags, options, inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid); } catch (Exception ex) { Slog.e(TAG, "Exception on startActivityInner", ex); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); startedActivityRootTask = handleStartResult(r, options, result, isIndependentLaunch, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> remoteTransition, transition); } } finally { mService.continueWindowLayout(); } postStartActivityProcessing(r, result, startedActivityRootTask); return result;}
复制代码 startActivityInner源码如下:
ActivityStarter.java- /** * Start an activity and determine if the activity should be adding to the top of an existing * task or delivered new intent to an existing activity. Also manipulating the activity task * onto requested or valid root-task/display. * * Note: This method should only be called from {@link #startActivityUnchecked}. */// TODO(b/152429287): Make it easier to exercise code paths through startActivityInner@VisibleForTestingint startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, ActivityOptions options, Task inTask, TaskFragment inTaskFragment, BalVerdict balVerdict, NeededUriGrants intentGrants, int realCallingUid) { setInitialState(r, options, inTask, inTaskFragment, startFlags, sourceRecord, voiceSession, voiceInteractor, balVerdict.getCode(), realCallingUid); computeLaunchingTaskFlags(); mIntent.setFlags(mLaunchFlags); boolean dreamStopping = false; if (!com.android.window.flags.Flags.removeActivityStarterDreamCallback()) { for (ActivityRecord stoppingActivity : mSupervisor.mStoppingActivities) { if (stoppingActivity.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_DREAM) { dreamStopping = true; break; } } } // Get top task at beginning because the order may be changed when reusing existing task. final Task prevTopRootTask = mPreferredTaskDisplayArea.getFocusedRootTask(); final Task prevTopTask = prevTopRootTask != null ? prevTopRootTask.getTopLeafTask() : null; final boolean sourceActivityLaunchedFromBubble = sourceRecord != null && sourceRecord.getLaunchedFromBubble(); // if the flag is enabled, allow reusing bubbled tasks only if the source activity is // bubbled. final boolean includeLaunchedFromBubble = Flags.onlyReuseBubbledTaskWhenLaunchedFromBubble() ? sourceActivityLaunchedFromBubble : true; final Task reusedTask = resolveReusableTask(includeLaunchedFromBubble); // If requested, freeze the task list if (mOptions != null && mOptions.freezeRecentTasksReordering() && mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid) && !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) { mFrozeTaskList = true; mSupervisor.mRecentTasks.setFreezeTaskListReordering(); } // Compute if there is an existing task that should be used for. final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask(); final boolean newTask = targetTask == null; mTargetTask = targetTask; computeLaunchParams(r, sourceRecord, targetTask); // Check if starting activity on given task or on a new task is allowed. int startResult = isAllowedToStart(r, newTask, targetTask); if (startResult != START_SUCCESS) { if (r.resultTo != null) { r.resultTo.sendResult(INVALID_UID, r.resultWho, r.requestCode, RESULT_CANCELED, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> null /* data */, null /* callerToken */, null /* dataGrants */); } return startResult; } if (targetTask != null) { if (targetTask.getTreeWeight() > MAX_TASK_WEIGHT_FOR_ADDING_ACTIVITY) { Slog.e(TAG, "Remove " + targetTask + " because it has contained too many" + " activities or windows (abort starting " + r + " from uid=" + mCallingUid); targetTask.removeImmediately("bulky-task"); return START_ABORTED; } // When running transient transition, the transient launch target should keep on top. // So disallow the transient hide activity to move itself to front, e.g. trampoline. if (!avoidMoveToFront() && (mService.mHomeProcess == null <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> || mService.mHomeProcess.mUid != realCallingUid) && (prevTopTask != null && prevTopTask.isActivityTypeHomeOrRecents()) && r.mTransitionController.isTransientHide(targetTask)) { mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY; } // If the activity is started by sending a pending intent and only its creator has the // privilege to allow BAL (its sender does not), avoid move it to the front. Only do // this when it is not a new task and not already been marked as avoid move to front. // Guarded by a flag: balDontBringExistingBackgroundTaskStackToFg if (balDontBringExistingBackgroundTaskStackToFg() && !avoidMoveToFront() && balVerdict.onlyCreatorAllows()) { mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS; } mPriorAboveTask = TaskDisplayArea.getRootTaskAbove(targetTask.getRootTask()); } final ActivityRecord targetTaskTop = newTask ? null : targetTask.getTopNonFinishingActivity(); if (targetTaskTop != null) { // Removes the existing singleInstance activity in another task (if any) while // launching a singleInstance activity on sourceRecord's task. if (LAUNCH_SINGLE_INSTANCE == mLaunchMode && mSourceRecord != null && targetTask == mSourceRecord.getTask()) { final ActivityRecord activity = mRootWindowContainer.findActivity(mIntent, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> mStartActivity.info, false); if (activity != null && activity.getTask() != targetTask) { activity.destroyIfPossible("Removes redundant singleInstance"); } } if (mLastStartActivityRecord != null) { targetTaskTop.mLaunchSourceType = mLastStartActivityRecord.mLaunchSourceType; } targetTaskTop.mTransitionController.collect(targetTaskTop); recordTransientLaunchIfNeeded(targetTaskTop); // Recycle the target task for this launch. startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants, balVerdict); if (startResult != START_SUCCESS) { return startResult; } } else { mAddingToTask = true; } // 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 Task topRootTask = mPreferredTaskDisplayArea.getFocusedRootTask(); if (topRootTask != null) { startResult = deliverToCurrentTopIfNeeded(topRootTask, intentGrants); if (startResult != START_SUCCESS) { return startResult; } } if (mTargetRootTask == null) { mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> mOptions); } if (newTask) { final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null) ? mSourceRecord.getTask() : null; setNewTask(taskToAffiliate); } else if (mAddingToTask) { addOrReparentStartingActivity(targetTask, "adding to task"); } // After activity is attached to task, but before actual start recordTransientLaunchIfNeeded(mLastStartActivityRecord); if (mDoResume) { if (!avoidMoveToFront()) { mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask); final boolean launchBehindDream; if (com.android.window.flags.Flags.removeActivityStarterDreamCallback()) { final TaskDisplayArea tda = mTargetRootTask.getTaskDisplayArea(); final Task top = (tda != null ? tda.getTopRootTask() : null); launchBehindDream = (top != null && top != mTargetRootTask) && top.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_DREAM && top.getTopNonFinishingActivity() != null; } else { launchBehindDream = !mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming() && !dreamStopping; } if (launchBehindDream) { // Launching underneath dream activity (fullscreen, always-on-top). Run the // launch--behind transition so the Activity gets created and starts // in visible state. mLaunchTaskBehind = true; r.mLaunchTaskBehind = true; } } else { logPIOnlyCreatorAllowsBAL(); } } mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> mStartActivity.getUriPermissionsLocked()); if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) { // we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs final PackageManagerInternal pmInternal = mService.getPackageManagerInternalLocked(); final int resultToUid = pmInternal.getPackageUid( mStartActivity.resultTo.info.packageName, 0 /* flags */, mStartActivity.mUserId); pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> resultToUid /*visible*/, true /*direct*/); } else if (mStartActivity.mShareIdentity) { final PackageManagerInternal pmInternal = mService.getPackageManagerInternalLocked(); pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> r.launchedFromUid /*visible*/, true /*direct*/); } final Task startedTask = mStartActivity.getTask(); if (newTask) { EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> startedTask.getRootTaskId(), startedTask.getDisplayId()); } mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask); mStartActivity.getTaskFragment().clearLastPausedActivity(); mRootWindowContainer.startPowerModeLaunchIfNeeded( false /* forceSend */, mStartActivity); final boolean isTaskSwitch = startedTask != prevTopTask; mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> mOptions, sourceRecord); if (mDoResume) { final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked(); if (!mTargetRootTask.isTopActivityFocusable() || (topTaskActivity != null && topTaskActivity.isTaskOverlay() && 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. // Passing {@code null} as the start parameter ensures all activities are made // visible. mTargetRootTask.ensureActivitiesVisible(null /* starting */); // 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. mTargetRootTask.mDisplayContent.executeAppTransition(); } else { // If the target root-task was not previously focusable (previous top running // activity on that root-task was not visible) then any prior calls to move the // root-task to the will not update the focused root-task. If starting the new // activity now allows the task root-task to be focusable, then ensure that we // now update the focused root-task accordingly. if (mTargetRootTask.isTopActivityFocusable() && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) { if (!avoidMoveToFront()) { mTargetRootTask.moveToFront("startActivityInner"); } else { logPIOnlyCreatorAllowsBAL(); } } mRootWindowContainer.resumeFocusedTasksTopActivities( mTargetRootTask, mStartActivity, mOptions, mTransientLaunch); // 1 } } mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask); // Update the recent tasks list immediately when the activity starts mSupervisor.mRecentTasks.add(startedTask); mSupervisor.handleNonResizableTaskIfNeeded(startedTask, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask); // If Activity's launching into PiP, move the mStartActivity immediately to pinned mode. // Note that mStartActivity and source should be in the same Task at this point. if (mOptions != null && mOptions.isLaunchIntoPip() && sourceRecord != null && sourceRecord.getTask() == mStartActivity.getTask() && balVerdict.allows()) { mRootWindowContainer.moveActivityToPinnedRootTask(mStartActivity, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> sourceRecord, "launch-into-pip", null /* bounds */); } mSupervisor.getBackgroundActivityLaunchController() .onNewActivityLaunched(mStartActivity); return START_SUCCESS;}
复制代码 源码中
mStartActivity 是 ActivityStarter对象的ActivityRecord类型的成员变量.
mSupervisor是ActivityTaskSupervisor类型的对象,管理任务栈逻辑.
mRootWindowContainer是RootWindowContainer类型的对象.
我们看下RootWindowContainer类型的对象的resumeFocusedTasksTopActivities方法的源码:
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java- boolean resumeFocusedTasksTopActivities( Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions, boolean deferPause) { if (!mTaskSupervisor.readyToResume()) { return false; } boolean result = false; if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea() <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> || getTopDisplayFocusedRootTask() == targetRootTask)) { result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> deferPause); } for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); final boolean curResult = result; boolean[] resumedOnDisplay = new boolean[1]; final ActivityRecord topOfDisplay = display.topRunningActivity(); display.forAllRootTasks(rootTask -> { final ActivityRecord topRunningActivity = rootTask.topRunningActivity(); if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) { return; } if (rootTask == targetRootTask) { // Simply update the result for targetRootTask because the targetRootTask // had already resumed in above. We don't want to resume it again, // especially in some cases, it would cause a second launch failure // if app process was dead. resumedOnDisplay[0] |= curResult; return; } if (topRunningActivity.isState(RESUMED) && topRunningActivity == topOfDisplay) { // Kick off any lingering app transitions form the MoveTaskToFront operation, // but only consider the top activity on that display. rootTask.executeAppTransition(targetOptions); } else { resumedOnDisplay[0] |= topRunningActivity.makeActiveIfNeeded(target); } }); result |= resumedOnDisplay[0]; if (!resumedOnDisplay[0]) { // In cases when there are no valid activities (e.g. device just booted or launcher // crashed) it's possible that nothing was resumed on a display. Requesting resume // of top activity in focused root task explicitly will make sure that at least home // activity is started and resumed, and no recursion occurs. final Task focusedRoot = display.getFocusedRootTask(); if (focusedRoot != null) { result |= focusedRoot.resumeTopActivityUncheckedLocked( target, targetOptions, false /* skipPause */); // 1 } else if (targetRootTask == null) { result |= resumeHomeActivity(null /* prev */, "no-focusable-task", <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> display.getDefaultTaskDisplayArea()); } } } return result;}
复制代码 focusedRoot是Task类型的对象,接下来查看方法resumeTopActivityUncheckedLocked的源码:
frameworks/base/services/core/java/com/android/server/wm/Task.java- /** * Ensure that the top activity in the root task is resumed. * * @param prev The previously resumed activity, for when in the process * of pausing; can be null to call from elsewhere. * @param options Activity options. * @param deferPause When {@code true}, this will not pause back tasks. * * @return Returns true if something is being resumed, or false if * nothing happened. * * NOTE: It is not safe to call this method directly as it can cause an activity in a * non-focused root task to be resumed. * Use {@link RootWindowContainer#resumeFocusedTasksTopActivities} to resume the * right activity for the current system state. */@GuardedBy("mService")boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options, boolean deferPause) { if (mInResumeTopActivity) { // Don't even start recursing. return false; } boolean someActivityResumed = false; try { // Protect against recursion. mInResumeTopActivity = true; if (isLeafTask()) { if (isFocusableAndVisible()) { someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause); } } else { int idx = mChildren.size() - 1; while (idx >= 0) { final Task child = (Task) getChildAt(idx--); if (!child.isTopActivityFocusable()) { continue; } if (child.getVisibility(null /* starting */) != TASK_FRAGMENT_VISIBILITY_VISIBLE) { if (child.topRunningActivity() == null) { <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>// Skip the task if no running activity and continue resuming next task. <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>continue; } // Otherwise, assuming everything behind this task should also be invisible. break; } someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> deferPause); // Doing so in order to prevent IndexOOB since hierarchy might changes while // resuming activities, for example dismissing split-screen while starting // non-resizeable activity. if (idx >= mChildren.size()) { idx = mChildren.size() - 1; } } } // When resuming the top activity, it may be necessary to pause the top activity (for // example, returning to the lock screen. We suppress the normal pause logic in // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the // end. We call the {@link ActivityTaskSupervisor#checkReadyForSleepLocked} again here // to ensure any necessary pause logic occurs. In the case where the Activity will be // shown regardless of the lock screen, the call to // {@link ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped. final ActivityRecord next = topRunningActivity(true /* focusableOnly */); if (next == null || !next.canTurnScreenOn()) { checkReadyForSleep(); } } finally { mInResumeTopActivity = false; } return someActivityResumed;}
复制代码 继续看Task对象的resumeTopActivityInnerLocked方法:- @GuardedBy("mService")
- private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options, boolean deferPause) {
- if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
- // Not ready yet!
- return false;
- }
- final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);
- if (topActivity == null) {
- // There are no activities left in this task, let's look somewhere else.
- return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);
- }
- final boolean[] resumed = new boolean[1];
- final TaskFragment topFragment = topActivity.getTaskFragment();
- resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
- forAllLeafTaskFragments(f -> {
- if (topFragment == f) {
- return;
- }
- if (!f.canBeResumed(null /* starting */)) {
- return;
- }
- resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
- }, true);
- return resumed[0];
- }
复制代码 TaskFragment的resumeTopActivity源码如下:
frameworks/base/services/core/java/com/android/server/wm/TaskFragment.java- final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options, boolean skipPause) { ActivityRecord next = topRunningActivity(true /* focusableOnly */); if (next == null || !next.canResumeByCompat()) { return false; } next.delayedResume = false; if (!skipPause && !mRootWindowContainer.allPausedActivitiesComplete()) { // If we aren't skipping pause, then we have to wait for currently pausing activities. ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: some activity pausing."); return false; } final TaskDisplayArea taskDisplayArea = getDisplayArea(); // If the top activity is the resumed one, nothing to do. if (mResumedActivity == next && next.isState(RESUMED) && taskDisplayArea.allResumedActivitiesComplete()) { // Ensure the visibility gets updated before execute app transition. taskDisplayArea.ensureActivitiesVisible(null /* starting */, true /* notifyClients */); // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. executeAppTransition(options); // In a multi-resumed environment, like in a freeform device, the top // activity can be resumed, but it might not be the focused app. // Set focused app when top activity is resumed. However, we shouldn't do it for a // same task because it can break focused state. (e.g. activity embedding) if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null) { final ActivityRecord focusedApp = taskDisplayArea.mDisplayContent.mFocusedApp; if (focusedApp == null || focusedApp.getTask() != next.getTask()) { taskDisplayArea.mDisplayContent.setFocusedApp(next); } } ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity " + "resumed %s", next); return false; } // If we are sleeping, and there is no resumed activity, and the top activity is paused, // well that is the state we want. if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) { // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. executeAppTransition(options); ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Going to sleep and" + " all paused"); return false; } // Make sure that the user who owns this activity is started. If not, // we will just leave it as is because someone should be bringing // another user's activities to the top of the stack. if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) { Slog.w(TAG, "Skipping resume of top activity " + next + ": user " + next.mUserId + " is stopped"); return false; } // The activity may be waiting for stop, but that is no longer // appropriate for it. mTaskSupervisor.mStoppingActivities.remove(next); if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid); ActivityRecord lastResumed = null; final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask(); if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTaskFragment().asTask()) { // So, why aren't we using prev here??? See the param comment on the method. prev // doesn't represent the last resumed activity. However, the last focus stack does if // it isn't null. lastResumed = lastFocusedRootTask.getTopResumedActivity(); } boolean pausing = !skipPause && taskDisplayArea.pauseBackTasks(next); if (mResumedActivity != null) { ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity); pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> next, "resumeTopActivity"); } if (pausing) { ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to" + " start pausing"); // At this point we want to put the upcoming activity's process // at the top of the LRU list, since we know we will be needing it // very soon and it would be a waste to let it get killed if it // happens to be sitting towards the end. if (next.attachedToProcess()) { next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> true /* activityChange */, false /* updateOomAdj */, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> false /* addPendingTopUid */); } else if (!next.isProcessRunning()) { // Since the start-process is asynchronous, if we already know the process of next // activity isn't running, we can start the process earlier to save the time to wait // for the current activity to be paused. final boolean isTop = this == taskDisplayArea.getFocusedRootTask(); mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> : HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY); } if (lastResumed != null) { lastResumed.setWillCloseOrEnterPip(true); } return true; } else if (mResumedActivity == next && next.isState(RESUMED) && taskDisplayArea.allResumedActivitiesComplete()) { // It is possible for the activity to be resumed when we paused back stacks above if the // next activity doesn't have to wait for pause to complete. // So, nothing else to-do except: // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. executeAppTransition(options); ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity resumed " + "(dontWaitForPause) %s", next); return true; } // If the most recent activity was noHistory but was only stopped rather // than stopped+finished because the device went to sleep, we need to make // sure to finish it as we're making a new activity topmost. if (shouldSleepActivities()) { mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next); } if (prev != null && prev != next && next.nowVisible) { // The next activity is already visible, so hide the previous // activity's windows right now so we can show the new one ASAP. // We only do this if the previous is finishing, which should mean // it is on top of the one being resumed so hiding it quickly // is good. Otherwise, we want to do the normal route of allowing // the resumed activity to be shown so we can decide if the // previous should actually be hidden depending on whether the // new one is found to be full-screen or not. if (prev.finishing) { prev.setVisibility(false); if (DEBUG_SWITCH) { Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev + ", nowVisible=" + next.nowVisible); } } else { if (DEBUG_SWITCH) { Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev + ", nowVisible=" + next.nowVisible); } } } try { mTaskSupervisor.getActivityMetricsLogger() .notifyBeforePackageUnstopped(next.packageName); mAtmService.getPackageManagerInternalLocked().notifyComponentUsed( next.packageName, next.mUserId, next.packageName, next.toString()); /* TODO: Verify if correct userid */ } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " + next.packageName + ": " + e); } // We are starting up the next activity, so tell the window manager // that the previous one will be hidden soon. This way it can know // to ignore it when computing the desired screen orientation. boolean anim = true; final DisplayContent dc = taskDisplayArea.mDisplayContent; if (prev != null) { if (prev.finishing) { if (DEBUG_TRANSITION) { Slog.v(TAG_TRANSITION, "Prepare close transition: prev=" + prev); } if (mTaskSupervisor.mNoAnimActivities.contains(prev)) { anim = false; dc.prepareAppTransition(TRANSIT_NONE); } else { dc.prepareAppTransition(TRANSIT_CLOSE); } prev.setVisibility(false); } else { if (DEBUG_TRANSITION) { Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev); } if (mTaskSupervisor.mNoAnimActivities.contains(next)) { anim = false; dc.prepareAppTransition(TRANSIT_NONE); } else { dc.prepareAppTransition(TRANSIT_OPEN, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0); } } } else { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous"); if (mTaskSupervisor.mNoAnimActivities.contains(next)) { anim = false; dc.prepareAppTransition(TRANSIT_NONE); } else { dc.prepareAppTransition(TRANSIT_OPEN); } } if (anim) { next.applyOptionsAnimation(); } else { next.abortAndClearOptionsAnimation(); } mTaskSupervisor.mNoAnimActivities.clear(); if (next.attachedToProcess()) { if (DEBUG_SWITCH) { Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.mAppStopped + " visibleRequested=" + next.isVisibleRequested()); } // If the previous activity is translucent, force a visibility update of // the next activity, so that it's added to WM's opening app list, and // transition animation can be set up properly. // For example, pressing Home button with a translucent activity in focus. // Launcher is already visible in this case. If we don't add it to opening // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation. final boolean lastActivityTranslucent = inMultiWindowMode() || mLastPausedActivity != null && !mLastPausedActivity.occludesParent(); // This activity is now becoming visible. if (!next.isVisibleRequested() || next.mAppStopped || lastActivityTranslucent) { next.app.addToPendingTop(); next.setVisibility(true); } // schedule launch ticks to collect information about slow apps. next.startLaunchTickingLocked(); ActivityRecord lastResumedActivity = lastFocusedRootTask == null ? null : lastFocusedRootTask.getTopResumedActivity(); final ActivityRecord.State lastState = next.getState(); mAtmService.updateCpuStats(); ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next); next.setState(RESUMED, "resumeTopActivity"); // Activity should also be visible if set mLaunchTaskBehind to true (see // ActivityRecord#shouldBeVisibleIgnoringKeyguard()). if (shouldBeVisible(next)) { // We have special rotation behavior when here is some active activity that // requests specific orientation or Keyguard is locked. Make sure all activity // visibilities are set correctly as well as the transition is updated if needed // to get the correct rotation behavior. Otherwise the following call to update // the orientation may cause incorrect configurations delivered to client as a // result of invisible window resize. // TODO: Remove this once visibilities are set correctly immediately when // starting an activity. final int originalRelaunchingCount = next.mPendingRelaunchCount; mRootWindowContainer.ensureVisibilityAndConfig(next, mDisplayContent, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> false /* deferResume */); if (next.mPendingRelaunchCount > originalRelaunchingCount) { // The activity is scheduled to relaunch, then ResumeActivityItem will be also // included (see ActivityRecord#relaunchActivityLocked) if it should resume. next.completeResumeLocked(); return true; } } try { final IApplicationThread appThread = next.app.getThread(); // Deliver all pending results. final ArrayList a = next.results; if (a != null) { final int size = a.size(); if (!next.finishing && size > 0) { if (DEBUG_RESULTS) { <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a); } final ActivityResultItem item = new ActivityResultItem(next.token, a); mAtmService.getLifecycleManager().scheduleTransactionItem(appThread, item); } } if (next.newIntents != null) { final NewIntentItem item = new NewIntentItem(next.token, next.newIntents, true /* resume */); mAtmService.getLifecycleManager().scheduleTransactionItem(appThread, item); } // Well the app will no longer be stopped. // Clear app token stopped state in window manager if needed. next.notifyAppResumed(); EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next), <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> next.getTask().mTaskId, next.shortComponentName); mAtmService.getAppWarningsLocked().onResumeActivity(next); final int topProcessState = mAtmService.mTopProcessState; next.app.setPendingUiCleanAndForceProcessStateUpTo(topProcessState); next.abortAndClearOptionsAnimation(); final ResumeActivityItem resumeActivityItem = new ResumeActivityItem( next.token, topProcessState, dc.isNextTransitionForward(), next.shouldSendCompatFakeFocus()); mAtmService.getLifecycleManager().scheduleTransactionItem( appThread, resumeActivityItem); ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next); } catch (Exception e) { // Whoops, need to restart this activity! ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: " + "%s", lastState, next); next.setState(lastState, "resumeTopActivityInnerLocked"); // lastResumedActivity being non-null implies there is a lastStack present. if (lastResumedActivity != null) { lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); } Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null && lastFocusedRootTask.isTopRootTaskInDisplayArea()) { next.showStartingWindow(false /* taskSwitch */); } mTaskSupervisor.startSpecificActivity(next, true, false); return true; } next.completeResumeLocked(); } else { // Whoops, need to restart this activity! if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW) { next.showStartingWindow(false /* taskSwich */); } if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); } ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next); mTaskSupervisor.startSpecificActivity(next, true, true); } return true;}
复制代码 注意:
记得留意andResume这个参数,此处的值为true,代表的是LifecyclePath的finish状态,即:ActivityLifecycleItem.ON_RESUME.
2处的代码,如果任务栈顶的Activity是处于Resume状态,则先将其置于Pause状态。
代码1处ActivityTaskSupervisor对象调用startSpecificActivity方法启动Activity,源码如下:- void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? final WindowProcessController wpc = mService.getProcessController(r.processName, r.info.applicationInfo.uid); boolean knownToBeDead = false; if (wpc != null && wpc.hasThread()) { try { realStartActivityLocked(r, wpc, andResume, checkConfig); return; // 1 如果进程已经存在 } catch (RemoteException e) { Slog.w(TAG, "Exception when starting activity " + r.intent.getComponent().flattenToShortString(), e); } // If a dead object exception was thrown -- fall through to // restart the application. knownToBeDead = true; // Remove the process record so it won't be considered as alive. mService.mProcessNames.remove(wpc.mName, wpc.mUid); mService.mProcessMap.remove(wpc.getPid()); } else if (ActivityTaskManagerService.isSdkSandboxActivityIntent( mService.mContext, r.intent)) { Slog.e(TAG, "Abort sandbox activity launching as no sandbox process to host it."); r.finishIfPossible("No sandbox process for the activity", false /* oomAdj */); r.launchFailed = true; r.detachFromProcess(); return; } r.notifyUnknownVisibilityLaunchedForKeyguardTransition(); final boolean isTop = andResume && r.isTopRunningActivity(); mService.startProcessAsync(r, knownToBeDead, isTop, <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> : HostingRecord.HOSTING_TYPE_ACTIVITY); // 2}
复制代码 如果Activity所在的应用的进程已经存在,则执行代码1处的代码然后返回,否则执行代码2处的代码,fork新的进程。
代码2处mService是ActivityTaskManagerService类型的示例,调用了其startProcessAsync方法,其源码如下:- void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop, String hostingType) { if (!mStartingProcessActivities.contains(activity)) { mStartingProcessActivities.add(activity); // Let the activity with higher z-order be started first. if (mStartingProcessActivities.size() > 1) { mStartingProcessActivities.sort(null /* by WindowContainer#compareTo */); } } else if (mProcessNames.get( activity.processName, activity.info.applicationInfo.uid) != null) { // The process is already starting. Wait for it to attach. return; } try { if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:" <intent-filter>
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity> + activity.processName); } // Post message to start process to avoid possible deadlock of calling into AMS with the // ATMS lock held. final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess, mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead, isTop, hostingType, activity.intent.getComponent()); // 1 mH.sendMessage(m); // 2 } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); }}
复制代码 代码1处接口PooledLambda的obtainMessage静态方法源码如下:
[code]static Message obtainMessage( HeptConsumer |