🤔startActivity到底发生了什么(二)
startActivity到底发生了什么(二)
启动另外一个应用的MainActivity
<activity
	android:name=".activity.MainActivity"
	android:exported="true">
	<intent-filter>
		<action android:name="android.intent.action.MAIN" />
		<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,
						   "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)
							  && 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,
																		  newActivityCreated, launchingRecord, originalOptions);
			if (mRequest.waitResult != null) {
				mRequest.waitResult.result = res;
				res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
										 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,
													  request.voiceInteractor, startFlags, checkedOptions,
													  inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid, transition,
													  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,
														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
@VisibleForTesting
int 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,
								  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
									|| 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,
																			  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,
											  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,
																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,
									   UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
									   resultToUid /*visible*/, true /*direct*/);
	} else if (mStartActivity.mShareIdentity) {
		final PackageManagerInternal pmInternal =
			mService.getPackageManagerInternalLocked();
		pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
									   UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
									   r.launchedFromUid /*visible*/, true /*direct*/);
	}
	final Task startedTask = mStartActivity.getTask();
	if (newTask) {
		EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId,
									   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,
										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,
											   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,
														  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()
								   || getTopDisplayFocusedRootTask() == targetRootTask)) {
		result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
																 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",
											 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) {
						// Skip the task if no running activity and continue resuming next task.
						continue;
					}
					// Otherwise, assuming everything behind this task should also be invisible.
					break;
				}
				someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
																			  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 */,
								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 */,
									   true /* activityChange */, false /* updateOomAdj */,
									   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,
										  isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_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,
										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,
														   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<ResultInfo> a = next.results;
			if (a != null) {
				final int size = a.size();
				if (!next.finishing && size > 0) {
					if (DEBUG_RESULTS) {
						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),
											   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,
							   isTop ? HostingRecord.HOSTING_TYPE_TOP_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:"
							 + 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静态方法源码如下:
static <A, B, C, D, E, F, G> Message obtainMessage(
	HeptConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
	? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
	synchronized (Message.sPoolSync) {
		PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, null, null, null, null); // 1
		return Message.obtain().setCallback(callback.recycleOnUse());
	}
}
查看代码1处acquire方法,他是PooledLambdaImpl的静态方法,其源码如下:
static <E extends PooledLambda> E acquire(Pool pool, Object func, int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k,  Object l) {
	PooledLambdaImpl r = acquire(pool);
	if (DEBUG) {
		Log.i(LOG_TAG,
			  "acquire(this = @" + hashCodeHex(r)
			  + ", func = " + func
			  + ", fNumArgs = " + fNumArgs
			  + ", numPlaceholders = " + numPlaceholders
			  + ", fReturnType = " + LambdaType.ReturnType.toString(fReturnType)
			  + ", a = " + a
			  + ", b = " + b
			  + ", c = " + c
			  + ", d = " + d
			  + ", e = " + e
			  + ", f = " + f
			  + ", g = " + g
			  + ", h = " + h
			  + ", i = " + i
			  + ", j = " + j
			  + ", k = " + k
			  + ", l = " + l
			  + ")");
	}
	r.mFunc = Objects.requireNonNull(func);
	r.setFlags(MASK_FUNC_TYPE, LambdaType.encode(fNumArgs, fReturnType)); // 2
	r.setFlags(MASK_EXPOSED_AS, LambdaType.encode(numPlaceholders, fReturnType));
	if (ArrayUtils.size(r.mArgs) < fNumArgs) r.mArgs = new Object[fNumArgs];
	setIfInBounds(r.mArgs, 0, a);
	setIfInBounds(r.mArgs, 1, b);
	setIfInBounds(r.mArgs, 2, c);
	setIfInBounds(r.mArgs, 3, d);
	setIfInBounds(r.mArgs, 4, e);
	setIfInBounds(r.mArgs, 5, f);
	setIfInBounds(r.mArgs, 6, g);
	setIfInBounds(r.mArgs, 7, h);
	setIfInBounds(r.mArgs, 8, i);
	setIfInBounds(r.mArgs, 9, j);
	setIfInBounds(r.mArgs, 10, k);
	setIfInBounds(r.mArgs, 11, l);
	return (E) r;
}
static PooledLambdaImpl acquire(Pool pool) {
	PooledLambdaImpl r = pool.acquire();
	if (r == null) r = new PooledLambdaImpl();
	r.mFlags &= ~FLAG_RECYCLED;
	r.setFlags(FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL,
			   pool == sMessageCallbacksPool ? 1 : 0);
	return r;
}
可以看到其将所有参数传递给了PooledLambdaImpl示例r.PooledLambdaImpl实现了抽象类OmniFunction,OmniFunction又继承了PooledRunnable接口.
代码Message.obtain().setCallback(callback.recycleOnUse());表明handler在sendMesssage的时候会通过下面的代码1处回调recycleOnUse方法,其返回PooledRunnable接口,PooledRunnable接口又实现Runnable方法,接着执行Runnale方法的run方法,接着就是要看run方法做了什么。
public void dispatchMessage(@NonNull Message msg) {
	if (msg.callback != null) {
		handleCallback(msg); // 1
	} else {
		if (mCallback != null) {
			if (mCallback.handleMessage(msg)) {
				return;
			}
		}
		handleMessage(msg);
	}
}
run方法是如何实现的呢?首先查看PooledLambdaImpl的父类OmniFunction实现了run方法,其调用了一个抽象方法invoke如下:
@Override
public void run() {
	invoke(null, null, null, null, null, null, null, null, null, null, null);
}
abstract R invoke(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k);
PooledLambdaImpl实现了invoke方法
@Override
R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7,
		 Object a8, Object a9, Object a10, Object a11) {
	checkNotRecycled();
	if (DEBUG) {
		Log.i(LOG_TAG, this + ".invoke("
			  + commaSeparateFirstN(
				  new Object[] { a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 },
				  LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS)))
			  + ")");
	}
	final boolean notUsed = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4)
		&& fillInArg(a5) && fillInArg(a6) && fillInArg(a7) && fillInArg(a8)
		&& fillInArg(a9) && fillInArg(a10) && fillInArg(a11);
	int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE));
	if (argCount != LambdaType.MASK_ARG_COUNT) {
		for (int i = 0; i < argCount; i++) {
			if (mArgs[i] == ArgumentPlaceholder.INSTANCE) {
				throw new IllegalStateException("Missing argument #" + i + " among "
												+ Arrays.toString(mArgs));
			}
		}
	}
	try {
		return doInvoke();
	} finally {
		if (isRecycleOnUse()) {
			doRecycle();
		} else if (!isRecycled()) {
			int argsSize = ArrayUtils.size(mArgs);
			for (int i = 0; i < argsSize; i++) {
				popArg(i);
			}
		}
	}
}
接着执行doInvoke()方法的case7分支,最终完成run方法的执行。
整个对象池就是复用对象,减少GC。最后mFunc就是ActivityManagerInternal::startProcess其源码如下:
/** Starts a given process. */
public abstract void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName);
代码2处发出了一个开启新进程的message,mH是ActivityTaskManagerService的内部类H.其mH.sendMessage(m); // 2,会触发run方法执行,然后通过一个特殊的机制,来进行调用。
编译时,像 ActivityManagerInternal::startProcess 这样的 方法引用 在字节码里会用 invokedynamic 指令(bootstrap 到 LambdaMetafactory)。运行时 JVM 会生成/返回一个实现 HeptConsumer 的对象,这个对象“绑定”了目标方法句柄(MethodHandle):
概念性示例(伪代码)——你不会在 classfile 里看到这个,但有助理解:
// 运行时生成的类(伪)
final class $Lambda$... implements HeptConsumer {
    private final MethodHandle target; // 指向 ActivityManagerInternal.startProcess
    $Lambda$(MethodHandle mh) { this.target = mh; }
    public void accept(Object a0, Object a1, ..., Object a6) {
        try {
            // 通过 MethodHandle 调用目标。不是 java.lang.reflect.Method.invoke。
            target.invokeExact(a0, a1, ..., a6);
        } catch (Throwable t) { throw new RuntimeException(t); }
    }
}
target.invokeExact(...)(或 invoke)是 java.lang.invoke.MethodHandle 的调用形式,不是反射 Method.invoke。
invokeExact/invoke 的调用语义由 java.lang.invoke 和 JIT 优化器支持,通常比反射快很多,并且在合适的条件下可以被内联。
obtainMessage 中传入的是 ActivityManagerInternal::startProcess(未绑定的实例方法引用)并把 mAmInternal 作为第一个参数传入 PooledLambda:
这种情况是“未绑定的实例方法引用(unbound)”,函数式接口期望第一个参数是 receiver(即调用目标对象)。
所以 HeptConsumer 的第一个参数恰好是 ActivityManagerInternal 实例,后面 6 个是 startProcess 的真实参数。doInvoke() 通过 popArg(0..6) 把这些参数传给 accept,合成实现再把它们传到真实 startProcess。
这特殊的机制相比于反射,性能更高,并且可以被JIT优化。不过真TN绕。
在ActivityTaskManagerService的startProcessAsync方法代码1处,第一个参数中的ActivityManagerInternal是抽象类,第二个参数mAmInternal被赋值通过mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
LocalServices有个ArrayMap类型的成员变量key是类类型,value是实例,ActivityManagerInternal是在ActivityManagerService在onStart时添加的
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private void start() {
	mBatteryStatsService.publish();
	mAppOpsService.publish();
	mProcessStats.publish();
	Slog.d("AppOps", "AppOpsService published");
	LocalServices.addService(ActivityManagerInternal.class, mInternal);
// ...
mInternal是LocalService类型的对象,LocalService是ActivityManagerService的内联类,他又是ActivityManagerInternal的实现类。
查看LocalService的startProcess方法源码如下:
@VisibleForTesting
public final class LocalService extends ActivityManagerInternal
            implements ActivityManagerLocal {
  @Override
        public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,  boolean isTop, String hostingType, ComponentName hostingName) {
            try {
                if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"
                            + processName);
                }
                synchronized (ActivityManagerService.this) {
                    // If the process is known as top app, set a hint so when the process is
                    // started, the top priority can be applied immediately to avoid cpu being
                    // preempted by other processes before attaching the process of top app.
                    HostingRecord hostingRecord =
                            new HostingRecord(hostingType, hostingName, isTop);
                    ProcessRecord rec = getProcessRecordLocked(processName, info.uid);
                    ProcessRecord app = startProcessLocked(processName, info, knownToBeDead,
                            0 /* intentFlags */, hostingRecord,
                            ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
                            false /* isolated */);
                }
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }
}
接着会调用ActivityManagerService类的startProcessLocked方法,其源码如下:
@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated) {
	return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */, false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */, null /* sdkSandboxClientAppPackage */, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */);
}
mProcessList.startProcessLocked的源码如下
@GuardedBy("mService")
ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
								 int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
								 boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,
								 String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
	long startTime = SystemClock.uptimeMillis();
	final long startTimeNs = SystemClock.elapsedRealtimeNanos();
	ProcessRecord app;
	if (!isolated) {
		app = getProcessRecordLocked(processName, info.uid);
		checkSlow(startTime, "startProcess: after getProcessRecord");
		if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
			// If we are in the background, then check to see if this process
			// is bad.  If so, we will just silently fail.
			if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
				if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
											+ "/" + processName);
				return null;
			}
		} else {
			// When the user is explicitly starting a process, then clear its
			// crash count so that we won't make it bad until they see at
			// least one crash dialog again, and make the process good again
			// if it had been bad.
			if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
										+ "/" + processName);
			mService.mAppErrors.resetProcessCrashTime(processName, info.uid);
			if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
				EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
									UserHandle.getUserId(info.uid), info.uid,
									info.processName);
				mService.mAppErrors.clearBadProcess(processName, info.uid);
				if (app != null) {
					app.mErrorState.setBad(false);
				}
			}
		}
	} else {
		// If this is an isolated process, it can't re-use an existing process.
		app = null;
	}
	// We don't have to do anything more if:
	// (1) There is an existing application record; and
	// (2) The caller doesn't think it is dead, OR there is no thread
	//     object attached to it so we know it couldn't have crashed; and
	// (3) There is a pid assigned to it, so it is either starting or
	//     already running.
	if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
								+ " app=" + app + " knownToBeDead=" + knownToBeDead
								+ " thread=" + (app != null ? app.getThread() : null)
								+ " pid=" + (app != null ? app.getPid() : -1));
	ProcessRecord predecessor = null;
	if (app != null && app.getPid() > 0) {
		if ((!knownToBeDead && !app.isKilled()) || app.getThread() == null) {
			// We already have the app running, or are waiting for it to
			// come up (we have a pid but not yet its thread), so keep it.
			if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
			// If this is a new package in the process, add the package to the list
			app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
			checkSlow(startTime, "startProcess: done, added package to proc");
			return app;
		}
		// An application record is attached to a previous process,
		// clean it up now.
		if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
		checkSlow(startTime, "startProcess: bad proc running, killing");
		ProcessList.killProcessGroup(app.uid, app.getPid());
		checkSlow(startTime, "startProcess: done killing old proc");
		if (!app.isKilled()) {
			// Throw a wtf if it's not killed
			Slog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process");
		} else {
			Slog.w(TAG_PROCESSES, app.toString() + " is attached to a previous process");
		}
		// We are not going to re-use the ProcessRecord, as we haven't dealt with the cleanup
		// routine of it yet, but we'd set it as the predecessor of the new process.
		predecessor = app;
		app = null;
	} else if (!isolated) {
		// This app may have been removed from process name maps, probably because we killed it
		// and did the cleanup before the actual death notification. Check the dying processes.
		predecessor = mDyingProcesses.get(processName, info.uid);
		if (predecessor != null) {
			// The process record could have existed but its pid is set to 0. In this case,
			// the 'app' and 'predecessor' could end up pointing to the same instance;
			// so make sure we check this case here.
			if (app != null && app != predecessor) {
				app.mPredecessor = predecessor;
				predecessor.mSuccessor = app;
			} else {
				app = null;
			}
			Slog.w(TAG_PROCESSES, predecessor.toString() + " is attached to a previous process "
				   + predecessor.getDyingPid());
		}
	}
	if (app == null) {
		checkSlow(startTime, "startProcess: creating new process record");
		app = newProcessRecordLocked(info, processName, isolated, isolatedUid, isSdkSandbox,
									 sdkSandboxUid, sdkSandboxClientAppPackage, hostingRecord);
		if (app == null) {
			Slog.w(TAG, "Failed making new process record for "
				   + processName + "/" + info.uid + " isolated=" + isolated);
			return null;
		}
		app.mErrorState.setCrashHandler(crashHandler);
		app.setIsolatedEntryPoint(entryPoint);
		app.setIsolatedEntryPointArgs(entryPointArgs);
		if (predecessor != null) {
			app.mPredecessor = predecessor;
			predecessor.mSuccessor = app;
		}
		checkSlow(startTime, "startProcess: done creating new process record");
	} else {
		// If this is a new package in the process, add the package to the list
		app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
		checkSlow(startTime, "startProcess: added package to existing proc");
	}
	// If the system is not ready yet, then hold off on starting this
	// process until it is.
	if (!mService.mProcessesReady
		&& !mService.isAllowedWhileBooting(info)
		&& !allowWhileBooting) {
		if (!mService.mProcessesOnHold.contains(app)) {
			mService.mProcessesOnHold.add(app);
		}
		if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
									"System not ready, putting on hold: " + app);
		checkSlow(startTime, "startProcess: returning with proc on hold");
		return app;
	}
	checkSlow(startTime, "startProcess: stepping in to startProcess");
	final boolean success =
		startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride); // 1
	checkSlow(startTime, "startProcess: done starting proc!");
	return success ? app : null;
}
@GuardedBy("mService")
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
						   int zygotePolicyFlags, String abiOverride) {
	return startProcessLocked(app, hostingRecord, zygotePolicyFlags,
							  false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,
							  abiOverride);
}
/**
     * @return {@code true} if process start is successful, false otherwise.
     */
@GuardedBy("mService")
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
						   int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
						   String abiOverride) {
	if (app.isPendingStart()) {
		return true;
	}
	final long startUptime = SystemClock.uptimeMillis();
	final long startElapsedTime = SystemClock.elapsedRealtime();
	if (app.getPid() > 0 && app.getPid() != ActivityManagerService.MY_PID) {
		checkSlow(startUptime, "startProcess: removing from pids map");
		mService.removePidLocked(app.getPid(), app);
		app.setBindMountPending(false);
		mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
		checkSlow(startUptime, "startProcess: done removing from pids map");
		app.setPid(0);
		app.setStartSeq(0);
	}
	// Clear any residual death recipient link as the ProcessRecord could be reused.
	app.unlinkDeathRecipient();
	app.setDyingPid(0);
	if (DEBUG_PROCESSES && mService.mProcessesOnHold.contains(app)) Slog.v(
		TAG_PROCESSES,
		"startProcessLocked removing on hold: " + app);
	mService.mProcessesOnHold.remove(app);
	checkSlow(startUptime, "startProcess: starting to update cpu stats");
	mService.updateCpuStats();
	checkSlow(startUptime, "startProcess: done updating cpu stats");
	try {
		final int userId = UserHandle.getUserId(app.uid);
		try {
			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;
		boolean externalStorageAccess = false;
		if (!app.isolated) {
			int[] permGids = null;
			try {
				checkSlow(startUptime, "startProcess: getting gids from package manager");
				final IPackageManager pm = AppGlobals.getPackageManager();
				permGids = pm.getPackageGids(app.info.packageName,
											 MATCH_DIRECT_BOOT_AUTO, app.userId);
				StorageManagerInternal storageManagerInternal = LocalServices.getService(
					StorageManagerInternal.class);
				mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
																				   app.info.packageName);
				externalStorageAccess = storageManagerInternal.hasExternalStorageAccess(uid,
																						app.info.packageName);
				if (mService.isAppFreezerExemptInstPkg()
					&& pm.checkPermission(Manifest.permission.INSTALL_PACKAGES,
										  app.info.packageName, userId)
					== PackageManager.PERMISSION_GRANTED) {
					Slog.i(TAG, app.info.packageName + " is exempt from freezer");
					app.mOptRecord.setFreezeExempt(true);
				}
			} 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, externalStorageAccess);
		}
		app.setMountMode(mountExternal);
		checkSlow(startUptime, "startProcess: building args");
		if (app.getWindowProcessController().isFactoryTestProcess()) {
			uid = 0;
		}
		int runtimeFlags = 0;
		boolean debuggableFlag = (app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
		boolean isProfileableByShell = app.info.isProfileableByShell();
		boolean isProfileable = app.info.isProfileable();
		if (app.isSdkSandbox) {
			ApplicationInfo clientInfo = app.getClientInfoForSdkSandbox();
			if (clientInfo != null) {
				debuggableFlag |= (clientInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
				isProfileableByShell |= clientInfo.isProfileableByShell();
				isProfileable |= clientInfo.isProfileable();
			}
		}
		if (debuggableFlag) {
			runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
			runtimeFlags |= Zygote.DEBUG_ENABLE_PTRACE;
			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 verification
			if (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 (isProfileableByShell) {
			runtimeFlags |= Zygote.PROFILE_FROM_SHELL;
		}
		if (isProfileable) {
			runtimeFlags |= Zygote.PROFILEABLE;
		}
		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 anything
			runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
			runtimeFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE;   // Disbale optimizations
			mService.mNativeDebuggingApp = null;
		}
		if (app.info.isEmbeddedDexUsed()
			|| (app.processInfo != null && app.processInfo.useEmbeddedDex)) {
			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;
		}
		if (appCompatOption16kb()) {
			boolean is16KbDevice = Os.sysconf(OsConstants._SC_PAGESIZE) == 16384;
			if (is16KbDevice
				&& mService.mContext
				.getPackageManager()
				.isPageSizeCompatEnabled(app.info.packageName)) {
				runtimeFlags |= Zygote.ENABLE_PAGE_SIZE_APP_COMPAT;
			}
		}
		String invokeWith = null;
		if (debuggableFlag) {
			// 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) {
			// If ABI override is specified, use the isa derived from the value of ABI override.
			// Otherwise, use the isa derived from primary ABI
			instructionSet = VMRuntime.getInstructionSet(requiredAbi);
		}
		app.setGids(gids);
		app.setRequiredAbi(requiredAbi);
		app.setInstructionSet(instructionSet);
		// If this was an external service, the package name and uid in the passed in
		// ApplicationInfo have been changed to match those of the calling package;
		// that will incorrectly apply compat feature overrides for the calling package instead
		// of the defining one.
		ApplicationInfo definingAppInfo;
		if (hostingRecord.getDefiningPackageName() != null) {
			definingAppInfo = new ApplicationInfo(app.info);
			definingAppInfo.packageName = hostingRecord.getDefiningPackageName();
			definingAppInfo.uid = uid;
		} else {
			definingAppInfo = app.info;
		}
		runtimeFlags |= Zygote.getMemorySafetyRuntimeFlags(
			definingAppInfo, app.processInfo, instructionSet, mPlatformCompat);
		// the per-user SELinux context must be set
		if (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 + ")"));
		}
		String seInfo = updateSeInfo(app);
		// 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, startUptime, startElapsedTime); // 2
	} 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, false, app.userId, "start failure");
		return false;
	}
}
@GuardedBy("mService")
boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
						   int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
						   String seInfo, String requiredAbi, String instructionSet, String invokeWith,
						   long startUptime, long startElapsedTime) {
	app.setPendingStart(true);
	app.setRemoved(false);
	synchronized (mProcLock) {
		app.setKilledByAm(false);
		app.setKilled(false);
	}
	if (app.getStartSeq() != 0) {
		Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
				 + " with non-zero startSeq:" + app.getStartSeq());
	}
	if (app.getPid() != 0) {
		Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
				 + " with non-zero pid:" + app.getPid());
	}
	app.setDisabledCompatChanges(null);
	app.setLoggableCompatChanges(null);
	if (mPlatformCompat != null) {
		app.setDisabledCompatChanges(mPlatformCompat.getDisabledChanges(app.info));
		app.setLoggableCompatChanges(mPlatformCompat.getLoggableChanges(app.info));
	}
	final long startSeq = ++mProcStartSeqCounter;
	app.setStartSeq(startSeq);
	app.setStartParams(uid, hostingRecord, seInfo, startUptime, startElapsedTime);
	app.setUsingWrapper(invokeWith != null
						|| Zygote.getWrapProperty(app.processName) != null);
	mPendingStarts.put(startSeq, app);
	if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
		if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
									"Posting procStart msg for " + app.toShortString());
		mService.mProcStartHandler.post(() -> handleProcessStart(
			app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,
			requiredAbi, instructionSet, invokeWith, startSeq));
		return true;
	} else {
		try {
			final Process.ProcessStartResult startResult = startProcess(hostingRecord, entryPoint, app, uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startUptime); // 3
			handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper, startSeq, false);
		} catch (RuntimeException e) {
			Slog.e(ActivityManagerService.TAG, "Failure starting process "
				   + app.processName, e);
			app.setPendingStart(false);
			mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, false, app.userId, "start failure");
		}
		return app.getPid() > 0;
	}
}
查看3处的startProcess方法如下
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) {
	try {
		Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
						 app.processName);
		checkSlow(startTime, "startProcess: asking zygote to start proc");
		final boolean isTopApp = hostingRecord.isTopApp();
		if (isTopApp) {
			// Use has-foreground-activities as a temporary hint so the current scheduling
			// group won't be lost when the process is attaching. The actual state will be
			// refreshed when computing oom-adj.
			app.mState.setHasForegroundActivities(true);
		}
		Map<String, Pair<String, Long>> pkgDataInfoMap;
		Map<String, Pair<String, Long>> allowlistedAppDataInfoMap;
		boolean bindMountAppStorageDirs = false;
		boolean bindMountAppsData = mAppDataIsolationEnabled
			&& (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid)
				|| app.isSdkSandbox)
			&& mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info);
		// Get all packages belongs to the same shared uid. sharedPackages is empty array
		// if it doesn't have shared uid.
		final PackageManagerInternal pmInt = mService.getPackageManagerInternal();
		// In the case of sdk sandbox, the pkgDataInfoMap of only the client app associated with
		// the sandbox is required to handle app visibility restrictions for the sandbox.
		final String[] targetPackagesList;
		if (app.isSdkSandbox) {
			targetPackagesList = new String[]{app.sdkSandboxClientAppPackage};
		} else {
			final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
				app.info.packageName, app.userId);
			targetPackagesList = sharedPackages.length == 0
				? new String[]{app.info.packageName} : sharedPackages;
		}
		final boolean hasAppStorage = hasAppStorage(pmInt, app.info.packageName);
		pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid);
		if (pkgDataInfoMap == null) {
			// TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
			// tmp free pass.
			bindMountAppsData = false;
		}
		// Remove all packages in pkgDataInfoMap from mAppDataIsolationAllowlistedApps, so
		// it won't be mounted twice.
		final Set<String> allowlistedApps = new ArraySet<>(mAppDataIsolationAllowlistedApps);
		for (String pkg : targetPackagesList) {
			allowlistedApps.remove(pkg);
		}
		allowlistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt,
															 allowlistedApps.toArray(new String[0]), uid);
		if (allowlistedAppDataInfoMap == null) {
			// TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
			// tmp free pass.
			bindMountAppsData = false;
		}
		if (!hasAppStorage && !app.isSdkSandbox) {
			bindMountAppsData = false;
			pkgDataInfoMap = null;
			allowlistedAppDataInfoMap = null;
		}
		int userId = UserHandle.getUserId(uid);
		StorageManagerInternal storageManagerInternal = LocalServices.getService(
			StorageManagerInternal.class);
		if (needsStorageDataIsolation(storageManagerInternal, app)) {
			// We will run prepareStorageDirs() after we trigger zygote fork, so it won't
			// slow down app starting speed as those dirs might not be cached.
			if (pkgDataInfoMap != null && storageManagerInternal.isFuseMounted(userId)) {
				bindMountAppStorageDirs = true;
			} else {
				// Fuse is not mounted or inode == 0,
				// so we won't mount it in zygote, but resume the mount after unlocking device.
				app.setBindMountPending(true);
				bindMountAppStorageDirs = false;
			}
		}
		// If it's an isolated process, it should not even mount its own app data directories,
		// since it has no access to them anyway.
		if (app.isolated) {
			pkgDataInfoMap = null;
			allowlistedAppDataInfoMap = null;
		}
		boolean bindOverrideSysprops = false;
		String[] syspropOverridePkgNames = DeviceConfig.getString(
			DeviceConfig.NAMESPACE_APP_COMPAT,
			"appcompat_sysprop_override_pkgs", "").split(",");
		String[] pkgs = app.getPackageList();
		for (int i = 0; i < pkgs.length; i++) {
			if (ArrayUtils.contains(syspropOverridePkgNames, pkgs[i])) {
				bindOverrideSysprops = true;
				break;
			}
		}
		AppStateTracker ast = mService.mServices.mAppStateTracker;
		if (ast != null) {
			final boolean inBgRestricted = ast.isAppBackgroundRestricted(
				app.info.uid, app.info.packageName);
			if (inBgRestricted) {
				synchronized (mService) {
					mAppsInBackgroundRestricted.add(app);
				}
			}
			app.mState.setBackgroundRestricted(inBgRestricted);
		}
		final Process.ProcessStartResult startResult;
		boolean regularZygote = false;
		app.mProcessGroupCreated = false;
		app.mSkipProcessGroupCreation = false;
		long forkTimeNs = SystemClock.uptimeNanos();
		if (hostingRecord.usesWebviewZygote()) {
			startResult = startWebView(entryPoint,
									   app.processName, uid, uid, gids, runtimeFlags, mountExternal,
									   app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
									   app.info.dataDir, null, app.info.packageName,
									   app.getDisabledCompatChanges(),
									   new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
		} else if (hostingRecord.usesAppZygote()) {
			final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
			// We can't isolate app data and storage data as parent zygote already did that.
			startResult = appZygote.getProcess().start(entryPoint,
													   app.processName, uid, uid, gids, runtimeFlags, mountExternal,
													   app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
													   app.info.dataDir, null, app.info.packageName,
													   /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
													   app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap,
													   false, false, false,
													   new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
		} else { // 1
			regularZygote = true;
			startResult = Process.start(entryPoint,
										app.processName, uid, uid, gids, runtimeFlags, mountExternal,
										app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
										app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
										isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap,
										allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
										bindOverrideSysprops,
										new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
			// By now the process group should have been created by zygote.
			app.mProcessGroupCreated = true;
		}
		if (android.app.Flags.appStartInfoTimestamps()) {
			mAppStartInfoTracker.addTimestampToStart(app, forkTimeNs,
													 ApplicationStartInfo.START_TIMESTAMP_FORK);
		}
		if (!regularZygote) {
			// webview and app zygote don't have the permission to create the nodes
			synchronized (app) {
				if (!app.mSkipProcessGroupCreation) {
					// If we're not told to skip the process group creation, go create it.
					final int res = Process.createProcessGroup(uid, startResult.pid);
					if (res < 0) {
						if (res == -OsConstants.ESRCH) {
							Slog.e(ActivityManagerService.TAG,
								   "Unable to create process group for "
								   + app.processName + " (" + startResult.pid + ")");
						} else {
							throw new AssertionError("Unable to create process group for "
													 + app.processName + " (" + startResult.pid + ")");
						}
					} else {
						app.mProcessGroupCreated = true;
					}
				}
			}
		}
		// This runs after Process.start() as this method may block app process starting time
		// if dir is not cached. Running this method after Process.start() can make it
		// cache the dir asynchronously, so zygote can use it without waiting for it.
		if (bindMountAppStorageDirs) {
			storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
													  app.processName);
		}
		checkSlow(startTime, "startProcess: returned from zygote!");
		return startResult;
	} finally {
		Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
	}
}
我们一般只走代码1处的Regular Zygote 分支,会调用Process的start方法。其源码如下:
public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();
/**
     * Start a new process.
     *
     * <p>If processes are enabled, a new process is created and the
     * static main() function of a <var>processClass</var> is executed there.
     * The process will continue running after this function returns.
     *
     * <p>If processes are not enabled, a new thread in the caller's
     * process is created and main() of <var>processClass</var> called there.
     *
     * <p>The niceName parameter, if not an empty string, is a custom name to
     * give to the process instead of using processClass.  This allows you to
     * make easily identifyable processes even if you are using the same base
     * <var>processClass</var> to start them.
     *
     * When invokeWith is not null, the process will be started as a fresh app
     * and not a zygote fork. Note that this is only allowed for uid 0 or when
     * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
     *
     * @param processClass The class to use as the process's main entry
     *                     point.
     * @param niceName A more readable name to use for the process.
     * @param uid The user-id under which the process will run.
     * @param gid The group-id under which the process will run.
     * @param gids Additional group-ids associated with the process.
     * @param runtimeFlags Additional flags for the runtime.
     * @param targetSdkVersion The target SDK version for the app.
     * @param seInfo null-ok SELinux information for the new process.
     * @param abi non-null the ABI this app should be started with.
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     * @param invokeWith null-ok the command to invoke with.
     * @param packageName null-ok the name of the package this process belongs to.
     * @param zygotePolicyFlags Flags used to determine how to launch the application
     * @param isTopApp whether the process starts for high priority application.
     * @param disabledCompatChanges null-ok list of disabled compat changes for the process being
     *                             started.
     * @param pkgDataInfoMap Map from related package names to private data directory
     *                       volume UUID and inode number.
     * @param whitelistedDataInfoMap Map from allowlisted package names to private data directory
     *                       volume UUID and inode number.
     * @param bindMountAppsData whether zygote needs to mount CE and DE data.
     * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
     * @param zygoteArgs Additional arguments to supply to the zygote process.
     * @return An object that describes the result of the attempt to start the process.
     * @throws RuntimeException on fatal start failure
     *
     * {@hide}
     */
public static ProcessStartResult start(@NonNull final String processClass,
									   @Nullable final String niceName,
									   int uid, int gid, @Nullable int[] gids,
									   int runtimeFlags,
									   int mountExternal,
									   int targetSdkVersion,
									   @Nullable String seInfo,
									   @NonNull String abi,
									   @Nullable String instructionSet,
									   @Nullable String appDataDir,
									   @Nullable String invokeWith,
									   @Nullable String packageName,
									   int zygotePolicyFlags,
									   boolean isTopApp,
									   @Nullable long[] disabledCompatChanges,
									   @Nullable Map<String, Pair<String, Long>>
                                                   pkgDataInfoMap,
									   @Nullable Map<String, Pair<String, Long>>
                                                   whitelistedDataInfoMap,
									   boolean bindMountAppsData,
									   boolean bindMountAppStorageDirs,
									   boolean bindMountSystemOverrides,
									   @Nullable String[] zygoteArgs) {
	return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
								runtimeFlags, mountExternal, targetSdkVersion, seInfo,
								abi, instructionSet, appDataDir, invokeWith, packageName,
								zygotePolicyFlags, isTopApp, disabledCompatChanges,
								pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
								bindMountAppStorageDirs, bindMountSystemOverrides, zygoteArgs);
}
ZygoteProcess的start方法如下
/**
     * Start a new process.
     *
     * <p>If processes are enabled, a new process is created and the
     * static main() function of a <var>processClass</var> is executed there.
     * The process will continue running after this function returns.
     *
     * <p>If processes are not enabled, a new thread in the caller's
     * process is created and main() of <var>processclass</var> called there.
     *
     * <p>The niceName parameter, if not an empty string, is a custom name to
     * give to the process instead of using processClass.  This allows you to
     * make easily identifyable processes even if you are using the same base
     * <var>processClass</var> to start them.
     *
     * When invokeWith is not null, the process will be started as a fresh app
     * and not a zygote fork. Note that this is only allowed for uid 0 or when
     * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
     *
     * @param processClass The class to use as the process's main entry
     *                     point.
     * @param niceName A more readable name to use for the process.
     * @param uid The user-id under which the process will run.
     * @param gid The group-id under which the process will run.
     * @param gids Additional group-ids associated with the process.
     * @param runtimeFlags Additional flags.
     * @param targetSdkVersion The target SDK version for the app.
     * @param seInfo null-ok SELinux information for the new process.
     * @param abi non-null the ABI this app should be started with.
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     * @param invokeWith null-ok the command to invoke with.
     * @param packageName null-ok the name of the package this process belongs to.
     * @param zygotePolicyFlags Flags used to determine how to launch the application.
     * @param isTopApp Whether the process starts for high priority application.
     * @param disabledCompatChanges null-ok list of disabled compat changes for the process being
     *                             started.
     * @param pkgDataInfoMap Map from related package names to private data directory
     *                       volume UUID and inode number.
     * @param allowlistedDataInfoList Map from allowlisted package names to private data directory
     *                       volume UUID and inode number.
     * @param bindMountAppsData whether zygote needs to mount CE and DE data.
     * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
     *
     * @param zygoteArgs Additional arguments to supply to the Zygote process.
     * @return An object that describes the result of the attempt to start the process.
     * @throws RuntimeException on fatal start failure
     */
public final Process.ProcessStartResult start(@NonNull final String processClass,
											  final String niceName,
											  int uid, int gid, @Nullable int[] gids,
											  int runtimeFlags, int mountExternal,
											  int targetSdkVersion,
											  @Nullable String seInfo,
											  @NonNull String abi,
											  @Nullable String instructionSet,
											  @Nullable String appDataDir,
											  @Nullable String invokeWith,
											  @Nullable String packageName,
											  int zygotePolicyFlags,
											  boolean isTopApp,
											  @Nullable long[] disabledCompatChanges,
											  @Nullable Map<String, Pair<String, Long>>
                                                          pkgDataInfoMap,
											  @Nullable Map<String, Pair<String, Long>>
                                                          allowlistedDataInfoList,
											  boolean bindMountAppsData,
											  boolean bindMountAppStorageDirs,
											  boolean bindOverrideSysprops,
											  @Nullable String[] zygoteArgs) {
	// TODO (chriswailes): Is there a better place to check this value?
	if (fetchUsapPoolEnabledPropWithMinInterval()) {
		informZygotesOfUsapPoolStatus();
	}
	try {
		return startViaZygote(processClass, niceName, uid, gid, gids,
							  runtimeFlags, mountExternal, targetSdkVersion, seInfo,
							  abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
							  packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
							  pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
							  bindMountAppStorageDirs, bindOverrideSysprops, zygoteArgs); // 1
	} catch (ZygoteStartFailedEx ex) {
		Log.e(LOG_TAG,
			  "Starting VM process through Zygote failed");
		throw new RuntimeException(
			"Starting VM process through Zygote failed", ex);
	}
}
  /**
     * Starts a new process via the zygote mechanism.
     *
     * @param processClass Class name whose static main() to run
     * @param niceName 'nice' process name to appear in ps
     * @param uid a POSIX uid that the new process should setuid() to
     * @param gid a POSIX gid that the new process shuold setgid() to
     * @param gids null-ok; a list of supplementary group IDs that the
     * new process should setgroup() to.
     * @param runtimeFlags Additional flags for the runtime.
     * @param targetSdkVersion The target SDK version for the app.
     * @param seInfo null-ok SELinux information for the new process.
     * @param abi the ABI the process should use.
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     * @param startChildZygote Start a sub-zygote. This creates a new zygote process
     * that has its state cloned from this zygote process.
     * @param packageName null-ok the name of the package this process belongs to.
     * @param zygotePolicyFlags Flags used to determine how to launch the application.
     * @param isTopApp Whether the process starts for high priority application.
     * @param disabledCompatChanges a list of disabled compat changes for the process being started.
     * @param pkgDataInfoMap Map from related package names to private data directory volume UUID
     *                       and inode number.
     * @param allowlistedDataInfoList Map from allowlisted package names to private data directory
     *                       volume UUID and inode number.
     * @param bindMountAppsData whether zygote needs to mount CE and DE data.
     * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
     * @param extraArgs Additional arguments to supply to the zygote process.
     * @return An object that describes the result of the attempt to start the process.
     * @throws ZygoteStartFailedEx if process start failed for any reason
     */
    private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
                                                      @Nullable final String niceName,
                                                      final int uid, final int gid,
                                                      @Nullable final int[] gids,
                                                      int runtimeFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      @Nullable String seInfo,
                                                      @NonNull String abi,
                                                      @Nullable String instructionSet,
                                                      @Nullable String appDataDir,
                                                      @Nullable String invokeWith,
                                                      boolean startChildZygote,
                                                      @Nullable String packageName,
                                                      int zygotePolicyFlags,
                                                      boolean isTopApp,
                                                      @Nullable long[] disabledCompatChanges,
                                                      @Nullable Map<String, Pair<String, Long>>
                                                              pkgDataInfoMap,
                                                      @Nullable Map<String, Pair<String, Long>>
                                                              allowlistedDataInfoList,
                                                      boolean bindMountAppsData,
                                                      boolean bindMountAppStorageDirs,
                                                      boolean bindMountOverrideSysprops,
                                                      @Nullable String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<>();
        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("--runtime-flags=" + runtimeFlags);
        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
            argsForZygote.add("--mount-external-default");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
            argsForZygote.add("--mount-external-installer");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
            argsForZygote.add("--mount-external-pass-through");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
            argsForZygote.add("--mount-external-android-writable");
        }
        argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
        // --setgroups is a comma-separated list
        if (gids != null && gids.length > 0) {
            final StringBuilder sb = new StringBuilder();
            sb.append("--setgroups=");
            final int sz = gids.length;
            for (int i = 0; i < sz; i++) {
                if (i != 0) {
                    sb.append(',');
                }
                sb.append(gids[i]);
            }
            argsForZygote.add(sb.toString());
        }
        if (niceName != null) {
            argsForZygote.add("--nice-name=" + niceName);
        }
        if (seInfo != null) {
            argsForZygote.add("--seinfo=" + seInfo);
        }
        if (instructionSet != null) {
            argsForZygote.add("--instruction-set=" + instructionSet);
        }
        if (appDataDir != null) {
            argsForZygote.add("--app-data-dir=" + appDataDir);
        }
        if (invokeWith != null) {
            argsForZygote.add("--invoke-with");
            argsForZygote.add(invokeWith);
        }
        if (startChildZygote) {
            argsForZygote.add("--start-child-zygote");
        }
        if (packageName != null) {
            argsForZygote.add("--package-name=" + packageName);
        }
        if (isTopApp) {
            argsForZygote.add(Zygote.START_AS_TOP_APP_ARG);
        }
        if (pkgDataInfoMap != null && pkgDataInfoMap.size() > 0) {
            StringBuilder sb = new StringBuilder();
            sb.append(Zygote.PKG_DATA_INFO_MAP);
            sb.append("=");
            boolean started = false;
            for (Map.Entry<String, Pair<String, Long>> entry : pkgDataInfoMap.entrySet()) {
                if (started) {
                    sb.append(',');
                }
                started = true;
                sb.append(entry.getKey());
                sb.append(',');
                sb.append(entry.getValue().first);
                sb.append(',');
                sb.append(entry.getValue().second);
            }
            argsForZygote.add(sb.toString());
        }
        if (allowlistedDataInfoList != null && allowlistedDataInfoList.size() > 0) {
            StringBuilder sb = new StringBuilder();
            sb.append(Zygote.ALLOWLISTED_DATA_INFO_MAP);
            sb.append("=");
            boolean started = false;
            for (Map.Entry<String, Pair<String, Long>> entry : allowlistedDataInfoList.entrySet()) {
                if (started) {
                    sb.append(',');
                }
                started = true;
                sb.append(entry.getKey());
                sb.append(',');
                sb.append(entry.getValue().first);
                sb.append(',');
                sb.append(entry.getValue().second);
            }
            argsForZygote.add(sb.toString());
        }
        if (bindMountAppStorageDirs) {
            argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
        }
        if (bindMountAppsData) {
            argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS);
        }
        if (bindMountOverrideSysprops) {
            argsForZygote.add(Zygote.BIND_MOUNT_SYSPROP_OVERRIDES);
        }
        if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
            StringBuilder sb = new StringBuilder();
            sb.append("--disabled-compat-changes=");
            int sz = disabledCompatChanges.length;
            for (int i = 0; i < sz; i++) {
                if (i != 0) {
                    sb.append(',');
                }
                sb.append(disabledCompatChanges[i]);
            }
            argsForZygote.add(sb.toString());
        }
        argsForZygote.add(processClass);
        if (extraArgs != null) {
            Collections.addAll(argsForZygote, extraArgs);
        }
        synchronized(mLock) {
            // The USAP pool can not be used if the application will not use the systems graphics
            // driver.  If that driver is requested use the Zygote application start path.
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                              zygotePolicyFlags,
                                              argsForZygote); // 2
        }
    }
	/**
     * Sends an argument list to the zygote process, which starts a new child
     * and returns the child's pid. Please note: the present implementation
     * replaces newlines in the argument list with spaces.
     *
     * @throws ZygoteStartFailedEx if process start failed for any reason
     */
    @GuardedBy("mLock")
    private Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)
            throws ZygoteStartFailedEx {
        // Throw early if any of the arguments are malformed. This means we can
        // avoid writing a partial response to the zygote.
        for (String arg : args) {
            // Making two indexOf calls here is faster than running a manually fused loop due
            // to the fact that indexOf is an optimized intrinsic.
            if (arg.indexOf('\n') >= 0) {
                throw new ZygoteStartFailedEx("Embedded newlines not allowed");
            } else if (arg.indexOf('\r') >= 0) {
                throw new ZygoteStartFailedEx("Embedded carriage returns not allowed");
            } else if (arg.indexOf('\u0000') >= 0) {
                throw new ZygoteStartFailedEx("Embedded nulls not allowed");
            }
        }
        /*
         * See com.android.internal.os.ZygoteArguments.parseArgs()
         * Presently the wire format to the zygote process is:
         * a) a count of arguments (argc, in essence)
         * b) a number of newline-separated argument strings equal to count
         *
         * After the zygote process reads these it will write the pid of
         * the child or -1 on failure, followed by boolean to
         * indicate whether a wrapper process was used.
         */
        String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
        if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) {
            try {
                return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
            } catch (IOException ex) {
                // If there was an IOException using the USAP pool we will log the error and
                // attempt to start the process through the Zygote.
                Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
                        + ex.getMessage());
            }
        }
        return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr); // 3
    }
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);
        }
    }
 @GuardedBy("mLock")
    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        try {
            attemptConnectionToPrimaryZygote();
            if (primaryZygoteState.matches(abi)) {
                return primaryZygoteState;
            }
            if (mZygoteSecondarySocketAddress != null) {
                // The primary zygote didn't match. Try the secondary.
                attemptConnectionToSecondaryZygote();
                if (secondaryZygoteState.matches(abi)) {
                    return secondaryZygoteState;
                }
            }
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
        }
        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }
   @GuardedBy("mLock")
    private void attemptConnectionToPrimaryZygote() throws IOException {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            primaryZygoteState =
                    ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
            maybeSetApiDenylistExemptions(primaryZygoteState, false);
            maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
        }
    }
   static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
                @Nullable LocalSocketAddress usapSocketAddress)
                throws IOException {
            DataInputStream zygoteInputStream;
            BufferedWriter zygoteOutputWriter;
            final LocalSocket zygoteSessionSocket = new LocalSocket();
            if (zygoteSocketAddress == null) {
                throw new IllegalArgumentException("zygoteSocketAddress can't be null");
            }
            try {
                zygoteSessionSocket.connect(zygoteSocketAddress);
                zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
                zygoteOutputWriter =
                        new BufferedWriter(
                                new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
                                Zygote.SOCKET_BUFFER_SIZE);
            } catch (IOException ex) {
                try {
                    zygoteSessionSocket.close();
                } catch (IOException ignore) { }
                throw ex;
            }
            return new ZygoteState(zygoteSocketAddress, usapSocketAddress,
                                   zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
                                   getAbiList(zygoteOutputWriter, zygoteInputStream));
        }
AMS 调用 zygoteSendArgsAndGetResult()
至此AMS调用到ZygoteProcess整个流程就结束了
Zygote 接收 AMS 请求
查看ZygoteInit.java的main方法
@UnsupportedAppUsage
public static void main(String[] argv) {
	ZygoteServer zygoteServer = null;
	// Mark zygote start. This ensures that thread creation will throw
	// an error.
	ZygoteHooks.startZygoteNoThreadCreation();
	// Zygote goes into its own process group.
	try {
		Os.setpgid(0, 0);
	} catch (ErrnoException ex) {
		throw new RuntimeException("Failed to setpgid(0,0)", ex);
	}
	Runnable caller;
	try {
		// Store now for StatsLogging later.
		final long startTime = SystemClock.elapsedRealtime();
		final boolean isRuntimeRestarted = "1".equals(
			SystemProperties.get("sys.boot_completed"));
		String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
		TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
																  Trace.TRACE_TAG_DALVIK);
		bootTimingsTraceLog.traceBegin("ZygoteInit");
		RuntimeInit.preForkInit();
		boolean startSystemServer = false;
		String zygoteSocketName = "zygote";
		String abiList = null;
		boolean enableLazyPreload = false;
		for (int i = 1; i < argv.length; i++) {
			if ("start-system-server".equals(argv[i])) {
				startSystemServer = true;
			} else if ("--enable-lazy-preload".equals(argv[i])) {
				enableLazyPreload = true;
			} else if (argv[i].startsWith(ABI_LIST_ARG)) {
				abiList = argv[i].substring(ABI_LIST_ARG.length());
			} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
				zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
			} else {
				throw new RuntimeException("Unknown command line argument: " + argv[i]);
			}
		}
		final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
		if (!isRuntimeRestarted) {
			if (isPrimaryZygote) {
				FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
										BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
										startTime);
			} else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
				FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
										BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
										startTime);
			}
		}
		if (abiList == null) {
			throw new RuntimeException("No ABI list supplied.");
		}
		// In some configurations, we avoid preloading resources and classes eagerly.
		// In such cases, we will preload things prior to our first fork.
		if (!enableLazyPreload) {
			bootTimingsTraceLog.traceBegin("ZygotePreload");
			EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
								SystemClock.uptimeMillis());
			preload(bootTimingsTraceLog);
			EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
								SystemClock.uptimeMillis());
			bootTimingsTraceLog.traceEnd(); // ZygotePreload
		}
		// Do an initial gc to clean up after startup
		bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
		gcAndFinalize();
		bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
		bootTimingsTraceLog.traceEnd(); // ZygoteInit
		Zygote.initNativeState(isPrimaryZygote);
		ZygoteHooks.stopZygoteNoThreadCreation();
		zygoteServer = new ZygoteServer(isPrimaryZygote);
		if (startSystemServer) {
			Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // 2
			// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
			// child (system_server) process.
			if (r != null) {
				r.run();
				return;
			}
		}
		Log.i(TAG, "Accepting command socket connections");
		// The select loop returns early in the child process after a fork and
		// loops forever in the zygote.
		caller = zygoteServer.runSelectLoop(abiList); // 1
	} catch (Throwable ex) {
		Log.e(TAG, "System zygote died with fatal exception", ex);
		throw ex;
	} finally {
		if (zygoteServer != null) {
			zygoteServer.closeServerSocket();
		}
	}
	// We're in the child process and have exited the select loop. Proceed to execute the
	// command.
	if (caller != null) {
		caller.run(); // 2
	}
}
/**
  * Prepare the arguments and forks for the system server process.
  *
  * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
  * process; {@code null} in the parent.
  */
private static Runnable forkSystemServer(String abiList, String socketName,
										 ZygoteServer zygoteServer) {
	long capabilities =
		(1L << OsConstants.CAP_IPC_LOCK) |
		(1L << OsConstants.CAP_KILL) |
		(1L << OsConstants.CAP_NET_ADMIN) |
		(1L << OsConstants.CAP_NET_BIND_SERVICE) |
		(1L << OsConstants.CAP_NET_BROADCAST) |
		(1L << OsConstants.CAP_NET_RAW) |
		(1L << OsConstants.CAP_SYS_MODULE) |
		(1L << OsConstants.CAP_SYS_NICE) |
		(1L << OsConstants.CAP_SYS_PTRACE) |
		(1L << OsConstants.CAP_SYS_TIME) |
		(1L << OsConstants.CAP_SYS_TTY_CONFIG) |
		(1L << OsConstants.CAP_WAKE_ALARM) |
		(1L << OsConstants.CAP_BLOCK_SUSPEND);
	/* Containers run without some capabilities, so drop any caps that are not available. */
	StructCapUserHeader header = new StructCapUserHeader(
		OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
	StructCapUserData[] data;
	try {
		data = Os.capget(header);
	} catch (ErrnoException ex) {
		throw new RuntimeException("Failed to capget()", ex);
	}
	capabilities &= Integer.toUnsignedLong(data[0].effective) |
		(Integer.toUnsignedLong(data[1].effective) << 32);
	/* Hardcoded command line to start the system server */
	String[] args = {
		"--setuid=1000",
		"--setgid=1000",
		"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
			+ "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012",
		"--capabilities=" + capabilities + "," + capabilities,
		"--nice-name=system_server",
		"--runtime-args",
		"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
		"com.android.server.SystemServer",
	};
	ZygoteArguments parsedArgs;
	int pid;
	try {
		ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
		try {
			parsedArgs = ZygoteArguments.getInstance(commandBuffer);
		} catch (EOFException e) {
			throw new AssertionError("Unexpected argument error for forking system server", e);
		}
		commandBuffer.close();
		Zygote.applyDebuggerSystemProperty(parsedArgs);
		Zygote.applyInvokeWithSystemProperty(parsedArgs);
		if (Zygote.nativeSupportsMemoryTagging()) {
			String mode = SystemProperties.get("persist.arm64.memtag.system_server", "");
			if (mode.isEmpty()) {
				/* The system server has ASYNC MTE by default, in order to allow
                   * system services to specify their own MTE level later, as you
                   * can't re-enable MTE once it's disabled. */
				mode = SystemProperties.get("persist.arm64.memtag.default", "async");
			}
			if (mode.equals("async")) {
				parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
			} else if (mode.equals("sync")) {
				parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
			} else if (!mode.equals("off")) {
				/* When we have an invalid memory tag level, keep the current level. */
				parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
				Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
			}
		} else if (Zygote.nativeSupportsTaggedPointers()) {
			/* Enable pointer tagging in the system server. Hardware support for this is present
                 * in all ARMv8 CPUs. */
			parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
		}
		/* Enable gwp-asan on the system server with a small probability. This is the same
             * policy as applied to native processes and system apps. */
		parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;
		if (shouldProfileSystemServer()) {
			parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
		}
		/* Request to fork the system server process */
		pid = Zygote.forkSystemServer(
			parsedArgs.mUid, parsedArgs.mGid,
			parsedArgs.mGids,
			parsedArgs.mRuntimeFlags,
			null,
			parsedArgs.mPermittedCapabilities,
			parsedArgs.mEffectiveCapabilities);
	} catch (IllegalArgumentException ex) {
		throw new RuntimeException(ex);
	}
	/* For child process */
	if (pid == 0) {
		if (hasSecondZygote(abiList)) {
			waitForSecondaryZygote(socketName);
		}
		zygoteServer.closeServerSocket();
		return handleSystemServerProcess(parsedArgs);
	}
	return null;
}
代码2处方法forkSystemServer实现由Zygote进程fork出来的SystemServer进程。
通过 native fork 调用创建一个新的子进程(SystemServer)。
fork 的语义:调用一次,返回两次:
父进程(Zygote)里返回子进程 PID (> 0)
子进程(system_server)里返回 0.
代码1处在当前进程永久阻塞运行,监听AMS发来的fork请求,在子进程中会退出循环,执行代码2.
ZygoteServer的runSelectLoop的方法如下:
/**
     * Runs the zygote process's select loop. Accepts new connections as
     * they happen, and reads commands from connections one spawn-request's
     * worth at a time.
     * @param abiList list of ABIs supported by this zygote.
     */
Runnable runSelectLoop(String abiList) {
	ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
	ArrayList<ZygoteConnection> peers = new ArrayList<>();
	socketFDs.add(mZygoteSocket.getFileDescriptor());
	peers.add(null);
	mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
	while (true) {
		fetchUsapPoolPolicyPropsWithMinInterval();
		mUsapPoolRefillAction = UsapPoolRefillAction.NONE;
		int[] usapPipeFDs = null;
		StructPollfd[] pollFDs;
		// Allocate enough space for the poll structs, taking into account
		// the state of the USAP pool for this Zygote (could be a
		// regular Zygote, a WebView Zygote, or an AppZygote).
		if (mUsapPoolEnabled) {
			usapPipeFDs = Zygote.getUsapPipeFDs();
			pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
		} else {
			pollFDs = new StructPollfd[socketFDs.size()];
		}
		/*
             * For reasons of correctness the USAP pool pipe and event FDs
             * must be processed before the session and server sockets.  This
             * is to ensure that the USAP pool accounting information is
             * accurate when handling other requests like API deny list
             * exemptions.
             */
		int pollIndex = 0;
		for (FileDescriptor socketFD : socketFDs) {
			pollFDs[pollIndex] = new StructPollfd();
			pollFDs[pollIndex].fd = socketFD;
			pollFDs[pollIndex].events = (short) POLLIN;
			++pollIndex;
		}
		final int usapPoolEventFDIndex = pollIndex;
		if (mUsapPoolEnabled) {
			pollFDs[pollIndex] = new StructPollfd();
			pollFDs[pollIndex].fd = mUsapPoolEventFD;
			pollFDs[pollIndex].events = (short) POLLIN;
			++pollIndex;
			// The usapPipeFDs array will always be filled in if the USAP Pool is enabled.
			assert usapPipeFDs != null;
			for (int usapPipeFD : usapPipeFDs) {
				FileDescriptor managedFd = new FileDescriptor();
				managedFd.setInt$(usapPipeFD);
				pollFDs[pollIndex] = new StructPollfd();
				pollFDs[pollIndex].fd = managedFd;
				pollFDs[pollIndex].events = (short) POLLIN;
				++pollIndex;
			}
		}
		int pollTimeoutMs;
		if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) {
			pollTimeoutMs = -1;
		} else {
			long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp;
			if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
				// The refill delay has elapsed during the period between poll invocations.
				// We will now check for any currently ready file descriptors before refilling
				// the USAP pool.
				pollTimeoutMs = 0;
				mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
				mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
			} else if (elapsedTimeMs <= 0) {
				// This can occur if the clock used by currentTimeMillis is reset, which is
				// possible because it is not guaranteed to be monotonic.  Because we can't tell
				// how far back the clock was set the best way to recover is to simply re-start
				// the respawn delay countdown.
				pollTimeoutMs = mUsapPoolRefillDelayMs;
			} else {
				pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs);
			}
		}
		int pollReturnValue;
		try {
			pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
		} catch (ErrnoException ex) {
			throw new RuntimeException("poll failed", ex);
		}
		if (pollReturnValue == 0) {
			// The poll returned zero results either when the timeout value has been exceeded
			// or when a non-blocking poll is issued and no FDs are ready.  In either case it
			// is time to refill the pool.  This will result in a duplicate assignment when
			// the non-blocking poll returns zero results, but it avoids an additional
			// conditional in the else branch.
			mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
			mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
		} else {
			boolean usapPoolFDRead = false;
			while (--pollIndex >= 0) {
				if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
					continue;
				}
				if (pollIndex == 0) {
					// Zygote server socket
					ZygoteConnection newPeer = acceptCommandPeer(abiList);
					peers.add(newPeer);
					socketFDs.add(newPeer.getFileDescriptor());
				} else if (pollIndex < usapPoolEventFDIndex) {
					// Session socket accepted from the Zygote server socket
					try {
						ZygoteConnection connection = peers.get(pollIndex);
						boolean multipleForksOK = !isUsapPoolEnabled()
							&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();
						final Runnable command =
							connection.processCommand(this, multipleForksOK);
						// TODO (chriswailes): Is this extra check necessary?
						if (mIsForkChild) {
							// We're in the child. We should always have a command to run at
							// this stage if processCommand hasn't called "exec".
							if (command == null) {
								throw new IllegalStateException("command == null");
							}
							return command;
						} else {
							// We're in the server - we should never have any commands to run.
							if (command != null) {
								throw new IllegalStateException("command != null");
							}
							// We don't know whether the remote side of the socket was closed or
							// not until we attempt to read from it from processCommand. This
							// shows up as a regular POLLIN event in our regular processing
							// loop.
							if (connection.isClosedByPeer()) {
								connection.closeSocket();
								peers.remove(pollIndex);
								socketFDs.remove(pollIndex);
							}
						}
					} catch (Exception e) {
						if (!mIsForkChild) {
							// We're in the server so any exception here is one that has taken
							// place pre-fork while processing commands or reading / writing
							// from the control socket. Make a loud noise about any such
							// exceptions so that we know exactly what failed and why.
							Slog.e(TAG, "Exception executing zygote command: ", e);
							// Make sure the socket is closed so that the other end knows
							// immediately that something has gone wrong and doesn't time out
							// waiting for a response.
							ZygoteConnection conn = peers.remove(pollIndex);
							conn.closeSocket();
							socketFDs.remove(pollIndex);
						} else {
							// We're in the child so any exception caught here has happened post
							// fork and before we execute ActivityThread.main (or any other
							// main() method). Log the details of the exception and bring down
							// the process.
							Log.e(TAG, "Caught post-fork exception in child process.", e);
							throw e;
						}
					} finally {
						// Reset the child flag, in the event that the child process is a child-
						// zygote. The flag will not be consulted this loop pass after the
						// Runnable is returned.
						mIsForkChild = false;
					}
				} else {
					// Either the USAP pool event FD or a USAP reporting pipe.
					// If this is the event FD the payload will be the number of USAPs removed.
					// If this is a reporting pipe FD the payload will be the PID of the USAP
					// that was just specialized.  The `continue` statements below ensure that
					// the messagePayload will always be valid if we complete the try block
					// without an exception.
					long messagePayload;
					try {
						byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
						int readBytes =
							Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
						if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
							DataInputStream inputStream =
								new DataInputStream(new ByteArrayInputStream(buffer));
							messagePayload = inputStream.readLong();
						} else {
							Log.e(TAG, "Incomplete read from USAP management FD of size "
								  + readBytes);
							continue;
						}
					} catch (Exception ex) {
						if (pollIndex == usapPoolEventFDIndex) {
							Log.e(TAG, "Failed to read from USAP pool event FD: "
								  + ex.getMessage());
						} else {
							Log.e(TAG, "Failed to read from USAP reporting pipe: "
								  + ex.getMessage());
						}
						continue;
					}
					if (pollIndex > usapPoolEventFDIndex) {
						Zygote.removeUsapTableEntry((int) messagePayload);
					}
					usapPoolFDRead = true;
				}
			}
			if (usapPoolFDRead) {
				int usapPoolCount = Zygote.getUsapPoolCount();
				if (usapPoolCount < mUsapPoolSizeMin) {
					// Immediate refill
					mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE;
				} else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) {
					// Delayed refill
					mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
				}
			}
		}
		if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) {
			int[] sessionSocketRawFDs =
				socketFDs.subList(1, socketFDs.size())
				.stream()
				.mapToInt(FileDescriptor::getInt$)
				.toArray();
			final boolean isPriorityRefill =
				mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE;
			final Runnable command =
				fillUsapPool(sessionSocketRawFDs, isPriorityRefill);
			if (command != null) {
				return command;
			} else if (isPriorityRefill) {
				// Schedule a delayed refill to finish refilling the pool.
				mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
			}
		}
	}
}
// ============= TODO 待优化 ====================
总结
runSelectLoop(String abiList) 是 Zygote 的主事件循环:它在当前zygote进程里永久阻塞在 poll,按优先顺序处理 USAP 池相关 FD 与客户端(AMS)连接/命令。遇到 fork(由 processCommand() 内部触发)时,子进程会从这个循环返回一个 Runnable(要在子进程执行的命令)并离开循环;父进程继续循环监听下一个请求。
下面把这段代码按模块、按执行流程、按细节逐行拆开讲明白。
关键数据结构与不变式
ArrayList<FileDescriptor> socketFDs
存放要 poll() 的文件描述符(FileDescriptor)。索引含义:
socketFDs[0] 始终是 server socket(mZygoteSocket,用于 accept 新连接)。
socketFDs[1..k] 是已 accept 的 session sockets(每个 ZygoteConnection 对应一个 session socket)。
ArrayList<ZygoteConnection> peers
与 socketFDs 平行,peers.get(i) 对应 socketFDs.get(i):
peers[0] == null(server socket 没有对应 ZygoteConnection)
peers[i](i>0)是对应的 ZygoteConnection。
StructPollfd[] pollFDs
实际传给 Os.poll() 的数组。注意:数组排列并不是固定“server socket 最前”;代码设计为后面插入 USAP FD,再倒序遍历 pollFDs,从而保证 USAP 事件先被处理(详见后面)。
USAP 相关:
mUsapPoolEnabled:是否启用 USAP 池(预创建的“unspecialized app processes”)
mUsapPoolEventFD、usapPipeFDs:用于 USAP 管理和报告的 FD 列表
mUsapPoolRefillTriggerTimestamp、mUsapPoolRefillDelayMs、mUsapPoolRefillAction:控制何时补充 USAP 池
标记:
mIsForkChild:processCommand() 内部 fork 后设置,表示当前执行路径是不是子进程(在子进程中要返回并执行命令)
pollFDs 的构造与遍历顺序(关键,决定优先级)
构造顺序(伪):
先把 socketFDs(server + sessions)按索引 0..n-1 放入 pollFDs。
记住 usapPoolEventFDIndex = pollIndex(此时刚好等于 socketFDs.size())。
如果启用 USAP 池,则接着把 mUsapPoolEventFD(事件 FD)和若干 usapPipeFDs 追加到 pollFDs(索引更高)。
最终 pollFDs 的布局(索引从小到大)大概是:
[ server socket, session socket #1, session socket #2, ..., usapEventFD, usapPipe1, usapPipe2, ... ]
但遍历时使用的是:
while (--pollIndex >= 0) { ... }
也就是从 pollFDs.length-1 向 0 倒序遍历。因此实际处理顺序是:USAP 管理 FD → session sockets → server socket。这与源码注释一致:USAP pool 的 FD 必须先处理,保证在处理客户端命令前 USAP 的 accounting 是最新的。
poll 超时与 USAP 补充策略(pollTimeoutMs 的计算)
mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP → pollTimeoutMs = -1(无限阻塞,直到有事件)
否则计算 elapsedTimeMs = now - triggerTimestamp:
如果 elapsedTimeMs >= delay → pollTimeoutMs = 0(做一次非阻塞 poll,优先检查是否有 FD 已就绪,然后走补充逻辑)
如果 elapsedTimeMs <= 0(系统时间被回拨)→ 重新把超时设为 mUsapPoolRefillDelayMs
否则 pollTimeoutMs = remaining delay
用途:在计划延迟补充 USAP 池时,这里通过 poll 的超时来触发“到时检查并补充”。如果超时到达,用 poll(...,0) 立即检查现有 FD(不阻塞)再做补充。
poll 返回后的高层控制流
pollReturnValue == 0
表示超时或非阻塞 poll 没有就绪 FD → 把 mUsapPoolRefillAction = DELAYED(触发延迟 refill)。
pollReturnValue > 0
遍历 pollFDs(倒序),对每个 pollFDs[pollIndex]:
若 revents & POLLIN == 0 → skip
若 pollIndex == 0 → server socket ready,调用 acceptCommandPeer(abiList) 得到新连接 ZygoteConnection newPeer,并把它加入 peers/socketFDs(这仅是 accept,后续该 connection 会被当成 session socket 处理)
若 pollIndex < usapPoolEventFDIndex → session socket ready(有命令):
获取 connection = peers.get(pollIndex),计算 multipleForksOK(当没有 USAP 且系统允许线程无限期挂起时才可能允许 multiple forks)
Runnable command = connection.processCommand(this, multipleForksOK);
processCommand() 负责读取命令并调用 Zygote.forkAndSpecialize() 或 fork() 的流程
关键点:processCommand() 在 fork 之后 会把 mIsForkChild 设置为 true(在子进程中)。同时 processCommand() 的返回值:
在 子进程:通常会返回一个 Runnable(子进程要执行的命令/入口)
在 父进程(server):通常返回 null(父进程不应执行命令)
接着代码检查 mIsForkChild:
如果 true(当前是子进程):
要求 command != null(否则异常)
return command;:子进程从 runSelectLoop() 返回,外层会在子进程调用 command.run(),后续走 RuntimeInit 等应用启动逻辑。
如果 false(父进程):
要求 command == null(否则异常)
检查 connection.isClosedByPeer(),若已关闭则清理:conn.closeSocket()、从 peers、socketFDs 移除对应项。
finally 中有 mIsForkChild = false; —— 重置子进程标记(为 child-zygote 场景留意:该标记在本次循环之后将不再被利用)
若 pollIndex >= usapPoolEventFDIndex → USAP 事件或报文管道:
从对应 FD 读取固定长度的字节(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES),并用 DataInputStream.readLong() 得到 messagePayload
若 pollIndex > usapPoolEventFDIndex(即 reporting pipe,而不是 event FD)→ Zygote.removeUsapTableEntry((int) messagePayload);
标记 usapPoolFDRead = true 以便后面根据当前 pool count 决定是否补充 USAP 池
关于 processCommand() 与 mIsForkChild
processCommand() 内部会做解析命令、设置权限、并调用底层 Zygote.forkAndSpecialize(...)(native fork),因此它可能会导致两条执行路径同时返回(父返回 childPid,子返回 0)。
mIsForkChild 是一个在 processCommand() 或底层 fork 点设置的标志,用来让 caller(这里的 runSelectLoop())区分自己是否在子进程执行。
子进程路径:mIsForkChild == true,processCommand() 返回一个 Runnable command(通常不会为 null),runSelectLoop() 返回该 command 回上层,子进程退出循环并执行该 command(进一步初始化应用)。
父进程路径:mIsForkChild == false,processCommand() 返回 null,父进程在 finally 中把 mIsForkChild 重置(已无意义)并继续循环。
特别注意 finally { mIsForkChild = false; } 的存在 —— 目的是防止出错时该标志残留影响下一次循环(尤其在 child-zygote 的复合场景中)。
USAP 池相关细节(为什么要先处理 USAP)
USAP = Unspecialized App Process(或 Unspecialized)的池,用于降低冷启动延迟:提前 fork 出一批空白进程,等到需要时快速“specialize”(设置 uid/gid/命名空间/挂载等)而不是从零开始 fork。
源码注释强调:USAP pool 的 pipe 和 event FDs 必须在 session/server sockets 之前处理,以保证 USAP 的 accounting 信息(数量、状态)在处理客户端请求前是最新的。
因为 pollFDs 是倒序处理的(最后加的先处理),所以即使在数组里先放了 server/session,USAP 的 FD 会被优先处理。
当检测到 USAP 管道或 event 有数据时,会把 usapPoolFDRead = true,后面读取 Zygote.getUsapPoolCount() 并决定:
usapPoolCount < mUsapPoolSizeMin → IMMEDIATE refill(优先补足到最小数量)
mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold → DELAYED refill(不紧急,但安排延迟补充)
如果 mUsapPoolRefillAction != NONE,会调用 fillUsapPool(sessionSocketRawFDs, isPriorityRefill):
sessionSocketRawFDs 是把当前所有 session socket 的 “原始 FD 值” 取出来作为参数给 fillUsapPool(pool refill 需要这些 FD 去传递或挂载某些信息)。
fillUsapPool 可能会 fork 出新的 USAP(父进程返回 null,子进程返回一个 Runnable)。若 fillUsapPool 返回非空 command,函数会 return command;(同样:子进程从循环返回并执行);否则继续循环或安排延迟触发。
异常处理与连接关闭
poll 异常(ErrnoException)会被包装成 RuntimeException 抛出 —— 这通常会导致 Zygote 进程崩溃(这是致命的)。
在处理某个 session socket 时,如果在父进程中发生异常(pre-fork),会记录日志并关闭该 connection(conn.closeSocket()),然后从 peers 与 socketFDs 中移除对应项(避免僵尸 FD)。
如果在子进程(post-fork)发生异常,则打印错误并 rethrow —— 子进程应该终止(不能影响父 Zygote)。
对 USAP 管道读取异常使用 continue 忽略单次错,并做日志记录。
为什么 peers[0] == null
socketFDs[0] 是 server socket(listen socket),它不是一个与远端 peer 对应的 session,accept 后才会产生 session socket 并把对应的 ZygoteConnection 加入 peers。因此索引 0 的 peers 放 null 作为占位。
子进程如何“离开循环并执行应用入口”
processCommand() 在子进程通常会返回一个 Runnable command(比如封装了 RuntimeInit/ActivityThread 启动逻辑)。runSelectLoop() 在检测到 mIsForkChild 后 return command;,调用栈返回到上层(Zygote server 主逻辑),上层会在子进程直接执行 command.run(),进入应用进程初始化(RuntimeInit.zygoteInit()、ActivityThread.main() 等)。
重要:子进程 不 应继续在 Zygote 的监听循环中,因为它已成为一个应用进程,接下来要跑 app 的主线程消息循环。
常见疑问与注意点
为什么倒序遍历 pollFDs?
保证 USAP 管理 FD(被追加在数组尾部)优先处理,从而保持池状态的一致性。
pollReturnValue == 0 为什么触发 DELAYED refill?
当 poll() 超时返回 0,说明没有 FD 就绪且到达预设时间,意味着可以进行 USAP 补充(或者计划补充)。
multipleForksOK 的用途?
决定某些情况下是否可以在短时间内并发 fork 多个子进程(与 USAP 与线程挂起安全性相关)。
子进程为什么会得到 Runnable?
因为 processCommand() 在 child 路径会把需要在 child 执行的启动操作以 Runnable 形式返回,父进程不会得到该对象(或得到 null)。
资源清理:若 session socket 被 peer 关闭(isClosedByPeer()),父进程会显式关闭该 socket 并从列表中删除,避免 fd 泄露。
为什么 fillUsapPool 也可能返回 Runnable?
fillUsapPool 也是会 fork 的路径:当它 fork 创建 USAP(或直接 specializer)时,child 也需要执行 some command(例如 specialized init),因此也使用同样的约定返回 Runnable,使子进程能执行并离开循环。
// ============= TODO ====================
ZygoteConnection.java的processCommand方法的源码如下:
ZygoteConnection.java
  /**
     * Reads a command from the command socket. If a child is successfully forked, a
     * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
     * process. {@code null} is always returned in the parent process (the zygote).
     * If multipleOK is set, we may keep processing additional fork commands before returning.
     *
     * If the client closes the socket, an {@code EOF} condition is set, which callers can test
     * for by calling {@code ZygoteConnection.isClosedByPeer}.
     */
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
	ZygoteArguments parsedArgs;
	try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) {
		while (true) {
			try {
				parsedArgs = ZygoteArguments.getInstance(argBuffer);
				// Keep argBuffer around, since we need it to fork.
			} catch (IOException ex) {
				throw new IllegalStateException("IOException on command socket", ex);
			}
			if (parsedArgs == null) {
				isEof = true;
				return null;
			}
			int pid;
			FileDescriptor childPipeFd = null;
			FileDescriptor serverPipeFd = null;
			if (parsedArgs.mBootCompleted) {
				handleBootCompleted();
				return null;
			}
			if (parsedArgs.mAbiListQuery) {
				handleAbiListQuery();
				return null;
			}
			if (parsedArgs.mPidQuery) {
				handlePidQuery();
				return null;
			}
			if (parsedArgs.mUsapPoolStatusSpecified
				|| parsedArgs.mApiDenylistExemptions != null
				|| parsedArgs.mHiddenApiAccessLogSampleRate != -1
				|| parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
				// Handle these once we've released argBuffer, to avoid opening a second one.
				break;
			}
			if (parsedArgs.mPreloadDefault) {
				handlePreload();
				return null;
			}
			if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
				byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
				Parcel appInfoParcel = Parcel.obtain();
				appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
				appInfoParcel.setDataPosition(0);
				ApplicationInfo appInfo =
					ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
				appInfoParcel.recycle();
				if (appInfo != null) {
					handlePreloadApp(appInfo);
				} else {
					throw new IllegalArgumentException("Failed to deserialize --preload-app");
				}
				return null;
			}
			if (parsedArgs.mPermittedCapabilities != 0
				|| parsedArgs.mEffectiveCapabilities != 0) {
				throw new ZygoteSecurityException("Client may not specify capabilities: "
												  + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
												  + ", effective=0x"
												  + Long.toHexString(parsedArgs.mEffectiveCapabilities));
			}
			Zygote.applyUidSecurityPolicy(parsedArgs, peer);
			Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
			Zygote.applyDebuggerSystemProperty(parsedArgs);
			Zygote.applyInvokeWithSystemProperty(parsedArgs);
			int[][] rlimits = null;
			if (parsedArgs.mRLimits != null) {
				rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
			}
			int[] fdsToIgnore = null;
			if (parsedArgs.mInvokeWith != null) {
				try {
					FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
					childPipeFd = pipeFds[1];
					serverPipeFd = pipeFds[0];
					Os.fcntlInt(childPipeFd, F_SETFD, 0);
					fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
				} catch (ErrnoException errnoEx) {
					throw new IllegalStateException("Unable to set up pipe for invoke-with",
													errnoEx);
				}
			}
			/*
                 * In order to avoid leaking descriptors to the Zygote child,
                 * the native code must close the two Zygote socket descriptors
                 * in the child process before it switches from Zygote-root to
                 * the UID and privileges of the application being launched.
                 *
                 * In order to avoid "bad file descriptor" errors when the
                 * two LocalSocket objects are closed, the Posix file
                 * descriptors are released via a dup2() call which closes
                 * the socket and substitutes an open descriptor to /dev/null.
                 */
			int [] fdsToClose = { -1, -1 };
			FileDescriptor fd = mSocket.getFileDescriptor();
			if (fd != null) {
				fdsToClose[0] = fd.getInt$();
			}
			FileDescriptor zygoteFd = zygoteServer.getZygoteSocketFileDescriptor();
			if (zygoteFd != null) {
				fdsToClose[1] = zygoteFd.getInt$();
			}
			if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
				|| !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
				// Continue using old code for now. TODO: Handle these cases in the other path.
				pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,  parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList, parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs, parsedArgs.mBindMountSyspropOverrides); // 1
				try {
					if (pid == 0) {
						// in child
						zygoteServer.setForkChild();
						zygoteServer.closeServerSocket();
						IoUtils.closeQuietly(serverPipeFd);
						serverPipeFd = null;
						return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote); // 3
					} else {
						// In the parent. A pid < 0 indicates a failure and will be handled in
						// handleParentProc.
						IoUtils.closeQuietly(childPipeFd);
						childPipeFd = null;
						handleParentProc(pid, serverPipeFd);
						return null;
					}
				} finally {
					IoUtils.closeQuietly(childPipeFd);
					IoUtils.closeQuietly(serverPipeFd);
				}
			} else {
				ZygoteHooks.preFork();
				Runnable result = Zygote.forkSimpleApps(argBuffer, zygoteServer.getZygoteSocketFileDescriptor(), peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName); // 2
				if (result == null) {
					// parent; we finished some number of forks. Result is Boolean.
					// We already did the equivalent of handleParentProc().
					ZygoteHooks.postForkCommon();
					// argBuffer contains a command not understood by forksimpleApps.
					continue;
				} else {
					// child; result is a Runnable.
					zygoteServer.setForkChild();
					return result;
				}
			}
		}
	}
	// Handle anything that may need a ZygoteCommandBuffer after we've released ours.
	if (parsedArgs.mUsapPoolStatusSpecified) {
		return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
	}
	if (parsedArgs.mApiDenylistExemptions != null) {
		return handleApiDenylistExemptions(zygoteServer,
										   parsedArgs.mApiDenylistExemptions);
	}
	if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
		|| parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
		return handleHiddenApiAccessLogSampleRate(zygoteServer,
												  parsedArgs.mHiddenApiAccessLogSampleRate,
												  parsedArgs.mHiddenApiAccessStatslogSampleRate);
	}
	throw new AssertionError("Shouldn't get here");
}
代码1处是真正fork进程的方法,交由native方法执行,代码2处是Android10新增的方法。
Zygote.java
static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,  boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs,  boolean bindMountSyspropOverrides) {
	ZygoteHooks.preFork();
	int pid = nativeForkAndSpecialize(
		uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
		fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
		pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs,
		bindMountAppStorageDirs, bindMountSyspropOverrides);
	if (pid == 0) {
		// Note that this event ends at the end of handleChildProc,
		Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
		// If no GIDs were specified, don't make any permissions changes based on groups.
		if (gids != null && gids.length > 0) {
			NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
		}
	}
	// Set the Java Language thread priority to the default value for new apps.
	Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
	ZygoteHooks.postForkCommon();
	return pid;
}
static @Nullable Runnable forkSimpleApps(@NonNull ZygoteCommandBuffer argBuffer, @NonNull FileDescriptor zygoteSocket, int expectedUid, int minUid,  @Nullable String firstNiceName) {
	boolean in_child =
		argBuffer.forkRepeatedly(zygoteSocket, expectedUid, minUid, firstNiceName);
	if (in_child) {
		return childMain(argBuffer, /*usapPoolSocket=*/null, /*writePipe=*/null);
	} else {
		return null;
	}
}
nativeForkAndSpecialize本地方法在com_android_internal_os_Zygote.cpp
可以看到如下代码:
NO_STACK_PROTECTOR
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
        jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
        jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
        jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
        jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list,
        jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides){
		//...
		pid_t pid = zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore, true);
		//...
}
代码三处
/**
     * Handles post-fork setup of child proc, closing sockets as appropriate,
     * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
     * if successful or returning if failed.
     *
     * @param parsedArgs non-null; zygote args
     * @param pipeFd null-ok; pipe for communication back to Zygote.
     * @param isZygote whether this new child process is itself a new Zygote.
     */
private Runnable handleChildProc(ZygoteArguments parsedArgs,
								 FileDescriptor pipeFd, boolean isZygote) {
	/*
         * By the time we get here, the native code has closed the two actual Zygote
         * socket connections, and substituted /dev/null in their place.  The LocalSocket
         * objects still need to be closed properly.
         */
	closeSocket();
	Zygote.setAppProcessName(parsedArgs, TAG);
	// End of the postFork event.
	Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
	if (parsedArgs.mInvokeWith != null) {
		WrapperInit.execApplication(parsedArgs.mInvokeWith,
									parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
									VMRuntime.getCurrentInstructionSet(),
									pipeFd, parsedArgs.mRemainingArgs);
		// Should not get here.
		throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
	} else {
		if (!isZygote) {
			return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mDisabledCompatChanges, parsedArgs.mRemainingArgs, null /* classLoader */); // 1
		} else {
			return ZygoteInit.childZygoteInit(
				parsedArgs.mRemainingArgs  /* classLoader */);
		}
	}
}
isZygote代表的是Zygote进程本身。
接着frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) {
	if (RuntimeInit.DEBUG) {
		Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
	}
	Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
	RuntimeInit.redirectLogStreams();
	RuntimeInit.commonInit();
	ZygoteInit.nativeZygoteInit();
	return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv, classLoader); // 1
}
接着查看frameworks/base/core/java/com/android/internal/os/RuntimeInit.java的源码:
    protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        // If the application calls System.exit(), terminate the process
        // immediately without running any shutdown hooks.  It is not possible to
        // shutdown an Android application gracefully.  Among other things, the
        // Android runtime shutdown hooks close the Binder driver, which can cause
        // leftover running threads to crash before the process actually exits.
        nativeSetExitWithoutCleanup(true);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
        VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
        final Arguments args = new Arguments(argv);
        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        // Remaining arguments are passed to the start class's static main
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
 protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;
        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }
        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }
        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }
        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        return new MethodAndArgsCaller(m, argv);
    }
args.startClass的值为android.app.ActivityThread。后面就是众所周知的事情了,本编文章结束,感谢大家。

 🤔startActivity到底发生了什么(二)
        🤔startActivity到底发生了什么(二)
     
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号