接上篇: Android系统启动流程(一)init进程的启动流程
Zygote在英语中是受精卵的意思,从这个名字可以看出,zygote进程是用来孵化其他进程的,SystemServer和其他应用程序进程都是由Zygote进程所创建的。Zygote是以服务的形式存在于Android系统中的,是Android系统的一个重要的守护进程,下面我们通过源码来分析Zygote进程的启动流程。
1.解析Zygote服务的启动脚本并启动app_main
在init进程启动时,会解析Zygote服务进程的启动脚本并开启Zygote进程,针对不同位数的操作系统,Zygote也分别对应不同的启动脚本,在Android8.0系统的源码中共有4个启动脚本,分别是init.zygote32.rc(支持32位系统)、init.zygote64.rc(支持64位系统)、init.zygote32_64.rc(同时支持32位和64位,但以32位为主)、init.zygote64_32.rc(同时支持32位和64位,但以64位为主),我们以init.zygote32.rc为例来看一下Zygote服务的脚本源码:
目录位置:\system\core\rootdir\init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
从上面的代码可以看出,该服务的名称是zygote,路径为/system/bin/app_process,参数包含-Xzygote /system/bin --zygote --start-system-server,class的名称为main。
init进程在解析完上面的代码后,会对zygote服务进行启动,启动部分的脚本代码如下:
源码位置:\system\core\rootdir\init.rc
on zygote-start && property:ro.crypto.state=unencrypted //在.rc文件中,on表示一个触发器,zygote-start是触发器的名称
//当该触发器被触发后,便会执行下面的命令
exec_start update_verifier_nonencrypted
start netd
start zygote //启动zygote服务
start zygote_secondary
上面的代码是定义在init.rc中的一个触发器,当该触发器被触发后,便会执行start zygote这行命令,从而启动zygote服务,start命令对应的函数为do_start,源码如下:
源码路径:\system\core\init\builtins.cpp
static int do_start(const std::vector& args) {
// 1.根据service的名称找到该服务
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
LOG(ERROR) << "do_start: Service " << args[1] << " not found";
return -1;
}
if (!svc->Start()) //2.调用Start方法开启该服务
return -1;
return 0;
}
在注释1处通过service的名称来找到zygote这个服务的实例,然后再注释2出调用Service的Start方法来开启这个服务,我们来看一下Start方法的源码:
源码路径:\system\core\init\service.cpp
bool Service::Start() {
...
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork(); // 1.通过fork函数创建zygote子进程
}
if (pid == 0) { //pid为0,说明当前在子进程中
...
if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) { // 2.调用execve执行子进程的代码
PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
}
_exit(127);
}
...
return true;
}
在注释1处通过fork函数创建了一个子线程,由于fork函数是对父进程的自我复制,所以fork函数会同时在父进程和子进程中返回,并在父进程中返回子进程的id,在子进程中返回0。
在注释2处,通过调用execve函数来执行子进程的代码,从zygote的启动脚本中可以看到,该服务的执行代码位于 /system/bin/app_process中,对应的文件为app_main.cpp,这样程序即进入了app_main的main方法中。
2.通过AppRuntime启动Zygote
我们先来看一下app_main.cpp的main方法的源码:
源码路径:\frameworks\base\cmds\app_process\app_main.cpp
int main(int argc, char* const argv[])
{
...
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// 1.创建AppRuntime实例
...
while (i < argc) { // 2.循环遍历参数
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) { //当参数为“--zygote”时
zygote = true; //将zygote标记变为true
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) { //当参数为“--start-system-server”时
startSystemServer = true; //将startSystemServer参数变为true
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
if (zygote) {
// 3.如果zygote标志为true,则执行runtime的start方法
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
在注释1处创建了一个AppRuntime实例。
在注释2处对参数进行循环遍历,如果参数中含有 "--zygote",则将zygote置为true,如果参数中含有"--start-system-server",则将startSystemServer置为true。
在注释3处通过调用runtime的start方法来执行ZygoteInit文件中的代码,并将ZygoteInit的文件路径作为参数传入了start方法,这是一个java文件。start函数的源码位于AppRuntime的父类AndroidRuntime中,源码如下:
源码路径:\frameworks\base\core\jni\AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
...
JniInvocation jni_invocation;
jni_invocation.Init(NULL);//初始化jni
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) { // 1.启动java虚拟机
return;
}
onVmCreated(env);
//主要用于注册jni函数
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
/* 2.通过jni的方式执行ZygoteInit的main方法*/
char* slashClassName = toSlashClassName(className); //将classname中的"."替换为“/”
jclass startClass = env->FindClass(slashClassName);//通过jni的方式加载ZygoteInit的java类
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V"); //找到ZygoteInit的main方法
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);//通过jni的方式调用ZygoteInit的mian方法
...
}
...
}
由于ZygoteInit文件是由java代码编写的,因此我们需要用jni的方法来执行ZygoteInit的main方法。
在注释1处,通过startVm方法创建了java虚拟机。
在注释2处,通过执行一系列的jni方法,最终调用了ZygoteInit的main方法。
3.启动SystemServer并持续监听应用创建请求。
我们来看一下Zygote的main方法的源码:
源码路径:\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer(); //创建ZygoteServer实例
...
try {
...
zygoteServer.registerServerSocket(socketName); // 1.注册ServerSocket
...
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer); // 2.启动SystemServer
}
Log.i(TAG, "Accepting command socket connections");
zygoteServer.runSelectLoop(abiList); // 3.开启事件循环,不断监听新的请求
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
在main方法中,首先创建了一个ZygoteServer实例,然后在注释1处,通过调用zygoteServer的registerServerSocket方法对ServerSocket进行了注册。
在注释2处调用startSystemServer方法开启了SystemServer进程。
在注释3处通过调用zygoteServer的runSelectLoop方法开启了事件循环,这样zygote进程就可以持续监听新的应用进程创建请求。
我们先来看一下registerServerSocket方法的源码:
源码路径:\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
private LocalServerSocket mServerSocket;
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
int fileDesc;
//通过拼接字符串得到最终的Socket名称,最后的结果为“ANDROID_SOCKET_zygote”
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 {
FileDescriptor fd = new FileDescriptor();//创建文件描述符对象
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);//创建ServerSocket对象
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
在registerServerSocket方法中,首先通过字符串拼接的方式获得了Socket的名称,然后根据这个名称创建了一个文件描述符对象。基于linux一切都是文件的思想,socket也被看作是一个文件,该文件描述符即用来表示该socket。
然后通过这个文件描述符创建了一个LocalServerSocket对象,通过名称我们便可以看出,这是一个运行于服务端的socket,它的作用便是用来监听新的应用进程创建请求。
我们再来看一下runSelectLoop方法:
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
/* 1.开始无限循环,不断监听新的请求 */
while (true) {
/* 将fds中的数据转移到pollFds数组中 */
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {// 2.当数组中没有未执行的任务时
ZygoteConnection newPeer = acceptCommandPeer(abiList);//不断进行监听,当有新请求时便会返回
//将这个连接请求放入数组中
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce(this);// 3.从peers中去除连接请求并执行
if (done) {
//执行完成后从数组中移除
peers.remove(i);
fds.remove(i);
}
}
}
}
}
在runSelectLoop方法中,首先创建了一个FileDescriptor数组和一个ZygoteConnection数组,他们用来存储新接收到的请求。在注释1处开启了一个无限循环来不断监听新的请求,因此zygote进程在android系统的运行过程中会一直存在,直到系统关闭。
在这个无限循环中,先将fds数组的数据转移到了pollFds数组中,然后对pollFds数组进行了遍历,当i==0时,说明数组中所有请求任务都已经执行完了,那么调用acceptCommandPeer方法来获取新的请求,acceptCommandPeer方法是一个阻塞方法,如果没有新的连接请求,acceptCommandPeer会一直阻塞,直到有新的连接请求到来时,acceptCommandPeer才会将这个新的请求返回。获取到新的请求后便将这个请求放入peers和fds数组中。
当i不为0时,说明数组中还存在未执行的请求,则将请求取出并调用runOnce方法来执行这个请求。
我们先来看一下acceptCommandPeer方法的源码:
private ZygoteConnection acceptCommandPeer(String abiList) {
try {
return createNewConnection(mServerSocket.accept(), abiList);//调用accept方法等待新的请求
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
return new ZygoteConnection(socket, abiList); //创建ZygoteConnection实例
}
acceptCommandPeer的源码非常简单,就是就是调用accept方法等待新的请求,该方法会一直阻塞当前线程,直到有新的请求到来。
我们再来看一下ZygoteConnection的runOnce方法:
源码路径:\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
...
}
runOnce方法的代码很长,我们只看最关键的一句代码,即调用forkAndSpecialize方法创建新的进程,该方法最终会调用native方法来fork新的应用程序进程。
之前我们讲过,zygote进程在启动的时候会创建一个java虚拟机,而我们的应用程序进程都是由zygote进程fork得来的,而fork的本质是对父进程的自我复制,因此所有的应用程序子进程也会获得一个复制而来的java虚拟机副本,这样便无需在应用程序进程中单独启动java虚拟机了。