sunwengang blog

because it's there

  1. 1. zygote分析
    1. 1.1. 创建虚拟机startVM
    2. 1.2. 注册JNI函数 startReg
    3. 1.3. java入口 CallStaticVoidMethod
  2. 2. SystemServer
  3. 3. 开机耗时长的原因
  4. 4. 虚拟机heapsize的限制
  5. 5. watchdog看门狗

zygote和system_server在Android中的Java层很重要。

zygote分析

zygote由init进程根据init.rc的配置项创建的。最初叫app_process,但是在运行过程中,通过Linux的pctrl系统调用将其换成了zygote。通过adb shell ps -ef|grep zygote查看到该进程。

Android-10.0.0_r2 AOSP源码中,查看其入口函数:

frameworks/base/cmds/app_process/app_main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int main(int argc, char* const argv[])
{
if (!LOG_NDEBUG) {
String8 argv_String;
for (int i = 0; i < argc; ++i) {
argv_String.append("\"");
argv_String.append(argv[i]);
argv_String.append("\" ");
}
ALOGV("app_process main with argv: %s", argv_String.string());
}

AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
......
if (zygote) {
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.");
}
}

重要的功能由AppRuntime的start函数完成。而AppRuntime类就在app_main.cpp中,从AndroidRuntime派生而来。

frameworks/base/core/jni/AndroidRuntime.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());

static const String8 startSystemServer("start-system-server");
......
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) { //创建虚拟机
return;
}
onVmCreated(env);

/*
* Register android functions.
*/
if (startReg(env) < 0) { //注册JNI函数
ALOGE("Unable to register all android natives\n");
return;
}
.....
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className != NULL ? 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 {
env->CallStaticVoidMethod(startClass, startMeth, strArray); //通过JNI调用Java中ZygoteInit的main函数,进入Java世界

......

创建虚拟机startVM

该函数调用JNI的Dalvik虚拟机创建函数,在sdtartVM中确定创建虚拟机的一些参数

注册JNI函数 startReg

给虚拟机注册一些JNI函数,采用native方式实现。

java入口 CallStaticVoidMethod

CallStaticVoidMethod最终调用frameworks/base/core/java/com/android/internal/os/ZygoteInit.java的main函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

@UnsupportedAppUsage
public static void main(String argv[]) {
ZygoteServer zygoteServer = null;

// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();

// Zygote goes into its own process group.
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}

Runnable caller;
......
if (startSystemServer) { //启动system_server
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
......

forkSystemServer会创建java世界中系统service所驻留的进程system_server,该进程是framework的核心。


SystemServer

SystemServer的进程名叫做system_server,由zygote进程中创建。

forkSystemServer函数中调用handleSystemServerProcess()来处理自己的事务

调用到systemserver的main函数。

frameworks/base/services/java/com/android/server/SystemServer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}

public SystemServer() {
// Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();

// Record process start information.
// Note SYSPROP_START_COUNT will increment by *2* on a FDE device when it fully boots;
// one for the password screen, second for the actual boot.
mStartCount = SystemProperties.getInt(SYSPROP_START_COUNT, 0) + 1;
mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
mRuntimeStartUptime = SystemClock.uptimeMillis();

// Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
// We don't use "mStartCount > 1" here because it'll be wrong on a FDE device.
// TODO: mRuntimeRestart will *not* be set to true if the proccess crashes before
// sys.boot_completed is set. Fix it.
mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
}

随后会创建一些系统服务,并将调用线程加入到Binder通信中。并且会创建一个单独的线程,用以启动系统的各项服务,例如电池管理服务BatteryService,电源管理服务PowerManagerService,StartWindowManagerService,ActivityManagerService等等。

开机耗时长的原因

  1. ZygoteInit的main函数中的preloadClasses加载了上千个类
  2. 开机启动时会对系统所有的APK扫描并收集信息
  3. SystemServer创建的一系列service,占用不少时间

虚拟机heapsize的限制

zygote创建虚拟机的时候,系统默认设置的java虚拟机堆栈值(可修改)对于使用较大内存的程序远远不够。zygote通过fork创建子进程,因而本身设置的信息会被子进程全部继承,例如设置堆栈对32MB,则子进程也会使用32MB。

watchdog看门狗

watchdog作用是每隔一段时间去检查某个参数是否被设置了,如果发现该参数没有被设置,则判断为系统出错,然后强制重启。

Android对于systemserver的参数是否被设置也增加了一条看门狗。主要检查几个重要的service,如果service出了问题就会杀掉system_server,这回导致zygote也一起杀掉,导致java层重启。

SystemServer和Watchdog的交互大致分为三个步骤(frameworks/base/services/core/java/com/android/server/Watchdog.java):

  1. Watchdog.getInstance().init()初始化
  2. Watchdog.getInstance().start(),派生于Thread类,start启动线程,导致Watchdog的run在另外一个线程中被执行。该函数实现隔一段时间发送一条信息,那个线程将检查各个service的健康状况,而看门狗等待检查结果,如果第二次没有返回结果,将会杀掉systemserver
  3. Watchdog.getInstance().addMonitor(),如果要支持看门狗的检查,就需要让service实现monitor接口(比如ActivityManagerService,PowerManagerService,WindowManagerService)

Example:

当一个函数占着锁,长时间没有返回(原因是这个函数需要和硬件交互,而硬件没有及时返回),导致系统服务死锁被watchdog检查到。

本文作者 : sunwengang
本文使用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议
本文链接 : http://wizzie.top/2019/09/10/2019/190910_android_zygote_systemserver/

本文最后更新于 天前,文中所描述的信息可能已发生改变