Activity Starts the system
First of all, summarize the startup of the Android system:
- Start the power supply and the system
- BootLoader – BootLoader is a small program before the Android operating system starts running. Its main function is to pull up the operating system and run
- Linux kernel startup – After the kernel is started, the init.rc file is found in the system files and the init process is started
- Init process start – Initializes and starts the properties service and starts the Zygote process
- Zygote process start – Create Java VIRTUAL machine, register JNI method for Java VIRTUAL machine, create server socket, start systemServer process
- SystemServer process start – Start Binder thread pools and systemServerManager, and start various services
- Launcher – AMS that starts the SystemServer process starts the Launcher, which displays the shortcut icon of the installed application on the screen.
Start the root Activity (API28)
Activity startup can be divided into three stages:
- Launcher–AMS
- AMS–ApplicationThread (an inner class of ActivityThread)
- ActivityThread – start the Activity
Launcher–AMS
See Lacucher source can download the source code, you can also read online, launcher.java
public class Launcher extends BaseDraggingActivity implements LauncherExterns.LauncherModel.Callbacks.LauncherProviderChangeListener.UserEventDelegate{...public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
boolean success = super.startActivitySafely(v, intent, item);
if (success && v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
// from launcher. Since there is no callback for when the activity has finished
// launching, enable the press state and keep this reference to reset the press
// state when we return to launcher.
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
setOnResumeCallback(btv);
}
returnsuccess; }... }Copy the code
As you can see, you simply call the startActivitySafely method of the BaseDraggingActivity parent
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {...// Prepare intent
// The root Activity starts in the new stack
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if(v ! =null) {
intent.setSourceBounds(getViewBounds(v));
}
try {
boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise();
if (isShortcut) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
// Start the Activity from here
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
getUserEventDispatcher().logAppLaunch(v, intent);
return true;
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
}
return false;
}
Copy the code
And you can see that the last thing in the Launcher is calling startActivity, and
public abstract class BaseDraggingActivity extends BaseActivity
implements WallpaperColorInfo.OnChangeListener{... }public abstract class BaseActivity extends Activity implements UserEventDelegate{}Copy the code
As you can see, the launcher is essentially an inherited Activity that calls the Activity’s startActivity method.
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if(options ! =null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1); }}Copy the code
The startActivityForResult method is also called in the startActivity method, but the requestCode parameter is passed -1 indicating that it does not care about the startup result
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); . }else{... }}Copy the code
We only need to care about the logic of mParent==null, because mParent represents the definition of Activity mParent; Is the parent class of the current Activity, because the parent class is the root Activity, so mParent==null. Then call the mInstrumentation execStartActivity. It is important to note that the following one of the parameters mMainThread. GetApplicationThread (), it is the type of ApplicationThread, is the inner class ActivityThread, play an important role in the process of start.
Move on to the Instrumentation class
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {...try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
// Key code
intresult = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null,
requestCode, 0.null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
//ActivityManager.java
public static IActivityManager getService(a) {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create(a) {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
returnam; }};Copy the code
Can be seen from the above code, launch the Activity the real implementation is by ActivityManager. GetService startActivity () method to complete, that there is a difference between before and android8.0
- Before Android8.0 ActivityManagerNative. GetDefault () startActivity to complete, get to AMS by getDefault proxy objects, Use the AMS proxy object ActivityManagerProxy to communicate with AMS across processes.
- After 8.0, this logic was encapsulated in ActivityManager and communicated across processes through AIDL, using IActivityManager, which is the local proxy for AMS.
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor.BatteryStatsImpl.BatteryCallback {... }Copy the code
So far, the process for clicking from the desktop is as follows:
The Launcher call startActivitySafely method — > BaseDraggingActivity. StartActivity – > Activity. StartActivityForResult – > execStartAcitiv Ty –>Instrumentation startActivity–>IActivityManager startActivity–>AMS
AMS–ApplicationThread
From the previous section, the startup process has moved to AMS (ActivityManegerService), and now look at its startActivity method
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
Copy the code
This method internal call again startActivityAsUser overloads, one more parameter UserHandle. GetCallingUserId (), gets the current user id.
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
// Determine process isolation
enforceNotIsolatedCaller("startActivity");
// Check caller permissions
userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
// Switch here to the user application stack
return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
Copy the code
As you can see, the last call to ActivityStartController. ObtainStarter method
/**
* Controller for delegating activity launches.
*
* This class' main objective is to take external activity start requests and prepare them into
* a series of discrete activity launches that can be handled by an {@link ActivityStarter}. It is
* also responsible for handling logic that happens around an activity launch, but doesn't
* necessarily influence the activity start. Examples include power hint management, processing
* through the pending activity list, and recording home activity launches.
*/
public class ActivityStartController {
ActivityStarter obtainStarter(Intent intent, String reason) {
returnmFactory.obtain().setIntent(intent).setReason(reason); }}Copy the code
What does this ActivityStartController do? The ActivityStarter class handles the Activity as a delegate and does not affect the startup result. It is an indirect class, adding a layer to ActivityStarter and AMS.
As you can see, the ActivityStarter class implements the Intent and flag into the Activity, associates the Activity’s task stack, and finally executes the.executer() method
/** * Controller for interpreting how and then launching an activity. * * This class collects all the logic for determining how an intent and flags should be turned into * an activity and associated task and stack. */
class ActivityStarter {
int execute(a) {
try {
// TODO(b/64750076): Look into passing request directly to these methods to allow
// for transactional diffs and preprocessing.
if (mRequest.mayWait) {
return startActivityMayWait(mRequest.caller, mRequest.callingUid,
mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup);
} else {
returnstartActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo, mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, mRequest.resultWho, mRequest.requestCode, mRequest.callingPid, mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.componentSpecified, mRequest.outActivity, mRequest.inTask, mRequest.reason, mRequest.allowPendingRemoteAnimationRegistryLookup); }}finally{ onExecutionComplete(); }}}Copy the code
SetMayWait (userId).execute(); setMayWait(userId).execute(); We’re just going to look at execute, so let’s look at the setMayWait method above
ActivityStarter setMayWait(int userId) {
mRequest.mayWait = true;
mRequest.userId = userId;
return this;
}
Copy the code
As you can see, in the execute method, the if condition is satisfied, so we execute the startActivityMayWait method, which is a very long method and only looks at the parts we care about.
private int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, WaitResult outResult,
Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
int userId, TaskRecord inTask, String reason,
boolean allowPendingRemoteAnimationRegistryLookup) {
// Refuse possible leaked file descriptors
if(intent ! =null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
booleancomponentSpecified = intent.getComponent() ! =null;
final int realCallingPid = Binder.getCallingPid();
final intrealCallingUid = Binder.getCallingUid(); .// Parse the Intent data
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
0 /* matchFlags */, computeResolveFilterUid( callingUid, realCallingUid, mRequest.filterCallingUid)); .// Collect information about the target of the Intent.ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo); .// Used to record Activity data
final ActivityRecord[] outRecord = new ActivityRecord[1];
/ / start the Activity
intres = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason, allowPendingRemoteAnimationRegistryLookup); . }Copy the code
You can see that the startActivity method is called internally
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, TaskRecord inTask, String reason,
boolean allowPendingRemoteAnimationRegistryLookup) {
if (TextUtils.isEmpty(reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
}
mLastStartReason = reason;
mLastStartActivityTimeMs = System.currentTimeMillis();
mLastStartActivityRecord[0] = null;
// Call the overloaded method of startActivity here again
mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
inTask, allowPendingRemoteAnimationRegistryLookup);
if(outActivity ! =null) {
// mLastStartActivityRecord[0] is set in the call to startActivity above.
outActivity[0] = mLastStartActivityRecord[0];
}
return getExternalResult(mLastStartActivityResult);
}
Copy the code
Call the overloaded method again here
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
finalBundle verificationBundle = options ! =null ? options.popAppVerificationBundle() : null;
ProcessRecord callerApp = null; .// Check the permission to start the Activity
booleanabort = ! mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho, requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, inTask ! =null, callerApp, resultRecord, resultStack); abort |= ! mService.mIntentFirewall.checkStartActivity(intent, callingUid, callingPid, resolvedType, aInfo.applicationInfo); .if (mService.mDidAppSwitch) {
// This is the second allowed switch since we stopped switches,
// so now just generally allow switches. Use case: user presses
// home (switches disabled, switch to home, mDidAppSwitch now true);
// user taps a home icon (coming from home so allowed, we hit here
// and now allow anyone to switch again).
mService.mAppSwitchesAllowedTime = 0;
} else {
mService.mDidAppSwitch = true;
}
mController.doPendingActivityLaunches(false);
// Continue the call
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true /* doResume */, checkedOptions, inTask, outActivity);
}
Copy the code
At the end of the return, another startActivity method is executed, just click:
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
int result = START_CANCELED;
try {
mService.mWindowManager.deferSurfaceLayout();
// Key points
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity);
} finally {
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
// without a window container.
// Get the Activity task stack
final ActivityStack stack = mStartActivity.getStack();
if(! ActivityManager.isStartResultSuccessful(result) && stack ! =null) {
stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
null /* intentResultData */."startActivity".true /* oomAdj */);
}
mService.mWindowManager.continueSurfaceLayout();
}
postStartActivityProcessing(r, result, mTargetStack);
return result;
}
Copy the code
You can see that in this startActivity method, it’s finally not calling the startActivity method anymore (I’m going crazy if I do that again), so let’s go ahead and look at startActivityUnchecked
// Note: This method should only be called from {@link startActivity}.
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
// Handle the Activity's startup modecomputeLaunchingTaskFlags(); computeSourceStack(); mIntent.setFlags(mLaunchFlags); .int result = START_SUCCESS;
FLAG_ACTIVITY_NEW_TASK is set to flag_activity_task when the root Activity is launched
if (mStartActivity.resultTo == null && mInTask == null&&! mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) ! =0) {
newTask = true;
// Create a new TaskRecord
result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
} else if(mSourceRecord ! =null) {
result = setTaskFromSourceRecord();
} else if(mInTask ! =null) {
result = setTaskFromInTask();
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.setTaskToCurrentTopOrCreateNewTask(); }...// Determine whether to insert the existing top of the stack directly or a new stack based on the Activity startup mode
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if(! mTargetStack.isFocusable() || (topTaskActivity ! =null&& topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) {// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
mTargetStack.ensureActivitiesVisibleLocked(null.0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mService.mWindowManager.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
// will not update the focused stack. If starting the new activity now allows the
// task stack to be focusable, then ensure that we now update the focused stack
// accordingly.
if(mTargetStack.isFocusable() && ! mSupervisor.isFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked");
}
// Key pointsmSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); }}else if(mStartActivity ! =null) {
mSupervisor.mRecentTasks.add(mStartActivity.getTask());
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
preferredLaunchDisplayId, mTargetStack);
return START_SUCCESS;
}
Copy the code
The startActivityUnchecked method, noted above in key places, handles the stack word handling logic because we set FLAG to FLAG_ACTIVITY_NEW_TASK when we start the Activity at the root, This will be used in setTaskFromReuseOrCreateNewTask method, its internal will create a new TaskRecord, used to describe an Activity task stack.
Finally invokes ActivityStackSupervisor resumeFocusedStackTopActivityLocked method.
boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if(! readyToResume()) {return false;
}
if(targetStack ! =null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null| |! r.isState(RESUMED)) { mFocusedStack.resumeTopActivityUncheckedLocked(null.null);
} else if (r.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
return false;
}
Copy the code
According to the parameters of the coming, targetStack is not null, and isFocusedStack (targetStack) judgment also is true, is true, so judging conditions into execution resumeTopActivityUncheckedLocked method, ActivityStack is responsible for the management is going to start the Activity in the stack of tasks, to continue into the ActivityStack resumeTopActivityUncheckedLocked method in class
@GuardedBy("mService")
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
// 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 ActivityStackSupervisor#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 ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
Copy the code
Call the resumeTopActivityInnerLocked method
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if(! mService.mBooting && ! mService.mBooted) {// Not ready yet!
return false;
}
// Find the next top-most activity to resume in this stack that is not finishing and is
// focusable. If it is not focusable, we will fall into the case below to resume the
// top activity in the next focusable task.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */); . mStackSupervisor.startSpecificActivityLocked(next,true.false); / / comment 1.Copy the code
The thief long method code, we only care about invocation chain can, again call ActivityStackSupervisor method, continue to see startSpecificActivityLocked
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
// Get the application process in which the Activity is to be started
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
getLaunchTimeTracker().setLaunchTime(r);
if(app ! =null&& app.thread ! =null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
mService.mProcessStats);
}
//
realStartActivityLocked(r, app, andResume, checkConfig);
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.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true.0."activity", r.intent.getComponent(), false.false.true);
}
Copy the code
In this case, call the realStartActivityLocked method, and the app is the ProcessRecord obtained above.
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
if(! 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.
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"realStartActivityLocked: Skipping start of r=" + r
+ " some activities pausing...");
return false; }...// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, mService.isNextTransitionForward(),
profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.mService.getLifecycleManager().scheduleTransaction(clientTransaction); . }Copy the code
This is the biggest change in 9.0 compared to other versions. Let’s take a look at the 8.0 code
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
if(! 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.
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"realStartActivityLocked: Skipping start of r=" + r
+ " some activities pausing...");
return false; }... app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global and
// override configs.mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, ! andResume, mService.isNextTransitionForward(), profilerInfo); .Copy the code
By comparing the code 9.0 and 8.0, 9.0 can be found through the transaction mechanism to start the Activity, and by the main thread before, direct app. Thread. ScheduleLaunchActivity scheduling execution, this is the biggest difference
Starting with the 9.0 code, we manage the Activity startup process through ClientTranSaction, which contains a series of messages from the client app that can be responded to and sent back to the client. Let the client, the app, perform the callbacks, completing the specific message execution and scheduling execution throughout the lifecycle. Next, look at the scheduleTransaction method execution, which is one of ClientLifecycleManager’s methods:
/**
* Schedule a transaction, which may consist of multiple callbacks and a lifecycle request.
* @param transaction A sequence of client transaction items.
* @throws RemoteException
*
* @see ClientTransaction
*/
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
transaction.schedule();
// Client is a Binder
if(! (clientinstanceofBinder)) { transaction.recycle(); }}Copy the code
Client is a Binder, so just look at ClientTransaction’s Schedule () method.
public void schedule(a) throws RemoteException {
mClient.scheduleTransaction(this);
}
/** Obtain an instance initialized with provided params. */
public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
if (instance == null) {
instance = new ClientTransaction();
}
instance.mClient = client;
instance.mActivityToken = activityToken;
return instance;
}
Copy the code
MClient is defined in ClientTransaction as private IApplicationThread mClient; , you can see that the value is already assigned when obtain is executed in the realStartActivityLocked method above.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
Copy the code
MClient = app.thread, which is the IApplicationThread type, implements the inner class ApplicationThread of ActivityThread. ApplicationThread inherits from iApplicationThread.stub. App refers to the application process in which the Activity is passed in to start, so this code refers to starting the Activity in the target process.
private class ApplicationThread extends IApplicationThread.Stub{... }Copy the code
The current code runs in the same process as AMS, SystemServer, and communicates with the Binder through ApplicationThread to achieve cross-process communication
The sequence diagram is as follows:
ApplicationThread – start the Activity
With the above analysis, we are now at the source code for ApplicationThread
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
Copy the code
The ActivityThread parent’s ClientTransactionHandler method is called
/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
Copy the code
Send a message to the ActivityThread H class via sendMessage, which inherits from Handler and we’ll just follow in
class H extends Handler {...public void handleMessage(Message msg) {...case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
// Execute the statement
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break; . }... }Copy the code
You can see that the rest of the process is handled by the TransactionExecutor
public void execute(ClientTransaction transaction) {
final IBinder token = transaction.getActivityToken();
log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
log("End resolving transaction");
}
Copy the code
Now look at the executeCallbacks method
/** Cycle through all states requested by callbacks and execute them at proper times. */
@VisibleForTesting
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
if (callbacks == null) {
// No callbacks to execute, return early.
return;
}
log("Resolving callbacks");
// Get the current app from the service
final IBinder token = transaction.getActivityToken();
ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
// In case when post-execution state of the last callback matches the final state requested
// for the activity in this transaction, we won't do the last transition here and do it when
// moving to final state instead (because it may contain additional parameters from server).
final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
final intfinalState = finalStateRequest ! =null ? finalStateRequest.getTargetState()
: UNDEFINED;
// Index of the last callback that requests some post-execution state.
final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
log("Resolving callback: " + item);
final int postExecutionState = item.getPostExecutionState();
final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
item.getPostExecutionState());
if(closestPreExecutionState ! = UNDEFINED) { cycleToPath(r, closestPreExecutionState); }// Start the activity
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
if (r == null) {
// Launch activity request will create an activity record.
r = mTransactionHandler.getActivityClient(token);
}
if(postExecutionState ! = UNDEFINED && r ! =null) {
// Skip the very last transition and perform it by explicit state request instead.
final booleanshouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; cycleToPath(r, postExecutionState, shouldExcludeLastTransition); }}}Copy the code
You can see that the item.execute method is used to start the Activity, and what is the item, ClientTransactionItem?
/**
* A callback message to a client that can be scheduled and executed.
* Examples of these might be activity configuration change, multi-window mode change, activity
* result delivery etc.
*
* @see ClientTransaction
* @see com.android.server.am.ClientLifecycleManager
* @hide* /
public abstract class ClientTransactionItem implements BaseClientRequest.Parcelable {... }Copy the code
It can be seen from the notes that it serves as a callback hub for the system and app, such as configuration changes, multi-window mode changes, and Activity startup
Since what we see here is an abstract class, we need to find its implementation class.
Go back to the realStartActivityLocked method of ActivityStackSupervisor
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
if(! 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.
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"realStartActivityLocked: Skipping start of r=" + r
+ " some activities pausing...");
return false; }...// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
////////////////// note !!!!!!! /////////////////////////////////////////////
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, mService.isNextTransitionForward(),
profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.mService.getLifecycleManager().scheduleTransaction(clientTransaction); .Copy the code
In clientTransaction we add the LaunchActivityItem, which is the implementation class for ClientTransactionItem, so we just need to look at its execute method
@Override
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client);
// Finally execute here
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
Copy the code
Finally, the handleLaunchActivity method of ClientTransactionHandler is executed.
Happy to run a look at the source code, pit dad is an abstract class, to find its implementation class.
H receives an EXECUTE_TRANSACTION message
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
Copy the code
Look at how mTransactionExecutor is assigned,
private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
Copy the code
The ActivityThread itself inherits from ClientTransactionHandler, and the ActivityThread itself inherits from ClientTransactionHandler. So perform client. HandleLaunchActivity (r, pendingActions, null customIntent / * * /); That is, execute the handleLaunchActivity method in ActivityThread
@Override
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, 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.
handleConfigurationChanged(null.null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
if(! ThreadedRenderer.sRendererDisabled) { GraphicsEnvironment.earlyInitEGL(); } WindowManagerGlobal.initialize();/ / enforcement point
final Activity a = performLaunchActivity(r, customIntent);
if(a ! =null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
if(! r.activity.mFinished && pendingActions ! =null) {
pendingActions.setOldState(r.state);
pendingActions.setRestoreInstanceState(true);
pendingActions.setCallOnPostCreate(true); }}else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throwex.rethrowFromSystemServer(); }}return a;
}
Copy the code
Where the execution point is performLaunchActivity(r, customIntent); This method
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// Get the ActivityInfo class
ActivityInfo aInfo = r.activityInfo;/ / 1
if (r.packageInfo == null) {
// Get the description class LoadedApk for the APK file
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);/ / 2
}
ComponentName component = r.intent.getComponent();/ / 3.// Create the Activity Context
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
// Create an instance of the Activity with the class loader
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);/ / 5. }catch (Exception e) {
...
}
try {
/ / create the Application
Application app = r.packageInfo.makeApplication(false, mInstrumentation);/ / 6.if(activity ! =null) {
//7 Starts the Activity
activity.attach(appContext, 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.configCallback); .if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);/ / 8
} else{ mInstrumentation.callActivityOnCreate(activity, r.state); }... } r.setState(ON_CREATE); mActivities.put(r.token, r); }catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
return activity;
}
Copy the code
Comments explaining
-
Get ActivityInfo, which stores Activity and Receiver information for code and AndroidMainfes Settings, such as the Activity’s theme and LaunchMode.
-
Get the description class LoadedApk for the APK file
-
Gets the ComponentName class for the Activity to start, which holds the package name and class name for the Activity.
-
The context used to create the Activity that is launched
-
Create an instance of the Activity using the class loader based on the Activity class name stored in ComponentName
-
When you create an Application, the onCreate method is called inside the makeApplication method
-
The attach method of the Activity is called to initialize the Activity, and the phoneWindow object is created in attach and associated with the Activity
-
Call the callActivityOnCreate method in Instrumentation to start the Activity.
From Android Advanced Decryption, p. 100
Let’s look at the source code of callActivityOnCreate
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
Copy the code
Call the activity. PerformCreate (bonnie); Search directly for the Activity’s performCreate(Icicle) method
final void performCreate(Bundle icicle) {
performCreate(icicle, null);
}
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
mCanEnterPictureInPicture = true;
restoreHasCurrentPermissionRequest(icicle);
if(persistentState ! =null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate"); mActivityTransitionState.readState(icicle); mVisibleFromClient = ! mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay,false);
mFragments.dispatchActivityCreated();
mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}
Copy the code
Finally, after looking at dozens of classes, I saw the lovely onCreate method ~~~~
At this point, the root Activity has started!
PS: Time sequence painting is not moving, trapped into a dog
conclusion
The Launcher process asks AMS to create the root Activity. AMS determines whether the application for the Activity exists and starts it. If it doesn’t, the Zygote process forks itself to create the program. After the application process is started, AMS creates the application process and starts the Activity. The Launcher and AMS communicate with the application through THE Binder, and AMS communicates with Zygote using sockets.
When normal activities start, only AMS communicates with the application process
reference
(Android 9.0) Activity start process source code analysis
Android Advanced Decryption
My CSDN
Below is my public number, welcome everyone to pay attention to me