Activity overview
There are four components in Android: Activity, Service, BroadcastReceiver and ContentProvider. The Activity that we most often contact and users directly feel is Activity. Today, let's talk about the execution process and working principle of Android startup.
Activity is a presentation component, which is used to show users a page that can interact. Activity is the most important component in Android. For users, all activities are the whole of an App, while users of other components cannot directly perceive it. At the development level, to start an activity, you can use Intent, explicit and implicit, and you can also set the startup mode of the activity.
The Android system encapsulates the four components to a great extent, so that we can use the components quickly. After the system is encapsulated, the startup of activity becomes very simple. The startup activity code is shown as follows:
Intent intent = new Intent(this, TestActivity.class); this.startActivity(intent);
So you can start TestActivity. Then the problem comes,
- How does this code start an Activity?
- What's going on inside?
- onCreate when are these lifecycles executed?
- When was the Activity object created?
- How are views handled and when are they visible?
So why do we need to understand these problems? I don't understand. There seems to be no problem with development at ordinary times. In fact, it is not. After solving these problems, you will have a deeper understanding of the Android system and learn the excellent design of the system source code. It is necessary to solve some advanced technical problems. This requires us to sort out these problems by reading the source code, but on the other hand, the system source code is very large and complex. We need to grasp the main process with the problem and not fall into the code details - this is the correct posture for reading the system source code and other third-party library source codes.
Process analysis
Activity initiated
Now let's sort out the workflow of Activity to master the overall process of Activity. Starting from the startActivity method, you will go to the startActivityForResult method:
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); if (ar != null) { mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData()); } if (requestCode >= 0) { mStartedActivity = true; } cancelInputsAndStartExitTransition(options); } else { ... } }
I see that mminstrumentation. Is called inside Execstartactivity method, one of the parameters mmainthread Getapplicationthread(), whose type is ApplicationThread. ApplicationThread is the internal class of ActivityThread and inherits iaapplicationthread Stub, also a Binder object, plays an important role in the activity workflow. Instrumentation has the function of tracking the application and activity life cycle, which is used for code detection in android application testing framework. Then take a look at Mi instrumentation Execstartactivity method:
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; Uri referrer = target != null ? target.onProvideReferrer() : null; if (referrer != null) { intent.putExtra(Intent.EXTRA_REFERRER, referrer); } ... try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); int result = 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; }
Here you can see that the activation of the Activity is handed over to the activitymanager Getservice (), what is this? Follow in:
public static IActivityManager getService() { return IActivityManagerSingleton.get(); } private static final Singleton IActivityManagerSingleton = new Singleton() { @Override protected IActivityManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); final IActivityManager am = IActivityManager.Stub.asInterface(b); return am; } };
After seeing this, you should understand that this is to obtain a cross process service. Then let's take a look at the famous ActivityManagerService class
public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback
ActivityManagerService inherits IActivityManager Stub actually inherits Binder and implements the Binder interface of IActivityManager. AMS is also a Binder, which is the collective implementation of IActivityManager. So activitymanager The Binder object obtained by getservice () is implemented in ActivityManagerService(AMS) and provides services through singleton.
Then the activitymanager getService(). Startactivity has a return value result, and checkStartActivityResult(result, intent) is called:
public static void checkStartActivityResult(int res, Object intent) { if (!ActivityManager.isStartResultFatalError(res)) { return; } switch (res) { case ActivityManager.START_INTENT_NOT_RESOLVED: case ActivityManager.START_CLASS_NOT_FOUND: if (intent instanceof Intent && ((Intent)intent).getComponent() != null)throw new ActivityNotFoundException("Unable to find explicit activity class "+ ((Intent)intent).getComponent().toShortString()+ "; have you declared this activity in your AndroidManifest.xml?"); throw new ActivityNotFoundException("No Activity found to handle " + intent); case ActivityManager.START_PERMISSION_DENIED: throw new SecurityException("Not allowed to start activity "+ intent); ... case ActivityManager.START_CANCELED: throw new AndroidRuntimeException("Activity could not be started for "+ intent); default: throw new AndroidRuntimeException("Unknown error code "+ res + " when starting " + intent); } }
This is used to check the result of Activity startup. If a fatal error occurs, the corresponding exception will be thrown. Have you declared this Activity in your androidmanifest is thrown in the first case xml?—— This error occurs if the Activity is not registered in the Manifest.
Activity management - AMS
Well, here, the start of the Activity is transferred to the service AMS provided by the system process. Then look at the startActivity of AMS:
1 @Override2 public int startActivity(IApplicationThread caller, String callingPackage,3 Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,4 int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {5 return mActivityTaskManager.startActivity(caller, callingPackage, intent, resolvedType,6 resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);7 }
AMS transfers the startup to the Activity task manager service (ATMS), which is used to manage the system services of the Activity and its containers (tasks, stacks, displays, etc.). Then look at:
//ActivityTaskManagerService @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()); } @Override 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) { enforceNotIsolatedCaller("startActivityAsUser"); userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser"); // TODO: Switch to user app stacks here. return getActivityStartController().obtainStarter(intent, "startActivityAsUser").setCaller(caller).setCallingPackage(callingPackage).setResolvedType(resolvedType).setResultTo(resultTo).setResultWho(resultWho).setRequestCode(requestCode).setStartFlags(startFlags).setProfilerInfo(profilerInfo).setActivityOptions(bOptions).setMayWait(userId).execute(); } }
Follow to startActivityAsUser through getactivitystartcontroller() The obtainStarter method takes the ActivityStarter instance and then calls a series of methods. The last execute() method is to start activity:
int execute() { 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.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); } else { return startActivity(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,mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart); } } finally { onExecutionComplete(); } }
There are two cases, but whether startActivityMayWait or startActivity, it finally goes to the following startActivity method:
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity, boolean restrictedBgActivity) { int result = START_CANCELED; final ActivityStack startedActivityStack; try { mService.mWindowManager.deferSurfaceLayout(); result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,startFlags, doResume, options, inTask, outActivity, restrictedBgActivity); } finally { final ActivityStack currentStack = r.getActivityStack(); startedActivityStack = currentStack != null ? currentStack : mTargetStack; ... } postStartActivityProcessing(r, result, startedActivityStack); return result; }
The startActivityUnchecked method is called. The startActivityUnchecked internal calls the startActivityLocked method of ActivityStack. The startActivityLocked internal calls the ensureActivitiesVisibleLocked method. The ensureActivitiesVisibleLocked calls the makeVisibleAndRestartIfNeeded method. Let's see:
private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges, boolean isTop, boolean andResume, ActivityRecord r) { // We need to make sure the app is running if it's the top, or it is just made visible from // invisible. If the app is already visible, it must have died while it was visible. In this // case, we'll show the dead window but will not restart the app. Otherwise we could end up // thrashing. if (isTop || !r.visible) { // This activity needs to be visible, but isn't even running... // get it started and resume if no other stack in this stack is resumed. if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r); if (r != starting) { r.startFreezingScreenLocked(r.app, configChanges); } } if (!r.visible || r.mLaunchTaskBehind) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r); } r.setVisible(true); if (r != starting) { // We should not resume activities that being launched behind because these // activities are actually behind other fullscreen activities, but still required // to be visible (such as performing Recents animation). mStackSupervisor.startSpecificActivityLocked(r, andResume && !r.mLaunchTaskBehind,true /* checkConfig */); return true; } }
See the startSpecificActivityLocked method that finally called ActivityStackSupervisor:
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? final WindowProcessController wpc = mService.getProcessController(r.processName, r.info.applicationInfo.uid); boolean knownToBeDead = false; if (wpc != null && wpc.hasThread()) { try { realStartActivityLocked(r, wpc, andResume, checkConfig); return; } 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; } ... }
Then the realStartActivityLocked method is called:
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException { ... // Create activity launch transaction. final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.appToken); final DisplayContent dc = r.getDisplay().mDisplayContent; 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 desired final state. final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward()); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // Schedule transaction. mService.getLifecycleManager().scheduleTransaction(clientTransaction); ... return true; }
There is a piece of code in the middle, as above, through clientTransaction Obtain (proc.getThread(), r.apptoken) gets the clientTransaction, where the parameter proc Getthread () is iaapplicationthread, which is the proxy of ApplicationThread in the system process mentioned above.
ClientTransaction is a container containing a series of message s, which are used to send to the client, including callback methods and lifecycle states.
Next, use clienttransaction Addcallback added LaunchActivityItem instance:
//Are used to send to the client private List mActivityCallbacks; public void addCallback(ClientTransactionItem activityCallback) { if (mActivityCallbacks == null) { mActivityCallbacks = new ArrayList<>(); } mActivityCallbacks.add(activityCallback); }
Take a look at the acquisition of LaunchActivityItem instance:
/** Obtain an instance initialized with provided params. */ public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List pendingResults, List pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken) { LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); if (instance == null) { instance = new LaunchActivityItem(); } setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer, voiceInteractor, procState, state, persistentState, pendingResults, pendingNewIntents, isForward, profilerInfo, assistToken); return instance; }
new creates a LaunchActivityItem and then sets various values. We can see from the name that it is used to start the activity. How does it work? Then look at:
Return to the realStartActivityLocked method, and then call mService getLifecycleManager(). scheduleTransaction (clienttransaction), mService is the ActivityTaskManagerService mentioned earlier. Getlifecyclemanager () method obtains the clientllifecycle manager instance. Its scheduleTransaction method is as follows:
void scheduleTransaction(ClientTransaction transaction) throws RemoteException { final IApplicationThread client = transaction.getClient(); transaction.schedule(); if (!(client instanceof Binder)) { transaction.recycle(); } }
To call the schedule method of ClientTransaction, let's see:
public void schedule() throws RemoteException { mClient.scheduleTransaction(this); }
It is very simple to call the scheduleTransaction method of iaapplicationthread. Since iaapplicationthread is the proxy of ApplicationThread in the system process, the real place to execute is in the ApplicationThread of the client. In other words, the operation started by Activity is returned to the client across processes.
Well, let's sort it out a little here: the operation of starting an Activity is transferred from the client to AMS. AMS manages Activity tasks, Activity stacks and Activity records through ActivityTaskManagerService, ActivityStarter, ActivityStack and ActivityStackSupervisor, and then uses cross processes to transfer the starting process to the client.
Thread switching and message processing -- mH
Following the above analysis, we find the scheduleTransaction method of ApplicationThread:
@Override public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { ActivityThread.this.scheduleTransaction(transaction); }
Let's look at the scheduleTransaction method of ActivityThread. In fact, in its parent class ClientTransactionHandler:
void scheduleTransaction(ClientTransaction transaction) { transaction.preExecute(this); sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); }
Send a message using sendMessage. The parameter is activitythread H.EXECUTE_ Transaction and transaction, and then look at:
void sendMessage(int what, Object obj) { sendMessage(what, obj, 0, 0, false); } private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { if (DEBUG_MESSAGES) { Slog.v(TAG,"SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); } Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; if (async) { msg.setAsynchronous(true); } mH.sendMessage(msg); }
Finally called mH.. SendMessage (MSG), what is MH? Let's see:
//ActivityThread final H mH = new H(); class H extends Handler { public static final int BIND_APPLICATION = 110; @UnsupportedAppUsage public static final int EXIT_APPLICATION = 111; @UnsupportedAppUsage public static final int RECEIVER = 113; @UnsupportedAppUsage public static final int CREATE_SERVICE = 114; @UnsupportedAppUsage public static final int SERVICE_ARGS = 115; @UnsupportedAppUsage public static final int STOP_SERVICE = 116; public static final int CONFIGURATION_CHANGED = 118; ... @UnsupportedAppUsage public static final int BIND_SERVICE = 121; @UnsupportedAppUsage public static final int UNBIND_SERVICE = 122; ... public static final int EXECUTE_TRANSACTION = 159; public static final int RELAUNCH_ACTIVITY = 160; public static final int PURGE_RESOURCES = 161; public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case BIND_APPLICATION: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication"); AppBindData data = (AppBindData)msg.obj; handleBindApplication(data); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case EXIT_APPLICATION: if (mInitialApplication != null) { mInitialApplication.onTerminate(); } Looper.myLooper().quit(); break; case RECEIVER: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp"); handleReceiver((ReceiverData)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case CREATE_SERVICE: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj))); handleCreateService((CreateServiceData)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case BIND_SERVICE: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind"); handleBindService((BindServiceData)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case UNBIND_SERVICE: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind"); handleUnbindService((BindServiceData)msg.obj); schedulePurgeIdler(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case SERVICE_ARGS: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj))); handleServiceArgs((ServiceArgsData)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case STOP_SERVICE: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop"); handleStopService((IBinder)msg.obj); schedulePurgeIdler(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case CONFIGURATION_CHANGED: handleConfigurationChanged((Configuration) msg.obj); break; ... 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; case RELAUNCH_ACTIVITY: handleRelaunchActivityLocally((IBinder) msg.obj); break; case PURGE_RESOURCES: schedulePurgeIdler(); break; } Object obj = msg.obj; if (obj instanceof SomeArgs) { ((SomeArgs) obj).recycle(); } if (DEBUG_MESSAGES) Slog.v(TAG, "<< + codeToString(msg.what)); } }
mH is assigned when the ActivityThread instance is created. It is an instance of the custom Handler subclass H, that is, in the main method of ActivityThread, and the initialization is that the main thread already has a mainLooper. Therefore, using this mH to sendMessage sends the message to the main thread.
So which thread is it sent from? Let's see which thread the scheduleTransaction method of ApplicationThread executes on. According to the IPC knowledge, we know that the Binder method of the server runs in the Binder thread pool, that is, the system makes cross process calls, and the scheduletransfer of ApplicationThread is executed in the Binder thread pool.
At this point, the message is processed in the main thread, so how to handle the startup of Activity? Keep looking. We found activitythread H.EXECUTE_ The processing of the transaction message is in the penultimate case of the handleMessage method (in the code above): take out the ClientTransaction instance and call the execute method of the TransactionExecutor. Let's see:
public void execute(ClientTransaction transaction) { if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction"); final IBinder token = transaction.getActivityToken(); ... executeCallbacks(transaction); executeLifecycleState(transaction); ... }
Continue to follow up the executeCallbacks method:
public void executeCallbacks(ClientTransaction transaction) { final List callbacks = transaction.getCallbacks(); if (callbacks == null || callbacks.isEmpty()) { // No callbacks to execute, return early. return; } if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callbacks in transaction"); 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 int finalState = 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 < callbacks.siez(), i++){ final ClientTransactionItem item = callbacks.get(i); } ... item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); ... }
Traverse the callbacks and call the execute method of ClientTransactionItem. Here we should focus on the subclass LaunchActivityItem of ClientTransactionItem. Take a look at its execute method:
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); client.handleLaunchActivity(r, pendingActions, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }
It calls the client Handlelaunchactivity method. Client is an instance of ClientTransactionHandler, which is passed in the TransactionExecutor construction method. The TransactionExecutor is created in the ActivityThread:
//ActivityThread private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
So, client The handleLaunchActivity method is the handleLaunchActivity method of the ActivityThread.
Well, here, the ApplicationThread switches the operation of starting the Activity to the main thread through mH and goes to the handleLaunchActivity method of the ActivityThread.
Activity startup core implementation - initialization and life cycle
Then go on:
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) { ... final Activity a = performLaunchActivity(r, customIntent); ... return a; }
Continue with the performLaunchActivity method. Here is the core implementation of activity startup:
/** activity The core implementation of startup */ private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { //1. Get the component information of the Activity to be started from the ActivityClientRecord ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE); } ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity(mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } //Create ContextImpl object ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { //2. Create activity instance 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) { ... } try { //3. Create an Application object (if not) 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); } Window window = null; if (r.mPendingRemoveWindow != null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; } appContext.setOuterContext(activity); //4. The attach method associates the context for 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, r.assistToken); if (customIntent != null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; checkAndBlockForNetworkAccess(); activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } activity.mCalled = false; //5. Call lifecycle 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; } r.setState(ON_CREATE); synchronized (mResourcesManager) { mActivities.put(r.token, r); } } ... return activity; }
performLaunchActivity mainly completes the following things:
Get the component information of the Activity to be started from the ActivityClientRecord
Via mimstrumentation The newactivity method uses the class loader to create an activity instance
The Application object is created through the makeApplication method of LoadedApk, and the class loader is also used internally through mminstrumentation. After creation, instrumentation is called Callapplicationoncreate method, that is, the onCreate method of Application.
Create a ContextImpl object and use Activity The attach method initializes important data and associates the specific implementation ContextImpl of Context. The attach method also completes the creation of window internally, so that the window can pass to the Activity after receiving external events.
The onCreate method of the Activity is called through mminstrumentation Callactivityoncreate method completed.
Here, after the onCreate method of Activity is executed, what about onStart and onResume?
The LaunchActivityItem seen above is used to start the Activity, that is, go to onCreate of the Activity. Is there "XXXActivityItem"? yes , we have:
LaunchActivityItem onCreate lifecycle transaction on remote App side
ResumeActivityItem is the onResume lifecycle transaction on the remote App side
PauseActivityItem onPause lifecycle transaction on remote App side
StopActivityItem onStop lifecycle transaction on remote App side
DestroyActivityItem remote App side onDestroy lifecycle transaction
In addition, there are several categories involved in the combing process:
ClientTransaction client transaction controller
The lifecycle transaction controller of the clientllifecycle manager client
TransactionExecutor remote communication transaction executor
Then let's take a look at ResumeActivityItem.
Let's take another look at the realStartActivityLocked method in the ActivityStackSupervisor:
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException { ... // Create activity launch transaction. final ClientTransaction clientTransaction = ClientTransaction.obtain(proc.getThread(), r.appToken); final DisplayContent dc = r.getDisplay().mDisplayContent; clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),System.identityHashCode(r), r.info, 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 desired final state. final ActivityLifecycleItem lifecycleItem; //ResumeActivityItem here if (andResume) { lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward()); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // Schedule transaction. mService.getLifecycleManager().scheduleTransaction(clientTransaction); ... return true; }
Previously, we only talked about using clienttransaction Addcallback adds an instance of LaunchActivityItem. Note that clienttransaction is called next setLifecycleStateRequest (lifecycleItem) method. lifecycleItem is an instance of ResumeActivityItem or PauseActivityItem. Here, we focus on ResumeActivityItem. First, let's look at setLifecycleStateRequest method:
/** Final lifecycle state in which the client activity should be after the transaction is executed. */ private ActivityLifecycleItem mLifecycleStateRequest; public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) { mLifecycleStateRequest = stateRequest; }
Mlicyclestaterequest indicates the final lifecycle state after the transaction is executed.
Continue to see how to handle activitythread H.EXECUTE_ Transaction is the processing of this message, that is, the execute method of TransactionExecutor:
public void execute(ClientTransaction transaction) { if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction"); final IBinder token = transaction.getActivityToken(); ... executeCallbacks(transaction); executeLifecycleState(transaction); ... }
Earlier, we focused on the executeCallbacks method. Now let's look at the executelicyclestate method:
/** Transition to the final state if requested by the transaction. */ private void executeLifecycleState(ClientTransaction transaction) { final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest(); if (lifecycleItem == null) { // No lifecycle request, return early. return; } final IBinder token = transaction.getActivityToken(); final ActivityClientRecord r = mTransactionHandler.getActivityClient(token); ... // Execute the final transition with proper parameters. lifecycleItem.execute(mTransactionHandler, token, mPendingActions); lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions); }
Here, the activitylifecycle item is taken out and its execute method is called. In fact, it is the method of ResumeActivityItem:
@Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,"RESUME_ACTIVITY"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }
After the above analysis, we actually go to the handleResumeActivity method of ActivityThread:
@Override public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { ... // The performResumeActivity will go through onStart and onResume final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); if (r == null) { // We didn't actually resume the activity, so skipping any follow-up actions. return; } ... if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (r.mPreserveWindow) { a.mWindowAdded = true; r.mPreserveWindow = false; ViewRootImpl impl = decor.getViewRootImpl(); if (impl != null) { impl.notifyChildRebuilt(); } } ... if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { if (r.newConfig != null) { performConfigurationChangedForActivity(r, r.newConfig); if (DEBUG_CONFIGURATION) { Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig r.activity.mCurrentConfig);" + } r.newConfig = null; } if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward); WindowManager.LayoutParams l = r.window.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != forwardBit) { l.softInputMode = (l.softInputMode & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)) | forwardBit; if (r.activity.mVisibleFromClient) { ViewManager wm = a.getWindowManager(); View decor = r.window.getDecorView(); wm.updateViewLayout(decor, l); } } r.activity.mVisibleFromServer = true; mNumVisibleActivities++; if (r.activity.mVisibleFromClient) { //Add window, set visible r.activity.makeVisible(); } } r.nextIdle = mNewActivities; mNewActivities = r; if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r); Looper.myQueue().addIdleHandler(new Idler()); } }
handleResumeActivity does the following:
Use the performResumeActivity method to internally call the life cycles onStart and onresume (you can view it yourself, and it will not be extended here)
Through activity Makevisible method, add window and set visible. (so the view is really visible after the onResume method)
Well, here is the real creation completed and visible.
summary
The explanation of the process of Activity startup is divided into several stages: startup initiation, AMS management, thread switching and startup core implementation. We know that the startup process has experienced two IPC, client to AMS, AMS to client, and Activity creation and life cycle execution.