高通平台android环境搭建,编译,系统引导流程分析

1、高通平台android开发总结

1.1 搭建高通平台环境开发环境

在高通开发板上烧录文件系统
建立高通平台开发环境
高通平台,android和 modem 编译流程分析
高通平台 7620 启动流程分析
qcril 流程分析,设置sim卡锁
python scons 语法学习
Python 语言之 scons 工具流程分析:
 

1.2 搭建高通平台环境开发环境

高通android智能平台概述
选择合适的源代码以及工具
建立 Android 开发环境(部分略)
建立 modem 开发环境
 

1.2.1 高通android智能平台概述

高通 7230 android 智能手机解决方案的软件包括两个部分
1. 以linux 操作系统为基础的 android 系统
2. 以 L4,REX为基础的 Modem 部分
在高通7系列的架构中,一个IC内部集成有两个ARM处理器,一个ARM9(或者arm11),专门负责处理通信协议,射频以及GPIO等,软件架 构采用 AMSS, 另外一个是ARM11,用来处理多媒体,上层应用,以及其他的一些任务,运行的系统是 android 系统,这两个处理器之间通过共享内存的硬件方式来进行通信。
 

1.2.1.1 什么是L4,REX,BREW,AMSS以及相互之间的关系

L4是一组计算机程序,是最初由Jochen Liedtke设计的微内核构架的操作系统内核,现在已经形成一个微内核家族。L4这个微内核系统由于其出色的性能和很小的体积而开始被计算机工业所认 知,被移植到了许多不同的硬件构架上。高通的 L4 提供了操作系统最基本的操作,是买别人的。
早期的操作系统绝大多数是 Monolithic Kernel, 意思是整个操作系统 - 包括Scheduling (调度), File system (文件系统), Networking (网络), Device driver (设备驱动程序), Memory management (存储管理), Paging(存储页面管理) - 都在内核中完成.一直到现在广泛应用的操作系统,如UNIX,Linux,和Windows还大都是monolithic kernel操作系统.但随着操作系统变得越来越复杂(现代操作系统的内核有一两百万行C程序是很常见的事情),把所有这些功能都放在内核中使设计难度迅 速增加.
微内核是一个与Monolithic Kernel相反的设计理念.它的目的是使内核缩到最小,把所有可能的功能模块移出内核.理想情况下,内核中仅留下Address Space Support(地址空间支持),IPC (Inter-Process Communication,进程间通讯),和Scheduling(调度),其他功能模块做为用户进程运行。
REX 是在 L4 之上封装的服务,是一个抢占式,多任务的RTOS,所有的任务都以task的形式存在,REX提供包括任务创建,同步,互斥,计时器,中断控制等功能的 API,这里的task实际上就是我们的线程,每个 task对应着一个线程。REX维护一个task list(双向链表),始终运行高优先级的task。products里面所有的服务包括3g协议栈等都是以task的形式跑在rex之上的。
而Brew的话是运行的环境,跟Java 有点儿类似,相当于是一个虚拟机。
AMSS――高级的移动用户软件(Advanced Mobile Subscriber Software)技术,是一种新的软件架构,是对原来软件架构 DMSS 的升级。 AMSS源代码实际上是QC BREW(Binary Runtime Environment For Wireless)平台的的底层部分,去掉了为应用程序提供接口的AEE(application execution environment)部分,高通在Dual Proc芯片上的其他平台基本上都是采用的这样的架构。
 
参考文档:
微内核操作系统及L4概述
http://wenku.baidu.com/view/90929762caaedd3383c4d311.html
MSM平台上的AMSS
http://blog.csdn.net/yili_xie/archive/2010/01/04/5129469.aspx
 

1.2.2 选择合适的源代码以及工具

要编译出可供烧写使用的镜像文件需要三部分代码:
1) 获取经过高通打补丁的 android 源代码
2) 获取高通针对不同处理器的 vendor 源代码
3) 获取 modem 源代码
 

1.2.2.1 获取经过高通打补丁的android 源代码

网址:
https://www.codeaurora.org/wiki/QAEP#Branch_Releases
https://www.codeaurora.org/xwiki/bin/QAEP/eclair
https://www.codeaurora.org/xwiki/bin/QAEP/eclair_caramel
https://www.codeaurora.org/xwiki/bin/QAEP/froyo_almond
 
目前使用的 android 分支:
Android 2.1 版本 eclair
M7630AABBQMLZA1150 msm7630 eclair            M7630AABBQMLZA1150.xml 2010年02月01日
M7630AABBQMLZA1200 msm7630 eclair        M7630AABBQMLZA1200.xml 2010年03月30日
M7630AABBQMLZA2010 msm7630 éclair            M7630AABBQMLZA2010.xml July 02, 2010
M7630AABBQMLZA1240 msm7630 eclair_caramel  M7630AABBQMLZA1240.xml 2010年05月31日
M7630AABBQMLZA1250 msm7630 eclair_caramel  M7630AABBQMLZA1250.xml 2010年06月15日
M7630AABBQMLZA1280 msm7630 eclair_caramel  M7630AABBQMLZA1280.xml 2010年08月03日 
M76XXTSNCJNLYA5340 msm7627 eclair_chocolate M76XXTSNCJNLYA5340.xml 2010年06月04
Android 2.2 版本 froyo
M7630AABBQMLZA2020 msm7630  froyo           M7630AABBQMLZA2020.xml 2010年09月01
M76XXTSNCJNLYA6050 msm7627  froyo_almond   M76XXTSNCJNLYA6050.xml 2010年10月29日
 
以下命令获取代码:
https://www.codeaurora.org/xwiki/bin/QAEP/froyo_almond
ac_root=/home/shared/qualcomm
ac_root=/mnt/shared/qualcomm/
ac_date=20101105
ac_branch=froyo_almond
build_id=M76XXTSNCJNLYA6050
ac_xml=M76XXTSNCJNLYA6050.xml
mkdir -pv $ac_root/$ac_branch-$build_id-$ac_date
cd $ac_root/$ac_branch-$build_id-$ac_date
repo init -u git://codeaurora.org/platform/manifest.git -b $ac_branch -m  $ac_xml
nohup repo sync&

 
1.2.2.2 获取高通针对不同处理器的vendor源代码

根据选择的 Android 源代码分支不同, vendor 代码的选择也是不一样的,BUILD ID 必须一致
M7630AABBQMLZA1150 对应 HY11-VR881-5.zip
M7630AABBQMLZA1250 对应 HY11-VR881-11.zip
M7630AABBQMLZA2020 对应 HY11-N1627-3.zip   AMSS 7X30 LINUX RELEASE 2.0.20
M76XXTSNCJNLYA6050 对应 HY11-N1188-6.zip   AMSS 7X27 LINUX REL 6.0.50
vendor 代码通过有效的高通帐号登录 HYPERLINK "https://support.cdmatech.com/login/" https://support.cdmatech.com/login/ 网站获取
 

1.2.2.3 获取 modem 源代码

根据硬件配置情况,选择不同的 BUILD ID, 然后根据 BUILD ID 选择相近的源代码
modem 代码通过有效的高通帐号登录 HYPERLINK "https://support.cdmatech.com/login/" https://support.cdmatech.com/login/ 网站获取
 
BUILD ID 是一组字母的组合,如:AAABQOLYM
以下分别对各个字段进行说明:
第三个字母 A 表示 LPDDR2    #USES_LPDDR2=yes
第三个字母 B 表示 LPDDR1
第六个字母 M 表示 Multimode
第六个字母 C 表示 CDMA
第六个字母 D 表示 JCDMA      #相对于C多了:USES_UMTS=yes USES_DSHDR_JCDMA_APIS=yes
第六个字母 O 表示 UMTS only #相对于C多了:USES_UMTS=yes USES_SUPPORT_UMTS_GPS_PROTOCOLS=yes
                              #相对于C少了:USES_CDMA=yes USES_HDR=yes USES_REL_C=yes USES_CDMA2000=yes
                              #USES_EXPORT_MCCMEID=yes USES_SUPPORT_CDMA_GPS_PROTOCOLS=yes
第7,8个字母为 AZ  表示 NADN boot
第7,8个字母为 LY  表示 eMMC boot  #相对于AZ多了选项: USES_SDCC_BOOT=yes USES_HSU_MS_FD_BOOT=yes
最后一个字母为 M   表示  modem
最后一个字母为 A   表示  app
 
以上为 7x30 平台的一些规律,具体参考文档,7227 参考相应的 release note:
<<80-VR192-1_E_AMSS_Linux_Software_Users_Manual.pdf>>
第1个字母
第2个字母  F: 基于ffa参考设计 S: 基于surf的参考设计
第3个字母
第4个字母
第5个字母  K /J
K 相对于 J 多了以下选项
USES_HSU_CHG_BOOT=yes
USES_HSU_FAST_CHARGE=yes
USES_CHARGER=yes
USES_EBI1_TURBO_FFA=yes
第6个字母  O/ N / P
 
O表示只支持 UMTS(WCDMA)
------------------
USES_IPHC=yes                             
USES_PDCP=yes
USES_SUPPORT_UMTS_GPS_PROTOCOLS=yes
USES_UMTS=yes
-----------------
P表示只支持 CDMA/CDMA2000
USES_CDMA=yes
USES_CDMA2000=yes
USES_REL_C=yes
USES_SUPPORT_CDMA_GPS_PROTOCOLS=yes
USES_EXPORT_MCCMEID=yes
USES_HDR=yes
-----------------
N表示既支持 UMTS(WCDMA) 且支持 CDMA/CDMA2000
 
第7个字母
第8个字母
 
surf和ffa的区别
generally speaking surf have FPGA and don't have battery.
and FFA don't have FPGA but have battery.
msm7627_surf and msm7627_ffa and msm7627_7x_surf means different hardware reference design. please check with your hardware engineer on which qualcomm hardware reference you use and then select the right build command.
 
 
 
 
 

4.6 Build commands

To create an AMSS build, run the command script with the build ID matching the build
configuration desired. The command scripts may be executed from the build/ms subdirectory or
from the AMSS root directory using the full path to the command script as in the following
examples:
./AMSS/products/<asic>/build/ms/MSNCJNLYM.cmd – For SURF multimode build
./AMSS/products/<asic>/build/ms/MSNCJOLYM.cmd – For SURF UMTS only build
./AMSS/products/<asic>/build/ms/MSNCJPLYM.cmd – For SURF 1X only build
./AMSS/products/<asic>/build/ms/MFNCKNLYM.cmd – For FFA multimode and for reference only
 
以高通的开发板子为例,看如何选择源代码,通过 QPST 连接高通的开发板,我们可以看到他的配置信息如下:
高通 demo 版的配置情况:SURF-MSM7630 7X30A-AAABQMAZM-1200
从配置情况来看只有 HY11-N0216-3_1.2.00  HY11-N0216-4_1.2.20 满足要求
HY11-N0216-3_1.2.00/AMSS/products/7x30/build/ms/AAABQMAZM.cmd
HY11-N0216-4_1.2.20/AMSS/products/7x30/build/ms/AAABQMAZM.cmd
后期我们要跟据实际情况来选择 BUILD ID,如我们的手机的配置情况为:
LPDDR2 ,WCDMA,eMMC 启动(NAND备选),那么modem 的BUILD ID为:
AAABQOLYM 或者 AAABQOAZM
AAABQOLYM HY11-N0723-2_1.2.20/AMSS/products/7x30/build/ms/AAABQOLYM.cmd
AAABQOAZM HY11-N1122-1_1.2.20/AMSS/products/7x30/build/ms/AAABQOAZM.cmd (NABD boot 备选)
高通的Android第一人晓峰不建议我们第一次就用eMMC,而应该用Nand,目前只有HTC在用eMMC。高通在eMMC上面提供了参考代码,但是是未经过验证。终端厂商在使用过程中,一定会有很多问题需要自己解。
 
补充信息:
现在可能用到 BUILD ID 以及相应的 modem 和 vendor 源代码。
modem代码:
  BUILD ID              modem 源代码        modem镜像         说明文档
M7630AABBQMAZM1200   HY11-N0216-3.zip  HK11-N0216-3.zip  HT11-N0216-3.zip
M7630AABBQMAZM1220   HY11-N0216-4.zip  HK11-N0216-4.zip  HT11-N0216-4.zip
--
M7630AABBQMLYM1200   HY11-N0723-1.zip  HK11-N0723-1.zip  HT11-N0723-1.zip
M7630AABBQMLYM1220   HY11-N0723-2.zip  HK11-N0723-2.zip  HT11-N0723-2.zip
--
M7630AAABQCAZM1220   HY11-N1122-1.zip  HK11-N1122-1.zip  HT11-N1122-1.zip
M7630AAABQCAZM1240   HY11-N1122-2.zip  HK11-N1122-2.zip  HT11-N1122-2.zip
M7630AAABQCAZM1250   HY11-N1122-3.zip  HK11-N1122-3.zip  HT11-N1122-3.zip
M7630AAABQCAZM1260   HY11-N1122-4.zip  HK11-N1122-4.zip  HT11-N1122-4.zip
M7630AAABQCAZM1280   HY11-N1122-5.zip  HK11-N1122-5.zip  HT11-N1122-5.zip
M7630AAABQCAZM1290   HY11-N1122-6.zip  HK11-N1122-6.zip  HT11-N1122-6.zip
--
M7630AAABQMAZM1240   HY11-N1496-2.zip  HK11-N1496-2.zip  HT11-N1496-2.zip
M7630AAABQMAZM1250   HY11-N1496-3.zip  HK11-N1496-3.zip  HT11-N1496-3.zip
 
 
80-N0216-3_B_M7630AABBQMAZM1200.pdf
5.3.2.1 LPDDR1 NAND boot Multimode              AABBQMAZM.cmd
5.3.2.2 LPDDR1 eMMC boot Multimode              AABBQMLYM.cmd
5.3.2.3 LPDDR1 eMMC boot UMTS only              AABBQOLYM.cmd
5.3.2.4 LPDDR1 NAND boot JCDMA                  AABBQDAZM.cmd
5.3.2.5 LPDDR2 NAND boot Multimode              AAABQMAZM.cmd
5.3.2.6 LPDDR2 eMMC boot Multimode              AAABQMLYM.cmd
 
80-N0216-4_A_M7630AABBQMAZM1220.pdf
5.3.2 Build instructions and commands
5.3.2.1 LPDDR1 NAND boot Multimode              AABBQMAZM.cmd
5.3.2.2 LPDDR1 eMMC boot Multimode              AABBQMLYM.cmd
5.3.2.3 LPDDR1 eMMC boot UMTS only              AABBQOLYM.cmd
5.3.2.4 LPDDR1 NAND boot JCDMA                  AABBQDAZM.cmd
5.3.2.5 LPDDR2 NAND boot Multimode              AAABQMAZM.cmd
5.3.2.6 LPDDR2 eMMC boot Multimode              AAABQMLYM.cmd
5.3.2.7 LPDDR2 eMMC boot UMTS only              AAABQOLYM.cmd
5.3.2.8 LPDDR2 NAND boot C2K Only               AAABQCAZM.cmd
5.3.2.9 LPDDR1 eMMC boot C2K Only               AABBQCLYM.cmd
5.3.2.10 LPDDR2 NAND boot JCDMA                 AAABQDAZM.cmd
5.3.2.11 LPDDR2 NAND boot UMTS only             AAABQOAZM.cmd
 
 
80-N1665-1_B_M7630AAABQ_AZM1240.pdf
5.3.2 Build instructions and commands
5.3.2.1 LPDDR1/LPDDR2 eMMC boot Multimode      AABBQMLYM.cmd
5.3.2.2 LPDDR1/LPDDR2 eMMC boot UMTS only      AABBQOLYM.cmd
5.3.2.3 LPDDR1/LPDDR2 eMMC boot C2K only       AABBQCLYM.cmd
5.3.2.4 LPDDR2/LPDDR1 NAND boot Multimode      AAABQMAZM.cmd
5.3.2.5 LPDDR1/LPDDR2 NAND boot JCDMA          AABBQDAZM.cmd
5.3.2.6 LPDDR2/LPDDR1 NAND boot C2K only       AAABQCAZM.cmd
5.3.2.7 LPDDR2/LPDDR1 NAND boot UMTS only      AAABQOAZM.cmd
The same build ID will now work for LPDDR1 as well as LPDDR2.
从以上的发布信息,只有 LPDDR2 和 LPDDR1 不同的情况下可以使用同一个 build ID。
对于我们的硬件配置情况(LPDDR2 eMMC boot UMTS only) 可以使用的编译命令文件为:
AAABQOLYM.cmd  AABBQOLYM.cmd
选择 modem 代码 M7630AAABQMAZM1250  HK11-N1496-3.zip
 
如果是支持 BREW 平台,通常多下面的选项:
USES_BREW_4.0=yes
USES_BREW=yes
USES_BREW_APPMGR=yes
或者 USES_BREW_USB_HID=yes
没有 USES_DIAG_SMD_SUPPORT=yes
 
项目 PD1007
OEM/Target Equipment (FeaturePhone,Smartphone,Datacard): Smartphone
Anticipated Launch Date: April 1 2011
Target market (such as China Telecom): China Open market
Current Software (such as Q6270BKPRZL1505):  froyo-M76XXTSNCJNLYA7010
Bluetooth IC/Module (vendor name and module if support BT): BTS4025
WLAN IC/Module (vendor and module if support WLAN ):WCN1312
Chipset (such as QSC6270):MSM7227-1
RF chipset (such as RGR6240):RTR6285
PMIC chipset (such as PM7540):PM7540
WCMDA Supported Bands (900,1900,2100…. if support WCDMA):2100
CMDA Supported Bands (450,850,1900,2100… if support CDMA ):not suport
OS (Brew,BMP,Android,WM,ThinUI(no UI)…):android froyo
OS version (Android Donuts…): android froyo
 
1.2.2.3.1 高通 modem 源代码编译前的修正
从高通获取的源代码直接编译会存在一些问题,以下为可能的问题以及解决方法:
1) 为相应的脚本加上编译选项
vim ./AMSS/products/7x30/build/ms/xxxxxx.cmd
加上: BUILD_UNIX=yes
 
2) 如果编译过程出现 .pl 文件没有执行权限而退出,那么为工程下面所有的 pl 文件加上可执行属性,命令:
find ./ -name "*.pl" |xargs chmod  755
 
3) 无法找到需要的 pl 脚本解析器
vim ./AMSS/products/7x30/tools/build/depgen.pl
修改
#!/pkg/perl/5.6.1/bin/perl -w

#!/usr/bin/perl -w
 
4) 如果出现错误: "AMSS/products/7x30/core/bsp/build/data/incpathsaaabqmlym.py", line 14
IndentationError: expected an indented block
修改文件:./AMSS/products/7x30/core/bsp/build/scripts/genpaths.pl 内容:
#if ($line =~ /^# makefile \(from/)
为:
if ($line =~ /^# makefile /)
原因分析:
genpaths.pl 会对编译过程的中间信息 :
...
line=# makefile (from'incpaths.min',line 363)
line=QVPCODEC_AUDIOINC = $(QVPCODEC)/audio/inc
...
等信息进行解析,由于我们使用的是中文系统,所以以上内容变为:
line=# makefile (从'incpaths.min',行 363)
line=QVPCODEC_AUDIOINC = $(QVPCODEC)/audio/inc
所以导致:
#if ($line =~ /^# makefile \(from/) 判断条件为为 false
无法正确生成  incpathsaaabqmlym.py,python 在解析该文件的时候认为存在语法错误。
 
 
在 modem 代码 M7630AABBQMAZM2020(HY11-N2280-2.zip)中开始使用 genincpaths.py 产生
./AMSS/products/7x30/core/bsp/build/data/incpathsaaabqoazm.py 文件,所以修改文件
amend-source-code-qualcomm-modem.sh 在脚本中需要加入以下内容:
incpathsxxx_py=$PRODUCT_DIR/core/bsp/build/scripts/genincpaths.py
if test -f $incpathsxxx_py; then
    PERL=`which /usr/bin/perl`
    sed -i "s/(from//g" $incpathsxxx_py
fi
./AMSS/products/7x30/multimedia/audio/drivers/Adie/AdieCodecDb/src/DALAdieCodecDb.c
#DalAdieCodecDbInternal.h 改为:
#include "DALAdieCodecDbInternal.h"
 
5) 如果出现 make: execvp: ../../../../platform/cs/bin/cifc: Permission denied 错误,执行以下命令:
chmod -R 755 AMSS/platform/cs/bin
      install_target_pbn = env.InstallAs(
         '${L4_ROOT}/build_${TARGET_BLD_KCFG}/bootimg.pbn', target_pbn)
 
 
      target_mbn = env.MbnBuilder('${TARGET_NAME}', target_pbn, IMAGE_TYPE="amss_mbn",
         FLASH_TYPE=env['TARGET_FLASH_TYPE'])
 
      install_target_mbn = env.InstallAs('${MBN_ROOT}/amss.mbn', target_mbn)
 
 
 
因为有:
ifeq ($(USES_HW6500),yes)
    BOOT = $(SRCROOT)/drivers/boot
 
else
    ifeq ($(IMAGE), APPS_PROC)
        BOOT = $(SRCROOT)/core/api/boot/appsproc/
        APPSBL = $(BOOT)
    else
        BOOT=$(SRCROOT)/core/api/boot/
    BOOT +=$(SRCROOT)/core/api/boot/amssboot/
    endif
 
endif
且我们定义 APPS_MODEM ,所以使用的是:
BOOT=$(SRCROOT)/core/api/boot/
BOOT +=$(SRCROOT)/core/api/boot/amssboot/
 
boot_reset_handler.s 使用的是:
./AMSS/products/7x30/core/boot/amssboot/shared/src/boot_reset_handler.s
...
EXPORT  Reset_Handler
EXPORT  soft_breakpoints_enabled
Reset_Handler
    ;------------------------------------------------------------------
    ; process init - initializes the AMSS process
    ; returns the number of bytes to pop off the stack
    ;------------------------------------------------------------------
    ldr     r0, [sp]
    blx     process_init
    add     sp, sp, r0
 
soft_breakpoints_enabled ; All pages of apps code have been paged in.
    ;------------------------------------------------------------------
    ; Pop argc and argv and launch into main.  If main is compiled with
    ; thumb mode, blx will ensure that we properly change to thumb mode
    ;------------------------------------------------------------------
    ldmia   sp!, {r0}
    mov     r1, sp
    blx     main
...
 
 
./AMSS/products/7x30/core/boot/amssboot/shared/src/boot_vectors.s:49:        IMPORT  Reset_Handler
./AMSS/products/7x30/core/boot/amssboot/shared/src/boot_vectors.s:102:        DCD       Reset_Handler
 
 
 
 
./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/SConscript:102:   install_temp_adsp_mbn = env.InstallAs(adsp_mbn_path, adsp_bin_path)
./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/SConscript:108:   install_adsp_mbn = env.InstallAs('${MBN_ROOT}/adsp.mbn', ADSP_mbn)
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:193:   install_target_reloc = env.InstallAs(AMSS_RELOC, target_elf)
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:203:   install_target_pbn = env.InstallAs(BOOTING_PBN, target_pbn)
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:215:   install_quartz_constant_cmm = env.InstallAs(
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:261:   install_target_mbn = env.InstallAs("${MBN_ROOT}/amss.mbn", target_mbn)
./AMSS/products/7x30/core/bsp/coreimg/build/arm11/CoreImage.py:240:      install_target_mbn = env.InstallAs('${MBN_ROOT}/amss.mbn', target_mbn)
1.3.3.10.1  
1.3.3.11 partition规则解析
1.3.3.11.1 eMCC 启动和 NAND 启动的分区格式是不一样的,如果是 eMCC 启动,多了编译选项:
USES_SDCC_BOOT=yes USES_HSU_MS_FD_BOOT=yes
如果 USES_HSU_MS_FD_BOOT=yes
=== Compiling  boot/osbl/fd_storage_scsi.c
=== Compiling  boot/osbl/fd_storage_usb.c
如果 USES_SDCC_BOOT=yes
那么会进行 partition 规则的处理,它会覆盖掉 corebsp_build 规则阶段生成的 partition.mbn
./AMSS/products/7x30/build/ms/dmss_rules.min
-----------
   。。。
partition :
    @echo Generate partition.bin.....
    @$(GENERATE_PARTITION)
   。。。
不同 modem 版本中,GENERATE_PARTITION 的定义会不同
HY11-N0723-1_1.2.00  中为:
-------
define GENERATE_PARTITION
        @echo ------------------------------------------------------------------
        @echo Changing to Tools directory...
        @pwd
        cd $(TOOLSDIR_JSDCC); make; make genpart
endef
-------
HY11-N1496-2_1.2.40 中为:
-------
define GENERATE_PARTITION
        @echo ------------------------------------------------------------------
        @echo Changing to Tools directory...
        @pwd
        cd $(TOOLSDIR_JSDCC); make; make genpart
        perl $(TOOLSDIR_JSDCC)/partition_extract_mbr.pl 2 0 $(TOOLSDIR_JSDCC)/
        rm -f $(MBNPATH)/partition.mbn
        rm -f $(MBNPATH)/ENPRG7x30.hex
        cp -f $(TOOLSDIR_JSDCC)/partition.mbn $(MBNPATH)/
        cp -f $(MBNPATH)/MPRG7x30.hex $(MBNPATH)/ENPRG7x30.hex
        cp -f $(MBNPATH)/MPRG7x30.hex $(MBNPATH)/NPRG7x30.hex
endef
------
partition 规则主要完成以下功能:
1) 编译 ./AMSS/products/7x30/core/storage/tools/jsdcc/partition_load_pt 代码,生成 loadpt 和 msp
2) 解析 loadpt 解析 partition.xml 文件,把分区信息保存成二进制文件 partition.bin
3) 由 partition.bin 文件生成 partition.mbn,然后拷贝到 ./AMSS/products/7x30/build/ms/bin/AAABQMAZ/partition.mbn
-----
cd $(TOOLSDIR_JSDCC); make; make genpart 命令会到目录:
./AMSS/products/7x30/core/storage/tools/jsdcc/ 下执行 make; make genpart
因为有:
./AMSS/products/7x30/core/storage/tools/jsdcc/partition_load_pt/Makefile
   。。。
all:   $(TARGET_LOADPT)$(EXE) $(TARGET_MSP)$(EXE)
genpart:
    ./$(TARGET_LOADPT)$(EXE)
   。。。
所以 make 命令会生成 loadpt 和 mps
make genpart 执行 loadpt 命令
 
-------------
loadpt 命令解析 partition.xml 文件分析:
fp_input = fopen("partition.xml", "rt"); 打开文件:
AMSS/products/7x30/core/storage/tools/jsdcc/partition_load_pt/partition.xml
 
#define INPUT_BUFFER_SIZE     10240
input_buf = malloc(INPUT_BUFFER_SIZE);
申请一个大小为 10240的缓冲区,对 partition.xml 文件内容进行解析,然后以串的形式保存在变量: input_buf 中。
 
fp_bin_out = fopen("partition.bin", "wb");
生成一个 partition.bin 文件,用于保存二进制的分区信息
 
parse_element(input_buf, LEVEL_IMAGE);
对每个分区描述符进行解析,然后保存到文件 partition.bin 中。
---------------
命令 perl $(TOOLSDIR_JSDCC)/partition_extract_mbr.pl 2 0 $(TOOLSDIR_JSDCC)/ 会生成文件:
./AMSS/products/7x30/core/storage/tools/jsdcc/partition_load_pt/partition.mbn
---------------
./AMSS/products/7x30/core/bsp/tools/emmcbld/build/MPRG7x30.hex
./AMSS/products/7x30/build/ms/bin/AABBQOLY/MPRG7x30.hex
 
在 HY11-N0216-4_1.2.20 版本中不存在文件
./AMSS/products/7x30/core/bsp/tools/emmcbld/build/MPRG7x30.hex
 
1.4 高通平台 7630 启动流程分析
1.4.1 启动流程概述
开机后,首先从 rom 中的 pbl 开始执行,pbl 装载 dbl
1.4.2 pbl 流程
pbl 是固化在高通芯片中的一段程序,没有相应的源代码。
1.4.3 dbl 流程
pbl运行以后,它会装载 dbl,dbl是从其__main 函数开始执行,此函数在汇编文件 dbl.s 中。
./AMSS/products/7x30/core/boot/secboot2/dbl/shared/src/dbl.s
__main
_main
    ...
    ldr    r5, =dbl_main_ctl   
    blx    r5
    ...
通过 dbl_main_ctl 调用会进入 c 函数, dbl_main_ctl 函数在文件:
./AMSS/products/7x30/core/boot/secboot2/dbl/shared/src/dbl_mc.c:282中:
void dbl_main_ctl(boot_pbl_shared_data_type *pbl_shared)
    ...
    调用表 dbl_init_func_tbl 中的每个函数
    for ( i=0; dbl_init_func_tbl[i] != NULL; i++ )
    {
        dbl_init_func_tbl[i](&dbl_shared_data);
    }
    ...
    #经过一系列的初始化,dbl 会把控制权传递给 osbl
    dbl_shared_data.entry_ptr(dbl_shared_data.dbl_data_for_osbl);
    ...
 
dbl_init_func_tbl 表在文件:
./AMSS/products/7x30/core/boot/secboot2/dbl/shared/src/dbl_mc.c:122 中,其中的函数:
dbl_load_osbl_image 会完成 osbl 的装载
dbl_load_osbl_image 函数在文件:
./AMSS/products/7x30/core/boot/secboot2/dbl/shared/src/dbl_loader.c:322 中:
void dbl_load_osbl_image(dbl_shared_data_type *shared_data)
{
  dbl_error_type ret_value = DBL_ERR_NONE;
  ret_value = dbl_load_image(shared_data, OSBL_IMG);
  DBL_VERIFY((ret_value == DBL_ERR_NONE),  (uint32)ret_value);
}
 
dbl_load_osbl_image
    ret_value = dbl_load_image(shared_data, OSBL_IMG);
        shared_data->dbl_state = DBL_STATE_LOAD_OSBL_IMG;
        ret_value = dbl_load_hdr_and_image(  shared_data,img_type,MIBIB_OSBL_PARTI_NAME,MI_OSBL_MAGIC1,MI_OSBL_MAGIC2);
           shared_data->entry_ptr      = (void (*)(void*))(image_hdr.image_dest_ptr);
 
dbl_shared_data.entry_ptr(dbl_shared_data.dbl_data_for_osbl)
在调用 dbl_shared_data.entry_ptr 之前,已经对该函数指针进行了初始化:
shared_data->entry_ptr      = (void (*)(void*))(image_hdr.image_dest_ptr);
它实际上是指向 osbl 镜像的起始地址,所以执行之后,系统进入 osbl 阶段
1.4.4 osbl 流程
osbl 的入口函数 __main 在汇编文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/shared/src/osbl.s:86: 中
    ...
    IMPORT osbl_main_ctl
    ...
    AREA    OSBL_ENTRY, CODE, READONLY
    CODE32
    ENTRY       
__main
_main
    ...
    ldr    r5, =osbl_main_ctl   
    blx    r5
    ...
 
__main 函数会调用 osbl_main_ctl ,此函数在文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/shared/src/osbl_mc.c:234 中。
void osbl_main_ctl(boot_dbl_if_shared_info_type *dbl_shared_info_ptr)
{
    ...
    #Process the target-dependent OSBL procedures
    osbl_do_procedures( &bl_shared_data,osbl_main_procs );
    ...
    //把控制权给 AMSS
    bl_shared_data.amss_entry_ptr();
 
}
在此阶段,osbl 通过 osbl_main_procs 中定义的 osbl_load_appsbl 函数把应用程序的控制权交给了android 系统,modem 端的控制权通过 bl_shared_data.amss_entry_ptr() 交割 AMSS,他们分别在两个处理器上同时运行,两个处理期间通过 smd 进行通信。
osbl_main_procs 在文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/target/msm7x30/src/osbl_mc_target.c:524中,它定义了一些初始化函数:
osbl_procedure_func_type osbl_main_procs[] =
{
   ...
   //初始化 迷你usb 充电硬件
   osbl_hw_init,
   ...
   //在 osbl 阶段会提升系统时钟
   #ifndef RUMIBUILD
    osbl_increase_clk_speed,
   #endif
   ...
   //初始化 osbl 模并且锁住接口
  
   osbl_init_modules,
   ...
   初始化 flash 设备
   osbl_flash_init,
   ...
   //检测是否通过sd卡更新镜像文件
   osbl_sd_image_upgrade,
   ...
   //初始化数据结构,以便装载 AMSS 镜像
   osbl_init_amss_image,
   ...
#ifdef FEATURE_FOTA
 
  osbl_fota_init,
#endif
   //amss 镜像进行授权鉴定 
   osbl_auth_amss_image,
   //如果有 adsp 那么进行相应处理
#ifdef FEATURE_OSBL_LOAD_AND_BOOT_ADSP
   //装载 adsp 镜像
  osbl_load_adsp,
  //授权
  osbl_auth_adsp,  
#endif 
 
#ifdef FEATURE_SDCC_BOOT
   //装载 amss 镜像
   osbl_load_amss_image,
   ...
#endif
 
#ifndef FEATURE_STANDALONE_MODEM
   //从flash 设备装载 appsboot
   osbl_load_appsbl,
   ...
   //从flash中装载 OS 镜像
   * Load the OS image from flash
   osbl_load_apps_os,
   //引导 aARM 处理器
   osbl_boot_aarm,
#endif
  对于 nand 启动,AMSS 应该在 apps 引导以后再装载
#ifndef FEATURE_SDCC_BOOT
   // nand 启动,装载 amss 镜像
   osbl_load_amss_image,
#endif
   ...
};
 

1.4.4.1 osbl 装载 appsbl 过程分析

osbl 通过 osbl_load_appsbl 函数装载应用程序的 boot loader 到指定的 RAM 中
osbl_load_appsbl 在文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/shared/src/osbl_aarm_boot.c:119 中
void osbl_load_appsbl( bl_shared_data_type *bl_shared_data )
{
...
    osbl_load_header_and_image_with_cookie( APPSBL_IMG, &appsbl_image_header_with_cookie );
... 
 
  if ( apps_image_start_addr != 0x0 )
  {
复位向量的初始化值与 appsbl 镜像起始地址有关,复位的时候此值会被放入到 PC 寄存器
向量 0x00000020 中保存 appsbl 镜像的起始地址
向量 0x00000000 中的值为 0xE59FF018
    address 0x00000000:     ldr pc, [pc, #0x18]
address 0x00000020:     apps_image_start_addr */   
 
    uint32 *vector_ptr = (uint32*) 0x00000020;   
    *vector_ptr = apps_image_start_addr;
    for ( --vector_ptr; vector_ptr; vector_ptr-- )
    {
      *vector_ptr = 0xEAFFFFFE;        
    }
    *vector_ptr  = 0xE59FF018;         
  }
}
osbl_load_header_and_image_with_cookie 函数完成 appsbl 镜像头和镜像的装载,它首先会尝试从 mibi 中装载 appsbl 镜像头,如果当前是 nor non-partition table 设备,那么装载将会成功,如果不成功,那么认为 appsbl 头位于它分区的起始位置,将其读出。
 
1.4.5 appsbl 流程(源代码在 android中)
appsbl 是 applications ARM boot loader 的简称,不同的软件框架,此分区来自不同的源代码
在android 系统中  appsbl 代码为 bootable/bootloader/lk
brew 框架的系统中 appsbl 代码在 ./AMSS/products/7x30/core/boot/appsproc/target/msm7x30/src
brew 框架系统,入口函数 __main -> appsbl_main_ctl 在文件:
./AMSS/products/7x30/core/boot/appsproc/target/msm7x30/src/appsbl_handler.s 中。
 
android 系统中有:
vendor/qcom/msm7630_surf/AndroidBoard.mk:25:
include bootable/bootloader/lk/AndroidBoot.mk
bootable/bootloader/lk/arch/arm/system-onesegment.ld
system-onesegment.ld 中 ENTRY(_start) 指定了 appsbl 分区从 _start 函数开始执行,此函数在文件 ./bootable/bootloader/lk/arch/arm/crt0.S:25 中:
...
.text
.globl _start
_start:
    b   reset
   ...
   bl      kmain
   ...
kmain 会跳转到 C 文件中执行,此函数文件
bootable/bootloader/lk/kernel/main.c 中:
void kmain(void)
    thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
static int bootstrap2(void *arg)
{
    arch_init();
    platform_init();
    target_init();
    apps_init();
    return 0;
}
 
apps_init 在文件:bootable/bootloader/lk/app/app.c:33 中:
void apps_init(void)
{
    const struct app_descriptor *app;
 
   
    for (app = &__apps_start; app != &__apps_end; app++) {
       if (app->init)
           app->init(app);
    }
 
   
    for (app = &__apps_start; app != &__apps_end; app++) {
       if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {
           start_app(app);
       }
    }
}
 
因为:bootable/bootloader/lk/include/app.h:45 中有:
#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,
#define APP_END };
bootable/bootloader/lk/app/aboot/aboot.c 中有:
APP_START(aboot)
    .init = aboot_init,
APP_END
所以有:
struct app_descriptor _app_aboot __SECTION(".apps") =
{
      .name = aboot,
      .init = aboot_init,
};
 
所以 apps_init 函数中的: app->init 实际上调用的是文件:
bootable/bootloader/lk/app/aboot/aboot.c:398 中的函数 aboot_init
 
1.4.5.1 aboot_init 过程分析(需要侧重关心的部分)
aboot_init 阶段我们应该关心 fastboot 模式 和 appsbl 对 android 系统的引导过程。
void aboot_init(const struct app_descriptor *app)
{
        unsigned reboot_mode = 0;
    page_size = flash_page_size();
    page_mask = page_size - 1;
    if (keys_get_state(KEY_HOME) != 0)
            boot_into_recovery = 1;
    if (keys_get_state(KEY_BACK) != 0)
       goto fastboot;
    if (keys_get_state(KEY_CLEAR) != 0)
       goto fastboot;
 
    reboot_mode = check_reboot_mode();
        if (reboot_mode == RECOVERY_MODE){
            boot_into_recovery = 1;
        }else if(reboot_mode == FASTBOOT_MODE){
            goto fastboot;
        }
recovery_init();
    //从falsh上读取 linux 然后引导
    boot_linux_from_flash();
    dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
       "to fastboot mode.\n");
 
fastboot:
        display_init();
    dprintf(INFO, "Diplay initialized\n");
    udc_init(&surf_udc_device);
 
    fastboot_register("boot", cmd_boot);
    fastboot_register("erase:", cmd_erase);
    fastboot_register("flash:", cmd_flash);
    fastboot_register("continue", cmd_continue);
    fastboot_register("reboot", cmd_reboot);
    fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
    fastboot_publish("product", "swordfish");
    fastboot_publish("kernel", "lk");
 
    fastboot_init((void*) SCRATCH_ADDR, 100 * 1024 * 1024);
    udc_start();
}
 
recovery_init() 调用的是文件 bootable/bootloader/lk/app/aboot/recovery.c中的函数:
从 misc 分区读取
 
 
struct bootloader_message {
    char command[32];
    char status[32];
    char recovery[1024];
};
 
int get_bootloader_message(struct bootloader_message *out);
int set_bootloader_message(const struct bootloader_message *in);
 
int write_update_for_bootloader(
        const char *update, int update_len,
        int bitmap_width, int bitmap_height, int bitmap_bpp,
        const char *busy_bitmap, const char *error_bitmap);
 
ROM上又分为几个分区:boot, system, recovery, cache, userdata和misc。在boot上存着bootloader和Linux Kernel,system上面是Android系统,userdata包含登录信息/个人软件和设置等。recovery区里放着的是如何控制系统恢复 的工具,如Google官方的stock恢复器。系统开机的时候,bootloader会首先检查硬件配置,然后将Radio Firmware写入RAM,接着调进kernel,最后再装载Android OS进入桌面
misc - misc分区,一般不会去动它,和我们没有太大关系
recovery -recovery分区
boot - 存储linux系统内核的分区,包括 kernel 和 ramdisk 两部分
system -系统分区,储存着Android系统的数据,刷 ROM 主要刷的是这个
cache -缓存分区,刷ROM时最好一起擦一下
Dalvik-cache- 这个是Android使用的Java虚拟机的缓存分区,刷ROM时最好一起擦一下
userdata - 用户自己使用的数据部分,存储我们自己的软件设置等等,恢复出厂设置的时候,这个分区会被格式化
还有Radio,这个部分通常负责无线信号,可以理解为手机信号收发部分的驱动,不过N1的视频编码器也集成在这里面,Radio可以随便刷,不过某些特定的ROM可能会指定Radio版本。
最后是SPL/Bootloader,这个我们一般不会用到它也不会修改它,除了第一次解锁的时候(不过解锁信息储存在哪里,现在xda上也没有定论,似乎不是在SPL里面,这个大致相当于电脑上的 BIOS,负责整个手机的最底层引导,坏了可能导致变砖。
 
recovery 分区的 init.rc 文件比较简单
./out/target/product/msm7630_surf/recovery/root/init.rc
service recovery /sbin/recovery
service adbd /sbin/adbd recovery
on property:persist.service.adb.enable=1
    start adbd
on property:persist.service.adb.enable=0
    stop adbd
它只启动了 /sbin/recovery /sbin/adbd
Recovery 可执行程序的mian函数在
bootable/recovery/recovery.c
    ui_init(); 初始化 recovery 模式的界面
    get_args(&argc, &argv); 获取按键选择
 
 
prompt_and_wait()
install_package()
    handle_update_package()
        try_update_binary(path, zip)
           handle_firmware_update(firmware_type, firmware_filename, zip)
              remember_firmware_update(type, data, data_size)
                  update_type = type;
                  update_data = data;
                  update_length = length;
 
maybe_install_firmware_update(send_intent);
write_update_for_bootloader() 写入数据
snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
set_bootloader_message(&boot)
才是真正的更新 radio.img
 
 
1、下载最新的CursorSense的ROM:CursorSense32A-Mod-0.9.1.1-signed,和要求的 RADIO(radio6.35.07.29.img),SPL(hboot1.76.2007.img),HERO的 RECOVERY(recovery-RA-hero-v1.5.2.img)
2、在FASTBOOT下用下面的命令开刷(文件改过名):
fastboot flash hboot hboot.img
fastboot flash radio radio.img
fastboot erase system -w
fastboot erase boot
fastboot erase recovery
fastboot flash recovery recovery.img
 
 
1.4.5.1.1 fastboot 模式分析
1.4.5.1.1.1 什么是 fastboot 模式
fastboot 是android 系统的软件烧写模式,通过它我们可以为系统烧写软件
参考文档:
工程模式與FASTBOOT
http://android.cool3c.com/article/2260
 
 
1.4.5.1.1.2 fastboot 模式与 recovery 模式的区别
fastboot 模式 和 recovery 模式都是 android系统的软件烧写或者升级方式,通过他们可以为机器烧写软件。
他们有如下区别:
1.  代码来自不同分区,fastboot 在 appsbl 分区 ,recovery 是单独的一个分区
2.  fastboot 比 recovery 功能更强,它可以用来烧写 recovery 分区
fastboot 可以做的事情:
1.  重启机器
2.烧写分区
3. 擦除分区
4. 重启 appsbl
5. 系统更新等
常有如下命令:
fastboot reboot         重启机器
fastboot flash boot     boot.img    烧写引导分区
fastboot flash system   system.img  烧写系统分区
fastboot flash userdata data.img    烧写数据分区
fastboot flash recovery recovery.img     烧写恢复模式分区
fastboot flash splash1  mysplash.rgb565  烧写开机画面
fastboot erase  system  擦除系统分区
fastboot update update.zip  update.zip 是 boot.img, system.img和recovery.img的zip压缩包
以上子命令不一定存在,要根绝实际情况确定。fastboot 中是通过 fastboot_register 方式注册了一系列可用的子命令,如:
fastboot_register("boot", cmd_boot);
fastboot_register("erase:", cmd_erase);
fastboot_register("flash:", cmd_flash);
fastboot_register("continue", cmd_continue);
fastboot_register("reboot", cmd_reboot);
fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
fastboot_register("getvar:", cmd_getvar);
fastboot_register("download:", cmd_download);
我们可以根绝实际情况修改 fastboot 代码,让其支持更多命令,如:
fastboot flashall  在当前目录寻找各种所有的image文件,在刷完所有分区后重启手机
recovery 分区只能对 system ,data,cache boot 等分区进行烧写,sd卡上放 update.zip 的升级方式就可以通过 recovery 的方式完成。
 
 
除了 fastboot 模式可以烧写 recovery ,在 android 系统的命令模式下可以通过 flash_image 命令
./out/target/product/msm7630_surf/symbols/system/bin/flash_image 进行烧写。
flash_image recovery /sdcard/recovery.img  红色部分是你解压出的文件名包含后缀名
reboot recovery
之后就能看到新的recovery 了
E/flash_image(   35): can't find recovery partition
参考资料:
最新Amon-RA 1.3.2 Recovery原创教程(完成)
http://www.androidin.net/bbs/thread-29285-1-1.html
 
 
 
1.4.5.1.1.3 怎样进入 fastboot 模式
在系统启动的 appsboot 阶段,通过以下几种方式可以进入 fastboot 模式
1.   通过按键,如: KEY_BACK 或者 KEY_CLEAR 等
2.   当前系统的重启模式,如果为 FASTBOOT_MODE
3.   引导linux失败
unsigned check_reboot_mode(void)
{
    unsigned mode[2] = {0, 0};
    unsigned int mode_len = sizeof(mode);
    unsigned smem_status;
 
    smem_status = smem_read_alloc_entry(SMEM_APPS_BOOT_MODE,
                  &mode, mode_len );
    if(smem_status)
    {
      dprintf(CRITICAL, "ERROR: unable to read shared memory for reboot mode\n");
      return 0;
    }
    return mode[0];
}
bootable/bootloader/lk/platform/msm_shared/smem.h:83:  SMEM_APPS_BOOT_MODE = 106
 
按键进入 fastboot 模式要根据实际情况决定,因为这些在代码中都是可以更改的,参考文档:
市面常见机器进入 Recovery 模式及 Fastboot 模式的方法:http://android.cool3c.com/article/12221
 
1.4.5.1.1.4 android 系统手机刷机过程分析(补充知识)
将以 G1 为样机分析刷机过程
放到SD卡根目录(不要改名,直接丢进去)
打开终端输入
su(回车r)
mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system (回车)
cd sdcard (回车r)
flash_image recovery recovery-RAv1.2.1G.img (回车)
以上是从一个帖子里找来的。上面说不要改名,我改了名字刷成功了。
 
 
1.4.5.1.2 appsbl 引导 android 系统
appsbl 对 android 系统的引导是从 boot_linux_from_flash 开始,它首先引导 linux 内核,然后由 linux 内核装载引导上层的 android 系统。
boot_linux_from_flash() 函数在文件:
bootable/bootloader/lk/app/aboot/aboot.c:182 中。
它实际上是从 boot 分区中读取 boot.img (内核+ramdisk)然后引导执行,具体过程如下:
int boot_linux_from_flash(void)
{
    struct boot_img_hdr *hdr = (void*) buf;
    unsigned n;
    struct ptentry *ptn;
    struct ptable *ptable;
    unsigned offset = 0;
    const char *cmdline;
 
        首先判断是否为 eMMC启动
    if (target_is_emmc_boot()) {
       hdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
       if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
           dprintf(CRITICAL, "ERROR: Invalid boot image header\n");
           return -1;
       }
       goto continue_boot;
    }
        获取分区表
    ptable = flash_get_ptable();
    if (ptable == NULL) {
       dprintf(CRITICAL, "ERROR: Partition table not found\n");
       return -1;
    }
        如果不是进入 recovery 模式
    if(!boot_into_recovery)
    {
            ptn = ptable_find(ptable, "boot");
            if (ptn == NULL) {
               dprintf(CRITICAL, "ERROR: No boot partition found\n");
               return -1;
            }
    }
        //进入 recovery 模式
    else
    {
            ptn = ptable_find(ptable, "recovery");
            if (ptn == NULL) {
               dprintf(CRITICAL, "ERROR: No recovery partition found\n");
               return -1;
            }
    }
        //读取 boot.img
    if (flash_read(ptn, offset, buf, page_size)) {
       dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
       return -1;
    }
    offset += page_size;
 
    if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
       dprintf(CRITICAL, "ERROR: Invaled boot image heador\n");
       return -1;
    }
 
    if (hdr->page_size != page_size) {
       dprintf(CRITICAL, "ERROR: Invaled boot image pagesize. Device pagesize: %d, Image pagesize: %d\n",page_size,hdr->page_size);
       return -1;
    }
        //获取 kernel 镜像文件地址
    n = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
    if (flash_read(ptn, offset, (void *)hdr->kernel_addr, n)) {
       dprintf(CRITICAL, "ERROR: Cannot read kernel image\n");
       return -1;
    }
    offset += n;
        //获取 ramdisk 镜像文件地址
    n = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
    if (flash_read(ptn, offset, (void *)hdr->ramdisk_addr, n)) {
       dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n");
       return -1;
    }
    offset += n;
 
continue_boot:
    dprintf(INFO, "\nkernel  @ %x (%d bytes)\n", hdr->kernel_addr,
       hdr->kernel_size);
    dprintf(INFO, "ramdisk @ %x (%d bytes)\n", hdr->ramdisk_addr,
       hdr->ramdisk_size);
 
    if(hdr->cmdline[0]) {
       cmdline = (char*) hdr->cmdline;
    } else {
       cmdline = DEFAULT_CMDLINE;
    }
    dprintf(INFO, "cmdline = '%s'\n", cmdline);
 
   
        //开始引导内核
    dprintf(INFO, "\nBooting Linux\n");
    boot_linux((void *)hdr->kernel_addr, (void *)TAGS_ADDR,
          (const char *)cmdline, board_machtype(),
          (void *)hdr->ramdisk_addr, hdr->ramdisk_size);
 
    return 0;
}
 
boot_linux 调用的文件:
bootable/bootloader/lk/app/aboot/aboot.c:94 中的函数:
void boot_linux(void *kernel, unsigned *tags,
       const char *cmdline, unsigned machtype,
       void *ramdisk, unsigned ramdisk_size)
{
    ...
    void (*entry)(unsigned,unsigned,unsigned*) = kernel;
    ...
    entry(0, machtype, tags);
}
 
entry(0, machtype, tags); 正式进入内核,将由kernel 完成 android 系统的启动。
 
 
====================================
 
osbl_load_appsbl:
  This function loads the applications ARM boot loader to its
  destination RAM.  It may load the aARM from flash or from data
  contained within the OEM SBL image depending on OEM security
  requirements. 
 
osbl_load_apps_os:
 This function loads the APPS image from flash to its destination
 address in RAM. A cookie read from the APPSBL header is checked for
 the size of OS image and magic number. If the magic number matches and
 the size of apps image is greater than 0, the image is loaded. 
 
osbl_load_apps_os 函数在文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/shared/src/osbl_aarm_boot.c:394 中:
void osbl_load_apps_os( bl_shared_data_type *bl_shared_data )
   
    unified_boot_init(&appsbl_image_header_with_cookie);
 
./AMSS/products/7x30/core/boot/tools/headergen/shared/src/image_header.c:492:     
    boot_cookie.OS_type = atoi(argv[i+5]);
    header[12] = boot_cookie.OS_type;      
 
nand_tools 工具来自源代码:
 
编译脚本:
./AMSS/products/7x30/core/bsp/tools/flash/nand_exe/build/SConscript
========================================
env.Replace(TARGET_NAME = 'nand_tools')
nand_tools_exe = env.Program('${TARGET_NAME}', source=[], LIBS=libs, LIBPATH=libs_path)
# copy elf and reloc to needed locations for AMSS tools to load on target
install_target_exe = env.Install(SRCPATH, nand_tools_exe)
========================================
nand_tools 工具语法:
./AMSS/products/7x30/core/bsp/tools/flash/nand_exe/build/nand_tools -fp flash_page_size -fb flash_block_size -fd flash_device_size -d device_bootloader_fname -u usr_partition_fname -m mibib_partition_fname -p binary_folder_path
 
 
 
 
 
 
每一个烧写的 *.mbn 都有一个标准的头,它由函数
 
 
  header[0] = id;
  header[2] = image_source;
  header[3] = image_dest;
  header[4] = image_size;
  header[5] = code_size;
  header[6] = image_dest+code_size;
  header[7] = signature_size;           
  header[8] = image_dest+code_size+signature_size;
  header[9] = cert_chain_size;                   
  header[10] = UNIFIED_BOOT_COOKIE_MAGIC_NUMBER;
  header[11] = 0;                        
  header[12] = boot_cookie.OS_type;          
  header[13] = 0;         
  header[14] = boot_cookie.boot_apps_size_entry;
  header[15] = boot_cookie.boot_apps_ram_loc;
  header[16] = 0;         
  header[17] = 0;         
  header[18] = 0;         
  header[19] = 0;         
  printf("image_size = 0x%X, code_size= =0x%X\n", image_size, code_size);
 
 
因为文件:
./AMSS/products/7x30/build/ms/boot_targets_nonsec.min:346
./AMSS/products/7x30/build/ms/boot_targets_sec.min:498
中有:
GEN_AMSS_HEADER    = $(HEADERGEN)/image_header $(FLASH_TYPE) amss $(MBNPATH)/amss.mbn $(MBNPATH)/amsshd.mbn
语法如下:
Usage: ./AMSS/products/7x30/tools/headergen/image_header flash_type header_type input_code_file \
output_header_file secure_type [dbl_preamble_file or elf_src_file]
例如:
./AMSS/products/7x30/tools/headergen/image_header nand amss ./AMSS/products/7x30/build/ms/bin/AAABQMAZ/amss.mbn amssh.mbn  dbl_preamble_file
 
 
./AMSS/products/7x30/tools/headergen/image_header "nand" amss ./AMSS/products/7x30/build/ms/bin/AAABQMAZ/amss.mbn ./aaahd.mbn
 
文件: ./AMSS/products/7x30/build/ms/dmss_flags.min:131: 中有:
ifeq ($(USES_NOR16_CFG_DATA)$(USES_NOR32_CFG_DATA),yes)#  NAND or NOR
  FLASH_TYPE=nor
else
  FLASH_TYPE=nand
endif
从我们的环境变量可以知道使用的是 nand flash
#pragma RUNLOCAL 
$(MBNPATH)/amsshd.mbn: $(IMAGE_HEADER) $(MBNPATH)/amss.mbn
    @echo ---------------------------------------------------------------
    @echo Generating image header for AMSS.
    @echo
    @$(GEN_AMSS_HEADER)
    @echo ---------------------------------------------------------------
1.4.5.1.2.1 Android 系统启动过程中存在的问题
1.4.5.1.1.1.1 linker 问题导致系统无法启动
高通 sdk 打印信息:
D/qemud   (   37): fdhandler_accept_event: accepting on fd 10
D/qemud   (   37): created client 0xe078 listening on fd 8
D/qemud   (   37): client_fd_receive: attempting registration for service 'boot-properties'
D/qemud   (   37): client_fd_receive:    -> received channel id 1
D/qemud   (   37): client_registration: registration succeeded for client 1
I/qemu-props(   47): connected to 'boot-properties' qemud service.
I/qemu-props(   47): received: qemu.sf.lcd_density=160
I/qemu-props(   47): received: dalvik.vm.heapsize=16m
D/qemud   (   37): fdhandler_accept_event: accepting on fd 10
D/qemud   (   37): created client 0xe078 listening on fd 11
D/qemud   (   37): fdhandler_event: disconnect on fd 11
D/qemud   (   37): fdhandler_accept_event: accepting on fd 10
D/qemud   (   37): created client 0xe078 listening on fd 11
D/qemud   (   37): client_fd_receive: attempting registration for service 'gsm'
D/qemud   (   37): client_fd_receive:    -> received channel id 2
D/qemud   (   37): client_registration: registration succeeded for client 2
 
通过ps可以看出,主要是因为 zygote 未能正常启动,手动启动该服务:
/system/bin/app_process -Xzygote /system/bin --zygote &
弹出一些错误信息:
# link_image[1729]:    71 could not load needed library 'libandroid_runtime.so' for '/system/bin/app_process' (link_image[1729]:    71 could not load needed library 'libnativehelper.so' for 'libandroid_runtime.so' (link_image[1729]:    71 could not load needed library 'libicudata.so' for 'libnativehelper.so' (alloc_mem_region[823]: OOPS:    71 cannot map library 'libicudata.so'. no vspace available.)))CANNOT LINK EXECUTABLE
从以上信息可以断定,是应用程序在linker的时候未能装载需要的库,导致服务终止。
因为我们目前编译的sdk和generic版本都是给予 armv5te ,而高通是 armv7 所以暂时不建议修改代码
我们可以先从网上 sdk 的 elair版本中考取 linker 文件,拷贝到:
out/target/product/generic/system/bin/  然后重新打包 system.img : make snod
bionic/linker/linker.c
#define LINKER_BASE ((LINKER_TEXT_BASE) & 0xfff00000)
#define LINKER_TOP  (LINKER_BASE + (LINKER_AREA_SIZE))
======标准代码========
LINKER_TEXT_BASE := 0xB0000100
LINKER_AREA_SIZE := 0x01000000
#define LIBBASE 0x80000000
#define LIBLAST 0x90000000
LINKER_BASE=0xB0000000
======高通======
LINKER_TEXT_BASE := 0x70000100
LINKER_AREA_SIZE := 0x01000000
#define LIBBASE 0x40000000
#define LIBLAST 0x50000000
#define R_ARM_REL32      3
LINKER_BASE=0x70000000
===============
R_ARM_ABS32 32bit 绝对地址重定位引用
R_ARM_PC24  24bit PC相对地址重定位引用
R_ARM_ABS32 32bit 绝对地址重定位引用
R_ARM_REL32 32bit 相对地址重定位引用
REL 是 relative 的缩写,是以当前指令结束时的EIP为参考地址
ABS 是 absolute 的缩写,指绝对地址.
rel32 立即数
r32   寄存器
m32   内存访问
 
1.4.6 AMSS 流程
osbl 阶段,通过函数 osbl_load_amss_image 装载 amss 镜像文件
void osbl_load_amss_image( bl_shared_data_type *bl_shared_data )
{
    ...
     bl_shared_data->amss_entry_ptr = (amss_entry_ptr_type) boot_sec_elf_get_entry_point( bl_shared_data->amss_elf_if );
    ...  
}
 
在 osbl_main_ctl 函数中通过 bl_shared_data.amss_entry_ptr() 把控制权交给了 AMSS。
在文件:
AMSS/products/7x30/core/kernel/arch/arm/pistachio/src/gnu/linker.lds:33: 中有:
ENTRY(_start)
所以可以确定 AMSS 的镜像是从 _start 函数开始执行,该函数在文件:
AMSS/products/7x30/core/kernel/arch/arm/pistachio/src/head.spp:51: 中 
。。。   
BEGIN_PROC(_start)
。。。
       
        adr     r0,     __phys_addr_ram
        bl      arch_init
。。。
 
Amss 镜像由几部分组成,
AMSS/products/7x30/core/kernel/tools/amss.py
def get_amss_kernel_platform_src(build_asic, build_target, platform_dir):
platform_src = ["%s/src/" % platform_dir + fn for fn in ["plat_asm.spp", "timer.cc", "irq.cc", "plat.cc", "init_warm.cc", "head.spp" ]]
 
AMSS/products/7x30/core/kernel/arch/arm/pistachio/src/head.spp:51:       
BEGIN_PROC(_start)
 
TASK_COMMON_SOURCES =  [
   '${BUILDPATH}/mobile.c',
   '${BUILDPATH}/task.c',
   '${BUILDPATH}/task_iram.c'
]
task_objs = env.Object(TASK_COMMON_SOURCES)
task_lib = env.Library('${BUILDPATH}/task', task_objs)
./AMSS/products/7x30/core/debugtools/task/build/corelibs/arm11/task.lib
 
env.AddLibsToImage(['MODEM_IMAGE', 'CBSP_MODEM_IMAGE'],
   [task_lib,
   task_dog_lib,
   task_dog_keepalive_modem_lib,
   task_dog_keepalive_client_lib])
 
./AMSS/products/7x30/core/bsp/build/scripts/utils.py:59:  
env.AddMethod(add_libs_to_image, "AddLibsToImage")
./AMSS/products/7x30/core/bsp/build/scripts/utils.py:140:
def add_libs_to_image(env, targets, libs):
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:65:env.Replace(MODEM_IMAGE = env.subst('${PROC}'))
./AMSS/products/7x30/core/bsp/build/msm7x30_modem.mak:34:PROC = MULTI_PROC
IMAGE=MODEM_PROC
 
./AMSS/products/7x30/modem/rfa/rf/task/common/inc/rf_task.h:79:TASK_START_SIG     0x8000
./AMSS/products/7x30/core/boot/appsproc/target/msm7x30/src/process.c:31:                   SMSM RESET state to process_restart from err.c.
./AMSS/products/7x30/core/debugtools/err/src/err.c:808:      process_restart();
 
err_fatal_jettison_core
    -> err_fatal_handler
 
 
    代码运行到了Main()之后,在这个函数里面将完成操作系统(rex)的初始化工作,其实现方法是调用rex_init()。Rex_init()完成的工作很简单:
完成操作系统必要的一些数据结构(timer链表、任务链表等))的初始化之外;
接下来,它创建了三个任务,分别是:rex_idle_task、rex_dpc_task和tmc_task。
Idle任务没什么好解释的,目前这个任务为空,什么也没做,dpc_task目前不知道是做什么的,暂时可以不用管。前面的这两个任务都属于操作 系统层面的,由操作系统来维护,和手机软件关系不大。哪一个和手机软件关系大呢?答案是:tmc_task。大家可以把这个当作操作系统的入口(主)任 务,也可以把它当作整个手机软件的入口任务。即AMSS软件里的所有其它任务的创建和维护就是由这个tmc_task来完成的。
    到此为止,整个AMSS软件还并没有跑起来,只是跑到了tmc_task里面了。在tmc_task里面,会调用tmc_init()来完成整个AMSS 软件包的初始化工作,其中最重要的一项工作就是调用tmc_define_tasks()将AMSS软件包所有需要的任务都创建起来了。比如说 slee_task、dog_task、cm_task、wms_task、ui_task等。这些任务,一般不需要直接和AL层软件打交道,但请大家记 住,手机上所有功能的实现最根本点就是由这些服务组件(Service Task)来完成的。将来大家跟踪一个具体的功能模块时,比如说通话模块,如果需要,可以再去深入研究它的具体实现。
    好了,到现在为止,所有的AMSS核心软件就全部跑起来了(手机的功能模块,在软件方面就体现为OS层面的一个任务)。但现在大家还根本看不到Brew和 AEE的影子。呵呵,各位不要急。到了这个层面之后,我想稍微多说几句。最早的Qualcomm平台,比如说5xxx系列,是根本没有Brew的,那个时 候的AL(Application Layer)层软件开发,是直接调用底层Service task所提供的API来完成相应的工作的。从这种角度来看的话,显然那时的开发是比较郁闷和难度较高的。不过,到了65xx之后,Qualcomm平台 引入了Brew,手机开发商就没必要去从这么底层(Service API)的层面进行手机开发了,他们完全可以基于Brew来实现一台手机的所有功能(Qualcomm给我们的参考代码,就是全Brew平台的)。
    Brew的运行环境AEE是如何跑起来的呢?关键在于ui_task(),由于ui_task和我们手机开发的关系非常密切,其地位也相当重要,所以,后 文我将单独对它进行一个深入的研究与分析。到目前为止,大家只需要知道ui_task将AEE加载起来了,并且,它起到了一个中间层的作用,即所有 AMSS底层服务组件的消息,都将经由ui_task而转到AEE,并最终转到具体的App(Applet)的执行代码里面 (HandleEvent())。
注意:
上述的开机过程,在每一次按开机键都需要走一遍,即关机之后,整个系统的所有功能都将消失,而不像有些手机,看起来是关了机,但实际上底层还是有一 些软件模块在跑。为什么可以肯定地说上述开机过程每次都必须走一遍,原因很简单,因为我们的平台软件是基于Nand Flash启动的,所有的代码都需要Copy到SDRAM才能运行,而关机断电之后,SDRAM里的东东会全部丢失,所以,毫无疑问,上述的过程必须每次 开机都执行;
关机的过程相对比较简单,系统检测到关机中断之后,将调用tmc_powerdown_handler()来完成关机动作,它将把所有AMSS的任务都Stop掉,并最后调用rex_exit()退出Rex,从而完成整个关机动作。
显然,关机动作前,如果有必要,每一个任务必须将它希望保存的信息保存到Flash上面,以便下次开机时可以得到这些信息;
开机流程简图
EMBED Visio.Drawing.11 
图1 Qualcomm平台开机框图
    说明:
Tmc是操作系统层面和AMSS软件关系最密切的一个任务,不过需要OEM商在此处修改的地方应该不多;
ui_task是在操作系统层面,OEM商需要重点研究清楚的一个任务,它是连接底层Task和上层AL的一个中间层,有可能需要加入OEM商的操作流程;
CoreApp是在Brew层面的一个AL层的入口Applet,它其着管理整个上层AL层软件的作用,根据产品需求,这个App需要定做;
AEE是整个上层App的运行环境,目前Qualcomm没有公开它的源码,但它的运行机制,Amoi需要好好研究清楚,我将在另外一篇《Qualcomm平台AEE运行机制深入分析与研究》中探讨它的运行机理和调度机制,大家有兴趣可以参考此文;
Boot代码深入分析
Boot代码大部分是用汇编语言写的,也有小部分,可能需要由OEM商修改,所以用C语言来写。另外,Boot代码属于Driver范围,所以大家 可以在drivers/boot目录里面找到相应的代码。Boot的代码组织得非常模块化,整个boot的入口点是在 Boot_function_table.s里面,这个汇编代码里面实际上是将Boot需要完成的任务封装成了不同的函数,由不同的函数来完成相应的工 作,接下来,我将深入分析这些函数所完成的工作,如下所述。
mmu_enable_instruction_cache;
这个只有在Nand启动模式时才需要,打开ARM的指令Cache.
boot_hw_ctrl_init
此函数主要是完成两条总线(EBI1、EBI2)控制器的初始化,这个函数执行完了       之后,系统就可以知道两条总线上连接了哪些设备,同时也可以找得到这些       设备,不过,至于单个设备自身的初始化,则不在这里.
[注]
这个函数很重要,OEM商如果需要加新的设备到系统中(挂在两条总线上),则需
要定做此模块,目前阶段主要是内存。另外,如前文所述,这个函数是由C语言
来写的,主要目的就是为了方便OEM商定做。内存设备的修改,可以在这个模块
里找到相应的数据结构,相对还是比较简单的。
boot_hw_tlmm_init
1.晶振时钟的初始化;
2.中断表的初始化;
3.GPIO的初始化;
4.Msm本身的驱动,除了EBI2;
boot_rom_test
这个函数非常简单,只是做一个很简单的Rom检查.(比对两个标志位来检查,并
没有一块一块地去检查)。
boot_ram_test
Ram自检,具体算法其实也很简单,就是读、写内存以判断是否成功.
boot_ram_init
1.拷贝手机代码从Nand Flash到SDRAM。
a.Image__BB_RAM__Base:Core Code;
    b.Image__APP_RAM__Base:App Code;
    [注]
    上述动作是分块进行的,原因是因为Qualcomm支持分块Boot Load.
2.将Image__ZI_REGION__ZI区域初始化为0;
3.初始化OEM要求的动态Heap;
4.至于代码段里的数据初始化,直接在Image里就完成了(编译器完成);
boot_stack_initialize
ARM栈初始化,主要是为分块代码加载而预留的.
boot_cache_mmu_init
ARM Mmu初始化
    注意:
       到此为止,整个Boot的工作就告完结了,那么,它又是如何跳到AMSS的main
入口点呢?原因很简单,ARM编译器在链接的时候会自动做出一个__rt_entry(),
由此函数来完成ARM库函数的初始化,并最后将代码执行点跳转到main()。而
__rt_entry()会在boot_reset_handler.s里调用,具体细节,大家可以不用太过关心,
只需要明白,Boot跑完之后,手机软件就跑到了main里就Ok了。
Ui_task的深入分析
从大的方向来讲,ui_task只完成两件事,一件是必要的初始化工作(这个也是我们所关心的,即ui_task到底完成了哪些工作);另外一件事 就是各种信号量的事件处理,这也是我们比较关心的,即ui_task到底将哪些事件转发给了上层App。搞清楚了上述两点,我们也就能大致把 ui_task的承上启下的工作机理研究清楚。
ui_Init;
初始化过程中,ui_task主要完成了如下几件事。
创建一个用于Kick Watchdog的定时器,这样WatchDog能够及时得到Kick,假如今后发现手机在ui_task里面自动重启,很有可能就是这个定时器的Timeout设置得过短而造成的;
注册通话相关的回调,主要是和紧急呼叫相关;
电话本初始化,之所以要进行这个工作,主要是加快开机之后AL层软件操作电话本的速度,但这样将有可能导致开机速度过慢,如果开机速度过慢,可以考虑进入待机界面之后,在后台开一个task去完成这项工作;
初始化Sound设备;
向底层服务任务wms_task注册wms回调,这个回调是在IWms组件里实现的。从这种角度来看,u帮我们把wms_task和IWMS组件联 系起来了,但并没有去将AL层软件和IWMS联系起来,这个工作将是由AL层软件自己去完成。当然,注册回调的这个工作也是可以在AL层完成,之所以在这 里完成,而不是在AL层完成,其主要目的是这个工作可以做到与AL层无关,即AL层不需要关心这个事情,但这个事情是短消息功能得于实现的必须步骤;
注册键盘消息回调;
通过这个回调,所有的按键消息都将经由底层的hs_task传到此回调函数里。然后回调函数将把所有的按键信息放到一个全局变量 ui_key_buffer里面,接着发送一个UI_KEY_SIG信号给ui_task通知它去处理按键信息,至于ui_task如何处理按键消息的, 后面的ui_handleSignals里会有详细描述。
初始化Lcd,这个工作不是LCD硬件设备的真正初始化,只是一些UI需要用到的LCD数据结构的初始化,和我们关系不大;
[注]
硬件的初始化,全部都在hs_task里面完成,从这种角度来看的话,系统能跑到ui_task里面,表明所有的硬件设备的驱动都已经成功加载。
置开机标志ui_powerup为True;
注册IPC信号量UI_IPC_SIG,这个可以暂时不管;
bridle_InitSWITable的初始化,这个目标,暂时不知道,也可以先略过;
初始化资源文件,其主要工作就是在Rom里面建立资源文件的符号链表,这样就可以让系统找到这些资源文件了(资源文件是被编译在代码段的,假如不这样做的话,系统将找不到这些资源文件);
Brew运行环境AEE的初始化:AEE_Init,这个函数看不到代码,大家只需要知道,到了这一步,整个Brew也就Run起来了,在AEE初 始化完成之后,它将自动启动一个Applet,即CoreStartApp,而CoreStartApp将把CoreApp启动起来;
到此为止,ui_task的初始化工作完成;
[注意]
    1) 从上述的ui_task的初始化工作可以看出,ui_task并没有完成手机AL层软件的
基本功能的初始化,比如说Sim卡检测、网络初始化等,这些工作,应该是在
CoreApp里完成的
       2) 真正和手机功能相关的初始化工作,是在CoreApp里完成的,这个Applet的工
作机理,后面也会有详细描述;
ui_HandleSignals;
ui_task主要完成如下事件的处理。
看门狗喂食;
TASK_STOP_SIG信号,任务Stop,目前这个任务为空,没做任何事;
TASK_OFFLINE_SIG的处理,这几个任务都属于操作系统层面的事件,目前我们可以暂时不管;
处理关机信号:CoreAppHandleStopSig(),这个只是处理ui_task在关机前需要完成的任务,比如说发送一个消息给CoreApp让它关掉自己,然后将ui_task关闭;
[A]
系统的真正关机信号是由tmc来处理,当它发现需要关机时,调用tmc_powerdown_handler来完成相应的工作,在这里就是给所有的任务发送TASK_STOP_SIG的信号。
[A]
深层次的关机处理,不需要我们了解,也没必要去知道,我们只需要知道在ui_task里面把该关的关掉就Ok了。
[A]
关机是一个层层深入的过程,每一个App或者任务只需要负责将它们自己创建的资源释放掉就Ok了。而关机的导引线,显然是在CoreApp里截获到关机键之后发送出来的,事实上也是如此。
网络掉线时,发送掉线信号给CoreApp;

你可能感兴趣的:(高通平台android环境搭建,编译,系统引导流程分析)