sunwengang blog

developer | android display/graphics

  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) 协议
本文链接 : https://alonealive.github.io/Blog/2019/09/10/2019/190910_android_zygote_systemserver/

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