“This is my 28th day of participating in the First Challenge 2022. For details: First Challenge 2022.”
The application Activity Launcher process
After the main function of the ActivityThread is started, it initializes an ActivityThread object and calls its attach function. And finally call AMS’s attachApplicationLocked function. In this function, it mainly does:
- Start the Application object
- Start the Activity object
As follows, we continue our analysis from the previous paper
Application Start process analysis
In the initial article, we analyzed that the bindApplication function of the ApplicationThread object is called in AMS attachApplicationLocked
ApplicationThread.java
public final void bindApplication(String processName, ApplicationInfo appInfo,
ProviderInfoList providerList, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
if(services ! =null) {
/ /...
// Setup the service cache in the ServiceManager
// Add the corresponding services required by AMS to the ServiceManager cache, so that in subsequent work,
// You can directly obtain the corresponding service from the ServiceManager
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);
// Initializes the AppBindData object and sets its corresponding parameters
// This object holds the application information that started the application
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providerList.getList();
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableBinderTracking = enableBinderTracking;
data.trackAllocation = trackAllocation;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
data.buildSerial = buildSerial;
data.autofillOptions = autofillOptions;
data.contentCaptureOptions = contentCaptureOptions;
data.disabledCompatChanges = disabledCompatChanges;
// Send the message, which is eventually processed in the ActivityThread.h class object
sendMessage(H.BIND_APPLICATION, data);
}
Copy the code
As you can see, the main thing here is to initialize an AppBindData object and then process it by sending a message to the ActivityThread.h object
ActivityThread. H classpublic void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
AppBindData data = (AppBindData)msg.obj;
// Call handleBindApplication
handleBindApplication(data);
break;
/ /...}}private void handleBindApplication(AppBindData data) {
/ /...
// Initialize an Instrumentation object
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
/ /...
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
// Initialize the Application object
// If an Application class that inherits the Application class is defined in the Application's Androidmanifest.xml file, the class object is initialized here
// If not, an Application base object is initialized
This section uses AOSP Launcher3 as an example to initialize the Application object
// It is worth mentioning that this function also adds the current Application object to the mAllApplications parameter of ActivityThread
app = data.info.makeApplication(data.restrictedBackupMode, null);
/ /...
mInitialApplication = app;
// Run all contentProviders for the corresponding application
if(! data.restrictedBackupMode) {if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
}
/ /...
try {
// Call the onCreate function of the Application object corresponding to ApplicationInfo
// Of course, in our Application Launcher, we call the Application's default onCreate without doing anything
mInstrumentation.callApplicationOnCreate(app);
}
/ /...
}
/ /...
}
Copy the code
In the code and remarks above, the Application onCreate function does nothing for the Application Launcher, but if some other Application defines an Application subclass object in androidmanifest.xml, The onCreate function will be called to perform some application-level initialization operations and start some key services, such as AOSP Dialer application.
In this way, we have finished analyzing the startup process of the Application.
Note: After the Application startup process has been analyzed, ProcessRecord’s makeActive function is called, which sets the thread parameter of ProcessRecord to the current ApplicationThread object. And set the mThread parameter value of its mWindowProcessController parameter to this object. Because the code is relatively simple, it is not analyzed here
Analyze the Activity startup process
The ATMS.LocalService object uses the attachApplication function to start the Activity declaration cycle
ActivityManagerService.java
if (normalMode) {
try {
/ / mAtmInternal is a generally. The LocalService objects, the class inherits from ActivityTaskManagerInternal class
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true; }}public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
/ /...
return mRootWindowContainer.attachApplication(wpc);
/ /...
}
boolean attachApplication(WindowProcessController app) throws RemoteException {
boolean didSomething = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
/ /...
final DisplayContent display = getChildAt(displayNdx);
for (int areaNdx = display.getTaskDisplayAreaCount() - 1; areaNdx >= 0; --areaNdx) {
final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(areaNdx);
for (int taskNdx = taskDisplayArea.getStackCount() - 1; taskNdx >= 0; --taskNdx) {
// Get the previously created ActivityStack object, which holds the previously added ActivityRecord object to the top layer
final ActivityStack rootTask = taskDisplayArea.getStackAt(taskNdx);
/ /...
// PooledLambda will eventually call the function applied to the first argument
final PooledFunction c = PooledLambda.obtainFunction(
RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
PooledLambda.__(ActivityRecord.class), app,
rootTask.topRunningActivity());
rootTask.forAllActivities(c);
/ /...
}
}
didSomething |= mTmpBoolean;
}
/ /...
return didSomething;
}
Copy the code
Since the obtainFunction function of the PooledLambda class object eventually initializes the PooledFunction object and eventually runs the corresponding function reference for that object
rivate boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r, WindowProcessController app, ActivityRecord top) {
/ /...
// realStartActivityLocked of the ActivityStackSupervisor object
if (mStackSupervisor.realStartActivityLocked(r, app,
top == r && r.isFocusable() /*andResume*/.true /*checkConfig*/)) {
mTmpBoolean = true;
}
/ /...
return false;
}
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
/ /...
// Create activity launch transaction.
// A ClientTransaction object is initialized here
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
final DisplayContent dc = r.getDisplay().mDisplayContent;
// Add the current ClientTransaction object's callback,
// Actually add the LaunchActivityItem here to the mActivityCallbacks parameter of the ClientTransaction object
clientTransaction.addCallback(/ *... This parameter is temporarily ignored, when necessary to analyze */);
/ /...
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
// A ResumeActivityItem object is initialized here
lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
// Lifecycle Request is set for ClientTransaction
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
// Finally get the scheduleTransaction function of the ClientLifecycleManager object
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
/ /...
}
Copy the code
As you can see from the code and comments above, after initializing a ClientTransaction object and setting its Callback and Lifecycle State Request, The scheduleTransaction function of ClientListcycleManager is called to plan the business process
Before moving on to the code flow, it is important to review the structure of the ClientTransaction and ClientTransactionItem classes as follows
classDiagram Parcelable <|-- ClientTransactionItem ClientTransactionItem <|-- LaunchActivityItem ClientTransactionItem <|-- ActivityLifecycleItem BaseClientRequest <|-- ClientTransactionItem ObjectPoolItem <|-- BaseClientRequest ActivityLifecycleItem <|-- ResumeActivityItem ActivityLifecycleItem <|-- PauseActivityItem ActivityLifecycleItem <|-- StopActivityItem ActivityLifecycleItem <|-- DestroyActivityItem ActivityLifecycleItem <|-- StartActivityItem ClientTransaction <-- ClientTransactionItem Parcelable <|-- ClientTransaction ObjectPoolItem <|-- ClientTransaction ClientTransaction <-- ActivityLifecycleItem class BaseClientRequest { +preExecute(ClientTransactionHandler, IBinder) void default +execute(ClientTransactionHandler, IBinder, PendingTransactionActions) void +postExecute(ClientTransactionHandler, IBinder, PendingTransactionActions) void default } class ClientTransaction { +schedule() void } class ObjectPoolItem { #recycle() void } class ClientTransactionItem { +getPostExecutionState() int +describeContents() int } class LaunchActivityItem { +preExecute(ClientTransactionHandler, IBinder) void +execute(ClientTransactionHandler, IBinder, PendingTransactionActions) void +postExecute(ClientTransactionHandler, IBinder, PendingTransactionActions) void -LaunchActivityItem() +recycle() +obtain(......) LaunchActivityItem -LaunchActivityItem(Parcel in) -setValues(......) void } <<interface>> ObjectPoolItem <<interface>> BaseClientRequest <<interface>> Parcelable <<abstract>> ClientTransactionItem <<abstract>> ActivityLifecycleItem
As you can see from this schematic
- Both ClientTransaction and ClientTransactionItem implement the Parcelable interface, which at least indicates that both objects can be carried through Message messages
- Both ActivityLifecycleItem and LaunchActivityItem inherit from ClientTransactionItem and are associated with ClientTransaction
- The ActivityLifecycleItem class contains five subclasses that, from their names, seem to correspond to the various stages of an Activity launch
We continue our code flow through the scheduleTransaction function of the ClientLifecycleManager object
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
/ /...
transaction.schedule();
/ /...
}
public void schedule(a) throws RemoteException {
// The mClient parameter is passed in when the ClientTransaction object's obtain function is called to initialize
// It is passed in through the mThread argument of WindowProcessController, which is set through the makeActive function of ProcessRecord
// Therefore, mClient is the inner class ApplicationThread object in the ActivityThread class
mClient.scheduleTransaction(this);
}
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
// Call ActivityThread's scheduleTransaction function. ActivityThread did not override this function
// Therefore call the scheduleTransaction function of its parent class ClientTransactionHandler
ActivityThread.this.scheduleTransaction(transaction);
}
void scheduleTransaction(ClientTransaction transaction) {
// The preExecute function of the ClientTransaction object is called first
transaction.preExecute(this);
// The message is processed in ActivityThread.h after being sent
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
Copy the code
As you can see from the above code, there are two operations
- The preExecute function of the ClientTransaction object is called first, marking this as the A identifier
- After the message is sent, it is processed in ActivityThread.h
Let’s skip the first operation and look at the second operation
public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
/ / -_ -
final ClientTransaction transaction = (ClientTransaction) msg.obj;
// Call the TransactionExecutor object's execute function
mTransactionExecutor.execute(transaction);
/ /...}}public void execute(ClientTransaction transaction) {
/ /...
// 1. Call executeCallbacks first
executeCallbacks(transaction);
// 2. Call the executeLifecycleState function
executeLifecycleState(transaction);
/ /...
}
Copy the code
Call the executeCallbacks function
Following the code above, let’s take a look at the first point in the remarks
public void executeCallbacks(ClientTransaction transaction) {
// Get the Callbacks in ClientTransaction,
// Remember from the above code that the addCallback function corresponds to a LaunchActivityItem object
// to the ClientTransaction object mActivityCallbacks parameter?
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
/ / not be empty
if (callbacks == null || callbacks.isEmpty()) {
// No callbacks to execute, return early.
return;
}
/ /...
final IBinder token = transaction.getActivityToken();
ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
/ /...
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
// Get the corresponding LaunchActivityItem object from ClientTransaction
final ClientTransactionItem item = callbacks.get(i);
/ /...
// Call the execute function of the LaunchActivityItem object, temporarily labeled b
item.execute(mTransactionHandler, token, mPendingActions);
// Call the postExecute function of the LaunchActivityItem object, temporarily labeled C
item.postExecute(mTransactionHandler, token, mPendingActions);
/ /...}}Copy the code
With the code and comments above, we continue with the B and C identifiers
Call the executeLifecycleState function
We continue with the second point above, the executelifeccleState function
private void executeLifecycleState(ClientTransaction transaction) {
// Get the Lifecycle Request of the ClientTransaction object
// In the previously analyzed code, a ResumeActivityItem object was set
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
/ /...
// Cycle to the state right before the final requested state.
// Call cycleToPath
Lifecycle Request object Lifecycle Request object Lifecycle Request object Lifecycle Request object Lifecycle Request object Lifecycle Request object Lifecycle Request
// Check if there are any other states in the interval, if so, run the corresponding state function
// We'll temporarily label it d here
cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);
// Execute the final transition with proper parameters.
// Run the execute function on the ResumeActivityItem object described above, which we temporarily identified here as e
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
// Run the postExecute function for the ResumeActivityItem object above, which we temporarily identified here as f
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
Copy the code
With the code and comments above, we continue to annotate E and F
summary
As for the overall code analysis above, our identifiers are:
- A calls the preExecute function of ClientTransaction
- B Calls the execute function of the LaunchActivityItem object
- C calls the postExecute function of the LaunchActivityItem object
- D calls the TransactionExecutor cycleToPath function
- E Calls the execute function of the ResumeActivityItem object
- F calls the postExecute function of the ResumeActivityItem object
The code represented by these symbols also forms the lifecycle of an Activity, which we’ll examine in the next article