2025-01-20 19:21阅读: 26评论: 1推荐: 0

🤔startActivity到底发生了什么?

startActivity到底发生了什么?

大家好不好奇,我们平常使用的最多的startActivity这个方法底层到底是什么样子的?本篇文章就为大家来解密!
本文主要源码的位置如下:
frameworks/base/services/core/java/com/android/server/wm
我们先根据下面的图从宏观上看一下startActivity发生了什么.
image

一、App进程中

startActivity方法的调用链如下:
Activity中:
startActivity -> startActivityForResult -> mInstrumentation.execStartActivity -> ActivityTaskManager.getService().startActivity.
ActivityTaskManager.getService()是从单例对象中,通过binder跨进程调用拿到的是一个IActivityTaskManager, 它是ActivityTaskManagerService的一个代理对象, 然后调动的是其startActivity方法,然后后面的逻辑都是在系统进程完成的。
源码如下:

private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};

二、系统进程中

startActivity快进程调用了ActivityTaskManagerServicestartActivityAsUser方法。
我们查看一下源码:

ActivityTaskManagerServicestartActivityAsUser方法,展开查看
private int startActivityAsUser(
IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
if (isSdkSandboxActivityIntent(mContext, intent)) {
SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
SdkSandboxManagerLocal.class);
sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
intent, Binder.getCallingUid(), callingPackage
);
}
if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
SdkSandboxManagerLocal.class);
if (sdkSandboxManagerLocal == null) {
throw new IllegalStateException("SdkSandboxManagerLocal not found when starting"
+ " an activity from an SDK sandbox uid.");
}
sdkSandboxManagerLocal.enforceAllowedToStartActivity(intent);
}
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(opts)
.setUserId(userId)
.execute();
}

由源码可知,又调用了ActivityStartController对象的obtainStarter方法.
obtainStarter源码如下

ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory
.obtain().setIntent(intent).setReason(reason);
}

由源码可知通过链式调用返回了一个ActivityStarter对象,所以obtainStarter返回的ActivityStarter也通过链式调用最后执行到execute方法,我们查看下其源码:
ActivityStarter.java

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.
launchingRecord = mDoResume ? mLastStartActivityRecord : null;
// 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处是真正完成Activity启动流程的代码。
其源码如下:
ActivityStarter.java

/**
* Executing activity start request and starts the journey of starting an activity. Here
* begins with performing several preliminary checks. The normally activity launch flow will
* go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
*/
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 IApplicationThread caller = request.caller;
Intent intent = request.intent;
NeededUriGrants intentGrants = request.intentGrants;
String resolvedType = request.resolvedType;
ActivityInfo aInfo = request.activityInfo;
ResolveInfo rInfo = request.resolveInfo;
final IVoiceInteractionSession voiceSession = request.voiceSession;
final IBinder resultTo = request.resultTo;
String resultWho = request.resultWho;
int requestCode = request.requestCode;
int callingPid = request.callingPid;
int callingUid = request.callingUid;
String callingPackage = request.callingPackage;
String callingFeatureId = request.callingFeatureId;
final int realCallingPid = request.realCallingPid;
final int realCallingUid = request.realCallingUid;
final int startFlags = request.startFlags;
final SafeActivityOptions options = request.activityOptions;
Task inTask = request.inTask;
TaskFragment inTaskFragment = request.inTaskFragment;
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
final Bundle verificationBundle =
options != null ? options.popAppVerificationBundle() : null;
WindowProcessController callerApp = null;
if (caller != null) {
callerApp = mService.getProcessController(caller);
if (callerApp != null) {
callingPid = callerApp.getPid();
callingUid = callerApp.mInfo.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
+ ") when starting: " + intent.toString());
err = START_PERMISSION_DENIED;
}
}
final int userId = aInfo != null && aInfo.applicationInfo != null
? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
final int launchMode = aInfo != null ? aInfo.launchMode : 0;
if (err == ActivityManager.START_SUCCESS) {
request.logMessage.append("START u").append(userId).append(" {")
.append(intent.toShortString(true, true, true, false))
.append("} with ").append(launchModeToString(launchMode))
.append(" from uid ").append(callingUid);
if (callingUid != realCallingUid
&& realCallingUid != Request.DEFAULT_REAL_CALLING_UID) {
request.logMessage.append(" (realCallingUid=").append(realCallingUid).append(")");
}
}
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
if (resultTo != null) {
sourceRecord = ActivityRecord.isInAnyTask(resultTo);
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);
}
if (sourceRecord != null) {
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
final int launchFlags = intent.getFlags();
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
// Transfer the result target from the source activity to the new one being started,
// including any failures.
if (requestCode >= 0) {
SafeActivityOptions.abort(options);
return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
}
resultRecord = sourceRecord.resultTo;
if (resultRecord != null && !resultRecord.isInRootTaskLocked()) {
resultRecord = null;
}
resultWho = sourceRecord.resultWho;
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
}
if (sourceRecord.launchedFromUid == callingUid) {
// The new activity is being launched from the same uid as the previous activity
// in the flow, and asking to forward its result back to the previous. In this
// case the activity is serving as a trampoline between the two, so we also want
// to update its launchedFromPackage to be the same as the previous activity.
// Note that this is safe, since we know these two packages come from the same
// uid; the caller could just as well have supplied that same package name itself
// . This specifially deals with the case of an intent picker/chooser being
// launched in the app flow to redirect to an activity picked by the user, where
// we want the final activity to consider it to have been launched by the
// previous app activity.
callingPackage = sourceRecord.launchedFromPackage;
callingFeatureId = sourceRecord.launchedFromFeatureId;
}
}
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
// We couldn't find a class that can handle the given Intent.
// That's the end of that!
err = ActivityManager.START_INTENT_NOT_RESOLVED;
}
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
// We couldn't find the specific class specified in the Intent.
err = ActivityManager.START_CLASS_NOT_FOUND;
if (isArchivingEnabled()) {
PackageArchiver packageArchiver = mService
.getPackageManagerInternalLocked()
.getPackageArchiver();
if (packageArchiver.isIntentResolvedToArchivedApp(intent, mRequest.userId)) {
err = packageArchiver
.requestUnarchiveOnActivityStart(
intent, callingPackage, mRequest.userId, realCallingUid);
}
}
}
if (err == ActivityManager.START_SUCCESS && sourceRecord != null
&& sourceRecord.getTask().voiceSession != null) {
// If this activity is being launched as part of a voice session, we need to ensure
// that it is safe to do so. If the upcoming activity will also be part of the voice
// session, we can only launch it if it has explicitly said it supports the VOICE
// category, or it is a part of the calling app.
if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
try {
intent.addCategory(Intent.CATEGORY_VOICE);
if (!mService.getPackageManager().activitySupportsIntentAsUser(
intent.getComponent(), intent, resolvedType, userId)) {
Slog.w(TAG, "Activity being started in current voice task does not support "
+ "voice: " + intent);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
} catch (RemoteException e) {
Slog.w(TAG, "Failure checking voice capabilities", e);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
}
}
if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
// If the caller is starting a new voice session, just make sure the target
// is actually allowing it to run this way.
try {
if (!mService.getPackageManager().activitySupportsIntentAsUser(
intent.getComponent(), intent, resolvedType, userId)) {
Slog.w(TAG,
"Activity being started in new voice task does not support: " + intent);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
} catch (RemoteException e) {
Slog.w(TAG, "Failure checking voice capabilities", e);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
}
final Task resultRootTask = resultRecord == null
? null : resultRecord.getRootTask();
if (err != START_SUCCESS) {
if (resultRecord != null) {
resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
null /* data */, null /* callerToken */, null /* dataGrants */);
}
SafeActivityOptions.abort(options);
return err;
}
boolean abort;
try {
abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord,
resultRootTask);
} catch (SecurityException e) {
// Return activity not found for the explicit intent if the caller can't see the target
// to prevent the disclosure of package existence.
final Intent originalIntent = request.ephemeralIntent;
if (originalIntent != null && (originalIntent.getComponent() != null
|| originalIntent.getPackage() != null)) {
final String targetPackageName = originalIntent.getComponent() != null
? originalIntent.getComponent().getPackageName()
: originalIntent.getPackage();
if (mService.getPackageManagerInternalLocked()
.filterAppAccess(targetPackageName, callingUid, userId)) {
if (resultRecord != null) {
resultRecord.sendResult(INVALID_UID, resultWho, requestCode,
RESULT_CANCELED, null /* data */, null /* callerToken */,
null /* dataGrants */);
}
SafeActivityOptions.abort(options);
return ActivityManager.START_CLASS_NOT_FOUND;
}
}
throw e;
}
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
callingPackage);
// Merge the two options bundles, while realCallerOptions takes precedence.
ActivityOptions checkedOptions = options != null
? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
final BalVerdict balVerdict;
if (!abort) {
try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
"shouldAbortBackgroundActivityStart");
BackgroundActivityStartController balController =
mSupervisor.getBackgroundActivityLaunchController();
balVerdict =
balController.checkBackgroundActivityStart(
callingUid,
callingPid,
callingPackage,
realCallingUid,
realCallingPid,
callerApp,
request.originatingPendingIntent,
request.forcedBalByPiSender,
resultRecord,
intent,
checkedOptions);
request.logMessage.append(" (").append(balVerdict).append(")");
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
} else {
// Sets ALLOW_BY_DEFAULT as default value as the activity launch will be aborted anyway.
balVerdict = BalVerdict.ALLOW_BY_DEFAULT;
}
if (request.allowPendingRemoteAnimationRegistryLookup) {
checkedOptions = mService.getActivityStartController()
.getPendingRemoteAnimationRegistry()
.overrideOptionsIfNeeded(callingPackage, checkedOptions);
}
if (mService.mController != null) {
try {
// The Intent we give to the watcher has the extra data stripped off, since it
// can contain private information.
Intent watchIntent = intent.cloneFilter();
abort |= !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
} catch (RemoteException e) {
mService.mController = null;
}
}
final TaskDisplayArea suggestedLaunchDisplayArea =
computeSuggestedLaunchDisplayArea(inTask, sourceRecord, checkedOptions);
mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
callingFeatureId);
if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment,
callingPid, callingUid, checkedOptions, suggestedLaunchDisplayArea)) {
// activity start was intercepted, e.g. because the target user is currently in quiet
// mode (turn off work) or the target application is suspended
intent = mInterceptor.mIntent;
rInfo = mInterceptor.mRInfo;
aInfo = mInterceptor.mAInfo;
resolvedType = mInterceptor.mResolvedType;
inTask = mInterceptor.mInTask;
callingPid = mInterceptor.mCallingPid;
callingUid = mInterceptor.mCallingUid;
checkedOptions = mInterceptor.mActivityOptions;
// The interception target shouldn't get any permission grants
// intended for the original destination
intentGrants = null;
}
if (abort) {
if (resultRecord != null) {
resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
null /* data */, null /* callerToken */, null /* dataGrants */);
}
// We pretend to the caller that it was really started, but they will just get a
// cancel result.
ActivityOptions.abort(checkedOptions);
return START_ABORTED;
}
// If permissions need a review before any of the app components can run, we
// launch the review activity and pass a pending intent to start the activity
// we are to launching now after the review is completed.
if (aInfo != null) {
if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
aInfo.packageName, userId)) {
final IIntentSender target = mService.getIntentSenderLocked(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,
callingUid, userId, null, null, 0, new Intent[]{intent},
new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_ONE_SHOT, null);
Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
int flags = intent.getFlags();
flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
/*
* Prevent reuse of review activity: Each app needs their own review activity. By
* default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities
* with the same launch parameters (extras are ignored). Hence to avoid possible
* reuse force a new activity via the MULTIPLE_TASK flag.
*
* Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used,
* hence no need to add the flag in this case.
*/
if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {
flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
}
newIntent.setFlags(flags);
newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
if (resultRecord != null) {
newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
}
intent = newIntent;
// The permissions review target shouldn't get any permission
// grants intended for the original destination
intentGrants = null;
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
computeResolveFilterUid(
callingUid, realCallingUid, request.filterCallingUid),
realCallingPid);
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
null /*profilerInfo*/);
if (DEBUG_PERMISSIONS_REVIEW) {
final Task focusedRootTask =
mRootWindowContainer.getTopDisplayFocusedRootTask();
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
true, false) + "} from uid " + callingUid + " on display "
+ (focusedRootTask == null ? DEFAULT_DISPLAY
: focusedRootTask.getDisplayId()));
}
}
}
// If we have an ephemeral app, abort the process of launching the resolved intent.
// Instead, launch the ephemeral installer. Once the installer is finished, it
// starts either the intent we resolved here [on install error] or the ephemeral
// app [on install success].
if (rInfo != null && rInfo.auxiliaryInfo != null) {
intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,
callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
// The ephemeral installer shouldn't get any permission grants
// intended for the original destination
intentGrants = null;
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
}
// TODO (b/187680964) Correcting the caller/pid/uid when start activity from shortcut
// Pending intent launched from systemui also depends on caller app
if (callerApp == null && realCallingPid > 0) {
final WindowProcessController wpc = mService.mProcessMap.getProcess(realCallingPid);
if (wpc != null) {
callerApp = wpc;
}
}
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

/**
* Start an activity while most of preliminary checks has been done and caller has been
* confirmed that holds necessary permissions to do so.
* Here also ensures that the starting activity is removed if the start wasn't successful.
*/
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, // 1
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;
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);
if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
&& !dreamStopping) {
// 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); // mStartActivity 是 ActivityStarter对象的ActivityRecord类型的成员变量
return START_SUCCESS;
}

源码中
mStartActivityActivityStarter对象的ActivityRecord类型的成员变量.
mSupervisorActivityTaskSupervisor类型的对象,管理任务栈逻辑.
mRootWindowContainerRootWindowContainer类型的对象.
我们看下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;
}

focusedRootTask类型的对象,接下来查看方法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); // 1
}
} 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); // 1
forAllLeafTaskFragments(f -> {
if (topFragment == f) {
return;
}
if (!f.canBeResumed(null /* starting */)) {
return;
}
resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
}, true);
return resumed[0];
}

TaskFragmentresumeTopActivity源码如下:
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); // 1
}
return true;
}

代码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); // 1
return;
} 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);
}

代码1处ActivityTaskSupervisor对象调用realStartActivityLocked方法启动Activity,源码如下:

boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException {
if (!mRootWindowContainer.allPausedActivitiesComplete()) {
// While there are activities pausing we skipping starting any new activities until
// pauses are complete. NOTE: that we also do this for activities that are starting in
// the paused state because they will first be resumed then paused on the client side.
ProtoLog.v(WM_DEBUG_STATES,
"realStartActivityLocked: Skipping start of r=%s some activities pausing...",
r);
return false;
}
final Task task = r.getTask();
if (andResume) {
// Try pausing the existing resumed activity in the Task if any.
if (task.pauseActivityIfNeeded(r, "realStart")) {
return false;
}
final TaskFragment taskFragment = r.getTaskFragment();
if (taskFragment != null && taskFragment.getResumedActivity() != null) {
if (taskFragment.startPausing(mUserLeaving, false /* uiSleeping */, r,
"realStart")) {
return false;
}
}
}
final Task rootTask = task.getRootTask();
beginDeferResume();
// The LaunchActivityItem also contains process configuration, so the configuration change
// from WindowProcessController#setProcess can be deferred. The major reason is that if
// the activity has FixedRotationAdjustments, it needs to be applied with configuration.
// In general, this reduces a binder transaction if process configuration is changed.
proc.pauseConfigurationDispatch();
try {
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
r.lastLaunchTime = SystemClock.uptimeMillis();
r.setProcess(proc);
// Ensure activity is allowed to be resumed after process has set.
if (andResume && !r.canResumeByCompat()) {
andResume = false;
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
// Have the window manager re-evaluate the orientation of the screen based on the new
// activity order. Note that as a result of this, it can call back into the activity
// manager with a new orientation. We don't care about that, because the activity is
// not currently running so we are just restarting it anyway.
if (checkConfig) {
// Deferring resume here because we're going to launch new activity shortly.
// We don't want to perform a redundant launch of the same record while ensuring
// configurations and trying to resume top activity of focused root task.
mRootWindowContainer.ensureVisibilityAndConfig(r, r.mDisplayContent, true /* deferResume */);
}
if (mKeyguardController.checkKeyguardVisibility(r) && r.allowMoveToFront()) {
// We only set the visibility to true if the activity is not being launched in
// background, and is allowed to be visible based on keyguard state. This avoids
// setting this into motion in window manager that is later cancelled due to later
// calls to ensure visible activities that set visibility back to false.
r.setVisibility(true);
}
final int applicationInfoUid =
(r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
if ((r.mUserId != proc.mUserId) || (r.info.applicationInfo.uid != applicationInfoUid)) {
Slog.wtf(TAG,
"User ID for activity changing for " + r
+ " appInfo.uid=" + r.info.applicationInfo.uid
+ " info.ai.uid=" + applicationInfoUid
+ " old=" + r.app + " new=" + proc);
}
// Send the controller to client if the process is the first time to launch activity.
// So the client can save binder transactions of getting the controller from activity
// task manager service.
final IActivityClientController activityClientController =
proc.hasEverLaunchedActivity() ? null : mService.mActivityClientController;
r.launchCount++;
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
final LockTaskController lockTaskController = mService.getLockTaskController();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
|| task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV
|| (task.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED
&& lockTaskController.getLockTaskModeState()
== LOCK_TASK_MODE_LOCKED)) {
lockTaskController.startLockTaskMode(task, false, 0 /* blank UID */);
}
try {
if (!proc.hasThread()) {
throw new RemoteException();
}
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume) {
// We don't need to deliver new intents and/or set results if activity is going
// to pause immediately after launch.
results = r.results;
newIntents = r.newIntents;
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Launching: " + r + " savedState=" + r.getSavedState()
+ " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r),
task.mTaskId, r.shortComponentName);
updateHomeProcessIfNeeded(r);
mService.getPackageManagerInternalLocked().notifyPackageUse(
r.intent.getComponent().getPackageName(), NOTIFY_PACKAGE_USE_ACTIVITY);
mService.getAppWarningsLocked().onStartActivity(r);
final Configuration procConfig = proc.prepareConfigurationForLaunchingActivity();
final Configuration overrideConfig = r.getMergedOverrideConfiguration();
r.setLastReportedConfiguration(procConfig, overrideConfig);
final ActivityWindowInfo activityWindowInfo = r.getActivityWindowInfo();
r.setLastReportedActivityWindowInfo(activityWindowInfo);
logIfTransactionTooLarge(r.intent, r.getSavedState());
final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
if (organizedTaskFragment != null) {
// Sending TaskFragmentInfo to client to ensure the info is updated before
// the activity creation.
mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent(
organizedTaskFragment);
}
// Create activity launch transaction.
final boolean isTransitionForward = r.isTransitionForward();
final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
final int deviceId = getDeviceIdForDisplayId(r.getDisplayId());
final LaunchActivityItem launchActivityItem = new LaunchActivityItem(r.token, r.intent, System.identityHashCode(r), r.info,
procConfig, overrideConfig, deviceId,
r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken,
r.initialCallerInfoAccessToken, activityWindowInfo);
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = new ResumeActivityItem(r.token, isTransitionForward,
r.shouldSendCompatFakeFocus());
} else if (r.isVisibleRequested()) {
lifecycleItem = new PauseActivityItem(r.token);
} else {
lifecycleItem = new StopActivityItem(r.token);
}
// Schedule transaction.
if (shouldDispatchLaunchActivityItemIndependently(r.info.packageName, r.getUid())) {
// LaunchActivityItem has @UnsupportedAppUsage usages.
// Guard with targetSDK on Android 15+.
// To not bundle the transaction, dispatch the pending before schedule new
// transaction.
mService.getLifecycleManager().dispatchPendingTransaction(proc.getThread());
}
mService.getLifecycleManager().scheduleTransactionAndLifecycleItems(
proc.getThread(), launchActivityItem, lifecycleItem,
// Immediately dispatch the transaction, so that if it fails, the server can
// restart the process and retry now.
true /* shouldDispatchImmediately */); // 1
if (procConfig.seq > mRootWindowContainer.getConfiguration().seq) {
// If the seq is increased, there should be something changed (e.g. registered
// activity configuration).
proc.setLastReportedConfiguration(procConfig);
}
if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
&& mService.mHasHeavyWeightFeature) {
// This may be a heavy-weight process! Note that the package manager will ensure
// that only activity can run in the main process of the .apk, which is the only
// thing that will be considered heavy-weight.
if (proc.mName.equals(proc.mInfo.packageName)) {
if (mService.mHeavyWeightProcess != null
&& mService.mHeavyWeightProcess != proc) {
Slog.w(TAG, "Starting new heavy weight process " + proc
+ " when already running "
+ mService.mHeavyWeightProcess);
}
mService.setHeavyWeightProcess(r);
}
}
} catch (RemoteException e) {
if (r.launchFailed) {
// This is the second time we failed -- finish activity and give up.
Slog.e(TAG, "Second failure launching "
+ r.intent.getComponent().flattenToShortString() + ", giving up", e);
proc.appDied("2nd-crash");
r.finishIfPossible("2nd-crash", false /* oomAdj */);
return false;
}
// This is the first time we failed -- restart process and
// retry.
r.launchFailed = true;
r.detachFromProcess();
throw e;
}
} finally {
endDeferResume();
proc.resumeConfigurationDispatch();
}
r.launchFailed = false;
// TODO(lifecycler): Resume or pause requests are done as part of launch transaction,
// so updating the state should be done accordingly.
if (andResume && readyToResume()) {
// As part of the process of launching, ActivityThread also performs
// a resume.
r.setState(RESUMED, "realStartActivityLocked");
r.completeResumeLocked();
} else if (r.isVisibleRequested()) {
// This activity is not starting in the resumed state... which should look like we asked
// it to pause+stop (but remain visible), and it has done so and reported back the
// current icicle and other state.
ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s "
+ "(starting in paused state)", r);
r.setState(PAUSED, "realStartActivityLocked");
mRootWindowContainer.executeAppTransitionForAllDisplay();
} else {
// This activity is starting while invisible, so it should be stopped.
r.setState(STOPPING, "realStartActivityLocked");
}
// Perform OOM scoring after the activity state is set, so the process can be updated with
// the latest state.
proc.onStartActivity(mService.mTopProcessState, r.info); // 2
// Launch the new version setup screen if needed. We do this -after-
// launching the initial activity (that is, home), so that it can have
// a chance to initialize itself while in the background, making the
// switch back to it faster and look better.
if (mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask)) {
mService.getActivityStartController().startSetupActivity(); // 3
}
// Update any services we are bound to that might care about whether
// their client may have activities.
if (r.app != null) {
r.app.updateServiceConnectionActivities();
}
return true;
}

在1处真正启动Activity,
mService是一个ActivityTaskManagerService类型的对象。
mService.getLifecycleManager()方法返回的是一个ClientLifecycleManager类型的对象。
scheduleTransactionAndLifecycleItems源码如下:
frameworks/base/services/core/java/com/android/server/wm/ClientLifecycleManager.java

void scheduleTransactionAndLifecycleItems(@NonNull IApplicationThread client,
@NonNull ClientTransactionItem transactionItem,
@NonNull ActivityLifecycleItem lifecycleItem,
boolean shouldDispatchImmediately) throws RemoteException {
// Wait until RootWindowContainer#performSurfacePlacementNoTrace to dispatch all pending
// transactions at once.
final ClientTransaction clientTransaction = getOrCreatePendingTransaction(client);
clientTransaction.addTransactionItem(transactionItem);
clientTransaction.addTransactionItem(lifecycleItem);
onClientTransactionItemScheduled(clientTransaction, shouldDispatchImmediately);
}

scheduleTransactionAndLifecycleItems方法又调用了onClientTransactionItemScheduled方法,其源码如下:
frameworks/base/services/core/java/com/android/server/wm/ClientLifecycleManager.java

/** Must only be called with WM lock. */
private void onClientTransactionItemScheduled(
@NonNull ClientTransaction clientTransaction,
boolean shouldDispatchImmediately) throws RemoteException {
if (shouldDispatchImmediately || shouldDispatchPendingTransactionsImmediately()) {
// Dispatch the pending transaction immediately.
mPendingTransactions.remove(clientTransaction.getClient().asBinder());
scheduleTransaction(clientTransaction);
}
}
/**
* Schedules a transaction, which may consist of multiple callbacks and a lifecycle request.
* @param transaction A sequence of client transaction items.
* @throws RemoteException
*
* @see ClientTransaction
*/
@VisibleForTesting
void scheduleTransaction(@NonNull ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
try {
transaction.schedule(); // 1
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver transaction for " + client + "\ntransaction=" + transaction);
throw e;
}
}

transactionClientTransaction的源码如下:
frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java

/**
* Schedule the transaction after it was initialized. It will be send to client and all its
* individual parts will be applied in the following sequence:
* 1. The client calls {@link #preExecute(ClientTransactionHandler)}, which triggers all work
* that needs to be done before actually scheduling the transaction for callbacks and
* lifecycle state request.
* 2. The transaction message is scheduled.
* 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes
* all callbacks and necessary lifecycle transitions.
*/
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}

mClientIApplicationThread代理对象
frameworks/base/core/java/android/app/IApplicationThread.aidl

void scheduleTransaction(in ClientTransaction transaction);

则服务端进程调用链完成,现在回到App进程中。
ApplicationThreadActivityThread的内部类,我们来看下scheduleTransaction方法的源码。
frameworks/base/core/java/android/app/ActivityThread.java

/**
* This manages the execution of the main thread in an
* application process, scheduling and executing activities,
* broadcasts, and other operations on it as the activity
* manager requests.
*
* {@hide}
*/
public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal {
private class ApplicationThread extends IApplicationThread.Stub{
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction); // 1
}
}
// 真正的实现方法
void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1) {
sendMessage(what, obj, arg1, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2) {
sendMessage(what, obj, arg1, arg2, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) {
Slog.v(TAG,
"SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj);
}
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg); // 2
}
}

1处方法调用了ClientTransactionHandler对象的scheduleTransaction方法,其源码如下:
frameworks/base/core/java/android/app/ClientTransactionHandler.java

// Schedule phase related logic and handlers.
/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

如代码2处,
ClientTransactionHandler对象的sendMessage方法在ActivityThread中实现,最终调用了,ActivityThread的内部类H类型的对象mHsendMessage方法。我们来看一下EXECUTE_TRANSACTION常量对应的逻辑源码:
frameworks/base/core/java/android/app/ActivityThread.java

case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
final ClientTransactionListenerController controller =
ClientTransactionListenerController.getInstance();
controller.onClientTransactionStarted();
try {
mTransactionExecutor.execute(transaction); // 1
} finally {
controller.onClientTransactionFinished();
}
break;

private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
由源码可知mTransactionExecutor是一个TransactionExecutor类型的对象,其execute方法源码如下:
frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java

/**
* Resolve transaction.
* First all callbacks will be executed in the order they appear in the list. If a callback
* requires a certain pre- or post-execution state, the client will be transitioned accordingly.
* Then the client will cycle to the final lifecycle state if provided. Otherwise, it will
* either remain in the initial state, or last state needed by a callback.
*/
public void execute(@NonNull ClientTransaction transaction) {
if (DEBUG_RESOLVER) {
Slog.d(TAG, tId(transaction) + "Start resolving transaction");
Slog.d(TAG, transactionToString(transaction, mTransactionHandler));
}
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "clientTransactionExecuted");
try {
executeTransactionItems(transaction); // 1
} catch (Exception e) {
Slog.e(TAG, "Failed to execute the transaction: "
+ transactionToString(transaction, mTransactionHandler));
throw e;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
mPendingActions.clear();
if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
}
/** Cycles through all transaction items and execute them at proper times. */
@VisibleForTesting
public void executeTransactionItems(@NonNull ClientTransaction transaction) {
final List<ClientTransactionItem> items = transaction.getTransactionItems();
final int size = items.size();
for (int i = 0; i < size; i++) {
final ClientTransactionItem item = items.get(i);
if (item.isActivityLifecycleItem()) {
executeLifecycleItem(transaction, (ActivityLifecycleItem) item); // 2
} else {
executeNonLifecycleItem(transaction, item,
shouldExcludeLastLifecycleState(items, i));
}
}
}
private void executeLifecycleItem(@NonNull ClientTransaction transaction,
@NonNull ActivityLifecycleItem lifecycleItem) {
final IBinder token = lifecycleItem.getActivityToken();
final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
if (DEBUG_RESOLVER) {
Slog.d(TAG, tId(transaction) + "Resolving lifecycle state: "
+ lifecycleItem + " for activity: "
+ getShortActivityName(token, mTransactionHandler));
}
if (r == null) {
if (mTransactionHandler.getActivitiesToBeDestroyed().get(token) == lifecycleItem) {
// Always cleanup for destroy item.
lifecycleItem.postExecute(mTransactionHandler, mPendingActions);
}
// Ignore requests for non-existent client records for now.
return;
}
// Cycle to the state right before the final requested state.
cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction); // 3
// Execute the final transition with proper parameters.
lifecycleItem.execute(mTransactionHandler, mPendingActions);
lifecycleItem.postExecute(mTransactionHandler, mPendingActions);
}
/**
* Transition the client between states with an option not to perform the last hop in the
* sequence. This is used when resolving lifecycle state request, when the last transition must
* be performed with some specific parameters.
*/
private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState,
ClientTransaction transaction) {
final int start = r.getLifecycleState();
if (DEBUG_RESOLVER) {
Slog.d(TAG, tId(transaction) + "Cycle activity: "
+ getShortActivityName(r.token, mTransactionHandler)
+ " from: " + getStateName(start) + " to: " + getStateName(finish)
+ " excludeLastState: " + excludeLastState);
}
final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
performLifecycleSequence(r, path, transaction); // 4
}
/** Transition the client through previously initialized state sequence. */
private void performLifecycleSequence(ActivityClientRecord r, IntArray path,
ClientTransaction transaction) {
final int size = path.size();
for (int i = 0, state; i < size; i++) {
state = path.get(i);
if (DEBUG_RESOLVER) {
Slog.d(TAG, tId(transaction) + "Transitioning activity: "
+ getShortActivityName(r.token, mTransactionHandler)
+ " to state: " + getStateName(state));
}
switch (state) {
case ON_CREATE: // 5
mTransactionHandler.handleLaunchActivity(r, mPendingActions,
Context.DEVICE_ID_INVALID, null /* customIntent */);
break;
case ON_START:
mTransactionHandler.handleStartActivity(r, mPendingActions,
null /* sceneTransitionInfo */);
break;
case ON_RESUME:
mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */,
r.isForward, false /* shouldSendCompatFakeFocus */,
"LIFECYCLER_RESUME_ACTIVITY");
break;
case ON_PAUSE:
mTransactionHandler.handlePauseActivity(r, false /* finished */,
false /* userLeaving */,
false /* autoEnteringPip */, mPendingActions,
"LIFECYCLER_PAUSE_ACTIVITY");
break;
case ON_STOP:
mTransactionHandler.handleStopActivity(r,
mPendingActions, false /* finalStateRequest */,
"LIFECYCLER_STOP_ACTIVITY");
break;
case ON_DESTROY:
mTransactionHandler.handleDestroyActivity(r, false /* finishing */,
false /* getNonConfigInstance */,
"performLifecycleSequence. cycling to:" + path.get(size - 1));
break;
case ON_RESTART:
mTransactionHandler.performRestartActivity(r, false /* start */);
break;
default:
throw new IllegalArgumentException("Unexpected lifecycle state: " + state);
}
}
}

代码5处执行了mTransactionHandler.handleLaunchActivity()方法,
mTransactionHandlerlientTransactionHandler类型的对象,其方法handleLaunchActivity源码如下所示:
frameworks/base/core/java/android/app/ClientTransactionHandler.java

public abstract Activity handleLaunchActivity(@NonNull ActivityClientRecord r, PendingTransactionActions pendingActions, int deviceId, Intent customIntent);

最终是由其子类ActivityThread实现,其源码如下:
frameworks/base/core/java/android/app/ActivityThread.java

/**
* Extended implementation of activity launch. Used when server requests a launch or relaunch.
*/
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, int deviceId, Intent customIntent) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config and resource paths.
applyPendingApplicationInfoChanges(r.activityInfo.packageName);
mConfigurationController.handleConfigurationChanged(null, null);
updateDeviceIdForNonUIContexts(deviceId);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
if (ThreadedRenderer.sRendererEnabled
&& (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
HardwareRenderer.preload();
}
WindowManagerGlobal.initialize();
// Hint the GraphicsEnvironment that an activity is launching on the process.
GraphicsEnvironment.hintActivityLaunch();
final Activity a = performLaunchActivity(r, customIntent); // 1
if (a != null) {
r.createdConfig = new Configuration(mConfigurationController.getConfiguration());
reportSizeConfigurations(r);
if (!r.activity.mFinished && pendingActions != null) {
pendingActions.setOldState(r.state);
pendingActions.setRestoreInstanceState(true);
pendingActions.setCallOnPostCreate(true);
}
// Trigger ActivityWindowInfo callback if first launch or change from relaunch.
handleActivityWindowInfoChanged(r);
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
ActivityClient.getInstance().finishActivity(r.token, Activity.RESULT_CANCELED,
null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
}
return a;
}
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (getInstrumentation() != null
&& getInstrumentation().getContext() != null
&& getInstrumentation().getContext().getApplicationInfo() != null
&& getInstrumentation().isSdkSandboxAllowedToStartActivities()) {
// Activities launched from CTS-in-sandbox tests use a customized ApplicationInfo. See
// also {@link SdkSandboxManagerLocal#getSdkSandboxApplicationInfoForInstrumentation}.
r.packageInfo =
getPackageInfo(
getInstrumentation().getContext().getApplicationInfo(),
mCompatibilityInfo,
Context.CONTEXT_INCLUDE_CODE);
} else if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, mCompatibilityInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
boolean isSandboxActivityContext =
sandboxActivitySdkBasedContext()
&& SdkSandboxActivityAuthority.isSdkSandboxActivityIntent(
mSystemContext, r.intent);
boolean isSandboxedSdkContextUsed = false;
ContextImpl activityBaseContext;
if (isSandboxActivityContext) {
activityBaseContext = createBaseContextForSandboxActivity(r);
if (activityBaseContext == null) {
// Failed to retrieve the SDK based sandbox activity context, falling back to the
// app based context.
activityBaseContext = createBaseContextForActivity(r);
} else {
isSandboxedSdkContextUsed = true;
}
} else {
activityBaseContext = createBaseContextForActivity(r);
}
Activity activity = null;
try {
java.lang.ClassLoader cl;
if (isSandboxedSdkContextUsed) {
// In case of sandbox activity, the context refers to the an SDK with no visibility
// on the SandboxedActivity java class, the App context should be used instead.
cl = activityBaseContext.getApplicationContext().getClassLoader();
} else {
cl = activityBaseContext.getClassLoader();
}
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent); // 2
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
activityBaseContext.getAttributionSource());
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
// updatePendingActivityConfiguration() reads from mActivities to update
// ActivityClientRecord which runs in a different thread. Protect modifications to
// mActivities to avoid race.
synchronized (mResourcesManager) {
mActivities.put(r.token, r);
}
if (activity != null) {
CharSequence title =
r.activityInfo.loadLabel(activityBaseContext.getPackageManager());
Configuration config =
new Configuration(mConfigurationController.getCompatConfiguration());
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
// Activity resources must be initialized with the same loaders as the
// application context.
activityBaseContext.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
activityBaseContext.setOuterContext(activity);
activity.attach(activityBaseContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
r.assistToken, r.shareableActivityToken, r.initialCallerInfoAccessToken);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
if (r.mSceneTransitionInfo != null) {
activity.mSceneTransitionInfo = r.mSceneTransitionInfo;
r.mSceneTransitionInfo = null;
}
activity.mLaunchedFromBubble = r.mLaunchedFromBubble;
activity.mCalled = false;
// Assigning the activity to the record before calling onCreate() allows
// ActivityThread#getActivity() lookup for the callbacks triggered from
// ActivityLifecycleCallbacks#onActivityCreated() or
// ActivityLifecycleCallback#onActivityPostCreated().
r.activity = activity;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state); // 1
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.mLastReportedWindowingMode = config.windowConfiguration.getWindowingMode();
}
r.setState(ON_CREATE);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}

代码2处mInstrumentation是一个Instrumentation类型的对象,其调用了newActivity方法,其源码如下:
frameworks/base/core/java/android/app/Instrumentation.java

public Activity newActivity(Class<?> clazz, Context context,
IBinder token, Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance) throws InstantiationException,
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
// Activity.attach expects a non-null Application Object.
if (application == null) {
application = new Application();
}
activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null /* referrer */, null /* voiceInteractor */,
null /* window */, null /* activityCallback */, null /* assistToken */,
null /* shareableActivityToken */, null /* initialCallerInfoAccessToken */);
return activity;
}

代码1处调用了ActivityonCreate方法,
frameworks/base/core/java/android/app/Instrumentation.java

/**
* Perform calling of an activity's {@link Activity#onCreate}
* method. The default implementation simply calls through to that method.
*
* @param activity The activity being created.
* @param icicle The previously frozen state (or null) to pass through to onCreate().
*/
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle); // 1
postPerformCreate(activity);
}

1处代码最终调用了Activity对象的onCreate方法,其源码如下:

@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "performCreate:"
+ mComponent.getClassName());
}
dispatchActivityPreCreated(icicle);
mCanEnterPictureInPicture = true;
// initialize mIsInMultiWindowMode and mIsInPictureInPictureMode before onCreate
final int windowingMode = getResources().getConfiguration().windowConfiguration
.getWindowingMode();
mIsInMultiWindowMode = inMultiWindowMode(windowingMode);
mIsInPictureInPictureMode = windowingMode == WINDOWING_MODE_PINNED;
mShouldDockBigOverlays = getResources().getBoolean(R.bool.config_dockBigOverlayWindows);
restoreHasCurrentPermissionRequest(icicle);
final long startTime = SystemClock.uptimeMillis();
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle); // 1
}
final long duration = SystemClock.uptimeMillis() - startTime;
EventLogTags.writeWmOnCreateCalled(mIdent, getComponentName().getClassName(),
"performCreate", duration);
mActivityTransitionState.readState(icicle);
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
mActivityTransitionState.setEnterSceneTransitionInfo(this, getSceneTransitionInfo());
dispatchActivityPostCreated(icicle);
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}

至此从startActivtyActivity对象的onCreate方法执行的调用链全部分析完成。

有什么不足的地方还望大家批评指正,提出宝贵意见,我一定慢慢完善。😊


关联文章
// TODO
1. 启动一个未启动的App进程的Activity会发生什么?
2. 在LauncherActivity界面点击应用图标会发生什么?

本文作者:爱情丶眨眼而去

本文链接:https://www.cnblogs.com/zshsboke/p/18679838/startActivity01

版权声明:本作品采用©️CC BY-NC-SA 4.0许可协议进行许可。

posted @   爱情丶眨眼而去  阅读(26)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 赤伶 HITA
  2. 2 樱花树下的约定 (DJ-lucky小阳版) 旺仔小乔
  3. 3 踏雪 国风新语,Babystop_山竹
  4. 4 虞兮叹 闻人听書_
  5. 5 广寒宫 花沫
  6. 6 踏山河 七叔(叶泽浩)
  7. 7 破茧 张韶涵
  8. 8 下山 要不要买菜
  9. 9 红昭愿 音阙诗听
  10. 10 渡我不渡她 独孤
  11. 11 海草舞 陈冬霖
  12. 12 纸短情长 (女声版) 林玉冰
  13. 13 把梦照亮 赵小炮
  14. 14 沙漠骆驼 烟火兄弟
  15. 15 赢在江湖 姜鹏
  16. 16 孤勇者 杨宇峰
  17. 17 口是心非 张大帅
  18. 18 赐我 小时姑娘
  19. 19 囍(Chinese Wedding) 葛东琪
赤伶 - HITA
00:00 / 00:00

赤伶 - HITA

词:清彦

曲:李建衡

编曲:何天程

昆曲念白:朱虹

混音:何天程

二胡:钟意

笛子:笛呆子囚牛

戏一折 水袖起落

唱悲欢唱离合 无关我

扇开合 锣鼓响又默

扇开合 锣鼓响又默

戏中情戏外人 凭谁说

惯将喜怒哀乐都融入粉墨

惯将喜怒哀乐都融入粉墨

陈词唱穿又如何

白骨青灰皆我

白骨青灰皆我

乱世浮萍忍看烽火燃山河

乱世浮萍忍看烽火燃山河

位卑未敢忘忧国

位卑未敢忘忧国

哪怕无人知我

台下人走过 不见旧颜色

台上人唱着 心碎离别歌

情字难落墨

她唱须以血来和

戏幕起 戏幕落 谁是客

浓情悔认真

回头皆幻景

回头皆幻景

对面是何人

对面是何人

戏一折 水袖起落

戏一折 水袖起落

唱悲欢唱离合 无关我

扇开合 锣鼓响又默

扇开合 锣鼓响又默

戏中情戏外人 凭谁说

惯将喜怒哀乐都藏入粉墨

惯将喜怒哀乐都藏入粉墨

陈词唱穿又如何

白骨青灰皆我

乱世浮萍忍看烽火燃山河

乱世浮萍忍看烽火燃山河

位卑未敢忘忧国

位卑未敢忘忧国

哪怕无人知我

台下人走过 不见旧颜色

台下人走过 不见旧颜色

台上人唱着 心碎离别歌

情字难落墨

她唱须以血来和

戏幕起 戏幕落 终是客

你方唱罢我登场

你方唱罢我登场

莫嘲风月戏 莫笑人荒唐

莫嘲风月戏 莫笑人荒唐

也曾问青黄

也曾铿锵唱兴亡

道无情 道有情 怎思量

道无情 道有情 费思量

道无情 道有情 费思量