Startup process of root Activity
The overall process of starting the root Activity is as follows:
It is mainly divided into four parts
- The Launcher requests ATMS to create a root Activity
- ATMS will request zygote to create the application process
- zygote to create application process
- ATMS requests ApplicationThread to create a root Activity
If we analyze, we will not analyze according to each step above. We will analyze the source code (android 10) according to the following three parts
- The process by which the Launcher requests ATMS
- Calling procedure from ATMS to ApplicationThread
- ActivityThread the process of starting an Activity
The process by which the Launcher requests ATMS
First, click the desktop icon, and the Launcher will call the startactivitysafe function
//Launcher.java public boolean startActivitySafely(View v, Intent intent, ItemInfo item, @Nullable String sourceContainer) { ... boolean success = super.startActivitySafely(v, intent, item, sourceContainer);//1 ... return success; }
A key line of code is that it will call the parent class's startactivitysafe, which will eventually call the methods in the BaseDraggingActivity
//BaseDraggingActivity.java public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item, @Nullable String sourceContainer) { ... // Note 1 Prepare intent intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (v != null) { intent.setSourceBounds(getViewBounds(v)); } try { boolean isShortcut = (item instanceof WorkspaceItemInfo) && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) && !((WorkspaceItemInfo) item).isPromise(); if (isShortcut) { // Shortcuts need some special checks due to legacy reasons. startShortcutIntentSafely(intent, optsBundle, item, sourceContainer); } else if (user == null || user.equals(Process.myUserHandle())) { // Could be launching some bookkeeping activity if (TestProtocol.sDebugTracing) { android.util.Log.d(TestProtocol.NO_START_TAG, "startActivitySafely 2"); } // Note 2 startActivity(intent, optsBundle); ... } return false; }
Note 1 of the code, which everyone understands, is to start the Activity in a new task stack, and then note 2 is to call startActivity. The code here calls startActivity in Activity
//Activity.java @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); } } public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { //Note 1 if (mParent == null) { options = transferSpringboardActivityOptions(options); Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } ... } }
It can be seen from comment 1 that since we started the Activity, the judgment condition of mParent==null is true, and the if statement will enter the if statement, and then the if statement will call mminstrumentation execStartActivity. What does the Instrumentation class do? It is mainly used to monitor the interaction between the system and applications. So here, the next steps go into the Instrumentation class.
@UnsupportedAppUsage public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { ... try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); // Note 1 int result = ActivityTaskManager.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; }
Note 1. Here is the called ActivityTaskManager Getservice (), ActivityTaskManager, is a new class added after Android 10,
//ActivityTaskManager.java public static IActivityTaskManager getService() { return IActivityTaskManagerSingleton.get(); } @UnsupportedAppUsage(trackingBug = 129726065) private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() { @Override protected IActivityTaskManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE); //Note 1 return IActivityTaskManager.Stub.asInterface(b);//Note 2 } };
Here, the binder IPC is used to call * * ActivityTaskManagerService (ATMS) * *.
ATMS is a remote service that needs to be obtained through ServiceManager. The ServiceManager at the bottom of ServiceManager finally calls the ServiceManager at the Native layer. It is the guardian service of Binder. It can obtain the system services registered when the Android system is started, including ATMS mentioned here. The code for obtaining the service is as follows:
//ActivityTaskManager.java public static IActivityTaskManager getService() { return IActivityTaskManagerSingleton.get(); } @UnsupportedAppUsage(trackingBug = 129726065) private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() { @Override protected IActivityTaskManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);// Note 1 return IActivityTaskManager.Stub.asInterface(b); //Note 2 } };
In note 1, obtain the corresponding system service through the ServiceManager, that is, the ATMS reference of IBinder type. In Note 2, convert it into an object of ActivityTaskManager type. This code uses AIDL, iaactivitytaskmanager The Java class is automatically generated by the AIDL tool at compile time, iaactivitytaskmanager The file path of AIDL is frameworks / base / core / Java / Android / APP / iactivitytaskmanager AIDL. To realize inter process communication, the server, that is, ATMS, only needs to inherit iactivitytaskmanager Stub class and implement the corresponding methods. This completes the process of Launcher requesting ATMS. Let's look at a sequence diagram to review the whole process.
Calling procedure from ATMS to ApplicationThread
Explain the process from Launcher to ATMS. Next, we need to understand the process from ATMS to ApplicationThread. First of all, it should be clear that ATMS runs in the system server process, not in the application process. At this time, our application process has not been up yet. Go on
//ActivityTaskManagerService.java 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()); }
The startActivityAsUser method will be called in ATMS. It should be noted that the startActivityAsUser method has one more parameter than startActivity, userhandle Getcallinguserid(), ATMS judges the caller's permission based on this parameter.
//ActivityTaskManagerService.java public 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*/); } 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) { // Note 1 enforceNotIsolatedCaller("startActivityAsUser"); //Note 2 userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser, Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser"); // Note 3 return getActivityStartController().obtainStarter(intent, "startActivityAsUser") .setCaller(caller) .setCallingPackage(callingPackage) .setResolvedType(resolvedType) .setResultTo(resultTo) .setResultWho(resultWho) .setRequestCode(requestCode) .setStartFlags(startFlags) .setProfilerInfo(profilerInfo) .setActivityOptions(bOptions) .setMayWait(userId) //Here mrrequest mayWait = true .execute(); }
In note 1, judge whether the caller process is isolated. If it is isolated, a SecurityException exception will be thrown.
In Note 2, check whether the caller has permission. If not, a SecurityException exception will be thrown.
Note 3 shows that an ActivityStarter is obtained through the ActivityStartController and some parameters are configured. Here, note that the setMayWait method passes in the userId, and the mayWait property of the ActivityStarter will be set to true, which will be used later.
Activity starter is a newly added class in Android 7.0. It is a control class for loading activities. It will collect all logic to decide how to convert Intent and Flags into activities, and associate activities with tasks and stacks. The next step is to enter the logic in the ActivityStarter.
//ActivityStarter.java int execute() { try { //Here is true. Enter the if statement if (mRequest.mayWait) { return startActivityMayWait(mRequest.caller, mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid, 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, mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart); } ... } finally { onExecutionComplete(); } } private int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, int requestRealCallingPid, int requestRealCallingUid, 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, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { // File descriptors are not allowed in intent if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } ··· // Parse Intent ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0 /* matchFlags */, computeResolveFilterUid( callingUid, realCallingUid, mRequest.filterCallingUid)); ··· // Analyze the Activity information. When there are multiple choices, a selection box pops up here ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo); synchronized (mService.mGlobalLock) { ··· // Start Activity int res = 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, originatingPendingIntent, allowBackgroundActivityStart); ··· return res; } } 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, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { ··· // An ActivityRecord object is created here. ActivityRecord is used to describe an Activity and record all the information of the Activity // appToken will be built through ActivityRecord and intent at the same time ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid, callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null, mSupervisor, checkedOptions, sourceRecord); if (outActivity != null) { outActivity[0] = r; } ...... final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity);//4 ..... return res; }
startActivity calls the overload of another startActivity, and then calls the startActivityUnchecked method.
//ActivityStarter.java private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) { // Set the initial state value, where r is assigned to mStartActivity setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor); // Calculate the Flag bit Flag of the start task // It mainly deals with some Intent Flag conflicts and reuse problems // And the processing of SingleInstance and SingleTask computeLaunchingTaskFlags(); // Calculate sourceTask through sourceActivity // It mainly deals with FLAG_ACTIVITY_NEW_TASK problem computeSourceStack(); mIntent.setFlags(mLaunchFlags); // Look for activity records that can be reused ActivityRecord reusedActivity = getReusableIntentActivity(); ··· if (mReusedActivity != null) { ··· // Move the current stack to the foreground mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity); ··· setTaskFromIntentActivity(mReusedActivity); if (!mAddingToTask && mReuseTask == null) { resumeTargetStackIfNeeded(); return START_TASK_TO_FRONT; } } ··· //Processing of singleTop or singleInstance if (dontStart) { // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; if (mDoResume) { mRootActivityContainer.resumeFocusedStacksTopActivities(); } ActivityOptions.abort(mOptions); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and the client said not to do // anything if that is the case, so this is it! return START_RETURN_INTENT_TO_CALLER; } ··· // Distribute a new Intent to an existing Activity // Will call back its onNewIntent() method deliverNewIntent(top); ··· return START_DELIVERED_TO_TOP; } boolean newTask = false; final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null) ? mSourceRecord.getTaskRecord() : null; // Set the corresponding task int result = START_SUCCESS; if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) { newTask = true; // intent set FLAG_ACTIVITY_NEW_TASK, new task result = setTaskFromReuseOrCreateNewTask(taskToAffiliate); } else if (mSourceRecord != null) { // Set the stack where sourceRecord is located, that is, the standard startup mode result = setTaskFromSourceRecord(); } else if (mInTask != null) { // Specify the taskAffinity to start and set it to the corresponding task result = setTaskFromInTask(); } else { // This does not happen if you start in the task in the current focus result = setTaskToCurrentTopOrCreateNewTask(); } if (result != START_SUCCESS) { return result; } ··· // mDoResume is passed in from outside, which is true in this process if (mDoResume) { // Use the ActivityStaskSupervisor to display the Activity final ActivityRecord topTaskActivity = mStartActivity.getTaskRecord().topRunningActivityLocked(); if (!mTargetStack.isFocusable() || (topTaskActivity != null && topTaskActivity.mTaskOverlay && mStartActivity != topTaskActivity)) { mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS); mTargetStack.getDisplay().mDisplayContent.executeAppTransition(); } else { // If the current activity can get the focus, but the current Stack does not get the focus if (mTargetStack.isFocusable() && !mRootActivityContainer.isTopDisplayFocusedStack(mTargetStack)) { // Move the corresponding Task to the foreground mTargetStack.moveToFront("startActivityUnchecked"); } // Make the activity at the top of the stack visible, that is, the resume state mRootActivityContainer.resumeFocusedStacksTopActivities( mTargetStack, mStartActivity, mOptions); } } else if (mStartActivity != null) { mSupervisor.mRecentTasks.add(mStartActivity.getTaskRecord()); } mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack); mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(), preferredWindowingMode, mPreferredDisplayId, mTargetStack); return START_SUCCESS; }
The startActivityUnchecked method mainly deals with the logic related to branch management. In the previous analysis, we set Flag to Flag when setting_ ACTIVITY_ NEW_ Task, that is, it will execute settaskfromreuseorcreatewtask, and a new TaskRecord will be created to describe the activity task stack. Activity money is actually an imaginary model, which does not really exist. Then resumeFocusedStacksTopActivities will be called, and the Activity in the resumeFocusedStacksTopActivities method will be called ActivityStack#resumeTopActivityUncheckedLocked to start the top of the stack.
// ActivityStack.java boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { if (mInResumeTopActivity) { // Don't even start recursing. return false; } boolean result = false; try { // Protect against recursion. Prevent recursion and ensure that only one Activity executes the method mInResumeTopActivity = true; result = resumeTopActivityInnerLocked(prev, options); final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */); if (next == null || !next.canTurnScreenOn()) { checkReadyForSleep(); } } finally { mInResumeTopActivity = false; } return result; }
mInResumeTopActivity = true; Used to ensure that only one Activity at a time performs the resumeTopActivityUncheckedLocked() operation. Then call topRunningActivityLocked
// ActivityStack.java private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { ··· // Get the un finish ed activity at the top of the stack ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */); ··· if (next.attachedToProcess()) { ··· } else { ··· mStackSupervisor.startSpecificActivityLocked(next, true, true); } }
The logic of the resumetoperactivityinnerlocked method is very complex. It is mainly to judge whether the resume stack top activity is really needed at present. It is simplified here. When our top stack activity is not bound to any Application, it will call ActivityStackSupervisor#startSpecificActivityLocked. This is exactly the case at this time.
// ActivityStackSupervisor.java void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Obtain the WindowProcessController object of the target process through ATMS // WindowProcessController is used to synchronize process status between ActivityManager and WindowManager // If wpc is empty, the corresponding process does not exist or is not started final WindowProcessController wpc = mService.getProcessController(r.processName, r.info.applicationInfo.uid); boolean knownToBeDead = false; // The hashthread here represents the iaapplicationthread if (wpc != null && wpc.hasThread()) { try { // Start activity realStartActivityLocked(r, wpc, 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. knownToBeDead = true; } // This mainly deals with the keyboard lock problem if (getKeyguardController().isKeyguardLocked()) { r.notifyUnknownVisibilityLaunched(); } try { ··· // If the corresponding App process has not been started // Start the process by sending a message through the handler final Message msg = PooledLambda.obtainMessage( ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName, r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent()); mService.mH.sendMessage(msg); } finally { Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } }
Here we know that if our application process is not started, we need to start the application process by sending a message. We won't talk about this part of the process here. The statement that actually starts the Activity is the method realStartActivityLocked()
// ActivityStackSupervisor.java boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException { ··· // Create a start Activity transaction final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.appToken); final DisplayContent dc = r.getDisplay().mDisplayContent; // Add the Callback. Note that the LaunchActivityItem is created here 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, proc.getReportedProcState(), r.icicle, r.persistentState, results, newIntents, dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(), r.assistToken)); // Set the final state that this transaction should execute // This process will be set to resume, indicating that the activity should be executed to onResume final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward()); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // Execute transaction mService.getLifecycleManager().scheduleTransaction(clientTransaction); ··· return true; }
A start Activity transaction is created in the realStartActivityLocked method and sent to the target App using iaapplicationthread. Starting from Android 8.0, the start of Activity will be completed through transactions, which will be remotely sent to the target App through the iaapplicationthread of the target App, and then executed through clientllifecycle manager. At this point, the logic executed in ATMS is over, and the rest is the ApplicationThread of the target App to execute each life cycle method of the target Activity.
ActivityThread starts the Activity process
After a series of calls, the start of Activity comes to the target App.
As we know from the above, this process starts from the transaction passed by Binder communication received by ApplicationThread. ApplicationThread#scheduleTransaction calls ActivityThread#scheduleTransaction. Let's look directly at the scheduleTransaction function of ActivityThread
// ActivityThread.java @Override public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { ActivityThread.this.scheduleTransaction(transaction); }
The ActivityThread#scheduleTransaction method is defined in its parent class ClientTransactionHandler.
//ClientTransactionHandler.java void scheduleTransaction(ClientTransaction transaction) { transaction.preExecute(this); sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); }
Here, the sendMessage method is called to send a what is activitythread to the main thread H.EXECUTE_ Transaction and deliver the transaction.
ApplicationThread runs in Binder thread, and communication with ActivityThread needs to go through Handler. H is an internal class in ActivityThread, which inherits from Handler. When ActivityThread calls sendMessage method, it is actually calling H#sendMessage.
//ActivityThread.java 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 is an instance of class H mH.sendMessage(msg); }
If mH sends a message, it will be received and processed in the handlerMessage of class h, so we can take a look at the handlerMessage method of class H
//ActivityThread.H.java public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { // Omit some case s ··· 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; // Omit some case s ··· } Object obj = msg.obj; if (obj instanceof SomeArgs) { ((SomeArgs) obj).recycle(); } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what)); }
Where TransactionExecutor#execute is used to execute transactions.
TransactionExecutor is a class dedicated to processing transactions to ensure that transactions are executed in the correct order.
//TransactionExecutor.java public void execute(ClientTransaction transaction) { if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction"); // appToken in ActivityRecord final IBinder token = transaction.getActivityToken(); ··· if (DEBUG_RESOLVER) Slog.d(TAG, transactionToString(transaction, mTransactionHandler)); // Execute all callbacks executeCallbacks(transaction); // Execute to corresponding lifecycle executeLifecycleState(transaction); mPendingActions.clear(); if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction"); }
Previously, we created a transaction in the ActivityStackSupervisor and added it to the ClientTransaction by addCallback. Now we call executeCallbacks to execute each Callback.
//TransactionExecutor.java public void executeCallbacks(ClientTransaction transaction) { final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); if (callbacks == null || callbacks.isEmpty()) { // Fast return path return; } ... // Execute the extract of each item in a loop for (int i = 0; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item); final int postExecutionState = item.getPostExecutionState(); final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r, item.getPostExecutionState()); if (closestPreExecutionState != UNDEFINED) { // This method can smooth the execution life cycle cycleToPath(r, closestPreExecutionState, transaction); } // Execute the item's execute method item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); ... } }
In the previous section, we know that the ClientTransactionItem created when starting the Activity is * * LaunchActivityItem * *, and its execute method will be executed later. So let's take a look at the implementation of the execute method in LaunchActivityItem
//LaunchActivityItem.java @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, mAssistToken); // Handle matters before starting an Activity client.handleLaunchActivity(r, pendingActions, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }
client is ActivityThread. In the method, ActivityThread#handleLaunchActivity is called to start Activity.
//ActivityThread.java public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { ··· // Initialize WindowManager WindowManagerGlobal.initialize(); ··· // Start Activity final Activity a = performLaunchActivity(r, customIntent); ··· return a; }
The core code started by the Activity is in the performLaunchActivity method.
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ··· // Create the context in which you want to start the Activity ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { // Create the Activity instance with the class loader, that is, through reflection java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); 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 { // Create Application instance Application app = r.packageInfo.makeApplication(false, mInstrumentation); ··· if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); 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; } appContext.setOuterContext(activity); // Call activity Initialize attach // Establish the connection between Context and Activity, and Window will be created here 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, r.assistToken); ··· // Callback onCreate if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onCreate()"); } r.activity = activity; } // Update LifeCycle status r.setState(ON_CREATE); ··· return activity; }
At this point, the Activity has been successfully created and its life cycle related methods have been executed.
The above is the start process of the whole root Activity.
summary
Corresponding to the first figure above, the startup of the root Activity involves a total of four processes. Launcher process, SystemServer process, Zygote process, and application process.
First, the Launcher process will request ATMS to create an Activity, and ATMS will judge whether the application process required by the root Activity exists and start it. If it does not exist, the Zygote process is requested to create an application process. After the application process starts, ATMS will request the application process to create a root Activity and start it. Step 1 is cross process communication through Binder, step 2 is communication through socket, and step 4 is Binder communication.
reference resources:
1. Android advanced decryption
2,Activity start process