美文网首页Android开发
Android Zygote进程和app进程fork过程分析1

Android Zygote进程和app进程fork过程分析1

作者: 牛晓伟 | 来源:发表于2018-02-05 20:41 被阅读137次

    dvm,app进程,linux进程三者关系

    DVM指 dalivk 的虚拟机。每一个 Android 应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik 虚拟机实例。而每一个 DVM 都是在 Linux 中的一个进程,所以说可以认为是同一个概念

    Zygote进程与app进程关系

    Zygote是java层的进程即它也拥有一个独立的Dalvik 虚拟机实例,它是被linux层的第一个用户空间Init进程所启动的,它的主要作用就是用来孵化app进程系统进程
    fork一个app进程,是通过ActivityManagerService类向Zygote发出fork命令,ActivityManagerService是在系统进程,但是Zygote处于自己的进程中,它们之间的通信没有采用binder机制,而是采用了socket机制,因此我们可以把Zygote称为一个孵化server,ActivityMamagerService称为一个client

    下面的图描述了上面的过程

    fork进程

    涉及到的类

    我们先来梳理这个过程中使用到的类,并且这些类是做什么的


    涉及到的类

    以server和client2个维度来归纳这些类

    Zygote进程启动分析

    Zygote进程启动后,ZygoteInit类的main方法会被执行

        public static void main(String argv[]) {
        try {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();
    
            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = 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.");
            }
            /*启动servier socket*/
            registerZygoteSocket(socketName);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());
    
            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();
    
            // Do an initial gc to clean up after startup
            gc();
    
            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);
    
            if (startSystemServer) {
                /*启动系统服务*/
                startSystemServer(abiList, socketName);
            }
    
            Log.i(TAG, "Accepting command socket connections");
            runSelectLoop(abiList);
    
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            //这行代码很重要
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }
    

    上面代码主要做了下面的事情:

    • registerZygoteSocket(socketName)启动一个ServerSocket
    • preload()预加载资源,预加载耗时的类
    • startSystemServer(abiList, socketName)启动系统服务,并且fork系统进程
    • runSelectLoop(abiList)监听client socket的连接

    来看下registerZygoteSocket(socketName)方法

        private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }
    
            try {
                sServerSocket = new LocalServerSocket(
                        createFileDescriptor(fileDesc));
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }
    

    代码很简单,再来看下preload()方法

      static void preload() {
        Log.d(TAG, "begin preload");
        preloadClasses();
        preloadResources();
        preloadOpenGL();
        preloadSharedLibraries();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        Log.d(TAG, "end preload");
    }
    

    预加载耗时的类,预加载资源等等其他的预加载工作,我们简单看下preloadClasses()preloadResources()所做的事情

      private static void preloadClasses() {
            .......省略代码
            is = new FileInputStream(PRELOADED_CLASSES);
             ......省略代码
            BufferedReader br
                = new BufferedReader(new InputStreamReader(is), 256);
    
            int count = 0;
            String line;
            while ((line = br.readLine()) != null) {
                // Skip comments and blank lines.
                line = line.trim();
                if (line.startsWith("#") || line.equals("")) {
                    continue;
                }
    
                try {
                    if (false) {
                        Log.v(TAG, "Preloading " + line + "...");
                    }
                    Class.forName(line);
                    if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
                        if (false) {
                            Log.v(TAG,
                                " GC at " + Debug.getGlobalAllocSize());
                        }
                        System.gc();
                        runtime.runFinalizationSync();
                        Debug.resetGlobalAllocSize();
                    }
                    count++;
                     ......省略代码
    
                }
    
             ......省略代码
    }
    
    private static void preloadResources() {
        final VMRuntime runtime = VMRuntime.getRuntime();
    
        Debug.startAllocCounting();
        try {
            System.gc();
            runtime.runFinalizationSync();
            mResources = Resources.getSystem();
            mResources.startPreloading();
            if (PRELOAD_RESOURCES) {
                Log.i(TAG, "Preloading resources...");
    
                long startTime = SystemClock.uptimeMillis();
                TypedArray ar = mResources.obtainTypedArray(
                        com.android.internal.R.array.preloaded_drawables);
                int N = preloadDrawables(runtime, ar);
                ar.recycle();
                Log.i(TAG, "...preloaded " + N + " resources in "
                        + (SystemClock.uptimeMillis()-startTime) + "ms.");
    
                startTime = SystemClock.uptimeMillis();
                ar = mResources.obtainTypedArray(
                        com.android.internal.R.array.preloaded_color_state_lists);
                N = preloadColorStateLists(runtime, ar);
                ar.recycle();
                Log.i(TAG, "...preloaded " + N + " resources in "
                        + (SystemClock.uptimeMillis()-startTime) + "ms.");
            }
            mResources.finishPreloading();
        } catch (RuntimeException e) {
            Log.w(TAG, "Failure preloading resources", e);
        } finally {
            Debug.stopAllocCounting();
        }
    }
    

    preloadClasses方法所做的事情是从"/system/etc/preloaded-classes"文件种把预加载的类加载到虚拟机中
    在来看runSelectLoop方法

      private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        FileDescriptor[] fdArray = new FileDescriptor[4];
    
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
    
        int loopCount = GC_LOOP_COUNT;
        while (true) {
            int index;
    
            /*
             * Call gc() before we block in select().
             * It's work that has to be done anyway, and it's better
             * to avoid making every child do it.  It will also
             * madvise() any free memory as a side-effect.
             *
             * Don't call it every time, because walking the entire
             * heap is a lot of overhead to free a few hundred bytes.
             */
            if (loopCount <= 0) {
                gc();
                loopCount = GC_LOOP_COUNT;
            } else {
                loopCount--;
            }
    
    
            try {
                fdArray = fds.toArray(fdArray);
                index = selectReadable(fdArray);
            } catch (IOException ex) {
                throw new RuntimeException("Error in select()", ex);
            }
    
            if (index < 0) {
                throw new RuntimeException("Error in select()");
            } else if (index == 0) {
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDescriptor());
            } else {
                boolean done;
                /*开始读取client发出的命令*/
                done = peers.get(index).runOnce();
    
                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }
    

    它所做的事情是:
    - 监听client的socket连接
    - 发现有连接则建立一个ZygoteConnection对象
    - client发送命令,则找到相应的ZygoteConnection对象,并且调用该对象的runOnce方法,来处理client发送的命令
    - ZygoteConnection对象处理完毕,则从列表中移除

    关于Zygote进程内容介绍到这,后面介绍app进程的fork过程

    相关文章

      网友评论

        本文标题:Android Zygote进程和app进程fork过程分析1

        本文链接:https://www.haomeiwen.com/subject/nfybzxtx.html