Android创世纪 - 第二天
转自:http://www.cnblogs.com/hangxin1940/archive/2011/10/14/2206754.html
第二天,google说,荒芜要被开垦,系统便运作了,它是linux。
--xxx
荒蛮大地就要变得肥沃,linux已经运行起来了。。。。
linux就不多讲了,这里只讲讲被google大刀阔斧改了内核后的linux。
第一天最后,内核init已经干完了自己的事,把控制权交给了第一个用户级进程,也叫做init。
想知道这个init干了什么事,我们只能看看源码,不贴代码,这里只说说它干了什么。
(system/core/init/init.c -->main)
一、清空umask
也就是设置缺省权限,这里设置为0,umask为0000的话,就相当于chmod中的0777,经常使用linux对于chmod 777应该很熟悉,就是赋予某个文件的权限为,所有组、所有用户可读可写可运行,也就是最宽松的权限。
二、创建并挂载一些基本的目录
创建目录并挂载相应系统:
/dev 设备目录,所有的外围设备都在这里了,包括真实的设备如sim卡,也包括虚拟的设备如必不可少的null设备。挂载关系是 /dev -> tmpfs,tmpfs顾名思义就是临时文件系统,这个系统只占用内存空间。
/proc 系统信息目录,包含了当前系统的所有信息,比如进程、时钟等等动态的信息。挂载关系是 /proc -> proc
/sys 这里存储的东西,都是硬件设备在linux上映射的对象,比如pci设备。挂载关系是 /sys -> sysfs
/dev/pts 这个是远程终端控制台设备,字符终端啦,如果木有这个的话,就不可能adb shell调试android。挂载关系是 /dev/pts -> devpts
/dev/socket 服务于android的,socket是linux中进程通信的一种方式,/dev/socket下面就是已经被系统分配的soket资源,这里基本上是一些本地服务,比如ridl,有兴趣可以adb shell查看一下。
三、初始化NULL设备,重定向标准输入输出,初始化kmsg系统,并且解析init.rc文件
null是Linux的一个标准设备,也就是所谓的黑洞,至于为什么有它,就得从输入输出重定向说起,比如linux控制台下运行一个程序,有时会输出一 大堆东西,这是它向标准输出写的,我们不想让它显示出来,就是用 > NULL给它的输出重定向到了这个黑洞设备,系统呢会给这个程序返回一个写入成功的操作,实质上,系统什么都木有干。
kmsg是linux下的一个内核级的日志系统,kernel message。就好比anroid提供的Log系统一样,只是针对内核级别的。
对于init.rc文件,这里只进行了解析,并没有执行里面的一些命令。
四、获得内核命令参数并且解析特定机型的init.*.rc文件
获得内核命令参数,也就是显式说明的一些参数,如果配置过grub或者Loli的话,就可能与这个打过交道。
每个手机硬件平台都不一样,adb shell一下,会发现有两个rc文件,其中一个就是与特定平台有关的rc配置文件,比如我的defy就是init.mapphone_umts.rc, 为什么叫这个?中间就是手机硬件平台的名字,可以 cat /proc/cpuinfo来获得Hardware信息,我的如下:
01 | # cat cpuinfo |
02 | cat cpuinfo |
03 | Processor : ARMv7 Processor rev 2 (v7l) |
04 | BogoMIPS : 299.11 |
05 | Features : swp half thumb fastmult vfp edsp neon vfpv3 |
06 | CPU implementer : 0x41 |
07 | CPU architecture: 7 |
08 | CPU variant : 0x3 |
09 | CPU part : 0xc08 |
10 | CPU revision : 2 |
11 |
12 | Hardware : mapphone_UMTS |
13 | Revision : 0000 |
14 | Serial : 0000000000000000 |
15 | CPU Tier : 10 |
可以看到Hardware的值就是rc的副名称。
init首先会获得/porc/cpuinfo中的这个属性值,然后根据这个字符串查找特定的rc文件,最后根据rc中的配置内容,解析它。
五、执行rc文件中的命令
上一步,init已经解析了那两个rc文件,这里,会根据rc文件中的具体内容,来分别执行对应的动作,后面会独立分析rc文件的格式内容,以及执行方法。
六、变为守护神
到这里,init就进入了死循环了for(;;){}。那么它都守护了些什么?
1、porpety service 启动并守护属性服务
android下特有的。就好比windows下面的注册表,记录了各种信息。大到系统是否成功运行的标志,小到短信声音。用户在设置一些手机设置的时候,在底层,实际就是和propety service打交道。
属性前缀 | 描述 | 示例(shell下操作) |
ro. | 只读属性 | setprop ro.media.capture.maxres 5m 摄像头的最大像素 |
persist. | 额外存储到/data/property目录下 | setprop persist.sys.country CN 不解释。注意,每个属性都存储为单独的一个文件 |
net. | 联网相关,比如gprs、蓝牙… | setprop net.bt.name CAPF 蓝牙的网络名称为CAPF net.change的值为最后一次更改net.*属性的属性名,例如: net.change=net.gprs.local-ip |
ctrl.start 控制命令 | 启动init.rc中标注为service的服务 | setprop ctl.start bootanim 启动boot动态图像(第二屏启动画面) 一个服务设置后,其结果会以下面的属性返回,例如 init.svc.bootanim=running |
ctrl.stop | 停止init.rc中标注为service的服务 | setprop ctl.stop bootanim 停止boot动态图像(第二屏启动画面) 一个服务设置后,其结果会以下面的属性返回,例如 init.svc.bootanim=stoped |
想要查看并设置属性,可以通过以下三种途径:
shell浏览文件:
/default.prop
/system/build.prop
/data/property/*
java:
System.getProperty(“xxxx”);
System.setProperty(“xxxx”);
c/c++:
demo.c:
01 | #include <cutils/properties.h> |
02 | #include <stdio.h> |
03 | void print_prop( const char * key, const char * value, void * cookie) |
04 | { |
05 |
printf ( "key=%s,value=%s/n" ,key,value); |
06 | } |
07 |
08 | int main() |
09 | { |
10 |
property_list(print_prop,NULL); |
11 | } |
Android.mk:
01 | LOCAL_PATH:= $(call my- dir ) |
02 |
03 | include $(CLEAR_VARS) |
04 |
05 | LOCAL_SRC_FILES:= / |
06 |
07 | list_property.cpp / |
08 |
09 | LOCAL_SHARED_LIBRARIES := / |
10 |
11 | libcutils / |
12 |
13 | libutils / |
14 |
15 | LOCAL_MODULE:= list_prop |
16 |
17 | include $(BUILD_EXECUTABLE) |
18 |
19 | include $(call all-makefiles-under,$(LOCAL_PATH)) |
2、动态生成设备节点
android的linux下面是没有udev的,udev可以说是一个根据内核的硬件消息来自动发现设备的一个程序,android下面根据硬件相应 的,也就是键盘与内存卡,在平板上面的话就更多了,比如鼠标、键盘等等。没有udev的话,android是如何实现硬件的热插拔呢?
和udev一样,init守护神同样监听了uevent事件,自己根据uevent的内容来做相应的事情,与udev做了异曲同工之事。
看一下大致流程。首先设备状态更改,内核会检测到,并发出uevent消息(字符串),init检测到消息,交给相应函数处理,这个函数根据uevent 的内容,再做进一步处理。除了插拔内存卡等(android有专门的外存管理机制,就是vold),其它(比如数据线插入、鼠标插入)都会处理。
3、监听keychord事件
keychord是组合按键,从源码的行为来看,应该是考虑到组合键盘这种外设,大部分情况不会用到手机上,而多用在智能设备上,也就是没有触屏以及按键 很少的android设备,比如运行android的手表神马的,通过不同的按键组合,来代表一个标准键盘的输入。
这个东东估计用的不多。
4、杀死僵尸进程
什么是僵尸进程?
linux的进程有个特点,一个主进程可以分裂(fork)子进程(android的受精卵zygote完美的发扬了这种精神),在桌面版的一些 linux中,查看系统监视器,仔细看看进程信息,会发现很多进程会是树状结构,点击一个进程后面又展开了好几个进程,而且是个多级树。这都是一个进程有 fork了好几个子进程的结果。
如果主进程被kill的话,那么它的子进程就有可能成为僵尸进程,所谓僵尸就是不干活但占用空间的程序死尸,这时,init守护神就负责回收这些无辜的灵魂,来释放本来就稀缺的内存资源。
5、守护重要服务
这些服务是native层面的服务,比如servicemanager、vold。例如重要的zygote,有时候(不经常)碰到的感觉和突然重启一样,这八成就是zygote崩溃并重启了,要知道java世界可是zygote孵化出来的。
解读init.rc
android的init.rc语法是独有的,可以说是一种语言吧。
init.rc的语法分为行为(Actions),、命令(Commands)、服务(Services)、选项(Options)。
类别 | 名称 | 描述 |
SECTION | on | 触发条件 |
同上.. | service | 解析service |
COMMAND | chdir | 更改当前工作目录 |
同上.. | chroot | 更改参考的根目录位置 |
.. | class_start | 启动某个设置了class名称的服务 |
.. | class_stop | 停止某个设置了class名称的服务 |
.. | domainname | 域名 |
.. | exec | 调用程序并转移进程 |
.. | export | 提交变量 |
.. | hostname | 主机名 |
.. | ifup | 激活网卡 |
.. | insmod | 挂载模块 |
.. | import | 引入配置,比如etc下的一些rc文件,和java中的import差不多 |
.. | mkdir | 建立目录 |
.. | mount | 挂载文件系统 |
.. | setkey | 从源码看,应该是设置一个命令的关键字缩写,比如可以将domainname映射为dn |
.. | setprop | 设置一个属性 |
.. | setrlimit | 设置当前程序可以打开的最大文件数到系统规定程序可以打开的最大文件数 |
.. | start | 启动服务 |
.. | stop | 停止服务 |
.. | trigger | 不清楚,难道是自定义触发器? |
.. | symlink | 建立符号链接 |
.. | sysclktz | 设置基准时间 |
.. | wait | 等待文件准备好?Linux中这是进程调度的函数 |
.. | write | 向文件、设备写个什么东西。肯定不是传消息的那个wirte |
.. | copy | 不解释 |
.. | chown | 更改所有者 |
.. | chmod | 更改权限 |
.. | loglevel | Log输出级别,低于这个级别的就输出 |
.. | restart | 重启服务 |
OPTION | capability | 能力,也就是系统对进程的一种权限控制。 |
同上.. | class | 设置class name |
.. | console | 启用控制台 |
.. | critical | 是否关键,也就是4分钟之内重启超过4次的话,重启之后就进入recovery模式 |
.. | disabled | 不随class自动启动 |
.. | group | 组归属 |
.. | keycodes | 不明白。。。。。 |
.. | oneshot | 只启动一次,意外退出后不必重启 |
.. | onrestart | 重启时 |
.. | setenv | 增加环境变量 |
.. | socket | 申请socket资源 |
.. | user | 用户归属 |
.. | ioprio | io调度优先级 |
(很多属性与命令用法都与linux中同名命令差球不多)
init是分段(section)解析init.rc的,在keywords.h中可以查看关键字的定义。init是以什么标志来分段解析 init.rc呢?结合init.rc的内容,可以看出,分段标记是以on 和 service来标记的。下面详细说明。
on 啥时候干什么
on属于行为。
on early-init
init之前、加载完所有rc文件后即执行,在miui的rom中,init.rc在early-init执行的是start ueventd,根据keywords.h的定义,start是个命令(COMMAND)。
这里顺便说下ueventd,android中底层(一般指驱动)通知上层的事件,用的是uevent,java层通过观察者模式实现,用到的类为UEventObserver,使用intent来传递;native层用的是android_os_UEventObserver.cpp,使用uevent.c通过socket传递。当然,这是framework及以下的层面,一般开发不经常用到,更何况这几个类都没有被暴露出来。
on init
加载propety各项属性文件之前执行,在init变为propety service之前都属于init阶段。
on early-boot
启动属性服务后即执行。
on boot
boot的时候执行。
on property:xxxxx=x
当某个属性设置为预期值时执行。
关于init.rc,其实结合/src/system/core/init/* 源码和init.rc文件来看,会明白许多。
水平有限,错误之处请指正,多谢!
更多相关文章
- 一款常用的 Squid 日志分析工具
- GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
- RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
- Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
- 一款霸榜 GitHub 的开源 Linux 资源监视器!
- Android带进度条文件上传
- Android(安卓)AMS(二) App启动过程之onCreate
- Android培训班(39)
- android fitSystemWindow属性