Android源码分析--Zygote进程分析

时间:2023-01-01 16:48:55

众所周知,Android系统中存在着两个完全不同的世界:
1. Java世界,Google所提供的SDK就主要是针对这个世界的,在这个世界中运行的程序都是基于Dalvik虚拟机的Java程序。
2. native世界,也就是利用C或C++语言开发的程序。

那么问题来了,Android系统具体是如何将这两个世界联系起来的,这就是关系到本篇博文所讲的Zygote进程。Android是基于Linux内核构建的,这样Android最早进入的也就是native世界。Linux系统启动的第一个进程是init进程,Android系统中最早启动的进程也是init进程,接下来init进程根据init.rc文件中的配置选项创建了Zygote进程。

Zygote名字的来历

Zygote进程的名字最初时并不是“zygote”,而是“app_process”,这个名字是在Android.mk文件中指定的,但在运行过程中app_process通过Linux下pctrl系统调用把名字换成了“zygote”。其所对应的源文件是App_main.cpp。

App_main.cpp分析

(源码位置:frameworks\base\cmds\app_process\app_main.cpp)
被执行的方法是App_main.cpp中的main方法,该方法比较简单,它首先为虚拟机添加了一些参数,接下来解析了运行时的参数,如果我们的参数设定为执行Zygote进程,则会将bool值zygote置为true,接下来调用了AppRuntime中的start方法。

int main(int argc, char* const argv[])
{
........
// 两个全局变量被定义在ProcessState.cpp中
mArgC = argc;
mArgV = argv;

mArgLen = 0;
for (int i=0; i<argc; i++) {
mArgLen += strlen(argv[i]) + 1;
}
mArgLen--;

AppRuntime runtime;
const char* argv0 = argv[0];

// Process command line arguments
// ignore argv[0]
argc--;
argv++;

// Everything up to '--' or first non '-' arg goes to the vm

int i = runtime.addVmArguments(argc, argv);

// 接下来解析一些运行时参数
bool zygote = false;
bool startSystemServer = false;
bool application = false;
const char* parentDir = NULL;
const char* niceName = NULL;
const char* className = NULL;
while (i < argc) {
const char* arg = argv[i++];
if (!parentDir) {
parentDir = arg;
} else if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = "zygote";
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName = arg + 12;
} else {
className = arg;
break;
}
}

if (niceName && *niceName) {
setArgv0(argv0, niceName);
//在这里将进程的名称更换为zygote
set_process_name(niceName);
}

runtime.mParentDir = parentDir;

if (zygote) {
// 调用AppRuntime的start方法以执行名称为ZygoteInit的类其中的main方法。
// argv的参数为"--zygote" "--start-system-server",则startSystemServer为true
runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");
} else if (className) {

runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.RuntimeInit",
application ? "application" : "tool");
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}

AppRuntime中start方法分析

在App_main的main方法中我们最终进入到AppRuntime的start方法中去,接下来分析一下AppRuntime中的start方法,该类的实现和定义均在app_main.cpp中。

//传入参数为"com.android.internal.os.ZygoteInit","start-system-server"
void AndroidRuntime::start(const char* className, const char* options)
{
ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
className != NULL ? className : "(unknown)");

/*
* 'startSystemServer == true' 我们在这里打印出启动引导事件
*/

if (strcmp(options, "start-system-server") == 0) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
//如果环境变量中没有ANDROID_ROOT则设置该环境变量
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}

/* 开启虚拟机 */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
return;
}
onVmCreated(env);

/*
* 注册一些jni函数
*/

if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}

/*
* 接下来通过jni调用,调用ZygoteInit的main方法,并设置好传递参数
*/

jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
jstring optionsStr;

stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(2, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
optionsStr = env->NewStringUTF(options);
env->SetObjectArrayElement(strArray, 1, optionsStr);

/*
* 该线程将会成为虚拟机的主线程,并且伴随虚拟机一直存在
*/

char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//调用Java类中的静态main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
.......
}
free(slashClassName);
......
}

我们来总结一下start方法的工作:
1. 设置ANDROID_ROOT环境变量
2. 调用AndroidRuntime类中的startVM方法创建虚拟机
3. 调用startReg函数注册JNI函数
4. 通过jni调用调用Java类ZygoteInit的main方法
至此,我们已经进入了Java的世界。

进入Java世界

通过上面的分析,我们的程序已经来到了Java类ZygoteInit的静态main方法中,该类被定义在frameworks\base\core\java\com\android\internal\os\ZygoteInit.java中。接下来我们看看她的工作:

    public static void main(String argv[]) {
try {
// 开始配置Zygote进程的初始化工作
SamplingProfilerIntegration.start();

//建立IPC通信的服务端
registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//预加载类和资源
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());

// 结束配置Zygote的初始化
SamplingProfilerIntegration.writeZygoteSnapshot();

// 进行一次垃圾回收
gc();

// 禁用跟踪
Trace.setTracingEnabled(false);

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

if (argv[1].equals("start-system-server")) {
startSystemServer();//启动system_server进程
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}

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

runSelectLoop();//处理客户连接和客户请求

closeServerSocket();//关闭服务端
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}

总结一下:
1. 调用registerZygoteSocket注册IPC通信服务端的socket
2. preload预加载类和资源
3. startSystemServer启动system_server
4. runSelectLoop处理客户连接和客户请求
在这里zygote进程建立了一个子进程system_server,该进程是framework的核心,并且和Zygote保持相同的生命周期。但是,system_server的作用将在runSelectLoop中体现出来。

runSelectLoop分析

在前面我们知道runSelectLoop被用来处理客户连接和客户请求,接下来我们来看看这个方法。

    private static void runSelectLoop() 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);
//selectReadable是一个native方法,内部使用的是select使用多路复用I/O模型
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();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done;
done = peers.get(index).runOnce();

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

在这段程序中我们可以发现每一次客户的连接中,客户是由ZygoteConnection对象来表示,客户的请求是由ZygoteConnection的runOnce方法来处理。

至此,我们对Zygote进程的分析以及结束,它运行起漫长的runSelectLoop方法就沉沉的睡去,接下来的重要任务将在system_server进程中处理执行。关于system_server进程的分析详见 Android源码分析–system_server进程分析

参考书目:深入理解Android 卷I