preface

The previous article talked about the four components of the startup and the startup of the launcher. This article will finally talk about the application of the startup of the Activity, I wanted to continue this module, but considering that there is some pre-knowledge in the system startup, I will leave it here

For young comrades who do not speak martial arts, you can still see the summary at the end of the article

above

  • Android System Revealed (1) -Activity startup process (1)
  • Android System Revealed (1) -Activity startup process (1)
  • Android System Disclosure (2) -Service startup process
  • Android System Revealed (3) – Overview of Android system startup
  • Android System Revealed (4) – The launch of the Launcher

Where is the application launched

Normally, the application is created when we start the first Activity and we looked at this code when the Activity started

Frameworks/base/services/core/Java/com/android/server/am/ActivityStackSupervisor. Java (android8, 9)

void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { ... / / start the application process mService. StartProcessLocked (r.p rocessName, r.i show nfo. ApplicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }Copy the code

Frameworks/base/services/core/Java/com/android/server/wm/ActivityStackSupervisor. Java (android10, 11)

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) { ... try { ... / / notice to start the application final Message MSG = PooledLambda. ObtainMessage (ActivityManagerInternal: : startProcess, mService mAmInternal, r.processName, r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent()); mService.mH.sendMessage(msg); } finally { Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }}Copy the code

The ActivityManagerInternal implementer for Android 10 is AMS Frameworks/base/services/core/Java/com/android/server/am/ActivityManagerService. Java (android10, 11)

@Override public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName) { try { ... synchronized (ActivityManagerService.this) { startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */, new HostingRecord(hostingType, hostingName, isTop), ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */, false /* isolated */, true /* keepIfLarge */); } } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); }}Copy the code

As you can see, the application is started by AMS’s startProcessLocked method

AMS sends a request to start the application process

Android 8-9 Timing diagram:



Android 10-11 Timing diagram:



frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { ... try { try { final int userId = UserHandle.getUserId(app.uid); AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } // get user ID of the application process to be created int uid = app.uid; int[] gids = null; int mountExternal = Zygote.MOUNT_EXTERNAL_NONE; if (! app.isolated) { int[] permGids = null; try { checkTime(startTime, "startProcess: getting gids from package manager"); final IPackageManager pm = AppGlobals.getPackageManager(); permGids = pm.getPackageGids(app.info.packageName, MATCH_DEBUG_TRIAGED_MISSING, app.userId); StorageManagerInternal storageManagerInternal = LocalServices.getService( StorageManagerInternal.class); mountExternal = storageManagerInternal.getExternalStorageMountMode(uid, app.info.packageName); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } /* * Add shared application and profile GIDs so applications can share some * resources like shared libraries and If (arrayutils.isempty (permGids)) {gids = new int[3]; } else { gids = new int[permGids.length + 3]; System.arraycopy(permGids, 0, gids, 3, permGids.length); } gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid)); gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid)); gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid)); }... if (entryPoint == null) entryPoint = "android.app.ActivityThread"; Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName); checkTime(startTime, "startProcess: asking zygote to start proc"); ProcessStartResult startResult; if (hostingType.equals("webview_service")) { startResult = startWebView(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, entryPointArgs); Start (entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, entryPointArgs); }... } catch (RuntimeException e) { Slog.e(TAG, "Failure starting process " + app.processName, e); forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, UserHandle.getUserId(app.userId), "start failure"); }}Copy the code

If android 10 is behind, start with ProcessList

   @GuardedBy("this")
    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
                keepIfLarge, null /* ABI override */, null /* entryPoint */,
                null /* entryPointArgs */, null /* crashHandler */);
    }
Copy the code

frameworks/base/services/core/java/com/android/server/am/ProcessList.java

@GuardedBy("mService") boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks, boolean mountExtStorageFull, String abiOverride) { .... return startProcessLocked(hostingRecord, entryPoint, app, uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); } catch (RuntimeException e) { ... return false; }}Copy the code

The next Process – > start () method is used to start the frameworks/base/core/Java/android/OS/Process. Java

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String invokeWith,
                              String[] zygoteArgs) {
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
Copy the code

Process is started by calling ZygoteProcess

frameworks/base/core/java/android/os/ZygoteProcess.java

public final Process.ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String invokeWith, String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); throw new RuntimeException( "Starting VM process through Zygote failed", ex); }}Copy the code

Look at the startViaZygote method

private Process.ProcessStartResult startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String invokeWith, String[] extraArgs) throws ZygoteStartFailedEx { ArrayList<String> argsForZygote = new ArrayList<String>(); // --runtime-args, --setuid=, --setgid=, // and --setgroups= must go first argsForZygote.add("--runtime-args"); argsForZygote.add("--setuid=" + uid); argsForZygote.add("--setgid=" + gid); if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) ! = 0) { argsForZygote.add("--enable-jni-logging"); }... synchronized(mLock) { return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); }}Copy the code

This method the parameters into the array, and get the Zygote connection, together sent to zygoteSendArgsAndGetResult method We see first get openZygoteSocketIfNeeded Zygote connection method

/** * Tries to open socket to Zygote process if not already open. If * already open, does nothing. May block and retry. Requires that mLock be held. */ @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 = a connection is established with the Zygote process ZygoteState.connect(mSocket); } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe); }} / if/whether abi matching (primaryZygoteState. Matches (abi)) {return primaryZygoteState; } / / don't match, try to Zygote auxiliary mode if (secondaryZygoteState = = null | | secondaryZygoteState. IsClosed ()) {try {secondaryZygoteState =  ZygoteState.connect(mSecondarySocket); } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe); } } if (secondaryZygoteState.matches(abi)) { return secondaryZygoteState; } throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); }Copy the code

Then watch zygoteSendArgsAndGetResult method

@GuardedBy("mLock") private static Process.ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx { try { int sz = args.size(); for (int i = 0; i < sz; i++) { if (args.get(i).indexOf('\n') >= 0) { throw new ZygoteStartFailedEx("embedded newlines not allowed"); } } final BufferedWriter writer = zygoteState.writer; final DataInputStream inputStream = zygoteState.inputStream; writer.write(Integer.toString(args.size())); writer.newLine(); for (int i = 0; i < sz; i++) { String arg = args.get(i); writer.write(arg); writer.newLine(); } writer.flush(); // Should there be a timeout on this? Process.ProcessStartResult result = new Process.ProcessStartResult(); result.pid = inputStream.readInt(); result.usingWrapper = inputStream.readBoolean(); if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } return result; } catch (IOException ex) { zygoteState.close(); throw new ZygoteStartFailedEx(ex); }}Copy the code

It writes data to ZygoteState

Android after 10 is written in attemptZygoteSendArgsAndGetResult method

 @GuardedBy("mLock")
    private Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)
            throws ZygoteStartFailedEx {
          ...
        String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";

        if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) {
            try {
                return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
            } catch (IOException ex) {
                Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
                        + ex.getMessage());
            }
        }

        return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
    }

    private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
            ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
        try {
            final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
            final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;

            zygoteWriter.write(msgStr);
            zygoteWriter.flush();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            Process.ProcessStartResult result = new Process.ProcessStartResult();
            result.pid = zygoteInputStream.readInt();
            result.usingWrapper = zygoteInputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }

            return result;
        } catch (IOException ex) {
            zygoteState.close();
            Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
                    + ex.toString());
            throw new ZygoteStartFailedEx(ex);
        }
    }

Copy the code

Zygote receives the request and creates the application process

Then let’s examine the Zygote request receiving steps

Take a look at the sequence diagram:

At system startup section we analyzed the start of the Zygote, one Runnable frameworks/base/core/Java/com/android/internal/OS/ZygoteInit. Java

public static void main(String argv[]) { ZygoteServer zygoteServer = new ZygoteServer(); . final Runnable caller; try { ... String socketName = "zygote"; / / wait for AMS caller = zygoteServer runSelectLoop (abiList); } catch (Throwable ex) { Log.e(TAG, "System zygote died with exception", ex); throw ex; } finally { zygoteServer.closeServerSocket(); } if (caller ! = null) { caller.run(); }}Copy the code

The runSelectLoop method is a circulator that receives messages from AMS

frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

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) { ... 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

The Zygote connected processOneCommand method (runOnce for Android 8.0) processes the command when it is received. The details of the code vary in other versions, but the process is the same

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

Runnable processOneCommand(ZygoteServer zygoteServer) { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; Try {// Get the application start argument args = readentList (); // Args = zygote. readentList (mSocketReader); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { throw new IllegalStateException("IOException on command socket", ex); }... Gid, parseDargs.gids, parseDargs.debugFlags, Zygote. ForkAndSpecialize (parsedargs.uid, parsedargs.gid, ParseDargs.gids, parsedargs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet, parsedArgs.appDataDir); Try {the if (pid = = 0) {/ / child zygoteServer setForkChild (); zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; return handleChildProc(parsedArgs, descriptors, childPipeFd); } else {ioutils. closeQuietly(childPipeFd); childPipeFd = null; handleParentProc(pid, descriptors, serverPipeFd); return null; } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); }}Copy the code

As you can see, Zygote gets the start parameters, then forks the process, and then starts processing the application process if PI returns 0. Android 10 gets parameters from the Zygote class

    private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd) {
        ...

        // 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 {
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                    null /* classLoader */);
          
        }
    }
Copy the code

This approach will be different after Android 10

private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor pipeFd, boolean isZygote) { ... if (parsedArgs.mInvokeWith ! = null) { .... } else { if (! isZygote) { return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mDisabledCompatChanges, parsedArgs.mRemainingArgs, null /* classLoader */); } else {/ / jump start Binder thread pool return ZygoteInit. ChildZygoteInit (parsedArgs. MTargetSdkVersion, parsedArgs mRemainingArgs, null /* classLoader */); }}}Copy the code

We then call the ZygoteInit method of ZygoteInit

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

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(); / / create a Binder thread pool ZygoteInit. NativeZygoteInit (); / / initializes the application return RuntimeInit. ApplicationInit (targetSdkVersion, argv, this); }Copy the code

This step will create Binder thread pool, and then inform the initialization application frameworks/base/core/Java/com/android/internal/OS/RuntimeInit. Java

protected static Runnable applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) { nativeSetExitWithoutCleanup(true); VMRuntime. GetRuntime (). SetTargetHeapUtilization (0.75 f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args = new Arguments(argv); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Android8.0 invokeStaticMain return findStaticMain(args. StartClass, args. StartArgs, classLoader); }Copy the code

Call the main method through reflection

private static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<? > cl; try { // android.app.ActivityThread 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); } 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);} // Remove all stack frames required by the setup process and make the Main method of ActivityThread look like the entry method of the application process. }Copy the code

The className here is android. App. ActivityThread, call the main method of ActivityThread through reflection

frameworks/base/core/java/android/app/ActivityThread.java

public static void main(String[] args) { ... / / initialize the Environment Environment. InitForCurrentUser (); . PrepareMainLooper (); prepareMainLooper(); // Create ActivityThread ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }Copy the code

conclusion

  • Call THE startProcessLocked method of AMS to send a request to start the application process
  • Zygote receives the request and creates the application process

AMS sends a request to start the application process

Android 8-9 Timing diagram:



Android 10-11 Timing diagram:

Zygote receives the request and creates the application process

Afterword.

I believe that can digest the reader here has a certain source reading ability.

Revelations about the system will be updated as a column from time to time.

Another is that IO conference said Android 12 underlying code has a big update, so it is estimated that in the near future, there will be a relatively large expansion, to follow the Android 12 update