• 前序

  时间从来不语,却回答了所有问题,岁月从来不言,却见证了所有努力,愿大家遇到困难时都能换乘机遇,踏歌而行时一往无前。

参考资料

  • Android Framework 开发揭秘

  本文中的所有内容大部分来源于网络资料,如有侵权请联系本人修改或删除,请大家多多支持原创!非常感谢!

简介

  Android 是一种基于 Linux 的开放源代码软件栈,为各类设备和机型而创建。

平台架构.png

  Android 平台的基础是Linux内核。例如,Android Runtime(ART)依靠Linux内核来执行底层功能,例如线程和底层内存管理。

Linux 内核

  • 硬件抽象层(HAL)

    • HAL提供标准界面,向更高级的Java API 框架显示设备硬件功能。
  • Android Runtime

    • 对于运行在Android 5.5(API 21)以上的设备,每个应用都有自己的ART实例并在其自己的进程中运行。
    • ART编写为通过执行DEX文件在低内存上运行多个虚拟机。
    • ART的功能包括
      • 预先AOT和及时JIT,编译优化而垃圾回收GC
      • 在API 28以上,支持将应用软件包中的Dalvik Executable格式(DEX)文件转换为更紧凑的机器代码。
  • 原生C/C++库

  • Java API框架

Android 系统启动的大概流程

  1. 启动电源以及系统启动:当电源按下,引导芯片代码开始从预定义的地方(固化在ROM硬盘)开始执行。加载引导程序到RAM内存。Boot ROM
  2. 引导程序:引导程序是在Android操作系统开始运行前的程序,针对特定主板和芯片。比如redboot、uboot、qibootloader或者其他。android引导程序可以在./bootable找到。
  3. 内核:Android内核与桌面linux内核启动方式差不多。内核启动时读取配置文件,设置缓存,被保护存储器、计划列表,加载驱动,当内核完成系统设置,它首先在系统文件中找”init”文件,然后启动root进程或者系统的第一个进程。
  4. init进程:init进程是系统所有进程的起点,进程号固定为1。Kernel启动后,在用户空间启动init进程,并调用init中的main()方法进行init进程的职责。
  5. 启动Lancher App

init进程分析

  init进程是Android 系统中及其重要的第一个进程

  1. 创建和挂载启动所需要的文件目录
  2. 初始化和启动属性服务
  3. 解析init.rc配置文件并启动Zygote进程
  • system/core/init/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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int main(int argc, char** argv) {
// 如果编译时开启了 AddressSanitizer,则设置地址检测器错误报告回调函数
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
// 如果编译时开启了 HardwareAddressSanitizer,则设置硬件地址检测器错误报告回调函数
#elif __has_feature(hwaddress_sanitizer)
__hwasan_set_error_report_callback(AsanReportCallback);
#endif

// 提高进程优先级,稍后会恢复
setpriority(PRIO_PROCESS, 0, -20);

// 如果可执行文件的基本名称(去掉路径部分)是 "ueventd",则调用 ueventd_main 函数
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}

// 如果命令行参数个数大于 1
if (argc > 1) {
// 如果第一个参数是 "subcontext"
if (!strcmp(argv[1], "subcontext")) {
// 初始化日志系统,并调用 SubcontextMain 函数
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

return SubcontextMain(argc, argv, &function_map);
}

// 如果第一个参数是 "selinux_setup",则调用 SetupSelinux 函数
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}

// 如果第一个参数是 "second_stage",则调用 SecondStageMain 函数
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}

// 默认情况下调用 FirstStageMain 函数
return FirstStageMain(argc, argv);
}

  后续在FirstStageMain()函数中mount挂载文件系统,创建一系列文件,以及初始化目录的读写权限,并创建设备文件,位于./first_stage_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
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
int FirstStageMain(int argc, char** argv) {
// InstallRebootSignalHandlers 用于在发生 panic 时重新启动到 bootloader,如果已配置。
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}

// 记录启动时间,使用 boot_clock。
boot_clock::time_point start_time = boot_clock::now();

// 存储初始化过程中遇到的错误的向量。
std::vector<std::pair<std::string, int>> errors;

// CHECKCALL 宏用于检查系统调用的结果,并将任何错误添加到 'errors' 向量中。
#define CHECKCALL(x) \
if ((x) != 0) errors.emplace_back(#x " 失败", errno);

// 将 umask 设置为 0。
umask(0);

// 清除环境变量。
CHECKCALL(clearenv());

// 将 PATH 环境变量设置为默认路径。
CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));

// 挂载必要的文件系统并创建基本目录。
// ...

// 为 vold 管理的设备挂载分区的暂存区域。
// ...
CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=0"));

// 重置错误检查宏。
#undef CHECKCALL

// 将标准输入、输出和错误重定向到 /dev/null。
SetStdioToDevNull(argv);

// 初始化内核日志。
InitKernelLogging(argv);

// 如果初始化过程中遇到错误,记录错误信息。
if (!errors.empty()) {
for (const auto& [error_string, error_errno] : errors) {
LOG(ERROR) << error_string << " " << strerror(error_errno);
}
LOG(FATAL) << "Init 在启动第一阶段时遇到错误,中止";
}

// 记录第一阶段启动的消息。
LOG(INFO) << "init 第一阶段启动!";

// 如果需要,释放 ramdisk。
// ...

// 确定是否启用 console,并检查是否请求并行模块加载。
auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0;
auto want_parallel = bootconfig.find("androidboot.load_modules_parallel = \"true\"") != std::string::npos;

// 加载内核模块。
int module_count = 0;
// ...
LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig), want_console,
want_parallel, module_count);

// 打印有关加载的内核模块的信息。
// ...

// 如果启用失败时的 console,创建设备。
bool created_devices = false;
if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
if (!IsRecoveryMode()) {
created_devices = DoCreateDevices();
if (!created_devices) {
LOG(ERROR) << "无法提前创建设备节点";
}
}
StartConsole(cmdline);
}

// 如果存在 ramdisk prop,则复制。
// ...

// 设置环境变量,以便第二阶段 init 读取调试文件。
setenv("INIT_FORCE_DEBUGGABLE", "true", 1);

// 如果强制正常启动,则切换根目录。
if (ForceNormalBoot(cmdline, bootconfig)) {
// ...
SwitchRoot("/first_stage_ramdisk");
}

// 执行第一阶段挂载。
if (!DoFirstStageMount(!created_devices)) {
LOG(FATAL) << "无法提前挂载所需的分区...";
}

// 如果存在旧的 ramdisk,则释放它。
// ...

// 如果需要,在 recovery 中设置 AVB 版本。
SetInitAvbVersionInRecovery();

// 设置环境变量以记录启动时间。
setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);

// 调用 execv() 替换当前进程为第二阶段 init。
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
execv(path, const_cast<char**>(args));

// 如果发生错误,execv() 只有在发生错误时才返回。
PLOG(FATAL) << "execv(\"" << path << "\") 失败";

return 1;
}

init.rc 解析

  • 路径:system/core/rootdir/init.rc

  init.rc 是一个非常重要的配置文件,由Android初始化语言(Android Init Language)编写的脚本,它主要包含五种类型语句:Action(Action中包含了一系列的Command)、Commands(init语言中的命令)、Service(由init进程启动的服务)、Options(对服务进行配置的选项)和Import(引入其他配置文件)。

1
2
3
4
5
6
7
8
9
10
11
## line 490
on property:apexd.status=ready && property:ro.product.cpu.abilist64=*
exec_start boringssl_self_test_apex64

service boringssl_self_test32 /system/bin/boringssl_self_test32
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
# Explicitly specify that boringssl_self_test32 doesn't require any capabilities
capabilities
user nobody
# ...
  • 语法
1
2
3
4
5
6
7
8
9
10
on  <trigger> [&& <trigger>]* //设置触发器
<command>
<command> //动作触发之后要执行的命令

service <name> <pathname> [<argument>]* //<service的名字><执行程序路径><传递参数>
<option> //options是services的参数配置,它们影响Service如何运行及运行时机
group <groupname> [<groupname>\*] //在启动Service前将group改为第一个groupname,第一个groupname是必须有的
//默认值是root,第二各groupname可以不设置,用于追加组(通过setgroups)
priority <proiority> //设置进程优先级,在-20~19之间,默认值是0,通过setpriority实现
socket <name> <type> <perm> [<user> [<group> [<seclabel>]]] //创建一个unix域的socket,名字叫/dev/socket/name,并将fd返回给Service,type只能是dgram,stream,swqpacket

Action

  Action通过触发器trigger,即以on开头的语句来决定执行相应的service的时机。具体有如下时机:

  • on early-init:在初始化早期阶段触发
  • on init:在初始化阶段触发
  • on late-init:在初始化晚期阶段触发
  • on boot/charger:当系统启动/充电时触发
  • on property:=:当属性值满足条件时触发

Service

  服务Service,以service开头,由init进程启动,一般运行在init的一个子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service在启动时会通过fork方式生成子进程。例如

1
service boringssl_self_test32 /system/bin/boringssl_self_test32

  代表的是服务名为boringssl_self_test32,服务执行的路径为/system/bin/boringssl_self_test32

Command

  • class_start : 启动属于同一个class的所有服务
  • start :启动指定的服务,若已启动则跳过
  • stop :停止正在运行的服务
  • setprop:设置属性值
  • mkdir:创建指定目录
  • symlink :创建连接到的符号链接
  • write:向文件path中写入字符串
  • exec:fork并执行,会阻塞init进程直到程序完毕
  • exprot:设定环境变量
  • loglevel:设定log级别

Options

  Options是Service的可选项,与service配合使用

  • disabled:不随class自动启动,只有根据Service名才启动

  • oneshot:service退出后不再重启

  • user/group:设置执行服务的用户/用户组,默认都是root;

  • class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;onrestart:当服务重启时执行相应命令

  • socket:创建名为/dev/socket/的socket,critical:在规定时间内该Service不断重启,则系统会重启并进入恢复模式 default:意味着disabled=flase,oneshot=false,critical=false

  • system/core/rootdir/init.zygote64.rc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
# NOTE: If the wakelock name here is changed, then also
# update it in SystemSuspend.cpp
onrestart write /sys/power/wake_lock zygote_kwl
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart media.tuner
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh MaxPerformance
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

service解析流程

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
//line 337

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);//创建解析器

std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
// late_import is available only in Q and earlier release. As we don't
// have system_ext in those versions, skip late_import for system_ext.
parser.ParseConfig("/system_ext/etc/init");
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
} else {
parser.ParseConfig(bootscript);//开始解析
}
}

//Line 270

Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;

parser.AddSectionParser("service", std::make_unique<ServiceParser>(
&service_list, GetSubcontext(), std::nullopt));//service解析
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));

return parser;
}

  • system/core/init/parser.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
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
void Parser::ParseData(const std::string& filename, std::string* data) {
data->push_back('\n');
data->push_back('\0');

parse_state state;
state.line = 0;
state.ptr = data->data();
state.nexttoken = 0;

SectionParser* section_parser = nullptr;
int section_start_line = -1;
std::vector<std::string> args;

// If we encounter a bad section start, there is no valid parser object to parse the subsequent
// sections, so we must suppress errors until the next valid section is found.
bool bad_section_found = false;

auto end_section = [&] {
bad_section_found = false;
if (section_parser == nullptr) return;

if (auto result = section_parser->EndSection(); !result.ok()) {
parse_error_count_++;
LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();
}

section_parser = nullptr;
section_start_line = -1;
};

for (;;) {
switch (next_token(&state)) {
case T_EOF:
end_section();

for (const auto& [section_name, section_parser] : section_parsers_) {
section_parser->EndFile();
}

return;
case T_NEWLINE: {
state.line++;
if (args.empty()) break;
// If we have a line matching a prefix we recognize, call its callback and unset any
// current section parsers. This is meant for /sys/ and /dev/ line entries for
// uevent.
auto line_callback = std::find_if(
line_callbacks_.begin(), line_callbacks_.end(),
[&args](const auto& c) { return android::base::StartsWith(args[0], c.first); });
if (line_callback != line_callbacks_.end()) {
end_section();

if (auto result = line_callback->second(std::move(args)); !result.ok()) {
parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
} else if (section_parsers_.count(args[0])) {
end_section();
section_parser = section_parsers_[args[0]].get();
section_start_line = state.line;
if (auto result =
section_parser->ParseSection(std::move(args), filename, state.line);
!result.ok()) {
parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
section_parser = nullptr;
bad_section_found = true;
}
} else if (section_parser) {
if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
!result.ok()) {
parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
} else if (!bad_section_found) {
parse_error_count_++;
LOG(ERROR) << filename << ": " << state.line
<< ": Invalid section keyword found";
}
args.clear();
break;
}
case T_TEXT:
args.emplace_back(state.text);
break;
}
}
}
  • system/core/init/service.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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Result<std::unique_ptr<Service>> Service::MakeTemporaryOneshotService(
const std::vector<std::string>& args) {
// Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
// SECLABEL can be a - to denote default
std::size_t command_arg = 1;
for (std::size_t i = 1; i < args.size(); ++i) {
if (args[i] == "--") {
command_arg = i + 1;
break;
}
}
if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
return Error() << "exec called with too many supplementary group ids";
}

if (command_arg >= args.size()) {
return Error() << "exec called without command";
}
std::vector<std::string> str_args(args.begin() + command_arg, args.end());

static size_t exec_count = 0;
exec_count++;
std::string name = "exec " + std::to_string(exec_count) + " (" + Join(str_args, " ") + ")";

unsigned flags = SVC_ONESHOT | SVC_TEMPORARY;
unsigned namespace_flags = 0;

std::string seclabel = "";
if (command_arg > 2 && args[1] != "-") {
seclabel = args[1];
}
Result<uid_t> uid = 0;
if (command_arg > 3) {
uid = DecodeUid(args[2]);
if (!uid.ok()) {
return Error() << "Unable to decode UID for '" << args[2] << "': " << uid.error();
}
}
Result<gid_t> gid = 0;
std::vector<gid_t> supp_gids;
if (command_arg > 4) {
gid = DecodeUid(args[3]);
if (!gid.ok()) {
return Error() << "Unable to decode GID for '" << args[3] << "': " << gid.error();
}
std::size_t nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
for (size_t i = 0; i < nr_supp_gids; ++i) {
auto supp_gid = DecodeUid(args[4 + i]);
if (!supp_gid.ok()) {
return Error() << "Unable to decode GID for '" << args[4 + i]
<< "': " << supp_gid.error();
}
supp_gids.push_back(*supp_gid);
}
}

return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, namespace_flags, seclabel,
nullptr, /*filename=*/"", str_args);//构建一个service对象
}

  解析完成后,就是启动service,以启动Zygote为例

  • system/core/init/builtins.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    static Result<void> do_class_start(const BuiltinArguments& args) {
    // Do not start a class if it has a property persist.dont_start_class.CLASS set to 1.
    if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
    return {};
    // Starting a class does not start services which are explicitly disabled.
    // They must be started individually.
    for (const auto& service : ServiceList::GetInstance()) {
    if (service->classnames().count(args[1])) {
    if (auto result = service->StartIfNotDisabled(); !result.ok()) {
    LOG(ERROR) << "Could not start service '" << service->name()
    << "' as part of class '" << args[1] << "': " << result.error();
    }
    }
    }
    return {};
    }
  • system/core/init/service.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
    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
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    Result<void> Service::Start() {
    auto reboot_on_failure = make_scope_guard([this] {
    if (on_failure_reboot_target_) {
    trigger_shutdown(*on_failure_reboot_target_);
    }
    });

    if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
    ServiceList::GetInstance().DelayService(*this);
    return Error() << "Cannot start an updatable service '" << name_
    << "' before configs from APEXes are all loaded. "
    << "Queued for execution.";
    }

    bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
    ResetFlagsForStart();

    // Running processes require no additional work --- if they're in the
    // process of exiting, we've ensured that they will immediately restart
    // on exit, unless they are ONESHOT. For ONESHOT service, if it's in
    // stopping status, we just set SVC_RESTART flag so it will get restarted
    // in Reap().
    //如果service已经运行,则不启动
    if (flags_ & SVC_RUNNING) {
    if ((flags_ & SVC_ONESHOT) && disabled) {
    flags_ |= SVC_RESTART;
    }

    LOG(INFO) << "service '" << name_
    << "' requested start, but it is already running (flags: " << flags_ << ")";

    // It is not an error to try to start a service that is already running.
    reboot_on_failure.Disable();
    return {};
    }

    // cgroups_activated is used for communication from the parent to the child
    // while setsid_finished is used for communication from the child process to
    // the parent process. These two communication channels are separate because
    // combining these into a single communication channel would introduce a
    // race between the Write() calls by the parent and by the child.
    InterprocessFifo cgroups_activated, setsid_finished;
    OR_RETURN(cgroups_activated.Initialize());
    OR_RETURN(setsid_finished.Initialize());

    if (Result<void> result = CheckConsole(); !result.ok()) {
    return result;
    }
    //判断需要启动的service的对应执行文件是否存在,不存在就不启动service struct
    struct stat sb;
    if (stat(args_[0].c_str(), &sb) == -1) {
    flags_ |= SVC_DISABLED;
    return ErrnoError() << "Cannot find '" << args_[0] << "'";
    }

    std::string scon;
    if (!seclabel_.empty()) {
    scon = seclabel_;
    } else {
    auto result = ComputeContextFromExecutable(args_[0]);
    if (!result.ok()) {
    return result.error();
    }
    scon = *result;
    }

    if (!mount_namespace_.has_value()) {
    // remember from which mount namespace the service should start
    SetMountNamespace();
    }

    post_data_ = ServiceList::GetInstance().IsPostData();

    LOG(INFO) << "starting service '" << name_ << "'...";

    std::vector<Descriptor> descriptors;
    for (const auto& socket : sockets_) {
    if (auto result = socket.Create(scon); result.ok()) {
    descriptors.emplace_back(std::move(*result));
    } else {
    LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
    }
    }

    for (const auto& file : files_) {
    if (auto result = file.Create(); result.ok()) {
    descriptors.emplace_back(std::move(*result));
    } else {
    LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
    }
    }
    //如果子进程没有启动,则调用fork()函数创建子进程
    pid_t pid = -1;
    if (namespaces_.flags) {
    pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    } else {
    pid = fork();
    }

    if (pid == 0) {//当前代码逻辑在子进程中运行
    umask(077);
    cgroups_activated.CloseWriteFd();
    setsid_finished.CloseReadFd();
    RunService(descriptors, std::move(cgroups_activated), std::move(setsid_finished));
    _exit(127);
    } else {
    cgroups_activated.CloseReadFd();
    setsid_finished.CloseWriteFd();
    }

    if (pid < 0) {
    pid_ = 0;
    return ErrnoError() << "Failed to fork";
    }

    once_environment_vars_.clear();

    if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
    std::string oom_str = std::to_string(oom_score_adjust_);
    std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
    if (!WriteStringToFile(oom_str, oom_file)) {
    PLOG(ERROR) << "couldn't write oom_score_adj";
    }
    }

    time_started_ = boot_clock::now();
    pid_ = pid;
    flags_ |= SVC_RUNNING;
    start_order_ = next_start_order_++;
    process_cgroup_empty_ = false;

    if (CgroupsAvailable()) {
    bool use_memcg = swappiness_ != -1 || soft_limit_in_bytes_ != -1 || limit_in_bytes_ != -1 ||
    limit_percent_ != -1 || !limit_property_.empty();
    errno = -createProcessGroup(proc_attr_.uid, pid_, use_memcg);
    if (errno != 0) {
    Result<void> result = cgroups_activated.Write(kActivatingCgroupsFailed);
    if (!result.ok()) {
    return Error() << "Sending notification failed: " << result.error();
    }
    return Error() << "createProcessGroup(" << proc_attr_.uid << ", " << pid_ << ", "
    << use_memcg << ") failed for service '" << name_
    << "': " << strerror(errno);
    }

    // When the blkio controller is mounted in the v1 hierarchy, NormalIoPriority is
    // the default (/dev/blkio). When the blkio controller is mounted in the v2 hierarchy, the
    // NormalIoPriority profile has to be applied explicitly.
    SetProcessProfiles(proc_attr_.uid, pid_, {"NormalIoPriority"});

    if (use_memcg) {
    ConfigureMemcg();
    }
    }

    if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
    LmkdRegister(name_, proc_attr_.uid, pid_, oom_score_adjust_);
    }

    if (Result<void> result = cgroups_activated.Write(kCgroupsActivated); !result.ok()) {
    return Error() << "Sending cgroups activated notification failed: " << result.error();
    }

    cgroups_activated.Close();

    // Call setpgid() from the parent process to make sure that this call has
    // finished before the parent process calls kill(-pgid, ...).
    if (!RequiresConsole(proc_attr_)) {
    if (setpgid(pid, pid) < 0) {
    switch (errno) {
    case EACCES: // Child has already performed setpgid() followed by execve().
    case ESRCH: // Child process no longer exists.
    break;
    default:
    PLOG(ERROR) << "setpgid() from parent failed";
    }
    }
    } else {
    // The Read() call below will return an error if the child is killed.
    if (Result<uint8_t> result = setsid_finished.Read();
    !result.ok() || *result != kSetSidFinished) {
    if (!result.ok()) {
    return Error() << "Waiting for setsid() failed: " << result.error();
    } else {
    return Error() << "Waiting for setsid() failed: " << static_cast<uint32_t>(*result)
    << " <> " << static_cast<uint32_t>(kSetSidFinished);
    }
    }
    }

    setsid_finished.Close();

    NotifyStateChange("running");
    reboot_on_failure.Disable();

    LOG(INFO) << "... started service '" << name_ << "' has pid " << pid_;

    return {};
    }

Zygote

  Zygote中文翻译是“受精卵“,正如其名,它主要用于孵化子进程。在Android系统中有两种程序:

  • java应用程序,主要基于ART虚拟机,所有的应用程序apk都属于这类native程序,也就是利用C或C++语言开发的程序,如Bootanimation。所有的Java应用程序进程及系统服务SystemServer进程都由Zygote进程通过Linux的fork()函数孵化出来的,而native程序则由init程序创建启动。最初的名字是app_process。Zygote是Android中的第一个art虚拟机,通过socket的方式与其他进程进行通信。Zygote是一个C/S模型,Zygote进程作为服务端,它主要负责创建Java虚拟机,加载系统资源,启动SystemServer进程,以及在后续运行过程中启动普通的应用程序,其他进程作为客户端向它发出“孵化”请求,而Zygote接收到这个请求后就“孵化”出一个新的进程。比如,当点击Launcher里的应用图标去启动一个新的应用程序时,这个请求会到达框架层的核心服务ActivityMangerService中,当AMS受到这个请求后,它通过调用Process类发出一个“孵化”子进程的Socket请求,而Zygote监听到这个请求后就立刻fork一个新的进程出来。

Zygote触发过程

  1. init.zygoteXX.rc

import /init.${ro.zygote}.rc

  ${ro.zygote}会被替换成ro.zygote的属性值,这个是由不同的硬件厂商自己定制,有4个值

  • zygote32:zygote进程对应的执行程序是app_process(纯32bit模式)
  • zygote64:zygote进程对应的执行程序是app_process64(纯64bit模式)
  • zygote32_64:启动两个zygote进程(名为zygote和zygote_secondary),对应的执行程序,对应的执行程序app_process32(主模式)
  • zygote64_32:启动两个zygote进程(名为zygote和zygote_secondary),对应的执行程序分别是app_process64(主模式)、app_process32
  1. start zygote
  • system/core/rootdir/init.rc
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
# Line 1070
# 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
wait_for_prop odsign.verification.done 1
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start statsd
start netd
start zygote
start zygote_secondary

on zygote-start && property:ro.crypto.state=unsupported
wait_for_prop odsign.verification.done 1
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start statsd
start netd
start zygote
start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
wait_for_prop odsign.verification.done 1
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start statsd
start netd
start zygote
start zygote_secondary

  zygote-start是在on late-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
## line 532

on late-init
trigger early-fs

# Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
# '--early' can be specified to skip entries with 'latemount'.
# /system and /vendor must be mounted by the end of the fs stage,
# while /data is optional.
trigger fs
trigger post-fs

# Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
# to only mount entries with 'latemount'. This is needed if '--early' is
# specified in the previous mount_all command on the fs stage.
# With /system mounted and properties form /system + /factory available,
# some services can be started.
trigger late-fs

# Now we can mount /data. File encryption requires keymaster to decrypt
# /data, which in turn can only be loaded when system properties are present.
trigger post-fs-data

# Should be before netd, but after apex, properties and logging is available.
trigger load_bpf_programs

# Now we can start zygote for devices with file based encryption
trigger zygote-start

# Remove a file to wake up anything waiting for firmware.
trigger firmware_mounts_complete

trigger early-boot
trigger boot

# Line 1346
on userspace-reboot-resume
trigger userspace-reboot-fs-remount
trigger post-fs-data
trigger zygote-start
trigger early-boot
trigger boot

Zygote启动过程

  • 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
29
30
31
32
33
34
35
36
37

int main(int argc, char* const argv[])
{
//...Line 264
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} 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.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
//...
if (zygote) {
//这些Java的应用都是通过AppRuntime.start(className)开始的
//其实AppRuntime是AndroidRuntime的子类,它主要实现了几个回调函数,而start()方法是实现在AndroidRutime这个方法类里
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (!className.isEmpty()) {
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.");
}

}

  在app_main.cpp的main函数中,主要做的事情就是参数解析,这个函数有两种启动模式:

  1. 一种zygote模式,也就是初始化zygote进程,传递的参数有–start-system-server –socket- name=zygote,前者表示启动SystemServer,后者指定socket的名称
  2. 一种是application模式,也就是启动普通应用程序,传递的参数有class名字以及class带的参数两者最终都是调用AppRuntime对象的start函数,加载ZygoteInit或RuntimeInit两个Java类,并将之前整理的参数传入进去。

  app_process里面定义了三种应用程序类型:

  • Zygote:com.android.internal.os.ZygoteInit
  • System Server,不单独启动,而是由Zygote启动
  • 其他指定类名的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
class AppRuntime : public AndroidRuntime
{
public:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength)
, mClass(NULL)
{
}

void setClassNameAndArgs(const String8& className, int argc, char * const *argv) {
mClassName = className;
for (int i = 0; i < argc; ++i) {
mArgs.add(String8(argv[i]));
}
}

virtual void onVmCreated(JNIEnv* env)
{
if (mClassName.isEmpty()) {
return; // Zygote. Nothing to do here.
}

/*
* This is a little awkward because the JNI FindClass call uses the
* class loader associated with the native method we're executing in.
* If called in onStarted (from RuntimeInit.finishInit because we're
* launching "am", for example), FindClass would see that we're calling
* from a boot class' native method, and so wouldn't look for the class
* we're trying to look up in CLASSPATH. Unfortunately it needs to,
* because the "am" classes are not boot classes.
*
* The easiest fix is to call FindClass here, early on before we start
* executing boot class Java code and thereby deny ourselves access to
* non-boot classes.
*/
char* slashClassName = toSlashClassName(mClassName.string());
mClass = env->FindClass(slashClassName);
if (mClass == NULL) {
ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
}
free(slashClassName);

mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
}

virtual void onStarted()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();

AndroidRuntime* ar = AndroidRuntime::getRuntime();
ar->callMain(mClassName, mClass, mArgs);

IPCThreadState::self()->stopProcess();
hardware::IPCThreadState::self()->stopProcess();
}

virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}

virtual void onExit(int code)
{
if (mClassName.isEmpty()) {
// if zygote
IPCThreadState::self()->stopProcess();
hardware::IPCThreadState::self()->stopProcess();
}

AndroidRuntime::onExit(code);
}


String8 mClassName;
Vector<String8> mArgs;
jclass mClass;
};

  • 什么是Runtime?

    • Runtime是支撑程序运行的基础库,它与语言绑定在一起。
    • C Runtime:就是C standard lib也就是常说的libc(有趣的是Wiki自动将“C runtime”重定向到”C Standard Library)
    • Java Runtime: 同样,Wiki将其重定向到“Java Virtual Machine”,这里当然包括Java的支撑类库
    • AndroidRuntime:显而易见,就是为Android应用运行所需的运行时环境。这个环境包括一下东西。
      • Dalvik VM:Android 的Java VM,解释运行Dex格式Java程序。每个进程运行一个虚拟机(什么叫运行虚拟机?就是一些C代码,不停的去解释Dex格式的二进制码(Bytecode),把他们转换称机器码Machine code,现在大多数java虚拟机都支持JIT,bytecode可能在运行前就已经被转换成机器码,从而大大提高了性能。在某些情况下,Java甚至可以比C/C++跑得更快,同时又兼具平台无关的特性)。
      • Android的Java类库,大部分来自于Apache Hamony,开源的Java API实现,如java.lang,java.util,java.net,但去除了AWT,Swing等部件
      • JNI: C和Java互调的接口
      • Libc: Android也有很多C代码,自然少不了libc,注意的是,Android的libc叫bionic C.
  • 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
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
// Line 1175

/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
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");
// Whether this is the primary zygote, meaning the zygote which will fork system server.
bool primary_zygote = false;

/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
primary_zygote = true;
/* 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)));
}
}

const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /system does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}

const char* artRootDir = getenv("ANDROID_ART_ROOT");
if (artRootDir == NULL) {
LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
return;
}

const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
if (i18nRootDir == NULL) {
LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
return;
}

const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
if (tzdataRootDir == NULL) {
LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
return;
}

//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_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);

#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");
}

  • Java虚拟机的启动大致做了如下事情
  1. 从property读取一系列启动参数

  2. 创建和初始化结构体全局对象(每个进程)gDVM,及对应与JavaVM和JNIEnv的内部结构体JavaVMExt,JNIEnvExt

  3. 初始化java虚拟机,并创建虚拟机线程

  4. 注册系统的JNI,Java程序通过这些JNI接口来访问底层的资源。

    • loadJniLibrary(“javacode”); loadJniLibrary(“nativehelper”);
  5. 为Zygote的启动做最后的准备,包括设置SID/UID,以及mount 文件系统

  6. 返回JavaVM给Native代码,这样它就可以向上访问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
//line 634

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
JavaVMInitArgs initArgs;
char propBuf[PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];

//more....

/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
//startVM的前半部分是在处理虚拟机的启动参数,处理完配置参数后,会调用libart.so提供的一个接口JNI_CreateJavaVM函数
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}

return 0;
}
  • art/runtime/jni/java_vm_ext.cc
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
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
ScopedTrace trace(__FUNCTION__);
const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
if (JavaVMExt::IsBadJniVersion(args->version)) {
LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
return JNI_EVERSION;
}
RuntimeOptions options;
for (int i = 0; i < args->nOptions; ++i) {
JavaVMOption* option = &args->options[i];
options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
}
bool ignore_unrecognized = args->ignoreUnrecognized;
//通过Runtime的create方法创建单例的Runtime对象
if (!Runtime::Create(options, ignore_unrecognized)) {
return JNI_ERR;
}

// When `ART_CRASH_RUNTIME_DELIBERATELY` is defined (which happens only in the
// case of a test APEX), we crash the runtime here on purpose, to test the
// behavior of rollbacks following a failed ART Mainline Module update.
#ifdef ART_CRASH_RUNTIME_DELIBERATELY
LOG(FATAL) << "Runtime crashing deliberately for testing purposes.";
#endif

// Initialize native loader. This step makes sure we have
// everything set up before we start using JNI.
android::InitializeNativeLoader();

Runtime* runtime = Runtime::Current();
bool started = runtime->Start();
if (!started) {
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
LOG(WARNING) << "CreateJavaVM failed";
return JNI_ERR;
}

*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();
return JNI_OK;
}

  首先通过Runtime的create方法创建单例的Runtime对象,runtime负责提供art虚拟机的运行时环境,然后调用其init方法来初始化虚拟机

  • art/runtime/runtime.cc
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
//more ....
//创建堆管理对象
heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
runtime_options.GetOrDefault(Opt::HeapMinFree),
runtime_options.GetOrDefault(Opt::HeapMaxFree),
runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
foreground_heap_growth_multiplier,
runtime_options.GetOrDefault(Opt::StopForNativeAllocs),
runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
GetBootClassPath(),
GetBootClassPathLocations(),
GetBootClassPathFds(),
GetBootClassPathImageFds(),
GetBootClassPathVdexFds(),
GetBootClassPathOatFds(),
image_locations_,
instruction_set_,
// Override the collector type to CC if the read barrier config.
gUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,
background_gc,
runtime_options.GetOrDefault(Opt::LargeObjectSpace),
runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
runtime_options.GetOrDefault(Opt::ParallelGCThreads),
runtime_options.GetOrDefault(Opt::ConcGCThreads),
runtime_options.Exists(Opt::LowMemoryMode),
runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),
runtime_options.GetOrDefault(Opt::LongGCLogThreshold),
runtime_options.Exists(Opt::IgnoreMaxFootprint),
runtime_options.GetOrDefault(Opt::AlwaysLogExplicitGcs),
runtime_options.GetOrDefault(Opt::UseTLAB),
xgc_option.verify_pre_gc_heap_,
xgc_option.verify_pre_sweeping_heap_,
xgc_option.verify_post_gc_heap_,
xgc_option.verify_pre_gc_rosalloc_,
xgc_option.verify_pre_sweeping_rosalloc_,
xgc_option.verify_post_gc_rosalloc_,
xgc_option.gcstress_,
xgc_option.measure_,
runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
use_generational_cc,
runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs),
runtime_options.Exists(Opt::DumpRegionInfoBeforeGC),
runtime_options.Exists(Opt::DumpRegionInfoAfterGC));

//more ....

//创建java虚拟机对象
java_vm_ = JavaVMExt::Create(this, runtime_options, &error_msg);
if (java_vm_.get() == nullptr) {
LOG(ERROR) << "Could not initialize JavaVMExt: " << error_msg;
return false;
}

// Add the JniEnv handler.
// TODO Refactor this stuff.
java_vm_->AddEnvironmentHook(JNIEnvExt::GetEnvHandler);

Thread::Startup();

// ClassLinker needs an attached thread, but we can't fully attach a thread without creating
// objects. We can't supply a thread group yet; it will be fixed later. Since we are the main
// thread, we do not get a java peer.

//连接主线程
Thread* self = Thread::Attach("main", false, nullptr, false, /* should_run_callbacks= */ true);
CHECK_EQ(self->GetThreadId(), ThreadList::kMainThreadId);
CHECK(self != nullptr);

self->SetIsRuntimeThread(IsAotCompiler());

// Set us to runnable so tools using a runtime can allocate and GC by default
self->TransitionFromSuspendedToRunnable();

// Now we're attached, we can take the heap locks and validate the heap.
GetHeap()->EnableObjectValidation();

CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);

//创建类连接器
if (UNLIKELY(IsAotCompiler())) {
class_linker_ = new AotClassLinker(intern_table_);
} else {
class_linker_ = new ClassLinker(
intern_table_,
runtime_options.GetOrDefault(Opt::FastClassNotFoundException));
}
if (GetHeap()->HasBootImageSpace()) {
//初始化类连接器
bool result = class_linker_->InitFromBootImage(&error_msg);
if (!result) {
LOG(ERROR) << "Could not initialize from image: " << error_msg;
return false;
}
if (kIsDebugBuild) {
for (auto image_space : GetHeap()->GetBootImageSpaces()) {
image_space->VerifyImageAllocations();
}
}
{
ScopedTrace trace2("AddImageStringsToTable");
for (gc::space::ImageSpace* image_space : heap_->GetBootImageSpaces()) {
GetInternTable()->AddImageStringsToTable(image_space, VoidFunctor());
}
}

const size_t total_components = gc::space::ImageSpace::GetNumberOfComponents(
ArrayRef<gc::space::ImageSpace* const>(heap_->GetBootImageSpaces()));
if (total_components != GetBootClassPath().size()) {
// The boot image did not contain all boot class path components. Load the rest.
CHECK_LT(total_components, GetBootClassPath().size());
size_t start = total_components;
DCHECK_LT(start, GetBootClassPath().size());
std::vector<std::unique_ptr<const DexFile>> extra_boot_class_path;
if (runtime_options.Exists(Opt::BootClassPathDexList)) {
extra_boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList));
} else {
ArrayRef<const int> bcp_fds = start < GetBootClassPathFds().size()
? ArrayRef<const int>(GetBootClassPathFds()).SubArray(start)
: ArrayRef<const int>();
OpenBootDexFiles(ArrayRef<const std::string>(GetBootClassPath()).SubArray(start),
ArrayRef<const std::string>(GetBootClassPathLocations()).SubArray(start),
bcp_fds,
&extra_boot_class_path);
}
class_linker_->AddExtraBootDexFiles(self, std::move(extra_boot_class_path));
}
if (IsJavaDebuggable() || jit_options_->GetProfileSaverOptions().GetProfileBootClassPath()) {
// Deoptimize the boot image if debuggable as the code may have been compiled non-debuggable.
// Also deoptimize if we are profiling the boot class path.
ScopedThreadSuspension sts(self, ThreadState::kNative);
ScopedSuspendAll ssa(__FUNCTION__);
DeoptimizeBootImage();
}
} else {
std::vector<std::unique_ptr<const DexFile>> boot_class_path;
if (runtime_options.Exists(Opt::BootClassPathDexList)) {
boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList));
} else {
OpenBootDexFiles(ArrayRef<const std::string>(GetBootClassPath()),
ArrayRef<const std::string>(GetBootClassPathLocations()),
ArrayRef<const int>(GetBootClassPathFds()),
&boot_class_path);
}
if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {
LOG(ERROR) << "Could not initialize without image: " << error_msg;
return false;
}

// TODO: Should we move the following to InitWithoutImage?
SetInstructionSet(instruction_set_);
for (uint32_t i = 0; i < kCalleeSaveSize; i++) {
CalleeSaveType type = CalleeSaveType(i);
if (!HasCalleeSaveMethod(type)) {
SetCalleeSaveMethod(CreateCalleeSaveMethod(), type);
}
}
}

// Now that the boot image space is set, cache the boot classpath checksums,
// to be used when validating oat files.
ArrayRef<gc::space::ImageSpace* const> image_spaces(GetHeap()->GetBootImageSpaces());
ArrayRef<const DexFile* const> bcp_dex_files(GetClassLinker()->GetBootClassPath());
boot_class_path_checksums_ = gc::space::ImageSpace::GetBootClassPathChecksums(image_spaces,
bcp_dex_files);

CHECK(class_linker_ != nullptr);

verifier::ClassVerifier::Init(class_linker_);

if (runtime_options.Exists(Opt::MethodTrace)) {
trace_config_.reset(new TraceConfig());
trace_config_->trace_file = runtime_options.ReleaseOrDefault(Opt::MethodTraceFile);
trace_config_->trace_file_size = runtime_options.ReleaseOrDefault(Opt::MethodTraceFileSize);
trace_config_->trace_mode = Trace::TraceMode::kMethodTracing;
trace_config_->trace_output_mode = runtime_options.Exists(Opt::MethodTraceStreaming) ?
Trace::TraceOutputMode::kStreaming :
Trace::TraceOutputMode::kFile;
trace_config_->clock_source = runtime_options.GetOrDefault(Opt::MethodTraceClock);
}

// TODO: Remove this in a follow up CL. This isn't used anywhere.
Trace::SetDefaultClockSource(runtime_options.GetOrDefault(Opt::ProfileClock));

if (GetHeap()->HasBootImageSpace()) {
const ImageHeader& image_header = GetHeap()->GetBootImageSpaces()[0]->GetImageHeader();
ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects =
ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(
image_header.GetImageRoot(ImageHeader::kBootImageLiveObjects));
pre_allocated_OutOfMemoryError_when_throwing_exception_ = GcRoot<mirror::Throwable>(
boot_image_live_objects->Get(ImageHeader::kOomeWhenThrowingException)->AsThrowable());
DCHECK(pre_allocated_OutOfMemoryError_when_throwing_exception_.Read()->GetClass()
->DescriptorEquals("Ljava/lang/OutOfMemoryError;"));
pre_allocated_OutOfMemoryError_when_throwing_oome_ = GcRoot<mirror::Throwable>(
boot_image_live_objects->Get(ImageHeader::kOomeWhenThrowingOome)->AsThrowable());
DCHECK(pre_allocated_OutOfMemoryError_when_throwing_oome_.Read()->GetClass()
->DescriptorEquals("Ljava/lang/OutOfMemoryError;"));
pre_allocated_OutOfMemoryError_when_handling_stack_overflow_ = GcRoot<mirror::Throwable>(
boot_image_live_objects->Get(ImageHeader::kOomeWhenHandlingStackOverflow)->AsThrowable());
DCHECK(pre_allocated_OutOfMemoryError_when_handling_stack_overflow_.Read()->GetClass()
->DescriptorEquals("Ljava/lang/OutOfMemoryError;"));
pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(
boot_image_live_objects->Get(ImageHeader::kNoClassDefFoundError)->AsThrowable());
DCHECK(pre_allocated_NoClassDefFoundError_.Read()->GetClass()
->DescriptorEquals("Ljava/lang/NoClassDefFoundError;"));
} else {
// Pre-allocate an OutOfMemoryError for the case when we fail to
// allocate the exception to be thrown.
CreatePreAllocatedException(self,
this,
&pre_allocated_OutOfMemoryError_when_throwing_exception_,
"Ljava/lang/OutOfMemoryError;",
"OutOfMemoryError thrown while trying to throw an exception; "
"no stack trace available");
// Pre-allocate an OutOfMemoryError for the double-OOME case.
CreatePreAllocatedException(self,
this,
&pre_allocated_OutOfMemoryError_when_throwing_oome_,
"Ljava/lang/OutOfMemoryError;",
"OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
"no stack trace available");
// Pre-allocate an OutOfMemoryError for the case when we fail to
// allocate while handling a stack overflow.
CreatePreAllocatedException(self,
this,
&pre_allocated_OutOfMemoryError_when_handling_stack_overflow_,
"Ljava/lang/OutOfMemoryError;",
"OutOfMemoryError thrown while trying to handle a stack overflow; "
"no stack trace available");

// Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
// ahead of checking the application's class loader.
CreatePreAllocatedException(self,
this,
&pre_allocated_NoClassDefFoundError_,
"Ljava/lang/NoClassDefFoundError;",
"Class not found using the boot class loader; "
"no stack trace available");
}

// Class-roots are setup, we can now finish initializing the JniIdManager.
GetJniIdManager()->Init(self);

InitMetrics();

// Runtime initialization is largely done now.
// We load plugins first since that can modify the runtime state slightly.
// Load all plugins
{
// The init method of plugins expect the state of the thread to be non runnable.
ScopedThreadSuspension sts(self, ThreadState::kNative);
for (auto& plugin : plugins_) {
std::string err;
if (!plugin.Load(&err)) {
LOG(FATAL) << plugin << " failed to load: " << err;
}
}
}

  1. new gc::Heap(),创建Heap对象,这是虚拟机管理对内存的起点
  2. new JavaVmExt(),创建Java虚拟机实例
  3. Thread::attach(),attach主线程
  4. 创建ClassLinker
  5. 初始化Classlinker,成功attach到runtime环境后,创建ClassLinker实例负责管理java class
  • art/runtime/thread.cc
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
//line 1009
template <typename PeerAction>
Thread* Thread::Attach(const char* thread_name,
bool as_daemon,
PeerAction peer_action,
bool should_run_callbacks) {
Runtime* runtime = Runtime::Current();
ScopedTrace trace("Thread::Attach");
if (runtime == nullptr) {
LOG(ERROR) << "Thread attaching to non-existent runtime: " <<
((thread_name != nullptr) ? thread_name : "(Unnamed)");
return nullptr;
}
Thread* self;
{
ScopedTrace trace2("Thread birth");
MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
if (runtime->IsShuttingDownLocked()) {
LOG(WARNING) << "Thread attaching while runtime is shutting down: " <<
((thread_name != nullptr) ? thread_name : "(Unnamed)");
return nullptr;
} else {
Runtime::Current()->StartThreadBirth();
self = new Thread(as_daemon);
bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
Runtime::Current()->EndThreadBirth();
if (!init_success) {
delete self;
return nullptr;
}
}
}

self->InitStringEntryPoints();

CHECK_NE(self->GetState(), ThreadState::kRunnable);
self->SetState(ThreadState::kNative);

// Run the action that is acting on the peer.
if (!peer_action(self)) {
runtime->GetThreadList()->Unregister(self, should_run_callbacks);
// Unregister deletes self, no need to do this here.
return nullptr;
}

if (VLOG_IS_ON(threads)) {
if (thread_name != nullptr) {
VLOG(threads) << "Attaching thread " << thread_name;
} else {
VLOG(threads) << "Attaching unnamed thread.";
}
ScopedObjectAccess soa(self);
self->Dump(LOG_STREAM(INFO));
}

if (should_run_callbacks) {
ScopedObjectAccess soa(self);
runtime->GetRuntimeCallbacks()->ThreadStart(self);
}

return self;
}

 除了系统的JNI接口(“javacore”,”nativehelper”),android framework还有大量的Native实现,Android将所有这些接口一次性通过startReg()来完成

  • 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
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

ALOGV("--- registering native functions ---\n");

/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven't really
* started the VM yet, they're all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
env->PushLocalFrame(200);

if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);

//createJavaThread("fubar", quickTest, (void*) "hello");

return 0;
}

  • system/core/libutils/Threads.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
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
//line 658
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
LOG_ALWAYS_FATAL_IF(name == nullptr, "thread name not provided to Thread::run");

Mutex::Autolock _l(mLock);

if (mRunning) {
// thread already started
return INVALID_OPERATION;
}

// reset status and exitPending to their default value, so we can
// try again after an error happened (either below, or in readyToRun())
mStatus = OK;
mExitPending = false;
mThread = thread_id_t(-1);

// hold a strong reference on ourself
mHoldSelf = sp<Thread>::fromExisting(this);

mRunning = true;

bool res;

//android native层有两种Thread的创建方式
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}

if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-1);
mHoldSelf.clear(); // "this" may have gone away after this.

return UNKNOWN_ERROR;
}

// Do not refer to mStatus here: The thread is already running (may, in fact
// already have exited with a valid mStatus result). The OK indication
// here merely indicates successfully starting the thread and does not
// imply successful termination/execution.
return OK;

// Exiting scope of mLock is a memory barrier and allows new thread to run
}


//line 117

int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
void *userData,
const char* threadName __android_unused,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

#if defined(__ANDROID__) /* valgrind is rejecting RT-priority create reqs */
if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
// Now that the pthread_t has a method to find the associated
// android_thread_id_t (pid) from pthread_t, it would be possible to avoid
// this trampoline in some cases as the parent could set the properties
// for the child. However, there would be a race condition because the
// child becomes ready immediately, and it doesn't work for the name.
// prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was
// proposed but not yet accepted.
thread_data_t* t = new thread_data_t;
t->priority = threadPriority;
t->threadName = threadName ? strdup(threadName) : NULL;
t->entryFunction = entryFunction;
t->userData = userData;
entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
userData = t;
}
#endif

if (threadStackSize) {
pthread_attr_setstacksize(&attr, threadStackSize);
}

errno = 0;
pthread_t thread;
int resulcreateJavaThreadt = pthread_create(&thread, &attr,
(android_pthread_entry)entryFunction, userData);
pthread_attr_destroy(&attr);
if (result != 0) {
ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, %s)\n"
"(android threadPriority=%d)",
entryFunction, result, strerror(errno), threadPriority);
return 0;
}

// Note that *threadID is directly available to the parent only, as it is
// assigned after the child starts. Use memory barrier / lock if the child
// or other threads also need access.
if (threadId != nullptr) {
*threadId = (android_thread_id_t)thread; // XXX: this is not portable
}
return 1;
}


  android native层有两种Thread的创建方式,它们的区别在是是否能够调用Java端函数,createThreadEtc做了封装。在Android 10上面,这两种方法做了区别,Android 14上面最终都调用了androidCreateRawThreadEtc函数。另外一种方式是javaCreateThreadEtc函数。接着来到java层。

  • frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@UnsupportedAppUsage
public static final void main(String[] argv) {
preForkInit();
if (argv.length == 2 && argv[1].equals("application")) {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
//将System.out和System.err输出重定向到Android的Log系统(定义在android.util.Log)
redirectLogStreams();
} else {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
}
//commonInit():初始化了一下系统属性,其中最重要的一点就是设置了一个未捕捉异常的handler,当代码有任何未知异常,就会执行它。
commonInit();

/*
* Now that we're running in interpreted code, call back into native code
* to run the system.
*/
nativeFinishInit();

if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}

  • 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
//  Line 255 nativeFinishInit

/*
* Code written in the Java Programming Language calls here from main().
*/
static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onStarted();
}

//line 271

/*
* JNI registration.
*/

int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{"nativeFinishInit", "()V",
(void*)com_android_internal_os_RuntimeInit_nativeFinishInit},
{"nativeSetExitWithoutCleanup", "(Z)V",
(void*)com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup},
};
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
methods, NELEM(methods));
}
  • frameworks/base/cmds/app_process/app_main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
//line 79 --->  gCurRuntime->onStarted();
virtual void onStarted()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();

AndroidRuntime* ar = AndroidRuntime::getRuntime();
ar->callMain(mClassName, mClass, mArgs);

IPCThreadState::self()->stopProcess();
hardware::IPCThreadState::self()->stopProcess();
}
  • ZygoteInit

  • frameworks/base/core/java/com/android/internal/os/ZygoteInit.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
/**
* This is the entry point for a Zygote process. It creates the Zygote server, loads resources,
* and handles other tasks related to preparing the process for forking into applications.
*
* This process is started with a nice value of -20 (highest priority). All paths that flow
* into new processes are required to either set the priority to the default value or terminate
* before executing any non-system code. The native side of this occurs in SpecializeCommon,
* while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
* ZygoteConnection.handleChildProc, and Zygote.childMain.
*
* @param argv Command line arguments used to specify the Zygote's configuration.
*/
@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;
try {
// Store now for StatsLogging later.
final long startTime = SystemClock.elapsedRealtime();
final boolean isRuntimeRestarted = "1".equals(
SystemProperties.get("sys.boot_completed"));

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

boolean startSystemServer = false;
String zygoteSocketName = "zygote";//Dalvik VM进程系统
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
//这里是app_main.cpp中传递的start-system-server参数
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)) {
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}

final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
if (!isRuntimeRestarted) {
if (isPrimaryZygote) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
startTime);
} else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
startTime);
}
}

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

// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
// 在有些情况下我们需要在第一个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
}

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

bootTimingsTraceLog.traceEnd(); // ZygoteInit

Zygote.initNativeState(isPrimaryZygote);

ZygoteHooks.stopZygoteNoThreadCreation();

zygoteServer = new ZygoteServer(isPrimaryZygote);//创建Zygote服务器端

if (startSystemServer) {
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;
}
}

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 fatal exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
zygoteServer.closeServerSocket();
}
}

// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}


// line 137

static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
beginPreload();
bootTimingsTraceLog.traceEnd(); // BeginPreload
bootTimingsTraceLog.traceBegin("PreloadClasses");
//加载指定的类到内存并且初始化,使用的Class.forName(class,ture,null)的方式
preloadClasses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
cacheNonBootClasspathClassLoaders();
bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
bootTimingsTraceLog.traceBegin("PreloadResources");
//加载Android 通用的资源,比如drawable
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
nativePreloadAppProcessHALs();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
maybePreloadGraphicsDriver();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
preloadSharedLibraries();
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
endPreload();
warmUpJcaProviders();
Log.d(TAG, "end preload");

sPreloadComplete = true;
}

  preloadClasses将freamwrok.jar里的preloaded-classed定义的所有class load到内存里,preloaded-classes编译Android后可以在framework/base下找到。而preloadResource将系统的Resourrce(不是用户apk里定义的resource)load到内存。资源preload到Zygote的进程地址空间,所有fork的子进程将共享这份空间而无需重新load,这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload类和资源数目的进行调整,可以加快系统启动。Preload也是android启动最耗时的部分之一。

  • libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//line 120

/**
* Runs several special GCs to try to clean up a few generations of
* softly- and final-reachable objects, along with any other garbage.
* This is only useful just before a fork().
*
* @hide
*/
@SystemApi(client = MODULE_LIBRARIES)
public static void gcAndFinalize() {
final VMRuntime runtime = VMRuntime.getRuntime();

/* runFinalizationSync() lets finalizers be called in Zygote,
* which doesn't have a HeapWorker thread.
*/
System.gc();
runtime.runFinalizationSync();
cleanLocaleCaches();
System.gc();
}

  gc()调用只是通知VM进行垃圾回收,是否回收,什么时候回收全由VM内部算法决定。GC的回收有一个复杂的状态机控制,通过多次调用,可以使得尽可能多的资源得到回收。gc()必须在fork之前完成(接下来的StatSystemServer就会有fork操作),这样将来被复制出来的子进程才能有尽可能少的垃圾内存没有释放。

  • frameworks/base/core/java/com/android/internal/os/ZygoteInit.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
/**
* 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 &= Integer.toUnsignedLong(data[0].effective) |
(Integer.toUnsignedLong(data[1].effective) << 32);

/* Hardcoded command line to start the system server */
//启动SystemServer的命令行,部分参数写死
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,3005,3006,3007,3009,3010,3011,3012",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
ZygoteArguments parsedArgs;

int pid;

try {
ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
try {
parsedArgs = ZygoteArguments.getInstance(commandBuffer);
} catch (EOFException e) {
throw new AssertionError("Unexpected argument error for forking system server", e);
}
commandBuffer.close();
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);//会设置InvokeWith参数,这个参数在接下来的初始化逻辑中会有调用

if (Zygote.nativeSupportsMemoryTagging()) {
String mode = SystemProperties.get("persist.arm64.memtag.system_server", "");
if (mode.isEmpty()) {
/* The system server has ASYNC MTE by default, in order to allow
* system services to specify their own MTE level later, as you
* can't re-enable MTE once it's disabled. */
mode = SystemProperties.get("persist.arm64.memtag.default", "async");
}
if (mode.equals("async")) {
parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
} else if (mode.equals("sync")) {
parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
} else if (!mode.equals("off")) {
/* When we have an invalid memory tag level, keep the current level. */
parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
}
} else if (Zygote.nativeSupportsTaggedPointers()) {
/* Enable pointer tagging in the system server. Hardware support for this is present
* in all ARMv8 CPUs. */
parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
}

/* Enable gwp-asan on the system server with a small probability. This is the same
* policy as applied to native processes and system apps. */
parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;

if (shouldProfileSystemServer()) {
parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}

/* Request to fork the system server process */

/* 创建System server 进程 */
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}

/* For child process */
if (pid == 0) {//如果是第一次创建的话 pid == 0
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}

zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}

return null;
}

  ZygoteInit.forkSystemServer()方法fork出SystemServer进程。fork出来的子进程在handleSystemServerProcess里开始初始化工作,主要工作分为:

  1. prepareSystemServerProfile()方法中将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM中
  2. 判断fork args中是否有invokWith参数,如果有则进行WrapperInit.execApplication
  • frameworks/base/core/java/com/android/internal/os/ZygoteInit.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

//Line 524

/**
* 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) {
Process.setArgV0(parsedArgs.mNiceName);
}

final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
// Capturing profiles is only supported for debug or eng builds since selinux normally
// prevents it.
if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
try {
Log.d(TAG, "Preparing system server profile");
final String standaloneSystemServerJars =
Os.getenv("STANDALONE_SYSTEMSERVER_JARS");
final String systemServerPaths = standaloneSystemServerJars != null
? String.join(":", systemServerClasspath, standaloneSystemServerJars)
: systemServerClasspath;
//将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM中
prepareSystemServerProfile(systemServerPaths);
} 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.

//判断fork args中是否有invokWith参数,如果有则进行WrapperInit.execApplication
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 {
ClassLoader cl = getOrCreateSystemServerClassLoader();
if (cl != null) {
Thread.currentThread().setContextClassLoader(cl);
}

/*
* Pass the remaining arguments to SystemServer.
*/
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, cl);
}

/* should never reach here */
}
  • frameworks/base/core/java/com/android/internal/os/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
//line296

/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;

try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}

Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}

int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}

/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
return new MethodAndArgsCaller(m, argv);
}


/**
* 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);
}
}
}

  很明显这是一个耗时操作所以使用线程来完成

System Servver启动流程

  System Server是Zygote fork的第一个Java进程,这个进程非常重要,因为他们有很多的系统线程,提供所有和信心的系统服务,比如WindowManager,ActivityManager,它们都是运行在system_server的进程中。还有很多“Binder-x”的线程,它们是各个Service为了响应应用程序远程调用请求而创建的。除此之外,还有很多内部线程,比如”UI thread”, “InputReader”,”InputDispatch”等等。现在着重看System Server是如何创建起来的。

  分成4部分详细分析SystemServer().run()方法的初始化流程,初始化必要的SystemServer环境参数,比如系统时间、默认时区、语言、Load一些Library等等,初始化Looper,我们在主线程中使用到的looper就是在SystemServer中进行初始化的,初始化Context,只有初始化一个Context才能进行启动Service等操作。

  • 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
    /**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}

//line 1044

private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);

final Context systemUiContext = activityThread.getSystemUiContext();
systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}

  继续看ActivityThread中如何生成Context:

  • frameworks/base/core/java/android/app/ActivityThread.java
1
2
3
4
5
6
7
8
9
10
@Override
@UnsupportedAppUsage
public ContextImpl getSystemContext() {
synchronized (this) {
if (mSystemContext == null) {
mSystemContext = ContextImpl.createSystemContext(this);
}
return mSystemContext;
}
}

  ContextImpl是Cotext类的具体实现,里面封装完成生成几种常用的createContext的方法:

  • frameworks/base/core/java/android/app/ContextImpl.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

    @UnsupportedAppUsage
    static ContextImpl createSystemContext(ActivityThread mainThread) {
    LoadedApk packageInfo = new LoadedApk(mainThread);
    ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
    ContextParams.EMPTY, null, null, null, null, null, 0, null, null);
    context.setResources(packageInfo.getResources());
    context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
    context.mResourcesManager.getDisplayMetrics());
    context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
    return context;
    }


    /**
    * System Context to be used for UI. This Context has resources that can be themed.
    * Make sure that the created system UI context shares the same LoadedApk as the system context.
    * @param systemContext The system context which created by
    * {@link #createSystemContext(ActivityThread)}.
    * @param displayId The ID of the display where the UI is shown.
    */
    static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) {
    final WindowTokenClient token = new WindowTokenClient();
    final ContextImpl context = systemContext.createWindowContextBase(token, displayId);
    token.attachContext(context);
    token.attachToDisplayContent(displayId);
    context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
    context.mOwnsToken = true;

    return context;
    }

    @UnsupportedAppUsage
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
    return createAppContext(mainThread, packageInfo, null);
    }

    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
    String opPackageName) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
    ContextParams.EMPTY, null, null, null, null, null, 0, null, opPackageName);
    context.setResources(packageInfo.getResources());
    context.mContextType = isSystemOrSystemUI(context) ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
    : CONTEXT_TYPE_NON_UI;
    return context;
    }

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    static ContextImpl createActivityContext(ActivityThread mainThread,
    LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
    Configuration overrideConfiguration) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");

    String[] splitDirs = packageInfo.getSplitResDirs();
    ClassLoader classLoader = packageInfo.getClassLoader();

    if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
    Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
    try {
    classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
    splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
    } catch (NameNotFoundException e) {
    // Nothing above us can handle a NameNotFoundException, better crash.
    throw new RuntimeException(e);
    } finally {
    Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
    }
    }

    final String attributionTag;
    if (activityInfo.attributionTags != null && activityInfo.attributionTags.length > 0) {
    attributionTag = activityInfo.attributionTags[0];
    } else {
    attributionTag = null;
    }

    ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
    attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader,
    null);
    context.mContextType = CONTEXT_TYPE_ACTIVITY;
    context.mIsConfigurationBasedContext = true;

    // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
    displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;

    final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
    ? packageInfo.getCompatibilityInfo()
    : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;

    final ResourcesManager resourcesManager = ResourcesManager.getInstance();

    // Create the base resources for which all configuration contexts for this Activity
    // will be rebased upon.
    context.setResources(resourcesManager.createBaseTokenResources(activityToken,
    packageInfo.getResDir(),
    splitDirs,
    packageInfo.getOverlayDirs(),
    packageInfo.getOverlayPaths(),
    packageInfo.getApplicationInfo().sharedLibraryFiles,
    displayId,
    overrideConfiguration,
    compatInfo,
    classLoader,
    packageInfo.getApplication() == null ? null
    : packageInfo.getApplication().getResources().getLoaders()));
    context.setDisplay(resourcesManager.getAdjustedDisplay(
    displayId, context.getResources()));
    return context;
    }

  初始化SystemServiceManager,用来管理启动service,SystemServiceManager中封装了启动Service的startService方法启动系统必要的Service,启动service的流程分为三步:

  • 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
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
private void run() {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
try {
t.traceBegin("InitBeforeStartServices");

// Record the process start information in sys props.
SystemProperties.set(SYSPROP_START_COUNT, String.valueOf(mStartCount));
SystemProperties.set(SYSPROP_START_ELAPSED, String.valueOf(mRuntimeStartElapsedTime));
SystemProperties.set(SYSPROP_START_UPTIME, String.valueOf(mRuntimeStartUptime));

EventLog.writeEvent(EventLogTags.SYSTEM_SERVER_START,
mStartCount, mRuntimeStartUptime, mRuntimeStartElapsedTime);

// Set the device's time zone (a system property) if it is not set or is invalid.
SystemTimeZone.initializeTimeZoneSettingsIfRequired();

// If the system has "persist.sys.language" and friends set, replace them with
// "persist.sys.locale". Note that the default locale at this point is calculated
// using the "-Duser.locale" command line flag. That flag is usually populated by
// AndroidRuntime using the same set of system properties, but only the system_server
// and system apps are allowed to set them.
//
// NOTE: Most changes made here will need an equivalent change to
// core/jni/AndroidRuntime.cpp
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();

SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}

// The system server should never make non-oneway calls
Binder.setWarnOnBlocking(true);
// The system server should always load safe labels
PackageItemInfo.forceSafeLabels();

// Default to FULL within the system server.
SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;

// Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
SQLiteCompatibilityWalFlags.init(null);

// Here we go!
Slog.i(TAG, "Entered the Android system server!");
final long uptimeMillis = SystemClock.elapsedRealtime();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
if (!mRuntimeRestart) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
FrameworkStatsLog
.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_INIT_START,
uptimeMillis);
}

// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
// property so that it is in sync. We can't do this in
// libnativehelper's JniInvocation::Init code where we already
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
// the property. http://b/11463182
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

// Mmmmmm... more memory!
VMRuntime.getRuntime().clearGrowthLimit();

// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();

// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);

// Within the system server, any incoming Bundles should be defused
// to avoid throwing BadParcelableException.
BaseBundle.setShouldDefuse(true);

// Within the system server, when parceling exceptions, include the stack trace
Parcel.setStackTraceParceling(true);

// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);

// Increase the number of binder threads in system_server
BinderInternal.setMaxThreads(sMaxBinderThreads);

// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
Looper.getMainLooper().setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

SystemServiceRegistry.sEnableServiceNotFoundWtf = true;

// Initialize native services.
System.loadLibrary("android_servers");

// Allow heap / perf profiling.
initZygoteChildHeapProfiling();

// Debug builds - spawn a thread to monitor for fd leaks.
if (Build.IS_DEBUGGABLE) {
spawnFdLeakCheckThread();
}

// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();

// Initialize the system context.
createSystemContext();

// Call per-process mainline module initialization.
ActivityThread.initializeMainlineModules();

// Sets the dumper service
ServiceManager.addService("system_server_dumper", mDumper);
mDumper.addDumpable(this);

// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
mDumper.addDumpable(mSystemServiceManager);

LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
SystemServerInitThreadPool tp = SystemServerInitThreadPool.start();
mDumper.addDumpable(tp);

// Load preinstalled system fonts for system server, so that WindowManagerService, etc
// can start using Typeface. Note that fonts are required not only for text rendering,
// but also for some text operations (e.g. TextUtils.makeSafeForPresentation()).
if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
Typeface.loadPreinstalledSystemFontMap();
}

// Attach JVMTI agent if this is a debuggable build and the system property is set.
if (Build.IS_DEBUGGABLE) {
// Property is of the form "library_path=parameters".
String jvmtiAgent = SystemProperties.get("persist.sys.dalvik.jvmtiagent");
if (!jvmtiAgent.isEmpty()) {
int equalIndex = jvmtiAgent.indexOf('=');
String libraryPath = jvmtiAgent.substring(0, equalIndex);
String parameterList =
jvmtiAgent.substring(equalIndex + 1, jvmtiAgent.length());
// Attach the agent.
try {
Debug.attachJvmtiAgent(libraryPath, parameterList, null);
} catch (Exception e) {
Slog.e("System", "*************************************************");
Slog.e("System", "********** Failed to load jvmti plugin: " + jvmtiAgent);
}
}
}
} finally {
t.traceEnd(); // InitBeforeStartServices
}

// Setup the default WTF handler
RuntimeInit.setDefaultApplicationWtfHandler(SystemServer::handleEarlySystemWtf);

// Start services.
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
startApexServices(t);
// Only update the timeout after starting all the services so that we use
// the default timeout to start system server.
updateWatchdogTimeout(t);
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}

StrictMode.initVmDefaults(null);

if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
final long uptimeMillis = SystemClock.elapsedRealtime();
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_READY,
uptimeMillis);
final long maxUptimeMillis = 60 * 1000;
if (uptimeMillis > maxUptimeMillis) {
Slog.wtf(SYSTEM_SERVER_TIMING_TAG,
"SystemServer init took too long. uptimeMillis=" + uptimeMillis);
}
}

// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}

  启动BootstrapServices,就是系统必须需要的服务,这些服务直接耦合性很高,所以干脆就放在一个方法里面一起启动,比如PowerManagerService、RecoverySystemService、DisplayManagerService、UsageStatsService、WebViewUpdateService启动其他需要用到的Service,比如NetworkScoreService、AlarmManagerService。

  Zygote还有善后工作,一旦发现System Server挂掉了,将其回收,然后将自己杀掉,重新开始新的一生。

  • frameworks/base/core/java/com/android/internal/os/Zygote.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
/**
* Special method to start the system server process. In addition to the
* common actions performed in forkAndSpecialize, the pid of the child
* process is recorded such that the death of the child process will cause
* zygote to exit.
*
* @param uid the UNIX uid that the new process should setuid() to after
* fork()ing and and before spawning any threads.
* @param gid the UNIX gid that the new process should setgid() to after
* fork()ing and and before spawning any threads.
* @param gids null-ok; a list of UNIX gids that the new process should
* setgroups() to after fork and before spawning any threads.
* @param runtimeFlags bit flags that enable ART features.
* @param rlimits null-ok an array of rlimit tuples, with the second
* dimension having a length of 3 and representing
* (resource, rlim_cur, rlim_max). These are set via the posix
* setrlimit(2) call.
* @param permittedCapabilities argument for setcap()
* @param effectiveCapabilities argument for setcap()
*
* @return 0 if this is the child, pid of the child
* if this is the parent, or -1 on error.
*/
static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();

int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);

// Set the Java Language thread priority to the default value for new apps.
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);

ZygoteHooks.postForkCommon();
return pid;
}

private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);

  • frameworks/base/core/jni/com_android_internal_os_Zygote.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
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

//line 2405

NO_STACK_PROTECTOR
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
jlong effective_capabilities) {
std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
fds_to_ignore(fds_to_close);

fds_to_close.push_back(gUsapPoolSocketFD);

if (gUsapPoolEventFD != -1) {
fds_to_close.push_back(gUsapPoolEventFD);
fds_to_ignore.push_back(gUsapPoolEventFD);
}

if (gSystemServerSocketFd != -1) {
fds_to_close.push_back(gSystemServerSocketFd);
fds_to_ignore.push_back(gSystemServerSocketFd);
}

pid_t pid = zygote::ForkCommon(env, true,
fds_to_close,
fds_to_ignore,
true);
if (pid == 0) {
// System server prcoess does not need data isolation so no need to
// know pkg_data_info_list.
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
false, nullptr, nullptr, /* is_top_app= */ false,
/* pkg_data_info_list */ nullptr,
/* allowlisted_data_info_list */ nullptr, false, false);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
gSystemServerPid = pid;
// There is a slight window that the system server process has crashed
// but it went unnoticed because we haven't published its pid yet. So
// we recheck here just to make sure that all is well.
// WNOHANG会让waitpid立即返回,这里只是为预防上面的赋值语句没有完成之前SystemServer就crash了

int status;
if (waitpid(pid, &status, WNOHANG) == pid) {
ALOGE("System server process %d has died. Restarting Zygote!", pid);
RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
}

if (UsePerAppMemcg()) {
// Assign system_server to the correct memory cgroup.
// Not all devices mount memcg so check if it is mounted first
// to avoid unnecessarily printing errors and denials in the logs.
if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) {
ALOGE("couldn't add process %d into system memcg group", pid);
}
}
}
return pid;
}

// line 2251
// Utility routine to fork a process from the zygote.
NO_STACK_PROTECTOR
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
bool is_priority_fork,
bool purge) {
SetSignalHandlers();

// Curry a failure function.
auto fail_fn = std::bind(zygote::ZygoteFailure, env,
is_system_server ? "system_server" : "zygote",
nullptr, _1);

// Temporarily block SIGCHLD during forks. The SIGCHLD handler might
// log, which would result in the logging FDs we close being reopened.
// This would cause failures because the FDs are not allowlisted.
//
// Note that the zygote process is single threaded at this point.
BlockSignal(SIGCHLD, fail_fn);

// Close any logging related FDs before we start evaluating the list of
// file descriptors.
__android_log_close();
AStatsSocket_close();

// If this is the first fork for this zygote, create the open FD table,
// verifying that files are of supported type and allowlisted. Otherwise (not
// the first fork), check that the open files have not changed. Newly open
// files are not expected, and will be disallowed in the future. Currently
// they are allowed if they pass the same checks as in the
// FileDescriptorTable::Create() above.
if (gOpenFdTable == nullptr) {
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
} else {
gOpenFdTable->Restat(fds_to_ignore, fail_fn);
}

android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();

if (purge) {
// Purge unused native memory in an attempt to reduce the amount of false
// sharing with the child process. By reducing the size of the libc_malloc
// region shared with the child process we reduce the number of pages that
// transition to the private-dirty state when malloc adjusts the meta-data
// on each of the pages it is managing after the fork.
if (mallopt(M_PURGE_ALL, 0) != 1) {
mallopt(M_PURGE, 0);
}
}

pid_t pid = fork();

if (pid == 0) {
if (is_priority_fork) {
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
} else {
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
}

#if defined(__BIONIC__) && !defined(NO_RESET_STACK_PROTECTOR)
// Reset the stack guard for the new process.
android_reset_stack_guards();
#endif

// The child process.
PreApplicationInit();

// Clean up any descriptors which must be closed immediately
DetachDescriptors(env, fds_to_close, fail_fn);

// Invalidate the entries in the USAP table.
ClearUsapTable();

// Re-open all remaining open file descriptors so that they aren't shared
// with the zygote across a fork.
gOpenFdTable->ReopenOrDetach(fail_fn);

// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);

// Reset the fd to the unsolicited zygote socket
gSystemServerSocketFd = -1;
} else if (pid == -1) {
ALOGE("Failed to fork child process: %s (%d)", strerror(errno), errno);
} else {
ALOGD("Forked child process %d", pid);
}

// We blocked SIGCHLD prior to a fork, we unblock it here.
UnblockSignal(SIGCHLD, fail_fn);

return pid;
}

// This signal handler is for zygote mode, since the zygote must reap its children
NO_STACK_PROTECTOR
static void SigChldHandler(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
pid_t pid;
int status;
int64_t usaps_removed = 0;

// It's necessary to save and restore the errno during this function.
// Since errno is stored per thread, changing it here modifies the errno
// on the thread on which this signal handler executes. If a signal occurs
// between a call and an errno check, it's possible to get the errno set
// here.
// See b/23572286 for extra information.
int saved_errno = errno;

while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
// Notify system_server that we received a SIGCHLD
sendSigChildStatus(pid, info->si_uid, status);
// Log process-death status that we care about.
if (WIFEXITED(status)) {
async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, "Process %d exited cleanly (%d)", pid,
WEXITSTATUS(status));

// Check to see if the PID is in the USAP pool and remove it if it is.
if (RemoveUsapTableEntry(pid)) {
++usaps_removed;
}
} else if (WIFSIGNALED(status)) {
async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
"Process %d exited due to signal %d (%s)%s", pid,
WTERMSIG(status), strsignal(WTERMSIG(status)),
WCOREDUMP(status) ? "; core dumped" : "");

// If the process exited due to a signal other than SIGTERM, check to see
// if the PID is in the USAP pool and remove it if it is. If the process
// was closed by the Zygote using SIGTERM then the USAP pool entry will
// have already been removed (see nativeEmptyUsapPool()).
if (WTERMSIG(status) != SIGTERM && RemoveUsapTableEntry(pid)) {
++usaps_removed;
}
}

// If the just-crashed process is the system_server, bring down zygote
// so that it is restarted by init and system server will be restarted
// from there.
if (pid == gSystemServerPid) {
async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
"Exit zygote because system server (pid %d) has terminated", pid);
kill(getpid(), SIGKILL);
}
}

// Note that we shouldn't consider ECHILD an error because
// the secondary zygote might have no children left to wait for.
if (pid < 0 && errno != ECHILD) {
async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Zygote SIGCHLD error in waitpid: %s",
strerror(errno));
}

if (usaps_removed > 0) {
if (TEMP_FAILURE_RETRY(write(gUsapPoolEventFD, &usaps_removed, sizeof(usaps_removed))) ==
-1) {
// If this write fails something went terribly wrong. We will now kill
// the zygote and let the system bring it back up.
async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
"Zygote failed to write to USAP pool event FD: %s",
strerror(errno));
kill(getpid(), SIGKILL);
}
}

errno = saved_errno;
}
// line 495

// Configures the SIGCHLD/SIGHUP handlers for the zygote process. This is
// configured very late, because earlier in the runtime we may fork() and
// exec() other processes, and we want to waitpid() for those rather than
// have them be harvested immediately.
//
// Ignore SIGHUP because all processes forked by the zygote are in the same
// process group as the zygote and we don't want to be notified if we become
// an orphaned group and have one or more stopped processes. This is not a
// theoretical concern :
// - we can become an orphaned group if one of our direct descendants forks
// and is subsequently killed before its children.
// - crash_dump routinely STOPs the process it's tracing.
//
// See issues b/71965619 and b/25567761 for further details.
//
// This ends up being called repeatedly before each fork(), but there's
// no real harm in that.
static void SetSignalHandlers() {
struct sigaction sig_chld = {.sa_flags = SA_SIGINFO, .sa_sigaction = SigChldHandler};

if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) {
ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
}

struct sigaction sig_hup = {};
sig_hup.sa_handler = SIG_IGN;
if (sigaction(SIGHUP, &sig_hup, nullptr) < 0) {
ALOGW("Error setting SIGHUP handler: %s", strerror(errno));
}
}

  在Unix系统中,父进程必须用waitpid等待子进程的退出,否则子进程将变成Zombie僵尸进程,不仅系统资源泄露,而且系统将崩溃(没有System Server,所有的Andoid应用程序都无法运行)。但是waitpid()是一个阻塞函数(WNOHANG参数除外),所以通常做法是在signal处理函数里进行无阻塞的处理,因为每个子进程的时候,系统会发出SIGCHID信号。Zygote会把自己杀掉,那父亲死了,所有的应用程序不就成了孤儿了?不会,因为父进程被杀掉系统会自动给所有的子进程发生SINGUP信号,该信号的默认处理就是杀掉自己退出当前进程。但是一些后台进程(Daemon)可以通过设置SIGING参数来忽略这个信号,从而得以在后台继续运行。

  • 总结
  1. init 根据init.rc 运行app_process,并携带’-zygote‘和‘-startSystemServer’参数
  2. AndroidRuntime.cpp::start()里将启动JavaVM,并且注册所有framework相关的系统JNI接口
  3. 运行ZygoteInit.java::main()函数初始化Zygote,Zygote并创建Socket的Server端
  4. 然后fork一个新的进程并在新进程里初始化SystemServer,Fork之前,Zygote是preload常用的Java类库,以及系统的resource,同时GC()清理内存空间,为子进程省去重复的工作。
  5. SystemServer丽江所有的系统Service初始化,包括ActivityManager和WindowManager,它们是应用程序运行起来的前提
  6. 同时Zygote监听服务端Socket,等待新的应用启动请求
  7. ActivityManager ready之后寻找系统的‘Startup’ Application,将请求发给Zygote
  8. Zygote收到请求后,fork出一个新的进程
  9. Zygote监听并处理SystemServer的SIGCHID信号,一旦System Server崩溃,立即将自己杀死。init会重启Zygote

fork函数

  • bionic/libc/bionic/fork.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
pid_t fork(void)
{
sigset_t set;
__fork_handler(-1);
__block_app_sigs(&set);
int need_locks = libc.need_locks > 0;
if (need_locks) {
__ldso_atfork(-1);
__inhibit_ptc();
for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
if (*atfork_locks[i]) LOCK(*atfork_locks[i]);
__malloc_atfork(-1);
__tl_lock();
}
pthread_t self=__pthread_self(), next=self->next;
pid_t ret = _Fork();
int errno_save = errno;
if (need_locks) {
if (!ret) {
for (pthread_t td=next; td!=self; td=td->next)
td->tid = -1;
if (__vmlock_lockptr) {
__vmlock_lockptr[0] = 0;
__vmlock_lockptr[1] = 0;
}
}
__tl_unlock();
__malloc_atfork(!ret);
for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
if (*atfork_locks[i])
if (ret) UNLOCK(*atfork_locks[i]);
else **atfork_locks[i] = 0;
__release_ptc();
__ldso_atfork(!ret);
}
__restore_sigs(&set);
__fork_handler(!ret);
if (ret<0) errno = errno_save;
return ret;
}

  1. 不需要参数
  2. 需要的头文件<sys/types.h> 和 <unistd.h>
  3. 返回值分两种情况:
    1. 返回0表示成功创建子进程,并且接下来进入子进程执行流程
    2. 返回PID(>0),成功创建子进程,并且继续执行父进程流程代码
    3. 返回非正数(<0),创建子进程失败,失败的原因主要有进程数超过系统所能创建的上限,ENGAIN系统内存不足

  使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间:包括进程上下文(进程执行活动全过程的静态描述)、进程堆栈,打开的文件描述符、信号控制设定、进程优先级、进程组号等。子进程所独有的只有它的进程号,计时器等(只要少量信息)。因此,使用fork()函数的代价是很大的。

其它

  1. 什么情况下Zygote进程会重启呢?
  • servicemanager进程被杀
  • (onresart)surfacelinger进程被杀
  • (onresart)Zygote进程自己被杀
  • (oneshot=false)system_server进程被杀(waitpid)
  1. 子进程与父进程的区别
  • 除了文件锁以外,其他的锁都会被继承
  • 各自的进程ID和父进程ID不同
  • 子进程的未决告警被清除
  • 子进程的未决信号集设置为空集
  1. 写时拷贝(copy-on-write)

  Linux的fork()使用是通过写时拷贝(copy-on-write)实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制地址空间,从而使各个进行拥有各自的地址空间。资源的复制是在需要写入的时候才会进行,在此之前,只有以读写方式共享

  1. 孤儿进程、僵尸进程

  fork系统调用之后,父子进程将交替执行,执行顺序不定。如果父进程先退出,子进程还没退出。那么子进程的父进程将变为init进程(托孤给了init进程)。(注:任何一个进程都必须有父进程)如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵尸进程(只保留一些退出信息供父进程查询)

  1. 多线程进程的Fork调用

  在POSIX标准中,fork的行为是这样的:复制整个用户空间的数据(通常使用copy-on-write的策略,所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子线程。这里:所有父进程中别的线程,到了子进程中都是突然蒸发掉的。

  假设这么一个环境,在fork之前,有一个子线程lock了某个锁,获得了对锁的所有权。fork以后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主人,所以没有任何人可以对它解锁。当子进程想unlock这个锁时,不再有任何手段可以解开。程序发生死锁。

常见面试题

  1. 你了解Android系统启动流程吗?

  当按下电源键触发开机,首先会从ROM中预定义的地方加载引导程序BootLoader到RAM中,并执行BootLoader程序启动Linux Kernel,然后启动用户级别的第一个进程:init进程。init进程会解析init.rc脚本做一些初始化工作,包括挂载文件系统、创建工作目录以及启动系统服务进程等,其中系统服务进程包括Zygote、service manager、media等。在Zygote中会进一步去启动system_server进程,然后在system_server进程中会启动AMS、WMS、PMS等服务,这些服务启动之后,AMS中就会打开Launcher应用的home Activity,最终就看到了手机的“桌面”

  1. system_server为什么要在Zygote中启动,而不是由Init直接启动呢?

  Zygote作为一个孵化器,可以提前加载一些资源,这样fork()时基于Copy-On-Write机制创建的其他进程就能直接使用这些资源,而不用重新加载。比如system_server就可以直接使用Zygote中的JNI函数、共享库、常用类以及主题资源。

  1. 为什么要专门使用Zygote进程去孵化应用进程,而不是让system_server去孵化呢?

  首先system_server相比Zygote多运行了AMS、WMS等服务,对一些应用程序来说不是必需的。最重要的是进程的fork()对多线程不友好,只会将发起调用的线程拷贝到子进程,可能会导致死锁。

  1. 能说说具体是怎么导致死锁的吗?

  在POSIX标准中(可移植操作系统接口Portable Operating System Interface of UNIX),fork的行为是这样的:复制整个用户空间的数据(通常使用copy-on-write的策略,所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别的线程,到了子进程中都是突然蒸发掉的。对于锁来说,从OS看,每一个锁都有一个所有着,即最后一次lock它的线程。假设这么一个环境,在fork之前,有一个子线程lock了某个锁,获得了锁的所有权。fork以后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主任,所有没有任何人可以对它解锁。当子进程想lock这个锁时,不再有任何手段可以解开了。程序发生死锁

  1. Zygote为什么不采用Binder机制进行IPC通信?

  Binder机制中存在Binder线程池,是多线程的,如果Zygote采用Binder的话存在fork()与多线程的问题。严格来说,Binder机制不一定要多线程,所谓的Binder线程只不过是在循环读取Binder驱动的消息而已,只注册一个Binder线程也是可以工作的,比如service manager就是这样的。实际上Zygote尽管没有采取Binder机制,它也不是单线程的,蛋挞在fork前主动停止了其他线程,fork后重新启动了。