這是一個連載的系列「圖解 Android 系列」,我將持續爲你們提供儘量通俗易懂的 Android 源碼分析。html
全部引用的源碼片斷,我都會在第一行標明源文件完整路徑。爲了文章篇幅考慮源碼中間可能有刪減,刪減部分會用省略號代替。java
本系列源碼基於:Android Oreo(8.0)linux
在上篇文章 揭祕 Android 系統啓動過程 中介紹到,init 進程啓動分爲先後兩部分,前一部分是在內核啓動的,主要是完成建立和內核初始化工做,內容都是跟 Linux 內核相關的;後一部分是在用戶空間啓動的,主要完成 Android 系統的初始化工做。android
Android 系統通常會在根目錄下放一個 init 的可執行文件,也就是說 Linux 系統的 init 進程在內核初始化完成後,就直接執行 init 這個文件,這個文件的源代碼在 /system/core/init/init.cpp
。ios
init 進程是 Linux 系統中用戶空間的第一個進程(pid = 1),咱們熟悉的 App 應用程序都是以它爲父進程的,init 進程入口函數是 main 函數。這個函數作的事情仍是比較多的,主要分爲三個部分:c++
咱們先來看第一階段主要有如下內容:。git
//system/core/init/init.cpp
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
// 1 表示 true,也就執行 ueventd_main,ueventd
// 主要是負責設備節點的建立、權限設定等一些列工做
return ueventd_main(argc, argv);
}
// watchdogd 俗稱看門狗,用於系統出問題時重啓系統
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
if (REBOOT_BOOTLOADER_ON_PANIC) {
//初始化重啓系統的處理信號,內部經過 sigaction 註冊信號,
//當監聽到該信號時重啓系統
install_reboot_signal_handlers();
}
//註冊環境變量PATH
add_environment("PATH", _PATH_DEFPATH);
// init 的 main 方法會執行兩次,由 is_first_stage 控制,
// first_stage 就是第一階段要作的事
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
// 只執行一次,由於在方法體中有設置 INIT_SECOND_STAGE
if (is_first_stage) {
// 清空文件權限
umask(0);
// on / and then we'll let the rc file figure out the rest.
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0,
"hidepid=2,gid=" MAKE_STR(AID_READPROC));
// Don't expose the raw commandline to unprivileged processes.
chmod("/proc/cmdline", 0440);
gid_t groups[] = { AID_READPROC };
setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
// 初始化日誌輸出
InitKernelLogging(argv);
LOG(INFO) << "init first stage started!";
if (!DoFirstStageMount()) {
LOG(ERROR) << "Failed to mount required partitions early ...";
panic();
}
// 在刷機模式下初始化avb的版本,不是刷機模式直接跳過
SetInitAvbVersionInRecovery();
// 加載S ELinux policy,也就是安全策略
selinux_initialize(true);
// We're in the kernel domain, so re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
if (restorecon("/init") == -1) {
PLOG(ERROR) << "restorecon failed";
security_failure(); // 失敗則重啓系統
}
setenv("INIT_SECOND_STAGE", "true", 1);
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count()
/ kNanosecondsPerMillisecond;
setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ms).c_str(), 1);
char* path = argv[0];
char* args[] = { path, nullptr };
execv(path, args); // 從新執行 main 方法,進入第二階段
// execv() only returns if an error happened, in which case we
// panic and never fall through this conditional.
PLOG(ERROR) << "execv(\"" << path << "\") failed";
security_failure();
}
// ...
}
複製代碼
init 進程第一階段作的主要工做是掛載分區,建立設備節點和一些關鍵目錄,初始化日誌輸出系統,啓用 SELinux 安全策略。github
咱們接着看第二階段,主要有如下內容:數組
//system/core/init/init.cpp
int main(int argc, char** argv) {
// 一樣進行 ueventd/watchdogd 跳轉及環境變量設置
// 以前準備工做時將 INIT_SECOND_STAGE設 置爲 true,
// 已經不爲 nullptr,因此 is_first_stage 爲 false
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
// is_first_stage爲false,直接跳過
if (is_first_stage) {
// ...
}
// 初始化日誌輸出
InitKernelLogging(argv);
// ...
// 初始化屬性系統,並從指定文件讀取屬性
property_init();
// ...
// 初始化子進程退出的信號處理函數
signal_handler_init();
// 加載 default.prop 文件
property_load_boot_defaults();
export_oem_lock_status();
// 啓動屬性服務器
start_property_service();
set_usb_controller();
//...
}
複製代碼
init 進程第二階段主要工做是初始化屬性系統,解析 SELinux 的匹配規則,處理子進程終止信號,啓動系統屬性服務,能夠說每一項都很關鍵。若是說第一階段是爲屬性系統、SELinux 作準備,那麼第二階段就是真正去把這些落實的。緩存
//system/core/init/init.cpp
int main(int argc, char** argv) {
// ...
const BuiltinFunctionMap function_map;
// 將 function_map 存放到 Action 中做爲成員屬性
Action::set_function_map(&function_map);
// 解析 init.rc 文件
Parser& parser = Parser::GetInstance();
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
std::string bootscript = GetProperty("ro.boot.init_rc", "");
// 若是 ro.boot.init_rc 沒有對應的值,
// 則解析 /init.rc 以及 /system/etc/init、/vendor/etc/init、
// /odm/etc/init 這三個目錄下的 .rc 文件
if (bootscript.empty()) {
parser.ParseConfig("/init.rc");
parser.set_is_system_etc_init_loaded(
parser.ParseConfig("/system/etc/init"));
parser.set_is_vendor_etc_init_loaded(
parser.ParseConfig("/vendor/etc/init"));
parser.set_is_odm_etc_init_loaded(
parser.ParseConfig("/odm/etc/init"));
} else { // 若是 ro.boot.init_rc 屬性有值就解析屬性值
parser.ParseConfig(bootscript);
parser.set_is_system_etc_init_loaded(true);
parser.set_is_vendor_etc_init_loaded(true);
parser.set_is_odm_etc_init_loaded(true);
}
// ...
ActionManager& am = ActionManager::GetInstance();
am.QueueEventTrigger("early-init");
// 等冷插拔設備初始化完成
am.QueueBuiltinAction(wait_for_coldboot_done_action,
"wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action,
"mix_hwrng_into_linux_rng");
am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
// 設備組合鍵的初始化操做
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
// 屏幕上顯示 Android 靜態 Logo,很熟悉的感受有沒有
am.QueueBuiltinAction(console_init_action, "console_init");
// Trigger all the boot actions to get us started.
am.QueueEventTrigger("init");
// 執行 rc 文件中觸發器爲 on init 的語句
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action,
"mix_hwrng_into_linux_rng");
// 當處於充電模式,則 charger 加入執行隊列,不然 late-init 加入隊列。
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init"); // 觸發 late-init
}
// 觸發器爲屬性是否設置
am.QueueBuiltinAction(queue_property_triggers_action,
"queue_property_triggers");
while (true) {
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
if (!(waiting_for_prop
|| ServiceManager::GetInstance().IsWaitingForExec())) {
am.ExecuteOneCommand();
}
if (!(waiting_for_prop
|| ServiceManager::GetInstance().IsWaitingForExec())) {
// 根據須要重啓服務
restart_processes();
// If there's a process that needs restarting, wake up in time for that.
if (process_needs_restart_at != 0) {
epoll_timeout_ms =
(process_needs_restart_at - time(nullptr)) * 1000;
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
}
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) epoll_timeout_ms = 0;
}
epoll_event ev;
// 循環等待事件發生
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1,
epoll_timeout_ms));
if (nr == -1) {
PLOG(ERROR) << "epoll_wait failed";
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
複製代碼
這一階段 init 進程作了許多重要的事情,好比解析 init.rc 文件,這裏配置了全部須要執行的 action 和須要啓動的 service,init 進程根據語法一步步去解析 init.rc,將這些配置轉換成一個個數組、隊列,而後開啓無限循環去處理這些數組、隊列中的 command 和 service,而且經過 epoll 監聽子進程結束和屬性設置。
init.rc 文件是 Android 系統的重要配置文件,位於 /system/core/rootdir/
目錄中。 主要功能是定義了系統啓動時須要執行的一系列 action 及執行特定動做、設置環境變量和屬性和執行特定的 service。
//system/core/rootdir/init.rc
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc // 稍後分析
on early-init
// ...
on init
// ...
on late-init
// ...
trigger zygote-start
on post-fs // 掛載文件系統
load_system_props
# start essential services
start logd
// 熟悉的 servermanager,後面章節再討論
start servicemanager
start hwservicemanager
start vndservicemanager
// ...
on post-fs-data // 掛載 data
# We chown/chmod /data again so because mount is run as root + defaults
chown system system /data
chmod 0771 /data
# We restorecon /data in case the userdata partition has been reset.
restorecon /data
# Make sure we have the device encryption key.
start vold
// ...
# 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 // 啓動 zygote,稍後分析
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=unsupported
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on boot
// ...
# Start standard binderized HAL daemons
class_start hal
class_start core
複製代碼
init 進程會解析 .rc
文件,而後獲得一些 service 去啓動,這些 service 一般不是普通的服務,文檔裏面的稱呼是daemon(守護進程)。
所謂守護進程就是這些服務進程會在系統初始化時啓動,並一直運行於後臺,直到系統關閉時終止。
到這裏 init 進程的主要流程已經分析完了,咱們總結下 init 進程啓動主要作了哪些工做。
首先在 Kernel 內核加載完後會調用 /system/core/init/init.cpp
文件中的 main()
方法。該方法執行分爲三個階段,前兩個的階段都是初始化環境,咱們主要關注下第三個階段 解析 .rc
文件。
在第三階段中經過解析 .rc 文件啓動了 servicemanager
和 zygote
等服務,最後 init 進程進入了 loop。
zygote 進程就是 daemon 其中之一,zygote 進程主要負責建立 Java 虛擬機,加載系統資源,啓動 SystemServer 進程,以及在後續運行過程當中啓動普通的應用程序。
在 init.rc 文件頭部有這麼一句:
import /init.${ro.zygote}.rc
複製代碼
其中 ${ro.zygote}
會被替換成 ro.zyogte 的屬性值,這個是由不一樣的硬件廠商本身定製的。 有四個值:zygote3二、zygote6四、zygote32_6四、zygote64_32 ,也就是說可能有四種 .rc 文件,分別是:
爲何要定義這麼多種狀況呢?直接定義一個不就行了,這主要是由於 Android 5.0 之後開始支持 64 位程序,爲了兼容 32 位和 64 位才這樣定義。
不一樣的 zygote.rc 內容大體相同,主要區別體如今啓動的是 32 位,仍是 64 位的進程。init.zygote32_64.rc 和 init.zygote64_32.rc 會啓動兩個進程,且存在主次之分。咱們以init.zygote64_32.rc
爲例。
//system/core/rootdir/init.zygote64_32.rc
// 進程名稱是 zygote,運行的二進制文件在 /system/bin/app_process64,稍後分析
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
//建立一個 socket,名字叫 zygote,以 tcp 形式
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
// 另外一個 service,名字 zygote_secondary
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
priority -20
user root
group root readproc
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
複製代碼
在 init.rc 文件中能夠找到一句 start zygote
,這是調用 zygote 服務的啓動方式。
//system/core/rootdir/init.rc
// ...
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
// 啓動 zygote,稍後分析
on zygote-start && property:ro.crypto.state=unencrypted
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=unsupported
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
複製代碼
在 init.zygote64_32.rc 文件中的頭部咱們能夠看到 zygote 對應的二進制文件是 /system/bin/app_process64
(以此爲例),咱們看一下對應的mk文件, 對應的目錄在 platform/frameworks/base/cmds/app_process/Android.mk
,其實不論是 app_process、app_process32 仍是 app_process64,對應的源文件都是 app_main.cpp。
//frameworks/base/cmds/app_process/Android.mk
// ...
app_process_src_files := \
app_main.cpp \
// ...
LOCAL_SRC_FILES:= $(app_process_src_files)
// ...
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
// ...
複製代碼
在 app_main.cpp 的 main 函數中,主要作的事情就是參數解析。 這個函數有兩種啓動模式:
二者最終都是調用 AppRuntime 對象的 start 函數,加載 ZygoteInit 或 RuntimeInit 兩個 Java 類,並將以前整理的參數傳入進去。
//frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[]) {
// 將參數 argv 放到 argv_String 字符串中,而後打印出來
if (!LOG_NDEBUG) {
String8 argv_String;
for (int i = 0; i < argc; ++i) {
argv_String.append("\"");
argv_String.append(argv[i]);
argv_String.append("\" ");
}
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// 全部在 "--" 後面的非 "-" 開頭的參數都將傳入 vm,
// 可是有個例外是 spaced commands 數組中的參數
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;
int i;
for (i = 0; i < argc; i++) {
// 將 spaced_commands 中的參數額外加入 VM
if (known_command == true) {
runtime.addOption(strdup(argv[i]));
known_command = false;
continue;
}
for (int j = 0;
j < static_cast<int>(sizeof(spaced_commands)
/ sizeof(spaced_commands[0]));
++j) {
if (strcmp(argv[i], spaced_commands[j]) == 0) {
known_command = true;
}
}
if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
runtime.addOption(strdup(argv[i]));
}
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
// 表示是 application 啓動模式,也就是普通應用程序
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
// 進程別名
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
// application 啓動的 class
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
// className 不爲空,說明是 application 啓動模式
args.add(application ? String8("application") : String8("tool"));
// 將 className 和參數設置給 runtime
runtime.setClassNameAndArgs(className, argc - i, argv + i);
if (!LOG_NDEBUG) {
String8 restOfArgs;
char* const* argv_new = argv + i;
int argc_new = argc - i;
for (int k = 0; k < argc_new; ++k) {
restOfArgs.append("\"");
restOfArgs.append(argv_new[k]);
restOfArgs.append("\" ");
}
}
} else { // zygote 啓動模式
// We're in zygote mode.
maybeCreateDalvikCache(); // 新建 Dalvik 的緩存目錄
if (startSystemServer) { // 加入 start-system-server 參數
args.add(String8("start-system-server"));
}
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag); // 加入 --abi-list= 參數
// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) { // 設置進程別名
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) { // 若是是 zygote 啓動模式,則加載 ZygoteInit
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
// 若是是 application 啓動模式,則加載 RuntimeInit
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
複製代碼
咱們看到,在最後調用的是 runtime.start 函數,這個就是要啓動虛擬機了,接下來咱們分析 start 函數。
//frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className,
const Vector<String8>& options, bool zygote) {
// ...
// 打印一些日誌,獲取 ANDROID_ROOT 環境變量
// ...
/* start the virtual machine */
JniInvocation jni_invocation;
// 初始化JNI,加載 libart.so
jni_invocation.Init(NULL);
JNIEnv* env;
// 建立虛擬機
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
// 表示虛擬建立完成,可是裏面是空實現
onVmCreated(env);
/* * Register android functions. * 註冊 JNI 函數 */
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
// JNI 方式調用 ZygoteInit 類的 main 函數
// ...
}
複製代碼
虛擬機建立完成後,咱們就能夠用 JNI 反射調用 Java 了,其實接下來的語法用過 JNI 的都應該比較熟悉了,直接是 CallStaticVoidMethod 反射調用 ZygoteInit 的 main 函數。
//frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options,
bool zygote) {
// 接下來的這些語法你們應該比較熟悉了,都是 JNI 裏的語法,
// 主要做用就是調用 ZygoteInit 類的 main 函數
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. */
// 將 "com.android.internal.os.ZygoteInit"
// 轉換爲 "com/android/internal/os/ZygoteInit"
char* slashClassName = toSlashClassName(className);
// 找到 class
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 {// 調用 ZygoteInit.main() 方法
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");
}
複製代碼
zygote 進程啓動主要建立了 Java 虛擬機,有了虛擬機,就能夠執行 Java 代碼了。
//frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
// 標記 zygote 進程已啓動
ZygoteHooks.startZygoteNoThreadCreation();
// 進入 Zygote 進程
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
try {
RuntimeInit.enableDdms(); // 開啓 DDMS 功能
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: "
+ argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
// 爲 zygote 註冊 socket
zygoteServer.registerServerSocket(socketName);
// 預加載處理
if (!enableLazyPreload) {
// zygote 預加載,下面介紹
preload(bootTimingsTraceLog);
} else {
Zygote.resetNicePriority();
}
gcAndFinalize(); // GC 操做
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
// Set seccomp policy
Seccomp.setPolicy();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) { // 啓動 system_server,下面介紹
startSystemServer(abiList, socketName, zygoteServer);
}
// 進入循環模式,下面介紹
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
zygoteServer.closeServerSocket();
throw ex;
}
}
複製代碼
這裏 startSystemServer()
方法會拋出一個 Zygote.MethodAndArgsCaller
異常,而後調用到 caller.run()
,這裏會在 SystemServer 章節繼續分析。
//frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
// ...
// 預加載位於 /system/etc/preloaded-classes 文件中的類
preloadClasses();
// 預加載資源,包含 drawable 和 color 資源
preloadResources();
// 預加載 OpenGL
preloadOpenGL();
// 經過 System.loadLibrary() 方法,
// 預加載 "android","compiler_rt","jnigraphics" 這 3 個共享庫
preloadSharedLibraries();
// 預加載 文本鏈接符資源
preloadTextResources();
// 僅用於 zygote 進程,用於內存共享的進程
WebViewFactory.prepareWebViewInZygote();
endIcuCachePinning();
warmUpJcaProviders();
Log.d(TAG, "end preload");
sPreloadComplete = true;
}
複製代碼
執行 zygote 進程的初始化,對於類加載,採用反射機制 Class.forName()
方法來加載。對於資源加載,主要是 com.android.internal.R.array.preloaded_drawables 和 com.android.internal.R.array.preloaded_color_state_lists,在應用程序中以 com.android.internal.R.xxx 開頭的資源,即是此時由 Zygote 加載到內存的。
zygote 進程內加載了 preload() 方法中的全部資源,當須要 fork 新進程時,採用 copy on write 技術,以下:
//frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller, RuntimeException {
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
);
/* Containers run without this capability, so avoid setting it in that case */
if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER,
false)) {
capabilities |=
posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
}
/* Hardcoded command line to start the system server */
// 準備參數
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
// 用於解析參數,生成目標格式
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
// fork 子進程,用於運行 system_server
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
// 進入子進程 system_server
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
// 完成 system_server 進程剩餘的工做
handleSystemServerProcess(parsedArgs);
}
return true;
}
複製代碼
能夠看到 zygote 進程 fork 出一個新進程名爲 system_server
也就是 SystemServer 進程。該方法是 SystemServer 進程啓動的起點,關於 SystemServer 啓動流程咱們在後面的章節在討論,這裏先分析完 zygote 的主要流程。
//frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
// mServerSocket 是 socket 通訊中的服務端,即 zygote 進程。保存到 fds[0]
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
// 處理輪詢狀態,當 pollFds 有事件到來則往下執行,不然阻塞在這裏
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
// 採用 I/O 多路複用機制,當接收到客戶端發出鏈接請求
// 或者數據處理請求到來,則往下執行;
// 不然進入continue,跳出本次循環。
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
// i>0,則表明經過 socket 接收來自對端的數據,並執行相應操做
boolean done = peers.get(i).runOnce(this);
if (done) {
peers.remove(i);
fds.remove(i); // 處理完則從 fds 中移除該文件描述符
}
}
}
}
}
複製代碼
zygote 採用高效的 I/O 多路複用機制,保證在沒有客戶端鏈接請求或數據處理時休眠,不然響應客戶端的請求。在調用 runSelectLoop()
後 zygote 進入了輪詢狀態,隨時待命當接收到請求建立新進程請求時,當即喚醒並執行相應工做。
到這裏 zygote 進程已經啓動完成了,Android 系統到目前已經啓動了第一個用戶進程 zygote。咱們來回顧下目前 Android 系統啓動的流程:
當咱們按下電源按鍵後會啓動 Bootloader,Bootloader 會加載 Kernel 內核到內存中,而後會啓動內核中的 idle 進程,idle 進程會啓動 kthreadd 和 init 兩個進程。
init 進程在啓動的時候會初始化運行環境,而後解析 init.rc 文件,解析 init.rc 文件的過程當中會啓動 servicemanager、zygote 等服務,最後進入 loop 狀態。
zygote 服務啓動時會建立 Java 虛擬機並初始化 Java 運行環境,而後啓動 SystemServer 服務,最後進入 loop 狀態。
這篇文章咱們分析到這裏,下一篇咱們接着分析 zygote 進程啓動中調用 startSystemServer() 方法後 SystemServer 進程啓動的流程。
歡迎關注個人公衆號,分享各類技術乾貨,各類學習資料,職業發展和行業動態。
歡迎加入技術交流羣,來一塊兒交流學習。