Android 1号进程init

(一) Init启动

从按电源键开始涉及到的关键流程步骤:

  1. 设备上电后CPU复位,指向Boot ROM上一个固定地址,并开始执行此处程序。
  2. 上述程序的作用是读取并加载启动设备上的引导程序Boot Loader到RAM中。
  3. CPU指向引导程序入口开始执行:初始化堆栈、硬件、内存等操作。
  4. 引导程序加载Android内核[boot.img]到RAM中,并从main入口开始执行Kernel初始化。
  5. Kernel初始化完成后,在用户空间启动init进程,调用init进程中的main方法初始化。

Init是Android系统中用户空间的第一个进程,进程号是1,父进程是0

从下图中可以看出:进程1和进程2的父进程都是0,其他进程直接或间接继承进程1或进程2.

进程0 (PID = 0) 运行在内核态,是系统创建的第一个进程, 也是唯一一个没有通过fork或者kernel_thread产生的进程.

static noinline void __ref rest_init(void)

{

struct task_struct *tsk;

int pid;

… …

pid = kernel_thread(kernel_init, NULL, CLONE_FS);

… …

pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

… …

complete(&kthreadd_done);

}

在内核初始化start_kernel()最后rest_init()中,从进程0复制创建init和kthreadd:

  • init进程 (PID = 1, PPID = 0)
  • kthreadd进程(PID = 2, PPID = 0)

init 进程 (pid = 1, ppid = 0) ,其他用户空间进程的 ppid 都是1或间接继承;

kthreadd进程负责内核线程的创建、维护等工作,内核中其他进程PPID都是2,都是由kthreadd进程创建.

(二) Init初始化 [ system/core/init ]

init 进程初始化做了很多工作,主要做了以下三件事:

创建(mkdir)和挂载(mount)启动所需的文件目录;

初始化和启动属性服务(property service)

解析 init.rc 配置文件并启动本地服务进程及Zygote 进程;

Android 新版本对 init 改动较大,入口换成了system/core/init/main.cpp 的 main 函数,分阶段启动:

// system/core/init/main.cpp
int main(int argc, char** argv) {
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap function_map;
            return SubcontextMain(argc, argv, &function_map);
        }
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
    return FirstStageMain(argc, argv); 
}

第一阶段:创建和挂载文件系统

init 进程的第一个阶段主要是用来创建和挂载启动所需的文件目录,其中挂载了 tmpfs、devpts、proc、sysfs 和 selinuxfs 共 5 种文件系统,这些都是系统运行时目录,只有在系统运行时才会存在,系统停止时会消失。

system/core/init/first_stage_init.cpp: 设置用户组,挂载文件系统

四类文件系统:

tmpfs:一种虚拟内存文件系统,它会将所有的文件存储在内存中; 由于 tmpfs 是驻留在 RAM 的,因此它的内容是不持久的。断电后,tmpfs 的内容就消失了.

devpts:为伪终端提供了一个标准接口

proc:可以看作是内核内部数据结构的接口,通过它我们可以获得系统信息,同时也能够在运行时修改特定的内核参数;

sysfs:与 proc 文件系统类似,也是一个虚拟文件系统。它通常被挂接在 /sys 目录下。它把连接在系统上的设备和总线组织成一个分级的文件,使得它们可以在用户空间存取;

system/core/init/selinux.cpp: 主要实现SeLinux初始化

第二阶段:初始化启动属性服务

system/core/init/init.cpp:

  1. 重定向标准输入/输出为空,初始化内核日志服务,记录开机时间

  1. property_init() 属性初始化

system/core/init/property_service.cpp
void PropertyInit() {
    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";
    }
    ExportKernelBootProps();
    PropertyLoadBootDefaults();
}

__system_property_area_init() 老版本调用fd = ashmem_create_region(name,size)创建32k/128k大小共享内存空间

typedef struct {

    void *data;   //存储空间的起始地址 pa

    size_tsize;  //存储空间的大小

    int fd;   //共享内存的文件描写叙述符

} workspace;

__system_property_area__ = pa [共享内存起始地址]; bionic libc库中输出的一个变量

client访问:

当bionic libc库被载入时会调用__libc_prenit函数,函数内实现共享内存到本地进程映射:

fd =getenv("ANDROID_PROPERTY_WORKSPACE");

pa =mmap(0, sz, PROT_READ, MAP_SHARED, fd, 0); //mmap设置client为只读属性

__system_property_area__ = pa

新版本实现:

PropertyLoadBootDefaults() 载入系统属性

   if (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
        if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
            load_properties_from_file("/default.prop", nullptr, &properties);
        }
    }
    load_properties_from_file("/system/build.prop", nullptr, &properties);
    load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
    load_properties_from_file("/vendor/default.prop", nullptr, &properties);
    load_properties_from_file("/vendor/build.prop", nullptr, &properties);
    if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
        load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
    } else {
        load_properties_from_file("/odm/default.prop", nullptr, &properties);
        load_properties_from_file("/odm/build.prop", nullptr, &properties);
    }
    load_properties_from_file("/product/build.prop", nullptr, &properties);
    load_properties_from_file("/factory/factory.prop", "ro.*", &properties);

老版本载入/data/property下的persist属性: load_persistent_properties();

  1. 监听处理子进程信号

InstallSignalFdHandler 函数用于设置子进程信号处理函数,在子进程终止的时候发出 SIGCHLD 信号,而 InstallSignalFdHandler 函数是用来接收 SIGCHLD 信号的,其内部只处理进程终止的 SIGCHLD 信号。

static void InstallSignalFdHandler(Epoll* epoll) {
    // Applying SA_NOCLDSTOP to a defaulted SIGCHLD handler prevents the signalfd from receiving
    // SIGCHLD when a child process stops or continues (b/77867680#comment9).
    const struct sigaction act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP };
    sigaction(SIGCHLD, &act, nullptr);
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);
}
  1. StartPropertyService 启动属性服务

system/core/init/property_service.cpp
void StartPropertyService(int* epoll_socket) {
    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, {});
        result.ok()) {
        property_set_fd = *result;
    }
    listen(property_set_fd, 8);
    auto new_thread = std::thread{PropertyServiceThread};
    property_service_thread.swap(new_thread);
}
 
static void PropertyServiceThread() {
     if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
         !result.ok()) {
         LOG(FATAL) << result.error();
     }
     while(true){
       auto pending_functions = epoll.Wait(std::nullopt);
        if (!pending_functions.ok()) {
            LOG(ERROR) << pending_functions.error();
        } else {
            for (const auto& function : *pending_functions) {
                (*function)();
            }
        }
     }
}

创建并监听一个用来接收请求的socket,将 property_set_fd 放入了 epoll 中来监听,当 property_set_fd 中有数据到来时,收到client请求时调用handle_property_set_fd进行处理:

static void handle_property_set_fd() {
    int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
    SocketConnection socket(s, cr);
    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: {
        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;
        }
        uint32_t result = HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);

system/core/init/property_service.cpp
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                           const std::string& source_context, const ucred& cr, std::string* error) {
	// 如果属性名称以ctl.开头,说明是控制属性
    if (StartsWith(name, "ctl.")) {
        HandleControlMessage(name.c_str() + 4, value, cr.pid);
        return PROP_SUCCESS;
    }
    return PropertySet(name, value, error);
}


static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
	//从属性存储空间查找属性
    prop_info* pi = (prop_info*) __system_property_find(name.c_str());
    if (pi != nullptr) { //属性存在
        if (StartsWith(name, "ro.")) {
            *error = "Read-only property was already set";
            return PROP_ERROR_READ_ONLY_PROPERTY;
        }
		//更新属性值
        __system_property_update(pi, value.c_str(), valuelen);
    } else { //不存在新增
        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
        if (rc < 0) {
            *error = "__system_property_add failed";
            return PROP_ERROR_SET_FAILED;
        }
    }
    //"persist."属性的特殊处理
    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
        WritePersistentProperty(name, value);
    }
    property_changed(name, value); // on section trigger
}

ro属性为只读,重启不失效,不能修改,只能刷机改变。

persist属性可修改,同时写入/data/property,重启后保留修改后的属性。

其他属性都是临时存在内存中,重启就失效了。

ctl控制属性需要特殊处理。

  1. Client 发送端:

int property_set(const char *key, const char*value){

   msg.cmd = PROP_MSG_SETPROP;

   strcpy((char*) msg.name, key);

   strcpy((char*) msg.value, value);

 //建立和属性server的socket连接

    s =socket_local_client(PROP_SERVICE_NAME,

                           ANDROID_SOCKET_NAMESPACE_RESERVED,

                            SOCK_STREAM);

//通过socket发送出去

    while((r = send(s, msg, sizeof(prop_msg), 0)) < 0) {

       if((errno == EINTR) || (errno == EAGAIN)) continue;

       break;

    }

}

第三阶段:解析init.rc启动服务

int SecondStageMain(int argc, char** argv) {
    InitializeSubcontext();
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    LoadBootScripts(am, sm);


    am.QueueEventTrigger("early-init");
    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    am.QueueEventTrigger("init");


    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else if (bootmode == "cali"){
        am.QueueEventTrigger("cali");
    } else if (bootmode == "factorytest"){
        am.QueueEventTrigger("factorytest");
    } else {
        am.QueueEventTrigger("late-init");
    }


    // Run all property triggers based on current state of the properties.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
    while (true) {
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            if (am.HasMoreCommands()) epoll_timeout = 0ms;
        }
        auto pending_functions = epoll.Wait(epoll_timeout);
        if (!pending_functions.ok()) {
        } else if (!pending_functions->empty()) {
            for (const auto& function : *pending_functions) {
                (*function)();
            }
        }
    }
}

启动init subcontext进程

InitializeSubcontext 进行vendor/odm初始化

加载rc配置文件LoadBootScripts(am, sm)

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

AIL语法

Android 8.以后对 init.rc 文件进行了拆分,每个服务对应一个 init.xxx.rc 文件;

从基础rc文件开始逐步导入所有需要的init.xxx.rc文件。

RC文件中的Action和Service是以Section的形式出现的,每个Action Section可以含有若干Command,而每个ServiceSection可以含有若干Option。

Section只有起始标记,没有明确的结束标记,是用“后一个Section”的起始来结束“前一个Section”。

Service不能出现重名, Action可以重复,但最后会合并到一起。

import则是导入其它init.*.rc用的,如import /init.${ro.hardware}.rc。

Action需要有一个触发器(trigger)来触发它,一旦满足了触发条件,这个Action就会被加到执行队列的末尾

init.rc 是非常重要的配置文件,由 Android 初始化语言(Android Init Language) 编写的脚本,这种语言主要包含 5 种类型语句:

Action(行为)

Command(命令)

Service(服务)

Option(选项)

Import(引入)

init.xxx.rc 文件内容大致分为两大部分:

以 on 关键字开头的“动作列表”(action list)

on <triggger> [&& <trigger>]* // 设置触发器 
   <command> // 动作触发之后要执行的命令 
   <command> 
   ... ...

动作列表用于创建所需目录以及为某些特定文件指定权限

on init
    sysclktz 0
    copy /proc/cmdline /dev/urandom
    copy /system/etc/prop.default /dev/urandom
on boot
    ifup lo
    hostname localhost
    domainname localdomain
on property:sys.boot_from_charger_mode=1
    class_stop charger
    trigger late-init

以 service 关键字开头的“服务列表”(service list)

service <name> <pathname> [<argument>]* // <service的名字><执行程序路径><传递参数>
	<option>  // 控制服务启动的时间,方式,用户及参数等
	<option>
	...

服务列表用来记录 init 进程需要启动的一些子进程

service ueventd /system/bin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
    shutdown critical

Command命令列表:

atic const BuiltinFunctionMap builtin_functions = {
        {"bootchart",               {1,     1,    {false,  do_bootchart}}},
        {"chmod",                   {2,     2,    {true,   do_chmod}}},
        {"chown",                   {2,     3,    {true,   do_chown}}},
        {"class_reset",             {1,     1,    {false,  do_class_reset}}},
        {"class_reset_post_data",   {1,     1,    {false,  do_class_reset_post_data}}},
        {"class_restart",           {1,     1,    {false,  do_class_restart}}},
        {"class_start",             {1,     1,    {false,  do_class_start}}},
        {"class_start_post_data",   {1,     1,    {false,  do_class_start_post_data}}},
        {"class_stop",              {1,     1,    {false,  do_class_stop}}},
        {"copy",                    {2,     2,    {true,   do_copy}}},
        {"domainname",              {1,     1,    {true,   do_domainname}}},
        {"enable",                  {1,     1,    {false,  do_enable}}},
        {"exec",                    {1,     kMax, {false,  do_exec}}},
        {"exec_background",         {1,     kMax, {false,  do_exec_background}}},
        {"exec_start",              {1,     1,    {false,  do_exec_start}}},
        {"export",                  {2,     2,    {false,  do_export}}},
        {"hostname",                {1,     1,    {true,   do_hostname}}},
        {"ifup",                    {1,     1,    {true,   do_ifup}}},
        {"init_user0",              {0,     0,    {false,  do_init_user0}}},
        {"insmod",                  {1,     kMax, {true,   do_insmod}}},
        {"installkey",              {1,     1,    {false,  do_installkey}}},
        {"interface_restart",       {1,     1,    {false,  do_interface_restart}}},
        {"interface_start",         {1,     1,    {false,  do_interface_start}}},
        {"interface_stop",          {1,     1,    {false,  do_interface_stop}}},
        {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
        {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
        {"loglevel",                {1,     1,    {false,  do_loglevel}}},
        {"mark_post_data",          {0,     0,    {false,  do_mark_post_data}}},
        {"mkdir",                   {1,     6,    {true,   do_mkdir}}},
        // TODO: Do mount operations in vendor_init.
        // mount_all is currently too complex to run in vendor_init as it queues action triggers,
        // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
        // mount and umount are run in the same context as mount_all for symmetry.
        {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
        {"mount",                   {3,     kMax, {false,  do_mount}}},
        {"perform_apex_config",     {0,     0,    {false,  do_perform_apex_config}}},
        {"umount",                  {1,     1,    {false,  do_umount}}},
        {"umount_all",              {1,     1,    {false,  do_umount_all}}},
        {"update_linker_config",    {0,     0,    {false,  do_update_linker_config}}},
        {"readahead",               {1,     2,    {true,   do_readahead}}},
        {"remount_userdata",        {0,     0,    {false,  do_remount_userdata}}},
        {"restart",                 {1,     1,    {false,  do_restart}}},
        {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
        {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
        {"rm",                      {1,     1,    {true,   do_rm}}},
        {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
        {"setprop",                 {2,     2,    {true,   do_setprop}}},
        {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
        {"start",                   {1,     1,    {false,  do_start}}},
        {"stop",                    {1,     1,    {false,  do_stop}}},
        {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
        {"enter_default_mount_ns",  {0,     0,    {false,  do_enter_default_mount_ns}}},
        {"symlink",                 {2,     2,    {true,   do_symlink}}},
        {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
        {"trigger",                 {1,     1,    {false,  do_trigger}}},
        {"verity_update_state",     {0,     0,    {false,  do_verity_update_state}}},
        {"wait",                    {1,     2,    {true,   do_wait}}},
        {"wait_for_prop",           {2,     2,    {false,  do_wait_for_prop}}},
        {"write",                   {2,     2,    {true,   do_write}}},
    };

Option选项列表:

static const KeywordMap<ServiceParser::OptionParser> parser_map = {
        {"capabilities",            {0,     kMax, &ServiceParser::ParseCapabilities}},
        {"class",                   {1,     kMax, &ServiceParser::ParseClass}},//设置service所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;常见的类名有:main、core、charge
        {"console",                 {0,     1,    &ServiceParser::ParseConsole}},
        {"critical",                {0,     0,    &ServiceParser::ParseCritical}},//设备关键服务,4分钟内重启超过4次会进入recovery模式  
        {"disabled",                {0,     0,    &ServiceParser::ParseDisabled}},//不跟随class启动  
        {"enter_namespace",         {2,     2,    &ServiceParser::ParseEnterNamespace}},
        {"file",                    {2,     2,    &ServiceParser::ParseFile}},
        {"group",                   {1,     NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},//服务用户组设置  
        {"interface",               {2,     2,    &ServiceParser::ParseInterface}},
        {"ioprio",                  {2,     2,    &ServiceParser::ParseIoprio}},//io 操作优先级设置  
        {"keycodes",                {1,     kMax, &ServiceParser::ParseKeycodes}},
        {"memcg.limit_in_bytes",    {1,     1,    &ServiceParser::ParseMemcgLimitInBytes}},
        {"memcg.limit_percent",     {1,     1,    &ServiceParser::ParseMemcgLimitPercent}},
        {"memcg.limit_property",    {1,     1,    &ServiceParser::ParseMemcgLimitProperty}},
        {"memcg.soft_limit_in_bytes",
                                    {1,     1,    &ServiceParser::ParseMemcgSoftLimitInBytes}},
        {"memcg.swappiness",        {1,     1,    &ServiceParser::ParseMemcgSwappiness}},
        {"namespace",               {1,     2,    &ServiceParser::ParseNamespace}},
        {"oneshot",                 {0,     0,    &ServiceParser::ParseOneshot}},//sevice退出后不再重启  
        {"onrestart",               {1,     kMax, &ServiceParser::ParseOnrestart}},,//当服务重启时执行相关的command  
        {"oom_score_adjust",        {1,     1,    &ServiceParser::ParseOomScoreAdjust}},
        {"override",                {0,     0,    &ServiceParser::ParseOverride}},
        {"priority",                {1,     1,    &ServiceParser::ParsePriority}},
        {"reboot_on_failure",       {1,     1,    &ServiceParser::ParseRebootOnFailure}},
        {"restart_period",          {1,     1,    &ServiceParser::ParseRestartPeriod}},
        {"rlimit",                  {3,     3,    &ServiceParser::ParseProcessRlimit}},
        {"seclabel",                {1,     1,    &ServiceParser::ParseSeclabel}},
        {"setenv",                  {2,     2,    &ServiceParser::ParseSetenv}},//设置service环境变量  
        {"shutdown",                {1,     1,    &ServiceParser::ParseShutdown}},
        {"sigstop",                 {0,     0,    &ServiceParser::ParseSigstop}},
        {"socket",                  {3,     6,    &ServiceParser::ParseSocket}},创建socket  
        {"stdio_to_kmsg",           {0,     0,    &ServiceParser::ParseStdioToKmsg}},
        {"timeout_period",          {1,     1,    &ServiceParser::ParseTimeoutPeriod}},
        {"updatable",               {0,     0,    &ServiceParser::ParseUpdatable}},
        {"user",                    {1,     1,    &ServiceParser::ParseUser}},//设置service的用户
        {"writepid",                {1,     kMax, &ServiceParser::ParseWritepid}},
    };

服务启动顺序

init将动作运行的时间划分为多个阶段:

early-init

init

late-init

early-fs

fs

post-fs

late-fs

post-fs-data

load_persist_props_action

firmware_mounts_complete

early-boot

boot [do_class_start]

每个action完成的任务:

  • Early-Init :设置init 进程 score adj值,重置安全上下文,启动uevent服务
  • Wait-for-coldboot-done:wait uevent_main – device_init完成coldboot_done目录创建,Timeout 1s
  • keychord_init:keychord是组合按键,keychord为每个服务配置组合键,在服务解析时为指定服务设置相应的键码值。
  • console-init:如果ro.boot.console指定了控制台终端,那么优先使用这个控制台,如果没有指定,那么将使用默认控制台终端/dev/console。
  • late-init: trigger early-fs fs post-fs  post-fs-data load_persist_props_action firmware_mounts_complete early-boot boot
  • early-fs:设置外部存储环境变量
  • fs:挂载mtd分区,创建adb设备目录,修改adf设备文件权限
  • post-fs:修改productinfo用户群组,改变系统目录访问权限(kmsg、vmallcoinfo、cache等)
  • Load_system_props_action:load property file,"/system/build.prop" “/vendor/build.prop” “/factory/factory.prop”
  • Post-fs-data:创建、改变/data目录以及它的子目录的访问权限,启动vold、debuggerd服务,bootchart_init.
  • Load_presist_props_action:启动logd服务,load property file /data/property,"/data/local.prop"
  • Firmware_mounts_complete:删除dev/.booting目录
  • Early-boot:修改proc、sys/class子目录访问权限
  • Boot:设置usb厂商参数、CPU参数,修改sensorhub、 bluetooth、gnss、thermal目录访问权限,网络参数设置。启动Core class service。
  • Nonencrypted:启动 main、late_start class service.

class_start是一个COMMAND,相应的函数为do_class_start, 位于boot section的范围内

当init进程运行到以下几句话时。do_class_start就会被运行了

//将bootsection节的command加入到运行队列

action_for_each_trigger("boot",action_add_queue_tail);

SVC_DISABLED:不随class自己主动启动。以下将会看到class的作用。

SVC_ONESHOT:退出后不须要重新启动,也就是这个service仅仅启动一次就能够了。

SVC_RUNNING:正在运行,这是service的状态。

SVC_RESTARTING:等待重新启动,这也是service的状态。

SVC_CONSOLE:该service须要使用控制台 。

SVC_CRITICAL:假设在规定时间内该service不断重新启动,则系统会重新启动并进入恢复模式。

假设设置了SVC_CRITICAL标示,则4分钟内该服务重新启动次数不能超过4次。否则机器会重新启动进入recovery模式。

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
    socket usap_pool_primary 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

System_Server启动

         zygote启动System_Server

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值