preface
As one of the four components of Android, Activity is definitely not that easy to start. Here involves the system service process, the startup process is a lot of details, here I only show the main process. As versions change, code details have been changed, each time there are big changes, such as Android5.0, Android8.0. My version here is based on Android API28, which is the latest source code I can check at present. In fact, the process is the same, master a version, the other version through the source code can also be quickly mastered.
Because it involves communication between different processes: system server processes and local processes, AIDL is used in the latest version of Android to communicate across processes. So you need to have some understanding of AIDL to help you understand the startup process.
The source code part of the explanation involves a lot of code explanation, may be a little uncomfortable, but still recommended to read the source code. Key source code I will add comments, easy to understand.
The code doesn’t focus too much on the details, just the overall flow. Want to know the details can go to the source code. The path of each code will be marked out in front of the code, you can go to see the corresponding source.
Before each part of the source I will put a flow chart, be sure to eat with a flow chart, otherwise it may be messy.
Overview of the overall process
This section focuses on an overview of the startup process, with a general idea in mind to help you understand the details of the process below.
Creation of a normal Activity
Normal Activity creation is how we normally create an Activity in our code using the startActivity(Intent Intent) method. The overall process is shown as follows:
The startup process is designed for two processes: the local process and the system service process. The local process is the process where our application resides. The system server process is shared by all applications. The overall idea is:
-
The activity requests creation of the Instrumentation
-
Instrumentation accesses AMS through the IBinder interface of AMS in the local process, where the cross-process technology used is AIDL.
-
The AMS process then performs a series of tasks, such as determining whether the activity exists, what startup mode it is in, whether it is registered, and so on.
-
With ClientLifeCycleManager, the local process accesses the local ActivityThread directly on the IBinder interface of the system server process.
ApplicationThread is an internal class of ActivityThread, which is the Binder interface on the remote server
-
When ApplicationThread receives a transaction from the server, it forwards the transaction directly to ActivityThread for processing.
-
The ActivityThread uses the Instrumentation class loader to create instances, and the Instrumentation callback to the activity lifecycle
There are two processes involved. The local process is responsible for creating the activity and the callback life cycle, and the service process is responsible for determining whether the activity is legitimate, whether the activity stack needs to be created, and so on. Process communication is involved between processes: AIDL. (If you are not familiar with it, you can learn about it first, but it can be simply understood as interface callback.)
Here are a few key classes:
-
Instrumentation is a class for activities that are associated with the outside world (not the outside world for activities themselves, relative to activities). Activities are created by Instrumentation, The ActivityThread uses Instrumentation to create activities and call activity lifecycles.
-
Activitythreads, a single instance of each application, are responsible for managing Activity creation, whereas ApplicationThreads are simply classes that communicate between applications and server processes, handing the task of AMS to ActivityThreads.
-
AMS, full name for ActivityManagerService, is responsible for coordinating the process created by the server for an activity.
Other classes, the following source code analysis will be explained in detail.
Creation of the root Activity
The root Activity is the process that starts the first Activity in the application when we click on the desktop icon. Here I focus on the relationship between multiple processes, the source code below will not talk about details, only explain the creation process of ordinary activities. This is also a supplement. First look at the overall flow chart:
There are four main processes involved:
- The Launcher process, also known as the desktop process
- System service process, the process where AMS resides
- Zygote process, responsible for creating processes
- The application process, that is, the process to be started
Main process:
- The Launcher process asks AMS to create an activity
- AMS asks Zygote to create the process.
- Zygote creates the process by forking itself. And notify AMS that creation is complete.
- AMS tells the application process to create the root Activity.
Much like normal Activity creation, the main step is to create a process.
The source code to explain
Activity Requests the AMS process
The flow chart
The source code
-
The system starts the application by calling the startActivitySafely method of the Launcher. Launcher is a class that starts the root Activity.
This step is only available for the root Activity startup process, which is not available for normal startup, but is put here as a supplement
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java/; public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { // The method of the parent class is called boolean success = super.startActivitySafely(v, intent, item); .return success; } Copy the code
packages/apps/Launcher3/src/com/android/launcher3/BaseDraggingActivity.java/; public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {...// Prepare intent // Set the flag "singleTask", which means open 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(); // Comments 1 and 2 are directly started with startActivity. Comment 1 does some setting //BaseDraggingActivity inherits from BaseActivity, and BaseActivity inherits from Activity // Jump directly to the startActivity logic of the Activity. if (isShortcut) { // Shortcuts need some special checks due to legacy reasons. startShortcutIntentSafely(intent, optsBundle, item);/ / 1 } else if (user == null || user.equals(Process.myUserHandle())) { // Could be launching some bookkeeping activity startActivity(intent, optsBundle);/ / 2 } else { LauncherAppsCompat.getInstance(this).startActivityForProfile( intent.getComponent(), user, intent.getSourceBounds(), optsBundle); }... }...return false; } Copy the code
-
Activity Starts an Activity with Instrumentation
/frameworks/base/core/java/android/app/Activity.java/; public void startActivity(Intent intent, @Nullable Bundle options) { // Eventually jump to the startActivityForResult method 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) { //mParent refers to activityGroup, which is now Fragment and will always be null . / / the next step will pass mInstrumentation execStartActivity to start if (mParent == null) { options = transferSpringboardActivityOptions(options); Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);/ / 1 if(ar ! =null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); }... }... }Copy the code
-
Instrumentation asks AMS to start. The purpose of this class is to monitor application and system interactions. At this point, AMS is left to perform a number of processes, and AMS starts the activity with a callback through its local interface, IActivityManager.
/frameworks/base/core/java/android/app/Instrumentation.java/; public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {...// This is a complicated place. I'll explain it again / / ActivityManager. GetService () access to the object is ActivityManagerService, hereinafter referred to as the AMS // Start the activity with AMS. AMS is globally unique, and all activity starts are authenticated by it, running in a separate process // The AIDL approach is used for cross-process communication. The object is actually an IBinder interface // Comment 2 checks the startup result and throws an exception, such as no registration. try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); intresult = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null, requestCode, 0.null, options);/ / 1 checkStartActivityResult(result, intent);/ / 2 } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } return null; } Copy the code
This step is cross-communication via AIDL technology. Get the AMS proxy object and hand off the startup task to AMS.
/frameworks/base/core/java/android/app/ActivityManager.java/; / / the singleton class public static IActivityManager getService(a) { return IActivityManagerSingleton.get(); } private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() { @Override protected IActivityManager create(a) { // get the AMS IBinder interface final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); // Convert to an IActivityManager object. The remote service implements this interface, so you can call this directly //AMS proxy object interface method to request AMS. The technique used here is AIDL final IActivityManager am = IActivityManager.Stub.asInterface(b); returnam; }};Copy the code
AMS processes requests
The flow chart
The source code
-
Let’s look at the implementation logic of AMS. The source code for AMS is to create an ActivityStarter with the ActivityStartController and hand the logic to the ActivityStarter. ActivityStarter is a class added to Android 7.0.
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java/; // Jump to startActivityAsUser / / attention to last more than a parameter UserHandle getCallingUserId (), said the caller 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()); } 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) { enforceNotIsolatedCaller("startActivity"); userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser, Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser"); // TODO: Switch to user app stacks here. // Get the ActivityStarter from ActivityStartController // Perform the startup task. This gives the task logic to the AcitivityStarter 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
ActivityStartController get ActivityStarter
/frameworks/base/services/core/java/com/android/server/am/ActivityStartController.java/; // Get the ActivityStarter object. This object is used only once and is invalidated after its execute is executed ActivityStarter obtainStarter(Intent intent, String reason) { return mFactory.obtain().setIntent(intent).setReason(reason); } Copy the code
-
This part is mainly the source content of ActivityStarter, involving a lot of source code. AMS leaves the entire startup logic to ActivityStarter. It mainly does pre-boot processing, creating processes and so on.
/frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java/; // The startActivityMayWait method is used int execute(a) { try{...if (mRequest.mayWait) { returnstartActivityMayWait(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); }... }... }// Start preprocessing 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) {.../ / jump startActivity final ActivityRecord[] outRecord = new ActivityRecord[1]; 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); } // Records information about the start process and activity 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) {...// Get the Launcher process ProcessRecord callerApp = null; if(caller ! =null) { callerApp = mService.getRecordForAppLocked(caller); . }...// Record the activity information obtained ActivityRecord r = newActivityRecord(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; }... mController.doPendingActivityLaunches(false); // Continue to jump return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, outActivity); } / / jump startActivityUnchecked 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(); / / jumpresult = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, outActivity); }...return result; } // Do stack related logic and jump to ActivityStackSupervisor for processing private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity) {...int result = START_SUCCESS; // This is related to our initial Launcher flag, FLAG_ACTIVITY_NEW_TASK, which creates a new stack if (mStartActivity.resultTo == null && mInTask == null&&! mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) ! =0) { newTask = true; result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack); }...if (mDoResume) { final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked(); if(! mTargetStack.isFocusable() || (topTaskActivity ! =null&& topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) { ... }else { if(mTargetStack.isFocusable() && ! mSupervisor.isFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked"); } // Jump to ActivityStackSupervisor for processingmSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); }}}Copy the code
-
The ActivityStackSupervisor is responsible for the activity stack and works in conjunction with ActivityStack. Determine the status of the activity, such as whether it is on the top of the stack or stopped
/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java/; boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {...// Determine whether the activity to be started is in the stopped or Resume state 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
-
ActivityStack deals primarily with the state of activities in the stack
/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java/; / / jump resumeTopActivityInnerLocked 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; / / jump resumeTopActivityInnerLockedresult = resumeTopActivityInnerLocked(prev, options); . }finally { mStackSupervisor.inResumeTopActivity = false; } return result; } / / jump to StackSupervisor startSpecificActivityLocked, note 1 @GuardedBy("mService") private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {...if(next.app ! =null&& next.app.thread ! =null) {... }else{... mStackSupervisor.startSpecificActivityLocked(next,true.true);/ / 1 } if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } Copy the code
-
Here we go back to the ActivityStackSupervisor to determine if the process has been created and has not thrown an exception. The transaction is then created and handed back to local execution. The transaction is the key here. The Activity performs the work of this transaction, and the content of the transaction is the item inside it, so pay attention to the following two items.
/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java/; void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Get the process in which the activity is to be started ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true); getLaunchTimeTracker().setLaunchTime(r); // Check whether the process is started, jump to realStartActivityLocked, and start the activity if(app ! =null&& app.thread ! =null) { try { if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 || !"android".equals(r.info.packageName)) { app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode, mService.mProcessStats); } realStartActivityLocked(r, app, andResume, checkConfig);/ / 1 return; }... } mService.startProcessLocked(r.processName, r.info.applicationInfo,true.0."activity", r.intent.getComponent(), false.false.true); } // Create transactions for local execution final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException {...// Create the ClientTransaction object that starts the activity // Create activity launch transaction. final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread, r.appToken); // Add the LaunchActivityItem, which creates the activity 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. // Add the Resume transaction ResumeActivityItem that will be executed locally final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward()); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // Start the transaction through ClientLifecycleManager // here the mService is AMS // Remember the two items above: LaunchActivityItem and ResumeActivityItem, which are the execution units of the transaction // Schedule transaction. mService.getLifecycleManager().scheduleTransaction(clientTransaction); } Copy the code
Get ClientLifecycleManager from AMS
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java/; // Get ClientLifecycleManager from AMS ClientLifecycleManager getLifecycleManager(a) { return mLifecycleManager; } Copy the code
-
ClientLifecycleManager is a transaction management class that is responsible for executing transactions
/frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java void scheduleTransaction(ClientTransaction transaction) throws RemoteException { final IApplicationThread client = transaction.getClient(); // Execute a transaction transaction.schedule(); if(! (clientinstanceofBinder)) { transaction.recycle(); }}Copy the code
-
Delegate transactions to the local ActivityThread for execution. Cross-process communication is done through the local ApplicationThread interface on the server, IApplicationThread. The logic then goes back to the application process.
/frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java/; // IApplicationThread is the IBinder interface to start the process //ApplicationThread is an internal class of ActivityThread. IApplicationThread is the IBinder proxy interface // Execute the logic locally private IApplicationThread mClient; public void schedule(a) throws RemoteException { mClient.scheduleTransaction(this); } Copy the code
ActivityThread Creates an Activity
The flow chart
The source code
-
The internal class ApplicationThread of ActivityThread, the native implementation of the IApplicationThread interface
/frameworks/base/core/java/android/app/ActivityThread.java/ApplicationThread.class/; // Jump to the ActivityThread method implementation public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { ActivityThread.this.scheduleTransaction(transaction); } Copy the code
-
ActivityThread performs transactions. ActivityThread inherits from ClientTransactionHandler, where scheduleTransaction is implemented. The main thing here is to send the transaction to the inner class H of the ActivityThread for execution. H is a Handle that cuts to the main thread to execute logic.
/frameworks/base/core/java/android/app/ClientTransactionHandler.java void scheduleTransaction(ClientTransaction transaction) { // Transaction preprocessing transaction.preExecute(this); // The Handle mechanism can be used to switch threads The concrete implementation of this method is in ActivityThread, which is an abstract method of ClientTransactionHandler sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); } /frameworks/base/core/java/android/app/ActivityThread.java/; final H mH = new H(); 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); } // Use Handle to switch. MH is an instance of the class H mH.sendMessage(msg); } Copy the code
-
H Processes transactions. The transaction pool is called to process the transaction
/frameworks/base/core/java/android/app/ActivityThread.java/H.class // Call the transaction pool to process the transaction public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { ... case EXECUTE_TRANSACTION: final ClientTransaction transaction = (ClientTransaction) msg.obj; // Call the transaction pool to process the transaction mTransactionExecutor.execute(transaction); if (isSystem()) { transaction.recycle(); } // TODO(lifecycler): Recycle locally scheduled transactions. break; . }... }Copy the code
-
Transaction pooling processes transactions. The transaction pool takes the two items of the transaction and executes them separately. These two transactions are the two items I mentioned above. Corresponding to different initialization tasks.
/frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java public void execute(ClientTransaction transaction) { final IBinder token = transaction.getActivityToken(); log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token); // Execute a transaction // These two transactions are the two events added to ActivityStackSupervisor at that time (step 8) // Comment 1 performs the creation of the activity, comment 2 performs the activity window and so on and calls the onStart and onResume methods // Focus on the process in comment 1 executeCallbacks(transaction);/ / 1 executeLifecycleState(transaction);/ / 2 mPendingActions.clear(); log("End resolving transaction"); } public void executeCallbacks(ClientTransaction transaction) {...// Execute a transaction // This is the same item that was added. Remember which item it was? // LaunchActivityItemitem.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); . }private void executeLifecycleState(ClientTransaction transaction) {...// As above, execute the item in the transaction. The item type is ResumeActivityItem lifecycleItem.execute(mTransactionHandler, token, mPendingActions); lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions); } Copy the code
-
LaunchActivityItem calls ActivityThread to perform the create logic.
/frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java/; 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); // ClientTransactionHandler is the interface implemented by ActivityThread, and the logic goes back to ActivityThread client.handleLaunchActivity(r, pendingActions, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } Copy the code
-
ActivityThread performs the creation of the Activity. Instrumentation is used primarily to create activities and callback activity lifecycles, and to create activity contexts and app contexts (if not already created).
/frameworks/base/core/java/android/app/ActivityThread.java/; public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {...// Jump to performLaunchActivity finalActivity a = performLaunchActivity(r, customIntent); . }// Use Instrumentation to create the activity callback lifecycle private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // Get ActivityInfo, user stored code, AndroidManifes information. ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { // Get the APK description class r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } // Get the package name type information for the activity ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); }...// Create context ContextImpl appContext = createBaseContextForActivity(r); / / create the activity Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); // Create an activity with Instrumentation 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); }}...try { // Create an Application based on the package name Application app = r.packageInfo.makeApplication(false, mInstrumentation); .// Add window to the Activity Window window = null; if(r.mPendingRemoveWindow ! =null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; } appContext.setOuterContext(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); }...// Call back the onCreate method of the Activity with Instrumentation ctivity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else{ mInstrumentation.callActivityOnCreate(activity, r.state); }}Copy the code
So let’s dig a little deeper and see when onCreate is called
/frameworks/base/core/java/android/app/Instrumentation.java/; public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) { prePerformCreate(activity); // Calls the activity's performCreate method activity.performCreate(icicle, persistentState); postPerformCreate(activity); } /frameworks/base/core/java/android/app/Activity.java/; final void performCreate(Bundle icicle, PersistableBundle persistentState) { mCanEnterPictureInPicture = true; restoreHasCurrentPermissionRequest(icicle); // the onCreate method is called if(persistentState ! =null) { onCreate(icicle, persistentState); } else{ onCreate(icicle); }... }Copy the code
-
Instrumentation uses the class loader to create an activity instance
/frameworks/base/core/java/android/app/Instrumentation.java/; public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { String pkg = intent ! =null&& intent.getComponent() ! =null ? intent.getComponent().getPackageName() : null; // Instantiate with AppComponentFactory return getFactory(pkg).instantiateActivity(cl, className, intent); } Copy the code
-
The last step is to create the instance through the AppComponentFactory factory.
/frameworks/support/compat/src/main/java/androidx/core/app/AppComponentFactory.java / / it is equivalent to return instantiateActivityCompat directly public final Activity instantiateActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return checkCompatWrapper(instantiateActivityCompat(cl, className, intent)); } // Generic methods static <T> T checkCompatWrapper(T obj) { if (obj instanceof CompatWrapped) { T wrapper = (T) ((CompatWrapped) obj).getWrapper(); if(wrapper ! =null) { returnwrapper; }}return obj; } // This is the end. Instantiation using class loaders. This completes the start of the activity. public @NonNull Activity instantiateActivityCompat(@NonNull ClassLoader cl, @NonNull String className, @Nullable Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { try { return (Activity) cl.loadClass(className).getDeclaredConstructor().newInstance(); } catch (InvocationTargetException | NoSuchMethodException e) { throw new RuntimeException("Couldn't call constructor", e); }}Copy the code
summary
Above through the overall process and code detailed analysis of an activity when the overall process. What is the use of this knowledge, readers may wonder? I don’t need it everyday. When you go through the whole process, you will find that you have a deeper understanding of Android and will be more confident in the face of development. Some bugs may take others a long time to solve, but you can solve them quickly. In addition, this part of the content in the plug-in also has a great use, is to learn the knowledge of plug-in.
Well, with all that said, I hope it was helpful. If you have any questions, please feel free to comment or send a private message. In addition, the blogger is new to Android, if there is something wrong, please correct it.
reference
- Android Advanced Decryption
- Exploring the Art of Android Development
- Android Advanced (4) : Activity startup process (most detailed & Easiest)