zoukankan      html  css  js  c++  java
  • ZygoteInit 相关分析

    上一篇文章我们已经分析到调用com.android.internal.os.ZygoteInit类的main函数

    今天分析一下com.android.internal.os.ZygoteInit类的main函数

    public static void main(String argv[]) {
           // 注册zygote的socket
        registerZygoteSocket();
        //加载Android Application Framework使用的类与资源
        preloadClasses();
        preloadResources();

        //启动SystemServer
        if(argv[1].equals("true")) {
          startSystemServer();
        }
    /** * 处理客户端连接及请求。由zygoteConnection的runOnce函数来处理。
        */ runSelectLoopMode();
    }

    在main函数我们就主要看registerZygoteSocket()与runSelectLoopMode()。

    • registerZygoteSocket():就是创建一个localsocket,也就是说注册了一个zygote的服务端socket。
    • runSelectLoopMode():就是一直无限循环,等待客户端socket的连接,然后通过zygoteConnectionrunOnce函数来处理对应的请求。
    • PreloadClass(): 读取framework/base/tools/preload/preload_class文件约1268类。

    • PreloadResources(): 加载framework-res.apk中的资源。

    • gc():执行垃圾收集。

    那么我们就看一下registerZygoteSocket()

    private static void registerZygoteSocket() {
           
           String env = System.getenv(ANDROID_SOCKET_ENV);
          fileDesc = Integer.parseInt(env);
     
           
           if (sServerSocket == null) {
                  sServerSocket = new LocalServerSocket(
                         createFileDescriptor(fileDesc));
           }
    }

    很简单就是创建一个LocalServerSocket。

    建立IPC通信服务器,从环境变量中获取(System.getenv(ANDROID_SOCKET_ENV);)socket的fd,之前用sig的fd来调用handle去创建的zygote。

    我们在来看一下runSelectLoopMode()

    private static void runSelectLoopMode() throws MethodAndArgsCaller {
        …
           while (true) {
                  int index;
    
                  fdArray = fds.toArray(fdArray);
                  index = selectReadable(fdArray);
    
                  if(index == 0) {
                         //连接客户端发送的请求(Command)
                         ZygoteConnection newPeer = acceptCommandPeer();
                         peers.add(newPeer);
                         fds.add(newPeer.getFileDesciptor());
                  } else {
                         //处理客户端发送的请求(Command)
                         boolean done;
                         done = peers.get(index).runOnce();
                        }     
           }
    }

    这个函数也很简单等待客户端发来的请求,当接收到请求时就运行run0nce函数去处理请求即可。

    客户端可以理解成AMS或SystemServer。

    在这里简单说明一下AMS与SystemServer

    • SystemServer

        Zygote的子进程,为JAVA世界做服务。

        Java世界系统Service,此进程是framework的核心,此server挂掉了,zygote会自杀。

         Zygote.forkSystemServer()而诞生。

    • AMS

        ActivityManagerService是由SystemServer创建。

        当一个Acitvity开启的时候,是由AMS中开启一个新的Process,而在Process类中最终会创建一个LocalSocket去连接ZYGOTE_SOCKET。

          而在AMS中的startProcessLocked()中调用Process.start()函数中会传入一个参数-android.app.ActivityThread。最终会通过socket传入zygote处理。

    我们继续看以下done = peers.get(index).runOnce();

    boolean runOnce( ) {
           Arguments parsedArgs = null;
           FileDescriptor[] descriptors;
    
           //Reads command socket.
           args = readArgumentList();
           descriptors = mSocket.getAncillaryFileDescriptors();
    
           try {  
                parsedArgs = new Arguments(args);  
                ......  
      
                pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,  
                        parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,  
                        parsedArgs.niceName);  
            } catch (IOException ex) {  
                ......  
            } catch (ErrnoException ex) {  
                ......  
            } catch (IllegalArgumentException ex) {  
                ......  
            } catch (ZygoteSecurityException ex) {  
                ......  
            }  
    
           
        //新创建的进程 pid == 0
    if (pid == 0) { // in child serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); return true; } else { // in parent,也就是Zygote进程执行过程
    childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } }

    我们分析一下以下几个函数

    • readArgumentList()与parsedArgs = new Arguments(args) 是用来获取command和解析command的。
    • Zygote.forkAndSpecialize()是很简单的,就是去调用native函数来fork的。
    • handleChildProc()是处理子进程。
    • handleParentProc()是处理父进程。也就是zygote进程,此函数会原路返回,通过socket的写入返还给systemserver最终到AMS,然后重新进入runSelectLoopMode。

    首先我们来看一下forkAndSpecialize()

    这个函数定义在文件libcore/dalvik/src/main/java/dalvik/system/Zygote.java中。

    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,  
                int[][] rlimits, int mountExternal, String seInfo, String niceName) {  
            preFork();  
            int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName);  
            postFork();  
            return pid;  
        }

    很简单就是调用native的ForkAndSpecialize函数。
    JNI函数nativeForkAndSpecialize的由Dalvik_dalvik_system_Zygote_forkAndSpecialize函数来实现。

    那我们就去看一下。

    这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.cpp中。

    static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args, JValue* pResult)  
    {  
    
    pid_t pid;
      //args指向的一块内存中 pid
    = forkAndSpecializeCommon(args, false); RETURN_INT(pid); }

    Dalvik_dalvik_system_Zygote_forkAndSpecialize函数通过调用forkAndSpecializeCommon函数来执行创建进程,

    实现如下所示:

    这个函数定义在文件dalvik/vm/native/dalvik_system_Zygote.cpp中。

    static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
    {
        pid_t pid;
    
        uid_t uid = (uid_t) args[0];
        gid_t gid = (gid_t) args[1];
        ......
        char *seInfo = NULL;
        char *niceName = NULL;
    
        if (isSystemServer) {
          //参数isSystemServer表示true时创建的是System Server进程。
      ...... }
    else {       //参数isSystemServer表示true时创建的是应用程序进程。
      ......
    } ...... pid = fork();   //表示当前是新创建的进程 if (pid == 0) { ...... err = setSELinuxContext(uid, isSystemServer, seInfo, niceName); ...... } ...... return pid; }

    我们不去看具体代码实现,主要了解一下主要是干什么的就可以了。
    我们要知道的是zygote是负责应用程序进程与SystemServer的进程就可以了。

    接下来我们回到之前的handleParentProc()

    private boolean handleParentProc(int pid,  
            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {  
        if (pid > 0) {  
            setChildPgid(pid);  
        }  
        if (descriptors != null) {  
            for (FileDescriptor fd: descriptors) {  
                IoUtils.closeQuietly(fd);  
            }  
        }  
        boolean usingWrapper = false;  
        if (pipeFd != null && pid > 0) {  
            DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));  
            int innerPid = -1;  
            try {  
                innerPid = is.readInt();  
            } catch (IOException ex) {  
                Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);  
            } finally {  
                try {  
                    is.close();  
                } catch (IOException ex) {  
                }  
            }  
            // Ensure that the pid reported by the wrapped process is either the  
            // child process that we forked, or a descendant of it.  
            if (innerPid > 0) {  
                int parentPid = innerPid;  
                while (parentPid > 0 && parentPid != pid) {  
                    parentPid = Process.getParentPid(parentPid);  
                }  
                if (parentPid > 0) {  
                    Log.i(TAG, "Wrapped process has pid " + innerPid);  
                    pid = innerPid;  
                    usingWrapper = true;  
                } else {  
                    Log.w(TAG, "Wrapped process reported a pid that is not a child of "  
                            + "the process that we forked: childPid=" + pid  
                            + " innerPid=" + innerPid);  
                }  
            }  
        }  
        //将创建的应用程序进程ID返回给SystemServer进程的ActivityManagerService服务  
        try {  
            mSocketOutStream.writeInt(pid);  
            mSocketOutStream.writeBoolean(usingWrapper);  
        } catch (IOException ex) {  
            Log.e(TAG, "Error reading from command socket", ex);  
            return true;  
        }  
        /* 
         * If the peer wants to use the socket to wait on the 
         * newly spawned process, then we're all done. 
         */  
        if (parsedArgs.peerWait) {  
            try {  
                mSocket.close();  
            } catch (IOException ex) {  
                Log.e(TAG, "Zygote: error closing sockets", ex);  
            }  
            return true;  
        }  
        return false;  
    }  

    也就是创建失败会进入此函数,也就是处理zygote进程的函数,此函数会原路返回,通过socket的写入返还给systemserver最终到AMS,然后重新进入runSelectLoopMode。继续监听客户端的请求。

    如果我们新创建进程成功了,会调用handleChildProc()。

    代码如下

    private void handleChildProc(Arguments parsedArgs,  
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)  
            throws ZygoteInit.MethodAndArgsCaller {  
        /* 
         * Close the socket, unless we're in "peer wait" mode, in which 
         * case it's used to track the liveness of this process. 
         */  
      
        if (parsedArgs.peerWait) {  
            try {  
                ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);  
                sPeerWaitSocket = mSocket;  
            } catch (IOException ex) {  
                Log.e(TAG, "Zygote Child: error setting peer wait "  
                        + "socket to be close-on-exec", ex);  
            }  
        } else {//关闭从Zygote进程复制过来的Socket连接  
            closeSocket();  
            ZygoteInit.closeServerSocket();  
        }  
        if (descriptors != null) {  
            try {  
                //为新创建的应用程序进程重新打开标准输入输出控制台  
                ZygoteInit.reopenStdio(descriptors[0],descriptors[1], descriptors[2]);  
                for (FileDescriptor fd: descriptors) {  
                    IoUtils.closeQuietly(fd);  
                }  
                newStderr = System.err;  
            } catch (IOException ex) {  
                Log.e(TAG, "Error reopening stdio", ex);  
            }  
        }  
        //设置新进程名称  
        if (parsedArgs.niceName != null) {  
        //设置新进程名称niceName是指systemServer
    Process.setArgV0(parsedArgs.niceName); }
    //重新初始化Runtime if (parsedArgs.runtimeInit) { if (parsedArgs.invokeWith != null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, pipeFd, parsedArgs.remainingArgs); } else { //为应用程序进程启动Binder线程池 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs); } } else { String className; try { //读取新进程执行的类名,在Process.start()函数中,传过来的类名为:"android.app.ActivityThread" className = parsedArgs.remainingArgs[0]; } catch (ArrayIndexOutOfBoundsException ex) { logAndPrintError(newStderr,"Missing required class name argument", null); return; } String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1]; System.arraycopy(parsedArgs.remainingArgs, 1,mainArgs, 0, mainArgs.length); if (parsedArgs.invokeWith != null) { WrapperInit.execStandalone(parsedArgs.invokeWith,parsedArgs.classpath, className, mainArgs); } else { //获取类加载器 ClassLoader cloader; if (parsedArgs.classpath != null) { cloader = new PathClassLoader(parsedArgs.classpath,ClassLoader.getSystemClassLoader()); } else { cloader = ClassLoader.getSystemClassLoader(); } //加载并执行"android.app.ActivityThread"类 try { ZygoteInit.invokeStaticMain(cloader, className, mainArgs); } catch (RuntimeException ex) { logAndPrintError(newStderr, "Error starting.", ex); } } } }

    由于应用程序启动参数中已经设置了"--runtime-init"标志位,因此新创建的应用程序进程将调用RuntimeInit.zygoteInit()函数来初始化运行时库,为应用程序启动Binder线程池,完成这些准备工作后,调用应用程序进程的入口函数ActivityThread.main()为应用程序进程创建消息循环。

    接下来我们就看一下RuntimeInit.zygoteInit()

    此函数在/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java中

    public static final void zygoteInit(int targetSdkVersion, String[] argv)  
            throws ZygoteInit.MethodAndArgsCaller {  
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");  
        //重定向Log输出流  
        redirectLogStreams();  
        //初始化运行环境  
        commonInit();  
        //启动Binder线程池  
        nativeZygoteInit();  
        //调用程序入口函数  
        applicationInit(targetSdkVersion, argv);  
    } 

    接下来我们看一下applicationInit()

    private static void applicationInit(int targetSdkVersion, String[] argv)  
            throws ZygoteInit.MethodAndArgsCaller {  
        // If the application calls System.exit(), terminate the process  
        // immediately without running any shutdown hooks.  It is not possible to  
        // shutdown an Android application gracefully.  Among other things, the  
        // Android runtime shutdown hooks close the Binder driver, which can cause  
        // leftover running threads to crash before the process actually exits.  
        nativeSetExitWithoutCleanup(true);  
      
        // We want to be fairly aggressive about heap utilization, to avoid  
        // holding on to a lot of memory that isn't needed.  
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);  
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);  
      
        final Arguments args;  
        try {  
            args = new Arguments(argv);  
        } catch (IllegalArgumentException ex) {  
            Slog.e(TAG, ex.getMessage());  
            // let the process exit  
            return;  
        }  
      
        // Remaining arguments are passed to the start class's static main  
        invokeStaticMain(args.startClass, args.startArgs);  
    } 

    在这里我们重点要看一下invokeStaticMain()
    通过调用invokeStaticMain来调用args.startClass这个类的main()方法。

    说明开启又一个新世界。

    在之前提过zygote的socket的客户端可以是AMS,下一节我们分析如何开启一个Activity。

  • 相关阅读:
    二维数组的查找问题
    将字符串编码成数值,求数值最大和问题(今日头条笔试题)
    链表的倒序打印
    求方程的近似解
    多边形构成问题(今日头条笔试题)
    各种语言数据类型大小
    luoguP1551 亲戚
    Codeforces 764 A-B
    Mixing Chemicals
    Day 8 of JZJX
  • 原文地址:https://www.cnblogs.com/hongguang-kim/p/4815351.html
Copyright © 2011-2022 走看看