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
下面的图描述了上面的过程
涉及到的类
我们先来梳理这个过程中使用到的类,并且这些类是做什么的
以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进程内容介绍到这