第二天,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信息,我的如下:
# cat cpuinfo cat cpuinfo Processor : ARMv7 Processor rev 2 (v7l) BogoMIPS : 299.11 Features : swp half thumb fastmult vfp edsp neon vfpv3 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x3 CPU part : 0xc08 CPU revision : 2 Hardware : mapphone_UMTS Revision : 0000 Serial : 0000000000000000 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:
#include <cutils/properties.h> #include <stdio.h> void print_prop(const char* key,const char* value,void* cookie) { printf("key=%s,value=%s/n",key,value); } int main() { property_list(print_prop,NULL); }
Android.mk:
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= / list_property.cpp / LOCAL_SHARED_LIBRARIES := / libcutils / libutils / LOCAL_MODULE:= list_prop include $(BUILD_EXECUTABLE) 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文件来看,会明白许多。
水平有限,错误之处请指正,多谢!
创世纪:第一天连接:http://www.cnblogs.com/hangxin1940/archive/2011/10/01/2196964.html
创世纪:第三天连接:http://www.cnblogs.com/hangxin1940/archive/2011/10/22/2221451.html
原创文章,转载请说明出处:
http://www.cnblogs.com/hangxin1940/archive/2011/10/01/2196964.html