美文网首页
《深入理解Android卷 I》- 第三章 - Init - 读

《深入理解Android卷 I》- 第三章 - Init - 读

作者: pokerWu | 来源:发表于2017-01-13 15:32 被阅读0次

    1 概述

    init是一个进程,确切地说,它是Linux系统中用户空间的第一个进程。由于Android是基于Linux内核的,所以init也是Android系统中用户空间的第一个进程,它的进程号是1
    职责:

    • init进程负责创建系统中的几个关键进程,尤其是Zygote,它更是Java世界的开创者。
    • Android系统有很多属性,于是init就提供了一个propertyService(属性服务)来管理它们。

    2 init分析

    init进程入口:
    system/core/init/init.cpp

    int main(int argc, char** argv) {
        // 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.
        if (is_first_stage) {
            ...
            //创建一些文件夹
            mkdir("/dev/pts", 0755);
            mkdir("/dev/socket", 0755);
            //挂载linux系统文件
            mount("devpts", "/dev/pts", "devpts", 0, NULL);
            ...
            early_mount();
        }
        //重定向标准输入,标准输出,标准错误输出到 /dev/null
        InitKernelLogging(argv);
        if (!is_first_stage) {
            // Indicate that booting is in progress to background fw loaders, etc.
            //在/dev目录创建一个空文件.booting来表示正在执行初始化
            close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
            //初始化和属性相关的资源
            property_init();
            // If arguments are passed both on the command line and in DT,properties set in DT always have priority over the command-line ones.
            process_kernel_dt();
            process_kernel_cmdline();
            // Propagate the kernel variables to internal variables
            //将内核变量设置到内部变量
            // used by init as well as the current required properties.
            export_kernel_boot_props();
        }
        // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
        //加载SELinux策略, 后面有一些初始化文件上下文的操作等
        selinux_initialize(is_first_stage);
        ...
        //初始化子进程退出的信号处理过程
        signal_handler_init();
        //加载/default.prop文件
        property_load_boot_defaults();
        export_oem_lock_status();
        //启动属性服务器(通过socket通信)
        start_property_service();
        set_usb_controller();
        //为Action设置<command>处理函数
        const BuiltinFunctionMap function_map;
        Action::set_function_map(&function_map);
        //解析init.rc文件
        Parser& parser = Parser::GetInstance();
        //设置对应的解析函数 “service”块以关键字“service”开始,表示启动某个进程的方式和参数
        parser.AddSectionParser("service",std::make_unique<ServiceParser>());
        //“action”块以关键字“on”开始,表示一堆命令的集合
        parser.AddSectionParser("on", std::make_unique<ActionParser>());
        //“import”是用来引入一个init配置文件,来扩展当前配置的
        parser.AddSectionParser("import", std::make_unique<ImportParser>());
        parser.ParseConfig("/init.rc");
        //actionManager
        ActionManager& am = ActionManager::GetInstance();
        am.QueueEventTrigger("early-init"); //earkay-init trigger
        // 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");
        // ... 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(keychord_init_action, "keychord_init");
        am.QueueBuiltinAction(console_init_action, "console_init");
        // Trigger all the boot actions to get us started.
        am.QueueEventTrigger("init"); // init trigger
         // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
        // wasn't ready immediately after wait_for_coldboot_done
        am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
       // Don't mount filesystems or start core system services in charger mode.充电模式下不加载系统服务
        std::string bootmode = property_get("ro.bootmode");
        if (bootmode == "charger") {
            am.QueueEventTrigger("charger");
        } 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 (!waiting_for_exec) {
                //依次执行每个action中携带command对应的执行函数
                am.ExecuteOneCommand();
                //重启一些挂掉的进程
                restart_processes();
            }
            //以下决定timeout的时间,将影响while循环的间隔
            int timeout = -1;
            //有进程需要重启时,等待该进程重启
            if (process_needs_restart) {
                timeout = (process_needs_restart - gettime()) * 1000;
                if (timeout < 0)
                    timeout = 0;
            }
            //有action待处理,不等待
            if (am.HasMoreCommands()) {
                timeout = 0;
            }
            //bootchart_sample应该是进行性能数据采样
            bootchart_sample(&timeout);
            epoll_event ev;
            //没有事件到来的话,最多阻塞timeout时间
            int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
            if (nr == -1) {
               PLOG(ERROR) << "epoll_wait failed";
            } else if (nr == 1) {
                //有事件到来,执行对应处理函数
                //根据上文知道,epoll句柄(即epoll_fd)主要监听子进程结束,及其它进程设置系统属性的请求。
                ((void (*)()) ev.data.ptr)();
            }
        }
        }
    

    Android在init过程中分别挂载了tmpfs,devpts,proc,sysfs这4类文件系统。

    2.1 配置文件解析

    system/core/rootdir/init.rc
    其中init.rc文件在Android系统运行过程中用于通用的环境设置与进程相关的定义,init.{hardware}.rc(例如,高通有init.qcom.rc,MTK有init.mediatek.rc)用于定义Android在不同平台下的特定进程和环境设置等。此处解析函数传入的参数为“/init.rc”,解析的是运行时与init进程同在根目录下的init.rc文件。
    主要有两部分:

    • on
      on <trigger>
      <command>
      <command>
      <command>
      Action其实就是一序列的CommandsAction都有一个trigger,它被用于决定action的执行时间。当一个符合action触发条件的事件发生时,action会被加入到执行队列的末尾。
      队列中的每一个action都会被提取出,而这个action中的每个command都将被依次执行。Init在这些命令的执行期间还控制着其他的活动

    on early-init
    //Set init and its forked children's oom_adj.
    write /proc/1/oom_score_adj -1000
    ...
    start ueventd

    • service
      service <name> <pathname> [ <argument> ]*
      Services是一个程序,他在初始化时启动,并在退出时重启(可选)。

    service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0

    借助系统环境变量或Linux命令,on列表用于创建所需目录,以及为某些特定文件指定权限,而服务列表用来记录init进程需要启动的一些子进程。如上面代码所示,service关键字后的第一个字符串表示服务(子进程)的名称,第二个字符串表示服务的执行路径。

    2.1.1 解析init.rc

    system/core/inti/inti_pareser.cpp

    bool Parser::ParseConfig(const std::string& path) {
        if (is_dir(path.c_str())) {
            return ParseConfigDir(path);
        }
        //init.cpp中传入的是"/init.rc"是文件
        return ParseConfigFile(path);
    }
    
    Parser::ParseConfigFile(const std::string& path) {
        Timer t;
        std::string data;
        //读取指定文件的内容,以string保存
        if (!read_file(path.c_str(), &data)) {
            return false;
        }
       ...
       ParseData(path, data);
        ...
    }
    

    Parser::ParseData(const std::string& filename, const std::string& data)根据关键字解析出服务和动作。动作与服务会分别放在了Action::ActionManager.actions_Service::ServiceManager.services_

    bool Parser::ParseConfig(const std::string& path) {
        if (is_dir(path.c_str())) {
            return ParseConfigDir(path);
        }
        //init.cpp中传入的是"/init.rc"是文件
        return ParseConfigFile(path);
    }
    
    
    Parser::ParseConfigFile(const std::string& path) {
        Timer t;
        std::string data;
        //读取指定文件的内容,以string保存
        if (!read_file(path.c_str(), &data)) {
            return false;
        }
       ...
       ParseData(path, data);
        ...
    }
    

    Parser::ParseData(const std::string& filename, const std::string& data)根据关键字解析出服务和动作。动作与服务会分别放在了Action::ActionManager.actions_Service::ServiceManager.services_

    void Parser::ParseData(const std::string& filename, const std::string& data) {
        std::vector<char> data_copy(data.begin(), data.end());
        data_copy.push_back('\0');
        parse_state state;
        ...
        SectionParser* section_parser = nullptr;
        std::vector<std::string> args;
        for (;;) {
            //next_token以行为单位分割参数传递过来的字符串
            //最先走到T_TEXT分支
            switch (next_token(&state)) {
            case T_EOF:
                if (section_parser) {
                    //EOF,解析结束
                    section_parser->EndSection();
                }
                return;
            case T_NEWLINE:
                state.line++;
                if (args.empty()) {
                    break;
                }
                 //在init.cpp::main()创建parser时,为service,on,import定义了对应的parser 
                //这里就是根据第一个参数,判断是否有对应的parser
                if (section_parsers_.count(args[0])) {
                    if (section_parser) {
                       //结束上一个parser的工作,将构造出的对象加入到对应的service_list与action_list中
                        section_parser->EndSection();
                    }
                    //获取参数对应的parser
                    section_parser = section_parsers_[args[0]].get();
                    std::string ret_err;
                    //调用实际parser的ParseSection函数
                    if (!section_parser->ParseSection(args, &ret_err)) {
                        parse_error(&state, "%s\n", ret_err.c_str());
                        section_parser = nullptr;
                    }
                } else if (section_parser) {
                    //如果第一个参数不是service,on,import
                    //则调用前一个parser的ParseLineSection函数
                    //这里相当于解析一个参数块的子项
                    std::string ret_err;
                    if (!section_parser->ParseLineSection(args, state.filename,state.line, &ret_err)) {
                        parse_error(&state, "%s\n", ret_err.c_str());
                    }
                }
                args.clear();
                break;
            case T_TEXT:
                //将本次解析的内容写入到args中
                args.emplace_back(state.text);
                break;
            }
        }
    }
    

    2.1.2 解析Service

    system/core/init/service.cpp
    从上面代码可知解析init.rc时section_parser->ParseSection(args, &ret_err)来接解析,在之前为每种section都设置了解析函数,service对应的解析函数就service.cpp::ServiceParser::ParseSection(onst std::vector<std::string>& args, std::string* err)

    bool ServiceParser::ParseSection(const std::vector<std::string>& args,std::string* err) {
        ...
        const std::string& name = args[1];
        ...
        //service section 对应为"service ueventd /sbin/ueventd...",下面就是讲name后的参数全部放在一个vector中
         std::vector<std::string> str_args(args.begin() + 2, args.end());
         //构造一个service对象
        service_ = std::make_unique<Service>(name, "default", str_args);
        return true;
    }
    

    在解析将一个section解析结束后会调用ServiceParser::EndSection()

    void ServiceParser::EndSection() {
        if (service_) {
            ServiceManager::GetInstance().AddService(std::move(service_));
        }
    }
    //
     void ServiceManager::AddService(std::unique_ptr<Service> service) {
        Service* old_service = FindServiceByName(service->name());
        if (old_service) {
            return;
        }
        //添加到services_中 (`ServicePaser::ServiceManager`中的一个vector)
        services_.emplace_back(std::move(service));
    }
    

    2.1.3 解析action

    ActionParser定义于system/core/init/action.cpp中。Action的解析过程,其实与Service差不多

    //解析 on <trigger>
    bool ActionParser::ParseSection(const std::vector<std::string>& args, std::string* err) {
        std::vector<std::string> triggers(args.begin() + 1, args.end());
       ...
       auto action = std::make_unique<Action>(false);
       //根据参数,填充action的trigger域
        if (!action->InitTriggers(triggers, err)) {
            return false;
        }
        action_ = std::move(action);
        return true;
    }
    
    //解析 <command>
    bool ActionParser::ParseLineSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) const {
        return action_ ? action_->AddCommand(args, filename, line, err) : false;
    }
    
    bool Action::AddCommand(const std::vector<std::string>& args,const std::string& filename, int line, std::string* err) {
       ...
       //找出action对应的执行函数
       auto function = function_map_->FindFunction(args[0], args.size() - 1, err);
        ...
        AddCommand(function, args, filename, line);
        return true;
    }
    
    //构造出command,加入到action对象的commands_中
    void Action::AddCommand(BuiltinFunction f,const std::vector<std::string>& args, const std::string& filename, int line) {
        commands_.emplace_back(f, args, filename, line);
    }
    
    //完成一次action解析
    void ActionParser::EndSection() {
        if (action_ && action_->NumCommands() > 0) {
            ActionManager::GetInstance().AddAction(std::move(action_));
        }
    }
    

    2.1.4 init控制service

    启动zygote
    actionon late-init中会执行 triger boot,on boot下有个class_start core 的commond,对应的处理函数式Builtins::do_class_start(const std::vector<std::string>& args)
    system/core/init/Builtins.cpp

    static int do_class_start(const std::vector<std::string>& args) {
            /* Starting a class does not start services
             * which are explicitly disabled.  They must
             * be started individually.
             */
             //传递一个匿名函数,在找到对应的service后执行StartIfNotDisabled()
        ServiceManager::GetInstance().ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
        return 0;
    }
    
    //init.${zygote}.rc中 zygote  class main
    //以下在/system/core/init/service.cpp中
    void ServiceManager::ForEachServiceInClass(const std::string& classname, void (*func)(Service* svc)) const {
        for (const auto& s : services_) {
            if (classname == s->classname()) {
                func(s.get());
            }
        }
    }
    
    bool Service::StartIfNotDisabled() {
        if (!(flags_ & SVC_DISABLED)) {
            return Start();
        } else {
            flags_ |= SVC_DISABLED_START;
        }
        return true;
    }
    
    bool Service::Start() {
    ...
    //已经在运行了,不处理
        if (flags_ & SVC_RUNNING) {
            return false;
        }
        ...
        //判断可执行文件是否存在
        //zygote对应的可执行文件是/system/bin/app_process
        if (stat(args_[0].c_str(), &sb) == -1) {
            flags_ |= SVC_DISABLED;
            return false;
        }
        ...
        //fork 子进程
        if (namespace_flags_) {
           ...
        } else {
            pid = fork();
        }
        if (pid == 0) {
        //pid为零,我们在子进程中
            //添加环境变量信息
            for (const auto& ei : envvars_) {
                add_environment(ei.name.c_str(), ei.value.c_str());
            }
            //创建sokcet
            CreateSockets(scon);
            //设置一些参数,uid,gid,写入文件等
            ...
            /*执行/system/bin/app_process,这样就进入到app_process的main函数中了。fork、execve这两个函数都是Linux系统上常用的系统调用。*/
            if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
              ...
            }
        }
        //父进程init的处理,设置service信息,如启动时间进程号,以及状态等
        ...
    }
    

    fork,execve拓展阅读
    linux c语言 fork() 和 exec 函数的简介和用法
    Linux下Fork与Exec使用

    重启zygote

    2.1.5 注册子进程信号处理器

    signal_handler_init()次函数在解析init.rc前先被调用。
    system/core/init/Signal_Handler.cpp

    void signal_handler_init() {
        // Create a signalling mechanism for SIGCHLD.
        int s[2];
        //通过socketpair创建两个socket,分别负责读写
        if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
        ... //失败,退出        
        }
        signal_write_fd = s[0];
        signal_read_fd = s[1];
        // Write to signal_write_fd if we catch SIGCHLD.
        struct sigaction act;
        memset(&act, 0, sizeof(act));
        //设置处理处理信号为"SIGCHLD"的消息的函数
        act.sa_handler = SIGCHLD_handler;
        act.sa_flags = SA_NOCLDSTOP;
        //信号注册,将监听及对应的信号处理注册到内核
        sigaction(SIGCHLD, &act, 0);
        ServiceManager::GetInstance().ReapAnyOutstandingChildren();
        register_epoll_handler(signal_read_fd, handle_signal);
    }
    

    sigaction注册到内核,监听SIGCHLD信号,交由SIGCHLD_handler处理,SIGCHLD_handler通过signal_wirte_fd写入信息

    //[system/core/init/Signal_Handler.cpp]
    static void SIGCHLD_handler(int) {
        if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) 
        ...
    }
    

    sinal_read_fdsignal_wirte_fd是一组,所以sinal_read_fd能接收到write的信息,在signal_handler_init的最后调用了register_epoll_handler(signal_read_fd, handle_signal)来注册处理signal_read_fd的处理函数,为handle_signal()

    //[system/core/init/init.cpp]
    void register_epoll_handler(int fd, void (*fn)()) {
        epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.ptr = reinterpret_cast<void*>(fn);
        //epoll_fd增加一个监听对象fd,fd上有数据到来时,调用fn处理
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1)
        ...
    }
    
    //[system/core/init/Signal_handler.cpp]
    static void handle_signal() {
        // Clear outstanding requests.
        char buf[32];
        read(signal_read_fd, buf, sizeof(buf));
        //调用ReapAnyOutstandingChildren做真正的子线程处理
        ServiceManager::GetInstance().ReapAnyOutstandingChildren();
    }
    
    20160807170210926.png 图片来自-《Android7.0 init进程源码分析》-ZhangJian的博客
    //[system/core/init/service.cpp]
    void ServiceManager::ReapAnyOutstandingChildren() {
        while (ReapOneProcess()) {
        }
    }
    
    bool ServiceManager::ReapOneProcess() {
        int status;
        //用waitpid函数获取状态发生变化的子进程pid
        //waitpid的标记为WNOHANG,即非阻塞,返回为正值就说明有进程挂掉了
        pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
        if (pid == 0) return false;
        else if (pid == -1) return false;
        ...
        //利用FindServiceByPid函数,找到pid对应的服务。
        Service* svc = FindServiceByPid(pid);
        //调用Reap()处理,判断service是否需要移除
        if (svc->Reap()) {
            waiting_for_exec = false;
            //移除服务
            RemoveService(*svc);
        }
        return true;
    }
    
    bool Service::Reap() {
        //清理未携带SVC_ONESHOT 或 携带了SVC_RESTART标志的子进程     
        if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART){
            KillProcessGroup(SIGKILL);
        }
        // Remove any sockets we may have created.
        //移除service中创建的socket
        for (const auto& si : sockets_) {
            unlink(tmp.c_str());
        }
        ...
        pid_ = 0;
        flags_ &= (~SVC_RUNNING);
        // Oneshot processes go into the disabled state on exit,
        // except when manually restarted.
        //对于携带了SVC_ONESHOT并且未携带SVC_RESTART的service,将这类服务的标志置为SVC_DISABLED,不再启动
        if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART)) {
            flags_ |= SVC_DISABLED;
        }
        // Disabled and reset processes do not get restarted automatically.
        if (flags_ & (SVC_DISABLED | SVC_RESET))  {
            NotifyStateChange("stopped");
            return false;
        }
        time_t now = gettime();
         //未携带SVC_RESTART的SVG_CRITICAL(重要的)服务,在规定的间隔内,crash字数过多时,会导致整机重启;
        if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
            if (time_crashed_ + CRITICAL_CRASH_WINDOW >= now) {
                if (++nr_crashed_ > CRITICAL_CRASH_THRESHOLD) {
                    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
                    return false;
                }
            } else {
                time_crashed_ = now;
                nr_crashed_ = 1;
            }
        }
        //将待重启service的标志位置为SVC_RESTARTING(init进程将根据该标志位,重启服务)
        flags_ &= (~SVC_RESTART);
        flags_ |= SVC_RESTARTING;
        // Execute all onrestart commands for this service.
        //执行在init.rc文件中service下面所有onrestart选项
        onrestart_.ExecuteAllCommands();
        NotifyStateChange("restarting");
        return false;
    }
    

    被标记为SVC_RESTARTING的service将在init中的restart_processes()中重启,所以zygote能在此被重启
    流程可简化为:

    20160807172447044.png 图片来自-《Android7.0 init进程源码分析》-ZhangJian的博客

    2.1.6 总结

    整体流程和《深入理解Android卷I》是一样的,只是更好的面向对象去处理,封装更好。还有就是I/O方式变了,epoll更加灵活,没有描述符限制,更多可参考
    IO多路复用之epoll总结
    Linux IO模式及 select、poll、epoll详解

    2.2 属性服务

    2.2.1 初始化

    Init.cppmain函数中执行了property_init()进行初始化

    //[system/core/init/Property_service.cpp]
    void property_init() {
        if (__system_property_area_init()) {
            exit(1);
        }
    }
    
    //[bionic/libc/inlcude/System_properties.cpp]
    int __system_property_area_init()
    {
        free_and_unmap_contexts();
        mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
        if (!initialize_properties()) {
            return -1;
        }
      ...
      //分配内存
        if (open_failed || !map_system_property_area(true, &fsetxattr_failed)) {
        ... 
         }
        initialized = true;
        return fsetxattr_failed ? -2 : 0;
    }
    
    //[bionic/libc/inlcude/System_properties.cpp]
    static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
    ...
        if (access_rw) {
        //这里才是真正分配内存的地方,大小为 [128 * 1024]
        //prop_area也改为了class
            __system_property_area__ = map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);
        }
         ...
        return __system_property_area__;
    }
    

    在书中说将pa赋值__system_property_area__是为了完成内存共享,这7.0这部分改动很大,有点看不明白,大致流程和卷一的流程是一样的。网上这部分的资料也没找到,还有就是property_init()是在!is_first_stage情况下执行的,那么property_load_boot_defaults()第一次执行加载的放在哪里?希望有前辈指教。
    不过好像也不影响我们理解:创建一个文件句柄,分配一个匿名共享内存区用于存放属性.

    2.2.2 启动属性服务

    在执行property_load_boot_defaults()Init.cpp::main中接着执行了start_property_service()

    //[system/core/init/Property_service.cpp]
    void start_property_service() {
    //创建socket
        property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,0666, 0, 0, NULL);
       ...
        listen(property_set_fd, 8);
        //注册处理函数
        register_epoll_handler(property_set_fd, handle_property_set_fd);
    }
    

    Init::main()在的最后又这么一段断码,通过取出注册的处理函数,然后处理消息。

    epoll_event ev;
    int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
        ...       
    else if (nr == 1) {
        ((void (*)()) ev.data.ptr)();
    }
    

    所以响应设置属性的请求就在handle_property_set_fd()中执行。

    2.2.3 处理属性设置

    //[system/core/init/Property_service.cpp]
    static void handle_property_set_fd()
    {
        ...
        //接受连接
        int s = accept(property_set_fd, nullptr, nullptr);
        ...
        //取出客户端进程的权限等
        if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0)
        ...
        //接受请求数据
        r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
        switch(msg.cmd) {
        case PROP_MSG_SETPROP:
            msg.name[PROP_NAME_MAX-1] = 0;
            msg.value[PROP_VALUE_MAX-1] = 0;
            ...
            //如果是ctl开头的消息,则认为是控制消息,控制消息用来执行一些命令,例如用adb shell登录后,输入setprop ctl.start bootanim就可以查看开机动画了,关闭的话就输入setpropctl.stop bootanim
            if(memcmp(msg.name,"ctl.",4) == 0) {
                // Keep the old close-socket-early behavior when handling
                // ctl.* properties.
                close(s);
                if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
                    handle_control_message((char*) msg.name + 4, (char*) msg.value);
                    }
                ...
            }else {
            //检查客户端进程是否有足够的权限
                if (check_mac_perms(msg.name, source_ctx, &cr)) {
                    //设置属性
                    property_set((char*) msg.name, (char*) msg.value);
                }
                ...
            }
            ...
    }
    
    //设置
    int property_set(const char* name, const char* value) {
        int rc = property_set_impl(name, value);
      ...
        return rc;
    }
    
    static int property_set_impl(const char* name, const char* value) {
        //更具不同的属性名称进行各种处理    
        ...
        //这个函数将触发 init.rc中的trigger 以执行command
        /*
    on property:persist.service.adb.enable=1
    start adb
    当persist.service.adb.enable属性置为1后,就会执行start adbd这个command,这是通过property_changed函数来完成的    
        */
        property_changed(name, value);
        return 0;
    }
    

    2.2.4 客户端发送设置请求

    客户端通过property_set发送请求,property_setlibcutils库提供

    //[system/core/libcutils/Properties.c]
    int property_set(const char *key, const char *value)
    {
        return __system_property_set(key, value);
    }
    
    //[bionic/libc/System_properties.cpp]
    int __system_property_set(const char *key, const char *value)
    {
        ...
        const int err = send_prop_msg(&msg);
        ...
    }
    
    //[bionic/libc/System_properties.cpp]
    static int send_prop_msg(const prop_msg *msg){
        ...
        sockaddr_un addr;
        memset(&addr, 0, sizeof(addr));
        strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
        addr.sun_family = AF_LOCAL;
        socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
        //建立和属性服务器的socket连接
        if (TEMP_FAILURE_RETRY(connect(fd, reinterpret_cast<sockaddr*>(&addr), alen)) < 0) {
            close(fd);
            return -1;
        }
        //通过socket发送出去
        const int num_bytes = TEMP_FAILURE_RETRY(send(fd, msg, sizeof(prop_msg), 0));
    }
    

    3 总结

    总体来说流程和原书是一致的,只是在实现采用了面向对象,通信方式也采用了更加高效的方式,加入了SELinux的东西,对属性初始化那一部分还有点迷惑。但是更具原书的流程走,也不是很费力。其中的一些细节,后面再去填坑。
    感谢以下博文的帮助:
    Android系统启动-init篇
    Android7.0 init进程源码分析
    Android的init进程启动过程

    上一篇 《第二章 - JNI》读书笔记
    上一篇 《第四章 - Zygote》读书笔记

    相关文章

      网友评论

          本文标题:《深入理解Android卷 I》- 第三章 - Init - 读

          本文链接:https://www.haomeiwen.com/subject/sbdsbttx.html