您的位置:首页 > 移动开发 > Android开发

深入理解Android(06)——Java世界的入口ZygoteInit

2015-02-03 23:55 826 查看

1、ZygoteInit源码

CallStaticVoidMethod最终将调用com.android.internal.os.ZygoteInit的main函数,这里是函数代码,如下所示:

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

public static void main(String argv[]) {
        try {
            VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024);

            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();
//1、注册zygote用的socket
            registerZygoteSocket();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
//2、预加载类和资源
            preloadClasses();
            //cacheRegisterMaps();
            preloadResources();
            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();

            // If requested, start system server directly from Zygote
            if (argv.length != 2) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            if (argv[1].equals("true")) {
//3、启动system_server进程
                startSystemServer();
            } else if (!argv[1].equals("false")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            Log.i(TAG, "Accepting command socket connections");

            if (ZYGOTE_FORK_MODE) {
                runForkMode();
            } else {
//4、zygote调用这个函数
                runSelectLoopMode();
            }

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
//5、很重要的一个方法
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }


2、IPC通信服务端

zygote及系统中其它程序的通信没有使用Binder,而是采用了基于AF_UNIX类型的Socket,registerZygoteSocket函数的使命是建立这个Socket。

/**
     * Registers a server socket for zygote command connections
     *
     * @throws RuntimeException when open fails
     */
    private static void registerZygoteSocket() {
        if (sServerSocket == null) {
            int fileDesc;
			// 从环境变量中获取Socket的fd,前面我们介绍的zygote是如何启动的
			// 这个环境变量由execv传入。
            try {
                String env = System.getenv(ANDROID_SOCKET_ENV);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(
                        ANDROID_SOCKET_ENV + " unset or invalid", ex);
            }

            try {
			// 创建服务端Socket,这个Socket将listen并accept Client
                sServerSocket = new LocalServerSocket(
                        createFileDescriptor(fileDesc));
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }


registerZyoteSocket很简单,就是创建一个服务端的Socket,但是这里有两个问题:

1)谁是客户端?

2)服务端会怎么处理客户端的消息?

3、预加载类和资源

两个比较重要的函数,preloadClasses和preloadResources。先看看preloadClasses

/**
     * Performs Zygote process initialization. Loads and initializes
     * commonly used classes.
     *
     * Most classes only cause a few hundred bytes to be allocated, but
     * a few will allocate a dozen Kbytes (in one case, 500+K).
     */
    private static void preloadClasses() {
        final VMRuntime runtime = VMRuntime.getRuntime();
		
		// 预加载类的信息存储在PRELOADED_CLASSES变量中,它的值为“preload-classes”
        InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
                PRELOADED_CLASSES);
        if (is == null) {
            Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
        } else {
		
		// 做一些统计和准备工作
            Log.i(TAG, "Preloading classes...");
            long startTime = SystemClock.uptimeMillis();

            // Drop root perms while running static initializers.
            setEffectiveGroup(UNPRIVILEGED_GID);
            setEffectiveUser(UNPRIVILEGED_UID);

            // Alter the target heap utilization.  With explicit GCs this
            // is not likely to have any effect.
            float defaultUtilization = runtime.getTargetHeapUtilization();
            runtime.setTargetHeapUtilization(0.8f);

            // Start with a clean slate.
            runtime.gcSoftReferences();
            runtime.runFinalizationSync();
            Debug.startAllocCounting();

            try {
			// 读取文件的每一行,忽略#开头的注释行
                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 {
                        // 通过反射加载类
                        Class.forName(line);
                        
						// ......
						
                        count++;
                    } catch (ClassNotFoundException e) {
                        Log.w(TAG, "Class not found for preloading: " + line);
                    } catch (Throwable t) {
                        // ......
                    }
                }

                Log.i(TAG, "...preloaded " + count + " classes in "
                        + (SystemClock.uptimeMillis()-startTime) + "ms.");
            } catch (IOException e) {
                Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
            } finally {
                // ......扫尾
            }
        }
    }


preloadClasses主要工作就是加载类,不过它加载的类有点多,大概有1300个左右类需要加载。正是因为启动Android系统,需要有这么多类需要加载,所以才导致了Android系统启动比较慢,一般的,如果加载一个类的时间超过1250毫秒,那么这个类就不会被preloadClasses加载。(注意,preloadClasses加载的类,是根据preload-classes文件来)

preloadResources,顾名思义,这个函数主要是加载资源文件的,这里就不再赘述了。

4、启动system_server

这里有一个非常关键的方法,名为startSystemServer,这个函数会创建Java世界中系统Service所驻留的进程system_server,该进程是framework的核心。如果它死了,就会导致zygote自杀。

/**
     * Prepare the arguments and fork for the system server process.
     */
    private static boolean startSystemServer()
            throws MethodAndArgsCaller, RuntimeException {
        /* Hardcoded command line to start the system server */
		// 设置参数
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
            "--capabilities=130104352,130104352",
            "--runtime-init",
            "--nice-name=system_server",     // 进程名,叫做system_server
            "com.android.server.SystemServer",   // 启动的类名
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
		// 把上面字符串数组参数转换成Arguments对象,具体内容请读者自行研究。
            parsedArgs = new ZygoteConnection.Arguments(args);
			
			// fork一个子进程,看来,这个子进程就是system_server进程
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, debugFlags, null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
		// system_server 进程的工作
            handleSystemServerProcess(parsedArgs);
        }
		
		// zygote 返回true
        return true;
    }


5、有求必应的等待请求

这里说的请求,也是一个方法,名为runSelectLoopMode,前面我们提到了一个在registerZygoteSocket中注册了一个用于IPC的Socket,不过那个时候还没有地方用到它,它的用途将在这个runSelectLoopMode中体现出来。代码如下:

/**
     * Runs the zygote process's select loop. Accepts new connections as
     * they happen, and reads commands from connections one spawn-request's
     * worth at a time.
     *
     * @throws MethodAndArgsCaller in a child process when a main() should
     * be executed.
     */
    private static void runSelectLoopMode() throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList();
        ArrayList<ZygoteConnection> peers = new ArrayList();
        FileDescriptor[] fdArray = new FileDescriptor[4];
		
		// sServerSocket 是我们前面在registerZygoteSocket中建立的Socket
        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);
				/*
				selectReadable内部调用select,使用多路复用I/O模型,
				当有客户端链接或有数据时,则selectReadable就会返回。
				*/
                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) {
			// 有一个客户端连接上,客户端在Zygote的代表时ZygoteConnection
                ZygoteConnection newPeer = acceptCommandPeer();
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                boolean done;
			// 客户端发送了请求,peers.get返回的是ZygoteConnection
			// 后续处理将交给ZygoteConnection的runOnce函数完成
                done = peers.get(index).runOnce();

                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }


runSelectLoopMode总体上比较见简单,主要是两个问题:

1)处理客户端连接和客户请求

2)客户的请求有ZygoteConnection的runOnce来处理
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: