android开机过程.docx

上传人:b****0 文档编号:18048173 上传时间:2023-08-07 格式:DOCX 页数:30 大小:82.78KB
下载 相关 举报
android开机过程.docx_第1页
第1页 / 共30页
android开机过程.docx_第2页
第2页 / 共30页
android开机过程.docx_第3页
第3页 / 共30页
android开机过程.docx_第4页
第4页 / 共30页
android开机过程.docx_第5页
第5页 / 共30页
android开机过程.docx_第6页
第6页 / 共30页
android开机过程.docx_第7页
第7页 / 共30页
android开机过程.docx_第8页
第8页 / 共30页
android开机过程.docx_第9页
第9页 / 共30页
android开机过程.docx_第10页
第10页 / 共30页
android开机过程.docx_第11页
第11页 / 共30页
android开机过程.docx_第12页
第12页 / 共30页
android开机过程.docx_第13页
第13页 / 共30页
android开机过程.docx_第14页
第14页 / 共30页
android开机过程.docx_第15页
第15页 / 共30页
android开机过程.docx_第16页
第16页 / 共30页
android开机过程.docx_第17页
第17页 / 共30页
android开机过程.docx_第18页
第18页 / 共30页
android开机过程.docx_第19页
第19页 / 共30页
android开机过程.docx_第20页
第20页 / 共30页
亲,该文档总共30页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

android开机过程.docx

《android开机过程.docx》由会员分享,可在线阅读,更多相关《android开机过程.docx(30页珍藏版)》请在冰点文库上搜索。

android开机过程.docx

android开机过程

一、Android开机启动流程简介

1、OS-level:

由bootloader载入linuxkernel后kernel开始初始化,并载入built-in的驱动程序。

Kernel完成开机后,载入initprocess,切换至user-space。

Init进程是第一个在user-space启动的进程。

2、Android-level:

由initprocess读取init.rc,Native服务启动,并启动重要的外部程序,例如:

servicemanager、Zygote以及SystemServer等。

由initprocess根据硬件类型读取init.xxx.rc。

由init.xxx.rc加载init.xxx.sh。

由init.xxx.sh加载特定的硬件驱动。

如hi_tuner.ko、hi_demux.ko等。

3、Zygote-Mode:

Zygote启动完SystemServer后,进入ZygoteMode,在Socket等候命令。

随后,使用者将看到一个桌面环境(HomeScreen)。

桌面环境由一个名为[Launcher]的应用程序负责提供。

本文档重点研究Android-level中的启动流程。

启动流程如下图所示:

二、initprocess流程分析

init进程简介

init进程是第一个在user-space启动的进程。

由内核启动参数[init]传递给内核,如果该项没有设置,内核会按

/etc/init,/bin/init,/sbin/init,/bin/sh的顺序进行尝试,如果都有的都没找到,内核会抛出kernelpanic:

的错误。

init进程包含在跟文件系统中,跟文件系统被直接编译到了内核。

对init进程的修改,需要重新编译烧写内核。

编译命令:

#cdkernel

#makeuImag

CONFIG_INITRAMFS_SOURCE=../out/target/product/Hi3716C/root/-j8

#cpkernel/arch/arm/boot/uImageout/target/product/Hi3716C/kernel-afv

源代码路径:

froyo\system\core\init

编译的文件:

builtins.c

init.c

devices.c

property_service.c

util.c

parser.c

logo.c

编译命令:

makeinit

生成的文件:

/out/target/product/Hi3716C/root/init

init进程启动流程

1.安装SIGCHLD信号。

sigaction(SIGCHLD,&act,0);

如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。

因此需要对SIGCHLD信号做出处理,回收僵尸进程的资源,避免造成不必要的资源浪费。

2.对umask进行清零。

umask(0);

umask是什么?

登录系统之后创建一个文件总是有一个默认权限的,那么这个权限是怎么来的呢?

这就是umask干的事情。

umask设置了用户创建文件的默认权限,它与chmod的效果刚好相反,umask设置的是权限“补码”,而chmod设置的是文件权限码。

设置文件的默认权限,umask和chmod的权限刚好反的,umask的0000相当于chmod的0777。

3.为rootfs建立必要的文件夹,并挂载适当的分区。

mkdir("/dev",0755);

mkdir("/proc",0755);

mkdir("/sys",0755);

mount("tmpfs","/dev","tmpfs",0,"mode=0755");

mkdir("/dev/pts",0755);

mkdir("/dev/socket",0755);

mount("devpts","/dev/pts","devpts",0,NULL);

mount("proc","/proc","proc",0,NULL);

mount("sysfs","/sys","sysfs",0,NULL);

4.创建/dev/null和/dev/kmsg节点。

创建/dev/null结点,重定向标准输入,输出以及标准出错。

open_devnull_stdio();

创建/dev/kmsg设备结点,我们可以利用这个设备输出调试信息

log_init();

5.解析/init.rc,将所有服务和操作信息加入链表。

解析初始化脚本,这里只是parse,将脚本解析到一个链表中,并没有执行。

parse_config_file("/init.rc");

6.从/proc/cmdline中提取信息内核启动参数,并保存到全局变量。

qemu_init();

import_kernel_cmdline(0);

7.根据6获得的hardware参数信息,解析额外的硬件相关init脚本.

hi3726c中为init.godbox.rc

get_hardware_name();

snprintf(tmp,sizeof(tmp),"/init.%s.rc",hardware);

parse_config_file(tmp);

8.找到init.rcpaser链表中为early-init属性的项目,将其添加到actionqueue中,并执行执行这些queue中的动作。

action_for_each_trigger("early-init",action_add_queue_tail);

drain_action_queue();

9.遍历/sys文件夹,是内核产生设备添加事件(为了自动产生设备节点)。

device_fd=device_init();

10.初始化属性系统,并导入初始化属性文件。

property_init();

每个属性都有一个名称和值,它们都是字符串格式。

属性被大量使用在Android系统中,用来记录系统设置或进程之间的信息交换。

属性是在整个系统中全局可见的。

每个进程可以get/set属性。

在系统初始化时,Android将分配一个共享内存区来存储的属性,这里主要是从/default.prop属性文件读取属性。

类似于像Windows下的注册表的作用。

/default.pro的内容

ro.secure=0

ro.allow.mock.location=1

ro.debuggable=1

persist.service.adb.enable=1

11.从属性系统中得到ro.debuggable,若为1,則初始化keychord监听。

keychord_fd=open_keychord();

12.判断是否有控制台,如果没有,就尝试是否是可以打缺省的控制台。

缺省控制台名称:

staticchar*console_name="/dev/console";

if(console[0]){

snprintf(tmp,sizeof(tmp),"/dev/%s",console);

console_name=strdup(tmp);

}

fd=open(console_name,O_RDWR);

if(fd>=0)

have_console=1;

close(fd);

13.读取/initlogo.rle,如果成功則在/dev/graphics/fb0显示Logo,如果失败则将/dev/tty0设为文本模式,并打开/dev/tty0,输出文本“ANDROID”。

if(load_565rle_image(INIT_IMAGE_FILE)){

fd=open("/dev/tty0",O_WRONLY);

if(fd>=0){

constchar*msg;

msg="\n"

"\n"

"\n"

"\n"

"\n"

"\n"

"\n"/*consoleis40colsx30lines*/

"\n"

"\n"

"\n"

"\n"

"\n"

"\n"

"\n"

"ANDROID";

write(fd,msg,strlen(msg));

close(fd);

}

}

14.判断是否使用模拟器运行,如果时,就加载内核命令行参数。

if(qemu[0])

import_kernel_cmdline

(1);

15.根据内核命令行参数来设置工厂模式测试。

if(!

strcmp(bootmode,"factory"))

property_set("ro.factorytest","1");

elseif(!

strcmp(bootmode,"factory2"))

property_set("ro.factorytest","2");

else

property_set("ro.factorytest","0");

16.设置序列号属性值。

property_set("ro.serialno",serialno[0]?

serialno:

"");

17.设置启动模式属性值。

property_set("ro.bootmode",bootmode[0]?

bootmode:

"unknown");

18.设置基带频率属性值。

property_set("ro.baseband",baseband[0]?

baseband:

"unknown");

19.设置硬件载波方式属性值。

property_set("ro.carrier",carrier[0]?

carrier:

"unknown");

20.设置引导程序的版本号属性值。

property_set("ro.bootloader",bootloader[0]?

bootloader:

"unknown");

21.设置硬件信息属性值。

property_set("ro.hardware",hardware);

22.设置硬件版本号属性值

snprintf(tmp,PROP_VALUE_MAX,"%d",revision);

property_set("ro.revision",tmp);

23.添加所有的init命令到队列,然后再执行。

action_for_each_trigger("init",action_add_queue_tail);

drain_action_queue();

24.加载system和data目录下的属性,并启动属性监听服务。

property_set_fd=start_property_service();

加载的属性文件为:

#definePROP_PATH_SYSTEM_BUILD"/system/build.prop"

#definePROP_PATH_SYSTEM_DEFAULT"/system/default.prop"

#definePROP_PATH_LOCAL_OVERRIDE"/data/local.prop"

25.创建一个全双工的通讯机制的两个SOCKET,信号可以在signal_fd和signal_recv_fd双向通讯,从而建立起沟通的管道。

这个信号管理,就是用来让init进程与它的子进程进行沟通的,子进程从signal_fd写入信息,init进程从signal_recv_fd收到信息,然后再做处理。

if(socketpair(AF_UNIX,SOCK_STREAM,0,s)==0){

signal_fd=s[0];

signal_recv_fd=s[1];

fcntl(s[0],F_SETFD,FD_CLOEXEC);

fcntl(s[0],F_SETFL,O_NONBLOCK);

fcntl(s[1],F_SETFD,FD_CLOEXEC);

fcntl(s[1],F_SETFL,O_NONBLOCK);

}

26.判断设备文件系统device_fd是否成功初始化,属性服务property_set_fd是否成功初始化,信号通讯机制signal_recv_fd是否成功初始化。

if((device_fd<0)||(property_set_fd<0)||(signal_recv_fd<0)){

ERROR("initstartupfailure\n");

return1;

}

27.执行early-boot和boot属性的命令。

action_for_each_trigger("early-boot",action_add_queue_tail);

action_for_each_trigger("boot",action_add_queue_tail);

drain_action_queue();

28.执行当前载入的属性命令。

并标明属性触发器已经初始化完成。

queue_all_property_triggers();

drain_action_queue();

property_triggers_enabled=1;

29.保存设备文件系统device_fd,属性服务property_set_fd,信号通讯机制signal_recv_fd,以便后面轮询使用。

ufds[0].fd=device_fd;

ufds[0].events=POLLIN;

ufds[1].fd=property_set_fd;

ufds[1].events=POLLIN;

ufds[2].fd=signal_recv_fd;

ufds[2].events=POLLIN;

fd_count=3;

30.判断是否处理组合键轮询。

if(keychord_fd>0){

ufds[3].fd=keychord_fd;

ufds[3].events=POLLIN;

fd_count++;

}else{

ufds[3].events=0;

ufds[3].revents=0;

}

31.初始化linux程序启动速度的性能分析工具。

#ifBOOTCHART

bootchart_count=bootchart_init();

if(bootchart_count<0){

ERROR("bootchartinginitfailure\n");

}elseif(bootchart_count>0){

NOTICE("bootchartingstarted(period=%dms)\n",\

bootchart_count*BOOTCHART_POLLING_MS);

}else{

NOTICE("bootchartingignored\n");

}

#endif

32.进入主进程循环,重置轮询事件状态、查询action队列,并执行、重启需要重启的服务、轮询注册的事件状态。

for(;;){

intnr,i,timeout=-1;

for(i=0;i

ufds[i].revents=0;

}

drain_action_queue();

restart_processes();

if(process_needs_restart){

timeout=(process_needs_restart-gettime())*1000;

if(timeout<0)

timeout=0;

}

#ifBOOTCHART

if(bootchart_count>0){

if(timeout<0||timeout>BOOTCHART_POLLING_MS)

timeout=BOOTCHART_POLLING_MS;

if(bootchart_step()<0||--bootchart_count==0){

bootchart_finish();

bootchart_count=0;

}

}

#endif

nr=poll(ufds,fd_count,timeout);

if(nr<=0)

continue;

if(ufds[2].revents==POLLIN){

/*wegotaSIGCHLD-reapandrestartasneeded*/

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

}

三、init.rc脚本加载流程分析

1、init.rc脚本语法介绍

Android初始化语言由四大类声明组成:

行为类(Actions),命令类(Commands),服务类(Services),选项类(Options)。

*初始化语言以行为单位,由以空格间隔的语言符号组成。

C风格的反斜杠转义符可以用来插入空白到语言符号。

双引号也可以用来防止文本被空格分成多个语言符号。

当反斜杠在行末时,作为折行符。

*以#开始(前面允许有空格)的行为注释行。

*Actions和Services隐含声明一个新的段落。

所有该段落下Commands或

Options的声明属于该段落。

第一段落前的Commands或Options被忽略。

*Actions和Services拥有独一无二的命名。

在它们之后声明相同命名的类将

被当作错误并忽略。

●Actions

Actions是一系列命令的命名。

Actions拥有一个触发器(trigger)用来决定action何时执行。

当一个action在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,则加入到队列最后。

队列中的action依次执行,action中的命令也依次执行。

Init在执行命令的中间处理其它活动(设备创建/销毁,property设置,进程重启)。

Actions语法形式为:

on

...

●Services

Services是由init启动,在它们退出时重启(可选)。

Service表现形式为:

service[]*

...

●Options

Options是Services的修饰,它们影响init何时、如何运行service.

critical

这是一个设备关键服务(device-criticalservice).

如果它在4分钟内退出超过4次,设备将重启并进入恢复模式。

disabled

该服务将不会自动启动,它必须被依照服务名指定启动才可以启动。

setenv

设置已启动的进程的环境变量的值

socket[[]]

创建一个名为/dev/socket/的unixdominsocket,并传送它的fd

到已启动的进程。

必须为"dgram"或"stream".用户和组默认为0.

user

在执行服务前改变用户名。

group[]*

在执行服务前改变组。

在第一个组后的组将设为进程附加组

(通过setgroups()).当前默认为root.

oneshot

在服务退出后不重启。

class

为service指定一个类别名。

同样类名的所有的服务可以一起启动或停止。

如果没有指定类别的服务默认为"default"类。

onrestart

当服务重启时执行一个命令。

●Triggers

触发器是一个字符串,可以用来匹配某种类型的事件并执行一个action。

Boot

这是当init开始后执行的第一个触发器(当/init.conf被加载)

=

当property被设为指定的值时触发。

device-added-

device-removed-

当设备节点被添加或移除时触发。

service-exited-

当指定的服务存在时触发

●Commands

exec[]*

Fork并执行一个程序().这将被block直到程序执行完毕。

最好避免

执行例如内建命令以外的程序,它可能会导致init被阻塞不动。

export

设定全局环境变量的值,当这个命令执行后所有的进程都可

以取得该环境变量的值。

ifup

使网络接口联机。

import

解析一个init配置文件,扩展当前配置文件。

hostname

设置主机名

chmod

改变文件访问权限

chown

改变文件所属和组

class_start

当指定类别的服务没有运行,启动该类别所有的服务。

class_stop

当指定类别的服务正在运行,停止该类别所有的服务。

domainname

设置域名。

insmod

加载该路径的模块

mkdir[mode][owner][group]

创建一个目录,可选选项:

mod,owner,group.如果没有指定,目录以

755权限,owner为root,group为root创建。

mount

[]*

尝试mount到目录

.可以用mtd@name格式以命名指

定一个mtd块设备。

包含"ro","rw","remount","noatime".

setprop

设置系统property的值<

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2