ANDROID init进程
init简要
init是Android上启动的第一个用户态进程。
执行序列是:
start_kernel() -> rest_init() -> kernel_init() -> init_post() -> run_init_process()
if (ramdisk_execute_command) { //rdinit, default "/init"
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command);
}
ramdisk_execute_command是内核启动参数rdinit指定的值,默认为“/init”。
static void run_init_process(const char *init_filename)
{
argv_init[0] = init_filename;
kernel_execve(init_filename, argv_init, envp_init);
}
至此,内核初始化完毕,用户init进程开始启动。
init功能
Android的init进程源码位于aosp的system/core/init目录,主要完成了4项工作:
解析处理init.rc文件
生成设备驱动节点
处理子进程终止
属性读取、设置服务
1)处理子进程终止
init子进程终止处理的初始化在signal_init函数完成。
/* signal_handler.c */
void signal_init(void)
{
int s[2];
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = sigchld_handler;
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &act, 0); //@1
/* create a signalling mechanism for the sigchld handler */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { @2
signal_fd = s[0]; @3
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);
}
handle_signal();
}
首先@1注册了SIGCHLD信号处理函数sigchld_handler,用于设置全局signal_fd。
/* signal_handler.c */
static void sigchld_handler(int s) //s是SIGCHLD信号编号
{
write(signal_fd, &s, 1);
}
接着@2创建UNIX域套接字,关联signal_fd、signal_recv_fd。
当子进程终止,SIGCHLD信号编号被写入socketpair的signal_fd @3,信号编号将传递到接收端的socket_recv_fd套接字。socket_recv_fd已经注册到POLL,因此SIGCHLD信号将触发其POLLIN事件,poll事件监听返回,执行wait_for_one_proces。
/* init.c */
/* init的事件循环 */
for(;;) {
nr = poll(ufds, fd_count, timeout); //接收SIGCHLD信号后,监听返回
if (nr <= 0)
continue;
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd()) //socket_recv_fd事件
handle_signal();
}
}
}
在wait_for_one_process函数中,将完成进程资源回收或进程重启工作。
void handle_signal(void)
{
char tmp[32];
/* we got a SIGCHLD - reap and restart as needed */
read(signal_recv_fd, tmp, sizeof(tmp));
while (!wait_for_one_process(0))
;
}
2)生成设备驱动节点
init会创建并挂载系统启动所需的文件目录,编译Android系统源码时,并不存在/dev、/proc、/sys等目录,它们是系统运行时由init进行生成的。在Android上,init扮演着Linux系统上udev守护进程的角色。
/* init.c */
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "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);
3)init.rc解析
init会解析两个配置文件,分别是init.rc和init.{hardware}.rc,两者语法是一样的,init.{hardware}.rc中是与硬件相关的一些配置信息。
init.rc文件大致分为两大部分,一部分是以on关键字开头的动作列表(Action List),一部分是以service关键字开头的服务列表(Service List)。
动作列表主要进行一些属性,环境配置,示例:
on init
sysclktz 0
loglevel 3
# Backward compatibility
symlink /system/etc /etc
symlink /sys/kernel/debug /d
# Right now vendor lives on the same filesystem as system,
# but someday that may change.
symlink /system/vendor /vendor
# Create cgroup mount point for cpu accounting
mkdir /acct
mount cgroup none /acct cpuacct
mkdir /acct/uid
on post-fs
# once everything is setup, no need to modify /
mount rootfs rootfs / ro remount
# mount shared so changes propagate into child namespaces
mount rootfs rootfs / shared rec
on boot
# basic network init
ifup lo
hostname localhost
domainname localdomain
# set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
服务列表用来记录init进程启动的进程,包括运行一次的程序,Daemon进程等,示例:
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0
service healthd /sbin/healthd
class core
critical
seclabel u:r:healthd:s0
service healthd-charger /sbin/healthd -n
class charger
critical
seclabel u:r:healthd:s0
on property:selinux.reload_policy=1
restart ueventd
restart installd
init.rc文件解析是在main函数完成的。
init_parse_config_file("/init.rc");
4)属性读取、设置服务
属性变更请求是init事件处理循环中的另一个事件。
/* init.c */
if (!property_set_fd_init && get_property_set_fd() > 0) {
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
}
在Android平台中,为了让运行中的所有进程共享系统运行时所需要的各种环境变量,系统开辟了一块称作属性的共享内存区域,并提供了访问该区域的API。
Android平台的属性是K-V的键值对。系统中所有进程都可以读取属性值,但只有init进程才能修改它。其它进程修改属性值,需向init进程提出请求,并由init进程进行权限检查后,决定是否修改,这之间是通过UNIX域套接字进行通信。
当属性值更改后,若定义在init.rc中的某个特定条件得到满足,则与此条件相匹配的动作就会执行。每个动作都有一个触发器(Trigger),记录在on property关键字后。
/* init.rc */
on property:selinux.reload_policy=1
restart ueventd
restart installd //selinux策略改变时,重启installd进程
这块内存区域初始化是在property_init函数中完成的:
/* property_service.c */
void property_init(void)
{
init_property_area();
}
接着读入并解析default.prop配置文件,设置初始化属性值:
/* property_service.c */
// #define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
void property_load_boot_defaults(void)
{
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}
系统中进程与init的通信使用unix域套接字,套接字在start_property_service中完成创建。接下来就可以通过property_get和property_set访问这些属性值了。
具体unix域套接字处理请求的实现,就不再赘述。
ro.debuggable 是只读属性(**R**ead**O**nly),这种属性初始化完,不允许修改。
ANDROID init进程的更多相关文章
- android init进程分析 init脚本解析和处理
(懒人近期想起我还有csdn好久没打理了.这个android init躺在我的草稿箱中快5年了.略微改改发出来吧) RC文件格式 rc文件是linux中常见的启动载入阶段运行的文件.rc是run co ...
- Android init进程概述
init进程,其程序位于根文件系统中,在kernle自行启动后,其中的 start_kernel 函数把根文件系统挂载到/目录后,在 rest_init 函数中通过 kernel_thread(ker ...
- Android Init进程命令的执行和服务的启动
这里开始分析init进程中配置文件的解析,在配置文件中的命令的执行和服务的启动. 首先init是一个可执行文件,它的对应的Makfile是init/Android.mk. Android.mk定义了i ...
- android init进程分析 ueventd
转自:http://blog.csdn.net/freshui/article/details/2132299 (懒人最近想起我还有csdn好久没打理了,这个Android init躺在我的草稿箱中快 ...
- Android init.rc解析【转】
转自:http://www.linuxidc.com/Linux/2014-10/108438.htm 本文主要来自$Android_SOURCE/system/init/readme.txt的翻译. ...
- init进程 && 解析Android启动脚本init.rc && 修改它使不启动android && init.rc中启动一个sh文件
Android启动后,系统执行的第一个进程是一个名称为init 的可执行程序.提供了以下的功能:设备管理.解析启动脚本.执行基本的功能.启动各种服务.代码的路径:system/core/init,编译 ...
- Android系统开机启动流程及init进程浅析
Android系统启动概述 Android系统开机流程基于Linux系统,总体可分为三个阶段: Boot Loader引导程序启动Linux内核启动Android系统启动,Launcher/app启动 ...
- Android系统启动流程(一)解析init进程启动过程
整体流程大致如下: 1.init简介 init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等.in ...
- Android系统init进程启动及init.rc全解析
转:https://blog.csdn.net/zhonglunshun/article/details/78615980 服务启动机制system/core/init/init.c文件main函数中 ...
随机推荐
- Object对象的浅拷贝与深拷贝方法详解
/* ===================== 直接看代码 ===================== */ <!DOCTYPE html> <html> <head& ...
- Spring控制反转(依赖注入)的最简单说明
1.常规方式实现实例化 1.1已有角色如下: 一个接口Interface,两个接口实现类InstatnceA.InstanceB,一个调用类User 1.2当前实例化InstanceA如下: Inte ...
- VMware进入BIOS
在虚拟机关机状态下,点击“虚拟机”--“电源”--“打开电源时进入固件”即自动启动进入bios
- Kali配置教程
1.配置软件源 所有操作没有说明,都是以root身份执行. 打开一个终端执行: cat >> /etc/apt/sources.list <<EOF deb http://mi ...
- mybatis标签之——<trim>及 <foreach collection>
https://www.cnblogs.com/zjfjava/p/8882614.html trim标记是一个格式化的标记,主要用于拼接sql的条件语句(前缀或后缀的添加或忽略),可以完成set或者 ...
- linux查看在线用户并踢出用户
linux查看在线用户并踢出用户 1.查看在线用户 w [root@dbserver01 ~]# w 16:45:04 up 16 days, 8:48, 1 user, load average: ...
- JavaScrip(三)JavaScrip变量高级操作(字符串,数组,日期)
一:字符串 charAt() 返回指定位置的字符 indexof() 返回指定字符串首次出现的位置 replace() 替换指定的字符 concat() 连接两个或多个字符串 substr(start ...
- MYSQL数据库字母数字混合字段排序问题
对MySQL数据表里的一个字符型字段排序,其内容格式为一位字母+顺序数字.数字没有前导零,长度不固定.这种含字母的数字序列,排序出来的结果和我们想要的结果是不一样的,因为它不是纯数字,只能按字符规则排 ...
- SignalR 开始聊天室之旅
首先明确需求,我现在有很多个直播间,每个直播间内需要存在一个聊天室,每个聊天室内可以存在很多人聊天,当然,只有登陆系统的会员才能聊天,没有登陆的,干看着吧! 根据以上需求,可以做出三个简单的页面:登陆 ...
- ftp上传操作
采用 :FtpWebRequest 进行操作ftp. 1.代码上传文件必须是被动模式 UsePassive=false 2.最好采用二进制传输 UseBinary=true 注意缓冲区大小,还有注意 ...