For the first time to read dry goods, you can pay attention to my public number: program ape cultivation center
Interviewer: Briefly describe the APP startup process and Activity startup process
A: The APP starts when the user clicks on the icon on the desktop. The Android desktop application is called Launcher. The desktop can also be regarded as an application of the Android system, and the desktop is just one of the pages of the application. Every app in Android is a process, and that app starts another app and communicates with each other. There must be interprocess communication, which is CALLED IPC communication, and most of IPC in Android is implemented with Binder. In this way, the APP startup process is actually the Activity startup process, but the middle will determine whether the process to start the Activity exists, if not, the Zygote process will be notified to fork() a new process, and then start the target page. If you want to just look at the summary, scroll to the bottom and summarize seven points: 1. Start with the LauncherActivity click on the desktop app:
//LauncherActivity inherits from ListActivity, which is a desktop that hosts many applications
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = intentForPosition(position);
startActivity(intent); // Executes the startActivity of the Activity
}
// Start the Activity's startActivity -- startActivityForResult
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) { //mParent is used to check whether there is a parent Activity
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity( //mMainThread is an instance of ActivityThread.
// The application has not been started yet. This is actually the Launcher, which is the current one.
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if(ar ! =null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
//....
} else {
//....}}Copy the code
The activityForResult method above calls execStartActivity through the mInstrumentation object. Instrumentation is used primarily to monitor the interaction between the application and the system. The mMainThread is actually an ActivityThread object, which is the ActivityThread for the application Launcher, initialized at startup time.
/ / Instrumentation. Java classes
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, String target,
Intent intent, int requestCode, Bundle options) {
//....
try {
//....
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token, target,
requestCode, 0.null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
/ / ActivityTaskManager. GetService () to see what is obtained:
/** ActivityTaskManager.java*/
public static IActivityTaskManager getService(a) {
return IActivityTaskManagerSingleton.get();
}
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create(a) {
// Get a service from the ServiceManager. Regardless of the service, the ServiceManager is the class that manages all the services in the system
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
// What kind of service does it get? Here you see xxx.stub.asInterface (), which is something you usually see in AIDL. Who see that implements IActivityTaskManager. Stub interface
returnIActivityTaskManager.Stub.asInterface(b); }};// Find it:
public class ActivityTaskManagerService extends IActivityTaskManager.Stub
Copy the code
ActivityTaskManagerService referred to as “generally, to understand: Through a series of operations, the Binder sends the data to the ATMS using AIDL. (Here is an IPC communication to launch the application, that is, a communication between the ATMS and the Launcher.) The ATMS starts processing the message. Instrumentation has put the Launcher’s process (whoThread parameters, is the front to mMainThread. GetApplicationThread) coming, AMS save it as a ActivityRecord object, This object has an ApplicationThreadProxy proxy object with Binder. AMS sends messages to the Launcher through ApplicationTreadProxy. When the ATMS receives a message, it will tell you that the previous page is going to pause.
//ActivityStack.java
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
/ /...
ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
/ /...
boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
if(mResumedActivity ! =null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
pausing |= startPausingLocked(userLeaving, false, next, false);
}
/ /...
if (next.attachedToProcess()) {
// The application has been started
try {
/ /...
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
getDisplay().mDisplayContent.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
/ /...
} catch (Exception e) {
/ /...
mStackSupervisor.startSpecificActivityLocked(next, true.false);
return true;
}
/ /...
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
next.completeResumeLocked();
} catch (Exception e) {
// If any exception gets thrown, toss away this
// activity and try the next one.
Slog.w(TAG, "Exception thrown during resume of " + next, e);
requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null."resume-exception".true);
return true; }}else {
// Cold start process
mStackSupervisor.startSpecificActivity(next, true.true); }}Copy the code
StartPausingLocked () first causes the previous page to enter pause state, and then determines whether the process for the APP to start exists. If so, start the target Activity directly, and if not, create the process. If it’s a Launcher, there’s a process that goes into the hot launch process, and if it doesn’t, there’s a cold launch process. This is why, when an Activity is started during its life cycle, onPause is executed before the target Activity starts its life cycle method. Then look at the cold start process:
//ActivityStackSupervisor.java
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(wpc ! =null && wpc.hasThread()) {
try {
// Continue to check if there is a process, if so, return
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
}
knownToBeDead = true;
}
/ /... MService is an instance object of ATMS, where the process is created
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}
Copy the code
How does ATMS create a new process? Or how to communicate with Zygote, let Zygote fork() process, look at ATMS:
//ActivityTaskManagerService.java
void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
String hostingType) {
try {
/ /...
// Post message to start process to avoid possible deadlock of calling into AMS with the
Publish a message to start the process to avoid potential deadlocks when AMS is called
// ATMS lock held.
final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
isTop, hostingType, activity.intent.getComponent());
mH.sendMessage(m);
} finally{ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); }}Copy the code
ActivityManagerInternal: : startProcess look at this, start a new process:
// is an abstract method. Find where to implement it:
public abstract void startProcess(String processName, ApplicationInfo info,
boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName);
/ / implementation ActivityManagerInternal: : startProcess method in ActivityManagerService class:
//ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor.BatteryStatsImpl.BatteryCallback {
/ /... .
public final class LocalService extends ActivityManagerInternal {
@Override
public void startProcess(String processName, ApplicationInfo info,
boolean knownToBeDead, String hostingType, ComponentName hostingName) {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"
+ processName);
}
// Thread synchronization prevents multithreading from creating processes. Process creation can only support single threads, so the subsequent communication between AMS and Zygote cannot be communicated with Binder, and Socket is selected
synchronized (ActivityManagerService.this) {
startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */.new HostingRecord(hostingType, hostingName),
false /* allowWhileBooting */.false /* isolated */.true /* keepIfLarge */); }}finally{ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); }}}/ /... .
}
Copy the code
Here you can see that in the cold start process, the task of creating a new process is handed over to AMS and finally executed to ZygoteProcess, which is responsible for creating the new process.
//ZygoteProcess.java
private Process.ProcessStartResult attemptUsapSendArgsAndGetResult( ZygoteState zygoteState, String msgStr)
throws ZygoteStartFailedEx, IOException {
try (LocalSocket usapSessionSocket = zygoteState.getUsapSessionSocket()) {
final BufferedWriter usapWriter =
new BufferedWriter(
new OutputStreamWriter(usapSessionSocket.getOutputStream()),
Zygote.SOCKET_BUFFER_SIZE);
final DataInputStream usapReader =
new DataInputStream(usapSessionSocket.getInputStream());
usapWriter.write(msgStr);
usapWriter.flush();
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = usapReader.readInt();
// USAPs can't be used to spawn processes that need wrappers.
result.usingWrapper = false;
if (result.pid >= 0) {
return result;
} else {
throw new ZygoteStartFailedEx("USAP specialization failed"); }}}Copy the code
As you can see, the socket communicates with the Zygote, and the BufferedWriter reads and receives messages. The message that the new process will be created is passed to Zygote, who forks the process and returns the PID of the new process. This process also instantiates the ActivityThread object and then executes the main method:
//RuntimeInit.java
protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<? > cl;try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main".new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
/ /...
return new MethodAndArgsCaller(m, argv);
}
Copy the code
I’m calling the main method by reflection, and then I’m going to go to the main method of the APP.
public static void main(String[] args) {
/ /...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
// This will tell AMS that the process is created and I'm ready to start... Create Application
thread.attach(false, startSeq);
/ /...
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
/ /...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Copy the code
Here, AMS told Zygote to create a new process has been done, after a cigarette, a live immortal, I first rest…. Now continue: After the process is created, the Application is already started, because an Application is actually a process. At this point, the Application will create the Application itself, start the Activity, and then start startActivity again. At this point, the process of the target Activity already exists, and the Activity is started. Finally, the handleLaunchActivity() method of ActivityThread is executed:
//ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {
/ /...
WindowManagerGlobal.initialize();
/ /... Then perform performLaunchActivity
final Activity a = performLaunchActivity(r, customIntent);
/ /...
return a;
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
/ / create ContextImpl
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
/ / create the Activity
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
}
try {
if(activity ! =null) {
// Finish initializing some important data 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;
}
// Set the activity's theme
int theme = r.activityInfo.getThemeResource();
if(theme ! =0) {
activity.setTheme(theme);
}
// Call the activity's onCreate method. At this point, we are almost done...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else{ mInstrumentation.callActivityOnCreate(activity, r.state); }}}return activity;
}
Copy the code
Then to here, the second game is also over, summarize the results of this time, I do not know how much energy, exhausted feeling, just for the last moment, that is: attention, here underlined, will test! 1, Launcher is called click the event, go to the startActivity method of the Instrumentation class. 2, Instrumentation through AIDL using Binder mechanism to tell ATMS to start application requirements. 4. When THE Launcher enters Paused state, ATMS gives AMS the task of creating a process, and AMS communicates with Zygote through socket to inform Zygote that it needs to create a new process. Zygote fork and call ActivityThread’s main method, which is the entry point to the app. The ActivityThread main method creates an ActivityThread instance and creates a Looper instance to start the loop. The ActivityThread also tells AMS that the process is complete, starts creating the Application Provider, and calls the Attach, onCreate method of the Application. 7. Finally, create the context. Load the Activity through the class loader and call the Activity’s onCreate method.
The last
1. Attach method of Application. MultiDexApplication will execute the MultiDex logic in the method. Therefore, MultiDex optimization can be carried out here. For example, Toutiao solution is to start a separate process of activity to load MultiDex. 2. The onCreate method of Application is used to initialize a large number of tripartite libraries, so we can enable thread pooling, lazy loading, etc. Make a distinction between each startup task, which can be run by sub-threads, and which can be run in sequence. 3, Activity onCreate method, also thread processing, lazy loading. Or pre-create activities, pre-load classes, and so on.
See two pictures, sometimes eat their own home may not taste good, also can steal some, so I stole these two pictures:
Because the level is limited, have wrong place unavoidable, rather misdirect others, welcome big guy to point out! Code word is not easy, thank you for your attention!
🙏 If you are studying with me, you can follow my official account — ❤️ Program ape Development Center ❤️. Every week, we will share the technology of Android regularly.