1.APP startup optimization
1. System startup process
Before learning APP startup, let’s have a general understanding of the startup process of Android system. The flow chart is as follows:
When the Android system presses the power button, the code that boots the chip loads the Boot program BootLoader into RAM to execute. The BootLoader pulls up the operating system, and the Linux kernel starts to set up the system. Rc file to start the initialization process. Init initializes and starts the properties service. Zygote starts the JVM and registers the JNI methods. Open SystemServer SystemService ServiceThread of inner class is the main function of initial SystemService will initialize the thread, the thread will start next Binder in thread pool and SystemServiceManager To start the launcher, call ActivityManagerService systemReady in a run method, and call ActivityStack resumeTopActivityLocked in a run method , and then the logic is the underground flow of the APP. In this way, the system is started up and we can click the APP icon on the launcher to start the APP
2.App startup process analysis
The startup process analyzes process creation,ActivityThread creation,Application creation, and Activity creation
1. Activity : startActivity–>startActivityForResult
2. Instrumentation:execStartActivity()–>ActivityManagerService :startActivity ()–>startActivityAsUser()
3. ActivityStarter:execute()–>startActivity()–>startActivityUnchecked ()
4. ActivityStackSupervisor:resumeFocusedStackTopActivityLocked()
5. ActivityStarter :resumeTopActivityUncheckedLocked()–>resumeTopActivityInnerLocked()
7. ActivityStackSupervisor: startSpecificActivityLocked () – > realStartActivityLocked () this approach is to start the Activity of creating APP for the first time Step 8 creates the process first
8. ActivityManagerService :startProcessLocked()–>startProcess()
9. Process :start ()–>ZygoteProcess:start()–>startViaZygote()–>openZygoteSocketIfNeeded()
10. ZygoteState:connect()–>zygote :main()–>zygoteServer:runSelectLoop()
11. ZygoteConnection:processOneCommand()—>handleChildProc()
12. ZtgoteInit: zygoteInit()
RuntimeInit: applicationInit() where the app process is successfully created and the main function of ActivityThread is called
14.ActivityThread: main()–>attach()
16. ActivityManagerService : attachApplication()
17.ApplicationThread: bindApplication() Application is created here
18. ActivityStackSupervisor: attachApplicationLocked()—>realStartActivityLocked()
19. ClientTransaction—>schedule()
20. ActivityThread: scheduleTransaction()
20. TransactionExecutor:–execute(transaction)–>executeCallbacks()–>LaunchActivityItem:execute()
21. ActivityThread: handleLaunchActivity—>performLaunchActivity
The detailed source code is shown below
1. Start the Activity
OnClick (View View)–>startActivitySafely(v, intent, tag)–>startActivity(View V, Intent, tag) Intent Intent, Object tag) and then you go directly to the Activity’s startActivity(Intent Intent) method
/**
2031 * Launches the intent referred by the clicked shortcut.
2032 *
2033 * @param v The view representing the clicked shortcut.
2034 */
2035 public void onClick(View v) {
2036 .....
2045
2046 Object tag = v.getTag();
2047 if(tag instanceof ShortcutInfo) { 2048 .......... 2054 / / = = = = = = = = = = = = = = = = = note = = = = = = = = = = = = = = = = = = = 2055 Boolean success = startActivitySafely (v, intent, the tag); 2056 2057... 2061 } 2072 } boolean startActivitySafely(View v, Intent intent, Object tag) { 2216 boolean success =false; 2217 try {/ / = = = = = = = = = = = = = = = = = note = = = = = = = = = = = = = = = = = = = 2218 success = startActivity (v, intent, the tag); 2219 } catch (ActivityNotFoundException e) { 2220 Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); 2221 Log.e(TAG,"Unable to launch. tag=" + tag + " intent="+ intent, e); 2222} 2223returnsuccess; 2224 } boolean startActivity(View v, Intent intent, Object tag) { 2175 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2176 2184 this.getSystemService(Context.LAUNCHER_APPS_SERVICE); 2185... 2197if(user = = null | | user. Equals (android. OS. Process. MyUserHandle ())) {/ / = = = = = = = = = = = = = = = = = note = = = = = = = = = = = = = = = = = = = 2198 startActivity(intent); 2199}else{ 2200 launcherApps.startMainActivity(intent.getComponent(), user, 2201 intent.getSourceBounds(), null); 2202} 2203... 2204, 2212,return false; 2213}Copy the code
Activity : startActivity–>startActivityForResult
The first time mParent is null calls the Instrumentation execStartActivity directly
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
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) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if(options ! = null) { mParent.startActivityFromChild(this, intent, requestCode, options); }else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
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); . }Copy the code
Instrumentation:execStartActivity()–>ActivityManagerService :startActivity ()–>startActivityAsUser()
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { .... try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); / / = = = = = = = = = = = = = = = = = note -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 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;
}
Copy the code
ActivityManager here. GetService () to obtain is ActivityManagerService instance executes is in ActivityManagerService startActivity to get to
@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 final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivity");
userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// TODO: Switch to user app stacks here.
return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
Copy the code
ActivityStarter:execute()–>startActivity()–>startActivityUnchecked (
The code above ends up executing ActivityStarter’s execute() method
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.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);
} else {
returnstartActivity(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); } } finally { onExecutionComplete(); }}Copy the code
So this if condition here is going to eventually execute to the startActivity method in the else and then call both startActivity again and it’s going to go to the startActivityUnchecked method
.if(mTargetStack.isFocusable() && ! mSupervisor.isFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked"); } / / in the end method has this method mSupervisor resumeFocusedStackTopActivityLocked (mTargetStack mStartActivity, mOptions); }...Copy the code
ActivityStackSupervisor:resumeFocusedStackTopActivityLocked()
ActivityStackSupervisor->resumeFocusedStackTopActivityLocked
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if(! readyToResume()) {return false;
}
if(targetStack ! = null && isFocusedStack(targetStack)) {return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if(r == null || ! R.i sState (RESUMED)) {/ / = = = = = = = = = = = = = note = = = = = = = = = = = mFocusedStack. ResumeTopActivityUncheckedLocked (null, null); }else if (r.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
return false;
}
Copy the code
ActivityStarter :resumeTopActivityUncheckedLocked()–>resumeTopActivityInnerLocked
Perform the ActivityStackSupervisor resumeFocusedStackTopActivityLocked returned to the ActivityStarter In the call resumeTopActivityUncheckedLocked method
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
.............
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true; / / = = = = = = = = note = = = = = = = = = = = = the result = resumeTopActivityInnerLocked (prev, options); . } finally { mStackSupervisor.inResumeTopActivity =false;
}
return result;
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
..................................
} else {
// Whoops, need to restart this activity!
if(! next.hasBeenLaunched) { next.hasBeenLaunched =true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(null /* prev */, false /* newTask */,
false /* taskSwich */);
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting "+ next); / / = = = = = = = = = = = = = = = = = = = = note = = = = = = = = = = = = = = = = = = = = mStackSupervisor. StartSpecificActivityLocked (next,true.true);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
Copy the code
ActivityStackSupervisor: startSpecificActivityLocked () – > realStartActivityLocked activity (start)
Then after executing the startSpecificActivityLocked ActivityStackSupervisor method, this method is to judge whether ProcessRecord is empty If it is empty to initialize the process And creating an ActivityThread in this case creates the main thread for a new application. If the current process exists, realStartActivityLocked methods will be executed to open the corresponding Activity page. We first apply ProcessRecord at startup Is null
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running? ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true); getLaunchTimeTracker().setLaunchTime(r); if (app ! = null && app.thread ! = null) { try { if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 || !" android".equals(r.info.packageName)) { // Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a // separate apk in the process. app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode, mService.mProcessStats); } realStartActivityLocked(r, app, 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 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }Copy the code
2. Process creation and ActivityThread invocation
ActivityManagerService :startProcessLocked()–>startProcess()
ActivityManagerService to create a process,
@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
@GuardedBy("this") final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { ................... //=========== will create ProcessRecord first if the cache does not have a new assignment to app checkTime(startTime,"startProcess: stepping in to startProcess"); //============== note =========== final Boolean SUCCESS = startProcessLocked(app, hostingType, hostingNameStr, abiOverride); checkTime(startTime,"startProcess: done starting proc!");
returnsuccess ? app : null; }... Subsequent calls to the third startProcessLocked... private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { app.pendingStart =true;
app.killedByAm = false;
app.removed = false;
app.killed = false;
final long startSeq = app.startSeq = ++mProcStartSeqCounter;
app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
if (mConstants.FLAG_PROCESS_START_ASYNC) {
if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
"Posting procStart msg for " + app.toShortString());
mProcStartHandler.post(() -> {
try {
synchronized (ActivityManagerService.this) {
final String reason = isProcStartValidLocked(app, startSeq);
if(reason ! = null) { Slog.w(TAG_PROCESSES, app +" not valid anymore,"
+ " don't start process, " + reason);
app.pendingStart = false;
return; } app.usingWrapper = invokeWith ! = null || SystemProperties.get("wrap."+ app.processName) ! = null; mPendingStarts.put(startSeq, app); } //===================== note final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); synchronized (ActivityManagerService.this) { handleProcessStartedLocked(app, startResult, startSeq); } } catch (RuntimeException e) { synchronized (ActivityManagerService.this) { Slog.e(TAG,"Failure starting process " + app.processName, e);
mPendingStarts.remove(startSeq);
app.pendingStart = false;
forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false.false.true.false.false,
UserHandle.getUserId(app.userId), "start failure"); }}});return true;
} else{try {//===================== notice final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper, startSeq,false);
} catch (RuntimeException e) {
Slog.e(TAG, "Failure starting process " + app.processName, e);
app.pendingStart = false;
forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false.false.true.false.false,
UserHandle.getUserId(app.userId), "start failure");
}
return app.pid > 0;
}
}
private ProcessStartResult startProcess(String hostingType, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
final ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
checkTime(startTime, "startProcess: returned from zygote!");
returnstartResult; } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); }}Copy the code
Process :start ()–>ZygoteProcess:start()–>startViaZygote()–>openZygoteSocketIfNeeded()
Zygote socket connection: zygote socket connection: openZygoteSocketIfNeeded Zygote’s main() method is executed using native methods
@GuardedBy("mLock")
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
//========================
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
}
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// The primary zygote didn't match. Try the secondary. if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { try { secondaryZygoteState = ZygoteState.connect(mSecondarySocket); } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe); } maybeSetApiBlacklistExemptions(secondaryZygoteState, false); maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState); } if (secondaryZygoteState.matches(abi)) { return secondaryZygoteState; } throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); }Copy the code
ZygoteState:connect()–>zygote :main()–>zygoteServer:runSelectLoop()
The zygote main method is called
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid (0, 0)", ex);
}
final Runnable caller;
try {
// Report Zygote start time to tron unless it is a runtime restart
if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
MetricsLogger.histogram(null, "boot_zygote_init",
(int) SystemClock.elapsedRealtime());
}
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
RuntimeInit.enableDdms();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: "+ argv[i]); }}if (abiList == null) {
throw new RuntimeException("No ABI list supplied."); } / / registered socket zygoteServer. RegisterServerSocketFromEnv (socketName); // In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork.if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
bootTimingsTraceLog.traceEnd(); // ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false, 0); Zygote.nativeSecurityInit(); // Zygote process unmounts root storage spaces. Zygote.nativeUnmountStorageOnInit(); ZygoteHooks.stopZygoteNoThreadCreation(); / / = = = = = = = = = = = = = = = open systemserviceif (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} inthe parent (zygote) process, and {@code r ! = null}in the
// child (system_server) process.
if(r ! = null) { r.run();return;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever inThe zygote. //socket polls to create a new processcaller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
// We're in the child process and have exited the select loop. Proceed to execute the // command. / / = = = = = = = = = = = = = = = = = = = = ActivityThread the main method of the if (caller! = null) { caller.run(); }}Copy the code
ZygoteService—->runSelectLoop
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
//======================
final Runnable command= connection.processOneCommand(this); . } catch (Exception e) { ................. } } } } } }Copy the code
ZygoteConnection:processOneCommand()—>handleChildProc()
Runnable processOneCommand(ZygoteServer zygoteServer) {
.....................
try {
if (pid == 0) {
// inchild zygoteServer.setForkChild(); zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = herereturn handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
.................................
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if(parsedArgs.invokeWith ! = null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.remainingArgs); // Should not get here. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
if(! isZygote) {return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
returnZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); }}}Copy the code
ZtgoteInit: zygoteInit()
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit"); RuntimeInit.redirectLogStreams(); RuntimeInit.commonInit(); / / = = = = = = = = native to initialize the zygote ZygoteInit. NativeZygoteInit (); // Call ActivityThread's main methodreturn RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
Copy the code
RuntimeInit: applicationInit()
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
..............................
returnfindStaticMain(args.startClass, args.startArgs, classLoader); } 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 {/ / = = = = = = = = = = = = = = = = = = = = here through reflection calls the main method of ActivityThread 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);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
return new MethodAndArgsCaller(m, argv);
}
Copy the code
The initialization of the process and the call to ActivityTnread are complete
3. The Application of creation
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if(args ! = null) {for (int i = args.length - 1; i >= 0; --i) {
if(args[i] ! = null && args[i].startsWith(PROC_START_SEQ_IDENT)) { startSeq = Long.parseLong( args[i].substring(PROC_START_SEQ_IDENT.length())); } } } ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Copy the code
By looking at the source code for ActivityThread, you can find the startup entry of the program in the main() method. You can see that the startup entry initializes looper, and our startup logic is in the Attach method
Public static void main(String[] args) {......... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); // Start logic in attach thread. Attach (false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
}
Copy the code
AttachApplication (mAppThread, startSeq); This code calls the attachApplication method in ActivityManagerService to obtain application information, and finally calls bindApplication in ApplicationThread Through the process of distal to the callback handleBindApplication (AppBindData data) — – > app = data. Info. MakeApplication (data restrictedBackupMode, null); –> mInstrumentation.callApplicationOnCreate(app); – “app. The onCreate (); (This is the lifecycle of our initialization message)
Main ()–> Attach ()====> Mgr. attachApplication(mAppThread, startSeq);
public static void main(String[] args) { ....... PrepareMainLooper (); // initialize looper.prepareMainLooper (); // Find the valuefor {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if(args ! = null) {for (int i = args.length - 1; i >= 0; --i) {
if(args[i] ! = null && args[i].startsWith(PROC_START_SEQ_IDENT)) { startSeq = Long.parseLong( args[i].substring(PROC_START_SEQ_IDENT.length())); ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if(! system) { ViewRootImpl.addFirstDrawHandler(newRunnable() {
@Override
public void run() { ensureJitEnabled(); }}); android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
//========================
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// Watch for getting close
..............................
}}}
Copy the code
ActivityManagerService –>attachApplication–> ApplicationThread.bindApplication()–>attachApplicationLocked
void attachApplicationLocked() {...if(app.isolatedEntryPoint ! = null) { // This is an isolated processwhich should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
} else if(app.instr ! = null) { thread.bindApplication(processName, appInfo, providers, app.instr.mClass, profilerInfo, app.instr.mArguments, app.instr.mWatcher, app.instr.mUiAutomationConnection,testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.persistent, new Configuration(getGlobalConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, isAutofillCompatEnabled); }else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.persistent, new Configuration(getGlobalConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, isAutofillCompatEnabled); }... }Copy the code
ApplicationThread bindApplication sends a handler message, sendMessage(h.bin_application, The data callback to handleBindApplication executes the mInstrumentation in the makeApplication method The mActivityThread. MInstrumentation. NewApplication (cl, appClass, appContext); Create the Application object and call the attach method
private void handleBindApplication(AppBindData data) {
if((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) ! = 0) { dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); }else {
// Small heap, clamp to the current growth limit and let the heap release
// pages after the growth limit to the non growth limit capacity. b/18387825
dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
}
// Allow disk access during application and provider setup. This could
// block processing ordered broadcasts, but later processing would
// probably end up doing the same disk access.
Application app;
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
try {
// If the app is being launched for full backup or restore, bring it up in/ / = = = = = = = = = = = = = = = = = = = create Application app = data. Info. MakeApplication (data restrictedBackupMode, null); // Propagate autofill compat state app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled); mInitialApplication = app; // don't bring up providers in restricted mode; they may depend on the // app's custom Application class
if(! data.restrictedBackupMode) {if(! ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers); // For process that contains content providers, we want to // ensure that the JIT is enabled"at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing. try { mInstrumentation.onCreate(data.instrumentationArgs); } catch (Exception e) { throw new RuntimeException( "Exception thrown in onCreate() of " + data.instrumentationName + ": " + e.toString(), e); } the try {/ / callback mInstrumentation onCreate method of Application. The callApplicationOnCreate (app); } catch (Exception e) { if (! mInstrumentation.onException(app, e)) { throw new RuntimeException( "Unable to create application " + app.getClass().getName() + ": " + e.toString(), e); }}...Copy the code
At this point, the creation of the Application completes the loop code up to attachApplicationLocked in ActivityManagerService, the second half of the method that calls back the code for ApplicationThread This is where the Activity creation process is performed
5. The Activity of creation
attachApplicationLocked ()
In the second half of the code of the attachApplicationLocked StackSupervisor. AttachApplicationLocked (app) this call is to create the Activity
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true; }}Copy the code
ActivityStackSupervisor: attachApplicationLocked()—>realStartActivityLocked()
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { ... try { ... final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread, r.appToken); / / note: LaunchActivityItem ResumeActivityItem clientTransaction. AddCallback (LaunchActivityItem. Obtain (new Intent(r.intent), System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global // and override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, mService.isNextTransitionForward(), profilerInfo)); // Set desired final state. final ActivityLifecycleItem lifecycleItem;if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else{ lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); / / the Schedule transaction. / / the Activity starting the transaction mService. GetLifecycleManager () scheduleTransaction (clientTransaction); . } catch (RemoteException e) {if(r.launchfailed) {// Handle the exception of the second startup failurereturn false; } // The first startup failed, try r.launchfailed =true; app.activities.remove(r); throw e; } } finally { endDeferResume(); }...return true;
}
Copy the code
#####mService.getLifecycleManager().scheduleTransaction(clientTransaction)–> Transactionexecutor. Java —-> Execute (Transaction) finally LaunchActivityItem’s excute method to call ActivityThread The handleLaunchActivity
public void execute(ClientTransaction transaction) {
final IBinder token = transaction.getActivityToken();
log("Start resolving transaction for client: " + mTransactionHandler + ", token: "+ token); = = = = = = = = = = = = = = = = = = note = = = = = = = = = = = = / / the implementation of the Activity to create executeCallbacks (transaction); // state callback onStart onResume executeLifecycleState(transaction); mPendingActions.clear();log("End resolving transaction");
}
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
if (callbacks == null) {
// No callbacks to execute, return early.
return;
}
log("Resolving callbacks");
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(); // Loop through the previously added set to create the Ativity and execute onResume for (int I = 0; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); log("Resolving callback: " + item); final int postExecutionState = item.getPostExecutionState(); final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r, item.getPostExecutionState()); if (closestPreExecutionState ! = UNDEFINED) { cycleToPath(r, closestPreExecutionState); ActivityThread Item. execute(mTransactionHandler, Token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); if (r == null) { // Launch activity request will create an activity record. r = mTransactionHandler.getActivityClient(token); } if (postExecutionState ! = UNDEFINED && r ! = null) { // Skip the very last transition and perform it by explicit state request instead. final boolean shouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; cycleToPath(r, postExecutionState, shouldExcludeLastTransition); } } } @Override 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); \ / / = = = = = = = = = = = = = = = = = ActivityThread create Activity client. HandleLaunchActivity (r, pendingActions, null customIntent / * * /); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }Copy the code
ActivityThread: handleLaunchActivity—>performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ......... / / = = = = = = = = = = = = = = = = = = = create Activity = = = = = = = = = = = = = = = = = = = = = = = = Activity Activity = null; try { 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) {if(! mInstrumentation.onException(activity, e)) { throw new RuntimeException("Unable to instantiate activity " + component
+ ":"+ e.toString(), e); } } try { ............................. / / = = = = = = = = = = = = = = = = = = = = = the Activity of the attach method = = = = = = = = = = = = Activity. The attach (appContext, this getInstrumentation (), r.t oken, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback);if(customIntent ! = null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; checkAndBlockForNetworkAccess(); activity.mStartedActivity =false;
int theme = r.activityInfo.getThemeResource();
if(theme ! = 0) { activity.setTheme(theme); } / / = = = = = = = = = = = = = = = = = = = = = the Activity's lifecycle callback = = = = = = = = = = = = Activity. MCalled =false;
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);
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if(! mInstrumentation.onException(activity, e)) { throw new RuntimeException("Unable to start activity " + component
+ ":"+ e.toString(), e); }}return activity;
}
Copy the code