1 zygote的分裂

前面已经讲了zygote分裂出了长子system_server,然后SS(system_server)就通过initAndLoop进行消息循环处理了。那么谁会向zygote发送消息呢?这里以一个activity的启动为例,进行具体分析zygote的分裂和繁殖。

1.1  ActivityManagerService发送请求

ActivityManagerService也是SS创建的(在ServerThread里面)。假设通过startActivity来启动一个新的activity,而这个activity附属于一个还未启动的进程,那么这个进程该如何启动呢?先看看ActivityManagerService中的startProcessLocked函数:

这个函数很复杂,主要是判断启动activity的进程是否孤立进程,是否死亡等,并做好进程记录,放入processRecode类中~,核心部分在最后的函数调用startProcessLocked中。

startProcessLocked(ProcessRecord app,String hostingType, String hostingNameStr)的代码也比较多,这里就不详细列举了,只列出它完成的功能:

①设置pid并更新cpu状态。

②如果该进程不是孤立进程的话就通过PackageManager获取该进程对应的uid所对应的gid;否者直接跳到第四步。

③增加共享APP的 gid,这样的话,这些共享APP就可以想访问so库一样访问一些共享资源了。

④再设置该进程的一些属性——是否启用checkjni,安全模式之类的。

⑤然后调用Process.start("android.app.ActivityThread"……)来启动进程,这个函数要么正确执行并返回包含有新进程pid的结果,要么就失败抛出Runtime异常。这个process类是android提供的,并非jdk中的process类。

⑥最后就是一些不太重要的扫尾工作。

接下来看android.os.Process的start函数,详细代码在Process.java中:

public static final ProcessStartResult start(final String processClass,

final String niceName,int uid, int gid, int[] gids,int debugFlags, int mountExternal,

int targetSdkVersion,String seInfo,String[] zygoteArgs) {

try {

//调用startViaZygote函数

return startViaZygote(processClass, niceName, uid, gid, gids,

debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);

} catch (ZygoteStartFailedEx ex) {

Log.e(LOG_TAG,

"Starting VM process through Zygote failed");

throw new RuntimeException(

"Starting VM process through Zygote failed", ex);

}

}

startViaZygote函数代码如下:

private static ProcessStartResult startViaZygote(final String processClass,

final String niceName,

final int uid, final int gid,

final int[] gids,

int debugFlags, int mountExternal,

int targetSdkVersion,

String seInfo,

String[] extraArgs)

throws ZygoteStartFailedEx {

synchronized(Process.class) {

ArrayList<String> argsForZygote = new ArrayList<String>();

// --runtime-init, --setuid=, --setgid=,

// and --setgroups= must go first

argsForZygote.add("--runtime-init"); //这个参数很重要

……一些参数处理

//最后调用zygoteSendArgsAndGetResult

return zygoteSendArgsAndGetResult(argsForZygote);

}

}

zygoteSendArgsAndGetResult函数主要功能:向zygote进程发送一个参数列表,zygote进程会启动一个新的子进程并返回该子进程的pid号。详细代码如下:

private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args) throws ZygoteStartFailedEx {

//★这是关键函数!打开了同zygote进程的socket通信。

openZygoteSocketIfNeeded();

try {

/**

* See com.android.internal.os.ZygoteInit.readArgumentList()

* Presently the wire format to the zygote process is:

* a) a count of arguments (argc, in essence)

* b) a number of newline-separated argument strings equal to count

*

* After the zygote process reads these it will write the pid of

* the child or -1 on failure, followed by boolean to

* indicate whether a wrapper process was used.

*/

sZygoteWriter.write(Integer.toString(args.size()));

sZygoteWriter.newLine();

int sz = args.size();

for (int i = 0; i < sz; i++) {

String arg = args.get(i);

if (arg.indexOf('\n') >= 0) {

throw new ZygoteStartFailedEx(

"embedded newlines not allowed");

}

sZygoteWriter.write(arg);

sZygoteWriter.newLine();

}

//读取zygote处理完的结果,便可得到zygote返回的子进程的pid

sZygoteWriter.flush();

// Should there be a timeout on this?

ProcessStartResult result = new ProcessStartResult();

result.pid = sZygoteInputStream.readInt();

if (result.pid < 0) {

throw new ZygoteStartFailedEx("fork() failed");

}

result.usingWrapper = sZygoteInputStream.readBoolean();

return result;

} catch (IOException ex) {

try {

if (sZygoteSocket != null) {

sZygoteSocket.close();

}

} catch (IOException ex2) {

// we're going to fail anyway

Log.e(LOG_TAG,"I/O exception on routine close", ex2);

}

sZygoteSocket = null;

throw new ZygoteStartFailedEx(ex);

}

}

下面对openZygoteSocketIfNeeded函数进行详细分析:

/**

* Tries to open socket to Zygote process if not already open. If

* already open, does nothing.  May block and retry.

*/

/*此函数尝试打开同zygote进程的socket通信*/

private static void openZygoteSocketIfNeeded()

throws ZygoteStartFailedEx {

int retryCount;

if (sPreviousZygoteOpenFailed) {

/*如果上一次打开失败的话,就估计这一次打开也会失败,就直接返回失败状态*/

retryCount = 0;

} else {

retryCount = 10;     //允许尝试10次

}

/*

在bug#811181:某些时候runtime可能会使得本函数在zygote准备好之前就被调用,那么就肯定会失败的~这里系统暂时不做处理~~

*/

for (int retry = 0

; (sZygoteSocket == null) && (retry < (retryCount + 1))

; retry++ ) {

if (retry > 0) {

try {

Log.i("Zygote", "Zygote not up yet, sleeping...");

Thread.sleep(ZYGOTE_RETRY_MILLIS); //sleep 500毫秒

} catch (InterruptedException ex) {

// should never happen

}

}

try {

//创建同zygote的socket链接

sZygoteSocket = new LocalSocket();

sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,

LocalSocketAddress.Namespace.RESERVED));

sZygoteInputStream=new DataInputStream(sZygoteSocket.getInputStream());

sZygoteWriter =

new BufferedWriter(

new OutputStreamWriter(

sZygoteSocket.getOutputStream()),

256);

Log.i("Zygote", "Process: zygote socket opened");

sPreviousZygoteOpenFailed = false;

break;

} catch (IOException ex) {

if (sZygoteSocket != null) {

try {

sZygoteSocket.close();

} catch (IOException ex2) {

Log.e(LOG_TAG,"I/O exception on close after exception",

ex2);

}

}

sZygoteSocket = null;

}

}

if (sZygoteSocket == null) {

sPreviousZygoteOpenFailed = true;

throw new ZygoteStartFailedEx("connect failed");

}

}

好了,ActivityManagerService终于想zygote发送请求了~~。请求的参数中有一个字符串,它的值是“android.app.ActivityThread”。现在该回到zygote处理请求那块去看看了——就是runSelectLoop函数!

1.2 zygote接收并处理子进程的请求

在runSelectLoop函数中,一旦有来自客户端的连接,就调用zygoteConnection的runonce函数来处理客户端的连接请求,该函数的详细如下:

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

String args[];

try {

args = readArgumentList(); //读取SS发送过来的参数

descriptors = mSocket.getAncillaryFileDescriptors();

}

………

int pid = -1;

……….

//在这里zygote又分裂出了一个子进程

pid=Zygote.forkAndSpecialize(parsedArgs.uid,parsedArgs.gid,parsedArgs.gids,

parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,

parsedArgs.niceName, fdsToClose);

}

……

try {

if (pid == 0) {

// 子进程处理函数

handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

return true;

} else {

// in parent...pid of < 0 means failure

IoUtils.closeQuietly(childPipeFd);

childPipeFd = null;

return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);

}

}

}

接下来看看子进程处理函数handleChildProc干了些什么。具体的代码就不贴了,这里直接用文字加以描述:

①首先关闭zygote的sockets;

②然后根据传入的参数设置新进程的一些属性,因为我们传递进来的参数中有“runtime-init”所以会调用RuntimeInit.ZygoteInit函数,这个函数的功能我们已经分析过了,主要就是调用子进程类的main函数,这里就是调用android.app.ActivityThread类的main函数。实际上Android中APK程序所对应的进程就是这个类,它的main函数就是apk程序的main函数!!

③zygote子进程分裂成功后,就做一些扫尾工作,然后返回到runSelectLoop函数中继续等待请求进行下一次分裂。

所以说zygote是所有apk进程的祖先!

1.3 总结

这里以启动一个activity进程为例:

①ActivityManagerServer进程向zygote进程发送消息;

②zygote进程在runSelectLoop函数中接收到这个消息,fork创建子进程;

③子进程调用RuntimeInit.ZygoteInit函数,这个函数会调用子进程类的main函数,即android.app.ActivityThread的main函数,这样就启动了一个acivity进程。

zygote的分裂的更多相关文章

  1. Zygote进程【2】——Zygote的分裂

    在Zygote的诞生一文中init进程是如何一步步创建Zygote进程的,也了解了Zygote的进程的作用.Zygote进程的诞生对于整个Java世界可以说有着"开天辟地"的作用, ...

  2. Android源码阅读 – Zygote

    @Dlive 本文档: 使用的Android源码版本为:Android-4.4.3_r1 kitkat (源码下载: http://source.android.com/source/index.ht ...

  3. Zygote进程【3】——SystemServer的诞生

    在ZygoteInit的main()方法中做了几件大事,其中一件便是启动Systemserver进程,代码如下: @/frameworks/base/core/Java/com/Android/int ...

  4. Zygote过程【3】——SystemServer诞生

    欢迎转载.转载请注明:http://blog.csdn.net/zhgxhuaa 在ZygoteInit的main()方法中做了几件大事.当中一件便是启动Systemserver进程.代码例如以下: ...

  5. 认识Zygote

    概述 在java中不同的虚拟机实例会为不同的应用分配不同内存,为了使Android系统尽快启动,使用了Zygote来预加载核心类库和一些加载时间长的类(超过1250ms),让Dalvik虚拟机共享代码 ...

  6. [深入理解Android卷一全文-第四章]深入理解zygote

    由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该由于纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的所有内容. ...

  7. Zygote启动及其作用

    目录 1.Zygote简介 2.Zygote进程如何启动 2.1 init.zygote64_32.rc文件 2.2 查看ps信息 2.3 启动 3.Zygote作用 3.1 启动system_ser ...

  8. Android系统启动分析(Init->Zygote->SystemServer->Home activity)

    整个Android系统的启动分为Linux Kernel的启动和Android系统的启动.Linux Kernel启动起来后,然后运行第一个用户程序,在Android中就是init程序. ------ ...

  9. Android开发之漫漫长途 XI——从I到X的小结

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

随机推荐

  1. solver

    slover中有type,用于优化算法的选择,有6种: Stochastic Gradient Descent (type: “SGD”), AdaDelta (type: “AdaDelta”), ...

  2. Dede常用标记

    http://fontawesome.dashgame.com/ 字体图标使用方法 http://www.iconfont.cn/ 阿里的图标库 https://icomoon.io/ 字体制作 时间 ...

  3. Kenneth A.Lambert著的数据结构(用python语言描述)的第一章课后编程答案

    第6题:工资部门将每个支付周期的雇员信息的列表保存到一个文本文件, 每一行的格式:<last name><hourly wage><hours worked> 编写 ...

  4. Visual Studio 2017 UTF-8 无 BOM 一站式解决办法

    问题背景:最近捡起C++,使用VS 2017平台.因为以前的编程习惯,喜欢使用UTF-8 无 BOM 的编码格式,好让自己的代码全球通用.但是VS 2017 对这个问题不是很友善.但最终找到了解决办法 ...

  5. nrf52810学习笔记——二

    nrf52810为nordic支持蓝牙 5.0性价比最高的一款芯片,不过这个芯片的rom不得不吐槽下,只有192KB,不知道为什么定了个192,而不是大家所熟悉的256KB,估计价格是个原因吧,15. ...

  6. TCP的三次握手和四次握手

    三次握手(建立连接) 首先,服务器进程(B)先创建传控制块TCB(用来存储连接信息,如连接表,发送和接收序号等),准备接收客户进程(A)的请求.然后服务器进程处于LISTEN(收听)状态,等待客户的连 ...

  7. Linux学习-循环执行的例行性工作排程

    循环执行的例行性工作排程则是由 cron (crond) 这个系统服务来控制的.Linux 系统上面原本就有非常多的例行性工作,因此这个系统服务是默认启动的. 另外, 由于使用者自己也可以进行例行性工 ...

  8. HDU 3072 SCC Intelligence System

    给出一个带权有向图,要使整个图连通.SCC中的点之间花费为0,所以就先缩点,然后缩点后两点之间的权值为最小边的权值,把这些权值累加起来就是答案. #include <iostream> # ...

  9. UVa 10110 Light, more light

    开始所有的灯是灭的,不过我们只关心最后一个灯. 在第i次走动时,只有编号为i的倍数的灯的状态才会改变. 也就是说n有偶数个约数的时候,最后一个灯的状态不会改变,也就是灭的. n有奇数个约数的时候也就是 ...

  10. MyString的简单实现

    MyString.h 文件 #ifndef _STRING_H_ #define _STRING_H_ #include <iostream> using namespace std; c ...