Skytoby

Android系统SystemServer启动(上)

Android系统SystemServer启动(上)

1.0 前言

当按下终端的电源键到看到Home界面,这个过程需要经过Android系统体系结构中的内核层、运行层、框架层、应用层。本文只介绍到SystemServer启动(代码基于android 8.1),引用gityuan的一张整体框架图。

framwork

1.1 内核启动前准备

当电源键按下之后,引导芯片的代码会从预定义开始的地方开始执行,加载引导程序到RAM运行。引导程序可以在/bootable/bootloader中找到,由于引导程序各个设备制造商各不相同,不是Android系统的一部分。引导程序主要分为两个阶段执行:

第一个阶段为检测外部的RAM和加载对第二阶段有用的程序;

第二阶段为设置网络、内存等,为内核启动准备条件。

1.2 内核启动流程

Android系统本质上是Linux内核的操作系统。Linux内核启动主要涉及到三个进程,idle进程(PID=0), init进程(PID=1),kthreadd进程(PID=2)。

idle进程是Linux系统的第一个进程,是init和kthreadd进程的父进程。

init进程是Linux系统的第一个用户进程,是Android系统应用程序的首个进程。

kthreadd进程是Linux系统内核管理进程,所有的内核线程都是间接或直接以它为父进程。

1.2.1 idle进程启动

idle进程最开始的名字为init_task,后期退化为idle,在完成初始化操作后,主要负责进程的调度、交换。

idle进程启动对应的文件在/kernel/msm-3.18/arch/arm64/kernel/head.S

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
/*
* The following fragment of code is executed with the MMU enabled.
*/
.set initial_sp, init_thread_union + THREAD_START_SP
__mmap_switched:
// Clear BSS
adr_l x0, __bss_start
mov x1, xzr
adr_l x2, __bss_stop
sub x2, x2, x0
bl __pi_memset
dsb ishst // Make zero page visible to PTW

adr_l sp, initial_sp, x4
mov x4, sp
and x4, x4, #~(THREAD_SIZE - 1)
msr sp_el0, x4 // Save thread_info
str_l x21, __fdt_pointer, x5 // Save FDT pointer
str_l x24, memstart_addr, x6 // Save PHYS_OFFSET
mov x29, #0
#ifdef CONFIG_KASAN
bl kasan_early_init
#endif
b start_kernel
ENDPROC(__mmap_switched)

这里的比较重要的一句是b start_kernel,跳转到start_kernel函数。

start_kernel函数在/kernel/msm-3.18/init/main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
asmlinkage __visible void __init start_kernel(void)
{
char *command_line;
char *after_dashes;

/*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
lockdep_init();
set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();
......
/* Do the rest non-__init'ed, we're now alive */
rest_init();
}

可以看出这里主要进行的是各种初始化,最后调用的是rest_init,rest_init创建了Linux系统中最重要的两个进程init和kthreadd,最后把init_task进程变为idle进行,开始无限循环,负责进程调度。

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
static noinline void __init_refok rest_init(void)
{
int pid;

rcu_scheduler_starting();
smpboot_thread_init();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
kernel_thread(kernel_init, NULL, CLONE_FS); //创建init的进程
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);//创建kthreadd进程
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
complete(&kthreadd_done);

/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
init_idle_bootup_task(current);//当前0进程设置为idle进程
schedule_preempt_disabled();
/* Call into cpu_idle with preempt disabled */
cpu_startup_entry(CPUHP_ONLINE);
}

里面各个函数详细的介绍参考:https://github.com/foxleezh/AOSP/issues/3

1.2.2 kthreadd进程启动

kthreadd进程启动,在文件/kernel/msm-3.18/kernel/kthread.c中

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
int kthreadd(void *unused)
{
struct task_struct *tsk = current;

/* Setup a clean context for our children to inherit. */
set_task_comm(tsk, "kthreadd");
ignore_signals(tsk);
set_cpus_allowed_ptr(tsk, cpu_all_mask);
set_mems_allowed(node_states[N_MEMORY]);

current->flags |= PF_NOFREEZE;

for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (list_empty(&kthread_create_list))
schedule();
__set_current_state(TASK_RUNNING);

spin_lock(&kthread_create_lock);
while (!list_empty(&kthread_create_list)) {
struct kthread_create_info *create;

create = list_entry(kthread_create_list.next,
struct kthread_create_info, list);
list_del_init(&create->list);
spin_unlock(&kthread_create_lock);

create_kthread(create);

spin_lock(&kthread_create_lock);
}
spin_unlock(&kthread_create_lock);
}

return 0;
}

1.2.3 init进程启动

init进程分为两个部分,第一部分是在内核启动的,主要完成创建和内核初始化工作;第二部分是在用户空间启动的,主要完成Android系统的初始化工作。

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
44
static int __ref kernel_init(void *unused)
{
int ret;

kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
mark_readonly();
system_state = SYSTEM_RUNNING;
numa_default_policy();

flush_delayed_fput();

if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d)/n",
ramdisk_execute_command, ret);
}

/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d). Attempting defaults.../n",
execute_command, ret);
}
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;

panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
}

kernel_init主要完成了一些初始化操作,然后再系统目录下找到ramdisk_execute_command 和execute_command设置的应用程序,如果这两个目录找不到,就依次从/sbin/init,/etc/init,/bin/init,/bin/sh这四个应用程序中启动,只要有一个应用程序启动,其他就不启动。ramdisk_execute_command 和execute_command是通过bootloader传递过来的参数设置的。

Android系统一般会在根目录下放一个init的可执行文件。在linux系统的init进程在内核初始化完成后,就直接执行init这个文件,这个文件的源代码在/system/core/init/init.cpp中,而后开始Android系统的init进程。

init第二阶段(/system/core/init/init.cpp)

主要的工作是初始化属性系统,解析SELinux的匹配规则,处理子进程终止信号,启动系统属性服务。由于init进程执行的操作很多,不可能一行行代码去做,所以Android系统引入了init.rc。init.rc是init进程启动的配置脚本,这个脚本是用一种Android Init Language的语言编写,这个语法的定义在/system/core/init/README.md文件中。在Android7.0之前只解析根目录下的init.rc文件,但随着版本的叠加,越来越臃肿,所以以后的版本init.rc一些业务被拆分到/system/etc/init,/vendor/etc/init,/odm/etc/init中。

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
int main(int argc, char** argv) {
..............
// Set up SELinux, loading the SELinux policy.
selinux_initialize(true);

// We're in the kernel domain, so re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
if (selinux_android_restorecon("/init", 0) == -1) {
PLOG(ERROR) << "restorecon failed";
security_failure();
}

setenv("INIT_SECOND_STAGE", "true", 1);

static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);

char* path = argv[0];
char* args[] = { path, nullptr };
execv(path, args);

// execv() only returns if an error happened, in which case we
// panic and never fall through this conditional.
PLOG(ERROR) << "execv(/"" << path << "/") failed";
security_failure();
}

// At this point we're in the second stage of init.
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";

// Set up a session keyring that all processes will have access to. It
// will hold things like FBE encryption keys. No process should override
// its session keyring.
keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);

// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
property_init();
........
// Now set up SELinux for second stage.
selinux_initialize(false);
selinux_restore_context();
........
//解析.rc文件
if (bootscript.empty()) {
parser.ParseConfig("/init.rc");
parser.set_is_system_etc_init_loaded(
parser.ParseConfig("/system/etc/init"));
parser.set_is_vendor_etc_init_loaded(
parser.ParseConfig("/vendor/etc/init"));
parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
} else {
parser.ParseConfig(bootscript);
parser.set_is_system_etc_init_loaded(true);
parser.set_is_vendor_etc_init_loaded(true);
parser.set_is_odm_etc_init_loaded(true);
}
..........
}

init进程解析.rc文件(/system/core/rootdir/的目录下),会启动一些service,这些service不是普通的服务,是守护进程(daemon)。守护进程是在系统初始化时启动,一直运行在后台,直到系统关闭时终结。Android系统的母进程zygote进程就是在这个时候启动的,zygote进程主要负责Java虚拟机,加载系统资源,启动SystemServer进程。

1.3 zygote进程启动

在文件/system/core/rootdir/init.rc中看到start zygote来启动zygote进程

1
2
3
4
5
6
7
8
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary

zygote服务的定义在头文件中有声明import /init.${ro.zygote}.rc

ro.zygote的属性值是不同的硬件厂商定制

在/system/core/rootdir/目录下可以看到四种不同的zygote相关的文件

init.zygote32.rc: zygote进程对应的执行程序是app_process(纯32bit模式)

init.zygote64.rc: zygote进程对应的执行程序是app_process64(纯64bit模式)

init.zygote32_64.rc:启动两个zygote进程(名为zygote和zygote_secondary),对应的执行程序分别是app_process32(主模式),app_process64

init.zygote64_32.rc:启动两个zygote进程(名为zygote和zygote_secondary),对应的执行程序分别是app_process64(主模式),app_process32

之所以出现这种定义是因为Android5.0以后开始支持64位程序,为了兼容32位和64位才这样定义,不同的zygote文件相差不大,主要是启动32位还是64位的进程。下面以init.zygote32_64.rc为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
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

service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
priority -20
user root
group root readproc
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks

app_processXX为终端目录下的可执行文件,其对应的源码文件是

/frameworks/base/cmds/app_process/app_main.cpp,其main函数如下,函数中主要是参数解析,通过解析的结果来判断启动的模式,这里有两种启动模式。

zygote模式,在初始化zygote进程,传递的参数有–start-system-server –socket-name=zygote,前者表示启动SystemService,后者指定socket的名称

application模式,启动普通的应用程序,传递的参数有class名字以及class带的参数。

解析完成后最终调用AppRuntime对象的start函数,加载ZygoteInit或RuntimeInit两个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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
int main(int argc, char* const argv[])
{
std::string bootmode = GetProperty("ro.bootmode", "");

if ((strncmp(bootmode.c_str(), "ffbm-00", 7) == 0)
|| (strncmp(bootmode.c_str(), "ffbm-01", 7) == 0)) {
return 0;
}

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++;

// Everything up to '--' or first non '-' arg goes to the vm.
//
// The first argument after the VM args is the "parent dir", which
// is currently unused.
//
// After the parent dir, we expect one or more the following internal
// arguments :
//
// --zygote : Start in zygote mode
// --start-system-server : Start the system server.
// --application : Start in application (stand alone, non zygote) mode.
// --nice-name : The nice name for this process.
//
// For non zygote starts, these arguments will be followed by
// the main class name. All remaining arguments are passed to
// the main method of this class.
//
// For zygote starts, all remaining arguments are passed to the zygote.
// main function.
//
// Note that we must copy argument string values since we will rewrite the
// entire argument block when we apply the nice name to argv0.
//
// As an exception to the above rule, anything in "spaced commands"
// goes to the vm even though it has a space in it.
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;

int i;
for (i = 0; i < argc; i++) {
if (known_command == true) {
runtime.addOption(strdup(argv[i]));
// The static analyzer gets upset that we don't ever free the above
// string. Since the allocation is from main, leaking it doesn't seem
// problematic. NOLINTNEXTLINE
ALOGV("app_process main add known option '%s'", argv[i]);
known_command = false;
continue;
}

for (int j = 0;
j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
++j) {
if (strcmp(argv[i], spaced_commands[j]) == 0) {
known_command = true;
ALOGV("app_process main found known command '%s'", argv[i]);
}
}

if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}

runtime.addOption(strdup(argv[i]));
// The static analyzer gets upset that we don't ever free the above
// string. Since the allocation is from main, leaking it doesn't seem
// problematic. NOLINTNEXTLINE
ALOGV("app_process main add option '%s'", argv[i]);
}

// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;

++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
//启动systemServer
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
//application启动模式
} 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;
}
}

Vector<String8> args;
if (!className.isEmpty()) {
// We're not in zygote mode, the only argument we need to pass
// to RuntimeInit is the application argument.
//
// The Remainder of args get passed to startup class main(). Make
// copies of them before we overwrite them with the process name.
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);

if (!LOG_NDEBUG) {
String8 restOfArgs;
char* const* argv_new = argv + i;
int argc_new = argc - i;
for (int k = 0; k < argc_new; ++k) {
restOfArgs.append("/"");
restOfArgs.append(argv_new[k]);
restOfArgs.append("/" ");
}
ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
}
} else {
// We're in zygote mode.
maybeCreateDalvikCache();

if (startSystemServer) {
args.add(String8("start-system-server"));
}

char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}

String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);

// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}

if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}

if (zygote) {
//zygote启动模式,加载zygoteInit
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
//application启动模式,加载RuntimeInit
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.");
}
}

创建虚拟机,调用ZygoteInit函数

runtime.start函数在/frameworks/base/core/jni/AndroidRuntime.cpp中

主要是初始化JNI,然后创建虚拟机,注册JNI函数,而后通过反射调用ZygoteInit类中的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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
......
/* 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) {
ALOGE("Unable to register all android natives/n");
return;
}

/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;

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

for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}

/*
* 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);//调用main函数

#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);

ALOGD("Shutting down VM/n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread/n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly/n");
}

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

在zygoteInit中首先设置了Java虚拟机的堆内存,然后启动了一个类加载器加载Android启动依赖的类比如Activity等四大组件,dialog等UI的类,然后分出一个子系统启动SystemServer服务

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
@UnsupportedAppUsage
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();

// 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;
try {
// Report Zygote start time to tron unless it is a runtime restart
if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
MetricsLogger.histogram(null, "boot_zygote_init",
(int) SystemClock.elapsedRealtime());
}

String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
RuntimeInit.enableDdms();

boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}

if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}

// TODO (chriswailes): Wrap these three calls in a helper function?
final String blastulaSocketName =
socketName.equals(ZygoteProcess.ZYGOTE_SOCKET_NAME)
? ZygoteProcess.BLASTULA_POOL_SOCKET_NAME
: ZygoteProcess.BLASTULA_POOL_SECONDARY_SOCKET_NAME;
//为Zygote注册socket
zygoteServer.createZygoteSocket(socketName);
Zygote.createBlastulaSocket(blastulaSocketName);

Zygote.getSocketFDs(socketName.equals(ZygoteProcess.ZYGOTE_SOCKET_NAME));

// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
// 预加载类和资源
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}

// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

bootTimingsTraceLog.traceEnd(); // ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false, 0);

Zygote.nativeSecurityInit();

// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();

ZygoteHooks.stopZygoteNoThreadCreation();

//启动SystemServer进程
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, 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;
}
}

// If the return value is null then this is the zygote process
// returning to the normal control flow. If it returns a Runnable
// object then this is a blastula that has finished specializing.
caller = Zygote.initBlastulaPool();
//当接收到请求创建新进程请求时立即唤醒并执行相应工作。
if (caller == null) {
Log.i(TAG, "Accepting command socket connections");

// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
}
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}

// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
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
static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
beginPreload();
bootTimingsTraceLog.traceEnd(); // BeginPreload
bootTimingsTraceLog.traceBegin("PreloadClasses");
//预加载位于/system/etc/preloaded-classes文件中的类
preloadClasses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
cacheNonBootClasspathClassLoaders();
bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
bootTimingsTraceLog.traceBegin("PreloadResources");
//预加载资源,包含drawable和color资源
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
nativePreloadAppProcessHALs();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
//预加载OpenGL
preloadOpenGL();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
//通过System.loadLibrary()方法,
//预加载"android","compiler_rt","jnigraphics"这3个共享库
preloadSharedLibraries();
//预加载 文本连接符资源
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
//仅用于zygote进程,用于内存共享的进程
WebViewFactory.prepareWebViewInZygote();
endPreload();
warmUpJcaProviders();
Log.d(TAG, "end preload");

sPreloadComplete = true;
}

zygote进程内加载了preload()方法中的所有资源,当需要fork新进程时,采用copy on write技术,如下:

fork()采用copy on write技术,这是linux创建进程的标准方法,调用一次,返回两次,返回值有3种类型。

  • 父进程中,fork返回新创建的子进程的pid;
  • 子进程中,fork返回0;
  • 当出现错误时,fork返回负数。(当进程数超过上限或者系统内存不足时会出错)

fork()的主要工作是寻找空闲的进程号pid,然后从父进程拷贝进程信息,例如数据段和代码段,fork()后子进程要执行的代码等。 Zygote进程是所有Android进程的母体,包括system_server和各个App进程。zygote利用fork()方法生成新进程,对于新进程A复用Zygote进程本身的资源,再加上新进程A相关的资源,构成新的应用进程A。

copy-on-write过程:当父子进程任一方修改内存数据时(这是on-write时机),才发生缺页中断,从而分配新的物理内存(这是copy操作)。

copy-on-write原理:写时拷贝是指子进程与父进程的页表都所指向同一个块物理内存,fork过程只拷贝父进程的页表,并标记这些页表是只读的。父子进程共用同一份物理内存,如果父子进程任一方想要修改这块物理内存,那么会触发缺页异常(page fault),Linux收到该中断便会创建新的物理内存,并将两个物理内存标记设置为可写状态,从而父子进程都有各自独立的物理内存。

1.4 SystemServer启动

forkSystemServer函数将会启动SystemServer进程

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
* Prepare the arguments and forks for the system server process.
*
* @return A {@code Runnable} that provides an entrypoint into system_server code in the child
* process; {@code null} in the parent.
*/
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_IPC_LOCK,
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_PTRACE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG,
OsConstants.CAP_WAKE_ALARM,
OsConstants.CAP_BLOCK_SUSPEND
);
/* Containers run without some capabilities, so drop any caps that are not available. */
StructCapUserHeader header = new StructCapUserHeader(
OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
StructCapUserData[] data;
try {
data = Os.capget(header);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to capget()", ex);
}
capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
//参数准备
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
ZygoteArguments parsedArgs = null;

int pid;

try {
parsedArgs = new ZygoteArguments(args);
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);

boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver", false);
if (profileSystemServer) {
parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}

String use_app_image_cache = SystemProperties.get(
PROPERTY_USE_APP_IMAGE_STARTUP_CACHE, "");
// Property defaults to true currently.
if (!TextUtils.isEmpty(use_app_image_cache) && !use_app_image_cache.equals("false")) {
parsedArgs.mRuntimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE;
}
//开启systemServer进程,如果system_server进程死亡后,会重启zygote进程
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
//进入子进程system_server
/* For child process */
if (pid == 0) {
//从zygote进程fork新进程后,需要关闭zygote原有的socket。
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}

zygoteServer.closeServerSocket();
// 完成system_server进程剩余的工作
return handleSystemServerProcess(parsedArgs);
}

return null;
}

Zygote.forkSystemServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
//native实现
//代码路径在/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
// Enable tracing as soon as we enter the system_server.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
}
ZygoteHooks.postForkCommon();
return pid;
}

handleSystemServerProcess方法

此处systemServerClasspath环境变量主要有/system/framework/目录下的services.jar,ethernet-service.jar, wifi-service.jar这3个文件

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
* Finish remaining work for the newly forked system server process.
*/
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
// set umask to 0077 so new files and directories will default to owner-only permissions.
Os.umask(S_IRWXG | S_IRWXO);

if (parsedArgs.mNiceName != null) {
//设置当前进程名为"system_server"
Process.setArgV0(parsedArgs.mNiceName);
}

final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
//执行dex优化操作
if (performSystemServerDexOpt(systemServerClasspath)) {
// Throw away the cached classloader. If we compiled here, the classloader would
// not have had AoT-ed artifacts.
// Note: This only works in a very special environment where selinux enforcement is
// disabled, e.g., Mac builds.
sCachedSystemServerClassLoader = null;
}
// Capturing profiles is only supported for debug or eng builds since selinux normally
// prevents it.
boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver", false);
if (profileSystemServer && (Build.IS_USERDEBUG || Build.IS_ENG)) {
try {
prepareSystemServerProfile(systemServerClasspath);
} catch (Exception e) {
Log.wtf(TAG, "Failed to set up system server profile", e);
}
}
}

if (parsedArgs.mInvokeWith != null) {
String[] args = parsedArgs.mRemainingArgs;
// If we have a non-null system server class path, we'll have to duplicate the
// existing arguments and append the classpath to it. ART will handle the classpath
// correctly when we exec a new process.
if (systemServerClasspath != null) {
String[] amendedArgs = new String[args.length + 2];
amendedArgs[0] = "-cp";
amendedArgs[1] = systemServerClasspath;
System.arraycopy(args, 0, amendedArgs, 2, args.length);
args = amendedArgs;
}
//启动应用进程
WrapperInit.execApplication(parsedArgs.mInvokeWith,
parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args);

throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else {
// 创建类加载器,并赋予当前线程
createSystemServerClassLoader();
ClassLoader cl = sCachedSystemServerClassLoader;
if (cl != null) {
Thread.currentThread().setContextClassLoader(cl);
}
//最后通过反射方法启动system_server
/*
* Pass the remaining arguments to SystemServer.
*/
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, cl);
}

/* should never reach here */
}

ZygoteInit.zygoteInit最后调用的是这个方法,这样就进入到了SystemServer类的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
30
31
32
/**
* Helper class which holds a method and arguments and can call them. This is used as part of
* a trampoline to get rid of the initial process setup stack frames.
*/
static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;

/** argument array */
private final String[] mArgs;

public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}

public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}

1.5 总结

上面详细介绍了SystemServer进程的启动过程,在这个启动过程中,主要是一系列进程的启动,从内核启动的三个进程idle进程、kthreadd进程、init进程最后到zygote进程启动,通过zygote进程来启动SystemServer进程,最后通过反射的方法调用了SystemServer的main方法,下节将会介绍详细的SystemServer中的启动流程。

附录

本文设计的源码文件路径

1
2
3
4
5
6
7
8
/kernel/msm-3.18/arch/arm64/kernel/head.S
/kernel/msm-3.18/init/main.c
/kernel/msm-3.18/kernel/kthread.c
/system/core/init/init.cpp
/system/core/rootdir/init.rc
/frameworks/base/cmds/app_process/app_main.cpp
/frameworks/base/core/jni/AndroidRuntime.cpp
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java