Android5 Zygote 与 SystemServer 启动流程分析
Android5 Zygote 与 SystemServer 启动流程分析
前言
Android5.0.1 的启动流程与之前的版本相比变化并不大,OK,变化虽然还是有:SystemServer 启动过程的 init1(), init2()没有了,但主干流程依然不变:Linux 内核加载完毕之后,首先启动 init 进程,然后解析 init.rc,并根据其内容由 init 进程装载 Android 文件系统、创建系统目录、初始化属性系统、启动一些守护进程,其中最重要的守护进程就是 Zygote 进程。Zygote 进程初始化时会创建 Dalvik 虚拟机、预装载系统的资源和 Java 类。所有从 Zygote 进程 fork 出来的用户进程都将继承和共享这些预加载的资源。init 进程是 Android 的第一个进程,而 Zygote 进程则是所有用户进程的根进程。SystemServer 是 Zygote 进程 fork 出的第一个进程,也是整个 Android 系统的核心进程。
zygote 进程
解析 zygote.rc
在文件中 /system/core/rootdir/init.rc 中包含了 zygote.rc:
import /init.${ro.zygote}.rc
${ro.zygote}是平台相关的参数,实际可对应到 init.zygote32.rc, init.zygote64.rc, init.zygote64_32.rc, init.zygote32_64.rc,前两个只会启动单一app_process(64) 进程,而后两个则会启动两个app_process进程:第二个app_process进程称为 secondary,在后面的代码中可以看到相应 secondary socket 的创建过程。为简化起见,在这里就不考虑这种创建两个app_process进程的情形。
以 /system/core/rootdir/init.zygote32.rc 为例:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
第一行创建了名为 zygote 的进程,这个进程是通过 app_process 的 main 启动并以”-Xzygote /system/bin –zygote –start-system-server”作为main的入口参数。
app_process 对应代码为 framework/base/cmds/app_process/app_main.cpp。在这个文件的main函数中:
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args);
}
根据入口参数,我们知道 zygote 为true,args参数中包含了”start-system-server”。
AppRuntime 继承自 AndroidRuntime,因此下一步就执行到 AndroidRuntime 的 start 函数。
void AndroidRuntime::start(const char* className, const Vector& options)
{
/* start the virtual machine */ // 创建虚拟机
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
return;
}
onVmCreated(env);
...
//调用className对应类的静态main()函数
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
env->CallStaticVoidMethod(startClass, startMeth, strArray);
...
}
start函数主要做两件事:创建虚拟机和调用传入类名对应类的 main 函数。因此下一步就执行到 com.android.internal.os.ZygoteInit 的 main 函数。
public static void main(String argv[]) {
try {
boolean startSystemServer = false;
String socketName = "zygote";
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
}
...
}
registerZygoteSocket(socketName);
...
preload();
...
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;
}
}
它主要做了三件事情:
1. 调用 registerZygoteSocket 函数创建了一个 socket 接口,用来和 ActivityManagerService 通讯;
2. 调用 startSystemServer 函数来启动 SystemServer;
3. 调用 runSelectLoop 函数进入一个无限循环在前面创建的 socket 接口上等待 ActivityManagerService 请求创建新的应用程序进程。
这里要留意 catch (MethodAndArgsCaller caller) 这一行,android 在这里通过抛出一个异常来处理正常的业务逻辑。
socket zygote stream 660 root system
系统启动脚本文件 init.rc 是由 init 进程来解释执行的,而 init 进程的源代码位于 system/core/init 目录中,在 init.c 文件中,是由 service_start 函数来解释 init.zygote32.rc 文件中的 service 命令的:
void service_start(struct service *svc, const char *dynamic_args)
{
...
pid = fork();
if (pid == 0) {
struct socketinfo *si;
...
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type,
si->perm, si->uid, si->gid, si->socketcon ?: scon);
if (s >= 0) {
publish_socket(si->name, s);
}
}
...
}
...
}
每一个 service 命令都会促使 init 进程调用 fork 函数来创建一个新的进程,在新的进程里面,会分析里面的 socket 选项,对于每一个 socket 选项,都会通过 create_socket 函数来在 /dev/socket 目录下创建一个文件,在 zygote 进程中 socket 选项为“socket zygote stream 660 root system”,因此这个文件便是 zygote了,然后得到的文件描述符通过 publish_socket 函数写入到环境变量中去:
static void publish_socket(const char *name, int fd)
{
char key[64] = ANDROID_SOCKET_ENV_PREFIX;
char val[64];
strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
name,
sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
snprintf(val, sizeof(val), "%d", fd);
add_environment(key, val);
/* make sure we don't close-on-exec */
fcntl(fd, F_SETFD, 0);
}
这里传进来的参数name值为”zygote”,而 ANDROID_SOCKET_ENV_PREFIX 在 system/core/include/cutils/sockets.h 定义为:
#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
#define ANDROID_SOCKET_DIR "/dev/socket"
因此,这里就把上面得到的文件描述符写入到以 “ANDROID_SOCKET_zygote” 为 key 值的环境变量中。又因为上面的 ZygoteInit.registerZygoteSocket 函数与这里创建 socket 文件的 create_socket 函数是运行在同一个进程中,因此,上面的 ZygoteInit.registerZygoteSocket 函数可以直接使用这个文件描述符来创建一个 Java层的LocalServerSocket 对象。如果其它进程也需要打开这个 /dev/socket/zygote 文件来和 zygote 进程进行通信,那就必须要通过文件名来连接这个 LocalServerSocket了。也就是说创建 zygote socket 之后,ActivityManagerService 就能够通过该 socket 与 zygote 进程通信从而 fork 创建
您可能想查找下面的文章:
- Android 5.0(包含5.0以下版本) 获取栈顶应用程序包名,android包名
- Android5.0开发范例大全 读书笔记(五),android5.0范例
- Android5.0开发范例大全 读书笔记(六),android5.0范例
- Android5.0开发范例大全 读书笔记(三),android5.0范例
- Android5.0开发范例大全 读书笔记(四),android5.0范例
- android 5.0后对于apk 跑32 64 的逻辑
- Android 5.0 Settings源码简要分析
- Android5.0新特性-Material Design
- Android5.0之Toobar的使用
- ubuntu下安装AndroidStudio