本文的分析基於Android 8.1源碼。
Android系統啓動與應用程序的啓動流程、四大組件原理、AMS、ClassLoader等息息相關,因此瞭解Android系統啓動流程對深入理解Android有很大的幫助。
本文將分爲以下幾個小節講述Android系統的系統流程,分別是:init進程啓動、Zygote進程啓動、SystemServer進程啓動以及Launcher進程啓動。
一、init進程啓動
都知道當手機關機時不會啓動任何一個進程,所以在init進程啓動前,Android就爲進程的啓動做了很多鋪墊。具體爲:按下電源鍵加載BootLoader、拉起系統OS、啓動Linux內核…但由於本人暫未學到Linux內核,因此前面的暫不做分析(當我沒說emmm…)
本節涉及到的文件有:
文件 | 路徑 |
init.cpp | system/core/init/init.cpp |
init.rc | system/core/rootdir/init.rc |
init.zygote64_32.rc | system/core/rootdir/init.zygote64_32.rc |
service.cpp | system/core/init/service.cpp |
builtins.cpp | system/core/init/builtins.cpp |
1.1 init.main()
Linux內核啓動後,運行的第一個進程是init進程。
system/core/init/init.cpp |
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
add_environment("PATH", _PATH_DEFPATH);
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
//註釋1:掛載必須的文件路徑
if (is_first_stage) {
……
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));
//system/core/init/init_first_stage.cpp
SetInitAvbVersionInRecovery();
//加載及初始化SELinux
selinux_initialize(true);
……
}
//初始化Kernel Log
InitKernelLogging(argv);
//bionic/libc/bionic/system_properties.cpp
//註釋2:初始化屬性服務
property_init();
……
//
signal_handler_init();
//導入默認的環境變量
//"/system/etc/prop.default,/odm/default.prop,/vendor/default.prop"
property_load_boot_defaults();
//啓動屬性服務
start_property_service();
……
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
ActionManager& am = ActionManager::GetInstance();
ServiceManager& sm = ServiceManager::GetInstance();
Parser& parser = Parser::GetInstance();
//make_unique是C++的智能指針,可以自動管理內存
//ServiceParser、ActionParser、ImportParser分別解析service,action,import
parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
//若不存在"ro.boot.init_rc"屬性,則解析下列文件
parser.ParseConfig("/init.rc"); //註釋3,解析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);
}
……
while (true) {
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
//重置shutting_down標誌
if (do_shutdown && !shutting_down) {
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {
shutting_down = true;
}
}
if (!(waiting_for_prop || sm.IsWaitingForExec())) {
//執行每個Action所帶的執行函數
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || sm.IsWaitingForExec())) {
//重啓死去的進程
if (!shutting_down) restart_processes();
……
}
}
return 0;
}
init進程做的事較多,但我們只需關注幾點:
- 註釋1處創建和掛載啓動所需的文件
- 註釋2處初始化屬性服務,隨後調用start_property_service()啓動屬性服務
- 註釋3處解析**/init.rc,{/system,/vendor,/odm}/etc/init**幾個文件
1.2 解析init.rc
init.rc是用Android初始化語言(Android Init Language)編寫的文件,在init文件夾中的README對它有描述。感興趣的可以自行去看。
system/core/init/README.md |
AIL主要包含5種類型的語句:Actions, Commands, Services, Options, Imports.
重點來看看Actions和Services
Actions的格式如下:
on <trigger> [&& <trigger>]* #觸發條件
<command> #操作命令
<command>
例如:
on charger
class_start charger
只要條件charger成立,便會執行 class_start charger 命令
Services的格式如下:
service <name> <pathname> [<argument>] #<service服務名稱><執行文件路徑><參數>
<option> #這個服務的一些配置
<option>
例如:
service adbd /system/bin/adbd --root_seclabel=u:r:su:s0
class core
socket adbd stream 660 system system
disabled
seclabel u:r:adbd:s0
這是init.usb.rc的一段代碼,用來啓動adbd服務
瞭解了AIL語言後,我們來看看init.rc,代碼路徑如下:
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
……
在init.rc開始位置引入了一些rc文件,重點關注Zygote啓動相關的文件。/init.${ro.zygote}.rc
這裏根據ro.zygote屬性值加載對應的rc文件。這個屬性值可通過**adb shell getprop | grep “zygote”**獲取。
例如在我的手機上該屬性值爲: [ro.zygote]: [zygote64_32]
在我手機上啓動Zygote會涉及到init.zygote64_32.rc,代碼路徑如下:
system/core/rootdir/init.zygote64_32.rc |
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 stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_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
可以看到該文件裏有兩個service,最大的區別就是對應的可執行文件不一樣。可以看到,啓動64位的Zygote需要執行/system/bin/app_process64,後面是傳入的參數。
那麼zygote的service是怎麼被解析的呢? 我們回憶一下init.main()。
system/core/init/init.cpp |
int main(int argc, char** argv) {
……
ServiceManager& sm = ServiceManager::GetInstance();
Parser& parser = Parser::GetInstance();
//make_unique是C++的智能指針,可以自動管理內存
//ServiceParser、ActionParser、ImportParser分別解析service,action,import
parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
……
parser.ParseConfig("/init.rc");
……
return 0;
}
AddSectionParser函數將"service"當做鍵,ServiceParser對象當做值,存到一個map中,執行ParseConfig函數後,會調用ServiceParser的ParseSection和ParseLineSection函數來解析service語句。
1.2.1 解析service
system/core/init/service.cpp |
ServiceParser的實現在 system/core/init/service.cpp中,ParseSection的實現如下:
bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,int line, std::string* err) {
if (args.size() < 3) {
*err = "services must have a name and a program";
return false;
}
//獲取服務名
const std::string& name = args[1];
if (!IsValidName(name)) { //檢查service的name是否有效
*err = StringPrintf("invalid service name '%s'", name.c_str());
return false;
}
Service* old_service = service_manager_->FindServiceByName(name);
if (old_service) {
*err = "ignored duplicate definition of service '" + name + "'";
return false;
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
//將service_指針指向當前Service對象
service_ = std::make_unique<Service>(name, str_args);
return true;
}
ParseSection主要檢驗參數的有效性,並構造一個Service對象。
接下來看看ParseLineSection
bool ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) {
return service_ ? service_->ParseLine(std::move(args), err) : false;
}
再來看看ParseLine
bool Service::ParseLine(const std::vector<std::string>& args, std::string* err) {
static const OptionParserMap parser_map;
auto parser = parser_map.FindFunction(args, err); //1
if (!parser) {
return false;
}
return (this->*parser)(args, err); //2
}
ParseLine的作用是爲Service的每一個Option指定處理函數。
註釋1處FindFunction根據傳入的args找到對應的處理函數,並在註釋2的return語句中調用。
具體的Options和對應的函數在Service::OptionParserMap::map()中定義
const Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
// clang-format off
static const Map option_parsers = {
……
{"priority", {1,1,&Service::ParsePriority}},
……
{"namespace", {1,2,&Service::ParseNamespace}},
……
};
// clang-format on
return option_parsers;
}
解析完所有數據後,會調用EndSection函數
void ServiceParser::EndSection() {
if (service_) {
service_manager_->AddService(std::move(service_));
}
}
在EndSection中又調用了ServiceManager的AddService函數。
void ServiceManager::AddService(std::unique_ptr<Service> service) {
services_.emplace_back(std::move(service));
}
EndSection的主要工作是將解析完成的Service添加到ServiceManager的service_鏈表中。
1.2.2 啓動ServiceManager
ServiceManager用來管理系統中所有的binder service,最主要的作用是註冊添加服務和Zygote進程啓動。
system/core/rootdir/init.rc |
on post-fs
……
start servicemanager
……
1.2.3 啓動Zygote
system/core/rootdir/init.rc |
on nonencrypted
class_start main
class_start late_start
這是一個Action語句,class_start對應的函數是do_class_start, class_start main會啓動classname爲main的Service
system/core/init/builtins.cpp |
static int do_class_start(const std::vector<std::string>& args) {
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
return 0;
}
ForEachServiceInClass會找到classname爲main的Service,並執行Service的StartIfNotDisabled。
system/core/init/service.cpp |
bool Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
return true;
}
接着進入到Start()函數。Start函數較長,這裏只截取關鍵部分分析。
bool Service::Start() {
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
//如果Service已經啓動,則直接返回
if (flags_ & SVC_RUNNING) {
return false;
}
//對Service判斷,設置一些Flag
……
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork();
}
if (pid == 0) {
//fork出子進程後,爲子進程設置參數
……
//執行對應Service的對應執行文件
//調用execve函數執行程序
if (!ExpandArgsAndExecve(args_)) {
PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
}
}
……
return true;
}
Start()函數先通過fork函數創建一個子進程,然後在子進程中調用ExpandArgsAndExecve()->execve()函數啓動一個新的程序。fork()+execve()結合可以產生一個新的進程,這裏涉及到Linux內核層面,便不再繼續深入。
由init.zygote64_32.rc可知,Zygote的執行路徑爲:/system/bin/app_process64,執行該程序後,不管是32位還是64位系統,都會進入到framework/cmds/app_process/app_main.cpp的main()函數。
由此可知,Zygote進程也不是憑空產生,而是由Init進程fork而來。
1.3 小結
init進程的啓動做了很多工作,主要爲以下幾點:
- 創建和掛載必須的文件路徑
- 初始化並啓動屬性服務
- 解析並執行init.rc文件的語句
至此,代碼流程進入到framework層,關於Zygote進程的啓動將在下節講解。
Android系統啓動分析(二)