安卓系统启动流程

本文详细剖析了Android系统的启动过程,从Bootloader启动、Linux启动到Android启动的各个阶段,包括init进程、zygote服务、systemserver服务、launcher桌面和lockscreen的启动。深入分析了Bootloader的定义、种类,特别是U-Boot的启动流程,以及在Android启动过程中的logo显示机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,Android启动概述

       Android系统启动基本可分为3个阶段:Bootloader启动,Linux启动,Android启动。

1.1,Bootloader启动     

       系统引导bootloader(bootable/bootloader/* u-boot/*),加电后,CPU先执行bootloader程序,正常启动系统,加载boot.img,中包含内核。

       源码:bootable/bootloader/* , 说明:加电后,CPU将先执行bootloader程序,此处有三种选择:
       a: 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写
       b: 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.img包含内核,基本的文件系统,用于工程模式的烧写
       c:开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况)

1.2,linux启动

         由bootloader加载kernel,kernel经自解压,初始化,载入built-in驱动程序,完成启动。kernel启动后会创建若干内核线程,之后装入并执行程序/sbin/init/,载入init process,切换至user-space。

1.3,Android启动

1.3.1,init进程启动

        源码:system/core/init/*
        配置文件:system/rootdir/init.rc
        说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能。

1.3.2,zygote服务启动

       源码:frameworks/base/cmds/app_main.cpp等。
       说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process。
       作用:建立Java Runtime,建立虚拟机;建立Socket接收ActivityManangerService的请求,用于Fork应用程序;启动System Server。

1.3.3,systemserver服务启动

       源码:frameworks/base/services/Java/com/android/server/SystemServer.java
       说明:被zygote启动,通过System Manager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等)。

1.3.4,launcher桌面启动

       源码:ActivityManagerService.java为入口,packages/apps/launcher*实现。
       说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用startHomeActivityLocked()启launcher。

1.3.5,lockscreen启动

       源码:frameworks/policies/base/phone/com/android/internal/policy/impl/*lock*
       说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置。

1.3.6,othersapp启动

       源码:frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
       说明:系统启动成功后SystemServer调用ActivityManagerNative.getDefault().systemReady()通知ActivityManager启动成功,ActivityManager会通过置变量mBooting,通知它的另一线程,该线程会发送广播android.intent.action.BOOT_COMPLETED以告知已注册的第三方程序在开机时自动启动。

2,bootloader启动详细分析

2.1,Bootloader的定义和种类

        简单地说,BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备。这样描述是比较抽象的,但是它的任务确实不多,终极目标就是把OS拉起来运行。在嵌入式系统世界里存在各种各样的Bootloader,种类划分也有多种方式。除了按照处理器体系结构不同划分以外,还有功能复杂程度的不同。
        先区分一下Bootloader和Monitor[l1] : 严格来说,Bootloader只是引导OS运行起来的代码;而Monitor另外还提供了很多的命令行接口,可以进行调试、读写内存、烧写Flash、配置环境变量等。在开发过程中Monitor提供了很好地调试功能,不过在开发结束之后,可以完全将其设置成一个Bootloader。所以习惯上将其叫做Bootloader。

Bootloader

 Monitor

描述

 X86

 ARM

 PowerPC

U-boot

通用引导程序

RedBoot

基于eCos的引导程序

BLOB 

LART(主板)等硬件平台的引导程序

LILO

Linux磁盘引导程序

GRUB

GNU的LILO替代程序

Loadlin

从DOS引导Linux

Vivi

韩国mizi 公司开发的bootloader

       更多bootloader还有:ROLO、Etherboot、ARMboot 、LinuxBIOS等。

       对于每种体系结构,都有一系列开放源码Bootloader可以选用:

       X86:X86的工作站和服务器上一般使用LILO和GRUB。

       ARM:最早有为ARM720处理器开发板所做的固件,又有了armboot,StrongARM平台的blob,还有S3C2410处理器开发板上的vivi等。现在armboot已经并入了U-Boot,所以U-Boot也支持ARM/XSCALE平台。U-Boot已经成为ARM平台事实上的标准Bootloader。

       PowerPC:最早使用于ppcboot,不过现在大多数直接使用U-boot。

       MIPS:最早都是MIPS开发商自己写的bootloader,不过现在U-boot也支持MIPS架构

       M68K:Redboot能够支持m68k系列的系统。

2.2,Arm特定平台的bootloader

        到目前为止,我们公司已经做过多个Arm平台的android方案,包括:marvell(pxa935)、informax(im9815)、mediatek(mt6516/6517)、broadcom(bcm2157)。由于不同处理器芯片厂商对arm core的封装差异比较大,所以不同的arm处理器,对于上电引导都是由特定处理器芯片厂商自己开发的程序,这个上电引导程序通常比较简单,会初始化硬件,提供下载模式等,然后才会加载通常的bootloader。

       下面是几个arm平台的bootloader方案:

        marvell(pxa935) :                bootROM + OBM [l4] + BLOB

        informax(im9815) :             bootROM + barbox + U-boot

        mediatek(mt6516/6517) :     bootROM + pre-loader[l5]  + U-boot

        broadcom(bcm2157) :          bootROM + boot1/boot2 + U-boot

       为了明确U-boot之前的两个loader的作用,下面以broadcom平台为例,看下在上电之后到U-boot的流程,如图1.2.1:

                                          图1.2.1 broadcom平台上电流程

2.3,uboot启动流程详解

        最常用的bootloader还是U-boot,可以引导多种操作系统,支持多种架构的CPU。它支持的操作系统有:Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS等,支持的CPU架构有:ARM、PowerPC、MISP、X86、NIOS、Xscale等。手机系统不像其他的嵌入式系统,它还需要在启动的过程中关心CP的启动,这个时候就涉及到CP的image和唤醒时刻,而一般的嵌入式系统的uboot只负责引导OS内核。所以这里我们也暂不关心CP的启动,而主要关心AP侧。

        从上面第二小节中可以看出,bootloader通常都包含有处理器厂商开发的上电引导程序,不过也不是所有的处理都是这样,比如三星的S3C24X0系列,它的bootROM直接跳到U-boot中执行,首先由bootROM将U-boot的前4KB拷贝到处理器ISRAM,接着在U-boot的前4KB中必须保证要完成的两项主要工作:初始化DDR,nand和nand控制器,接着将U-boot剩余的code拷贝到SDRAM中,然后跳到SDRAM的对应地址上去继续跑U-boot。

       所以U-boot的启动过程,大致上可以分成两个阶段:第一阶段,汇编代码;第二阶段,c代码。

2.3.1,汇编代码阶段

      U-boot的启动由u-boot/arch/arm/cpu/xxx/u-boot.lds开始,其引导调用u-boot/arch/arm/cpu/xxx/start.S。u-boot.lds:

[cpp]  view plain  copy
  1. OUTPUT_FORMAT("elf32-littlearm""elf32-littlearm""elf32-littlearm")  
  2. OUTPUT_ARCH(arm)  
  3. ENTRY(_start)  
  4. SECTIONS  
  5. {  
  6.     . = 0x00000000;  
  7.   
  8.     . = ALIGN(4);  
  9.     .text :  
  10.     {  
  11.         arch/arm/cpu/arm920t/start.o    (.text)//调用对应的start.S,start.o由start.S编译生成  
  12.         *(.text)  
  13.     }  
  14.   
  15.     . = ALIGN(4);  
  16.     .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }  
  17.   
  18.     . = ALIGN(4);  
  19.     .data : {  
  20.         *(.data)  
  21.     }  
  22.   
  23.     . = ALIGN(4);  
  24.   
  25.     . = .;  
  26.     __u_boot_cmd_start = .;  
  27.     .u_boot_cmd : { *(.u_boot_cmd) }  
  28.     __u_boot_cmd_end = .;  
  29.   
  30.     . = ALIGN(4);  
  31.   
  32.     .rel.dyn : {  
  33.         __rel_dyn_start = .;  
  34.         *(.rel*)  
  35.         __rel_dyn_end = .;  
  36.     }  
  37.   
  38.     .dynsym : {  
  39.         __dynsym_start = .;  
  40.         *(.dynsym)  
  41.     }  
  42.   
  43.     .bss __rel_dyn_start (OVERLAY) : {  
  44.         __bss_start = .;  
  45.         *(.bss)  
  46.          . = ALIGN(4);  
  47.         _end = .;  
  48.     }  
  49.   
  50.     /DISCARD/ : { *(.dynstr*) }  
  51.     /DISCARD/ : { *(.dynamic*) }  
  52.     /DISCARD/ : { *(.plt*) }  
  53.     /DISCARD/ : { *(.interp*) }  
  54.     /DISCARD/ : { *(.gnu*) }  
  55. }  

      对应的Makefile文件如下:

[cpp]  view plain  copy
  1. include $(TOPDIR)/config.mk  
  2.   
  3. LIB = $(obj)lib$(CPU).o  
  4.   
  5. START   = start.o  
  6.   
  7. COBJS-y += cpu.o  
  8. COBJS-$(CONFIG_USE_IRQ) += interrupts.o  
  9.   
  10. SRCS    := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c)  
  11. OBJS    := $(addprefix $(obj),$(COBJS-y) $(SOBJS))  
  12. START   := $(addprefix $(obj),$(START))  
  13.   
  14. all:    $(obj).depend $(START) $(LIB)  
  15.   
  16. $(LIB): $(OBJS)  
  17.     $(call cmd_link_o_target, $(OBJS))  
  18.   
  19. #########################################################################  
  20.   
  21. # defines $(obj).depend target  
  22. include $(SRCTREE)/rules.mk  
  23.   
  24. sinclude $(obj).depend  

      所以U-boot的第一条指令从u-boot/arch/arm/cpu/xxx/start.S文件开始,第一阶段主要做了如下事情:

      

       (1). 设置CPU进入SVC模式(系统管理模式),cpsr[4:0]=0xd3。

       (2). 关中断,INTMSK=0xFFFFFFFF, INTSUBMSK=0x3FF。

       (3). 关看门狗,WTCON=0x0。

      (4). 调用s3c2410_cache_flush_all函数,使TLBS,I、D Cache,WB中数据失效。

      (5). 时钟设置CLKDIVN=0x3 , FCLK:HCLK:PCLK = 1:2:4。

      (6). 读取mp15的c1寄存器,将最高两位改成11,表示选择了异步时钟模型。

      (7). 检查系统的复位状态,以确定是不是从睡眠唤醒。

[cpp]  view plain  copy
  1. #include <asm-offsets.h>  
  2. #include <common.h>  
  3. #include <config.h>  
  4.   
  5. .globl _start  
  6. _start: b   start_code  
  7.     ldr pc, _undefined_instruction  
  8.     ldr pc, _software_interrupt  
  9.     ldr pc, _prefetch_abort  
  10.     ldr pc, _data_abort  
  11.     ldr pc, _not_used  
  12.     ldr pc, _irq  
  13.     ldr pc, _fiq  
  14.   
  15. ......  
  16.   
  17. //开始的一些初始化操作  
  18. start_code:  
  19.     /* 
  20.      * set the cpu to SVC32 mode 
  21.      */  
  22.     mrs r0, cpsr  
  23.     bic r0, r0, #0x1f  
  24.     orr r0, r0, #0xd3  
  25.     msr cpsr, r0  
  26.   
  27.     bl  coloured_LED_init  
  28.     bl  red_LED_on  
  29.   
  30. ......  
  31.   
  32.     /* 
  33.      * we do sys-critical inits only at reboot, 
  34.      * not when booting from ram! 
  35.      */  
  36. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
  37.     bl  cpu_init_crit //重点函数  
  38. #endif  
  39.   
  40. /* Set stackpointer in internal RAM to call board_init_f */  
  41. /*board.c的board_init_f()函数*/  
  42. call_board_init_f:  
  43.     ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)  
  44.     bic sp, sp, #7 /* 8-byte alignment for ABI compliance */  
  45.     ldr r0,=0x00000000  
  46.     bl  board_init_f//board初始化  
  47.   
  48.   
  49.     .globl  relocate_code  
  50. relocate_code:  
  51.     mov r4, r0  /* save addr_sp */  
  52.     mov r5, r1  /* save addr of gd */  
  53.     mov r6, r2  /* save addr of destination */  
  54.   
  55.     /* Set up the stack                         */  
  56. stack_setup:  
  57.     mov sp, r4  
  58.   
  59.     adr r0, _start  
  60.     cmp r0, r6  
  61.     beq clear_bss       /* skip relocation */  
  62.     mov r1, r6          /* r1 <- scratch for copy_loop */  
  63.     ldr r2, _TEXT_BASE  
  64.     ldr r3, _bss_start_ofs  
  65.     add r2, r0, r3      /* r2 <- source end address      */  
  66.   
  67. copy_loop:  
  68.     ldmia   r0!, {r9-r10}       /* copy from source address [r0]    */  
  69.     stmia   r1!, {r9-r10}       /* copy to   target address [r1]    */  
  70.     cmp r0, r2          /* until source end address [r2]    */  
  71.     blo copy_loop  
  72.   
  73. #ifndef CONFIG_PRELOADER  
  74.     /* 
  75.      * fix .rel.dyn relocations 
  76.      */  
  77.     ldr r0, _TEXT_BASE      /* r0 <- Text base */  
  78.     sub r9, r6, r0      /* r9 <- relocation offset */  
  79.     ldr r10, _dynsym_start_ofs  /* r10 <- sym table ofs */  
  80.     add r10, r10, r0        /* r10 <- sym table in FLASH */  
  81.     ldr r2, _rel_dyn_start_ofs  /* r2 <- rel dyn start ofs */  
  82.     add r2, r2, r0      /* r2 <- rel dyn start in FLASH */  
  83.     ldr r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */  
  84.     add r3, r3, r0      /* r3 <- rel dyn end in FLASH */  
  85. fixloop:  
  86.     ldr r0, [r2]        /* r0 <- location to fix up, IN FLASH! */  
  87.     add r0, r0, r9      /* r0 <- location to fix up in RAM */  
  88.     ldr r1, [r2, #4]  
  89.     and r7, r1, #0xff  
  90.     cmp r7, #23         /* relative fixup? */  
  91.     beq fixrel  
  92.     cmp r7, #2          /* absolute fixup? */  
  93.     beq fixabs  
  94.     /* ignore unknown type of fixup */  
  95.     b   fixnext  
  96. fixabs:  
  97.     /* absolute fix: set location to (offset) symbol value */  
  98.     mov r1, r1, LSR #4      /* r1 <- symbol index in .dynsym */  
  99.     add r1, r10, r1     /* r1 <- address of symbol in table */  
  100.     ldr r1, [r1, #4]        /* r1 <- symbol value */  
  101.     add r1, r1, r9      /* r1 <- relocated sym addr */  
  102.     b   fixnext  
  103. fixrel:  
  104.     /* relative fix: increase location by offset */  
  105.     ldr r1, [r0]  
  106.     add r1, r1, r9  
  107. fixnext:  
  108.     str r1, [r0]  
  109.     add r2, r2, #8      /* each rel.dyn entry is 8 bytes */  
  110.     cmp r2, r3  
  111.     blo fixloop  
  112. #endif  
  113.   
  114. clear_bss:  
  115. #ifndef CONFIG_PRELOADER  
  116.     ldr r0, _bss_start_ofs  
  117.     ldr r1, _bss_end_ofs  
  118.     ldr r3, _TEXT_BASE      /* Text base */  
  119.     mov r4, r6          /* reloc addr */  
  120.     add r0, r0, r4  
  121.     add r1, r1, r4  
  122.     mov r2, #0x00000000     /* clear                */  
  123.   
  124. clbss_l:str r2, [r0]        /* clear loop...            */  
  125.     add r0, r0, #4  
  126.     cmp r0, r1  
  127.     bne clbss_l  
  128.   
  129.     bl coloured_LED_init  
  130.     bl red_LED_on  
  131. #endif  
  132.   
  133. /* 
  134.  * We are done. Do not return, instead branch to second part of board 
  135.  * initialization, now running from RAM. 
  136.  */  
  137. #ifdef CONFIG_NAND_SPL  
  138.     ldr     r0, _nand_boot_ofs  
  139.     mov pc, r0  
  140.   
  141. _nand_boot_ofs:  
  142.     .word nand_boot  
  143. #else  
  144.     ldr r0, _board_init_r_ofs  
  145.     adr r1, _start  
  146.     add lr, r0, r1  
  147.     add lr, lr, r9  
  148.     /* setup parameters for board_init_r */  
  149.     mov r0, r5      /* gd_t */  
  150.     mov r1, r6      /* dest_addr */  
  151.     /* jump to it ... */  
  152.     mov pc, lr  
  153. /*board_init_r 此处走至u-boot\arch\arm\lib\board.c的board_init_r()函数 */  
  154. _board_init_r_ofs:  
  155.     .word board_init_r - _start  
  156. #endif  
  157. /*至此走至C代码的阶段*/  
  158. _rel_dyn_start_ofs:  
  159.     .word __rel_dyn_start - _start  
  160. _rel_dyn_end_ofs:  
  161.     .word __rel_dyn_end - _start  
  162. _dynsym_start_ofs:  
  163.     .word __dynsym_start - _start  
  164.       
  165. ......  
  166.   
  167. #endif  

 

        根据这几条语句来判断系统是从nand启动的还是直接将程序下载到SDRAM中运行的,这里涉及到运行时域 和位置无关代码的概念,ldr r0,_TEXT_BASE的作用是将config.mk文件中定义的TEXT_BASE值(0x33f80000)装载到r0中,adr r1,_start该指令是条伪指令,在编译的时候会被转换成ADD或SUB指令根据当前pc值计算出_start标号的地址,这样的话就可以知道当前程序在什么地址运行(位置无关代码:做成程序的所有指令都是相对寻址的指令,包括跳转指令等,这样代码就可以不在链接所指定的地址上运行)。在上电之后,系统从nand启动,这里得到r0和r1值是不一样的,r0=0x33f80000,而r1=0x00000000。所以接下来会执行cpu_init_crit函数。

        cpu_init_crit函数,主要完成了两个工作:首先使ICache and Dcache,TLBs中早期内容失效,再设置p15 control register c1,关闭MMU,Dcache,但是打开了Icache和Fault checking,(要求mmu和Dcache是必须要关闭的,而Icache可以打开可以关闭);其次调用/board/nextdvr2410/memsetup.S文件中的memsetup函数来建立对SDRAM的访问时序。

        Relocate函数,加载nand flash中的uboot到SDRAM中,代码会加载到0x33f80000开始的地址,空间大小是512。

        //这里参考的是展讯平台7710的源代码,所以并无start_armboot函数,取而代之的是board_init_r函数。请知悉。

        ldr pc, _start_armboot        

       _start_armboot: .word start_armboot

       这里将会进入第二阶段的c代码部分:board_init_r()函数,/u-boot/arch/arm/lib/board.c。

2.3.2,C代码阶段

       先看/u-boot/arch/arm/lib/board.c的board_init_r()函数:

[cpp]  view plain  copy
  1. void board_init_r (gd_t *id, ulong dest_addr)  
  2. {  
  3. ......  
  4. /**一系列初始化操作之后 重点为do_cboot(NULL, 0, 1, NULL)和main_loop ()*/  
  5.     board_init();   /* Setup chipselects */  
  6.   
  7.   boot_pwr_check();  
  8.   
  9. #ifdef CONFIG_SERIAL_MULTI  
  10.     serial_initialize();  
  11. #endif  
  12.   
  13.     debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);  
  14.   
  15. #ifdef CONFIG_LOGBUFFER  
  16.     logbuff_init_ptrs ();  
  17. #endif  
  18. #ifdef CONFIG_POST  
  19.     post_output_backlog ();  
  20. #endif  
  21.   
  22.     /* The Malloc area is immediately below the monitor copy in DRAM */  
  23.     malloc_start = dest_addr - TOTAL_MALLOC_LEN;  
  24. #ifdef SPRD_EVM_TAG_ON  
  25.         SPRD_EVM_TAG(4);  
  26. #endif  
  27.     mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);  
  28. #ifdef SPRD_EVM_TAG_ON  
  29.         SPRD_EVM_TAG(5);  
  30. #endif  
  31.     boot_pwr_check();  
  32.   
  33. #if !defined(CONFIG_SYS_NO_FLASH)  
  34.     puts ("FLASH: ");  
  35.   
  36.     if ((flash_size = flash_init ()) > 0) {  
  37. # ifdef CONFIG_SYS_FLASH_CHECKSUM  
  38.         print_size (flash_size, "");  
  39.         /* 
  40.          * Compute and print flash CRC if flashchecksum is set to 'y' 
  41.          * 
  42.          * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX 
  43.          */  
  44.         s = getenv ("flashchecksum");  
  45.         if (s && (*s == 'y')) {  
  46.             printf ("  CRC: %08X",  
  47.                 crc32 (0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)  
  48.             );  
  49.         }  
  50.         putc ('\n');  
  51. # else  /* !CONFIG_SYS_FLASH_CHECKSUM */  
  52.         print_size (flash_size, "\n");  
  53. # endif /* CONFIG_SYS_FLASH_CHECKSUM */  
  54.     } else {  
  55.         puts (failed);  
  56.         hang ();  
  57.     }  
  58. #endif  
  59.     boot_pwr_check();  
  60.   
  61. #if !defined(CONFIG_EMMC_BOOT)  
  62. #if defined(CONFIG_CMD_NAND)  
  63.     puts ("NAND:  ");  
  64.     ret = nand_init();      /* go init the NAND */  
  65.         if (ret) {  
  66.             puts ("NAND init error  ");  
  67.             while(1);  
  68.         }  
  69. #endif  
  70. #endif  
  71.   
  72.     boot_pwr_check();  
  73. #ifdef SPRD_EVM_TAG_ON  
  74.         SPRD_EVM_TAG(6);  
  75. #endif  
  76.   
  77. #if defined(CONFIG_CMD_ONENAND)  
  78. #if !(defined CONFIG_TIGER && defined CONFIG_EMMC_BOOT)  
  79.     onenand_init();  
  80. #endif  
  81. #endif  
  82.   
  83. #ifdef CONFIG_GENERIC_MMC  
  84.        puts("MMC:   ");  
  85.        mmc_initialize(bd);  
  86. #endif  
  87.   
  88. #ifdef CONFIG_HAS_DATAFLASH  
  89.     AT91F_DataflashInit();  
  90.     dataflash_print_info();  
  91. #endif  
  92.   
  93. #ifdef CONFIG_EMMC_BOOT  
  94.     mmc_legacy_init(1);  
  95. #endif  
  96.     /* initialize environment */  
  97.     env_relocate ();  
  98.     boot_pwr_check();  
  99.   
  100. #ifdef CONFIG_VFD  
  101.     /* must do this after the framebuffer is allocated */  
  102.     drv_vfd_init();  
  103. #endif /* CONFIG_VFD */  
  104.   
  105. /*tempaily use for tiger to avoid died as refreshing LCD*/  
  106.   
  107.     /* IP Address */  
  108.     gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");  
  109.   
  110.     stdio_init ();  /* get the devices list going. */  
  111.     boot_pwr_check();  
  112.   
  113.     jumptable_init ();  
  114.     boot_pwr_check();  
  115.   
  116. #if defined(CONFIG_API)  
  117.     /* Initialize API */  
  118.     api_init ();  
  119. #endif  
  120.     char fake[4]="fak";  
  121.     setenv("splashimage", fake);  
  122.   
  123.     console_init_r ();  /* fully init console as a device */  
  124.     boot_pwr_check();  
  125.   
  126. #if defined(CONFIG_ARCH_MISC_INIT)  
  127.     /* miscellaneous arch dependent initialisations */  
  128.     arch_misc_init ();  
  129. #endif  
  130. #if defined(CONFIG_MISC_INIT_R)  
  131.     /* miscellaneous platform dependent initialisations */  
  132.     misc_init_r ();  
  133. #endif  
  134.   
  135.      /* set up exceptions */  
  136.     interrupt_init ();  
  137.     /* enable exceptions */  
  138.     enable_interrupts ();  
  139.     boot_pwr_check();  
  140.   
  141.     /* Perform network card initialisation if necessary */  
  142. #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)  
  143.     /* XXX: this needs to be moved to board init */  
  144.     if (getenv ("ethaddr")) {  
  145.         uchar enetaddr[6];  
  146.         eth_getenv_enetaddr("ethaddr", enetaddr);  
  147.         smc_set_mac_addr(enetaddr);  
  148.     }  
  149. #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */  
  150.   
  151.     /* Initialize from environment */  
  152.     if ((s = getenv ("loadaddr")) != NULL) {  
  153.         load_addr = simple_strtoul (s, NULL, 16);  
  154.     }  
  155. #if defined(CONFIG_CMD_NET)  
  156.     if ((s = getenv ("bootfile")) != NULL) {  
  157.         copy_filename (BootFile, s, sizeof (BootFile));  
  158.     }  
  159. #endif  
  160.     boot_pwr_check();  
  161.     //usb_eth_initialize(NULL);  
  162. #ifdef BOARD_LATE_INIT  
  163.     board_late_init ();  
  164. #endif  
  165. ......  
  166.   
  167. #ifdef SPRD_EVM_TAG_ON  
  168.         SPRD_EVM_TAG(11);  
  169. #endif  
  170.     extern int do_cboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);  
  171.     boot_pwr_check();  
  172.   
  173.     do_cboot(NULL, 0, 1, NULL);//重点操作函数,此处走至u-boot\property\cmd_cboot.c  
  174.     /* main_loop() can return to retry autoboot, if so just run it again. */  
  175.     for (;;) {  
  176.         main_loop ();  
  177.     }  
  178.   
  179.     /* NOTREACHED - no way out of command loop except booting */  
  180. }  


         该段代码完成了一些设备的初始化do_cboot(NULL, 0, 1, NULL)和main_loop ()是此处重点函数,其中do_cboot(NULL, 0, 1, NULL)的实现在u-boot/property/cmd_cboot.c而main_loop()则是在u-boot/common/main.c中。先看u-boot/property/cmd_cboot.c。

[cpp]  view plain  copy
  1. int boot_pwr_check(void)  
  2. {  
  3.     static int total_cnt = 0;  
  4.     if(!power_button_pressed())  
  5.       total_cnt ++;  
  6.     return total_cnt;  
  7. }  
  8. #define mdelay(_ms) udelay(_ms*1000)  
  9.   
  10.   
  11. int do_cboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])  
  12. {  
  13.     uint32_t key_mode = 0;  
  14.     uint32_t key_code = 0;  
  15.     volatile int i;  
  16.   
  17.     if(argc > 2)  
  18.       goto usage;  
  19.   
  20. #ifdef CONFIG_SC8830  
  21.         if(cali_file_check())  
  22.                 calibration_detect(2);  
  23. #endif  
  24. #ifdef CONFIG_SC7710G2  
  25.     {  
  26.     extern void set_cp_emc_pad(void);  
  27.     set_cp_emc_pad();  
  28.     }  
  29. #endif  
  30.     CHG_Init();  
  31.   
  32. #ifdef CONFIG_SC8830  
  33.     DCDC_Cal_ArmCore();  
  34.     //DCDC_Cal_All(0);  
  35. #endif  
  36.   
  37. #ifdef CONFIG_AUTOBOOT  
  38.     normal_mode();//如果down的是autopoweron的uboot,这里会直接去正常开机  
  39. #endif  
  40.   
  41. #ifdef CONFIG_SC7710G2  
  42.     if(!pbint2_connected())  
  43.         normal_mode();  
  44. #endif  
  45.   
  46.     boot_pwr_check();  
  47.       
  48. #ifdef CONFIG_SC8800G  
  49.     CHG_ShutDown();  
  50.     if(charger_connected()){  
  51.         mdelay(10);  
  52.         CHG_TurnOn();  
  53.     }else{  
  54.         //根据sp8810.h里的LOW_BAT_VOL,如果电压低于3.5V,则直接power down  
  55.         if(is_bat_low()){  
  56.             printf("shut down again for low battery\n");  
  57.             power_down_devices();  
  58.             while(1)  
  59.               ;  
  60.         }  
  61.     }  
  62. #else  
  63.   
  64. #ifndef CONFIG_MACH_CORI  
  65.     if(is_bat_low()){  
  66.                 printf("shut down again for low battery\n");  
  67.                 mdelay(10000);  
  68.                 power_down_devices();  
  69.                 while(1)  
  70.                   ;  
  71.     }  
  72. #endif      
  73. #endif    
  74.   
  75.     boot_pwr_check();  
  76.     board_keypad_init();//初始化键盘  
  77.     boot_pwr_check();  
  78.   
  79. #ifdef CONFIG_SPRD_SYSDUMP  
  80.     write_sysdump_before_boot();  
  81. #endif  
  82.   
  83.     int recovery_init(void);  
  84.     int ret =0;  
  85.     ret = recovery_init();  
  86.     if(ret == 1){  
  87.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  88.         recovery_mode_without_update();  
  89.     }else if(ret == 2){  
  90. #ifndef CONFIG_SC8830  
  91.         try_update_modem(); //update img from mmc  
  92. #endif  
  93.         normal_mode();  
  94.     }  
  95.   
  96.     unsigned check_reboot_mode(void);  
  97.     //获取寄存器里HW的rest标志位,得到当前的开机模式  
  98.     //此处主要是异常重启,恢复出厂设置,关机闹钟等(没有按power键导致的开机)  
  99.     unsigned rst_mode= check_reboot_mode();  
  100.     //检查是否是recovery模式  
  101.     if(rst_mode == RECOVERY_MODE){  
  102.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  103.         recovery_mode();  
  104.     }  
  105.     else if(rst_mode == FASTBOOT_MODE){  
  106.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  107.         fastboot_mode();  
  108.     }else if(rst_mode == NORMAL_MODE){  
  109.         normal_mode();  
  110.     }else if(rst_mode == WATCHDOG_REBOOT){  
  111.         watchdog_mode();  
  112.     }else if(rst_mode == UNKNOW_REBOOT_MODE){  
  113.         unknow_reboot_mode();  
  114.     }else if(rst_mode == PANIC_REBOOT){  
  115.         panic_reboot_mode();  
  116.     }else if(rst_mode == ALARM_MODE){  
  117.               int flag =alarm_flag_check();  
  118.               if(flag == 1)  
  119.             alarm_mode();  
  120.               else if(flag == 2)  
  121.             normal_mode();  
  122.     }else if(rst_mode == SLEEP_MODE){  
  123.         sleep_mode();  
  124.     }else if(rst_mode == SPECIAL_MODE){  
  125.         special_mode();  
  126.     }else if(rst_mode == CALIBRATION_MODE){  
  127.         calibration_detect(0);  
  128.     }  
  129. #ifdef CONFIG_SC8810  
  130. //    normal_mode();  
  131. #endif  
  132.     DBG("func: %s line: %d\n", __func__, __LINE__);  
  133.   
  134.    if(charger_connected()){  
  135.         DBG("%s: charger connected\n", __FUNCTION__);  
  136. #if defined (CONFIG_SP8810W) || defined(CONFIG_SC7710G2)  
  137.             calibration_detect(1);  
  138. #endif  
  139.         charge_mode();  
  140.     }  
  141.     //find the power up trigger  
  142.     //如果按power键的“次数”达标了,认为这个是一次长按事件  
  143.     else if(boot_pwr_check() >= get_pwr_key_cnt()){  
  144.         DBG("%s: power button press\n", __FUNCTION__);  
  145.     DBG("boot_pwr_check=%d,get_pwr_key_cnt=%d\n",boot_pwr_check(),get_pwr_key_cnt());  
  146.         //go on to check other keys  
  147.         mdelay(50);  
  148.         for(i=0; i<10;i++){  
  149.             key_code = board_key_scan();//获取另外一个按键  
  150.             if(key_code != KEY_RESERVED)  
  151.               break;  
  152.         }  
  153.         DBG("key_code %d\n", key_code);  
  154.         //查找对应的按键码对应的开机模式  
  155.         key_mode = check_key_boot(key_code);  
  156.   
  157.         switch(key_mode){  
  158.             case BOOT_FASTBOOT:  
  159.                 fastboot_mode();  
  160.                 break;  
  161.             case BOOT_RECOVERY:  
  162.                 recovery_mode();  
  163.                 break;  
  164.             case BOOT_CALIBRATE:  
  165.                 engtest_mode();  
  166.                 return 0; //back to normal boot  
  167.                 break;  
  168.             case BOOT_DLOADER:  
  169.                 dloader_mode();  
  170.                 break;  
  171.             default:  
  172.                 break;//如果是正常开机模式,因为没有  
  173.         }  
  174.     }  
  175.     else if(alarm_triggered() && alarm_flag_check()){  
  176.         DBG("%s: alarm triggered\n", __FUNCTION__);  
  177.         int flag =alarm_flag_check();  
  178.   
  179.         if(flag == 1){  
  180.             //如果是闹钟触发导致的开机,则进入关机闹钟模式  
  181.             alarm_mode();  
  182.         }  
  183.         else if(flag == 2){  
  184.             normal_mode();//如果只按了power键。  
  185.         }  
  186.           
  187.     }else{  
  188. #if BOOT_NATIVE_LINUX_MODEM  
  189.         *(volatile u32*)CALIBRATION_FLAG = 0xca;  
  190. #endif  
  191. #if !defined (CONFIG_SC8830) && !defined(CONFIG_SC7710G2)  
  192.         calibration_detect(0);  
  193. #endif  
  194.         //if calibrate success, it will here  
  195.         DBG("%s: power done again\n", __FUNCTION__);  
  196.         power_down_devices();  
  197.         while(1)  
  198.           ;  
  199.     }  
  200.   
  201.     if(argc == 1){  
  202.     DBG("func: %s line: %d\n", __func__, __LINE__);  
  203.         normal_mode();  
  204.         return 1;  
  205.     }  
  206.   
  207.     if(argc == 2){  
  208.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  209.   
  210.         if(strcmp(argv[1],"normal") == 0){  
  211.             normal_mode();  
  212.             return 1;  
  213.         }  
  214.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  215.   
  216.         if(strcmp(argv[1],"recovery") == 0){  
  217.             recovery_mode();  
  218.             return 1;  
  219.         }  
  220.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  221.   
  222.         if(strcmp(argv[1],"fastboot") == 0){  
  223.             fastboot_mode();  
  224.             return 1;  
  225.         }  
  226.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  227.   
  228.         if(strcmp(argv[1],"dloader") == 0){  
  229.             dloader_mode();  
  230.             return 1;  
  231.         }  
  232.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  233.   
  234.         if(strcmp(argv[1],"charge") == 0){  
  235.             //如果没有按power键,且插入了充电器,则进入充电模式  
  236.             charge_mode();  
  237.             return 1;  
  238.         }  
  239.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  240.   
  241.         if(strcmp(argv[1],"caliberation") == 0){  
  242.             calibration_detect(1);  
  243.             return 1;  
  244.         }  
  245.         DBG("func: %s line: %d\n", __func__, __LINE__);  
  246.     }  
  247.     DBG("func: %s line: %d\n", __func__, __LINE__);  
  248.   
  249. usage:  
  250.     cmd_usage(cmdtp);  
  251.     return 1;  
  252. }  

           接下来分析正常开机的流程也就是normal_mode(),其他几种开机流程与normal_mode()类似,不再一一分析。android共提供了多种mode:


          normal_mode()的实现在 u-boot/property/normal_mode.c:

[java]  view plain  copy
  1. void normal_mode(void)  
  2. {  
  3. #if defined (CONFIG_SC8810) || defined (CONFIG_SC8825) || defined (CONFIG_SC8830)  
  4.     //MMU_Init(CONFIG_MMU_TABLE_ADDR);  
  5.     vibrator_hw_init();//初始化马达  
  6. #endif  
  7.     set_vibrator(1);//起震,这个就是开机震的那一下  
  8.   
  9. #ifndef UART_CONSOLE_SUPPORT  
  10. #ifdef CONFIG_SC7710G2  
  11.     extern int  serial1_SwitchToModem(void);  
  12.     serial1_SwitchToModem();  
  13. #endif  
  14. #endif  
  15.   
  16. #if BOOT_NATIVE_LINUX  
  17.     vlx_nand_boot(BOOT_PART, CONFIG_BOOTARGS, BACKLIGHT_ON);  
  18. #else  
  19.     vlx_nand_boot(BOOT_PART, NULL, BACKLIGHT_ON);  
  20. #endif  
  21.   
  22. }  


       最终将操作交给vlx_nand_boot(),其实现在u-boot/property/normal_nand_mode.c

[cpp]  view plain  copy
  1. void vlx_nand_boot(char * kernel_pname, char * cmdline, int backlight_set)  
  2. {  
  3. ......  
  4.     char *fixnvpoint = "/fixnv";  
  5.     char *fixnvfilename = "/fixnv/fixnv.bin";  
  6.     char *fixnvfilename2 = "/fixnv/fixnvchange.bin";  
  7.     char *backupfixnvpoint = "/backupfixnv";  
  8.     char *backupfixnvfilename = "/backupfixnv/fixnv.bin";  
  9.   
  10.     char *runtimenvpoint = "/runtimenv";  
  11.     char *runtimenvpoint2 = "/runtimenv";  
  12.     char *runtimenvfilename = "/runtimenv/runtimenv.bin";  
  13.     char *runtimenvfilename2 = "/runtimenv/runtimenvbkup.bin";  
  14.   
  15.     char *productinfopoint = "/productinfo";  
  16.     char *productinfofilename = "/productinfo/productinfo.bin";  
  17.     char *productinfofilename2 = "/productinfo/productinfobkup.bin";  
  18.   
  19.     int orginal_right, backupfile_right;  
  20.     unsigned long orginal_index, backupfile_index;  
  21.     nand_erase_options_t opts;  
  22.     char * mtdpart_def = NULL;  
  23. #if (defined CONFIG_SC8810) || (defined CONFIG_SC8825)  
  24.     MMU_Init(CONFIG_MMU_TABLE_ADDR);  
  25. #endif  
  26.     ret = mtdparts_init();  
  27.     if (ret != 0){  
  28.         printf("mtdparts init error %d\n", ret);  
  29.         return;  
  30.     }  
  31.   
  32. #ifdef CONFIG_SPLASH_SCREEN  
  33. #define SPLASH_PART "boot_logo"  
  34.     ret = find_dev_and_part(SPLASH_PART, &dev, &pnum, &part);  
  35.     if(ret){  
  36.         printf("No partition named %s\n", SPLASH_PART);  
  37.         return;  
  38.     }else if(dev->id->type != MTD_DEV_TYPE_NAND){  
  39.         printf("Partition %s not a NAND device\n", SPLASH_PART);  
  40.         return;  
  41.     }  
  42.     //读取下载到nand中的boot_logo,就是开机亮的那一屏  
  43.     off=part->offset;  
  44.     nand = &nand_info[dev->id->num];  
  45.     //read boot image header  
  46.     size = 1<<19;//where the size come from????//和dowload工具中的地址一致  
  47.     char * bmp_img = malloc(size);  
  48.     if(!bmp_img){  
  49.         printf("not enough memory for splash image\n");  
  50.         return;  
  51.     }  
  52.     ret = nand_read_offset_ret(nand, off, &size, (void *)bmp_img, &off);  
  53.     if(ret != 0){  
  54.         printf("function: %s nand read error %d\n", __FUNCTION__, ret);  
  55.         return;  
  56.     }  
  57.     //第一次LCD logo  
  58.     lcd_display_logo(backlight_set,(ulong)bmp_img,size);  
  59. #endif  
  60.     set_vibrator(0);//停止震动,如果发现开机狂震不止,那就是没走到这里。  
  61.     {  
  62.         nand_block_info(nand, &good_blknum, &bad_blknum);  
  63.         printf("good is %d  bad is %d\n", good_blknum, bad_blknum);  
  64.     }  
  65.   
  66.     ret = load_sector_to_memory(fixnvpoint,  
  67.             fixnvfilename2,  
  68.             fixnvfilename,  
  69.             (unsigned char *)FIXNV_ADR,  
  70.             (unsigned char *)MODEM_ADR,  
  71.             FIXNV_SIZE + 4);  
  72. ......  
  73.   
  74. #elif defined(CONFIG_CALIBRATION_MODE_NEW)  
  75. #if defined(CONFIG_SP7702) || defined(CONFIG_SP8810W)  
  76.     /* 
  77.        force dsp sleep in native 8810 verson to reduce power consumption 
  78.      */  
  79.     extern void DSP_ForceSleep(void);  
  80.     DSP_ForceSleep();  
  81.     printf("dsp nand read ok1 %d\n", ret);  
  82. #endif  
  83.   
  84. #ifdef CONFIG_SC7710G2  
  85.     ret = try_update_spl();  
  86.     if(ret == -1){  
  87.         printf("try update spl faild!\n");  
  88.         return -1;  
  89.     }  
  90.   
  91.     ret =  try_load_fixnv();  
  92.     if(ret == -1){  
  93.         printf("try load fixnv faild!\n");  
  94.         return -1;  
  95.     }  
  96.   
  97.     ret =  try_load_runtimenv();  
  98.     if(ret == -1){  
  99.         printf("try load runtimenv faild!\n");  
  100.     }  
  101.   
  102.     ret =  try_load_productinfo();  
  103.     if(ret == -1){  
  104.         printf("try load productinfo faild!\n");  
  105.     }  
  106. #endif  
  107.     if(poweron_by_calibration())  
  108.     {  
  109. #ifndef CONFIG_SC7710G2  
  110.         // ---------------------fix nv--------------------------------  
  111.   
  112. ......  
  113.   
  114.         // ---------------------runtime nv----------------------------  
  115. ......  
  116.         // ---------------------DSP ----------------------------  
  117. ......  
  118.   
  119. #endif  
  120.       
  121.     /* KERNEL_PART */  
  122.     printf("Reading kernel to 0x%08x\n", KERNEL_ADR);  
  123.   
  124.     ret = find_dev_and_part(kernel_pname, &dev, &pnum, &part);  
  125.     if(ret){  
  126.         printf("No partition named %s\n", kernel_pname);  
  127.         return;  
  128.     }else if(dev->id->type != MTD_DEV_TYPE_NAND){  
  129.         printf("Partition %s not a NAND device\n", kernel_pname);  
  130.         return;  
  131.     }  
  132.   
  133.     off=part->offset;  
  134.     nand = &nand_info[dev->id->num];  
  135.     //read boot image header  
  136. #if 0  
  137.     size = nand->writesize;  
  138.     flash_page_size = nand->writesize;  
  139.     ret = nand_read_offset_ret(nand, off, &size, (void *)hdr, &off);  
  140.     if(ret != 0){  
  141.         printf("function: %s nand read error %d\n", __FUNCTION__, ret);  
  142.         return;  
  143.     }  
  144.     if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)){  
  145.         printf("bad boot image header, give up read!!!!\n");  
  146.         return;  
  147.     }  
  148.     else  
  149.     {  
  150.         //read kernel image  
  151.         size = (hdr->kernel_size+(flash_page_size - 1)) & (~(flash_page_size - 1));  
  152.         if(size <=0){  
  153.             printf("kernel image should not be zero\n");  
  154.             return;  
  155.         }  
  156.         ret = nand_read_offset_ret(nand, off, &size, (void *)KERNEL_ADR, &off);  
  157.         if(ret != 0){  
  158.             printf("kernel nand read error %d\n", ret);  
  159.             return;  
  160.         }  
  161.         //read ramdisk image  
  162.         size = (hdr->ramdisk_size+(flash_page_size - 1)) & (~(flash_page_size - 1));  
  163.         if(size<0){  
  164.             printf("ramdisk size error\n");  
  165.             return;  
  166.         }  
  167.         ret = nand_read_offset_ret(nand, off, &size, (void *)RAMDISK_ADR, &off);  
  168.         if(ret != 0){  
  169.             printf("ramdisk nand read error %d\n", ret);  
  170.             return;  
  171.         }  
  172.     }  
  173. #else  
  174.   
  175.     ret = load_kernel_and_layout(nand,  
  176.             (unsigned int)off,  
  177.             (char *)raw_header,  
  178.             (char *) KERNEL_ADR,  
  179.             (char *) RAMDISK_ADR,  
  180.             2048,  
  181.             nand->writesize);  
  182.   
  183.     if (ret != 0) {  
  184.         printf("ramdisk nand read error %d\n", ret);  
  185.         return;  
  186.     }  
  187.   
  188. #endif  
  189.   
  190. ......  
  191.   
  192. {  
  193.   
  194.     good_blknum = 0;  
  195.     bad_blknum  = 0;  
  196.     nand_block_info(nand, &good_blknum, &bad_blknum);  
  197.     printf("good is %d  bad is %d\n", good_blknum, bad_blknum);  
  198. }  
  199. creat_cmdline(cmdline,hdr);  
  200. vlx_entry();//末尾进入entry(),其实现在normal_mode.c  
  201. }  

      该函数的重点在开头和结尾的相关操作,开头部分见注释,重点分析vlx_entry()函数,其实现在normal_mode.c:

[cpp]  view plain  copy
  1. void vlx_entry()  
  2. {  
  3. #if !(defined CONFIG_SC8810 || defined CONFIG_TIGER || defined CONFIG_SC8830)  
  4.     MMU_InvalideICACHEALL();  
  5. #endif  
  6.   
  7. #if (defined CONFIG_SC8810) || (defined CONFIG_SC8825) || (defined CONFIG_SC8830)  
  8.     MMU_DisableIDCM();  
  9. #endif  
  10.   
  11. #ifdef REBOOT_FUNCTION_INUBOOT  
  12.     reboot_func();  
  13. #endif  
  14.   
  15. #if BOOT_NATIVE_LINUX  
  16.     start_linux();  
  17. #else  
  18.     void (*entry)(void) = (void*) VMJALUNA_ADR;  
  19.     entry();  
  20. #endif  
  21. }  

      这里的entry()跳转到VM虚拟机的首地址,start_linux()则是进入kernel的方法,仍在normal_mode.c中实现:

[cpp]  view plain  copy
  1. static int start_linux()  
  2. {  
  3.     void (*theKernel)(int zero, int arch, u32 params);  
  4.     u32 exec_at = (u32)-1;  
  5.     u32 parm_at = (u32)-1;  
  6.     u32 machine_type;  
  7.   
  8.     machine_type = machine_arch_type;         /* get machine type */  
  9.     //重点根据KERNEL的地址  
  10.     theKernel = (void (*)(intint, u32))KERNEL_ADR; /* set the kernel address */  
  11. #ifndef CONFIG_SC8830  
  12.     *(volatile u32*)0x84001000 = 'j';  
  13.     *(volatile u32*)0x84001000 = 'm';  
  14.     *(volatile u32*)0x84001000 = 'p';  
  15. #endif  
  16.     //根据Kernel的地址走至Kernel\init\main.c的start_kernel()  
  17.     theKernel(0, machine_type, VLX_TAG_ADDR);    /* jump to kernel with register set */  
  18.     while(1);  
  19.     return 0;  
  20. }  


      至此,已经到了Kernel\init\main.c的start_kernel(),即来到了linux的世界。

3,linux启动详细分析

       Kernel\init\main.c的start_kernel()的kernel的起点,先看这个函数:

[cpp]  view plain  copy
  1. asmlinkage void __init start_kernel(void)  
  2. {  
  3.     char * command_line;  
  4.     extern const struct kernel_param __start___param[], __stop___param[];  
  5.   
  6. #ifdef CONFIG_NKERNEL  
  7.     jiffies_64 = INITIAL_JIFFIES;  
  8. #endif  
  9.     smp_setup_processor_id();  
  10.   
  11.     /* 
  12.      * Need to run as early as possible, to initialize the 
  13.      * lockdep hash: 
  14.      */  
  15.     lockdep_init();  
  16.     debug_objects_early_init();  
  17.   
  18.     /* 
  19.      * Set up the the initial canary ASAP: 
  20.      */  
  21.     boot_init_stack_canary();  
  22.   
  23.     cgroup_init_early();  
  24.   
  25.     local_irq_disable();  
  26.     early_boot_irqs_disabled = true;  
  27.   
  28. /* 
  29.  * Interrupts are still disabled. Do necessary setups, then 
  30.  * enable them 
  31.  */  
  32.     tick_init();  
  33.     boot_cpu_init();  
  34.     page_address_init();  
  35.     printk(KERN_NOTICE "%s", linux_banner);  
  36.     setup_arch(&command_line);  
  37.     mm_init_owner(&init_mm, &init_task);  
  38.     mm_init_cpumask(&init_mm);  
  39.     setup_command_line(command_line);  
  40.     setup_nr_cpu_ids();  
  41.     setup_per_cpu_areas();  
  42.     smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */  
  43.   
  44.     build_all_zonelists(NULL);  
  45.     page_alloc_init();  
  46.   
  47.     printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);  
  48.     parse_early_param();  
  49.     parse_args("Booting kernel", static_command_line, __start___param,  
  50.            __stop___param - __start___param,  
  51.            &unknown_bootoption);  
  52.     /* 
  53.      * These use large bootmem allocations and must precede 
  54.      * kmem_cache_init() 
  55.      */  
  56.     setup_log_buf(0);  
  57.     pidhash_init();  
  58.     vfs_caches_init_early();  
  59.     sort_main_extable();  
  60.     trap_init();  
  61.     mm_init();  
  62.   
  63.     /* 
  64.      * Set up the scheduler prior starting any interrupts (such as the 
  65.      * timer interrupt). Full topology setup happens at smp_init() 
  66.      * time - but meanwhile we still have a functioning scheduler. 
  67.      */  
  68.     sched_init();  
  69.     /* 
  70.      * Disable preemption - early bootup scheduling is extremely 
  71.      * fragile until we cpu_idle() for the first time. 
  72.      */  
  73.     preempt_disable();  
  74.     if (!irqs_disabled()) {  
  75.         printk(KERN_WARNING "start_kernel(): bug: interrupts were "  
  76.                 "enabled *very* early, fixing it\n");  
  77.         local_irq_disable();  
  78.     }  
  79.     idr_init_cache();  
  80.     perf_event_init();  
  81.     rcu_init();  
  82.     radix_tree_init();  
  83.     /* init some links before init_ISA_irqs() */  
  84.     early_irq_init();  
  85.     init_IRQ();  
  86.     prio_tree_init();  
  87.     init_timers();  
  88.     hrtimers_init();  
  89.     softirq_init();  
  90.     timekeeping_init();  
  91.     time_init();  
  92.     profile_init();  
  93.     call_function_init();  
  94.     if (!irqs_disabled())  
  95.         printk(KERN_CRIT "start_kernel(): bug: interrupts were "  
  96.                  "enabled early\n");  
  97.     early_boot_irqs_disabled = false;  
  98.     local_irq_enable();  
  99.   
  100.     /* Interrupts are enabled now so all GFP allocations are safe. */  
  101.     gfp_allowed_mask = __GFP_BITS_MASK;  
  102.   
  103.     kmem_cache_init_late();  
  104.   
  105.     /* 
  106.      * HACK ALERT! This is early. We're enabling the console before 
  107.      * we've done PCI setups etc, and console_init() must be aware of 
  108.      * this. But we do want output early, in case something goes wrong. 
  109.      */  
  110.     console_init();  
  111.     if (panic_later)  
  112.         panic(panic_later, panic_param);  
  113.   
  114.     lockdep_info();  
  115.   
  116.     /* 
  117.      * Need to run this when irqs are enabled, because it wants 
  118.      * to self-test [hard/soft]-irqs on/off lock inversion bugs 
  119.      * too: 
  120.      */  
  121.     locking_selftest();  
  122.   
  123. #ifdef CONFIG_BLK_DEV_INITRD  
  124.     if (initrd_start && !initrd_below_start_ok &&  
  125.         page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {  
  126.         printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "  
  127.             "disabling it.\n",  
  128.             page_to_pfn(virt_to_page((void *)initrd_start)),  
  129.             min_low_pfn);  
  130.         initrd_start = 0;  
  131.     }  
  132. #endif  
  133.     page_cgroup_init();  
  134.     enable_debug_pagealloc();  
  135.     debug_objects_mem_init();  
  136.     kmemleak_init();  
  137.     setup_per_cpu_pageset();  
  138.     numa_policy_init();  
  139.     if (late_time_init)  
  140.         late_time_init();  
  141.     sched_clock_init();  
  142.     calibrate_delay();  
  143.     pidmap_init();  
  144.     anon_vma_init();  
  145. #ifdef CONFIG_X86  
  146.     if (efi_enabled)  
  147.         efi_enter_virtual_mode();  
  148. #endif  
  149.     thread_info_cache_init();  
  150.     cred_init();  
  151.     fork_init(totalram_pages);  
  152.     proc_caches_init();  
  153.     buffer_init();  
  154.     key_init();  
  155.     security_init();  
  156.     dbg_late_init();  
  157.     vfs_caches_init(totalram_pages);  
  158.     signals_init();  
  159.     /* rootfs populating might need page-writeback */  
  160.     page_writeback_init();  
  161. #ifdef CONFIG_PROC_FS  
  162.     proc_root_init();  
  163. #endif  
  164.     cgroup_init();  
  165.     cpuset_init();  
  166.     taskstats_init_early();  
  167.     delayacct_init();  
  168.   
  169.     check_bugs();  
  170.   
  171.     acpi_early_init(); /* before LAPIC and SMP init */  
  172.     sfi_init_late();  
  173.   
  174.     ftrace_init();  
  175.   
  176.     /* Do the rest non-__init'ed, we're now alive */  
  177.     //第一个跟init 进程相关的函数  
  178.     rest_init();  
  179. }  

      该函数所调用的大部分都是相关的初始化操作,而跟启动关联的是结尾的rest_init() ,该函数是第一个跟init进程相关的函数,看其实现:

[cpp]  view plain  copy
  1. static noinline void __init_refok rest_init(void)  
  2. {  
  3.     int pid;  
  4.   
  5.     rcu_scheduler_starting();  
  6.     /* 
  7.      * We need to spawn init first so that it obtains pid 1, however 
  8.      * the init task will end up wanting to create kthreads, which, if 
  9.      * we schedule it before we create kthreadd, will OOPS. 
  10.      */  
  11.      //启动kernel_init来进行接下来的初始化  
  12.     kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);  
  13.     numa_default_policy();  
  14.     pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);  
  15.     rcu_read_lock();  
  16.     kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);  
  17.     rcu_read_unlock();  
  18.     complete(&kthreadd_done);  
  19.   
  20.     /* 
  21.      * The boot idle thread must execute schedule() 
  22.      * at least once to get things moving: 
  23.      */  
  24.     init_idle_bootup_task(current);  
  25.     preempt_enable_no_resched();  
  26.     schedule();  
  27.     preempt_disable();  
  28.   
  29.     /* Call into cpu_idle with preempt disabled */  
  30.     cpu_idle();//将系统交给调度器处理。  
  31. }  

      该函数启动了kernel_init来进行后续的初始化,进而看kernel_init(),这些函数任然在main.c中实现。

[cpp]  view plain  copy
  1. static int __init kernel_init(void * unused)  
  2. {  
  3.     /* 
  4.      * Wait until kthreadd is all set-up. 
  5.      */  
  6.     wait_for_completion(&kthreadd_done);  
  7.     /* 
  8.      * init can allocate pages on any node 
  9.      */  
  10.     set_mems_allowed(node_states[N_HIGH_MEMORY]);  
  11.     /* 
  12.      * init can run on any cpu. 
  13.      */  
  14.     set_cpus_allowed_ptr(current, cpu_all_mask);  
  15.   
  16.     cad_pid = task_pid(current);  
  17.   
  18.     smp_prepare_cpus(setup_max_cpus);  
  19.   
  20.     do_pre_smp_initcalls();  
  21.     lockup_detector_init();  
  22.   
  23.     smp_init();  
  24.     sched_init_smp();  
  25.     //此函数中会调用各个驱动模块的加载函数(静态编译的,非ko)来初始化设备  
  26.     do_basic_setup();  
  27.   
  28.     /* Open the /dev/console on the rootfs, this should never fail */  
  29.     if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)  
  30.         printk(KERN_WARNING "Warning: unable to open an initial console.\n");  
  31.   
  32.     (void) sys_dup(0);  
  33.     (void) sys_dup(0);  
  34.     /* 
  35.      * check if there is an early userspace init.  If yes, let it do all 
  36.      * the work 
  37.      */  
  38.   
  39.     if (!ramdisk_execute_command)  
  40.         ramdisk_execute_command = "/init";  
  41.   
  42.     if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {  
  43.         ramdisk_execute_command = NULL;  
  44.         prepare_namespace();  
  45.     }  
  46.   
  47.     /* 
  48.      * Ok, we have completed the initial bootup, and 
  49.      * we're essentially up and running. Get rid of the 
  50.      * initmem segments and start the user-mode stuff.. 
  51.      */  
  52.     //走至init 进程的相关操作  
  53.     init_post();  
  54.     return 0;  
  55. }  


      init进程由init_post()创建 即main.c 的init_post():

[cpp]  view plain  copy
  1. static noinline int init_post(void)  
  2. {  
  3.     /* need to finish all async __init code before freeing the memory */  
  4.     async_synchronize_full();  
  5.     free_initmem();  
  6.     mark_rodata_ro();  
  7.     system_state = SYSTEM_RUNNING;  
  8.     numa_default_policy();  
  9.   
  10.   
  11.     current->signal->flags |= SIGNAL_UNKILLABLE;  
  12.   
  13.     if (ramdisk_execute_command) {  
  14.         run_init_process(ramdisk_execute_command);  
  15.         printk(KERN_WARNING "Failed to execute %s\n",  
  16.                 ramdisk_execute_command);  
  17.     }  
  18.   
  19.     /* 
  20.      * We try each of these until one succeeds. 
  21.      * 
  22.      * The Bourne shell can be used instead of init if we are 
  23.      * trying to recover a really broken machine. 
  24.      */  
  25.     if (execute_command) {  
  26.         //至此init启动完成,接下来的启动就是System\core\init\init.c的main()  
  27.         run_init_process(execute_command);  
  28.         printk(KERN_WARNING "Failed to execute %s.  Attempting "  
  29.                     "defaults...\n", execute_command);  
  30.     }  
  31.     run_init_process("/sbin/init");  
  32.     run_init_process("/etc/init");  
  33.     run_init_process("/bin/init");  
  34.     run_init_process("/bin/sh");  
  35.   
  36.     panic("No init found.  Try passing init= option to kernel. "  
  37.           "See Linux Documentation/init.txt for guidance.");  
  38. }  

4,android启动详细分析

      android部分的启动包括几个部分:init,zygote,systemserver,launcher,lockscreen,othersapps。

4.1,init启动

      init是一个进程,确切的说,是linux系统用户空间的第一个进程,android是基于linux 的,所以init也是android用户空间的第一个进程,他的进程号是1,作为天字第一号进程,其有很多重要的职责。其最重要的职责是创建了Zygote以及提供了systemserver。system\core\init\init.c的入口函数是main()。

[cpp]  view plain  copy
  1. int main(int argc, char **argv)  
  2. {  
  3.     int fd_count = 0;  
  4.     struct pollfd ufds[4];  
  5.     char *tmpdev;  
  6.     char* debuggable;  
  7.     char tmp[32];  
  8.     int property_set_fd_init = 0;  
  9.     int signal_fd_init = 0;  
  10.     int keychord_fd_init = 0;  
  11.     bool is_charger = false;  
  12.   
  13.     if (!strcmp(basename(argv[0]), "ueventd"))  
  14.         return ueventd_main(argc, argv);  
  15.   
  16.     /* clear the umask */  
  17.     umask(0);  
  18.   
  19.         /* Get the basic filesystem setup we need put 
  20.          * together in the initramdisk on / and then we'll 
  21.          * let the rc file figure out the rest. 
  22.          */  
  23.     //创建一些文件夹,并挂载设备,这些是与linux相关的  
  24.     mkdir("/dev", 0755);  
  25.     mkdir("/proc", 0755);  
  26.     mkdir("/sys", 0755);  
  27.   
  28.     mount("tmpfs""/dev""tmpfs", MS_NOSUID, "mode=0755");  
  29.     mkdir("/dev/pts", 0755);  
  30.     mkdir("/dev/socket", 0755);  
  31.     mount("devpts""/dev/pts""devpts", 0, NULL);  
  32.     mount("proc""/proc""proc", 0, NULL);  
  33.     mount("sysfs""/sys""sysfs", 0, NULL);  
  34.   
  35.         /* indicate that booting is in progress to background fw loaders, etc */  
  36.     close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));  
  37.   
  38.         /* We must have some place other than / to create the 
  39.          * device nodes for kmsg and null, otherwise we won't 
  40.          * be able to remount / read-only later on. 
  41.          * Now that tmpfs is mounted on /dev, we can actually 
  42.          * talk to the outside world. 
  43.          */  
  44.     //重定向标准输入输出 错误输出到/dev/_null_  
  45.     open_devnull_stdio();  
  46.     //设置init的日志输出设备为/dev/_kmsg_,不过该文件打开后  
  47.     //会立刻被unlink,这样其他进程就无法打开这个文件读取日志信息  
  48.     klog_init();  
  49.     //prop配置文件的解析与初始化操作,如//设置"/default.prop"属性文件  
  50.     property_init();  
  51.         //通过读取proc/cpuinfo得到机器的hardware名  
  52.     get_hardware_name(hardware, &revision);  
  53.   
  54.     process_kernel_cmdline();  
  55.   
  56. #ifdef HAVE_SELINUX  
  57.     INFO("loading selinux policy\n");  
  58.     selinux_load_policy();  
  59. #endif  
  60.   
  61.     is_charger = !strcmp(bootmode, "charger");  
  62.   
  63.     INFO("property init\n");  
  64.     if (!is_charger)  
  65.         property_load_boot_defaults();  
  66.   
  67.     INFO("reading config file\n");  
  68.     //解析init.rc配置文件 非常重要,文件系统的挂载,权限设置  
  69.     //以及系统server的启动,包括Zygote的创建  
  70.     init_parse_config_file("/init.rc");  
  71.      /** 
  72.         **解析完init.rc 会得到一系列的action动作 
  73.         **keychord_init_action和console_init_action 
  74.         **/  
  75.     action_for_each_trigger("early-init", action_add_queue_tail);  
  76.   
  77.     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");  
  78.     queue_builtin_action(keychord_init_action, "keychord_init");  
  79.     //console_init_action为控制台初始化,此处会加载一帧boot logo文件为initlogo.rle  
  80.     queue_builtin_action(console_init_action, "console_init");  
  81.   
  82.     /* execute all the boot actions to get us started */  
  83.     action_for_each_trigger("init", action_add_queue_tail);  
  84.   
  85.     /* skip mounting filesystems in charger mode */  
  86.   
  87.     action_for_each_trigger("early-fs", action_add_queue_tail);  
  88.     //action_for_each_trigger("fs", action_add_queue_tail);  
  89.     {  
  90.         bool has_3partions = false;  
  91.   
  92.         has_3partions = (!access("/sys/block/mmcblk0/mmcblk0p3",R_OK))  
  93.             && (!access("/sys/block/mmcblk0/mmcblk0p2",R_OK))  
  94.             && (!access("/sys/block/mmcblk0/mmcblk0p1",R_OK));  
  95.   
  96.         if (has_3partions) {  
  97.             action_for_each_trigger("fs-two", action_add_queue_tail);  
  98.         } else {  
  99.             action_for_each_trigger("fs", action_add_queue_tail);  
  100.         }  
  101.     }  
  102.     action_for_each_trigger("post-fs", action_add_queue_tail);  
  103.     if (!is_charger) {  
  104.         //action_for_each_trigger("post-fs", action_add_queue_tail);  
  105.         action_for_each_trigger("post-fs-data", action_add_queue_tail);  
  106.     }  
  107.   
  108.     queue_builtin_action(property_service_init_action, "property_service_init");  
  109.     queue_builtin_action(signal_init_action, "signal_init");  
  110.     queue_builtin_action(check_startup_action, "check_startup");  
  111.   
  112.     if (!strcmp(bootmode, "alarm")) {  
  113.         action_for_each_trigger("alarm", action_add_queue_tail);  
  114.     }  
  115.     if (is_charger) {  
  116.         action_for_each_trigger("charger", action_add_queue_tail);  
  117.     } else {  
  118.         action_for_each_trigger("early-boot", action_add_queue_tail);  
  119.         action_for_each_trigger("boot", action_add_queue_tail);  
  120.     }  
  121.   
  122.         /* run all property triggers based on current state of the properties */  
  123.     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");  
  124.   
  125.   
  126. #if BOOTCHART  
  127.     queue_builtin_action(bootchart_init_action, "bootchart_init");  
  128. #endif  
  129.   
  130.     for(;;) {//无限循环启动进程  
  131.         int nr, i, timeout = -1;  
  132.   
  133.         execute_one_command();//再循环中执行动作  
  134.         restart_processes();//重启已经死去的进程  
  135.   
  136.         if (!property_set_fd_init && get_property_set_fd() > 0) {  
  137.             ufds[fd_count].fd = get_property_set_fd();  
  138.             ufds[fd_count].events = POLLIN;  
  139.             ufds[fd_count].revents = 0;  
  140.             fd_count++;  
  141.             property_set_fd_init = 1;  
  142.         }  
  143.         if (!signal_fd_init && get_signal_fd() > 0) {  
  144.             ufds[fd_count].fd = get_signal_fd();  
  145.             ufds[fd_count].events = POLLIN;  
  146.             ufds[fd_count].revents = 0;  
  147.             fd_count++;  
  148.             signal_fd_init = 1;  
  149.         }  
  150.         if (!keychord_fd_init && get_keychord_fd() > 0) {  
  151.             ufds[fd_count].fd = get_keychord_fd();  
  152.             ufds[fd_count].events = POLLIN;  
  153.             ufds[fd_count].revents = 0;  
  154.             fd_count++;  
  155.             keychord_fd_init = 1;  
  156.         }  
  157.   
  158.         if (process_needs_restart) {  
  159.             timeout = (process_needs_restart - gettime()) * 1000;  
  160.             if (timeout < 0)  
  161.                 timeout = 0;  
  162.         }  
  163.   
  164.         if (!action_queue_empty() || cur_action)  
  165.             timeout = 0;  
  166.   
  167. #if BOOTCHART  
  168.         if (bootchart_count > 0) {  
  169.             if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)  
  170.                 timeout = BOOTCHART_POLLING_MS;  
  171.             if (bootchart_step() < 0 || --bootchart_count == 0) {  
  172.                 bootchart_finish();  
  173.                 bootchart_count = 0;  
  174.             }  
  175.         }  
  176. #endif  
  177.   
  178.         nr = poll(ufds, fd_count, timeout);  
  179.         if (nr <= 0)  
  180.             continue;  
  181.   
  182.         for (i = 0; i < fd_count; i++) {  
  183.             if (ufds[i].revents == POLLIN) {  
  184.                 if (ufds[i].fd == get_property_set_fd())  
  185.                     handle_property_set_fd();  
  186.                 else if (ufds[i].fd == get_keychord_fd())  
  187.                     handle_keychord();  
  188.                 else if (ufds[i].fd == get_signal_fd())  
  189.                     handle_signal();  
  190.             }  
  191.         }  
  192.     }  
  193.   
  194.     return 0;  
  195. }  

      从以上代码可知,init的工作任务还是很重的,上面的代码已经省略的不少,但任然很多,不过分析两个知识点来看,可将init的工作流程精简为四点:1,解析配置文件重点是init.rc。2,执行各个阶段的动作,创建zygote的工作就在其中的某一个阶段完成。3,调用property_init()初始化属性相关的资源,并且通过property_load_boot_defaults()启动属性服务。4,init进入一个无限循环,并且等待一些事情的发生。接下来重点看下解析配置文件的init.rc。解析函数:

[cpp]  view plain  copy
  1. int init_parse_config_file(const char *fn)  
  2. {  
  3.     char *data;  
  4.     data = read_file(fn, 0);  
  5.     if (!data) return -1;  
  6.   
  7.     parse_config(fn, data);  
  8.     DUMP();  
  9.     return 0;  
  10. }  

      再看init.rc文件:

[cpp]  view plain  copy
  1. ......  
  2.   
  3. // service管理器 ---- > servicemanager.cpp/ servicemanager.java  
  4. service servicemanager /system/bin/servicemanager    
  5.     class core  
  6.     user system  
  7.     group system  
  8.     critical  
  9.     onrestart restart zygote ------ > 启动zygote进程  
  10.     onrestart restart media ------ > 启动media  
  11.     onrestart restart surfaceflinger------ > 启动surfaceflinger  
  12.     onrestart restart drm------ > 启动drm  
  13.   
  14. service vold /system/bin/vold  
  15.     class core  
  16.     socket vold stream 0660 root mount  
  17.     ioprio be 2  
  18.   
  19. service netd /system/bin/netd  
  20.     class main  
  21.     socket netd stream 0660 root system  
  22.     socket dnsproxyd stream 0660 root inet  
  23.   
  24. service debuggerd /system/bin/debuggerd  
  25.     class main  
  26.   
  27. service ril-daemon /system/bin/rild  
  28.     class main  
  29.     socket rild stream 660 root radio  
  30.     socket rild-debug stream 660 radio system  
  31.     user root  
  32.     group radio cache inet misc audio sdcard_rw log  
  33. // surfaceflinger服务  
  34. //对应surfaceflinger.cpp----- >在system_server中具体实现  
  35. service surfaceflinger /system/bin/surfaceflinger  
  36.     class main  
  37.     user system  
  38.     group graphics  
  39. onrestart restart zygote  
  40.   
  41. // zygote进程  
  42. //后面重点分析  
  43. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server  
  44.     class main  
  45.     socket zygote stream 666  
  46.     onrestart write /sys/android_power/request_state wake  
  47.     onrestart write /sys/power/state on  
  48.     onrestart restart media  
  49. onrestart restart netd  
  50.   
  51. // drm服务  
  52. service drm /system/bin/drmserver  
  53.     class main  
  54.     user drm  
  55. group system inet drmrpc  
  56.   
  57. // mediaserver服务  
  58. //在Main_mediaserver.cpp中实现,启动audio camera 等服务  
  59. service media /system/bin/mediaserver  
  60.     class main  
  61.     user media  
  62.     group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc  
  63.     ioprio rt 4  
  64. //此处引导播放开机动画,并在surfaceflinger中具体实现  
  65. service bootanim /system/bin/bootanimation  
  66.     class main  
  67.     user graphics  
  68.     group graphics  
  69.     disabled  
  70. oneshot  
  71. ......  

      在init.rc中完成了一系列的重要操作:文件系统权限及挂载,启动zygote,启动系统服务,播放开机动画。当然如何解析对应的代码,并完成对应的操作,如启动zygote、播放开机动画,可以参考相关资料或查看源码,此处不再详述。至此init已经将部分操作交给了zygote。

4.2,zygote启动

      zygote的启动预示着真正的来到了java的世界。zygote这个词的中文意思的受精卵,他和android系统中的java世界有着重要关系。zygote本身是一个native的应用程序,与驱动,内核均无关系。根据对init的了解我们知道,zygote是有init进程根据init.rc文件中的配置项创建的。先分析其来历,zygote最初的名字叫app_process,这个名字是在android.mk文件中指定的。但在运行过程中,app_process通过linux下的pctrl系统调用将自己的名字换成了zygote,所以通过进程看到的名称是zygote。

      Zygote进程中完成了java虚拟机的创建及初始化,以及准备了java运行时环境,还有jni的准备工作,所以zygote占据了整个android世界的半壁江山,另半壁江山则是system_server,后续会详细介绍。

      Zygote---- >入口文件App_main.cpp ---- >main()
      Zygote原意是受精卵的意思。
      在linux中指app_process即:frameworks/base/cmds/app_process目录下的App_main.cpp
      此处可发现main()

[cpp]  view plain  copy
  1. int main(int argc, const charconst argv[])  
  2. {  
  3.     // These are global variables in ProcessState.cpp  
  4.     mArgC = argc;  
  5.     mArgV = argv;  
  6.   
  7.     mArgLen = 0;  
  8.     for (int i=0; i<argc; i++) {  
  9.         mArgLen += strlen(argv[i]) + 1;  
  10.     }  
  11.     mArgLen--;  
  12.   
  13.     AppRuntime runtime;  
  14.     const char* argv0 = argv[0];  
  15.   
  16.     // Process command line arguments  
  17.     // ignore argv[0]  
  18.     argc--;  
  19.     argv++;  
  20.   
  21.     // Everything up to '--' or first non '-' arg goes to the vm  
  22.   
  23.     int i = runtime.addVmArguments(argc, argv);  
  24.   
  25.     // Parse runtime arguments.  Stop at first unrecognized option.  
  26.     bool zygote = false;  
  27.     bool startSystemServer = false;  
  28.     bool application = false;  
  29.     const char* parentDir = NULL;  
  30.     const char* niceName = NULL;  
  31.     const char* className = NULL;  
  32.     while (i < argc) {  
  33.         const char* arg = argv[i++];  
  34.         if (!parentDir) {  
  35.             parentDir = arg;  
  36.         } else if (strcmp(arg, "--zygote") == 0) {  
  37.             zygote = true;  
  38.             niceName = "zygote";  
  39.         } else if (strcmp(arg, "--start-system-server") == 0) {  
  40.             startSystemServer = true;  
  41.         } else if (strcmp(arg, "--application") == 0) {  
  42.             application = true;  
  43.         } else if (strncmp(arg, "--nice-name=", 12) == 0) {  
  44.             niceName = arg + 12;  
  45.         } else {  
  46.             className = arg;  
  47.             break;  
  48.         }  
  49.     }  
  50.   
  51.     if (niceName && *niceName) {  
  52.         setArgv0(argv0, niceName);  
  53.         set_process_name(niceName);  
  54.     }  
  55.   
  56.     runtime.mParentDir = parentDir;  
  57.   
  58.     if (zygote) {  
  59.         // do last shutdown check  
  60.         ALOGV("doLastShutDownCheck");  
  61.         doLastShutDownCheck();   
  62.         runtime.start("com.android.internal.os.ZygoteInit",  
  63.                 startSystemServer ? "start-system-server" : "");  
  64.     } else if (className) {  
  65.         // Remainder of args get passed to startup class main()  
  66.         runtime.mClassName = className;  
  67.         runtime.mArgC = argc - i;  
  68.         runtime.mArgV = argv + i;  
  69.         runtime.start("com.android.internal.os.RuntimeInit",  
  70.                 application ? "application" : "tool");  
  71.     } else {  
  72.         fprintf(stderr, "Error: no class name or --zygote supplied.\n");  
  73.         app_usage();  
  74.         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");  
  75.         return 10;  
  76.     }  
  77. }  


      该代码主要完成工作如下:

      1,niceName = "zygote";---- >重命名,原进程名称为app_process
     ,2,setArgv0(argv0, niceName);
     ,3,set_process_name(niceName); ---- >完成重命名操作
     ,4,AppRuntime runtime;----- >App_main.cpp的一个内部类,其继承AndroidRuntime.cpp
     ,5,runtime.start("com.android.internal.os.ZygoteInit",startSystemServer("startsystemserver"));

      备注:AppRuntime 作为一个内部类,在main()里调用。其完成:
      1, getClassName() ---- >运行时文件类名
      2, onVmCreated()---- >java虚拟机创建
      3, onStarted()---- >调用时加载
      4, onZygoteInit()---- >初始化虚拟机
      5, onExit()---- >退出时的操作 --------- > 上述函数基本自动调用

      接着,走进runtime.start(com.android.internal.os.ZygoteInit)。runtime来自AndroidRuntime.cpp。AndroidRuntime.cpp------ >AndroidRuntime::start(const char* className, const char* options)。frameworks\base\core\jni\AndroidRuntime.cpp。分析其start()函数:

[cpp]  view plain  copy
  1. void AndroidRuntime::start(const char* className, const char* options)  
  2. {  
  3.     ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",  
  4.             className != NULL ? className : "(unknown)");  
  5.   
  6.     blockSigpipe();  
  7.   
  8.     /* 
  9.      * 'startSystemServer == true' means runtime is obsolete and not run from 
  10.      * init.rc anymore, so we print out the boot start event here. 
  11.      */  
  12.     if (strcmp(options, "start-system-server") == 0) {  
  13.         /* track our progress through the boot sequence */  
  14.         const int LOG_BOOT_PROGRESS_START = 3000;  
  15.         LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  
  16.                        ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));  
  17.     }  
  18.   
  19.     const char* rootDir = getenv("ANDROID_ROOT");  
  20.     if (rootDir == NULL) {  
  21.         rootDir = "/system";  
  22.         if (!hasDir("/system")) {  
  23.             LOG_FATAL("No root directory specified, and /android does not exist.");  
  24.             return;  
  25.         }  
  26.         setenv("ANDROID_ROOT", rootDir, 1);  
  27.     }  
  28.   
  29.     //const char* kernelHack = getenv("LD_ASSUME_KERNEL");  
  30.     //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);  
  31.   
  32.     /* start the virtual machine */  
  33.     JNIEnv* env;  
  34.     if (startVm(&mJavaVM, &env) != 0) {  
  35.         return;  
  36.     }  
  37.     onVmCreated(env);  
  38.   
  39.     /* 
  40.      * Register android functions. 
  41.      */  
  42.     if (startReg(env) < 0) {  
  43.         ALOGE("Unable to register all android natives\n");  
  44.         return;  
  45.     }  
  46.   
  47.     /* 
  48.      * We want to call main() with a String array with arguments in it. 
  49.      * At present we have two arguments, the class name and an option string. 
  50.      * Create an array to hold them. 
  51.      */  
  52.     jclass stringClass;  
  53.     jobjectArray strArray;  
  54.     jstring classNameStr;  
  55.     jstring optionsStr;  
  56.   
  57.     stringClass = env->FindClass("java/lang/String");  
  58.     assert(stringClass != NULL);  
  59.     strArray = env->NewObjectArray(2, stringClass, NULL);  
  60.     assert(strArray != NULL);  
  61.     classNameStr = env->NewStringUTF(className);  
  62.     assert(classNameStr != NULL);  
  63.     env->SetObjectArrayElement(strArray, 0, classNameStr);  
  64.     optionsStr = env->NewStringUTF(options);  
  65.     env->SetObjectArrayElement(strArray, 1, optionsStr);  
  66.   
  67.     /* 
  68.      * Start VM.  This thread becomes the main thread of the VM, and will 
  69.      * not return until the VM exits. 
  70.      */  
  71.     char* slashClassName = toSlashClassName(className);  
  72.     jclass startClass = env->FindClass(slashClassName);  
  73.     if (startClass == NULL) {  
  74.         ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);  
  75.         /* keep going */  
  76.     } else {  
  77.         jmethodID startMeth = env->GetStaticMethodID(startClass, "main",  
  78.             "([Ljava/lang/String;)V");  
  79.         if (startMeth == NULL) {  
  80.             ALOGE("JavaVM unable to find main() in '%s'\n", className);  
  81.             /* keep going */  
  82.         } else {  
  83.             env->CallStaticVoidMethod(startClass, startMeth, strArray);  
  84.   
  85. #if 0  
  86.             if (env->ExceptionCheck())  
  87.                 threadExitUncaughtException(env);  
  88. #endif  
  89.         }  
  90.     }  
  91.     free(slashClassName);  
  92.   
  93.     ALOGD("Shutting down VM\n");  
  94.     if (mJavaVM->DetachCurrentThread() != JNI_OK)  
  95.         ALOGW("Warning: unable to detach main thread\n");  
  96.     if (mJavaVM->DestroyJavaVM() != 0)  
  97.         ALOGW("Warning: VM did not shut down cleanly\n");  
  98. }  


      该函数完成操作:
      1, onVmCreated(env);----- >创建虚拟机
      2, JNIEnv* env; ---- > JNI环境的初始化
      3, env->CallStaticVoidMethod(startClass, startMeth, strArray); ----- >最终函数与上述步骤中的runtime.start(com.android.internal.os.ZygoteInit)对应。
      4, 至此走到---- ZygoteInit.java----main()

      ZygoteInit.java ---main()----- >java世界准备已经完成,欢迎来到java世界。

[java]  view plain  copy
  1. public static void main(String argv[]) {  
  2.     try {  
  3.         // Start profiling the zygote initialization.  
  4.         SamplingProfilerIntegration.start();  
  5.   
  6.         registerZygoteSocket();  
  7.         EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,  
  8.             SystemClock.uptimeMillis());  
  9.         preload();  
  10.         EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,  
  11.             SystemClock.uptimeMillis());  
  12.   
  13.         // Finish profiling the zygote initialization.  
  14.         SamplingProfilerIntegration.writeZygoteSnapshot();  
  15.   
  16.         // Do an initial gc to clean up after startup  
  17.         gc();  
  18.   
  19.         // If requested, start system server directly from Zygote  
  20.         if (argv.length != 2) {  
  21.             throw new RuntimeException(argv[0] + USAGE_STRING);  
  22.         }  
  23.   
  24.         if (argv[1].equals("start-system-server")) {  
  25.             startSystemServer();  
  26.         } else if (!argv[1].equals("")) {  
  27.             throw new RuntimeException(argv[0] + USAGE_STRING);  
  28.         }  
  29.   
  30.         Log.i(TAG, "Accepting command socket connections");  
  31.   
  32.         if (ZYGOTE_FORK_MODE) {  
  33.             runForkMode();  
  34.         } else {  
  35.             runSelectLoopMode();  
  36.         }  
  37.   
  38.         closeServerSocket();  
  39.     } catch (MethodAndArgsCaller caller) {  
  40.         caller.run();  
  41.     } catch (RuntimeException ex) {  
  42.         Log.e(TAG, "Zygote died with exception", ex);  
  43.         closeServerSocket();  
  44.         throw ex;  
  45.     }  
  46. }  


      该函数重点完成如下3项工作:

      1, registerZygoteSocket();
      2, startSystemServer();----- > 核心方法,Zygote进程一分为二,此处分裂出一个system_server进程。
      3, 至此system_server进程进入SystemServer.java---- >main()

      先看下startSystemServer()方法:

[java]  view plain  copy
  1. private static boolean startSystemServer()  
  2.           throws MethodAndArgsCaller, RuntimeException {  
  3.       /* Hardcoded command line to start the system server */  
  4.       String args[] = {  
  5.           "--setuid=1000",  
  6.           "--setgid=1000",  
  7.           "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",  
  8.           "--capabilities=130104352,130104352",  
  9.           "--runtime-init",  
  10.           "--nice-name=system_server",  
  11.           "com.android.server.SystemServer",  
  12.       };  
  13.       ZygoteConnection.Arguments parsedArgs = null;  
  14.   
  15.       int pid;  
  16.   
  17.       try {  
  18.           parsedArgs = new ZygoteConnection.Arguments(args);  
  19.           ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);  
  20.           ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);  
  21.   
  22.           /* Request to fork the system server process */  
  23.           pid = Zygote.forkSystemServer(  
  24.                   parsedArgs.uid, parsedArgs.gid,  
  25.                   parsedArgs.gids,  
  26.                   parsedArgs.debugFlags,  
  27.                   null,  
  28.                   parsedArgs.permittedCapabilities,  
  29.                   parsedArgs.effectiveCapabilities);  
  30.       } catch (IllegalArgumentException ex) {  
  31.           throw new RuntimeException(ex);  
  32.       }  
  33.   
  34.       /* For child process */  
  35.       if (pid == 0) {  
  36.           handleSystemServerProcess(parsedArgs);  
  37.       }  
  38.   
  39.       return true;  
  40.   }  

      com.android.server.SystemServer的创建,预示着SystemServer的的正式启动,自此Zygote一分为二。Zygote将系统服务交给SystemServer统一管理。而zygote则负责java运行时环境和Dalvik虚拟机的管理工作。

4.3,systemserver启动

      system_server进程是android的第二大进程,其余zygote紧密联系,若其中任何一个进程死掉,就会导致系统死掉,其启动过程包含两个阶段Main()----- >init1()和init2()。
Init1(),为system_server的第一阶段SystemServer.java--- >Init1()的本地实现在com_android_server_SystemServer.cpp中。

      先看frameworks\base\services\java\com\android\server\SystemServer.java的main()函数。

[java]  view plain  copy
  1. native public static void init1(String[] args);  
  2.   
  3. public static void main(String[] args) {  
  4.     if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {  
  5.         // If a device's clock is before 1970 (before 0), a lot of  
  6.         // APIs crash dealing with negative numbers, notably  
  7.         // java.io.File#setLastModified, so instead we fake it and  
  8.         // hope that time from cell towers or NTP fixes it  
  9.         // shortly.  
  10.         Slog.w(TAG, "System clock is before 1970; setting to 1970.");  
  11.         SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);  
  12.     }  
  13.   
  14.     if (SamplingProfilerIntegration.isEnabled()) {  
  15.         SamplingProfilerIntegration.start();  
  16.         timer = new Timer();  
  17.         timer.schedule(new TimerTask() {  
  18.             @Override  
  19.             public void run() {  
  20.                 SamplingProfilerIntegration.writeSnapshot("system_server"null);  
  21.             }  
  22.         }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);  
  23.     }  
  24.   
  25.     // Mmmmmm... more memory!  
  26.     dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();  
  27.   
  28.     // The system server has to run all of the time, so it needs to be  
  29.     // as efficient as possible with its memory usage.  
  30.     VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);  
  31.   
  32.     System.loadLibrary("android_servers");  
  33.     init1(args);  
  34. }  
  35.   
  36. public static final void init2() {  
  37.     Slog.i(TAG, "Entered the Android system server!");  
  38.     Thread thr = new ServerThread();  
  39.     thr.setName("android.server.ServerThread");  
  40.     thr.start();  
  41. }  


      其中init1()的本地实现在com_android_server_SystemServer.cpp中:

[java]  view plain  copy
  1. static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)  
  2. {  
  3.     system_init();  
  4. }  


      system_init()在frameworks\base\cmds\system_server\library\system_init.cpp中:

[cpp]  view plain  copy
  1. extern "C" status_t system_init()  
  2. {  
  3.     ALOGI("Entered system_init()");  
  4.   
  5.     sp<ProcessState> proc(ProcessState::self());  
  6.   
  7.     sp<IServiceManager> sm = defaultServiceManager();  
  8.     ALOGI("ServiceManager: %p\n", sm.get());  
  9.   
  10.     sp<GrimReaper> grim = new GrimReaper();  
  11.     sm->asBinder()->linkToDeath(grim, grim.get(), 0);  
  12.   
  13.     char propBuf[PROPERTY_VALUE_MAX];  
  14.     property_get("system_init.startsurfaceflinger", propBuf, "1");  
  15.     if (strcmp(propBuf, "1") == 0) {  
  16.         // Start the SurfaceFlinger  
  17.         SurfaceFlinger::instantiate();  
  18.     }  
  19.   
  20.     property_get("system_init.startsensorservice", propBuf, "1");  
  21.     if (strcmp(propBuf, "1") == 0) {  
  22.         // Start the sensor service  
  23.         SensorService::instantiate();  
  24.     }  
  25.   
  26.     // And now start the Android runtime.  We have to do this bit  
  27.     // of nastiness because the Android runtime initialization requires  
  28.     // some of the core system services to already be started.  
  29.     // All other servers should just start the Android runtime at  
  30.     // the beginning of their processes's main(), before calling  
  31.     // the init function.  
  32.     ALOGI("System server: starting Android runtime.\n");  
  33.     AndroidRuntime* runtime = AndroidRuntime::getRuntime();  
  34.   
  35.     ALOGI("System server: starting Android services.\n");  
  36.     JNIEnv* env = runtime->getJNIEnv();  
  37.     if (env == NULL) {  
  38.         return UNKNOWN_ERROR;  
  39.     }  
  40.     jclass clazz = env->FindClass("com/android/server/SystemServer");  
  41.     if (clazz == NULL) {  
  42.         return UNKNOWN_ERROR;  
  43.     }  
  44.     jmethodID methodId = env->GetStaticMethodID(clazz, "init2""()V");  
  45.     if (methodId == NULL) {  
  46.         return UNKNOWN_ERROR;  
  47.     }  
  48.     env->CallStaticVoidMethod(clazz, methodId);  
  49.   
  50.     ALOGI("System server: entering thread pool.\n");  
  51.     ProcessState::self()->startThreadPool();  
  52.     IPCThreadState::self()->joinThreadPool();  
  53.     ALOGI("System server: exiting thread pool.\n");  
  54.   
  55.     return NO_ERROR;  
  56. }  

      再回到SystemServer.java的main()中的init2():init2()将操作交给了内部类ServerThread处理,看起run()函数:

[java]  view plain  copy
  1.    public void run() {  
  2.        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,  
  3.            SystemClock.uptimeMillis());  
  4.   
  5.        Looper.prepare();  
  6.   
  7.        android.os.Process.setThreadPriority(  
  8.                android.os.Process.THREAD_PRIORITY_FOREGROUND);  
  9.   
  10. .......  
  11.   
  12.   
  13.        AccountManagerService accountManager = null;  
  14.        ContentService contentService = null;  
  15.        LightsService lights = null;  
  16.        PowerManagerService power = null;  
  17.        BatteryService battery = null;  
  18.        VibratorService vibrator = null;  
  19.        AlarmManagerService alarm = null;  
  20.        NetworkManagementService networkManagement = null;  
  21.        NetworkStatsService networkStats = null;  
  22.        NetworkPolicyManagerService networkPolicy = null;  
  23.        ConnectivityService connectivity = null;  
  24.        WifiP2pService wifiP2p = null;  
  25.        WifiService wifi = null;  
  26.        NsdService serviceDiscovery= null;  
  27.        IPackageManager pm = null;  
  28.        Context context = null;  
  29.        WindowManagerService wm = null;  
  30.        BluetoothService bluetooth = null;  
  31.        BluetoothA2dpService bluetoothA2dp = null;  
  32.        DockObserver dock = null;  
  33.        UsbService usb = null;  
  34.        SerialService serial = null;  
  35.        UiModeManagerService uiMode = null;  
  36.        RecognitionManagerService recognition = null;  
  37.        ThrottleService throttle = null;  
  38.        NetworkTimeUpdateService networkTimeUpdater = null;  
  39.        CommonTimeManagementService commonTimeMgmtService = null;  
  40.        InputManagerService inputManager = null;  
  41.   
  42.        //Bug#185069 fix low storage ,check the space&delete the temp file weather need.  
  43.        DeviceStorageMonitorService.freeSpace();  
  44.          
  45.        .......  
  46.        ServiceManager.addService("xxx",XXX);  
  47.        .......  
  48.   
  49.        DevicePolicyManagerService devicePolicy = null;  
  50.        StatusBarManagerService statusBar = null;  
  51.        InputMethodManagerService imm = null;  
  52.        AppWidgetService appWidget = null;  
  53.        NotificationManagerService notification = null;  
  54.        WallpaperManagerService wallpaper = null;  
  55.        LocationManagerService location = null;  
  56.        CountryDetectorService countryDetector = null;  
  57.        TextServicesManagerService tsms = null;  
  58.        LockSettingsService lockSettings = null;  
  59.        DreamManagerService dreamy = null;  
  60.   
  61. ......  
  62.   
  63.        // These are needed to propagate to the runnable below.  
  64.        final Context contextF = context;  
  65.        final BatteryService batteryF = battery;  
  66.        final NetworkManagementService networkManagementF = networkManagement;  
  67.        final NetworkStatsService networkStatsF = networkStats;  
  68.        final NetworkPolicyManagerService networkPolicyF = networkPolicy;  
  69.        final ConnectivityService connectivityF = connectivity;  
  70.        final DockObserver dockF = dock;  
  71.        final UsbService usbF = usb;  
  72.        final ThrottleService throttleF = throttle;  
  73.        final UiModeManagerService uiModeF = uiMode;  
  74.        final AppWidgetService appWidgetF = appWidget;  
  75.        final WallpaperManagerService wallpaperF = wallpaper;  
  76.        final InputMethodManagerService immF = imm;  
  77.        final RecognitionManagerService recognitionF = recognition;  
  78.        final LocationManagerService locationF = location;  
  79.        final CountryDetectorService countryDetectorF = countryDetector;  
  80.        final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;  
  81.        final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;  
  82.        final TextServicesManagerService textServiceManagerServiceF = tsms;  
  83.        final StatusBarManagerService statusBarF = statusBar;  
  84.        final DreamManagerService dreamyF = dreamy;  
  85.        final InputManagerService inputManagerF = inputManager;  
  86.        final BluetoothService bluetoothF = bluetooth;  
  87.   
  88.   
  89.        ActivityManagerService.self().systemReady(new Runnable() {  
  90.            public void run() {  
  91.                Slog.i(TAG, "Making services ready");  
  92.   
  93.                if (!headless) startSystemUi(contextF);  
  94.                try {  
  95.                    if (batteryF != null) batteryF.systemReady();  
  96.                } catch (Throwable e) {  
  97.                    reportWtf("making Battery Service ready", e);  
  98.                }  
  99.                try {  
  100.                    if (networkManagementF != null) networkManagementF.systemReady();  
  101.                } catch (Throwable e) {  
  102.                    reportWtf("making Network Managment Service ready", e);  
  103.                }  
  104.                try {  
  105.                    if (networkStatsF != null) networkStatsF.systemReady();  
  106.                } catch (Throwable e) {  
  107.                    reportWtf("making Network Stats Service ready", e);  
  108.                }  
  109.                try {  
  110.                    if (networkPolicyF != null) networkPolicyF.systemReady();  
  111.                } catch (Throwable e) {  
  112.                    reportWtf("making Network Policy Service ready", e);  
  113.                }  
  114.                try {  
  115.                    if (connectivityF != null) connectivityF.systemReady();  
  116.                } catch (Throwable e) {  
  117.                    reportWtf("making Connectivity Service ready", e);  
  118.                }  
  119.                try {  
  120.                    if (dockF != null) dockF.systemReady();  
  121.                } catch (Throwable e) {  
  122.                    reportWtf("making Dock Service ready", e);  
  123.                }  
  124.                try {  
  125.                    if (usbF != null) usbF.systemReady();  
  126.                } catch (Throwable e) {  
  127.                    reportWtf("making USB Service ready", e);  
  128.                }  
  129.                try {  
  130.                    if (uiModeF != null) uiModeF.systemReady();  
  131.                } catch (Throwable e) {  
  132.                    reportWtf("making UI Mode Service ready", e);  
  133.                }  
  134.                try {  
  135.                    if (recognitionF != null) recognitionF.systemReady();  
  136.                } catch (Throwable e) {  
  137.                    reportWtf("making Recognition Service ready", e);  
  138.                }  
  139.                Watchdog.getInstance().start();  
  140.   
  141.                // It is now okay to let the various system services start their  
  142.                // third party code...  
  143.   
  144.                try {  
  145.                    if (appWidgetF != null) appWidgetF.systemReady(safeMode);  
  146.                } catch (Throwable e) {  
  147.                    reportWtf("making App Widget Service ready", e);  
  148.                }  
  149.                try {  
  150.                    if (wallpaperF != null) wallpaperF.systemReady();  
  151.                } catch (Throwable e) {  
  152.                    reportWtf("making Wallpaper Service ready", e);  
  153.                }  
  154.                try {  
  155.                    if (immF != null) immF.systemReady(statusBarF);  
  156.                } catch (Throwable e) {  
  157.                    reportWtf("making Input Method Service ready", e);  
  158.                }  
  159.                try {  
  160.                    if (locationF != null) locationF.systemReady();  
  161.                } catch (Throwable e) {  
  162.                    reportWtf("making Location Service ready", e);  
  163.                }  
  164.                try {  
  165.                    if (countryDetectorF != null) countryDetectorF.systemReady();  
  166.                } catch (Throwable e) {  
  167.                    reportWtf("making Country Detector Service ready", e);  
  168.                }  
  169.                try {  
  170.                    if (throttleF != null) throttleF.systemReady();  
  171.                } catch (Throwable e) {  
  172.                    reportWtf("making Throttle Service ready", e);  
  173.                }  
  174.                try {  
  175.                    if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();  
  176.                } catch (Throwable e) {  
  177.                    reportWtf("making Network Time Service ready", e);  
  178.                }  
  179.                try {  
  180.                    if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemReady();  
  181.                } catch (Throwable e) {  
  182.                    reportWtf("making Common time management service ready", e);  
  183.                }  
  184.                try {  
  185.                    if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();  
  186.                } catch (Throwable e) {  
  187.                    reportWtf("making Text Services Manager Service ready", e);  
  188.                }  
  189.                try {  
  190.                    if (dreamyF != null) dreamyF.systemReady();  
  191.                } catch (Throwable e) {  
  192.                    reportWtf("making DreamManagerService ready", e);  
  193.                }  
  194.                try {  
  195.                    if (inputManagerF != null) inputManagerF.systemReady(bluetoothF);  
  196.                } catch (Throwable e) {  
  197.                    reportWtf("making InputManagerService ready", e);  
  198.                }  
  199.            }  
  200.        });  
  201.   
  202.        //PowerManagerServer WakeLock dump thread  
  203.        (new Thread(new WakelockMonitor(power))).start();  
  204.   
  205. ......  
  206.   
  207.        Looper.loop();  
  208.        Slog.d(TAG, "System ServerThread is exiting!");  
  209.    }  

      该函数有3个重要功能:

      1,ServiceManager.addService("xxx",XXX),将系统服务注册进去。

      2,systemReady(),告诉已经实现该接口servers,系统已经启动OK。

      3,WakelockMonitor的启动。

      至此,systemserver的启动工作已经完成。

4.4,launcher启动

      桌面launcher即Home:
      1)源码:ActivityManagerService.java为入口,packages/apps/launcher*实现
      2)说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用startHomeActivityLocked()启动launcher。Home在((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady(.)。函数调用的过程中启动,其中systemReady()的参数是一段callback代码,如上面灰色显示的部分。这个函数的实现部分在文件:ActivityManagerService.java中。

      先看ActivityManagerService.java的systemReady():

[java]  view plain  copy
  1. public void systemReady(final Runnable goingCallback) {  
  2.   
  3. ..  
  4.   
  5.     retrieveSettings();  
  6.   
  7.     if (goingCallback != null) goingCallback.run();  
  8.       
  9.     synchronized (this) {  
  10.         if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {  
  11.             try {  
  12.                 List apps = AppGlobals.getPackageManager().  
  13.                     getPersistentApplications(STOCK_PM_FLAGS);  
  14.                 if (apps != null) {  
  15.                     int N = apps.size();  
  16.                     int i;  
  17.                     for (i=0; i<N; i++) {  
  18.                         ApplicationInfo info  
  19.                             = (ApplicationInfo)apps.get(i);  
  20.                         if (info != null &&  
  21.                                 !info.packageName.equals("android")) {  
  22.                             addAppLocked(info, false);  
  23.                         }  
  24.                     }  
  25.                 }  
  26.             } catch (RemoteException ex) {  
  27.                 // pm is in same process, this will never happen.  
  28.             }  
  29.         }  
  30.   
  31.         // Start up initial activity.  
  32.         mBooting = true;  
  33.           
  34.         try {  
  35.             if (AppGlobals.getPackageManager().hasSystemUidErrors()) {  
  36.                 Message msg = Message.obtain();  
  37.                 msg.what = SHOW_UID_ERROR_MSG;  
  38.                 mHandler.sendMessage(msg);  
  39.             }  
  40.         } catch (RemoteException e) {  
  41.         }  
  42.   
  43.         mMainStack.resumeTopActivityLocked(null);  
  44.     }  
  45. }  

      跳转至launcher的操作由resumeTopActivityLocked()完成,其实现在ActivityStack.java里的resumeTopActivityLocked()。

[java]  view plain  copy
  1. final ActivityManagerService mService;  
  2. final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {  
  3.     // Find the first activity that is not finishing.  
  4.     ActivityRecord next = topRunningActivityLocked(null);  
  5.   
  6.     // Remember how we'll process this pause/resume situation, and ensure  
  7.     // that the state is reset however we wind up proceeding.  
  8.     final boolean userLeaving = mUserLeaving;  
  9.     mUserLeaving = false;  
  10.   
  11.     if (next == null) {  
  12.         // There are no more activities!  Let's just start up the  
  13.         // Launcher...  
  14.         if (mMainStack) {  
  15.             ActivityOptions.abort(options);  
  16.             return mService.startHomeActivityLocked(0);  
  17.         }  
  18.     }  

      从上述代码可以看出其实是走到了mService.startHomeActivityLocked(0),而这里的mService也就是ActivityManagerService.java,再次回到ActivityManagerService.java的startHomeActivityLocked(0),至此launcher启动完成。

4.5,lockscreen启动


      源码:frameworks/policies/base/phone/com/android/internal/policy/impl/*lock*
      说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置。此处不再详细分析。

      frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java的systemReady()方法:

[java]  view plain  copy
  1. /** {@inheritDoc} */  
  2. public void systemReady() {  
  3.     if (mKeyguardMediator != null) {  
  4.         // tell the keyguard  
  5.         mKeyguardMediator.onSystemReady();  
  6.     }  
  7.     synchronized (mLock) {  
  8.         updateOrientationListenerLp();  
  9.         mSystemReady = true;  
  10.         mHandler.post(new Runnable() {  
  11.             public void run() {  
  12.                 updateSettings();  
  13.             }  
  14.         });  
  15.     }  
  16. }  


      第一步,告诉锁屏控制器,系统已经启动完成,接下来有锁屏处理。 frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardViewMediator.java:

[java]  view plain  copy
  1. public void onSystemReady() {  
  2.     synchronized (this) {  
  3.         if (DEBUG) Log.d(TAG, "onSystemReady");  
  4.         mSystemReady = true;  
  5.         doKeyguardLocked();  
  6.     }  
  7. }  


      再看其doKeyguardLocked()方法:

[java]  view plain  copy
  1. private void doKeyguardLocked() {  
  2.   
  3.   
  4.     if(engModeFlag){  
  5.         Log.d(TAG, "show engmode!");  
  6.         engModeFlag = false;  
  7.         return ;  
  8.     }  
  9.   
  10.     // if another app is disabling us, don't show  
  11.     if (!mExternallyEnabled) {  
  12.         if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");  
  13.   
  14.         // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes  
  15.         // for an occasional ugly flicker in this situation:  
  16.         // 1) receive a call with the screen on (no keyguard) or make a call  
  17.         // 2) screen times out  
  18.         // 3) user hits key to turn screen back on  
  19.         // instead, we reenable the keyguard when we know the screen is off and the call  
  20.         // ends (see the broadcast receiver below)  
  21.         // TODO: clean this up when we have better support at the window manager level  
  22.         // for apps that wish to be on top of the keyguard  
  23.         return;  
  24.     }  
  25.   
  26.     // if the keyguard is already showing, don't bother  
  27.     if (mKeyguardViewManager.isShowing()) {  
  28.         if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");  
  29.         return;  
  30.     }  
  31.   
  32.     final boolean provisioned = mUpdateMonitor.isDeviceProvisioned();  
  33.     final boolean lockedOrMissing = isSimLockedOrMissing();  
  34.   
  35.     if (!lockedOrMissing && !provisioned) {  
  36.         if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"  
  37.                 + " and the sim is not locked or missing");  
  38.         return;  
  39.     }  
  40.   
  41.     if (mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) {  
  42.         if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");  
  43.         return;  
  44.     }  
  45.   
  46.     if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");  
  47.     showLocked();  
  48. }  

       至此,锁屏启动完成。

4.6,othersapps启动

       系统启动完成后,launcher会加载系统已经安装的apk,并显示在launcher上。

       至此,android启动完成。

5,android启动动画效果剖析

       在android启动的过程中我们通常可以看到若干个启动画面,均代表着不同的启动阶段,接下来根据启动阶段分析启动画面。

       uboot启动:会有一帧 uboot logo。

       kernel启动:会有一帧kernel logo。(默认不显示,其控制宏是默认关闭的)

       android启动:会有一帧静态图片+一个闪动的图片序列(即开机动画)。

       通常情况下,我们在分析android的开机动画效果时,很少去分析uboot logo和kernel logo,因为ubootlogo 属于uboot阶段,kernel logo 属于linux范围。正常情况下,我们在down版本,烧到手机里去时,会吧logo.bmp加进去,这是系统的处理是:uboot logo,kernel logo,android static logo是同一张图片,即我们加的logo.bmp。

       双framebuffer显示logo机制分析:本来一直走的是一级logo显示,从uboot logo一直持续到系统动画,但考虑期间时间偏长,欲采用标准三级logo。1、uboot logo  2、kernle logo 3 initlogo.rle 最后动画bootanimation.zip。但是kernel 对framebuffer修改较大,故考虑在uboot开始和结束显示两张logo(第二幅logo显示调用在theKernel()跳入内核函数之前),kernel跳过。uboot 直接刷屏显示第二幅logo 动作过慢,效果不佳,经考虑采用双buffer策略。思路:

       1.原来只要显示一张uboot logo :把nand 中boot.logo 拷贝至lcd_base+fbsize处,然后搬至lcd_base显示;
       2.现在创建第二个framebuffer于lcd_base+2*fbsize处,在显示第二幅logo前把nand 中第二幅logo 仍然拷贝至lcd_base+fbsize处,然后搬至lcd_base+2*fbsize第二个framebuffer基地址;
       3.把第二个framebuffer基地址告诉lcd 控制寄存器,更新framebuffer基地址;
       4.但在kernel中,寄存器仍然会指向第一个framebuffer基地址,那么第二幅logo显示犹如昙花一现啊,不过这个问题好解决,既然第二幅logo已经搬进了第二个framebuffer那,那么只要在进入内核前做一个memcpy就好了。
       注:logo是bmp格式,在拷贝前需要进行相应的解析,参考uboot给的解析代码,自定义函数。

5.1,uboot logo

       以正常模式启动分析uboot logo。即normal_mode.c根据前部分的分析可知,流程会走至normal_nand_mode.c的vlx_nand_boot()函数。

[cpp]  view plain  copy
  1. //读取下载到nand中的boot_logo,就是开机亮的那一屏  
  2.    off=part->offset;  
  3.    nand = &nand_info[dev->id->num];  
  4.    //read boot image header  
  5.    size = 1<<19;//where the size come from????//和dowload工具中的地址一致  
  6.    char * bmp_img = malloc(size);  
  7.    if(!bmp_img){  
  8.        printf("not enough memory for splash image\n");  
  9.        return;  
  10.    }  
  11.    ret = nand_read_offset_ret(nand, off, &size, (void *)bmp_img, &off);  
  12.    if(ret != 0){  
  13.        printf("function: %s nand read error %d\n", __FUNCTION__, ret);  
  14.        return;  
  15.    }  
  16.    //第一次LCD logo  
  17.    lcd_display_logo(backlight_set,(ulong)bmp_img,size);  

       即由lcd_display_logo()完成相关操作。该函数在normal_mode.c中定义。

[cpp]  view plain  copy
  1. void lcd_display_logo(int backlight_set,ulong bmp_img,size_t size)  
  2. {  
  3. #ifdef CONFIG_SPLASH_SCREEN  
  4.     extern int lcd_display_bitmap(ulong bmp_image, int x, int y);  
  5.     extern void lcd_display(void);  
  6.     extern void *lcd_base;  
  7.     extern void Dcache_CleanRegion(unsigned int addr, unsigned int length);  
  8.     extern void set_backlight(uint32_t value);  
  9.     if(backlight_set == BACKLIGHT_ON){  
  10.         lcd_display_bitmap((ulong)bmp_img, 0, 0);  
  11. #if defined(CONFIG_SC8810) || defined(CONFIG_SC8825) || defined(CONFIG_SC8830)  
  12.         Dcache_CleanRegion((unsigned int)(lcd_base), size);//Size is to large.  
  13. #endif  
  14.         lcd_display();  
  15.         set_backlight(255);  
  16.     }else{  
  17.         memset((unsigned int)lcd_base, 0, size);  
  18. #if defined(CONFIG_SC8810) || defined(CONFIG_SC8825) || defined(CONFIG_SC8830)  
  19.         Dcache_CleanRegion((unsigned int)(lcd_base), size);//Size is to large.  
  20. #endif  
  21.         lcd_display();  
  22.     }  
  23. #endif  
  24. }  

5.2,kernel logo

       kernel logo 属于linux系统自带的logo机制,由于在android平台其显示默认是关闭的,此处不做多的分析,详细可参考博文:Android系统的开机画面显示过程分析 ,该博文只分析了启动过程的 kernel logo,android logo anim。

       相关代码: 
       /kernel/drivers/video/fbmem.c 
       /kernel/drivers/video/logo/logo.c 
       /kernel/drivers/video/logo/Kconfig 
       /kernel/include/linux/linux_logo.h

[cpp]  view plain  copy
  1. static int nologo;   
  2. module_param(nologo, bool, 0);   
  3. MODULE_PARM_DESC(nologo, "Disables startup logo");   
  4. /* logo's are marked __initdata. Use __init_refok to tell  
  5. * modpost that it is intended that this function uses data  
  6. * marked __initdata.  
  7. */   
  8. const struct linux_logo * __init_refok fb_find_logo(int depth)   
  9. {   
  10. const struct linux_logo *logo = NULL;   
  11. if (nologo)   
  12. return NULL;   
  13.     ......   
  14. }   

5.3,android logo anim 

       Android 系统启动后,init.c中main()调用queue_builtin_action(console_init_action, "console_init")时会根据console_init_action函数调用load_565rle_image()函数读取/initlogo.rle(一张565 rle压缩的位图),如果读取成功,则在/dev/graphics/fb0显示Logo图片;如果读取失败,则将/dev/tty0设为TEXT模式, 并打开/dev/tty0,输出文本“A N D R I O D”字样。

 

[cpp]  view plain  copy
  1. static int console_init_action(int nargs, char **args)  
  2. {  
  3.     int fd;  
  4.     char tmp[PROP_VALUE_MAX];  
  5.   
  6.     if (console[0]) {  
  7.         snprintf(tmp, sizeof(tmp), "/dev/%s", console);  
  8.         console_name = strdup(tmp);  
  9.     }  
  10.   
  11.     fd = open(console_name, O_RDWR);  
  12.     if (fd >= 0)  
  13.         have_console = 1;  
  14.     close(fd);  
  15.   
  16.     if( load_565rle_image(INIT_IMAGE_FILE) ) {  
  17.         fd = open("/dev/tty0", O_WRONLY);  
  18.         if (fd >= 0) {  
  19.             const char *msg;  
  20.                 msg = "\n"  
  21.             "\n"  
  22.             "\n"  
  23.             "\n"  
  24.             "\n"  
  25.             "\n"  
  26.             "\n"  // console is 40 cols x 30 lines  
  27.             "\n"  
  28.             "\n"  
  29.             "\n"  
  30.             "\n"  
  31.             "\n"  
  32.             "\n"  
  33.             "\n"  
  34.             "             A N D R O I D ";  
  35.             write(fd, msg, strlen(msg));  
  36.             close(fd);  
  37.         }  
  38.     }  
  39.     return 0;  
  40. }  


       由此调用logo.c 的load_565rle_image()函数。

[cpp]  view plain  copy
  1. int load_565rle_image(char *fn)  
  2. {  
  3.     struct FB fb;  
  4.     struct stat s;  
  5.     unsigned short *data, *bits, *ptr;  
  6.     unsigned count, max;  
  7.     int fd;  
  8.   
  9.     if (vt_set_mode(1))   
  10.         return -1;  
  11.   
  12.     fd = open(fn, O_RDONLY);  
  13.     if (fd < 0) {  
  14.         ERROR("cannot open '%s'\n", fn);  
  15.         goto fail_restore_text;  
  16.     }  
  17.   
  18.     if (fstat(fd, &s) < 0) {  
  19.         goto fail_close_file;  
  20.     }  
  21.   
  22.     data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);  
  23.     if (data == MAP_FAILED)  
  24.         goto fail_close_file;  
  25.   
  26.     if (fb_open(&fb))  
  27.         goto fail_unmap_data;  
  28.   
  29.     max = fb_width(&fb) * fb_height(&fb);  
  30.     ptr = data;  
  31.     count = s.st_size;  
  32.     bits = fb.bits;  
  33.     while (count > 3) {  
  34.         unsigned n = ptr[0];  
  35.         if (n > max)  
  36.             break;  
  37.         android_memset16(bits, ptr[1], n << 1);  
  38.         bits += n;  
  39.         max -= n;  
  40.         ptr += 2;  
  41.         count -= 4;  
  42.     }  
  43.   
  44.     munmap(data, s.st_size);  
  45.     fb_update(&fb);  
  46.     fb_close(&fb);  
  47.     close(fd);  
  48.     unlink(fn);  
  49.     return 0;  
  50.   
  51. fail_unmap_data:  
  52.     munmap(data, s.st_size);      
  53. fail_close_file:  
  54.     close(fd);  
  55. fail_restore_text:  
  56.     vt_set_mode(0);  
  57.     return -1;  
  58. }  


       该图片格式是565RLE image format格式的,可用工具将bmp格式转化为rle格式。之后会有init.rc 并发开机动画。

       相关文件: 
       /frameworks/base/cmds/bootanimation/BootAnimation.h 
       /frameworks/base/cmds/bootanimation/BootAnimation.cpp 
       /frameworks/base/cmds/bootanimation/bootanimation_main.cpp 
       /system/core/init/init.c 
       /system/core/rootdir/init.rc

       init.c解析init.rc(其中定义服务:“service bootanim /system/bin/bootanimation”),bootanim 服务由SurfaceFlinger.readyToRun()(property_set("ctl.start", "bootanim");)执行开机动画、bootFinished()(property_set("ctl.stop", "bootanim");)执行停止开机动画。 BootAnimation.h和BootAnimation.cpp文件放到了/frameworks/base/cmds /bootanimation目录下了,增加了一个入口文件bootanimation_main.cpp。Android.mk文件中可以看到,将开机 动画从原来的SurfaceFlinger里提取出来了,生成可执行文件:bootanimation。Android.mk代码如下:

[cpp]  view plain  copy
  1. //=============Android.mk======================   
  2. LOCAL_PATH:= $(call my-dir)   
  3. include $(CLEAR_VARS)   
  4. LOCAL_SRC_FILES:= \   
  5.     bootanimation_main.cpp \   
  6.     BootAnimation.cpp   
  7. # need "-lrt" on Linux simulator to pick up clock_gettime   
  8. ifeq ($(TARGET_SIMULATOR),true)   
  9.     ifeq ($(HOST_OS),linux)   
  10.         LOCAL_LDLIBS += -lrt   
  11.     endif   
  12. endif   
  13. LOCAL_SHARED_LIBRARIES := \   
  14.     libcutils \   
  15.     libutils \   
  16.     libui \   
  17.     libcorecg \   
  18.     libsgl \   
  19.     libEGL \   
  20.     libGLESv1_CM \   
  21.     libmedia     
  22. LOCAL_C_INCLUDES := \   
  23.     $(call include-path-for, corecg graphics)   
  24. LOCAL_MODULE:= bootanimation   
  25. include $(BUILD_EXECUTABLE)   
  26. //==========================================   

       备注:
       1,adb shell后,可以直接运行“bootanimation”来重新看开机动画,它会一直处于动画状态,而不会停止。

       2,adb shell后,命令“setprop ctl.start bootanim”执行开机动画;命令“getprop ctl.start bootanim”停止开机动画。这两句命令分别对应SurfaceFlinger.cpp的两句语 句:property_set("ctl.start", "bootanim");和property_set("ctl.stop", "bootanim")。

       至此android启动动画分析结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值