android系统启动流程分析(代码片段)

JackOu1110 JackOu1110     2023-01-13     419

关键词:

前言

写这篇blog背景是项目在做系统启动耗时优化,之前看了两遍罗升阳大神《Android系统源代码情景分析》都只是看了,没有实践,没有运用到项目中,因此借项目在做系统优化的机会,再次将Android系统的启动流程细细的在撸一遍,边撸边思考哪些点可以优化。

**声明:**由于家里面的代码是去年下的,去年还在做Android O(android-8.0.0_r1)的系统项目,如果博客中有方法在你的代码中找不到,要么选择和我一起看Android O的R1版本代码,要么可以尝试找找你下载版本的源码是否有对我博客中的代码进行封装。因为我经常发现google会将代码在不同版本中封装。大致流程肯定是完全一样的。

**说明:**这篇博客着实有点长,我本来想分几篇写的,但是感觉分几篇就不完整了,分散了心里始终感觉哪里不对头,所有就没分散。**我不能保证你一定能看完这篇博客,但是我可以保证你看完这篇博客,你肯定会对Android系统启动有更深的理解。**为了方便理解,我先丢两张图,先看图有个直观的认识,再看方法实现了什么功能更容易理解,也更容易在跟踪方法调用迷糊时找到调入的地方。

如果看不清楚,原图下载传送门:系统启动分析

1.Android系统大致启动流程

第一步: 启动电源以及系统启动
当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后 执行引导程序。

第二步:引导程序
引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针 对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运 营商加锁和限制的地方。
引导程序分两个阶段执行。
第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;
第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程 序可以根据配置参数或者输入数据设置内核。
Android引导程序可以在\\bootable\\bootloader\\legacy\\usbloader找到。传统的加载器包含两个文件, 需要在这里说明:
init.s初始化堆栈,清零BBS段,调用main.c的_main()函数;
main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签

第三步:内核
Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表, 加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第 一个进程

第四步:init进程
init进程是Linux系统中用户空间的第一个进程,进程号固定为1。Kernel启动后,在用户空间启动init进 程,并调用init中的main()方法执行init进程的职责。

第五步:启动zygote进程,通过zygote启动SystemServer,当服务都启动完成之后,启动Lancher App,然后退出开机动画。我们就可以看到桌面应用,此时启动过程就结束了。

2.启动init进程

init进程是Android系统中及其重要的第一个进程,是由内核拉起来的第一个用户进程。

init进程主要完成了三件事情。

  • 创建和挂载启动所需要的文件目录
  • 初始化和启动属性服务
  • 解析init.rc配置文件并启动Zygote进程
// \\system\\core\\init\\init.cpp main()
/* 
* 1.C++中主函数有两个参数,第一个参数argc表示参数个数,第二个参数是参数列表,也就是具体 的参数 
* 2.init的main函数有两个其它入口,一是参数中有ueventd,进入ueventd_main,二是参数中 有watchdogd,进入watchdogd_main 
*/ 
int main(int argc, char** argv) 
    /* 
    * 1.strcmp是String的一个函数,比较字符串,相等返回0 
    * 2.C++中0也可以表示false 
    * 3.basename是C库中的一个函数,得到特定的路径中的最后一个'/'后面的内容, 
    * 比如/sdcard/miui_recovery/backup,得到的结果是backup 
    */
    if (!strcmp(basename(argv[0]), "ueventd")) 
        //当argv[0]的内容为ueventd 时,strcmp的值为0,!strcmp为1 
		//1表示true,也就执行ueventd_main,ueventd主要是负责设备节点的创建、权限设定等一系列工作
        return ueventd_main(argc, argv);
    

    if (!strcmp(basename(argv[0]), "watchdogd")) 
        //watchdogd俗称看门狗,用于 系统出问题时重启系统
        return watchdogd_main(argc, argv);
    

    if (REBOOT_BOOTLOADER_ON_PANIC) 
        //初始化重启系统的处理信号,内部通过sigaction 注册信号,当监听到该信号时重启系统
        install_reboot_signal_handlers();
    

    add_environment("PATH", _PATH_DEFPATH);

    // 查看是否有环境变量INIT_SECOND_STAGE
    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);

    // 1.init的main方法会执行两次,由is_first_stage控制,first_stage就是第一阶段要做的事
    if (is_first_stage) 
        boot_clock::time_point start_time = boot_clock::now();

        // Clear the umask.
        //清空文件权限
        umask(0);

        // 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是用来挂载文件系统的,mount属于Linux系统调用
        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 ;
        // 用来将list数组中所标明的组加入到目前进程的组设置中
        setgroups(arraysize(groups), groups);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
        //mknod用于创建Linux中的设备文件
        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));

        // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
        // talk to the outside world...
        //将标准输入输出重定向到"/sys/fs/selinux/null"
        InitKernelLogging(argv);

        LOG(INFO) << "init first stage started!";

        if (!DoFirstStageMount()) 
            LOG(ERROR) << "Failed to mount required partitions early ...";
            panic();
        

        //Avb即Android Verfied boot,功能包括Secure Boot, verfying boot 和dm-verity, 
		//原理都是对二进制文件进行签名,在系统启动时进行认证,确保系统运行的是合法的二进制镜像文件。 
		//其中认证的范围涵盖:bootloader,boot.img,system.img
        // 通过调用FsManagerAvbHandle::Open()->FsManagerAvbOps::AvbSlotVerify->avb_slot_verify最终去验证每个分区。
        // 当验证成功之后,会将版本信息写到环境变量 INIT_AVB_VERSION 中
        SetInitAvbVersionInRecovery();

        // Set up SELinux, loading the SELinux policy.
        //加载SELinux 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.
        // 我们执行第一遍init的main方法是在kernel domain,所以要重新执行init文件,切换到加载了selinux策略的init domain,
        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 ;
        // 重新执行init,由于标志位置为了,因此再次执行init会进入阶段。
        execv(path, args);

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

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

    //初始化属性系统,并从指定文件读取属性
    // bionic/libc/bionic/system_properties.c
    // __system_property_area_init->map_prop_area_rw->打开/dev/__properties__文件->并且映射128kb空间大小内存来存属性键值对。
    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.
    //接下来的一系列操作都是从各个文件读取一些属性,然后通过property_set设置系统属性
    // 1.这句英文的大概意思是,如果参数同时从命令行和DT传过来,DT的优先级总是大于命令行的。
    // 2.DT即device-tree,中文意思是设备树,这里面记录自己的硬件配置和系统运行参数,参考http://www.wowotech.net/linux_kenrel/why-dt.html
    process_kernel_dt();//处理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();//处理其他的一些属性

    // Make the time that init started available for bootstat to log.
    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));

    // Set libavb version for Framework-only OTA match in Treble build.
    const char* avb_version = getenv("INIT_AVB_VERSION");
    // 将avb版本设置到系统属性中
    if (avb_version) property_set("ro.boot.avb_version", avb_version);

    // Clean up our environment.
    // 清除环境变量
    unsetenv("INIT_SECOND_STAGE");
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");

    // Now set up SELinux for second stage.
    selinux_initialize(false);
    selinux_restore_context();

    //创建epoll实例,并返回epoll的文件描述符
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) 
        PLOG(ERROR) << "epoll_create1 failed";
        exit(1);
    

    // 主要是创建handler处理子进程终止信号,创建一个匿名 socket并注册到epoll进行监听
    signal_handler_init();

    // 从文件中加载一些属性,读取usb配置
    // 涉及到的文件,/system/etc/prop.default,/odm/default.prop,/vendor/default.prop
    property_load_boot_defaults();
    export_oem_lock_status();// 设置ro.boot.flash.locked 属性
    start_property_service();//开启一个socket监听系统属性的设置
    set_usb_controller();//设置sys.usb.controller 属性

    //init.rc文件中方法映射,例如“class_start”-> "do_class_start"
    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);//将function_map存放到Action中作 为成员属性

    // 使用不同的parse解析init.rc文件中的不同字段,并且将service保存在servicelist中
    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", "");
    if (bootscript.empty()) 
        // 以下目录的所有rc文件默认都会被解析
        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 
        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);
    

    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    // Nexus 9 boot time, so it's disabled by default.
    if (false) parser.DumpState();//打印一些当前Parser的信息,默认是不执行的

    ActionManager& am = ActionManager::GetInstance();

    // QueueEventTrigger用于触发Action,这里触发early-init事件
    am.QueueEventTrigger("early-init");

    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    //QueueBuiltinAction用于添加Action,第一个参数是 Action要执行的Command,第二个是Trigger
    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");
    am.QueueBuiltinAction(console_init_action, "console_init");

    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");

    // 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 = GetProperty("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) 
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1; //epoll超时时间,相当于阻塞时间

        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) 
            am.ExecuteOneCommand();//执行一个command
        
        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.
            //当还有命令要执行时,将epoll_timeout_ms设置为0
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        

        epoll_event ev;
        /* 
        * 1.epoll_wait与epoll_create1、epoll_ctl是一起使用的 
        * 2.epoll_create1用于创建epoll的文件描述符,epoll_ctl、epoll_wait都把它创建的fd作为第一个参数传入 
        * 3.epoll_ctl用于操作epoll,EPOLL_CTL_ADD:注册新的fd到epfd中, 
        EPOLL_CTL_MOD:修改已经注册的fd的监听事件,EPOLL_CTL_DEL:从epfd中删除一个fd; 
        * 4.epoll_wait用于等待事件的产生,epoll_ctl调用EPOLL_CTL_ADD时会传入需要监听什么类型的事件, 
        *比如EPOLLIN表示监听fd可读,当该fd有可读的数据时,调用epoll_wait经过epoll_timeout_ms时间就会把该事件的信息返回给&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) 
            //当有event返回时,取出 ev.data.ptr(之前epoll_ctl注册时的回调函数),直接执行 
            //在signal_handler_init和start_property_service有注册两个fd的监听,一个用于监听SIGCHLD(子进程结束信号),一个用于监听属性设置
            ((void (*)()) ev.data.ptr)();
        
    

    return 0;

3.解析init.rc

init.rc是一个非常重要的配置文件,它是由Android初始化语言(Android Init Language)编写的脚本,它主要包含五种类型语句:Action(Action中包含了一系列的Command)、Commands(init语言中的命令)、Services(由init进程启动的服务)、Options(对服务进行配置的选项)和Import(引入其他配置文件)。init.rc的配置代码如下所示。

# \\system\\core\\rootdir\\init.rc 
on init # L41
	sysclktz 0
   # Mix device-specific information into the entropy pool    
   copy /proc/cmdline /dev/urandom
   copy /default.prop /dev/urandom
   ...
   
on <trigger> [&& <trigger>]* //设置触发器     
	<command>
    <command> //动作触发之后要执行的命令
    
service <name> <pathname> [ <argument> ]* #<service的名字><执行程序路径><传递参数>
    <option>  #Options是Services的参数配置. 它们影响Service如何运行及运行时机     
    group <groupname> [ <groupname>\\* ] #在启动Service前将group改为第一个 groupname,第一个groupname是必须有的,默认值为root(或许默认值是无),第二个groupname可以不设置,用于追加组(通过 setgroups)
    priority <priority> #设置进程优先级. 在-20~19之间,默认值是0,能过 setpriority实现
    socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ] #创建 一个unix域的socket,名字叫/dev/socket/name , 并将fd返回给Service. type 只能是 "dgram", "stream" or "seqpacket".
3.1 Action

Action: 通过触发器trigger,即以on开头的语句来决定执行相应的service的时机,具体有如下时机:

  • on early-init; 在初始化早期阶段触发;
  • on init; 在初始化阶段触发;
  • on late-init; 在初始化晚期阶段触发;
  • on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
  • on property:=: 当属性值满足条件时触发
3.2 Service

服务Service,以 service开头,由init进程启动,一般运行在init的一个子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service在启动时会通过 fork方式生成子进程。
例如: service servicemanager /system/bin/servicemanager代表的是服务名为 servicemanager,服务执行的路径为/system/bin/servicemanager。

3.3 Command

下面列举常用的命令:

  • class_start <service_class_name>: 启动属于同一个class的所有服务;
  • start <service_name>: 启动指定的服务,若已启动则跳过;
  • stop <service_name>: 停止正在运行的服务
  • setprop :设置属性值
  • mkdir :创建指定目录
  • symlink <sym_link>: 创建连接到的<sym_link>符号链接;
  • write : 向文件path中写入字符串;
  • exec: fork并执行,会阻塞init进程直到程序完毕;
  • exprot:设定环境变量;
  • loglevel :设置log级别
3.4 Options

Options是Service的可选项,与service配合使用

  • disabled: 不随class自动启动,只有根据service名才启动;
  • oneshot: service退出后不再重启;
  • user/group: 设置执行服务的用户/用户组,默认都是root;
  • class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default; onrestart:当服务重启时执行相应命令;
  • socket: 创建名为 /dev/socket/的socket
  • critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式
  • default: 意味着disabled=false,oneshot=false,critical=false。

下面看看zygote的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
3.5 逐行解析脚本
// system\\core\\init\\init_parser.cpp
void Parser::ParseData(const std::string& filename, const std::string& data) 
    //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.filename = filename.c_str();
    state.line = 0;
    state.ptr = &data_copy[0];
    state.nexttoken = 0;

    SectionParser* section_parser = nullptr;
    std::vector<std::string> args;

    for (;;) 
        switch (next_token(&state)) 
        case T_EOF:
            if (section_parser) 
                // 结束解析
                section_parser->EndSection();
            
            return;
        case T_NEWLINE:
            state.line++;
            if (args.empty()) 
                break;
            
            if (section_parsers_.count(args[0])) 
                if (section_parser) 
                    section_parser->EndSection();
                
                section_parser = section_parsers_[args[0]].get();
                std::string ret_err;
                // 逐行解析
                if (!section_parser->ParseSection(args, &ret_err)) 
                    parse_error(&state, "%s\\n", ret_err.c_str());
                    section_parser = nullptr;
                
             else if (section_parser) 
                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.emplace_back(state.text);
            break;
        
    

// \\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);//构建出一个service对象
   return Success(); 
// \\system\\core\\init\\service.cpp 
void ServiceParser::EndSection() 
    if (service_) 
        // 如果上面解析的service不为空,就加入到ServiceManager中
        ServiceManager::GetInstance().AddService(std::move(service_));
    

上面解析完成后,接下来就是启动Service,这里我们以启动Zygote来分析

# \\system\\core\\rootdir\\init.rc L680 
on nonencrypted
   class_start main #class_start是一个命令,通过do_class_start函数处理    
   class_start 	late_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])) 
           // 调用刚刚注册的service的StartIfNotDisabled()方法
           if (auto result = service->StartIfNotDisabled(); !result) 
               LOG(ERROR) << "Could not start service '" << service->name()                           << "' as part of class '" << args[1] << "': " << result.error();
      	       
       
	 
   return Success(); 

// \\system\\core\\init\\service.cpp 
Result<Success> Service::StartIfNotDisabled() 
   if (!(flags_ & SVC_DISABLED))         
       return Start();
    else 
       flags_ |= SVC_DISABLED_START;  
   	   return Success();

bool Service::Start() 
    // 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));

    // 如果service已经启动了,就不启动了
    if (flags_ & SVC_RUNNING) 
        return false;
    

    ......

    struct stat sb;
    //判断需要启动的service的对应的执行文件是否存在,不存在则不启动service
    if (stat(args_[0].c_str(), &sb) == -1) 
        PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
        flags_ |= SVC_DISABLED;
        return false;
    

    std::string scon;
    if (!seclabel_.empty()) 
        scon = seclabel_;
     else 
        LOG(INFO) << "computing context for service '" << name_ << "'";
        scon = ComputeContextFromExecutable(name_, args_[0]);
        if (scon == "") 
            return false;
        
    

    LOG(INFO) << "starting service '" << name_ << "'...";
	//如果子进程没有启动,则调用fork函数创建子进程
    pid_t pid = -1;
    if (namespace_flags_) 
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
     else 
        pid = fork();
    

    if (pid == 0) //当期代码逻辑在子进程中运行
        umask(077);

        if (namespace_flags_ & CLONE_NEWPID) 
            // This will fork again to run an init process inside the PID
            // namespace.
            SetUpPidNamespace(name_);
        

        for (const auto& ei : envvars_) 
            add_environment(ei.name.c_str(), ei.value.c_str());
        

        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 android::base::StartsWith(path, "/dev/cpuset/");
        ;
        auto iter = std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate);
        if (iter == writepid_files_.end()) 
     

android系统启动流程分析(代码片段)

一、启动初探在android手机上,当我们点击桌面上的按钮启动一个应用,就能打开应用的界面。这里我们所说的桌面其实就是android系统启动后的就已经帮我们运行的第一个程序,launcher程序。launcher程序可以理解为作为... 查看详情

说说android系统的启动流程(代码片段)

Android系统的启动流程Android系统的启动流程可以分三部分来分析,Android系统有哪些主要的系统进程?这些系统进程是怎么启动的?启动之后都做了什么事?首先看下图,分三个阶段介绍Android系统的启动流程... 查看详情

android系统启动流程分析(代码片段)

一、启动初探在android手机上,当我们点击桌面上的按钮启动一个应用,就能打开应用的界面。这里我们所说的桌面其实就是android系统启动后的就已经帮我们运行的第一个程序,launcher程序。launcher程序可以理解为作为... 查看详情

android7.0系统启动流程分析(代码片段)

随着Android版本的升级,aosp项目中的代码也有了些变化,本文基于Android7.0分析Android系统启动流程.当我们按下电源键后,整个Android设备大体经过了一下过程:今天我们只想来分析init进程及其后的过程,也就是下图所示部分:init进程init进... 查看详情

android12init启动流程分析(代码片段)

文章托管在gitee上AndroidNotes,同步csdn本文基于Android12分析概述init是Android启动的第一个用户空间进程,它的地位非常重要,它fork产生系统的一些关键进程(如zygote,surfaceflinger进程),而zygote进一步fork产生system_server和... 查看详情

android7.0应用冷启动流程分析(代码片段)

最近在为自己MotoG定制Rom,顺便重新读了一遍Android7.0的相关源码,特此记录当做笔记.在开始正文之前,首先要明白冷启动和热启动.所谓冷启动就是启动该应用时,后台没有该应用的进程,此时系统会创建一个进程分配给它(AMS通过Socket... 查看详情

android|activity启动流程分析(代码片段)

前言Activity类是android应用的关键组件,在日常开发中,绝对少不了组件。既然用了这么久,你知道他的启动流程🐴?作为一个应用层开发者,大多数人可能觉得学习这些对日常开发可能没有太大帮助。但... 查看详情

android启动过程activity启动源码分析(activitythread流程分析二)(代码片段)

文章目录前言一、ActivityManagerService.attachApplicationLocked二、ActivityStackSupervisor.attachApplicationLocked三、ActivityStackSupervisor.realStartActivityLocked前言在上一篇博客【Android启动过程】Activity启动源码分析(ActivityThre 查看详情

contentprovider的启动流程分析(代码片段)

ContentProvider是Android系统的四大组件之一,主要用于向外部提供数据。不仅可以向自己应用进程提供数据,也可以向其他进程的提供数据。所以在分析ContentProvider的时候我们首先分析本进程的ContentProvider的启动过程,... 查看详情

android音频源码分析——audioserver启动(代码片段)

Android音频源码分析——AndroidRecord录音(一)Android音频源码分析——AndroidRecord录音(二)Android音频源码分析——AndroidRecord音频数据传输流程Android音频源码分析——audioserver启动该源码分析基于android9.0 Android音... 查看详情

android启动过程activity启动源码分析(activitythread流程分析一)(代码片段)

文章目录一、ActivityThread主函数启动二、ActivityThread绑定ApplicationThread三、AMSattachApplication->attachApplicationLocked绑定ApplicationThread四、ApplicationThread.bindApplication绑定ApplicationThread五、ActivityThread. 查看详情

[rk3568android11]input子系统启动流程图(代码片段)

🚀返回专栏总目录文章目录一、InputManagerService启动流程图沉淀、分享、成长,让自己和他人都能有所收获!😄一、InputManagerService启动流程图分析Input子系统的启动主要是看InputManagerService的启动,InputManagerServ... 查看详情

android应用启动流程分析(代码片段)

1前言网上看过很多Activity启动过程的源码解析,很多文章会贴上一大段代码,然后从startActivity()函数开始深究整个源码的调用栈。个人感觉这类文章代码细节太多,反而容易迷失在源码调用之中,从而忽略了Activit... 查看详情

android逆向android进程简介(android应用启动流程)(代码片段)

文章目录前言一、Android进程二、Android应用启动流程前言参考【Android逆向】Android系统文件分析(/proc/pid进程号对应进程目录|oom_adj|maps|smaps|mem|task|environ)博客,/proc/目录中存放的是所有进程相关信息;一、Android进程Android操作系统中... 查看详情

android逆向android进程简介(android应用启动流程)(代码片段)

文章目录前言一、Android进程二、Android应用启动流程前言参考【Android逆向】Android系统文件分析(/proc/pid进程号对应进程目录|oom_adj|maps|smaps|mem|task|environ)博客,/proc/目录中存放的是所有进程相关信息;一、Android进程Android操作系统中... 查看详情

android应用启动流程分析(代码片段)

1前言网上看过很多Activity启动过程的源码解析,很多文章会贴上一大段代码,然后从startActivity()函数开始深究整个源码的调用栈。个人感觉这类文章代码细节太多,反而容易迷失在源码调用之中,从而忽略了Activit... 查看详情

[android5.1]开机动画显示工作流程分析(代码片段)

网上有很多关于android开机动画显示的分析,但大部分是针对于android的早期版本。在android5.1中,开机动画显示的工作流程做了一些修改,下面就针对android5.1,分析一下开机动画的启动、显示和停止的整个过程。1.b... 查看详情

从launcher程序启动app流程分析(代码片段)

一、启动初探”在android手机上,当我们点击桌面上的按钮启动一个应用,就能打开应用的界面。这里我们所说的桌面其实就是android系统启动后的就已经帮我们运行的第一个程序,launcher程序。launcher程序可以理解为作... 查看详情