android启动--深入理解init进程

全志平台Android init启动分析(1)init启动 1. 前言 总结下android init启动流程; 为平时debug梳理思路 2.Init代码结构 Init 源代码目录:system/core/init/ , 源文件如下: ├── Android.mk ├── bootchart.c ├── bootchart.h ├── builtins.c ├── devices.c ├── devices.h ├── drv_display.h ├── fswatcherd.c ├── fswatcherd.h ├── grab-bootchart.s 阅读详情
init是一个进程,它是linux系统中用户空间的第一个进程,其进程PID是1,父进程为linux
系统内核的0号进程。所以其被赋予很多极其重要的职责,linux内核初始化完成后就开始执行它。


代码路径:\system\core\init\init.c


下面就分析一下先吧,只分析重点的函数功能:
int main(int argc, char **argv)

{

     // 1、设置子进程退出的信号处理函数:sigchld_handler

    act.sa_handler = sigchld_handler;
    act.sa_flags = SA_NOCLDSTOP;
    act.sa_mask = 0;
    act.sa_restorer = NULL;
    sigaction(SIGCHLD, &act, 0);

    // 2、创建文件夹,并挂载设备
    mkdir("/dev", 0755);
    mkdir("/proc", 0755);
    ....

    

/* clear the umask */

umask(0); // 其实也就是 chmod 777 赋予所有权限


    // 3、重定向标准输入输出错误到 /dev/__null__
    open_devnull_stdio();
    
    // 4、解析 init.rc 脚本
    parse_config_file("/init.rc");


     // 5、解析机器相关的配置文件,一般相关的放在init.rc中利用service action调过去
     snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
    parse_config_file(tmp);


     // 6、建立 uevent,用于与linux kernel交互的socket
     device_fd = device_init();

     // 7、初始化及加载属性相关资源,这里利用ashmem共享,属于整个系统的资源
     property_init();

     // 8、执行 on init 、early-boot 及 boot 片段动作,这些定义于 init.rc 中
     /* execute all the boot actions to get us started */
     action_for_each_trigger("init", action_add_queue_tail);
     drain_action_queue();
    
    /* execute all the boot actions to get us started */
    action_for_each_trigger("early-boot", action_add_queue_tail);
    action_for_each_trigger("boot", action_add_queue_tail);

    // 9、这里定义的init进程需要关注的四个方面事情  
    ufds[0].fd = device_fd;
    ufds[0].events = POLLIN;   // Uevent事件
    ufds[1].fd = property_set_fd;
    ufds[1].events = POLLIN;   // 属性事件
    ufds[2].fd = signal_recv_fd;
    ufds[2].events = POLLIN;   // 子进程事件
    fd_count = 3;


   ufds[3].fd = keychord_fd;
    ufds[3].events = POLLIN;  // keychord热键事件
    fd_count++;

    // ok, 下面就是init进程的处理循环
    for(;;) {
         // I、执行init.rc 脚本中的动作
         drain_action_queue();
        
         // II、执行标志为SVC_RESTARTING的进程,利用fork+execve启动新的进程
         restart_processes();


 // III、调用poll轮询上述的四个事件
        nr = poll(ufds, fd_count, timeout);
        if (nr <= 0)
            continue;


 // IV、依次处理各个事件
         if (ufds[2].revents == POLLIN) {
            /* we got a SIGCHLD - reap and restart as needed */
            read(signal_recv_fd, tmp, sizeof(tmp));
            while (!wait_for_one_process(0))
                ;
            continue;
        }


        if (ufds[0].revents == POLLIN)
            handle_device_fd(device_fd);


        if (ufds[1].revents == POLLIN)
            handle_property_set_fd(property_set_fd);
        if (ufds[3].revents == POLLIN)
            handle_keychord(keychord_fd);
...
}

return 0;
}


这里我们重点关注一下service的解析过程:


这里以启动 zygote 为例讲解一下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    socket zygote stream 666   //创建一个stream流式套接字
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media



服务名称: zygote
进程路径: /system/bin/app_process
进程启动参数:-Xzygote /system/bin --zygote --start-system-server

解析入口函数:parse_new_section

void parse_new_section(struct parse_state *state, int kw,
                       int nargs, char **args)
{
    switch(kw) {
    case K_service:
        state->context = parse_service(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_service;
            return;
        }
        break;
...
}


--> 其中所有的解析的service放在如下双链表结构中
struct service {
    /* list of all services */
    struct listnode slist;


    const char *name;
    const char *classname; //所属class名字,默认为"default"


    unsigned flags;
    pid_t pid;


    struct socketinfo *sockets;
    struct svcenvinfo *envvars;


    struct action onrestart;  /* Actions to execute on restart. */
    ...
};


static void *parse_service(struct parse_state *state, int nargs, char **args)
{
    struct service *svc;

    svc = service_find_by_name(args[1]);

    svc->name = args[1];
    svc->classname = "default";
    memcpy(svc->args, args + 2, sizeof(char*) * nargs);
    svc->args[nargs] = 0;
    svc->nargs = nargs;
    svc->onrestart.name = "onrestart";
    list_init(&svc->onrestart.commands);


    // 加入到全局 service_list 链表中
    list_add_tail(&service_list, &svc->slist);
    return svc;
}


然后执行点都使用 list_for_each(node, &service_list) 循环遍历所有服务及执行动作


service 启动:


在解析 init.rc 脚本中 
class_start default 
这个class_start 是一个COMMAND,其对应的函数是 do_class_start ,注意类似的COMMAND也一样

加上前缀 do_xxx 即函数名称:   其实在文件  /system/core/init/keywords.h 头文件中定义了对应关系,由宏定义: 

#define KEYWORD(symbol, flags, nargs, func) K_##symbol,

    KEYWORD(chdir,       COMMAND, 1, do_chdir)
    KEYWORD(chroot,      COMMAND, 1, do_chroot)

ex: mount 对应于 do_mount 

代码:/system/core/init/builtins.c


do_class_start()
-->service_start_if_not_disabled()
--> service_start(svc, NULL);


void service_start(struct service *svc, const char *dynamic_args)
{
    // 已经运行则直接返回
    if (svc->flags & SVC_RUNNING) {
        return;
    }
    
    NOTICE("starting '%s'\n", svc->name);
    pid = fork();  //创建子进程 
    if(pid == 0){
    // 运行于子进程中
    
    // 准备好执行环境
    add_environment(ei->name, ei->value);
    create_socket(si->name,
                         !strcmp(si->type, "dgram") ? 
                         SOCK_DGRAM : SOCK_STREAM,
                         si->perm, si->uid, si->gid);    
    
    // 开始执行具体的进程
    execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);

    }


    svc->time_started = gettime();
    svc->pid = pid;
    svc->flags |= SVC_RUNNING;


    notify_service_state(svc->name, "running");
}


onrestart 用于重启使用,这就是最开始那个 sigchld_handler 函数:


static void sigchld_handler(int s)
{
    write(signal_fd, &s, 1); // 写数据
}

读取数据处理:
在 init 进程的main函数中处理:
    if (ufds[2].revents == POLLIN) {
        /* we got a SIGCHLD - reap and restart as needed */
        read(signal_recv_fd, tmp, sizeof(tmp));
        while (!wait_for_one_process(0))

            ;
        continue;
    }

-->
static int wait_for_one_process(int block)
{
    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );


    // 杀死zygote创建的所有子进程,这就是zygote 死则整个系统崩溃的原因了
    if (!(svc->flags & SVC_ONESHOT)) {
        kill(-pid, SIGKILL);
        NOTICE("process '%s' killing any children in process group\n", svc->name);
    }

    //超时及重启次数系统重启进入recovery模式
    if (svc->flags & SVC_CRITICAL) {
        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
                ERROR("critical process '%s' exited %d times in %d minutes; "
                      "rebooting into recovery mode\n", svc->name,
                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
                sync();
                __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                         LINUX_REBOOT_CMD_RESTART2, "recovery");

                return 0;
            }
        }
...

}


总结一下,整个init 进程启动后,基本的NATIVE 世界如下:





c# 开发串口调试助手 Visual Studio 2019 串口调试助手是用于在开发、测试和调试串口通信应用程序时进行串口数据的监视和交互的工具。 阅读详情

相关推荐

comsol移动网格_comsol模拟移动的纳秒脉冲激光烧蚀材料,温度场分布,结果总不理想,求助大佬!!...

本人comsol新手一枚,希望大家多多指点研究课题:纳秒脉冲激光刻蚀材料表面想用comsol模拟刻蚀过程中的温度场分布,脉宽为300ns,重复频率100kHz,光斑移动速度为5000mm/s,光斑直径50um,激光功率10W,材料种类为:有机涂层,属性如下目前,采用的是一个移动的高斯面光源x脉冲函数,脉冲函数我用的是一个周期性方波:周期性拓展后,画出来的脉冲图,不知道为什么在0~1s的区间内只有1...

weixin_33288893的博客 4740

android:init.rc里面的服务老是重启

service 不断的重启失败。不停的重启。 <5>[ 31.154227] init: starting 'xxxx' <6>[ 31.163313] init: waitpid returned pid 2651, status = 00000100 <5>[ 31.163343] init: process 'xxxx', pid 2651 ...

maze的专栏 3995

2025海外代理IP深度横评:Bright Data、IPFoxy、SmartProxy等六大服务商实战对比

本文深度横评2025年六大海外代理IP服务商(Bright Data、IPFoxy、SmartProxy、IPIPGO、Kookeey及青果网络),基于实战测试数据,从IP池质量、速度稳定性、性价比等维度进行对比。针对跨境电商、数据爬虫、社交媒体管理等不同业务场景,提供精准的选购指南与避坑建议,帮助企业用户根据自身需求选择最合适的代理IP解决方案。

weixin_29196891的博客 434

Android bootchart 分析

转载自 http://blog.youkuaiyun.com/weiqifa0/article/details/48996033 1.首先确保编译的init被烧录到板子里面去了,源码的位置在system/core/init/ 2.第一次修改后,编译了system/core/init/然后又编译了./mkkernel 生成boot.img 但是烧录进去还是不成功 3.然后 发现有一个宏没有设置 在

lqxandroid2012的专栏 1417

FTViewSE利用VB脚本制作简易日报表

罗克韦尔SE用VB做的简单的报表

z0800656的博客 3021

Redhawk-SC输入件配置中的5个常见错误及解决方法

本文针对Redhawk-SC功耗与可靠性签核工具,深入剖析了输入件配置中工艺文件错配、DEF文件路径、时序文件格式、电源网络模型及宏模型处理这5个最常见且棘手的错误。文章提供了资深工程师验证过的实战解决方案与检查清单,旨在帮助用户规避风险,提升配置效率与分析准确性,确保芯片签核流程的顺利进行。

earth的博客 233

Bootchart工具在Android手机上的使用方法和心得

1简介 BootChart是一个对Linux boot过程进行性能分析并把结果直观化的工具。BootChart包含数据收集和图像产生工具,Android中,数据收集工具被继承到了init程序中。 2.使用步骤 (1)在主机上安装BootChart; 请将附件中bootchart-0.9.tar.bz2下载到本地,例如tools目录下,解压,在tools下,就会看到boot

wangqiaozhi的专栏 1428

Cibersort免疫浸润 --- 详细教程

免疫浸润是指免疫细胞如淋巴细胞、浆细胞、巨噬细胞等进入到组织或器官中,并在这些组织或器官中发挥免疫功能的过程。免疫细胞的浸润可以是炎症反应的一部分,也可以是针对感染、肿瘤或其他疾病的免疫应答的一部分。免疫浸润通过调节免疫反应和炎症反应的程度和类型,起到维护机体免疫平衡和清除异常细胞或病原体的作用。在某些情况下,免疫浸润可能导致炎症反应过度,引起组织损伤,例如自身免疫性疾病。因此,免疫浸润在许多疾病的诊断和治疗中都具有重要的意义。免疫浸润可以通过组织切片染色和免疫组织化学等方法观察和分析。

ZxVSaccount的博客 9105

bootchart 使用说明及代码分析

bootchart是一个用于linux启动过程性能分析的开源软件工具,在系统启动过程自动收集CPU占用率、进程等信息,并以图形方式显示分析结果,可用作指导优化系统启动过程。bootchart是一个对linux启动流程进行分析得开源软件工具。android中有集成bootchart源码,路径为system/core/init/bootchart.c。

xiaowang_lj的博客 749

MDK5 Debug调试方法总结

MDK5 Debug调试方法总结

m0_70748084的博客 2万+

R数据分析:潜在转化分析LTA的做法和解释(一)

之前给大家写了很多潜在类别分析的教程Mplus教程:如何做潜在类别分析LCAR数据分析:用R语言做潜类别分析LCAMplus数据分析:潜在类别分析(LCA)流程(详细版)R数据分析:再写潜在类别分析LCA的做法与解释,今天继续给大家拓展一步。 今天要介绍的就是潜在转换分析,这个东西就是LCA的纵向版本。是一个专门用来研究质变的统计技巧。有一句话叫做量变起质变,你怎么知道质变到底发生没有?就用潜在转换分析。 Latent transition analysis is an extension of...

Codewar的博客 7701

Bug系列---------图片库崩溃(内存泄露)

最近遇到一个打开图片库就崩溃的,看了一下log感觉下面这段有点价值    0 I init    : Service 'imsdatadaemon' (pid 22635) exited with status 1 01-27 13:04:15.253     0     0 I init    : Service 'imsdatadaemon' (pid 22635) killing

u013308744的专栏 2641

桌面运维工程师面试题汇总(高频完整版)

岗位,覆盖:电脑硬件、系统安装与故障、网络、办公软件、安全、AD域、打印机、日常排错、服务意识。

老韩的Linux云计算架构师进阶之路 908

android启动—深入理解init进程

[导读]init是一个进程,它是linux系统中用户空间的第一个进程,其进程PID是1,父进程为linux init是一个进程,它是linux系统中用户空间的第一个进程,其进程PID是1,父进程为linux 系统内核的0号进程。所以其被赋予很多极其重要的职责,linux内核初始化完成后就开始执行它。代码路径:\system\core\init\init.c 下面就分析一下先吧,只分析重点的函数功能: int main(int argc, char **argv) { // 1、设置子进程退出的信号处理

hnlgzb的专栏 251

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

linux/init.h android,android启动—深入理解init进程

[导读]init是一个进程,它是linux系统中用户空间的第一个进程,其进程PID是1,父进程为linuxinit是一个进程,它是linux系统中用户空间的第一个进程,其进程PID是1,父进程为linux系统内核的0号进程。所以其被赋予很多极其重要的职责,linux内核初始化完成后就开始执行它。代码路径:\system\core\init\init.c下面就分析一下先吧,只分析重点的函数功能:in...

weixin_32098191的博客 268

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Android系统启动流程(一)解析init进程启动过程

前言 作为“Android框架层”这个大系列中的第一个系列,我们首先要了解的是Android系统启动流程,在这个流程中会涉及到很多重要的知识点,这个系列我们就来一一讲解它们,这一篇我们就来学习init进程。 1、init简介 init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等。init进程是由多个源文件共同组成的,这些文件位于源码目录system/core/init。本文将基于Android7.0源码来分

songzi1228的博客 1486

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Android之init启动流程(一)

本文着重分析android-init启动liuch

kevin's cache的专栏 1256

Android系统启动流程完整分析(一)

接触Android也有几年了,最近想对Android系统的启动流程做一个完整的分析总结,以便后续学习 。 (1)Android架构介绍 我们先来看一下Android文档给的一份系统架构图。 从以上可以看到,Android大体上被分为4个模块(Kernel,Hal/Native,Java Framework,Apps)。 接下来我们从系统启动的角度来看两种更加详细的图。 从上图可以看出,系统启动我们底层将其主要分为三个部分。 Android设备上电后,首先会从处理器片上ROM的启动引导代码开始执行,片

Flying snow 1552

Android 系统启动流程

Android系统启动,一共分七个流程,Android系统启动流程图: Android系统启动要比图上更复杂,这里是为了便于列举简化了细节。对于Android应用开发来说,这些知识点已经足够了。 1.启动电源以及系统启动 当电源按下时,引导芯片代码从预定义的地方(固化在ROM)开始执行。加载引导程序BootLoader到RAM,然后执行。 2.引导程序BootLoader 引导程序BootLoa...

王小_的博客 329

Android系统启动过程

首先Android框架架构图:(来自网上,我觉得这张图看起来很清晰)    Linux内核启动之后就到Android Init进程,进而启动Android相关的服务和应用。 启动的过程如下图所示:(图片来自网上,后面有地址)           下面将从Android4.0源码中,和网络达人对此的总结中,对此过程加以学习了解和总结, 以下学习过程中代码

tianruxishui的专栏 724

Android Init进程分析

原文:http://www.tuicool.com/articles/fqy2Qn 之前在看android启动过程总是带着完成工作任务的目的去分析代码,但是对于一些代码的细节并不是很清楚,在这里就分析一下Init进程的执行过程。 Init进程是android系统起来之后启动的第一个进程,对于研究android系统的启动过程很重要。 直接根据代码来分析整个进程的执行过程。 i

u013815973的专栏 640

Android从BIOS到Zygote到SystemService到Launcher启动概况

不想当将军的士兵不是好的士兵,作为Android开发 肯定好奇手机启动到运行经历了什么。最近有点时间,所以看了几本书。有《LINUX SYSTEM PROGRAMING》、《Android源码分析实录》。 只写流程和重要的几个点。代码都可以在《Android源码分析实录》上找到,太多我就不写了。开机第一个程序BIOS: BIOS程序启动,检查硬件。 BIOS是烧在主板上上的只读程序,叫做韧体。

zhjali123的专栏 760

浅谈Android系统启动过程

本篇文章主要介绍Android启动过程,Android是基于Linux内核的简易操作系统,init是Android中第一个启动的进程。

EdisonChang的博客 1495

【Android FrameWork】系统启动流程

Android系统启动流程

studyForMokey的博客 323
上一篇: android系统硬件OpenGL 3D 移植
下一篇: android启动--深入理解zygote
andyhuabing
博客等级 码龄19年 704粉丝 165原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值