I’m participating in nuggets Creators Camp # 4, click here to learn more and learn together!
Application Process Startup Process Analysis (Server)
In the previous analysis of the application Process startup Process (client), it was analyzed that when the process. start function was called, the corresponding connection was established through the socket corresponding to zygote, and then the parameter data was sent to the server through the socket communication. Then the server received the corresponding parameters, how to Process it?
Zygoteinit. main (zygoteinit. main) ¶ Zygoteinit. main (zygoteinit. main) ¶ The system_server process is forked, but a ZygoteServer object is initialized
public static void main(String argv[]) {
ZygoteServer zygoteServer = null;
/ / /...
Runnable caller;
try {
/ /...
Initialize the ZygoteServer object
zygoteServer = new ZygoteServer(isPrimaryZygote);
/ /...
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
}
/ /...
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if(caller ! =null) { caller.run(); }}Copy the code
After the ZygoteServer object is initialized, its runSelectLoop function is called and a Runnable object is returned, which is then run
In the runSelectLoop function, a while infinite loop is started, waiting for the Socket to connect
Runnable runSelectLoop(String abiList) {
/ /...
while (true) {
/ /...
int pollReturnValue;
try {
// Iterate over the polling all as pollFDs
pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
}
/ /...
{
boolean usapPoolFDRead = false;
while (--pollIndex >= 0) {
/ /...
// When the ZygoteServer is 0, it indicates that there is a client to connect after ZygoteServer starts
if (pollIndex == 0) {
Call the acceptCommandPeer function to initialize a ZygoteConnection object after receiving a client connection request
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
// At least one ZygoteConnection connection has been established
} else if (pollIndex < usapPoolEventFDIndex) {
/ /...
try {
// Get the corresponding ZygoteConnection object and call its processOneCommand function
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);
log("runSelectLoop : mIsForkChild = " + mIsForkChild);
// TODO (chriswailes): Is this extra check necessary?
if (mIsForkChild) {
// We're in the child. We should always have a command to run at
// this stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
returncommand; }}/ /...}}/ /...
}
/ /...}}Copy the code
When ZygoteServer is initialized and runSelectLoop is called, an infinite while loop is initiated. When a client connection request is received, the acceptCommandPeer function is called, Initialization establishes link ZygoteConnection
When a message request is received, since the peers contain a ZygoteConnection link, the link is retrieved, its processOneCommand function is called, a thread is returned, and the thread’s run function is finally called in zygoteinit. main
i.e.
Create a ZygoteConnection link
private ZygoteConnection acceptCommandPeer(String abiList) {
/ /...
return createNewConnection(mZygoteSocket.accept(), abiList);
}
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
return new ZygoteConnection(socket, abiList);
}
Copy the code
That is, initialize a ZygoteConnection object in a ZygoteServer
Run the ZygoteConnection processOneCommand function
Runnable processOneCommand(ZygoteServer zygoteServer) {
String[] args;
/ /...
// Read the parameter data from zygote socket
args = Zygote.readArgumentList(mSocketReader);
/ /...
// Convert to an array of recognizable parameters
ZygoteArguments parsedArgs = new ZygoteArguments(args);
/ /... Parameter configuration
// Call Zygote's Forkandwpecte function
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList,
parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
/ /...
return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
/ /...
}
Copy the code
Zygote. Forkandwte ends up calling the Native layer’s fork function. Fork a Launcher application in the kernel and, after a series of operations, Will call ZygoteConnection handleChildProc function
private Runnable handleChildProc(ZygoteArguments parsedArgs,
FileDescriptor pipeFd, boolean isZygote) {
/ /...
// Close the current SOCKET link
closeSocket();
// Set the process name
Zygote.setAppProcessName(parsedArgs, TAG);
/ /...
// Through the ZygoteInit function of the ZygoteInit object
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, null /* classLoader */);
/ /...
}
public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
/ /...
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
}
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
/ /...
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<? > cl;try {
// Find the corresponding Class
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
// Find the main function in the corresponding Class
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);
}
/ /...
// Finally returns the MethodAndArgsCaller object
return new MethodAndArgsCaller(m, argv);
}
Copy the code
As you can see from the flow above, a MethodAndArgsCaller object is finally initialized and returned from its class diagram structure
ClassDiagram Runnable < | - MethodAndArgsCaller: < < interface > > Runnable RuntimeInit * -- MethodAndArgsCaller: inner classes
Returns an object that implements the Runnable interface
To sort out the process,
- In ZygoteInit’s main function, we initialize a ZygoteServer object,
- It then calls its runSelectLoop function, which implements a while loop in the main thread,
- In this infinite loop, the zygote socket client is waiting for a connection. Once the connection request is received, the acceptCommandPeer function initializes a ZygoteConnection link and calls the processOneCommand function of the link.
- The JNI function forks an application process in kernel space, and eventually calls ZygoteConnection’s handleChildProc through a series of process scheduling operations, and finally returns a MethodAndArgsCaller object. The MethodAndArgsCaller object is an object that implements the Runnable interface
Run the MethodAndArgsCaller object obtained above
Back in ZygoteInit’s main function, you can see that runSelectLoop does not return null for MethodAndArgsCaller, so run the Runnable thread
ZygoteInit.main
if (caller ! =null) {
caller.run();
}
static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run(a) {
/ /...
mMethod.invoke(null.new Object[] { mArgs });
/ /...}}Copy the code
According to the previous analysis, this MethodAndArgsCaller mMethod parameters corresponding to the android. OS. ActivityThread main function of a class, and then through reflection calls to this function
public static void main(String[] args) {
/ /...
Environment.initForCurrentUser();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
// Call per-process mainline module initialization.
initializeMainlineModules();
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();
}
/ /...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Copy the code
Finally, the specific Activity of the corresponding application is launched in the ActivityThread object, which will be updated later