深入理解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来处理
相关文章推荐
- Android 应用的真正入口 - ZygoteInit.java
- android 启动 ZygoteInit.java分析
- 深入理解Android(08)——深入理解zygote的分裂原理
- Android 系统的java世界是怎么诞生的?孵化器zygote的初步探索
- 深入理解Android之Java虚拟机Dalvik
- [深入理解Android卷一全文-第四章]深入理解zygote
- android启动--深入理解zygote
- [深入理解Android卷一全文-第四章]深入理解zygote
- [置顶] JAVA中 错误代码是 the public type must be defined in its own file 解决方法 android开发 java编程
- 夯实java基础,深入理解Android设计思想
- JAVA中 错误代码是 the public type must be defined in its own file 解决方法 android开发 java编程
- 深入理解Android(05)——深入理解zygote
- 深入理解Android(3)——Eclipse集成javah和NDK-Builder
- JAVA中 错误代码是 the public type must be defined in its own file 解决方法 android开发 java编程
- android启动--深入理解zygote (II)
- android--地图系列之 Android 百度地图时遇到的 java.lang.UnsatisfiedLinkError: initClass
- Zygote (深入理解android 卷1)
- Android 百度地图时遇到的 java.lang.UnsatisfiedLinkError: initClass
- android启动--深入理解zygote (II)
- 深入理解Android之init与zygote