Android的开机流程
1. 系统引导bootloader
1) 源码:bootable/bootloader/*
2) 说明:加电后,CPU将先执行bootloader程序,此处有三种选择
a) 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写
b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.img包含内核,基本的文件系统,用于工程模式的烧写
c) 开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况)
2. 内核kernel
1) 源码:kernel/*
2) 说明:kernel由bootloader加载
3. 文件系统及应用init
1) 源码:system/core/init/*
2) 配置文件:system/rootdir/init.rc,
3) 说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能
4. 重要的后台程序zygote
1) 源码:frameworks/base/cmds/app_main.cpp等
2) 说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process
a) 建立Java Runtime,建立虚拟机
b) 建立Socket接收ActivityManangerService的请求,用于Fork应用程序
c) 启动SystemServer
5. 系统服务system server
1) 源码:frameworks/base/services/java/com/android/server/SystemServer.java
2) 说明:被zygote启动,通过System Manager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等)
6. 桌面launcher
1) 源码:ActivityManagerService.java为入口,packages/apps/launcher*实现
2) 说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用 ()启launcher
7. 解锁
1) 源码:
frameworks/policies/base/phone/com/android/internal/policy/impl/*lock*
2) 说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置
8. 开机自启动的第三方应用程序
1) 源码:
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
2) 说明:系统启动成功后SystemServer调用ActivityManagerNative.getDefault().systemReady()通知ActivityManager启动成功,ActivityManager会通过置变量mBooting,通知它的另一线程,该线程会发送广播android.intent.action.BOOT_COMPLETED以告知已注册的第三方程序在开机时自动启动。
9. 总结
综上所述,系统层次关于启动最核心的部分是zygote(即app_process)和system server,zygote它负责最基本的虚拟机的建立,以支持各个应用程序的启动,而system server用于管理android后台服务,启动步骤及顺序。
10. 参考
http://blog.csdn.net/basonjiang_sz/category/648399.aspx
Android 启动过程详解
Android从Linux系统启动有4个步骤;
(1) init进程启动
(2) Native服务启动
(3) System Server,Android服务启动
(4) Home启动
总体启动框架图如:
第一步:initial进程(system/core/init)
init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程.
Init.rc
Init.marvell.rc
Init进程一起来就根据init.rc和init.xxx.rc脚本文件建立了几个基本的服务:
servicemanamger
zygote
。。。
最后Init并不退出,而是担当起property service的功能。
1.1脚本文件
init@System/Core/Init
Init.c: parse_config_file(Init.rc)
@parse_config_file(Init.marvel.rc)
解析脚本文件:Init.rc和Init.xxxx.rc(硬件平台相关)
Init.rc是Android自己规定的初始化脚本(Android Init Language, System/Core/Init/readme.txt)
该脚本包含四个类型的声明:
Actions
Commands
Services
Options.
1.2 服务启动机制
我们来看看Init是这样解析.rc文件开启服务的。
(1)打开.rc文件,解析文件内容@ system/core/init/init.c
将service信息放置到service_list中。@ system/core/init parser.c
(2)restart_service()@system/core/init/init.c
service_start
execve(…).建立service进程。
第二步 Zygote
Servicemanager和zygote进程就奠定了Android的基础。Zygote这个进程起来才会建立起真正的Android运行空间,初始化建立的Service都是Navtive service.在.rc脚本文件中zygote的描述:
service zygote /system/bin/app_process-Xzygote /system/bin --zygote --start-system-server
所以Zygote从main(…)@frameworks/base/cmds/app_main.cpp开始。
(1)main(…)@frameworks/base/cmds/app_main.cpp
建立Java Runtime
runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);
(2) runtime.start@AndroidRuntime.cpp
建立虚拟机
运行:com.android.internal.os.ZygoteInit:main函数。
(3)main()@com.android.internal.os.ZygoteInit//正真的Zygote。
registerZygoteSocket();//登记Listen端口
startSystemServer();
进入Zygote服务框架。
经过这几个步骤,Zygote就建立好了,利用Socket通讯,接收ActivityManangerService的请求,Fork应用程序。
第三步 SystemServer
startSystemServer@com.android.internal.os.ZygoteInit在Zygote上fork了一个进程: com.android.server.SystemServer.于是SystemServer@(SystemServer.java)就建立了。Android的所有服务循环框架都是建立SystemServer@(SystemServer.java)上。在SystemServer.java中看不到循环结构,只是可以看到建立了init2的实现函数,建立了一大堆服务,并AddService到service Manager。
main() @ com/android/server/SystemServer
{
init1();
}
Init1()是在Native空间实现的(com_andoird_server_systemServer.cpp)。我们一看这个函数就知道了,init1->system_init()@System_init.cpp
在system_init()我们看到了循环闭合管理框架。
{
Call"com/android/server/SystemServer", "init2"
…..
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
init2()@SystemServer.java中建立了Android中所有要用到的服务。
这个init2()建立了一个线程,来New Service和AddService来建立服务
第三步 Home启动
在ServerThread@SystemServer.java后半段,我们可以看到系统在启动完所有的Android服务后,做了这样一些动作:
(1) 使用xxx.systemReady()通知各个服务,系统已经就绪。
(2) 特别对于ActivityManagerService.systemReady(回调)
Widget.wallpaper,imm(输入法)等ready通知。
Home就是在ActivityManagerService.systemReady()通知的过程中建立的。下面是ActivityManagerService.systemReady()的伪代码:
systemReady()@ActivityManagerService.java
resumeTopActivityLocked()
startHomeActivityLocked();//如果是第一个则启动HomeActivity。
startActivityLocked(。。。)CATEGORY_HOME
Android Booting:
init is the first process after kernelstarted. The corresponding source code lies in: device/system/init. It does thefollowing tasks step by step:
1.Initialize log system.
2.Parse /init.rc and /init.%hardware%.rc.
3. Execute early-init action in the twofiles parsed in step 2.
4. Device specific initialize. For example,make all device node in /dev and download firmwares.
5. Initialize property system. Actually theproperty system is working as a share memory. Logically it looks like aregistry under Windows system.
6. Execute init action in the two filesparsed in step 2.
7. Start property service.
8. Execute early-boot and boot actions inthe two files parsed in step 2.
9. Execute property action in the two filesparsed in step 2.
10. Enter into an indefinite loop towait for device/property set/child process exit events. For example, if an SDcard is plugined, init will receive a device add event, so it can make node forthe device. Most of the important process is forked in init, so if any of themcrashed, init will receive a SIGCHLD then translate it into a child processexit event, so in the loop init can handle the process exit event and executethe commands defined in *.rc(it will run command onrestart).
The .rc file is a script file defined byAndroid. The default is device/system/rootdir/init.rc. We can take a loot atthe file format(device/system/init/readme.txt is a good overall introduction ofthe script). Basically the script file contains actions and services.
Actions
Actions are named sequences of commands.Actions have a trigger which is used to determine when the action shouldoccur. When an event occurs which matches an action's trigger, thataction is added to the tail of a to-be-executed queue (unless it is already onthe queue).
Each action in the queue is dequeued insequence and each command in that action is executed in sequence. Inithandles other activities (device creation/destruction, property setting,process restarting) "between" the execution of the commands inactivities.
Actions take the form of:
on <trigger>
<command>
<command>
<command>
...
Services
Services are programs which init launchesand (optionally) restarts when they exit. Services take the form of:
service <name> <pathname> [<argument> ]*
<option>
<option>
...
Options
Options are modifiers to services. They affect how and when init runs the service.
Triggers
Triggers are strings which can be used tomatch certain kinds of events and used to cause an action to occur.
The builtin supported commands are definedin device/system/init/keywords.h. Commands are implementd indevice/system/init/bultins.c.
The init program only executes five kindsof triggers: “early-init”, “init”, “early-boot”, “boot”, “property:*”. Take alook at the following line in default init.rc.
class_start default
This line is a command for the actioncorresponding to “boot” trigger. It will start all services whose class nameequals to “default”. By default, if no class option is defined for a service,the service’s class name is “default”. So this line will start all the servicesin the order of position in the file by default. (BTW, you can start anyservice using start commands, if you like.) Any service is run as a forkedprocess of init, take a look at the source code of service_start indevice/system/init.c.
So according to the default init.rc, thefollowing services will be executed step by step:
console: star a shell. The source is indevice/system/bin/ash.
adbd: start adb daemon. The source is indevice/tools/adbd. By default is disabled.
servicemanager: start binder system. Thesource is in device/commands/binder.
mountd: mount all fs defined in/system/etc/mountd.conf if started, receive commands through local socket tomount any fs. The source is in device/system/bin/mountd.
debuggerd: start debug system. The sourceis in device/system/bin/debuggerd.
rild: start radio interface layer daemon.The source is in device/commands/rind.
zygote: start Android Java Runtime andstart system server. It’s the most important service. The source is indevice/servers/app.
media: start AudioFlinger, MediaPlayerServiceand CameraService. The source is in device/commands/mediaserver.
bootsound: play the default boot sound/system/media/audio/ui/boot.mp3. The source is in device/commands/playmp3.
dbus: start dbus daemon, it’s only used byBlueZ. The source is in device/system/Bluetooth/dbus-daemon.
hcid: redirect hcid’s stdout and stderr tothe Android logging system. The source is in device/system/bin/logwrapper. Bydefault is disabled.
hfag: start Bluetooth handsfree audiogateway, it’s only used by BlueZ. The source is indevice/system/Bluetooth/bluez-utils. By default is disabled.
hsag: start Bluetooth headset audiogateway, it’s only used by BlueZ. The source is indevice/system/Bluetooth/bluez-utils. By default is disabled.
installd: start install package daemon. Thesource is in device/servers/installd.
flash_recovery: load /system/recovery.img.The source is in device/commands/recovery/mtdutils.
Zygote service does the following tasksstep by step:
1. Create JAVA VM.
2. Register android native function forJAVA VM.
3. Call the main function in the JAVA classnamed com.android.internal.os.ZygoteInit whose source isdevice/java/android/com/android/internal/os/ZygoteInit.java.
a) Load ZygoteInit class
b) Register zygote socket
c) Load preload classes(thedefault file is device/java/android/preloaded-classes)
d) Load preload resources
e) Call Zygote::forkSystemServer(implemented in device/dalvik/vm/InternalNative.c) to fork a new process. Inthe new process, call the main function in the JAVA class namedcom.android.server.SystemServer, whose source is indevice/java/services/com/android/server.
i. Load libandroid_servers.so
ii. Call JNI native init1 function implemented indevice/libs/android_servers/com_android_server_SystemServers. It only callssystem_init implemented in device/servers/system/library/system_init.cpp.
If running on simulator, instantiate AudioFlinger, MediaPlayerService andCameraService here.
Call init2 function in JAVA class named com.android.server.SystemServer, whosesource is in device/java/services/com/android/server. This function is verycritical for Android because it start all of Android JAVA services.
If not running on simulator, call IPCThreadState::self()->joinThreadPool()to enter into service dispatcher.
SystemServer::init2 will start a new threadto start all JAVA services as follows:
Core Services:
1. Starting Power Manager //
2. Creating Activity Manager
3. Starting Telephony Registry //
4. Starting Package Manager //
5. SetActivity Manager Service as System Process
6. Starting Context Manager
7. Starting System Context Providers
8. Starting Battery Service //
9. Starting Alarm Manager //
10. Starting Sensor Service
11. Starting Window Manager
12. Starting Bluetooth Service //
13. Starting Mount Service//
Other services //
1. Starting Status Bar Service
2. Starting Hardware Service
3. Starting NetStat Service
4. Starting Connectivity Service
5. Starting Notification Manager
6. Starting DeviceStorageMonitor Service
7. Starting Location Manager
8. Starting Search Service
9. Starting Clipboard Service
10. Starting Checkin Service
11. Starting Wallpaper Service
12. Starting Audio Service
13. Starting HeadsetObserver
14. StartingAdbSettingsObserver
Finally SystemServer::init2 will callActivityManagerService.systemReady to launch the first activity by sentingIntent.CATEGORY_HOME intent.
There is another way to start systemserver, which is through a program named system_server whose source isdevice/servers/system/system_main.cpp. It also calls system_init to startsystem services. So there is a question: why does Android have two methods tostart system services? My guess is that directly start system_server may havesynchronous problem with zygote because system_server will call JNI to startSystemServer::init2, while at that time zygote may not start JAVA VM yet. SoAndroid uses another method. After zynote is initialized, fork a new process tostart system services.
Android 启动过程
1. Boot系统初始化,具体过程参见(system\core\init\Init.c)中的main函数,这时候,手机或者模拟器出现的画面是一个console,显示“ANDROID”msg。
2. 初始化成功后,就开始mounting系统,具体参见(system\core\mountd\Mountd.c) 中的main函数。
3.接下来运行ndroidRuntime,并开始启动java虚拟机dalvikvm。
4. Java虚拟机启动成功后,开始系统初始化。系统初始的第一步是用JNI方式实现的,对应java代码为(frameworks\base\services\java\com\android\server\SystemServer.java)init1(Native)函数,对应的JNI C++代码为(frameworks\base\core\jni\server\com_android_server_SystemServer.cpp),而实现的C++代码为
(frameworks\base\cmds\system_server\library\System_init.cpp) 中的system_init()函数。
5. system_init调用SurfaceFlinger,SurfaceFlinger的readyToRun()函数用BootAnimation来实现开机动画,这时候手机或者模拟器显示是一副背景图加一个动态的小机器人。
6. 系统初始化的第二步,将启动ServerThread进程,参见SystemServer.init2()。ServerThread将启动各种系统服务,如Power Manager、Activity Manager等等,具体参见ServerThread的run函数,ServerThread同在SystemServer.java中。
7.这之后的事,应该就是进入系统了。(这部分没有调查过)。
对Android启动过程的进一步研究
对于关注Android底层的朋友来说,其具体的启动过程应该是比较吸引我们的。但是很多启动文件什么的,都得adb push到host上来看,挺不方便的,都怪Android自带的Toolbox太简略了。所以在深入了解Android的启动流程之前,我们来把Busybox安装到Android上去,这样,就有很多工具供我们使用了。
首先去busybox主页 下载最新版本的源代码,然后用arm的交叉编译器编译出busybox的可执行程序,编译的时候需要注意一些设置选项,例如
BuildOptions —>
BuildBusyBox as a static binary (no shared libs) 这个要选上,因上这样子编译出来的busyBox才是可以独立运行的。
│Do you wantto build BusyBox with a Cross Compiler? ││
│ │(/HOME/toolchains/gcc-4.0.2-glibc-2.3.5/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu│ 这是交叉编译器的路径,要根据具体的情况来设置。
InstallationOptions —>
Don’t use/usr
这样子编译出来的busybox才不会安装到你主机的/usr目录下。一定要选上。
busybox的功能选项根据需要自选,但是不要太贪心.
OK,这里就不纠缠于编译busybox的东西了,网上资料无数。接下来,我们把busybox安装到模拟器上去。先在模拟器上随便建一个busybox的文件夹,然后进入busybox可执行文件目录,使用命令
adb pushbusybox.asc /data/busybox/busybox
然后进入adbshell,chmod 777./busybox,就可以直接使用了。但现在还是不方便,总不能每用一个命令就输一次busybox吧?所以,我们可以先用./busybox--install将程序都安装到当前目录下,然后把当前目录添加到PATH变量中即可。暂时使用export来添加吧,如果想永久添加,往下看。
好了,准备工作完成,开始研究的工作了。既然是研究启动过程,那当然是先看看init.rc文件。去etc目录打开它,分析一下内容,首先是对env的定义,也就是全局环境变量的定义,接下来的建立和初始化里面的内容目前还不清楚什么意思,紧接着就是系统启动时运行的初始进程信息,这个比较有意思,包括了usbd-config和qemu,qemu自不用说,而usbd-config作为初始启动的进程,应该就是和上一篇文章猜的一样,用来调试或者usb通信的。往下看,是在初始启动进程完成之后开始启动的服务进程,这些进程如果因故退出,会自动重启。这里面包括了console控制台,adbd监护进程,usbd监护进程,debuggerd监护进程等.除去这些守护进程,能引起我们注意的,是runtime和zygote。这两个进程似乎掌管着其他进程以及应用程序的启动。
现在,来让我们做一个实验吧,将自动调用的启动过程变成手动,看看启动流程具体是什么样的。想达到这个目的,首先就是要修改init.rc文件,当然不是在模拟器的console中改,一是不能改,二是你改了也没用,下次加载就会给你覆盖了。所以,我们要从原始镜像ramdisk.img入手了。从2.6标准Linux内核开始,initrd.img都采用cpio压缩,猜测ramdisk.img也一样,需要使用gunzip解压缩,然后再使用cpio解包。好,进入tools/lib/images目录下,先用file命令看看ramdisk.img的类型,没错,系统提示
ramdisk.img:gzip compressed data, from Unix
很好,然后将ramdisk.img复制一份到任何其他目录下,将其名称改为ramdisk.img.gz,并使用命令
gunzipramdisk.img.gz
然后新建一个文件夹,叫ramdisk吧,进入,输入命令
cpio -i -F../ramdisk.img
这下,你就能看见并操作ramdisk里面的内容了。当然你也可以直接在外面进行操作,但是还是建议把cpio解压缩出来的内容全部集中在一个文件夹里面,因为一会我们还要将其压缩成新的ramdisk.img。
OK,现在开始修改步骤吧。用任何一款编辑器打开init.rc,首先在PATH那里加上你的Busybox安装路径,然后注释内容,我们要手工启动他们。
# zygote {
# exec/system/bin/app_process
# args {
# 0 -Xzygote
# 1/system/bin
# 2 –zygote
# }
# autostart1
# }# runtime{
# exec/system/bin/runtime
# autostart1
# }
在这里需要注意,不要同时把两者都注释了,注释某一个,再试验手工启动它,如果两者同时注释我这里有问题,无法启动。
好,接下来,使用下列命令重新打包成镜像
cpio -i -t-F ../ramdisk.img > list
cpio -o -Hnewc -O lk.img < list
当前目录下生成的lk.img就是我们的新镜像了。使用自己的镜像启动emulator;
emulator-console -ramdisk lk.img
如果我们注释的是zygote,那么在#后输入
app_process-Xzygote /system/bin –zygote
手工启动,命令行中输出的信息是
Prepping:/system/app/AlarmProvider.apk:/system/app/Browser.apk:/system/app/
Calendar.apk:/system/app/Camera.apk:/system/app/Contacts.apk:
/system/app/Development.apk:/system/app/GDataFeedsProvider.apk:/system/app/
Gmail.apk:/system/app/GmailProvider.apk:/system/app/GoogleApps.apk:
/system/app/GoogleAppsProvider.apk:/system/app/Home.apk:/system/app/ImProvider.apk:
/system/app/Maps.apk:/system/app/MediaPickerActivity.apk:
/system/app/MediaProvider.apk:/system/app/Phone.apk:/system/app/PimProvider.apk:/system/
app/ApiDemos.apk:/system/app/SettingsProvider.apk:
/system/app/Sms.apk:/system/app/SyncProvider.apk:/system/app/TelephonyProvider.apk:
/system/app/XmppService.apk:/system/app/YouTube.apk
File notfound: /system/app/AlarmProvider.apk
File notfound: /system/app/Calendar.apk
File notfound: /system/app/Camera.apk
File notfound: /system/app/GDataFeedsProvider.apk
File notfound: /system/app/Gmail.apk
File notfound: /system/app/GmailProvider.apk
File notfound: /system/app/MediaPickerActivity.apk
File notfound: /system/app/PimProvider.apk
File notfound: /system/app/ApiDemos.apk
File notfound: /system/app/Sms.apk
File notfound: /system/app/SyncProvider.apk
File notfound: /system/app/YouTube.apk
Prepcomplete
嘿嘿,从File notfound的信息中可以看到一些Google可能会即将推出的应用,比如Gmail什么的。当然,这些都是Java框架的启动信息,我们以后还要借助其他工具来进行进一步探索。
如果我们注释的是runtime,那么输出信息是:
+++post-zygote
老实说,没有明白这是啥意思,呵呵,吃饭时间到了,懒得看了。
好了,今天就说到这,基本的方法就是这样,有兴趣的朋友可以进一步深入研究。