转载请标明出处:
http://blog.youkuaiyun.com/a991192001/article/details/34102491
1.Question
2.Bootloader
注:It’s not part of Android Operating System.
bootloader is the place where OEMs and Carriers put there locks and restrictions.
BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。
因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的。
3.Bootloaders on X86
注:BIOS是英文"Basic Input Output System"的缩略语,直译过来后中文名称就是"基本输入输出系统"。其实,它是一组固化到计算机内主板上一个ROM芯片上的程序,它保存着计算机最重要的基本输入输出的程序、系统设置信息、开机后自检程序和系统自启动程序。
4.Booting on embedded CPU
注:
Storage device can typically be: MMC, NAND,SPI fash,UART, etc.
Limited in size due to hardware constraints(SRAM size)
Provided either by the CPU vendor or throughcommunity Projects
第一阶段:
1,初始化基本硬件;
2,把bootloader自动搬运到内存中;
3,设置堆栈指针并将bss段清零。为后续执行代码做准备;
第二阶段:
1,初始化本阶段要用到的硬件;
2,读取环境变量;
3,启动:(a)自启动模式,从Flash或通过网络加载内核并执行;
(b) 下载模式,接收到用户的命令后执行;
5.Bootingon ARM TI OMAP3
注:
Linux Kernel启动后,bootloader不会再存在
6.加载linux kernel:第一个linux进程
注:
idle是一个进程,其pid号为0。其前身是系统创建的第一个进程,也是唯一一个没有通过fork()产生的进程。
注:这时候bootloader已经把kernel image导入了RAM,因而代码在android\kernel\arch\arm\kernel
当执行完汇编代码head.s后会直接跳到:start_kernel( )function
在此之前都是executed by jumping to their initial physical addresses
7.加载linux kernel:start_kernel( )
android/bootable/bootloader/lk/app/aboot/aboot.c
………………..
void(*entry)(unsigned, unsigned, unsigned*) = (entry_func_ptr*)(PA((addr_t)kernel));
uint32_ttags_phys = PA((addr_t)tags);
entry(0,machtype, (unsigned*)tags_phys);
…………………
entry(0, machtype,(unsigned*)tags_phys);//根据Kernel的地址走至Kernel\init\main.c的start_kernel()
8.Kernel启动
9.Kernel启动:init进程
注:
由idle进程开始执行start_kernel()
注意:idle进程是kernel thread,不会进入用户态,init进程才是第一个用户进程
Kernel threads run only in Kernel Mode, while regularprocesses run alternatively in Kernel Mode and in User Mode
10.创建内核线程
注:
Bootloader:android/bootable/bootloader/lk/app/aboot/aboot.c
Kernel入口代码路径 :android\kernel\init\main.c
Process.c :android\kernel\arch\arm\kernel
Fork.c :android\kernel
2.entry(0,machtype,(unsigned*)tags_phys);
//根据Kernel的地址走至Kernel\init\main.c的start_kernel()
3.大量形如XXX_init()的函数
4.Rest_init()是最后执行的
11.Kernel thread to Process
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
pid_tkernel_thread(int(*fn)(void *), void *arg, unsigned long flags)
内核创建的内核线程运行函数:kernel_init 位于main.c
init是个普通的用户态进程,它是Unix系统内核初始化与用户态初始化的接合点,它是所有process的祖宗。在运行kernel_init以前是内核态初始化
12.create Init process
这里的run_init_process就是通过execve()来运行init程序。从这里我们看到了init长大成人的整个过程。
http://blog.youkuaiyun.com/longshan_2009/article/details/8693672
这里在执行execve之前,进程1还是共享着内核线程0资源属性的内核线程。执行execve后(即执行了用户空间的init程序),此时,进程1就拥有了自己的地址空间等属性,成为一个普通进程。
而如果是在这些目录中扔未找到init文件,内核就会终止执行init进程,并引发kernel Panic.
panic("No init found. Try passing init= option to kernel. “
"See Linux Documentation/init.txt forguidance.");
13.android启动
15.Init process
16.Init.rc
” on post-fs-data“开始的这样一个section里的所有命令加入到一个执行队列,在未来的某个时候会顺序执行队列里的命令,所以调用action_for_each_trigger()的先后决定了命令执行的先后。
17.What is in Init.rc
详细见android源代码,这里略过。
18.Init.rcmajor events and services
注:安卓的内存管理机制:系统会根据“oom_adj”来判断需要结束哪些进程,一般来说,“oom_adj”的值越大,该进程被系统选中终止的可能就越高
存储器技术设备(英语:Memory Technology Device,缩写为 MTD),是Linux系统中设备文件系统的一个类型,主要用于闪存的应用,是一种闪存转换层(Flash Translation Layer,FTL)。创造MTD子系统的主要目的是提供一个介于闪存硬件驱动程序与高级应用程序之间的抽象层。
在init.rc中完成了一系列的重要操作:文件系统权限及挂载,启动zygote,启动系统服务,播放开机动画。当然如何解析对应的代码,并完成对应的操作,如启动zygote、播放开机动画,可以参考相关资料或查看源码
19.解析init.rc并执行action
20.Dalvik
21.Zygote
22.Zygote启动
由于Zygote进程在脚本文件init.rc中以服务的形式来启动,因此,会调用函数Service_start来启动。
Zygote进程以服务形式进行。
关键字service告诉init进程创建一个名为“zygote”的进程,这个zygote进程要执行的程序是/system/bin/app_process,后面四项是要传给app_process的参数。
最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。
ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的(先创建一个连接到Zygote进程的client断Socket)
23.Init fork Zygote
\android\system\core\init
Fork函数返回两次,第一次在当前进程init中,第二次在新创建的进程中返回。
Pid == 0代表在新创建的进程
24.Zygote进程启动的过程
第一步:
Bionic(Android的Linux内核库)
对于fork():
1、子进程复制父进程的所有进程内存到其内存地址空间中。父、子进程的
“数据段”,“堆栈段”和“代码段”完全相同,即子进程中的每一个字节都
和父进程一样。
2、子进程的当前工作目录、umask掩码值和父进程相同,fork()之前父进程
打开的文件描述符,在子进程中同样打开,并且都指向相同的文件表项。
3、子进程拥有自己的进程ID。对于父进程,fork函数返回了子程序的进程号,
而对于子程序,fork函数则返回零
对于exec():
1、进程调用exec()后,将在同一块进程内存里用一个新程序来代替调用
exec()的那个进程,新程序代替当前进程映像,当前进程的“数据段”,
“堆栈段”和“代码段”背新程序改写。
2、新程序会保持调用exec()进程的ID不变。
3、调用exec()之前打开打开的描述字继续打开(好像有什么参数可以令打开
的描述字在新程序中关闭)
第二步:
Zygote进程要执行的程序便是system/bin/app_process,它的源代码位于frameworks/base/cmds/app_process/app_main.cpp文件中,入口函数是main。
App_process执行的时候会把自己名字重命名:niceName = "zygote";
2.runtime.start("com.android.internal.os.ZygoteInit",startSystemServer ? "start-system-server" :"");
frameworks/base/core/jni/AndroidRuntime.cpp
3:startVm()创建虚拟机实例
4.在虚拟机实例中注册一系列JNI方法
5. env->CallStaticVoidMethod(startClass, startMeth, strArray); 调用ZygoteInit.main
ZygoteInit.java ---main()----- >java世界准备已经完成,欢迎来到java世界
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
registerZygoteSocket();创建server端的socket
startSystemServer(); 启动system进程
runSelectLoopMode();等待ActivityManagerService请求Zygote创建新进程。
25.ZygoteInit
26.System进程的启动过程
第一步:
6.由于由Zygote进程创建的子进程会继承Zygote进程在前面Step 4中创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。
7.调用RuntimeInit类的静态函数zygoteInit来进一步启动System进程
第二步:
2.System 进程时区等
3.在System进程中启动一个Binder线程池
4.invokeStaticMain()
6.Init native services(C++语言开发的系统服务)
7.将系统中的关键服务启动起来,注册到Service Manager中,最后通过函数loop(), 使当前线程进入一个消息循环中。
KK和KK以前的os不一样,KK是在SystemServerMain Thread上面跑initLoop
KK以前是start一个新的thread:ServerThread