4.App进程的启动

2020-03-07  本文已影响0人  梦想黑客

进程是如何启动的?

Android中进程的启动是被动的,当其他进程调用其他组件(四大组件)的时候,如果发现该组件所在的进程还没有启动,就会先向Zygote进程请求启动新的进程,再进行后续组件的启动。

所以进程启动的流程是:App -> AMS -> Zygote -> 新App

image
  1. App发起进程:当从桌面启动应用,则发起进程便是Launcher所在进程;当从某App内启动远程进程,则发送进程便是该App所在进程。发起进程先通过binder发送消息给system_server进程;
  2. system_server进程:调用Process.start()方法,通过socket向zygote进程发送创建新进程的请求;
  3. zygote进程:在执行ZygoteInit.main()后便进入runSelectLoop()循环体内,当有客户端连接时便会执行ZygoteConnection.runOnce()方法,再经过层层调用后fork出新的应用进程;
  4. 新进程:执行handleChildProc方法,最后调用ActivityThread.main()方法。

因为第一步发起的途径有很多startActivity、startService,这些后面单独介绍,本章先从system_server进程调用Process.start()方法开始。

Process.start()流程

1.Process.start()

 public static ProcessStartResult start(@NonNull final String processClass,
                                           @Nullable final String niceName,
                                           int uid, int gid, @Nullable int[] gids,
                                           ... ... 
                                           ) {
        return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, packageName,
                    /*useUsapPool=*/ true, zygoteArgs);
    }

接着会调用到startViaZygote()方法,可知这里要和Zygote通讯了;

    private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
                                                      @Nullable final String niceName,
                                                      final int uid, final int gid,
                                                      @Nullable final int[] gids,
                                                      int runtimeFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      ... ...)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<>();

        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("--runtime-flags=" + runtimeFlags);
        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
            argsForZygote.add("--mount-external-default");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
            argsForZygote.add("--mount-external-read");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
            argsForZygote.add("--mount-external-write");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
            argsForZygote.add("--mount-external-full");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
            argsForZygote.add("--mount-external-installer");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
            argsForZygote.add("--mount-external-legacy");
        }

        ... ...
        
        synchronized(mLock) {
            // The USAP pool can not be used if the application will not use the systems graphics
            // driver.  If that driver is requested use the Zygote application start path.
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                              useUsapPool,
                                              argsForZygote);
        }
    }

该方法主要是准备参数,openZygoteSocketIfNeeded()方法会连接Zygote暴露的本地socket服务,最后调用zygoteSendArgsAndGetResult()将准备好的创建请求参数发出,最终调用attemptZygoteSendArgsAndGetResult()完成发送和读取:

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);
        }
    }

到此Process的工作就做完了,接下来看看Zygote服务端是怎么处理的。

Zygote创建进程的流程

我们知道Zygote进程创建后会通过jni调用启动ZygoteInit.java的main()方法,在main()方法里面会做如下事情:
1.预加载:preloadClasses()和preloadResources()
2.forkSystemServer,最终会调用SystemServer.java的main()方法;
3.创建ZygoteService,进入runSelectLoop;

这里的第三步就循环监听socket请求:

 Runnable runSelectLoop(String abiList) {
    
         //循环
        while (true) {
            
           ... ... 

            try {
                //监听请求,阻塞
                Os.poll(pollFDs, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }

            boolean usapPoolFDRead = false;

            while (--pollIndex >= 0) {
                if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                    continue;
                }

                if (pollIndex == 0) {
                    // Zygote server socket

                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    socketFDs.add(newPeer.getFileDescriptor());

                } else if (pollIndex < usapPoolEventFDIndex) {
                    // 接收到新的请求

                    try {
                        ZygoteConnection connection = peers.get(pollIndex);
                        
                        //请求处理
                        final Runnable command = connection.processOneCommand(this);

                    
                        if (mIsForkChild) {
                           //fork出来的子进程处理

                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }

                            return command;
                        } else {
                           //父进程处理

                            if (command != null) {
                                throw new IllegalStateException("command != null");
                            }

                            // We don't know whether the remote side of the socket was closed or
                            // not until we attempt to read from it from processOneCommand. This
                            // shows up as a regular POLLIN event in our regular processing loop.
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(pollIndex);
                                socketFDs.remove(pollIndex);
                            }
                        }
                    } catch (Exception e) {
                        ...
                    } finally {
                   
                        mIsForkChild = false;
                    }
                } 
            }

            
        }
    }

从以上代码可以知道,当有新的请求到达的时候,会创建ZygoteConnection,并调用processOneCommand方法来处理:

Runnable processOneCommand(ZygoteServer zygoteServer) {
        String args[];
        ZygoteArguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            args = Zygote.readArgumentList(mSocketReader);

            // TODO (chriswailes): Remove this and add an assert.
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            throw new IllegalStateException("IOException on command socket", ex);
        }

     

        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.mTargetSdkVersion);

        try {
            if (pid == 0) {
                // in child
                zygoteServer.setForkChild();

                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;

                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.mStartChildZygote);
            } 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);
        }
    }

可以看到会调用Zygote.forkAndSpecialize()方法进行fork操作,该方法会调用native方法进行fork,然后返回pid,根据pid分别进入不同的处理:

我们先看看handleChildProc会做什么?

private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
          FileDescriptor pipeFd, boolean isZygote) {
      
      closeSocket();
  
      return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                      parsedArgs.mRemainingArgs, null /* classLoader */);
  }

该方法主要就是关闭socket,因为新创建的进程是不需要zygote的服务来,然后调用ZygoteInit.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();    //环境初始化
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

这里主要有三个步骤:

到这里新的App进程就创建起来了。

总结

我们总结一下一个app进程的创建主要的流程:
1.调用AMS进行组件调用(startActivity、startService);
2.如果目标组件的进程未启动,则调用Process.start()向Zygote进程请求fork进程;
3.进程fork成功后会执行ActivityThread的main()方法,之后会调用IActivityManager.attachApplication(IApplicationThread)方法来告诉AMS新的进程已经启动了;
4.AMS接收到attachApplication请求后,就会继续步骤1的操作,进行组件启动;

本章只介绍到了1,2步骤,接下来会继续分析进程创建成功之后的操作。

上一篇下一篇

猜你喜欢

热点阅读