1. 概述
init进程是Linux系统中用户空间的第一个进程。由于Android是基于Linux内核的,所以init进程也是Android系统中用户空间的第一个进程,它的进程号是1,作为天字一号进程,它被赋予很多重要的职责,但本次我们就关注它的2个重要职责:init进程如何创建zygote进程、init进程如何初始化并启动属性服务。
2. init启动之前的工作
当按下Power键,引导芯片加载bootloader并将系统OS拉起来,然后启动Linux内核,当内核完成系统设置,会寻找init文件,进而启动root进程或者Linux用户空间的都一个进程,也就是启动init进程。
3. init入口函数
system/core/init/init.cpp
int main(int argc, char** argv) {
....
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
if (is_first_stage) {//创建文件并挂载
boot_clock::time_point start_time = boot_clock::now();
// Clear the umask.
umask(0);
clearenv();
setenv("PATH", _PATH_DEFPATH, 1);
// Get the basic filesystem setup we need put together in the initramdisk
// 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));
if constexpr (WORLD_WRITABLE_KMSG) {
mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
}
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
// Mount staging areas for devices managed by vold
// See storage config details at http://source.android.com/devices/storage/
mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=1000");
// /mnt/vendor is used to mount vendor-specific partitions that can not be
// part of the vendor partition, e.g. because they are mounted read-write.
mkdir("/mnt/vendor", 0755);
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
InitKernelLogging(argv);
LOG(INFO) << "init first stage started!";
if (!DoFirstStageMount()) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
SetInitAvbVersionInRecovery();
// Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
global_seccomp();
// Set up SELinux, loading the SELinux policy.
SelinuxSetupKernelLogging();
SelinuxInitialize();
// We're in the kernel domain, so re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
if (selinux_android_restorecon("/init", 0) == -1) {
PLOG(FATAL) << "restorecon failed of /init failed";
}
setenv("INIT_SECOND_STAGE", "true", 1);
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
char* path = argv[0];
char* args[] = { path, nullptr };
execv(path, args);
// execv() only returns if an error happened, in which case we
// panic and never fall through this conditional.
PLOG(FATAL) << "execv(\"" << path << "\") failed";
}
// At this point we're in the second stage of init.
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
// Set up a session keyring that all processes will have access to. It
// will hold things like FBE encryption keys. No process should override
// its session keyring.
keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
property_init();//1: 创建共享内存,初始化属性内存区域
....
property_load_boot_defaults();// 2: 加载默认default.prop
export_oem_lock_status();
start_property_service();//3: 启动属性服务
set_usb_controller();
.....
LoadBootScripts(am, sm);//4: 解析init.rc 文件
....
while (true) {
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
if (do_shutdown && !shutting_down) {
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {
shutting_down = true;
}
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || Service::is_exec_service_running())) {
if (!shutting_down) {
auto next_process_restart_time = RestartProcesses();
// If there's a process that needs restarting, wake up in time for that.
if (next_process_restart_time) {
epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
*next_process_restart_time - boot_clock::now())
.count();
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;
}
从上面的代码可以看出main函数还是做了不少工作,上面的代码已经省略了好多,但是还是很长,但是我们主要关注以下几点:
- 注释1: property_init 创建共享内存,初始化属性内存区域
- 注释2: property_load_boot_defaults 加载默认default.prop
- 注释3: start_property_service 启动属性服务
- 注释4: LoadBootScripts(am, sm) 解析init.rc文件
3.1 property_init
system\core\init\property_service.cpp
void property_init() {
mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
CreateSerializedPropertyInfo();
if (__system_property_area_init()) {//初始化
LOG(FATAL) << "Failed to initialize property area";
}
if (!property_info_area.LoadDefaultPath()) {
LOG(FATAL) << "Failed to load serialized property info file";
}
}
下面来看下__system_property_area_init()的实现
bionic\libc\bionic\system_property_api.cpp
int __system_property_area_init() {
bool fsetxattr_failed = false;
return system_properties.AreaInit(PROP_FILENAME, &fsetxattr_failed) && !fsetxattr_failed ? 0 : -1;
}
bionic\libc\system_properties\system_properties.cpp
bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
if (strlen(filename) > PROP_FILENAME_MAX) {
return false;
}
strcpy(property_filename_, filename);
contexts_ = new (contexts_data_) ContextsSerialized();
if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {
return false;
}
initialized_ = true;
return true;
}
bionic\libc\system_properties\contexts_serialized.cpp
bool ContextsSerialized::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
filename_ = filename;
if (!InitializeProperties()) {
return false;
}
....
return true;
}
bool ContextsSerialized::InitializeProperties() {
if (!property_info_area_file_.LoadDefaultPath()) {
return false;
}
....
return true;
}
我们来看下LoadDefaultPath,实现路径是 system\core\property_service\libpropertyinfoparser\property_info_parser.cpp
bool PropertyInfoAreaFile::LoadDefaultPath() {
return LoadPath("/dev/__properties__/property_info");
}
bool PropertyInfoAreaFile::LoadPath(const char* filename) {
int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);//1 打开文件(/dev/__properties__/property_info)
struct stat fd_stat;
if (fstat(fd, &fd_stat) < 0) {
close(fd);
return false;
}
if ((fd_stat.st_uid != 0) || (fd_stat.st_gid != 0) ||
((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) ||
(fd_stat.st_size < static_cast<off_t>(sizeof(PropertyInfoArea)))) {
close(fd);
return false;
}
auto mmap_size = fd_stat.st_size;
void* map_result = mmap(nullptr, mmap_size, PROT_READ, MAP_SHARED, fd, 0);//2 创建共享内存
if (map_result == MAP_FAILED) {
close(fd);
return false;
}
auto property_info_area = reinterpret_cast<PropertyInfoArea*>(map_result);
if (property_info_area->minimum_supported_version() > 1 ||
property_info_area->size() != mmap_size) {
munmap(map_result, mmap_size);
close(fd);
return false;
}
close(fd);
mmap_base_ = map_result;
mmap_size_ = mmap_size;
return true;
}
经过层层调用,最终调用到 LoadPath,注释1出打开/dev/_properties__
/property_info虚拟设备,然后注释2出调用mmap函数创建共享内存,并将fd映射到内存。
3.2 property_load_boot_defaults
从各个系统分区加载default.prop
system\core\init\property_service.cpp
void property_load_boot_defaults() {
if (!load_properties_from_file("/system/etc/prop.default", NULL)) {
// Try recovery path
if (!load_properties_from_file("/prop.default", NULL)) {
// Try legacy path
load_properties_from_file("/default.prop", NULL);
}
}
load_properties_from_file("/product/build.prop", NULL);
load_properties_from_file("/odm/default.prop", NULL);
load_properties_from_file("/vendor/default.prop", NULL);
update_sys_usb_config();
}
3.3 start_property_service
启动属性服务
system\core\init\property_service.cpp
void start_property_service() {
selinux_callback cb;
cb.func_audit = SelinuxAuditCallback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
property_set("ro.property_service.version", "2");
//1 创建非阻塞的socket用来IPC
property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
false, 0666, 0, 0, nullptr);
if (property_set_fd == -1) {
PLOG(FATAL) << "start_property_service socket creation failed";
}
//2 监听property_set_fd,可以同时为8个设置属性的用户提供服务
listen(property_set_fd, 8);
//3 将property_set_fd放入epoll句柄,用epoll来监听property_set_fd,当有新数据到来是,init进程将调用
//handle_property_set_fd来处理
register_epoll_handler(property_set_fd, handle_property_set_fd);
}
- 注释1: 创建非阻塞的socket用来IPC
- 注释2: 调用listen用来监听property_set_fd,这样创建的的socket成为了server,第二个参数为8说明可以同时为8个设置属性的用户服务。
- 注释3: 将property_set_fd放入epoll句柄,用epoll来监听property_set_fd,当有新数据到来是,init进程将调用handle_property_set_fd来处理
static void handle_property_set_fd() {
static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
if (s == -1) {
return;
}
ucred cr;
socklen_t cr_size = sizeof(cr);
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
return;
}
SocketConnection socket(s, cr);
uint32_t timeout_ms = kDefaultSocketTimeout;
uint32_t cmd = 0;
if (!socket.RecvUint32(&cmd, &timeout_ms)) {
PLOG(ERROR) << "sys_prop: error while reading command from the socket";
socket.SendUint32(PROP_ERROR_READ_CMD);
return;
}
switch (cmd) {
case PROP_MSG_SETPROP: {
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
!socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
return;
}
prop_name[PROP_NAME_MAX-1] = 0;
prop_value[PROP_VALUE_MAX-1] = 0;
const auto& cr = socket.cred();
std::string error;
uint32_t result =
HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);//1 设置属性
if (result != PROP_SUCCESS) {
LOG(ERROR) << "Unable to set property '" << prop_name << "' to '" << prop_value
<< "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
<< error;
}
break;
}
case PROP_MSG_SETPROP2: {
std::string name;
std::string value;
if (!socket.RecvString(&name, &timeout_ms) ||
!socket.RecvString(&value, &timeout_ms)) {
PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
socket.SendUint32(PROP_ERROR_READ_DATA);
return;
}
const auto& cr = socket.cred();
std::string error;
uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);//2 设置属性
if (result != PROP_SUCCESS) {
LOG(ERROR) << "Unable to set property '" << name << "' to '" << value
<< "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
<< error;
}
socket.SendUint32(result);
break;
}
default:
LOG(ERROR) << "sys_prop: invalid command " << cmd;
socket.SendUint32(PROP_ERROR_INVALID_CMD);
break;
}
}
注释1、2处调用HandlePropertySet来设置属性,来看下实现
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
const std::string& source_context, const ucred& cr, std::string* error) {
if (!IsLegalPropertyName(name)) {//检查名字合法性
*error = "Illegal property name";
return PROP_ERROR_INVALID_NAME;
}
if (StartsWith(name, "ctl.")) {//处理以ctl开头的控制属性
if (!CheckControlPropertyPerms(name, value, source_context, cr)) {
*error = StringPrintf("Invalid permissions to perform '%s' on '%s'", name.c_str() + 4,
value.c_str());
return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
}
HandleControlMessage(name.c_str() + 4, value, cr.pid);
return PROP_SUCCESS;
}
const char* target_context = nullptr;
const char* type = nullptr;
property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
*error = "SELinux permission check failed";
return PROP_ERROR_PERMISSION_DENIED;
}
....
return PropertySet(name, value, error);//调用PropertySet设置属性
}
static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
size_t valuelen = value.size();
if (!IsLegalPropertyName(name)) {//1
*error = "Illegal property name";
return PROP_ERROR_INVALID_NAME;
}
if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {//2
*error = "Property value too long";
return PROP_ERROR_INVALID_VALUE;
}
if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
*error = "Value is not a UTF8 encoded string";
return PROP_ERROR_INVALID_VALUE;
}
prop_info* pi = (prop_info*) __system_property_find(name.c_str());
if (pi != nullptr) {
// ro.* properties are actually "write-once".
if (StartsWith(name, "ro.")) {//3
*error = "Read-only property was already set";
return PROP_ERROR_READ_ONLY_PROPERTY;
}
__system_property_update(pi, value.c_str(), valuelen);//4
} else {
int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);//5
if (rc < 0) {
*error = "__system_property_add failed";
return PROP_ERROR_SET_FAILED;
}
}
// Don't write properties to disk until after we have read all default
// properties to prevent them from being overwritten by default values.
if (persistent_properties_loaded && StartsWith(name, "persist.")) {//6
WritePersistentProperty(name, value);
}
property_changed(name, value);//7
return PROP_SUCCESS;
}
- 注释1:检查属性名的合法性
- 注释2:检查属性的长度
- 注释3:检查属性是否以ro开头,如果以ro.开头的属性不可更改
- 注释4:表示属性已经存在,直接更新
- 注释5:调价属性
- 注释6:以persistent开头的属性需要持久化
- 注释7:通知属性改变
3.4 解析init.rc 文件
我们这里要关注的是解析service的rc文件,所以我们来看下启动zygote的脚本语法
system\core\rootdir\init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
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
这里表示让init进程创建zygote,可执行文件路径是/system/bin/app_process64,-Xzygote /system/bin --zygote --start-system-server 这些表示要传递给app_process64的参数,class表示类属,为main,后边会用到他。下边来看下解析的过程
LoadBootScripts(am, sm)
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
return parser;
}
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);//1
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/init.rc");//2
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}
- 注释1:创建3个parse,分别是ServiceParser、ActionParser、ImportParser
- 注释2:解析init.rc
system\core\init\parser.cpp
bool Parser::ParseConfig(const std::string& path) {
size_t parse_errors;
return ParseConfig(path, &parse_errors);
}
bool Parser::ParseConfig(const std::string& path, size_t* parse_errors) {
*parse_errors = 0;
if (is_dir(path.c_str())) {
return ParseConfigDir(path, parse_errors);
}
return ParseConfigFile(path, parse_errors);
}
bool Parser::ParseConfigFile(const std::string& path, size_t* parse_errors) {
LOG(INFO) << "Parsing file " << path << "...";
android::base::Timer t;
auto config_contents = ReadFile(path);
if (!config_contents) {
LOG(ERROR) << "Unable to read config file '" << path << "': " << config_contents.error();
return false;
}
config_contents->push_back('\n'); // TODO: fix parse_config.
ParseData(path, *config_contents, parse_errors);
for (const auto& [section_name, section_parser] : section_parsers_) {
section_parser->EndFile();
}
LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
return true;
}
void Parser::ParseData(const std::string& filename, const std::string& data, size_t* parse_errors) {
// TODO: Use a parser with const input and remove this copy
std::vector<char> data_copy(data.begin(), data.end());
data_copy.push_back('\0');
parse_state state;
state.line = 0;
state.ptr = &data_copy[0];
state.nexttoken = 0;
SectionParser* section_parser = nullptr;
int section_start_line = -1;
std::vector<std::string> args;
auto end_section = [&] {
if (section_parser == nullptr) return;
if (auto result = section_parser->EndSection(); !result) {
(*parse_errors)++;
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();
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.
for (const auto& [prefix, callback] : line_callbacks_) {
if (android::base::StartsWith(args[0], prefix)) {
end_section();
if (auto result = callback(std::move(args)); !result) {
(*parse_errors)++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
break;
}
}
if (section_parsers_.count(args[0])) {//1
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);//2
!result) {
(*parse_errors)++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
section_parser = nullptr;
}
} else if (section_parser) {
if (auto result = section_parser->ParseLineSection(std::move(args), state.line);//3
!result) {
(*parse_errors)++;
LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
}
}
args.clear();//4
break;
case T_TEXT:
args.emplace_back(state.text);
break;
}
}
}
上边的调用过程: ParseConfig->ParseConfigFile->ParseData. 最后调用parseData来解析。
- 注释1:判断是否有对应的Parser(ServiceParser、ActionParser、ImportParser)
- 注释2:如果有对应的Parser,则调用对用Parser的ParseSection来解析
- 注释3:如果第一个参数不是service,on,import则调用前一个parser的ParseLineSection函数,这里相当于解析一个参数块的子项
- 注释4:清空本次解析的数据
我们这边主要关注service的解析,来看下ServiceParser都做了什么
system\core\init\service.cpp
Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
if (args.size() < 3) {
return Error() << "services must have a name and a program";
}
const std::string& name = args[1];
if (!IsValidName(name)) {
return Error() << "invalid service name '" << name << "'";
}
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
if (StartsWith(filename, subcontext.path_prefix())) {
restart_action_subcontext = &subcontext;
break;
}
}
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);//1
return Success();
}
Result<Success> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
return service_ ? service_->ParseLine(std::move(args)) : Success();
}
Result<Success> ServiceParser::EndSection() {
if (service_) {
Service* old_service = service_list_->FindService(service_->name());
if (old_service) {
if (!service_->is_override()) {
return Error() << "ignored duplicate definition of service '" << service_->name()
<< "'";
}
service_list_->RemoveService(*old_service);
old_service = nullptr;
}
service_list_->AddService(std::move(service_));//2
}
return Success();
}
-注释1:构建service对象,当解析完毕会调用EndSection
-注释2:将构建的service对象加入链表
4 init启动zygote
看完service的解析,我们来看zygote的启动,前边的zygote脚本我们可以看出他的类属是main,我们来看下init.rc的脚本
on nonencrypted
class_start main
class_start late_start
class_start是一个cmd,这句话表示启动类属为main的服务,他对应的方法是do_class_start,我们来下他做了什么
system\core\init\builtins.cpp
static Result<Success> do_class_start(const BuiltinArguments& args) {
// 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) {
LOG(ERROR) << "Could not start service '" << service->name()
<< "' as part of class '" << args[1] << "': " << result.error();
}
}
}
return Success();
}
来看下StartIfNotDisabled做了什么
system\core\init\service.cpp
Result<Success> Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
return Success();
}
Result<Success> Service::Start() {
bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
// 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().
if (flags_ & SVC_RUNNING) {//1
if ((flags_ & SVC_ONESHOT) && disabled) {
flags_ |= SVC_RESTART;
}
// It is not an error to try to start a service that is already running.
return Success();
}
bool needs_console = (flags_ & SVC_CONSOLE);
if (needs_console) {
if (console_.empty()) {
console_ = default_console;
}
// Make sure that open call succeeds to ensure a console driver is
// properly registered for the device node
int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
if (console_fd < 0) {
flags_ |= SVC_DISABLED;
return ErrnoError() << "Couldn't open console '" << console_ << "'";
}
close(console_fd);
}
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {//2
flags_ |= SVC_DISABLED;
return ErrnoError() << "Cannot find '" << args_[0] << "'";
}
....
LOG(INFO) << "starting service '" << name_ << "'...";
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork();//3
}
if (pid == 0) {
umask(077);
if (auto result = EnterNamespaces(); !result) {
LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error();
}
if (namespace_flags_ & CLONE_NEWNS) {
if (auto result = SetUpMountNamespace(); !result) {
LOG(FATAL) << "Service '" << name_
<< "' could not set up mount namespace: " << result.error();
}
}
if (namespace_flags_ & CLONE_NEWPID) {
// This will fork again to run an init process inside the PID
// namespace.
if (auto result = SetUpPidNamespace(); !result) {
LOG(FATAL) << "Service '" << name_
<< "' could not set up PID namespace: " << result.error();
}
}
for (const auto& [key, value] : environment_vars_) {
setenv(key.c_str(), value.c_str(), 1);
}
std::for_each(descriptors_.begin(), descriptors_.end(),
std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
// See if there were "writepid" instructions to write to files under /dev/cpuset/.
auto cpuset_predicate = [](const std::string& path) {
return StartsWith(path, "/dev/cpuset/");
};
auto iter = std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate);
if (iter == writepid_files_.end()) {
// There were no "writepid" instructions for cpusets, check if the system default
// cpuset is specified to be used for the process.
std::string default_cpuset = GetProperty("ro.cpuset.default", "");
if (!default_cpuset.empty()) {
// Make sure the cpuset name starts and ends with '/'.
// A single '/' means the 'root' cpuset.
if (default_cpuset.front() != '/') {
default_cpuset.insert(0, 1, '/');
}
if (default_cpuset.back() != '/') {
default_cpuset.push_back('/');
}
writepid_files_.push_back(
StringPrintf("/dev/cpuset%stasks", default_cpuset.c_str()));
}
}
std::string pid_str = std::to_string(getpid());
for (const auto& file : writepid_files_) {
if (!WriteStringToFile(pid_str, file)) {
PLOG(ERROR) << "couldn't write " << pid_str << " to " << file;
}
}
if (ioprio_class_ != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) {
PLOG(ERROR) << "failed to set pid " << getpid()
<< " ioprio=" << ioprio_class_ << "," << ioprio_pri_;
}
}
if (needs_console) {
setsid();
OpenConsole();
} else {
ZapStdio();
}
// As requested, set our gid, supplemental gids, uid, context, and
// priority. Aborts on failure.
SetProcessAttributes();
if (!ExpandArgsAndExecv(args_)) {//4
PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
}
_exit(127);
}
....
return Success();
}
static bool ExpandArgsAndExecv(const std::vector<std::string>& args) {
std::vector<std::string> expanded_args;
std::vector<char*> c_strings;
expanded_args.resize(args.size());
c_strings.push_back(const_cast<char*>(args[0].data()));
for (std::size_t i = 1; i < args.size(); ++i) {
if (!expand_props(args[i], &expanded_args[i])) {
LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'";
}
c_strings.push_back(expanded_args[i].data());
}
c_strings.push_back(nullptr);
return execv(c_strings[0], c_strings.data()) == 0;
}
- 注释1:如果服务已经启动,则不启动它
- 注释2:判断需要启动的Service的对应的执行文件是否存在,不存在则不启动该Service
- 注释3:通过fork函数创建子进程
- 注释4:通过execv执行system/bin/app_process64
通过上边分析,函数进入到了framework/cmds/app_process/app_main.cpp的main函数,如下所示:
int main(int argc, char* const argv[])
{
...
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//1
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}
- 注释1:通过runtime.start来启动zygote
5 init总结
通过本分的分析。我们知道了init进程做了如下工作:
- 创建并挂载设备
- 初始化并启动属性服务
- 解析init.rc并启动zygote
参考资料:
《深入理解Android卷1》