When I click on the App icon of the Launcher, I click on the onClickAppShortcut that’s passed to ItemClickHandler, And ultimately calls to the launcher. The startActivitySafely – > BaseDraggingActivity. StartActivitySafely:
public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
@Nullable String sourceContainer) {
// ...
// Set the Intent Flag to FLAG_ACTIVITY_NEW_TASK
// Start the Activity in a new Activity task stack
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// ...
try {
/ /... Omit some shortcuts to start
else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
// Start the application Activity
startActivity(intent, optsBundle);
AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
Process.myUserHandle(), sourceContainer);
}
// ...
return true;
} catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
}
return false;
}
Copy the code
The implementation of startActivity is in the Activity:
public void startActivity(Intent intent, @Nullable Bundle options) {
/ /... Both call startActivityForResult to start the Activity
// The incoming requestCode is -1
if(options ! =null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1); }}Copy the code
Start the Activity through the final Instrumentation execStartActivity method to start, and the role of Instrumentation is actually monitoring the application and system interaction in the middle of this, is a layer of Android Hook operation, ExecStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity execStartActivity
intresult = ActivityTaskManager.getService().startActivity(whoThread, who.getBasePackageName(), who.getAttributionTag(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null, requestCode, 0.null, options);
Copy the code
ActivityTaskManager is a new class added to Android 10 that takes over the role of activities interacting with ActivityTasks in ActivityManager. And ActivitTaskManager. GetService return is IActivityTaskManager the AIDL document declared in the interface, And system services in the process of the SystemServer ActivityTaskManagerService only needs to inherit IActivityTaskManager. The Stub can realize the user process and service process of communication.
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create(a) {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
returnIActivityTaskManager.Stub.asInterface(b); }};Copy the code
First get SystemServer ActivityTaskManagerService this system in the process of service’s IBinder interface, and then converts the IBinder interface IActivityTaskManager interface, This allows the reference process to call the methods of IActivityTaskManager to communicate with the ATMS.
The application process calls the startActivity method of the ATMS, and the logic to create the Activity goes from the Launcher process to the SystemServer process of the ATMS:
In the ATMS startActivity, call ATMS. StartActivityAsUser:
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
// Verify the pre-permission
// Get the ActivityStart object
// This object is a proxy object that controls the start of the Activity
// After 7.0, collect all kinds of parameter logic related to the Activity start
// Decide how to start the Activity level 1 Task and TaskStack association
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
/ /... A lot of parameters are set
.execute();
}
Copy the code
After setting a bunch of parameters to the ActivityStarter object, call it execute to start:
int execute(a) {
try {
// ...
int res;
synchronized (mService.mGlobalLock) {
// ...
// The startup information is in mRequest, execute the request
res = executeRequest(mRequest);
// Start some notification after completion of work......}}finally{ onExecutionComplete(); }}Copy the code
Executterequest contains a lot of validation logic, such as checking startup parameters, Flag, etc. The normal startup process will create an ActivityRecord object based on various startup parameters. The ActivityRecord object represents an Activity entity in the task stack that is finally called to ActivityStarter’s startActivityUnchecked.
StartActivityUnchecked ->startActivityInner. In startActivityInner, check the Activity Flag. For example, if you start a root Activity, But instead of FLAG_ACTIVITY_NEW_TASK, the LaunchFlag is changed to FLAG_ACTIVITY_NEW_TASK. It then finds out if there is a task stack that can be reused. If not, it creates a new task stack. The core logic of startActivityInner is to call:
mRootWindowContainer.resumeFocusedStacksTopActivities(
mTargetStack, mStartActivity, mOptions);
Copy the code
RootWindowContainer is an object created in the WMS and can be understood as the content displayed on its manager screen. In RootWindowContainer, it calls to ActivityStack resumeTopActivityUncheckedLocked – > resumeTopActivityInnerLocked. This method is 400+ lines long on 11 and has a lot of logic. Key points related to the main process we are analyzing are as follows:
// attachedToProcess determines whether the process to start the Activity exists and
// Whether the ActivityThread for the corresponding process exists, and we are starting a new process
//, before the new process is created and ActivityRecord is bound to the new process
if (next.attachedToProcess()) {
// ...
} else {
// ...
mStackSupervisor.startSpecificActivity(next, true.true);
}
Copy the code
ActivityStackSupervisor’s startSpecificActivity is as follows:
void startSpecificActivity(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 the application process already exists, execute realStartActivityLocked
// Start the Activity
if(wpc ! =null && wpc.hasThread()) {
try {
// This function will be analyzed later
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;
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
// If the application process does not exist, ATMS(eventually AMS) will start the application process asynchronously
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
Copy the code
In case the application process does not exist, AMS sends a Lambda Message to the SystemServer Message queue. When the Message executes, AMS calls the relation:
AMS.startProcessAsync->AMS.startProcess->AMS.startProcessLocked->ProcessList.startProcessLocked… Start ->ProcessList. StartProcess -> process. start -> startViaZygote -> ZygoteProcess -> startViaZygote A timeout message is sent to the SystemServer message queue (default: 10 seconds). If the application process has not started after the timeout, the failed process is killed.
After Zygote forks, it executes ActivityThrea’s main method, and the two most important things that ActivityThread’s main method does, Activate Looper for the main thread and create ActivityThread and call attach, where:
// mAppThread is an ApplicationThread object created when an ActivityThread is created
// Is the bridge between AMS and application processes
/ / initialization RuntimeInit here. MApplicationObject value
RuntimeInit.setApplicationObject(mAppThread.asBinder());
// Obtain the AMS Binder interface IActivityManager
final IActivityManager mgr = ActivityManager.getService();
try {
// invoke AMS attachApplication
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
Copy the code
AttachApplication in AMS is implemented as follows:
public final void attachApplication(IApplicationThread thread, long startSeq) {
// If the ApplicationThread passed is empty, the application process will be terminated unexpectedly
if (thread == null) {
throw new SecurityException("Invalid application interface");
}
synchronized (this) {
// Get the PID and uid of the binder caller process, which is the application process
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
// Change the calling pid and UID of binder to the calling process PID and UID, and return the combination of the original UID and PID
// The higher 32 bits indicate the uid above, and the lower 32 bits indicate the PID
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
// Restore the PID and UIDBinder.restoreCallingIdentity(origId); }}Copy the code
AttachApplicationLocked is an extremely long function that does a lot of checking and setting for App processes.
// If there are any old process records, do some cleaning of the class
// ...
// Then for example debug mode also does some special Settings
// ...
// Create a Binder death callback when AMS server exits unexpectedly.
// Binder drivers can notify application processes and release dead process locks held by Binder files that are not properly closed.
// When the SystemServer process hangs due to an exception, there is a restart mechanism
// ...
// Remove the PROC_START_TIMEOUT_MSG message buried when AMS starts the process
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
// ...
// IPC calls the bindApplication of the ApplicationThread:thread.bindApplication(...) ;Copy the code
After setting up the ApplicationThread, AMS returns to the bindApplication of the application. When bindApplication is performed, AMS passes some common system services to the application, such as WMS, IMS, and so on.
public final void bindApplication(...). {
if(services ! =null) {
// Cache the generic system services from AMS to the ServiceManager
// Static cache
ServiceManager.initServiceCache(services);
}
// H via ActivityThread (inherited from Handler)
// send a SET_CORE_SETTINGS message to the main thread
// Set the coreSettings to the ActivityThread object
// Triggers the restart of all activities in the current process (because the core Settings of the ActivityThread have been changed)
setCoreSettings(coreSettings);
// AppBindData is an encapsulation of bindApplication's data
AppBindData data = new AppBindData();
// Send the BIND_APPLICATION message to the main thread through the mH
sendMessage(H.BIND_APPLICATION, data);
}
Copy the code
The following bindApplication logic goes into H, which is the custom Handler for the ActivityThread, such as Service creation, binding, and Activity lifecycle handling:
For BIND_APPLICATION, handleMessage calls handleBindApplication.
In the handleBindApplication, the data.info field is populated with the LoadApk object, which is obtained by getPackageInfo and contains information such as mPackagerName application package name, mDataDir application data directory, MResources, mApplication and other information.
Then complete the creation of the Context:
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
// createAppContext
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo, String opPackageName) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
// Create ContextImpl, initializing ApplicationContext's mMainThread, packageInfo, and other fields
/ / in the constructor of ContextImpl, also created ApplicationContentResolver this object
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null.null.null.null.0.null, opPackageName);
context.setResources(packageInfo.getResources());
// Is the system status bar Context
context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
return context;
}
Copy the code
After the Context has been created, the Application object will continue to be created, again in handleBindApplication:
Application app;
// ...
app = data.info.makeApplication(data.restrictedBackupMode, null);
/ / LoadedApk. MakeApplication:
// ...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// Call newApplication to create the Application object
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
// ...
// Assign Application to LoadedApk's mApplication and add it to ActivityThread's Application list
mApplication = app;
Copy the code
In the newApplication:
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
// Inside is the newInstance of the reflection Application Class
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
// Bind the Context object to Application
app.attach(context);
return app;
}
// attach as follows:
final void attach(Context context) {
// attachBaseContext is the mBase field that assigns the context to the Application (inherited from ContextWrapper)
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
Copy the code
Continue back to the handleBindApplication of the Application process, after creating the Application object:
// Call back to the onCreate method of the Application object
mInstrumentation.callApplicationOnCreate(app);
Copy the code
Now that the Application process is finally created, let’s go back to AMS attachApplicationLocked, after bindApplication has finished creating the Application object:
// If Application has an Activity to start, start the Activity
// After creating a new process and Application, click icon to start an App from the Launcher
// Start MainActivity
if (normalMode) {
try {
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true; }}/ / ActivityTaskManagerService inner class LocalService implementation attachApplication method:
// Internal call
mRootWindowContainer.attachApplication(wpc);
Copy the code
RootWindowContainer. AttachApplication as follows:
boolean attachApplication(WindowProcessController app) throws RemoteException {
boolean didSomething = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
mTmpRemoteException = null;
mTmpBoolean = false; // Set to true if an activity was started.
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) {
final ActivityStack rootTask = taskDisplayArea.getStackAt(taskNdx);
if (rootTask.getVisibility(null /*starting*/) == STACK_VISIBILITY_INVISIBLE) {
break;
}
// Find the ActivityRecord to start, and then
/ / call startActivityForAttachedApplicationIfNeeded
final PooledFunction c = PooledLambda.obtainFunction(
RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
PooledLambda.__(ActivityRecord.class), app,
rootTask.topRunningActivity());
rootTask.forAllActivities(c);
c.recycle();
if(mTmpRemoteException ! =null) {
throw mTmpRemoteException;
}
}
}
didSomething |= mTmpBoolean;
}
if(! didSomething) { ensureActivitiesVisible(null.0.false /* preserve_windows */);
}
return didSomething;
}
Copy the code
And startActivityForAttachedApplicationIfNeeded implementation, is to launch ActivityRecord we find, call to mStackSupervisor realStartActivityLocked.
Back to ActivityStackSupervisor’s startSpecificActivity:
void startSpecificActivity(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 the application process already exists, execute realStartActivityLocked
// Start the Activity
if(wpc ! =null && wpc.hasThread()) {
try {
// This function will be analyzed later
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;
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
// If the application process does not exist, ATMS(eventually AMS) will start the application process asynchronously
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
Copy the code
AMS in the call to the mService. StartProcessAsync after starting a new application process, ultimately through ActivityStackSupervisor realStartActivityLocked, start the application process of the first Activity, RealStartActivityLocked Is still quite long. The logic we are interested in is:
// Create a transaction that the Activity starts. ClientTransaction is a class that implements the Parcelable interface
That is, the transaction object can be passed across processes
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
final DisplayContent dc = r.getDisplay().mDisplayContent;
// Add a LaunchActivityItem to the transaction, representing the transaction's Callback. The logic in the Callback will be executed later
clientTransaction.addCallback(LaunchActivityItem.obtain(newIntent(r.intent),...) );// ...
// Schedule transaction,
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
Copy the code
Let’s take a look at how transactions are acquired:
public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
// Create an object from the object pool
ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
if (instance == null) {
instance = new ClientTransaction();
}
// Assign IApplicationThread to the transaction's mClient field,
// Indicates which process's ApplicationThread is the receiver of this transaction
instance.mClient = client;
instance.mActivityToken = activityToken;
return instance;
}
Copy the code
ClinetLifeCycleManager schedules transactions as follows:
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
transaction.schedule();
// ...
}
//transaction.schedule(); The implementation is as follows: IPC calls scheduleTransaction of the ApplicationThread
mClient.scheduleTransaction(this);
Copy the code
The scheduleTransaction implementation of the ApplicationThread is the scheduleTransaction method that calls the ActivityThread (AT inherits from ClientTransactionHandler, Implementation in parent class) :
void scheduleTransaction(ClientTransaction transaction) {
// When a client process executes, a hook callback is performed prior to execution
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
Copy the code
The outgoing message is ultimately handed to H for processing:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
Copy the code
MTransactionExecutor is not a multithreaded Executor, but a logical encapsulation of the sequential processing of transactions. Execute:
public void execute(ClientTransaction transaction) {
// ...
// The point in executeCallbacks is to execute the callback method of the incoming transaction
// item.execute(mTransactionHandler, token, mPendingActions);
//
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
// ...
}
Copy the code
When AMS calls realStartActivityLocked the incoming transaction callback is the LaunchActivityItem, and its execute is as follows:
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
// Create an ActivityClientRecord object
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
// The client is actually the mTransactionHandler in TransactionExecutor
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
Copy the code
In ActivityThread, the mTransactionExecutor object is created when the ActivityThread object is created and the this reference is passed to the TransactionExecutor constructor. So mTransactionHandler is the ActivityThread object that implements the ClientTransactionHandler interface. In the ActivityThread handleLaunchActivity:
final Activity a = performLaunchActivity(r, customIntent);
Copy the code
PerformLaunchActivity creates the corresponding Activity object. For the analysis of performLaunchActivity, see the previous two Android UI workflow articles.
Android UI Workflow 1 Android UI Workflow 2