FallbackHome的启动流程(android11)
首次开机开机动画播完进入Launcher桌面时黑屏进入Launcher,有黑屏不太美观,在重启以后会在进入桌面后会显示android正在启动等一会进入Launcher,这就是系统FallBackHome机制
接下来我们跟着代码看下首次启动系统如何进入FallbackHome的
在SystemServer的startOtherServices这个方法里他会调mActivityManagerService.systemReady这个方法,主要是执行了这里
第一次执行判断为true,这里会执行,之后调用ActivityTaskManagerInternal.startHomeOnAllDisplays,这是个抽象类,我们找到他的实现类,在ActivityTaskManagerService中有个
我们看下我们所需方法的实现
@Overridepublic boolean startHomeOnAllDisplays(int userId, String reason) {synchronized (mGlobalLock) {return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);}}
之后调用到RootWindowContainer.startHomeOnAllDisplays
接着调用startHomeOnDisplay和他的重载
接着调用了startHomeOnTaskDisplayArea
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,boolean allowInstrumenting, boolean fromHomeKey) {// Fallback to top focused display area if the provided one is invalid.if (taskDisplayArea == null) {final ActivityStack stack = getTopDisplayFocusedStack();taskDisplayArea = stack != null ? stack.getDisplayArea(): getDefaultTaskDisplayArea();}Intent homeIntent = null;ActivityInfo aInfo = null;if (taskDisplayArea == getDefaultTaskDisplayArea()) {//第一次会进入这里,我们下面看具体实现homeIntent = mService.getHomeIntent();aInfo = resolveHomeActivity(userId, homeIntent);} else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);aInfo = info.first;homeIntent = info.second;}if (aInfo == null || homeIntent == null) {return false;}if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea, allowInstrumenting)) {return false;}// Updates the home component of the intent.homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);// Updates the extra information of the intent.if (fromHomeKey) {homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity");}// Update the reason for ANR debugging to verify if the user activity is the one that// actually launched.final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId();
最后调用这里来启动activitymService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,taskDisplayArea);return true;}
之后调用到
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,TaskDisplayArea taskDisplayArea) {final ActivityOptions options = ActivityOptions.makeBasic();options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);if (!ActivityRecord.isResolverActivity(aInfo.name)) {// The resolver activity shouldn't be put in home stack because when the foreground is// standard type activity, the resolver activity should be put on the top of current// foreground instead of bring home stack to front.options.setLaunchActivityType(ACTIVITY_TYPE_HOME);}final int displayId = taskDisplayArea.getDisplayId();options.setLaunchDisplayId(displayId);options.setLaunchTaskDisplayArea(taskDisplayArea.mRemoteToken.toWindowContainerToken());// The home activity will be started later, defer resuming to avoid unneccerary operations// (e.g. start home recursively) when creating home stack.mSupervisor.beginDeferResume();final ActivityStack homeStack;try {// Make sure home stack exists on display area.homeStack = taskDisplayArea.getOrCreateRootHomeTask(ON_TOP);} finally {mSupervisor.endDeferResume();}mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason).setOutActivity(tmpOutRecord).setCallingUid(0).setActivityInfo(aInfo).setActivityOptions(options.toBundle()).execute();mLastHomeActivityStartRecord = tmpOutRecord[0];if (homeStack.mInResumeTopActivity) {// If we are in resume section already, home activity will be initialized, but not// resumed (to avoid recursive resume) and will stay that way until something pokes it// again. We need to schedule another resume.mSupervisor.scheduleResumeTopActivities();}}
这个是关键,我们看下obtainStarter这个方法
int execute() {try {// Refuse possible leaked file descriptorsif (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {throw new IllegalArgumentException("File descriptors passed in Intent");}final LaunchingState launchingState;synchronized (mService.mGlobalLock) {final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mRequest.intent, caller);}// 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);}int res;synchronized (mService.mGlobalLock) {final boolean globalConfigWillChange = mRequest.globalConfig != null&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();if (stack != null) {stack.mConfigWillChange = globalConfigWillChange;}if (DEBUG_CONFIGURATION) {Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "+ globalConfigWillChange);}final long origId = Binder.clearCallingIdentity();res = resolveToHeavyWeightSwitcherIfNeeded();if (res != START_SUCCESS) {return res;}res = executeRequest(mRequest);Binder.restoreCallingIdentity(origId);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 (stack != null) {stack.mConfigWillChange = false;}if (DEBUG_CONFIGURATION) {Slog.v(TAG_CONFIGURATION,"Updating to new configuration after starting activity.");}mService.updateConfigurationLocked(mRequest.globalConfig, null, false);}// 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,mLastStartActivityRecord);return getExternalResult(mRequest.waitResult == null ? res: waitForResult(res, mLastStartActivityRecord));}} finally {onExecutionComplete();}}
主要方法是
之后调用了
private int executeRequest(Request request) {if (TextUtils.isEmpty(request.reason)) {throw new IllegalArgumentException("Need to specify a reason.");}mLastStartReason = request.reason;mLastStartActivityTimeMs = System.currentTimeMillis();mLastStartActivityRecord = null;final IApplicationThread caller = request.caller;Intent intent = request.intent;NeededUriGrants intentGrants = request.intentGrants;String resolvedType = request.resolvedType;ActivityInfo aInfo = request.activityInfo;ResolveInfo rInfo = request.resolveInfo;final IVoiceInteractionSession voiceSession = request.voiceSession;final IBinder resultTo = request.resultTo;String resultWho = request.resultWho;int requestCode = request.requestCode;int callingPid = request.callingPid;int callingUid = request.callingUid;String callingPackage = request.callingPackage;String callingFeatureId = request.callingFeatureId;final int realCallingPid = request.realCallingPid;final int realCallingUid = request.realCallingUid;final int startFlags = request.startFlags;final SafeActivityOptions options = request.activityOptions;Task inTask = request.inTask;int err = ActivityManager.START_SUCCESS;// Pull the optional Ephemeral Installer-only bundle out of the options early.final Bundle verificationBundle =options != null ? options.popAppVerificationBundle() : null;WindowProcessController callerApp = null;if (caller != null) {callerApp = mService.getProcessController(caller);if (callerApp != null) {callingPid = callerApp.getPid();callingUid = callerApp.mInfo.uid;} else {Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid+ ") when starting: " + intent.toString());err = ActivityManager.START_PERMISSION_DENIED;}}final int userId = aInfo != null && aInfo.applicationInfo != null? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;if (err == ActivityManager.START_SUCCESS) {Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)+ "} from uid " + callingUid);}ActivityRecord sourceRecord = null;ActivityRecord resultRecord = null;if (resultTo != null) {sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);if (DEBUG_RESULTS) {Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);}if (sourceRecord != null) {if (requestCode >= 0 && !sourceRecord.finishing) {resultRecord = sourceRecord;}}}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) {SafeActivityOptions.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);}if (sourceRecord.launchedFromUid == callingUid) {// The new activity is being launched from the same uid as the previous activity// in the flow, and asking to forward its result back to the previous. In this// case the activity is serving as a trampoline between the two, so we also want// to update its launchedFromPackage to be the same as the previous activity.// Note that this is safe, since we know these two packages come from the same// uid; the caller could just as well have supplied that same package name itself// . This specifially deals with the case of an intent picker/chooser being// launched in the app flow to redirect to an activity picked by the user, where// we want the final activity to consider it to have been launched by the// previous app activity.callingPackage = sourceRecord.launchedFromPackage;callingFeatureId = sourceRecord.launchedFromFeatureId;}}if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {// We couldn't find a class that can handle the given Intent.// That's the end of that!err = ActivityManager.START_INTENT_NOT_RESOLVED;}if (err == ActivityManager.START_SUCCESS && aInfo == null) {// We couldn't find the specific class specified in the Intent.// Also the end of the line.err = ActivityManager.START_CLASS_NOT_FOUND;}if (err == ActivityManager.START_SUCCESS && sourceRecord != null&& sourceRecord.getTask().voiceSession != null) {// If this activity is being launched as part of a voice session, we need to ensure// that it is safe to do so. If the upcoming activity will also be part of the voice// session, we can only launch it if it has explicitly said it supports the VOICE// category, or it is a part of the calling app.if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {try {intent.addCategory(Intent.CATEGORY_VOICE);if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(), intent, resolvedType)) {Slog.w(TAG, "Activity being started in current voice task does not support "+ "voice: " + intent);err = ActivityManager.START_NOT_VOICE_COMPATIBLE;}} catch (RemoteException e) {Slog.w(TAG, "Failure checking voice capabilities", e);err = ActivityManager.START_NOT_VOICE_COMPATIBLE;}}}if (err == ActivityManager.START_SUCCESS && voiceSession != null) {// If the caller is starting a new voice session, just make sure the target// is actually allowing it to run this way.try {if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),intent, resolvedType)) {Slog.w(TAG,"Activity being started in new voice task does not support: " + intent);err = ActivityManager.START_NOT_VOICE_COMPATIBLE;}} catch (RemoteException e) {Slog.w(TAG, "Failure checking voice capabilities", e);err = ActivityManager.START_NOT_VOICE_COMPATIBLE;}}final ActivityStack resultStack = resultRecord == null? null : resultRecord.getRootTask();if (err != START_SUCCESS) {if (resultRecord != null) {resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,null /* data */, null /* dataGrants */);}SafeActivityOptions.abort(options);return err;}boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,requestCode, callingPid, callingUid, callingPackage, callingFeatureId,request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord, resultStack);abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,callingPid, resolvedType, aInfo.applicationInfo);abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,callingPackage);boolean restrictedBgActivity = false;if (!abort) {try {Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,"shouldAbortBackgroundActivityStart");restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,request.originatingPendingIntent, request.allowBackgroundActivityStart,intent);} finally {Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);}}// Merge the two options bundles, while realCallerOptions takes precedence.ActivityOptions checkedOptions = options != null? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;if (request.allowPendingRemoteAnimationRegistryLookup) {checkedOptions = mService.getActivityStartController().getPendingRemoteAnimationRegistry().overrideOptionsIfNeeded(callingPackage, checkedOptions);}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,callingFeatureId);if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,callingUid, checkedOptions)) {// activity start was intercepted, e.g. because the target user is currently in quiet// mode (turn off work) or the target application is suspendedintent = mInterceptor.mIntent;rInfo = mInterceptor.mRInfo;aInfo = mInterceptor.mAInfo;resolvedType = mInterceptor.mResolvedType;inTask = mInterceptor.mInTask;callingPid = mInterceptor.mCallingPid;callingUid = mInterceptor.mCallingUid;checkedOptions = mInterceptor.mActivityOptions;// The interception target shouldn't get any permission grants// intended for the original destinationintentGrants = null;}if (abort) {if (resultRecord != null) {resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,null /* data */, null /* dataGrants */);}// We pretend to the caller that it was really started, but they will just get a// cancel result.ActivityOptions.abort(checkedOptions);return START_ABORTED;}// 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 (aInfo != null) {if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(aInfo.packageName, userId)) {final IIntentSender target = mService.getIntentSenderLocked(ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,callingUid, userId, null, null, 0, new Intent[]{intent},new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT| PendingIntent.FLAG_ONE_SHOT, null);Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);int flags = intent.getFlags();flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;/** Prevent reuse of review activity: Each app needs their own review activity. By* default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities* with the same launch parameters (extras are ignored). Hence to avoid possible* reuse force a new activity via the MULTIPLE_TASK flag.** Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used,* hence no need to add the flag in this case.*/if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;}newIntent.setFlags(flags);newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));if (resultRecord != null) {newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);}intent = newIntent;// The permissions review target shouldn't get any permission// grants intended for the original destinationintentGrants = null;resolvedType = null;callingUid = realCallingUid;callingPid = realCallingPid;rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,computeResolveFilterUid(callingUid, realCallingUid, request.filterCallingUid));aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,null /*profilerInfo*/);if (DEBUG_PERMISSIONS_REVIEW) {final ActivityStack focusedStack =mRootWindowContainer.getTopDisplayFocusedStack();Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,true, false) + "} from uid " + callingUid + " on display "+ (focusedStack == null ? DEFAULT_DISPLAY: focusedStack.getDisplayId()));}}}// If we have an ephemeral app, abort the process of launching the resolved intent.// Instead, launch the ephemeral installer. Once the installer is finished, it// starts either the intent we resolved here [on install error] or the ephemeral// app [on install success].if (rInfo != null && rInfo.auxiliaryInfo != null) {intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);resolvedType = null;callingUid = realCallingUid;callingPid = realCallingPid;// The ephemeral installer shouldn't get any permission grants// intended for the original destinationintentGrants = null;aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);}final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,callingPackage, callingFeatureId, intent, resolvedType, aInfo,mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,sourceRecord);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;}final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();// If we are starting an activity that is not from the same uid as the currently resumed// one, check whether app switches are allowed.if (voiceSession == null && stack != null && (stack.getResumedActivity() == null|| stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,realCallingPid, realCallingUid, "Activity start")) {if (!(restrictedBgActivity && handleBackgroundActivityAbort(r))) {mController.addPendingActivityLaunch(new PendingActivityLaunch(r,sourceRecord, startFlags, stack, callerApp, intentGrants));}ActivityOptions.abort(checkedOptions);return ActivityManager.START_SWITCHES_CANCELED;}}mService.onStartActivitySetDidAppSwitch();mController.doPendingActivityLaunches(false);mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,restrictedBgActivity, intentGrants);if (request.outActivity != null) {request.outActivity[0] = mLastStartActivityRecord;}return mLastStartActivityResult;}
之后调用了startActivityUnchecked
之后调用到startActivityInner里面的
调用resumeFocusedStacksTopActivities,之后调用
boolean resumeFocusedStacksTopActivities() {return resumeFocusedStacksTopActivities(null, null, null);}boolean resumeFocusedStacksTopActivities(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {if (!mStackSupervisor.readyToResume()) {return false;}boolean result = false;if (targetStack != null && (targetStack.isTopStackInDisplayArea()|| getTopDisplayFocusedStack() == targetStack)) {result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);}for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {final DisplayContent display = getChildAt(displayNdx);boolean resumedOnDisplay = false;for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);final ActivityRecord topRunningActivity = stack.topRunningActivity();if (!stack.isFocusableAndVisible() || topRunningActivity == null) {continue;}if (stack == targetStack) {// Simply update the result for targetStack because the targetStack 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 |= result;continue;}if (taskDisplayArea.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {// Kick off any lingering app transitions form the MoveTaskToFront// operation, but only consider the top task and stack on that display.stack.executeAppTransition(targetOptions);} else {resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);}}}if (!resumedOnDisplay) {// 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 stack explicitly will make sure that at least home// activity is started and resumed, and no recursion occurs.final ActivityStack focusedStack = display.getFocusedStack();if (focusedStack != null) {result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);} else if (targetStack == null) {result |= resumeHomeActivity(null /* prev */, "no-focusable-task",display.getDefaultTaskDisplayArea());}}}return result;}
之后调用了resumeTopActivityUncheckedLocked方法
这里调用了resumeTopActivityInnerLocked这个方法
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {// 检查系统是否已经完成启动,如果未完成,则不允许恢复 Activityif (!mAtmService.isBooting() && !mAtmService.isBooted()) {// 系统未准备好,直接返回 falsereturn false;}// 查找栈顶可聚焦且未结束的 ActivityActivityRecord next = topRunningActivity(true /* focusableOnly */);// 检查是否存在正在运行的 Activityfinal boolean hasRunningActivity = next != null;// TODO: 可能需要移除这个条件if (hasRunningActivity && !isAttached()) {return false;}// 取消所有正在初始化的 ActivitymRootWindowContainer.cancelInitializingActivities();// 记录当前的用户离开状态,并重置标志位boolean userLeaving = mStackSupervisor.mUserLeaving;mStackSupervisor.mUserLeaving = false;// 如果栈中没有 Activity,则尝试恢复下一个可聚焦的 Activityif (!hasRunningActivity) {return resumeNextFocusableActivityWhenStackIsEmpty(prev, options);}// 重置延迟恢复标志next.delayedResume = false;// 获取当前任务显示区域final TaskDisplayArea taskDisplayArea = getDisplayArea();// 如果栈顶 Activity 已经是 resumed 状态,则无需处理if (mResumedActivity == next && next.isState(RESUMED)&& taskDisplayArea.allResumedActivitiesComplete()) {// 执行未完成的过渡动画executeAppTransition(options);if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Top activity resumed " + next);return false;}// 检查 Activity 是否可以通过兼容性检查恢复if (!next.canResumeByCompat()) {return false;}// 检查是否有 Activity 正在暂停,如果有则等待暂停完成final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();if (!allPausedComplete) {if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) {Slog.v(TAG_PAUSE, "resumeTopActivityLocked: Skip resume: some activity pausing.");}return false;}// 如果系统处于睡眠状态,并且栈顶 Activity 已暂停,则无需恢复if (shouldSleepOrShutDownActivities()&& mLastPausedActivity == next&& mRootWindowContainer.allPausedActivitiesComplete()) {boolean nothingToResume = true;if (!mAtmService.mShuttingDown) {// 检查 Activity 是否可以显示在锁屏上或是否可以解锁屏幕final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard&& next.canShowWhenLocked();final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next&& next.containsDismissKeyguardWindow();if (canShowWhenLocked || mayDismissKeyguard) {ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,!PRESERVE_WINDOWS);nothingToResume = shouldSleepActivities();} else if (next.currentLaunchCanTurnScreenOn() && next.canTurnScreenOn()) {nothingToResume = false;}}if (nothingToResume) {// 执行未完成的过渡动画executeAppTransition(options);if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Going to sleep and all paused");return false;}}// 检查 Activity 所属用户是否已启动,如果未启动则不允许恢复if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {Slog.w(TAG, "Skipping resume of top activity " + next+ ": user " + next.mUserId + " is stopped");return false;}// 从停止列表中移除该 Activity,并重置睡眠状态mStackSupervisor.mStoppingActivities.remove(next);next.setSleeping(false);if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);// 再次检查是否有 Activity 正在暂停,如果有则等待暂停完成if (!mRootWindowContainer.allPausedActivitiesComplete()) {if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,"resumeTopActivityLocked: Skip resume: some activity pausing.");return false;}// 设置启动来源mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);// 获取上一个 resumed 的 ActivityActivityRecord lastResumed = null;final ActivityStack lastFocusedStack = taskDisplayArea.getLastFocusedStack();if (lastFocusedStack != null && lastFocusedStack != this) {lastResumed = lastFocusedStack.mResumedActivity;if (userLeaving && inMultiWindowMode() && lastFocusedStack.shouldBeVisible(next)) {// 如果处于多窗口模式且上一个栈应该可见,则重置用户离开标志userLeaving = false;}}// 暂停其他栈的 Activityboolean pausing = taskDisplayArea.pauseBackStacks(userLeaving, next);if (mResumedActivity != null) {// 如果当前有 resumed 的 Activity,则暂停它pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next);}if (pausing) {if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,"resumeTopActivityLocked: Skip resume: need to start pausing");// 如果 Activity 已附加到进程,则更新进程信息if (next.attachedToProcess()) {next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,true /* activityChange */, false /* updateOomAdj */,false /* addPendingTopUid */);} else if (!next.isProcessRunning()) {// 如果进程未运行,则异步启动进程final boolean isTop = this == taskDisplayArea.getFocusedStack();mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,isTop ? "pre-top-activity" : "pre-activity");}if (lastResumed != null) {lastResumed.setWillCloseOrEnterPip(true);}return true;} else if (mResumedActivity == next && next.isState(RESUMED)&& taskDisplayArea.allResumedActivitiesComplete()) {// 如果 Activity 已经是 resumed 状态,则执行未完成的过渡动画executeAppTransition(options);if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next);return true;}// 如果上一个 Activity 是 noHistory 且未结束,则结束它if (shouldSleepActivities() && mLastNoHistoryActivity != null&& !mLastNoHistoryActivity.finishing&& mLastNoHistoryActivity != next) {mLastNoHistoryActivity.finishIfPossible("resume-no-history", false /* oomAdj */);mLastNoHistoryActivity = null;}// 如果上一个 Activity 正在结束且下一个 Activity 已可见,则立即隐藏上一个 Activityif (prev != null && prev != next && next.nowVisible) {if (prev.finishing) {prev.setVisibility(false);}}// 确保应用不再处于停止状态try {mAtmService.getPackageManager().setPackageStoppedState(next.packageName, false, next.mUserId);} catch (RemoteException e1) {} catch (IllegalArgumentException e) {Slog.w(TAG, "Failed trying to unstop package "+ next.packageName + ": " + e);}// 准备过渡动画boolean anim = true;final DisplayContent dc = taskDisplayArea.mDisplayContent;if (prev != null) {if (prev.finishing) {if (mStackSupervisor.mNoAnimActivities.contains(prev)) {anim = false;dc.prepareAppTransition(TRANSIT_NONE, false);} else {dc.prepareAppTransition(prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_CLOSE: TRANSIT_TASK_CLOSE, false);}prev.setVisibility(false);} else {if (mStackSupervisor.mNoAnimActivities.contains(next)) {anim = false;dc.prepareAppTransition(TRANSIT_NONE, false);} else {dc.prepareAppTransition(prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_OPEN: next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND: TRANSIT_TASK_OPEN, false);}}} else {if (mStackSupervisor.mNoAnimActivities.contains(next)) {anim = false;dc.prepareAppTransition(TRANSIT_NONE, false);} else {dc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);}}// 应用或清除 Activity 的选项if (anim) {next.applyOptionsLocked();} else {next.clearOptionsLocked();}// 清除无动画 Activity 列表mStackSupervisor.mNoAnimActivities.clear();// 如果 Activity 已附加到进程,则恢复它if (next.attachedToProcess()) {// 设置 Activity 为可见状态if (!next.mVisibleRequested || next.stopped) {next.setVisibility(true);}// 启动延迟统计next.startLaunchTickingLocked();// 更新 CPU 统计信息mAtmService.updateCpuStats();// 将 Activity 状态设置为 RESUMEDnext.setState(RESUMED, "resumeTopActivityInnerLocked");// 更新进程信息next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,true /* activityChange */, true /* updateOomAdj */,true /* addPendingTopUid */);// 确保 Activity 可见并更新配置boolean notUpdated = true;if (shouldBeVisible(next)) {notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(),true /* markFrozenIfConfigChanged */, false /* deferResume */);}// 如果配置更新失败,则重新调度恢复if (notUpdated) {ActivityRecord nextNext = topRunningActivity();if (nextNext != next) {mStackSupervisor.scheduleResumeTopActivities();}if (!next.mVisibleRequested || next.stopped) {next.setVisibility(true);}next.completeResumeLocked();return true;}// 创建并执行恢复事务try {final ClientTransaction transaction =ClientTransaction.obtain(next.app.getThread(), next.appToken);// 传递所有未完成的结果if (next.results != null) {transaction.addCallback(ActivityResultItem.obtain(next.results));}// 传递新的 Intentif (next.newIntents != null) {transaction.addCallback(NewIntentItem.obtain(next.newIntents, true /* resume */));}// 通知应用已恢复next.notifyAppResumed(next.stopped);// 记录日志EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),next.getTask().mTaskId, next.shortComponentName);// 设置生命周期状态transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(next.app.getReportedProcState(),dc.isNextTransitionForward()));mAtmService.getLifecycleManager().scheduleTransaction(transaction);if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + next);} catch (Exception e) {// 如果恢复失败,则重置状态并重启 Activitynext.setState(lastState, "resumeTopActivityInnerLocked");if (lastResumed != null) {lastResumed.setState(RESUMED, "resumeTopActivityInnerLocked");}Slog.i(TAG, "Restarting because process died: " + next);if (!next.hasBeenLaunched) {next.hasBeenLaunched = true;} else if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null&& lastFocusedStack.isTopStackInDisplayArea()) {next.showStartingWindow(null /* prev */, false /* newTask */,false /* taskSwitch */);}mStackSupervisor.startSpecificActivity(next, true, false);return true;}// 完成恢复try {next.completeResumeLocked();} catch (Exception e) {Slog.w(TAG, "Exception thrown during resume of " + next, e);next.finishIfPossible("resume-exception", true /* oomAdj */);return true;}} else {// 如果 Activity 未附加到进程,则启动它if (!next.hasBeenLaunched) {next.hasBeenLaunched = true;} else {if (SHOW_APP_STARTING_PREVIEW) {next.showStartingWindow(null /* prev */, false /* newTask */,false /* taskSwitch */);}if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);}if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);mStackSupervisor.startSpecificActivity(next, true, true);}return true;
}
最后调用了 mStackSupervisor.startSpecificActivity(next, true, true);
之后调用了
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
之后调用
在这里启动了ActivityManagerInternal::startProcess,这和类是抽象类
接着调用到
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,boolean mountExtStorageFull, String abiOverride) {if (app.pendingStart) {return true;}long startTime = SystemClock.uptimeMillis();if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {checkSlow(startTime, "startProcess: removing from pids map");mService.removePidLocked(app);app.bindMountPending = false;mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);checkSlow(startTime, "startProcess: done removing from pids map");app.setPid(0);app.startSeq = 0;}if (DEBUG_PROCESSES && mService.mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,"startProcessLocked removing on hold: " + app);mService.mProcessesOnHold.remove(app);checkSlow(startTime, "startProcess: starting to update cpu stats");mService.updateCpuStats();checkSlow(startTime, "startProcess: done updating cpu stats");try {try {final int userId = UserHandle.getUserId(app.uid);AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);} catch (RemoteException e) {throw e.rethrowAsRuntimeException();}int uid = app.uid;int[] gids = null;int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;if (!app.isolated) {int[] permGids = null;try {checkSlow(startTime, "startProcess: getting gids from package manager");final IPackageManager pm = AppGlobals.getPackageManager();permGids = pm.getPackageGids(app.info.packageName,MATCH_DIRECT_BOOT_AUTO, app.userId);if (StorageManager.hasIsolatedStorage() && mountExtStorageFull) {mountExternal = Zygote.MOUNT_EXTERNAL_FULL;} else {StorageManagerInternal storageManagerInternal = LocalServices.getService(StorageManagerInternal.class);mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,app.info.packageName);}} catch (RemoteException e) {throw e.rethrowAsRuntimeException();}// Remove any gids needed if the process has been denied permissions.// NOTE: eventually we should probably have the package manager pre-compute// this for us?if (app.processInfo != null && app.processInfo.deniedPermissions != null) {for (int i = app.processInfo.deniedPermissions.size() - 1; i >= 0; i--) {int[] denyGids = mService.mPackageManagerInt.getPermissionGids(app.processInfo.deniedPermissions.valueAt(i), app.userId);if (denyGids != null) {for (int gid : denyGids) {permGids = ArrayUtils.removeInt(permGids, gid);}}}}gids = computeGidsForProcess(mountExternal, uid, permGids);}app.mountMode = mountExternal;checkSlow(startTime, "startProcess: building args");if (mService.mAtmInternal.isFactoryTestProcess(app.getWindowProcessController())) {uid = 0;}int runtimeFlags = 0;if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;runtimeFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;// Also turn on CheckJNI for debuggable apps. It's quite// awkward to turn on otherwise.runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;// Check if the developer does not want ART verificationif (android.provider.Settings.Global.getInt(mService.mContext.getContentResolver(),android.provider.Settings.Global.ART_VERIFIER_VERIFY_DEBUGGABLE, 1) == 0) {runtimeFlags |= Zygote.DISABLE_VERIFIER;Slog.w(TAG_PROCESSES, app + ": ART verification disabled");}}// Run the app in safe mode if its manifest requests so or the// system is booted in safe mode.if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 || mService.mSafeMode) {runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;}if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0) {runtimeFlags |= Zygote.PROFILE_FROM_SHELL;}if ("1".equals(SystemProperties.get("debug.checkjni"))) {runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;}String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");if ("1".equals(genDebugInfoProperty) || "true".equals(genDebugInfoProperty)) {runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;}String genMiniDebugInfoProperty = SystemProperties.get("dalvik.vm.minidebuginfo");if ("1".equals(genMiniDebugInfoProperty) || "true".equals(genMiniDebugInfoProperty)) {runtimeFlags |= Zygote.DEBUG_GENERATE_MINI_DEBUG_INFO;}if ("1".equals(SystemProperties.get("debug.jni.logging"))) {runtimeFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;}if ("1".equals(SystemProperties.get("debug.assert"))) {runtimeFlags |= Zygote.DEBUG_ENABLE_ASSERT;}if ("1".equals(SystemProperties.get("debug.ignoreappsignalhandler"))) {runtimeFlags |= Zygote.DEBUG_IGNORE_APP_SIGNAL_HANDLER;}if (mService.mNativeDebuggingApp != null&& mService.mNativeDebuggingApp.equals(app.processName)) {// Enable all debug flags required by the native debugger.runtimeFlags |= Zygote.DEBUG_ALWAYS_JIT; // Don't interpret anythingruntimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug inforuntimeFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // Disbale optimizationsmService.mNativeDebuggingApp = null;}if (app.info.isEmbeddedDexUsed()|| (app.info.isPrivilegedApp()&& DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet()))) {runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;}if (!disableHiddenApiChecks && !mService.mHiddenApiBlacklist.isDisabled()) {app.info.maybeUpdateHiddenApiEnforcementPolicy(mService.mHiddenApiBlacklist.getPolicy());@ApplicationInfo.HiddenApiEnforcementPolicy int policy =app.info.getHiddenApiEnforcementPolicy();int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {throw new IllegalStateException("Invalid API policy: " + policy);}runtimeFlags |= policyBits;if (disableTestApiChecks) {runtimeFlags |= Zygote.DISABLE_TEST_API_ENFORCEMENT_POLICY;}}String useAppImageCache = SystemProperties.get(PROPERTY_USE_APP_IMAGE_STARTUP_CACHE, "");// Property defaults to true currently.if (!TextUtils.isEmpty(useAppImageCache) && !useAppImageCache.equals("false")) {runtimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE;}runtimeFlags |= decideGwpAsanLevel(app);String invokeWith = null;if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {// Debuggable apps may include a wrapper script with their library directory.String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();try {if (new File(wrapperFileName).exists()) {invokeWith = "/system/bin/logwrapper " + wrapperFileName;}} finally {StrictMode.setThreadPolicy(oldPolicy);}}String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;if (requiredAbi == null) {requiredAbi = Build.SUPPORTED_ABIS[0];}String instructionSet = null;if (app.info.primaryCpuAbi != null) {instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);}app.gids = gids;app.setRequiredAbi(requiredAbi);app.instructionSet = instructionSet;// If instructionSet is non-null, this indicates that the system_server is spawning a// process with an ISA that may be different from its own. System (kernel and hardware)// compatililty for these features is checked in the decideTaggingLevel in the// system_server process (not the child process). As TBI is only supported in aarch64,// we can simply ensure that the new process is also aarch64. This prevents the mismatch// where a 64-bit system server spawns a 32-bit child that thinks it should enable some// tagging variant. Theoretically, a 32-bit system server could exist that spawns 64-bit// processes, in which case the new process won't get any tagging. This is fine as we// haven't seen this configuration in practice, and we can reasonable assume that if// tagging is desired, the system server will be 64-bit.if (instructionSet == null || instructionSet.equals("arm64")) {runtimeFlags |= decideTaggingLevel(app);}// the per-user SELinux context must be setif (TextUtils.isEmpty(app.info.seInfoUser)) {Slog.wtf(ActivityManagerService.TAG, "SELinux tag not defined",new IllegalStateException("SELinux tag not defined for "+ app.info.packageName + " (uid " + app.uid + ")"));}final String seInfo = app.info.seInfo+ (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);// Start the process. It will either succeed and return a result containing// the PID of the new process, or else throw a RuntimeException.final String entryPoint = "android.app.ActivityThread";return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,instructionSet, invokeWith, startTime);} catch (RuntimeException e) {Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e);// Something went very wrong while trying to start this process; one// common case is when the package is frozen due to an active// upgrade. To recover, clean up any active bookkeeping related to// starting this process. (We already invoked this method once when// the package was initially frozen through KILL_APPLICATION_MSG, so// it doesn't hurt to use it again.)mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),false, false, true, false, false, app.userId, "start failure");return false;}}
之后通过
启动了进程,
之后调用了
最后调用到
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {try {final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;zygoteWriter.write(msgStr);zygoteWriter.flush();// Always read the entire result from the input stream to avoid leaving// bytes in the stream for future process starts to accidentally stumble// upon.Process.ProcessStartResult result = new Process.ProcessStartResult();result.pid = zygoteInputStream.readInt();result.usingWrapper = zygoteInputStream.readBoolean();if (result.pid < 0) {throw new ZygoteStartFailedEx("fork() failed");}return result;} catch (IOException ex) {zygoteState.close();Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "+ ex.toString());throw new ZygoteStartFailedEx(ex);}}
zygoteState是在
之后调用了
其中 public static final String PRIMARY_SOCKET_NAME = "zygote";这是她通信的Sccket名称
我们找下服务端在哪里
这里在ZygoteInit.java这个类
主要执行了
之后调用了
接着调用
之后就fork出进程
在fork成功后会执行
fork成功会pid==0
执行了 return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
之后执行
这里对app进行了初始化