Qlcomm 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/*

 

 

1.2.3 建立 Android 開發環境

(略)

curl http://android.git.kernel.org/repo >~/bin/repo

chmod a+x ~/bin/repo

export PATH=~/bin:$PATH

1) 安裝基本軟件

sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl sun-java5-jdk zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev

 

2) 安裝 sun-java5-jdk

ubuntu 下通過命令: sudo apt-get install sun-java5-jdk 將會安裝下面的包

sun-java5-bin sun-java5-demo sun-java5-jdk sun-java5-jre sun-java5-plugin

如果ubuntu 發佈版本中沒有 sun-java5-jdk 那麼

sudo vim /etc/apt/source.list

#for sun-java5-jdk

deb http://us.archive.ubuntu.com/ubuntu/ jaunty multiverse

deb http://us.archive.ubuntu.com/ubuntu/ jaunty-updates multiverse

sudo apt-get update

sudo apt-get sun-java5-jdk

或者,如果 ubuntu 版中不支持 apt-get ,那麼用手動安裝:

sudo mount -t nfs  172.20.127.15:/home/shared /mnt

sudo dpkg -i /mnt/tools/debs/java-1.5.0-sun/sun-java5-*

 

3) 配置usb

cd /etc/udev/rules.d/

sudo vi 50-android.rules

# adb single interface device

SUBSYSTEM=="usb_device", SYSFS{idVendor}=="18d1", SYSFS{idProduct}=="d00d",

MODE="0664", GROUP="plugdev"

# adb composite interface device

SUBSYSTEM=="usb_device", SYSFS{idVendor}=="18d1", SYSFS{idProduct}=="deed",

MODE="0664", GROUP="plugdev"

# Sooner low-level bootloader

BUS=="usb", SYSFS{idVendor}=="0bb4", SYSFS{idProduct}=="0a51",

MODE="0664",GROUP="plugdev"

sudo /etc/init.d/udev restart

 

1.2.4 建立 modem 開發環境

與android 源代碼不同,modem 編譯工具使用的是 RVDS ,實際上只用到其中的 RVCT 編譯器, 高通不提供該工具,我們必須從arm公司獲取相應的授權,RVDS 是 ADS 的升級版本,從 ADS 1.2 開始到 RVDS 3.1 我們公司都有其授權,按照高通的要求我們目前必須使用 RVDS 2.2 並且使用他的 349 patch。

RVDS 2.2 安裝以及使用步驟如下:

1). RVDS 2.2 共享在 172.20.127.15:/home/shared/ 目錄

sudo mount -t nfs 172.20.127.15:/home/shared/ /mnt

cd /mnt/qualcommon/RVDS-2.2/

linux下rvds2.2的安裝程序爲:

./rvds2.2_linux-pentium/setuplinux.bin

執行以上命令,按照默認步驟安裝,安裝路徑爲:~/ARM

注意事項:

安裝過程如果出現錯誤:

..................java.lang.UnsatisfiedLinkError: /tmp/ismp001/6073753.tmp: libstdc++-libc6.2-2.so.3:

cannot open shared object file: No such file or directory

從網上下載 libstdc++-libc6.2-2.so.3 拷貝到 /usr/lib 目錄 ,或者從下面地址獲取:

http://172.20.127.15/repositories/DocsAndTools/Tools/Qualcomm/RVDS-2.2-patch/patch/libstdc++-libc6.2-2.so.3

工具的安裝通過腳本進行了簡化,具體過程請參考文檔:

80-N0216-2_A_M7630AABBQMAZM1170.pdf

80-VR881-7_B_M7630AABBQMLZA1200.pdf

80-VR192-1_C_AMSS_Linux_Software_Users_Guide.pdf

80-VR192-1_D_AMSS_Linux_Software_Users_Guide.pdf

 

2) 安裝高通指定的 593 patch

cd /mnt/qualcommon/RVDS2.2/下執行命令:

./setup-patch-rvct2.2-bin593-lib349.sh

 

目前版本只支持 32 位的系統

1.2.4.1 補充

vim ./AMSS/products/7x30/core/bsp/build/scripts/defaults.py 定義了工作線程

  #num_jobs = num_cpu * 2 modified by mhf

   num_jobs = 2

   if num_jobs < 4:

      num_jobs = 2

   if num_jobs > 8:

      num_jobs = 8

   env.SetOption('num_jobs', num_jobs)

―――――――

獲取 RVDS

官方網站下載評估版本

https://silver.arm.com/browse

http://www.arm.com/products/tools/software-development-tools.php

https://silver.arm.com/download/eval_download.tm

https://silver.arm.com/userguides/Web_Licensing_Portal_User_Guide.pdf (Licensing 需要通過 host id 註冊)

―――――――

1.2.4.1.1 獲取 licenses

RVDS 的 licenses 從其官方網站獲取

https://silver.arm.com/licensing/

https://silver.arm.com/licensing/generate.tm

http://www.keil.com/support/man/docs/license/license_sul_install.htm

 

入口 https://silver.arm.com/licensing/ 合法用戶登錄

用戶名: [email protected]  密碼: Mohuifu7737

入口 https://silver.arm.com/licensing/generate.tm 輸入產品的序列號

然後按照步驟一步步操作即可

Server Host Id Type 類型選擇 ETHERNET

Server Host Id 填寫需要綁定主機的MAC地址 00:1a:64:0a:ba:70

最後保存 license.dat 文件,文本格式。

 

 

1.2.4.1.2 Flex 簡單使用指南

FLEXlm是應用廣泛的License管理工具,它以使軟件License能夠在網上浮動而出名。浮動的License有利於軟件的使用和對 License的管理,這使得用戶能夠高效地使用有效的許可,並使管理者能夠控制允許使用它的節點。由於有大約1500廠商使用FLEXle管理 lICENSE,所以CAD系統管理人員極有可能要同時安裝和管理來自不同廠商的License或同一廠商多個產品的License文件。可採取以下方法避免產生衝突:

  (1)用一個服務器運行一個Lmgrd(License文件的後臺管理程序)和多個License文件;

  (2)用一個服務器運行多個Lmgrd和License文件;

  (3)運用多個服務器節點,每個服務器運行單獨的Lmgrd和License文件。

  第一種選擇主要造用於高版本的Lmgrd,V6之前和FLEXlm,每個Lmgrd只能管理一個License文件;

  第二種選擇,將使用一臺服務器,但需要運行多個Lmgrd;第三種選擇,必須使用多個License服務器。

  一、服務器端設定

  1.License文件的設定

  在使用FLEXlm進行管理的License文件中一般有SERVER行,它通過SERVER行的hostname和hostID定義License服務器。

   SERVER this_host 0050BB0F402 27000

   hostname hostID post

 

  2.服務方式的選擇

  (1)一個服務器運行一個Lmgrd和多個License文件如果多個License文件具有相同的hostID,則可以通過修改hostname進行合併。合併時,首先將多個License文件加到一個文件中,然後修改SERVER行,並且只保留一個SERVER行。對於Windows NT操作系統,應在各License的默認位置保存一個合併後的備份,這樣每個軟件將在其默認位置找到License信息,從而避免了對 LM_LICENSE_FILE的設定;對於UNIX操作系統,可以建立一個默認位置到License存放位置和Link。合併後的License文件,就可以使用同一個Lmgrd。

  (2)一個服務器運行一個Lmgrd和一個別License文件如果HostID不一樣,則這些License服務只能運行於不同的服務器節點上,並且License不能合併。可以選擇使用一個服務器運行一個Lmgrd和License文件。

  (3)一個服務器運行多個Lmgrd和License文件如果多個License未進行合併,可以通過在同一臺機器上啓動多個Lmgrd,每個 Lmgrd管理一個License文件。使用多個Lmgrd管理多個License文件對服務器的性能並沒有明顯影響。如果License是由不同版本的 FLEXlm產生的,一般是新版本可以管理舊版本的License文件。所以應使用最新的Lmgrd和Vendor daemon。另外,當用一個服務器的多個Lmgrd管理多個License文件時,應該注意任何二個License文件的post都不能一樣,並且對於每個License而言,應選用合造的Lmgrd。

 

  二、客戶端設定

  當使用客戶端應用程序時(a Licensedapplication),可以通過在系統的環境變量中設定LM_LICENSE_FILE,使Application能夠指向不同服務器上的License文件。如果要使a Licensed application使用不同服務器都有單獨的一個License文件),客戶端應將需要用到的License文件拷貝到本機目錄下,並指定LM_LICENSE_FILE環境變量。UNIX: %setenv LM_LICENSE_FILE lfpath1 : lfpath2 :…… : lfpathN Windows: lfpath1 ;lfpath2:…… ;lfpathN LfpathN爲第N個License的路徑;UNIX下路徑間用":"隔開;Windows/NT下路徑間使用";"隔開;

  這樣,每個Licensed aplication在啓動時將依次查詢LM_LICENSE_FILE中所指定的License文件,並向相應的License服務器申請許可,以使用戶能從所列的服務器得到許可。LM_LICENSE_FILE也可以使用各License文件中所指定的"post@hostname"。下面以Windows NT爲例介紹多個FLEXlm的安裝。

 

  三、同一機器上多個FLEXlm License Server的安裝

  (1) 以Administrator身分登錄;

  (2)在C盤建C:\FLEXlm目錄,並拷貝相關文件到其下;

  (3)在C:\FLEXlm下建立欲安裝License Server的軟件目錄,放置各軟件的License文件,Daemon和Daemon所需的動態連接庫;

  (4)修改License.dat和SERVER行和DAEMON的位置,並啓動FLEXlm License Manager。    

  (5)在Setup修改Service Name,輸入造當名稱,以區別是何種License服務;利用Browse選擇合適Lmgrd.exe和對應和License.dat並指定Debug.log和放置路徑;

  (6)選中"StartServer at Power-Up"與"Use NT Services",這樣下次啓動機器時,將自動啓動該Li-cense服務;

  (7)點擊Control按鈕檢查Service Name是否與設定名稱相同,如果不同,回到"Setup"重新選擇Service Name;如果一樣,點擊"Start"啓動該Li-cense Server;點擊"Status"檢查Licevse Server啓動情況,若出現Server_name: License server UP (MASTER),表示License Server啓動成功;

  (8)安裝另外的License Server:可依上述(3)~(7)重新執行一次即可;

  (9)切換不同License Server:在"Setup"中選擇適當的"Service Name",然後啓動或停止相應的License服務;

  (10)移除License Server:在"Setup"選擇適當的"Service Name",然後按"Remove"即可。

 

 

1.2.4.1.3 啓動 license 服務器

#!/bin/bash

ac_PATH=~/ARM/Utilities/FLEXlm/9.2/release/linux-pentium/

PATH=${ac_PATH}:${PATH}

export PATH

LICENSE_FILE=~/ARM/licenses/license.dat

LOG=~/ARM/licenses/license.log

case "$1" in

start)

    lmgrd -c ${LICENSE_FILE} 2>> ${LOG} 1>&2

    echo -n " lmgrd"

    ;;

stop)

    ac_pid=`pidof lmgrd`

    kill $ac_pid 2>> ${LOG} 1>&2

    ac_pid=`pidof armlmd`

    kill $ac_pid 2>> ${LOG} 1>&2

    #lmgrd -c ${LICENSE_FILE} -x lmdown 2>> ${LOG} 1>&2

    ;;

*)

    echo "Usage: `basename $0` {start|stop}" 1>&2

    exit 64

    ;;

esac

 

1.2.4.1.4 license 沒有辦法從服務器獲取的幾種情況

    1.需要關閉網絡防火牆

    2.在客戶端需要配置license服務器的服務端口

    3.要求在同一個局域網內

sudo ufw disable

防火牆在系統啓動時自動禁用

sudo iptables -A OUTPUT -p tcp --dport 8224 -j ACCEPT

修改/etc/sysconfig/iptables 文件,添加以下內容:

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 23 -j ACCEPT

 

1.2.4.1.5 破解 rvds 的license

第 1 章 歡迎使用 FLEXlm

在linux下創建一個虛擬網卡

http://nxjsjx.com/cgl/%E8%BD%AF%E4%BB%B6/%E5%A4%9A%E5%AA%92%E4%BD%93%E5%88%B6%E4%BD%9C%E8%BD%AF%E4%BB%B6/flash/Autocad%202002/Netsetup/support/AdLM/Docs/FlexUser/all.htm#895035

 

1.2.5 在高通開發板上燒錄文件系統

通過設置模塊完成系統,應用程序等個性化設置。

燒錄之前必須瞭解獲取硬件配置情況

2. 由硬件配置情況到高通網站選擇相應的鏡像文件

3. 燒錄鏡像文件到高通demo開發板

4. 從高通網站下載源代碼編譯相應的鏡像文件進行驗證

 

1. 燒錄之前必須瞭解獲取硬件配置情況

高通 demo 板的配置情況:SURF-MSM7630 7X30A-AAABQMBZM-1090  或者 7X30A-AAABQMAZM-1200

以上信息可以通過 QPST 連接高通的demo開發板獲得

 

2. 由硬件配置情況到高通網站選擇相應的鏡像文件

要給高通的開發板燒錄文件系統,必須有以下的鏡像文件:

adsp.mbn           dsp相關的

amss.mbn           AMSS modem binary image

dbl.mbn            設備啓動的裝載程序

osbl.mbn           OS boot loader binary image

partition.mbn      分區表的二進制文件

appsboot.mbn       應用程序的啓動文件,如果是 eMMC 啓動對應文件 emmc_appsboot.mbn

boot.img           ap 端的linux 內核

system.img         android 文件系統的 system 分區

userdata.img       android 文件系統的 data 分區

其中 adsp.mbn,amss.mbn,dbl.mbn,osbl.mbn,partition.mbn 可以從以下目錄獲取

unzip /home/shared/qualcommon/HK11-N0216-3.zip

unzip /home/shared/qualcommon/HK11-N0216-4.zip

HK11-N0216-3_1.2.00/AAABQMAZ/

HK11-N0216-4_1.2.20/AAABQMAZ/

appsboot.mbn,boot.img,system.img,userdata.img 必須來自eclair源代碼

 

3. 燒錄鏡像文件到高通demo開發板

怎樣燒寫文件請參考工具使用文檔

通過fastboot燒寫 boot.img syste.img usrdata.img

參考文檔:

80-VR192-1_D_AMSS_Linux_Software_Users_Guide.pdf

6.2 USB setup in Linux

6.2.1 Using Fastboot in Linux

 

 

4. 從高通網站下載源代碼編譯相應的鏡像文件進行驗證

高通有兩個cpu,他們分別跑不同的系統,應用程序(ap)端是android系統,modem 端是高通自己的系統。

======

android 系統目前使用的是 eclair 版本,此版本來自標準的 android 2.1 eclair,高通在上面加了自己的補丁,代碼網址:

https://www.codeaurora.org/wiki/QAEP#Branch_Releases

https://www.codeaurora.org/wiki/QLBEP

下載 M7630AABBQMLZA1150 分支:

February 1, 2010    M7630AABBQMLZA1150    msm7630    eclair    M7630AABBQMLZA1150.xml

命令如下:

mkdir  -pv ~/workspace/gphone/eclair-M7630AABBQMLZA1150-20100201

cd ~/workspace/gphone/eclair-M7630AABBQMLZA1150-20100201

repo init -u git://codeaurora.org/platform/manifest.git  -b eclair -m M7630AABBQMLZA1150.xml

nohup repo sync

代碼下的 vendor/qcom-proprietary 來自包 HY11-VR881-5.zip

以上兩部分代碼已經下載並且合併,共享在:

http://172.20.127.15/repositories/TD1002/trunk/eclair-M7630AABBQMLZA1150

---------------

編譯 eclair 代碼

svn co http://172.20.127.15/repositories/TD1002/trunk/eclair-M7630AABBQMLZA1150

cd eclair-M7630AABBQMLZA1150

cd eclair-M7630AABBQMLZA1150$

. ./setenv.sh

. ./make-image.sh

 

=======

modem代碼從高通網站:https://support.cdmatech.com/login/ 上獲取

我們目前使用的是:

共享在:

http://172.20.127.15/repositories/TD1002/trunk/modem-M7630AABBQMAZM1220

-------

編譯 modem 代碼

svn co http://172.20.127.15/repositories/TD1002/trunk/modem-M7630AABBQMAZM1220

cd modem-M7630AABBQMAZM1220

. ./setenv-qualcomm.sh

. ./make

========

編譯結果分別如下:

------------

其中 adsp.mbn,amss.mbn,dbl.mbn,osbl.mbn,partition.mbn 位於以下目錄:

./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/adsp.mbn

./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/amss.mbn

./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/dbl.mbn

./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/osbl.mbn

./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/partition.mbn

------------

appsboot.mbn,boot.img,system.img,userdata.img 位於以下目錄:

./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/appsboot.mbn

./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/boot.img

./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/system.img

./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/userdata.img

./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/system.img.ext3

./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/userdata.img.ext3

------------

eMMC 啓動使用的是 ext3 文件系統,需要使用鏡像 system.img.ext3 userdata.img.ext3

補充說明:

partition.mbn 文件的原始數據來自配置文件:

./AMSS/products/7x30/tools/jsdcc/partition_load_pt/partition.xml

 

 

1.3 高通平臺,android和 modem 編譯流程分析

android 代碼編譯流程分析

modem 代碼編譯流程分析

1.3.1 android代碼編譯流程分析

1.  從服務器下載 android 源碼到當前目錄

http://smartphone/repositories/TD1014/branch/froyo_almond-M76XXTSNCJNLYA6050-drivers/

svn co http://172.20.127.15/repositories/TD1014/trunk/froyo_almond-M76XXTSNCJNLYA6050/

cd froyo_almond-M76XXTSNCJNLYA6050/

. ./setenv.sh  設置環境變量

Setting Environment ...

通常情況下 generic 用於編譯模擬器版本

Options are:

     1. generic

     2. msm7627_surf

     3. msm7627_ffa

     4. tiny-system

====從以上列表中選擇====

Which would you like? [1]

 

燒錄的鏡像文件appsboothd.mbn  appsboot.mbn boot.img system.img userdata.img persist.img 來自 android 源碼

appsboot.mbn 的主要功能是裝載 linux 內核,通過 linux 的引導來完成 android 系統的加載,

appsboot.mbn 被燒寫在相應的分區,它的加載由 osbl.mbn 來完成, osbl.mbn 程序來自 modem。

7x30 7x27 系列 appsboot 不一樣,7x30 的 appsboot.mbn 是 7x27 appsboothd.mbn  appsboot.mbn 兩個文件的合併

 

1) appsboot.mbn 生成過程解析

2) boot.img 生成過程解析,怎樣手動生成 boog.img

 

1.3.1.1 編譯工具檢測

make out/target/product/msm7630_surf/appsboot.mbn

1.3.1.1.1  

1.3.1.2 appsboot.mbn 生成過程解析

make out/target/product/msm7630_surf/appsboot.mbn

make out/target/product/msm7630_surf/nandwrite

make out/target/product/msm7630_surf/emmc_appsboot.mbn

分別執行:

make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ msm7630_surf

make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/nandwrite msm7630_surf_nandwrite BUILD_NANDWRITE=1

make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_EMMC_OBJ msm7630_surf EMMC_BOOT=1

 

生成 nandwrite

===============

#build nandwrite as a part of Android Build

TARGET_NANDWRITE := $(PRODUCT_OUT)/obj/nandwrite/build-$(TARGET_PRODUCT)_nandwrite/lk

NANDWRITE_OUT := $(TOP)/$(TARGET_OUT_INTERMEDIATES)/nandwrite

 

nandwrite_clean:

    $(hide) rm -f $(TARGET_NANDWRITE)

    $(hide) rm -rf $(NANDWRITE_OUT)

 

$(NANDWRITE_OUT):

    mkdir -p $(NANDWRITE_OUT)

 

$(TARGET_NANDWRITE): nandwrite_clean $(NANDWRITE_OUT)

    @echo $(TARGET_PRODUCT)_nandwrite

    $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(TARGET_PRODUCT)_nandwrite BUILD_NANDWRITE=1

================

 

vim ./bootable/bootloader/lk/makefile:98:

TARGET   := msm7630_surf  #./bootable/bootloader/lk/project/msm7630_surf.mk

PLATFORM := msm7x30       #./bootable/bootloader/lk/target/msm7630_surf/rules.mk

msm7x30

msm7630_surf.mk

msm7630_surf_nandwrite

=============================

include project/$(PROJECT).mk

include target/$(TARGET)/rules.mk

include target/$(TARGET)/tools/makefile

include platform/$(PLATFORM)/rules.mk

include arch/$(ARCH)/rules.mk

include platform/rules.mk

include target/rules.mk

include kernel/rules.mk

include dev/rules.mk

include app/rules.mk

...

include make/module.mk

...

include make/build.mk

========================

vim bootable/bootloader/lk/make/module.mk

INCMODULES := $(MODULES)

$(info including $(INCMODULES))

include $(addsuffix /rules.mk,$(INCMODULES))

展開爲:

./bootable/bootloader/lk/app/nandwrite/rules.mk

./bootable/bootloader/lk/dev/fbcon/rules.mk

./bootable/bootloader/lk/dev/keys/rules.mk

./bootable/bootloader/lk/lib/debug/rules.mk

./bootable/bootloader/lk/lib/heap/rules.mk

./bootable/bootloader/lk/lib/libc/rules.mk

./bootable/bootloader/lk/lib/ptable/rules.mk

========================

bootable/bootloader/lk/make/build.mk:29:

include arch/$(ARCH)/compile.mk

 

 

./bootable/bootloader/lk/project/msm7630_surf_nandwrite.mk 中有:

MODULES += app/nandwrite

./bootable/bootloader/lk/platform/msm7x30/rules.mk中有:

MODULES += dev/fbcon

./bootable/bootloader/lk/kernel/rules.mk 中有:

MODULES += lib/libc lib/debug lib/heap

./bootable/bootloader/lk/target/msm7630_surf/rules.mk 中有:

MODULES += dev/keys lib/ptable

所以:

MODULES= app/nandwrite dev/fbcon dev/keys lib/debug lib/heap lib/libc lib/ptable

 

 

因爲

ifeq ($(BUILD_NANDWRITE), 1)

    APPSBOOTHDR_FILES :=

  else

out/host/linux-x86/bin/acp -fpt out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk out/target/product/msm7630_surf/nandwrite

 

 

  25780     184   34000   59964    ea3c ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk

arm-eabi-objcopy -O binary ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.bin

generating listing: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.lst

generating listing: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.debug.lst

generating symbols: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.sym

generating size map: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.size

make[2]:正在離開目錄 /opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/bootable/bootloader/lk

make[1]:正在離開目錄 /opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/bootable/bootloader/lk

target Prebuilt:  (out/target/product/msm7630_surf/nandwrite)


 


 

make -C bootable/bootloader/lk BOOTLOADER_OUT=./out/target/product/msm7630_surf/obj/nandwrite msm7630_surf_nandwrite BUILD_NANDWRITE=1

 

make[2]: 正在進入目錄 `/opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/bootable/bootloader/lk`

msm7630_surf_nandwrite

make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/nandwrite msm7630_surf_nandwrite BUILD_NANDWRITE=1

==》生成 mkheader 工具

gcc target/msm7630_surf/tools/mkheader.c -o target/msm7630_surf/tools/mkheader

 

$(BUILDDIR)/system-onesegment.ld: $(LOCAL_DIR)/system-onesegment.ld

    @echo generating $@

    @$(MKDIR)

    $(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/" < $< > $@

 

 

generating ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/system-onesegment.ld

compiling arch/arm/crt0.S

compiling arch/arm/crt0.S

。。。compiling lib/ptable/ptable.c

compiling lib/ptable/ptable.c

 

vim bootable/bootloader/lk/platform/msm7x30/rules.mk

-----

LINKER_SCRIPT += $(BUILDDIR)/system-onesegment.ld

include platform/msm_shared/rules.mk

-----

 

./build/core/product_config.mk:177:TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)

./build/core/envsetup.mk:152:OUT_DIR := $(TOPDIR)out

./build/core/envsetup.mk:159:TARGET_OUT_ROOT_release := $(OUT_DIR)/target

./build/core/envsetup.mk:161:TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))

./build/core/envsetup.mk:178:  TARGET_PRODUCT_OUT_ROOT := $(TARGET_OUT_ROOT)/product

./build/core/envsetup.mk:184:PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)

build/core/envsetup.mk:200:TARGET_OUT_INTERMEDIATES := $(PRODUCT_OUT)/obj

bootable/bootloader/lk/AndroidBoot.mk:4:BOOTLOADER_OUT := $(TOP)/$(TARGET_OUT_INTERMEDIATES)/BOOTLOADER_OBJ

bootable/bootloader/lk/makefile:32:BUILDDIR := $(BOOTLOADER_OUT)/build-$(PROJECT)

bootable/bootloader/lk/makefile:34:OUTELF := $(BUILDDIR)/lk

所以:

TARGET_PRODUCT_OUT_ROOT=out/target/product/

PRODUCT_OUT=out/target/product/msm7630_surf/

TARGET_OUT_INTERMEDIATES=out/target/product/msm7630_surf/obj/

BOOTLOADER_OUT=out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/

所以:

BUILDDIR=out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf

所以:

OUTELF=out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk

 

 

make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ msm7630_surf

 

 

bootable/bootloader/lk/makefile

OUTELF := $(BUILDDIR)/lk

./bootable/bootloader/lk/make/build.mk

$(OUTELF): $(ALLOBJS) $(LINKER_SCRIPT)

    @echo linking $@

    $(NOECHO)$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) $(ALLOBJS) $(LIBGCC) -o $@

 

 

 

vim ./bootable/bootloader/lk/AndroidBoot.mk

TARGET_NANDWRITE := $(PRODUCT_OUT)/obj/nandwrite/build-$(TARGET_PRODUCT)_nandwrite/lk

$(TARGET_NANDWRITE): nandwrite_clean $(NANDWRITE_OUT)

    @echo $(TARGET_PRODUCT)_nandwrite

    $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(TARGET_PRODUCT)_nandwrite BUILD_NANDWRITE=1

 

BOOTLOADER_EMMC_OUT := $(TOP)/$(TARGET_OUT_INTERMEDIATES)/BOOTLOADER_EMMC_OBJ

 

 

 

vim ./bootable/bootloader/lk/make/build.mk

$(OUTELF): $(ALLOBJS) $(LINKER_SCRIPT)

    @echo linking $@

    $(NOECHO)$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) $(ALLOBJS) $(LIBGCC) -o $@

 

bootable/bootloader/lk/makefile:33:OUTBIN := $(BUILDDIR)/lk.bin

bootable/bootloader/lk/makefile:34:OUTELF := $(BUILDDIR)/lk

 

 

./lk/platform/msm7x30/rules.mk:23:LINKER_SCRIPT += $(BUILDDIR)/system-onesegment.ld

 

 

==》鏈接 lk

linking ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk

linking ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk

generating image: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.bin

generating image: ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin

   text    data     bss     dec     hex filename

  29592    7388   42720   79700   13754 ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk

   text    data     bss     dec     hex filename

  25780     184   34000   59964    ea3c ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk

 

==》以 binary 格式,把文件 out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk 輸出到:

out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin

arm-eabi-objcopy -O binary out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin

 

==》

生成... out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.lst

生成... out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.debug.lst

生成... out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.sym

生成... out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.size

make[1]:正在離開目錄  /opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/bootable/bootloader/lk

==》

make -C kernel O=../out/target/product/msm7630_surf/obj/KERNEL_OBJ ARCH=arm CROSS_COMPILE=arm-eabi- msm7630-perf_defconfig

make[1]: 正在進入目錄 /opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/kernel

generating symbols: ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.sym

generating size map: ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.size

 

mkheader 從 lk.bin 生成 appsboothd.mbn 語法: mkheader <bin> <hdr>

然後把 appsboothd.mbn 和 lk.bin 合併爲文件 appsboot.mbn,刪除 appsboothd.mbn 文件

appsboothd.mbn 大小 40K

./bootable/bootloader/lk/target/msm7630_surf/tools/mkheader out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin out/target/product/msm7630_surf/appsboothd.mbn

合併 out/target/product/msm7630_surf/appsboothd.mbn out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin 爲:

out/target/product/msm7630_surf/appsboot.mbn

cat out/target/product/msm7630_surf/appsboothd.mbn out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin > out/target/product/msm7630_surf/appsboot.mbn

刪除:out/target/product/msm7630_surf/appsboothd.mbn

==================================================

1.3.1.3 boot.img 生成過程解析,怎樣手動生成 boog.img

boot.img 包括兩個部分: kernel 和 ramdisk ,通過命令:

make  out/target/product/msm7630_surf/boot.img showcommands

會自動生成 kernel 和 ramdisk,然後把兩者合併製作成燒寫的鏡像文件:boot.img

kernel 爲 out/target/product/$TARGET_PRODUCT/obj/KERNEL_OBJ/arch/arm/boot/zImage

或者 out/target/product/$TARGET_PRODUCT/kernel , kernel 是 zImage 的拷貝

編譯內核之前必須獲取一個默認的配置文件 .config ,此配置文件可以生成,或者來自默認配置,高通中 msm7630_surf 的

默認配置文件名爲: msm7630-perf_defconfig 在文件:

vendor/qcom/msm7630_surf/AndroidBoard.mk:45 中通過:

KERNEL_DEFCONFIG := msm7630-perf_defconfig 進行了指定。

我們可以通過命令:

make -j3 ARCH=arm CROSS_COMPILE=arm-eabi- kernel showcommands

或者通過如下命令一步步完成:

1. 獲取默認的內核配置並生成.config 的命令如下:

   make -C kernel O=../out/target/product/msm7630_surf/obj/KERNEL_OBJ ARCH=arm CROSS_COMPILE=arm-eabi- msm7630-perf_defconfig

   -C kernel 告訴 make 進入 kernel 工作目錄,到其下面尋找 makefile 文件

   O  內核編譯的中間文件以及編譯結果等都存儲在該目錄下,此做法的好處是不會在kernel源代碼目錄下生成垃圾文件

   ARCH=arm 告訴系統到 ./kernel/arch/$ARCH/configs/ 目錄下找文件 msm7630-perf_defconfig,生成的.config 保存在:

   out/target/product/msm7630_surf/obj/KERNEL_OBJ/.config

2. 手動編譯內核

   make -C kernel O=../out/target/product/msm7630_surf/obj/KERNEL_OBJ/

3. 如果需要配置內核,使用下面的命令

  make kernelconfig

  他首先會進入 menuconfig 界面,用戶配置完成以後,會把修改後的配置文件$(KERNEL_OUT)/.config 更新爲默認的配置文件

cp out/target/product/msm7627_ffa/obj/KERNEL_OBJ/.config kernel/arch/arm/configs/msm7627-perf_defconfig

  kernel/arch/arm/configs/$(KERNEL_DEFCONFIG)

 

4. 手動生成 ramdisk 執行命令

  make  out/target/product/msm7630_surf/ramdisk.img showcommands

    會用到命令:

  out/host/linux-x86/bin/mkbootfs out/target/product/msm7630_surf/root | out/host/linux-x86/bin/minigzip > \

  out/target/product/msm7630_surf/ramdisk.img

5. 手動生成 boot.img 需要使用命令 mkbootimg ,語法如下:

   mkbootimg --kernel 內核 --ramdisk ramdisk鏡像 --cmdline 命令行 --base 基地址 --pagesize 大小 --output 輸出的boot.img

 ==========

KERNEL=out/target/product/$TARGET_PRODUCT/kernel

KERNEL=out/target/product/$TARGET_PRODUCT/obj/KERNEL_OBJ/arch/arm/boot/zImage

RAMDISK=out/target/product/$TARGET_PRODUCT/ramdisk.img

CMDLINE="console=ttyDCC0 androidboot.hardware=qcom"

BASE=0x00200000

PAGESIZE=4096

OUTPUT=out/target/product/$TARGET_PRODUCT/boot.img

out/host/linux-x86/bin/mkbootimg  --kernel $KERNEL --ramdisk $RAMDISK --cmdline "$CMDLINE"  --base $BASE --pagesize $PAGESIZE --output $OUTPUT

=========================================

 

 

編譯 bootloader (appsboot.mbn) ,nandwrite 生成過程解析

./vendor/qcom/msm7630_surf/AndroidBoard.mk:25:

include bootable/bootloader/lk/AndroidBoot.mk

===================

因爲有:

bootable/bootloader/lk/AndroidBoot.mk:3:

TARGET_BOOTLOADER := $(PRODUCT_OUT)/appsboot.mbn

INSTALLED_BOOTLOADER_TARGET := $(PRODUCT_OUT)/bootloader

file := $(INSTALLED_BOOTLOADER_TARGET)

ALL_PREBUILT += $(file)

$(file): $(TARGET_BOOTLOADER) | $(ACP)

        $(transform-prebuilt-to-target)

所以拷貝:

out/target/product/msm7630_surf/appsboot.mbn

爲:

out/target/product/msm7630_surf/bootloader

====================

因爲有:

./bootable/bootloader/lk/AndroidBoot.mk:38:

TARGET_NANDWRITE := $(PRODUCT_OUT)/obj/nandwrite/build-$(TARGET_PRODUCT)_nandwrite/lk

# Copy nandwrite utility to target out directory

INSTALLED_NANDWRITE_TARGET := $(PRODUCT_OUT)/nandwrite

file := $(INSTALLED_NANDWRITE_TARGET)

ALL_PREBUILT += $(file)

$(file) : $(TARGET_NANDWRITE) | $(ACP)

        $(transform-prebuilt-to-target)

endif

所以拷貝:

out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk

爲:

out/target/product/msm7630_surf/nandwrite

=====================

編譯內核:

#----------------------------------------------------------------------

# Compile Linux Kernel

#----------------------------------------------------------------------

ifeq ($(KERNEL_DEFCONFIG),)

    KERNEL_DEFCONFIG := msm7630-perf_defconfig

endif

include kernel/AndroidKernel.mk

======================

 

編譯 appsboot.mbn

源代碼位於: bootable/bootloader/lk/

因爲:

vendor/qcom/msm7630_surf/BoardConfig.mk:60:

TARGET_USERIMAGES_USE_EXT2 := true

所以:分別編譯支持nand 和 emmc啓動的 appsboot.mbn

===================

bootable/bootloader/lk/AndroidBoot.mk

$(TARGET_BOOTLOADER): appsbootldr_clean emmc_appsbootldr_clean $(BOOTLOADER_OUT) $(BOOTLOADER_EMMC_OUT)

        $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(BOOTLOADER_OUT) $(TARGET_PRODUCT)

        $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(BOOTLOADER_EMMC_OUT) $(TARGET_PRODUCT) EMMC_BOOT=1

 

$(TARGET_NANDWRITE): nandwrite_clean $(NANDWRITE_OUT)

        @echo $(TARGET_PRODUCT)_nandwrite

        $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(TARGET_PRODUCT)_nandwrite BUILD_NANDWRITE=1

====================

-C 表明到目錄 bootable/bootloader/lk 下找 makfile 文件

bootable/bootloader/lk/makefile

====================

bootable/bootloader/lk/makefile:87:

include target/$(TARGET)/tools/makefile

bootable/bootloader/lk/target/msm7630_surf/tools/makefile

====================

appsboot.mbn: appsboothd.mbn $(OUTBIN)

        cat $(APPSBOOTHEADER_DIR)/appsboothd.mbn $(OUTBIN) > $(APPSBOOTHEADER_DIR)/appsboot.mbn

        rm -f $(APPSBOOTHEADER_DIR)/appsboothd.mbn

 

appsboothd.mbn: mkheader $(OUTBIN)

        $(SRC_DIR)/mkheader $(OUTBIN) $(APPSBOOTHEADER_DIR)/appsboothd.mbn

 

========================================

hexdump out/target/product/msm7630_surf/appsboothd.mbn

40個字節的內容如下:

-----

0000000 0005 0000 0002 0000 0000 0000 0000 0000

0000010 9074 0000 9074 0000 9074 0000 0000 0000

0000020 9074 0000 0000 0000                   

0000028

-----

我們編譯的:

0000000 0005 0000 0002 0000 0000 0000 0000 0000

0000010 9074 0000 9074 0000 9074 0000 0000 0000

0000020 9074 0000 0000 0000

高通的:

0000000 0005 0000 0002 0000 0000 0000 0000 0010

0000010 99ac 0000 99ac 0000 99ac 0010 0000 0000

0000020 99ac 0010 0000 0000

 

 

 

We found that the contents of the first 40 bytes is not the same

 

hexdump  out/target/product/msm7630_surf/appsboot.mbn > bbk.txt

hexdump  ~/appsboot.mbn > qualcomm > qualcomm.txt   (appsboot.mbn from Qualcomm, can properly programmed system.img)

 

the first 40 bytes below:

Content from the compilation:

0000000 0005 0000 0002 0000 0000 0000 0000 0000

0000010 9074 0000 9074 0000 9074 0000 0000 0000

0000020 9074 0000 0000 0000

Content from the Qualcomm:

0000000 0005 0000 0002 0000 0000 0000 0000 0010

0000010 99ac 0000 99ac 0000 99ac 0010 0000 0000

0000020 99ac 0010 0000 0000

========

Analysis of the generation of appsboot.mbn,from the command:

cat out/target/product/msm7630_surf/appsboothd.mbn out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin > out/target/product/msm7630_surf/appsboot.mbn

we known ,appsboot.mbn consists of two parts: appsboothd.mbn and lk.bin;

appsboothd.mbn come form command:

./bootable/bootloader/lk/target/msm7630_surf/tools/mkheader out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin out/target/product/msm7630_surf/appsboothd.mbn

 

1.3.1.4 編譯過程存在的問題

1.3.1.4.1 prelinkmap 的時候 base 0xaff00000 out of range

build/tools/apriori/prelinkmap.c(100): build/core/prelink-linux-arm.map:13 base 0xaff00000 out of range.

./build/tools/apriori/prelinkmap.c:99:                  

"%s:%d base 0x%08x out of range.\n",

1.3.1.4.2 LOCAL_SDK_VERSION 使應用程序不能訪問hide的api

LOCAL_SDK_VERSION 會使應用程序不能訪問hide的api,如果要訪問自定義的api,那麼在個應用的Android.mk 文件中屏蔽掉 LOCAL_SDK_VERSION := current

./packages/apps/Mms/Android.mk:13:#LOCAL_SDK_VERSION := current

./packages/apps/BBKMms/Android.mk:13:#LOCAL_SDK_VERSION := current

./packages/apps/Camera/Android.mk:9:# LOCAL_SDK_VERSION := current

 

1.3.1.4.3 armv5te-vfp 編譯配置,導致一些遊戲運行不了

device/qcom/msm7627_ffa/BoardConfig.mk:56:

TARGET_ARCH_VARIANT := armv5te-vfp

 

build/core/combo/TARGET_linux-arm.mk:37:

TARGET_ARCH_SPECIFIC_MAKEFILE := $(BUILD_COMBOS)/arch/$(TARGET_ARCH)/$(TARGET_ARCH_VARIANT).mk

......

$(TARGET_ARCH_SPECIFIC_MAKEFILE)

 

 

build/core/combo/arch/arm/armv5te-vfp.mk:6:

include $(BUILD_COMBOS)/arch/arm/armv5te.mk

 

 

                    

build/core/combo/TARGET_linux-arm.mk:209:   

如果 WITH_JIT 沒有賦值,那麼在文件 TARGET_linux-arm.mk 中會設置 WITH_JIT 默認值爲 true

# Enable the Dalvik JIT compiler if not already specified.

ifeq ($(strip $(WITH_JIT)),)

    WITH_JIT := true

Endif

 

 

dalvik/vm/Android.mk

 

 

 

 

 

 

 

 

 

 

 

1.3.2 分佈式編譯 android 代碼

編譯服務安裝過程

1. unzip distcc.zip

2. cd distcc

3. chmod u+x installdistcc3.0.sh

4. sudo ./installdistcc3.0.sh

編譯過程

5. cp setenv-dp.sh path to android source code root

6. . ./setenv-dp.sh

7. make -j24

 

1.3.3 modem 代碼編譯流程分析

從 svn 下載 modem 源代碼,進入其根目錄

svn co http://172.20.127.15/repositories/TD1014/trunk/modem-M76XXTSNCJNLYM6050/

首先執行環境變量設置腳本

cd modem-M76XXTSNCJNLYM6050

. ./setenv-qualcomm.sh

編譯程序執行腳本

. ./make-TFNCKNLYM.sh

 

#!/bin/bash

echo ". ./AMSS/products/76XX//build/ms/bbkTFNCKNLYM.cmd $1"

. ./AMSS/products/76XX//build/ms/bbkTFNCKNLYM.cmd  $1

 

AMSS/products/76XX/build/ms/bbkTFNCKNLYM.cmd

cd ./AMSS/products/76XX//build/ms

. ./TFNCKNLYM.cmd $1

cd –

 

./AMSS/products/7x30//build/ms/AAABQOLYM.cmd

AMSS/products/76XX/build/ms/TFNCKNLYM.cmd

make -r -f dmss76XXmodem.mak BUILD_UNIX=yes IMAGE=MODEM_PROC USES_SEC_CLNT=yes USES_MDDI=yes USES_CRYPTOMINCS=yes USES_RUIM=yes USES_PDCP=yes USES_HAL=yes USES_HSU_CHG_BOOT=yes USES_PMEM_REMOTE=yes USES_SDCC=yes USES_SUPPORT_UMTS_GPS_PROTOCOLS=yes USES_CDMA=yes USES_HSU_FAST_CHARGE=yes USES_CHARGER=yes USES_HSU_OTG=yes USES_ERR_SERVICES=yes USES_UMTS=yes USES_FTM_BT_MODEM_DUALPROC=yes USES_SMD_PORT_MGR=yes USES_SPLIT_CODE_DATA=yes USES_EXPORT_7K_APIS=yes USES_EBI1_TURBO_FFA=yes USES_SEC=yes USES_HDR=yes USES_DDR32_CFG_DATA=yes USES_HSU=yes USES_ONCRPC=yes USES_PHLP_XCVR=yes USES_SFS=yes USES_EFS2=yes USES_STRIP_NO_ODM=yes USES_SMD=yes USES_FEATURE_CGPS_XTRA=yes USES_VOCRTCV=yes USES_HS_USB_CHG_REMOTE_API=yes USES_CGPS=yes USES_FLASH_DAL=yes USES_ARM_ASM_SPINLOCK=yes USES_REL_C=yes USES_OEM_RAPI=yes USES_FEATURE_CGPS_XTRA_T=yes USES_IGUANA=yes USES_DAL=yes USES_LINUX_BT=yes USES_IPHC=yes USES_SEC_SVC=yes USES_ONCRPC_PROXY=yes USES_ONCRPC_ROUTER=yes USES_ONCRPC_CB=yes USES_NO_DEBUG=yes USES_DOG_KEEPALIVE=yes USES_HW7500=yes USES_VOCVP3=yes USES_VGA_CONTENT=yes USES_CGPS_SEC=yes USES_AUTH=yes USES_SMEM=yes USES_PICT_BRIDGE=yes USES_QOS=yes USES_BUS_MON_AXI_BUS_HANG_FIXED=yes USES_L4=yes USES_SBI=yes USES_HSU_MS_FD=yes USES_UIM=yes USES_IMG_UPDATE=yes USES_I2C_ON_APPS=yes USES_RPC_ROUTER_XAL_SMD=yes USES_CDMA2000=yes USES_SMEM_LOG=yes USES_EXPORT_MCCMEID=yes USES_NAND8_2K_CFG_DATA=yes USES_BUILD_NATIVELINUX_MODEM=yes USES_GSTK=yes USES_PS_DUN=yes USES_DEM=yes USES_DDR_ONLY=yes USES_DMOV=yes USES_HSU_ECM=yes USES_SUPPORT_CDMA_GPS_PROTOCOLS=yes USES_MBCBASBA=yes USES_BUS_PERF=yes USES_HIGH_POWER_CLK_FREQUENCY_PLAN=yes USES_GZRF6500=yes ASIC=76XXT BUILD=TFNCKNLYM VERSION=6050 BUILDDIR=TFNCKNLYM $1

 

1.3.3.1 單獨編譯某個模塊(如:qcsbl oemsbl)

編譯 modem   的主 makefile 文件爲 AMSS/products/76XX/build/ms/dmss76XXmodem.mak

. ./make-TFNCKNLYM.sh genqcsbl  單獨生成

. ./make-TFNCKNLYM.sh genoemsbl

 

./AMSS/products/76XX/build/ms/boot_targets_sec.min:1200

genqcsbl: $(MBNPATH_QCSBL)/qcsbl.mbn $(CERTDIR_QCSBL)/exist

./AMSS/products/76XX/build/ms/boot_targets_nonsec.min:870:

genqcsbl: $(MBNPATH)/qcsbl.mbn

./AMSS/products/76XX/build/ms/dmss76XXmodem.mak:49:

ifeq ($(USES_SECBOOT),yes)

   SEC_MODE = sec

else

   SEC_MODE = nonsec

endif

include boot_targets_$(SEC_MODE).min

./AMSS/products/76XX/build/ms/boot_targets_sec.min:108:

SECBOOT=$(SRCROOT)/secboot

./AMSS/products/76XX/build/ms/boot_targets_nonsec.min:107:

SECBOOT=$(SRCROOT)/secboot

 

./AMSS/products/76XX/build/ms/boot_targets_nonsec.min:872:

genoemsbl: $(MBNPATH)/oemsbl.mbn $(OEMSBL_HD_FILE_NAME)

./AMSS/products/76XX/build/ms/bin/TFNCKNLY/oemsbl.mbn

./AMSS/products/76XX/build/ms/bin/TFNCKNLY/oemsblhd.mbn

 

 

AMSS/products/76XX/build/ms/dmss76XXmodem.mak

...

all : dmss

...

include dmss_flags.min

include dmss_76XXT_flags.min

include incpaths.min

include armtools.min

-include amss_lint_flags.min

include dmss_objects.min

include boot_targets_$(SEC_MODE).min

...

include dmss_rules.min

-include amss_lint_rules.min

...

corebsp_build : corebsp_build_action corebsp_create_incpaths corebsp_setup

 

.PHONY: corebsp_build_action

corebsp_build_action :

ifeq ($(USES_COREBSP_BUILD_SYSTEM), yes)

    $(warning COREBSP Build System Enabled)

    @echo ================= COREBSP Build =======================================

    @echo COREBSP Build System and AMSS Objects

    #$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak $(MAKEFLAGS)

 

    $(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak

    #$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak -rk

    @echo COREBSP AMSS Libraries

   @if test -f $(COREBSP_BUILD)/msm7x30_lib.mak; then $(MAKE) -f $(COREBSP_BUILD)/msm7x30_lib.mak corebsplibs ; fi

    @echo ================= COREBSP Build Done ==================================

else

    $(warning COREBSP Build System Disabled)

    include $(COREBSP_BUILD)/dmss_objects.min

    OBJECTS := $(OBJECTS) $(COREBSP_OBJECTS)

    QCTLIBS := $(QCTLIBS) $(COREBSP_QCTLIBS)

Endif

...

編譯規則從 all : dmss 開始

dmss 規則 在文件 ./AMSS/products/7x30/build/ms/dmss_rules.min 中

...

ifeq ($(USES_L4), yes)

    ifeq ($(IMAGE), APPS_PROC)

        ifeq ($(USES_BUILD_NATIVELINUX_APPS), yes)

        #dmss : $(TARGETDIR)/exist setup firmware prereqs deps corebsp_build libs copybar exe bldprod

        dmss : $(TARGETDIR)/exist prereqs exe bldprod

    else

        #dmss : $(TARGETDIR)/exist setup firmware prereqs deps corebsp_build libs copybar exe bldprod

        dmss : $(TARGETDIR)/exist setup prereqs exe bldprod

    endif

    else

    ifneq ($(USES_OBJECT_ONLY), yes)

        ifeq ($(USES_SDCC_BOOT), yes)

            dmss : $(TARGETDIR)/exist setup firmware prereqs deps corebsp_build libs copybar exe bldprod create_mem_feat_html partition

        else

            dmss : $(TARGETDIR)/exist setup firmware prereqs deps corebsp_build libs copybar exe bldprod create_mem_feat_html

        endif

    else

        ifeq ($(USES_SDCC_BOOT), yes)

        dmss : $(TARGETDIR)/exist setup deps corebsp_build libs copybar exe bldprod create_mem_feat_html partition

        else

            dmss : $(TARGETDIR)/exist setup deps corebsp_build libs copybar exe bldprod create_mem_feat_html

        endif

    endif

    endif

endif

...

.PHONY: setup

setup : corebsp_create_incpaths create_incpaths amsssetup amsslinkaddress firmware

...

BUILDID 爲 AAABQOLYM 的腳本,比較關心的編譯選項有:

BUILD_UNIX=yes

USES_L4=yes

IMAGE=MODEM_PROC

USES_LPDDR2=yes

USES_SDCC=yes

USES_SDCC_BOOT=yes

所以 dmss 規則爲:

dmss : $(TARGETDIR)/exist setup deps corebsp_build libs copybar exe bldprod create_mem_feat_html partition

 

下面將分別對這些規則進行分析:

1.3.3.2 $(TARGETDIR)/exist 規則解析

1.3.3.3 setup規則解析

setup : corebsp_create_incpaths create_incpaths amsssetup amsslinkaddress firmware

1.3.3.3.1 corebsp_create_incpaths

1.3.3.3.2 create_incpaths

1.3.3.3.3 amsssetup

1.3.3.3.4 amsslinkaddress

amsslinkaddress 規則在文件:

./AMSS/products/7x30/build/ms/dmss_rules.min:871 中

amsslinkaddress : amsssetup

    @echo Generate AMSS Link Address file: $(CUSTL4SCLFILE).....

    @$(GEN_AMSS_LINK_ADDRESS)

amsssetup : create_incpaths

 

GEN_AMSS_LINK_ADDRESS 執行的是文件:

./AMSS/products/7x30/build/ms/dmss_rules.min:696 中的函數

。。。

L4_BASE_DIR := ../../core/kernel

AMSS_RELOC_DIR := build_$(BUILD_KCFG)/amss/bin

PLATMSDIR := ../../core/kernel/build_$(BUILD_KCFG)/ms

ELFWEAVER_CMD = python tools/pyelf/elfweaver

define GEN_AMSS_LINK_ADDRESS

    @echo --------------------------------------------------------

    @echo Determining AMSS link address from target XML file...

    @-if test -f $(CUSTL4SCLFILE); then rm $(CUSTL4SCLFILE); fi

    @echo "#ifndef CUST_L4_SCL_$(BUILD_KCFG)_H" >> $(CUSTL4SCLFILE)

    @echo "#define CUST_L4_SCL_$(BUILD_KCFG)_H" >> $(CUSTL4SCLFILE)

    @echo -n "#define SCL_L4_START_ADDRESS " >> $(CUSTL4SCLFILE)

    @echo Preprocessing XML file into quartz_cfg_$(BUILD)_cpp.xml...

 

    @echo Preprocessing XML file into quartz_cfg_machine_$(BUILD)_cpp.xml...

    $(CC) -E $(CFLAGS) $(DMSS_CFLAGS) $(ALL_INCLUDES) $(DIRNAME) -I"$(ARMINC)" $(BUILD_VERSION) $(APPFLAGS) $(MSG_BT_SSID) $(OBJ_CMD) quartz_cfg_machine_$(BUILD)_cpp.xml quartz_cfg_machine.xml

    @echo Copying cleaned XML file to quartz_cfg_machine_$(BUILD).xml...

    ./cleanup_xml.pl -i quartz_cfg_machine_$(BUILD)_cpp.xml -o quartz_cfg_machine_$(BUILD).xml

    rm -f quartz_cfg_machine_$(BUILD)_cpp.xml

 

    @echo Preprocessing XML file into quartz_cfg_$(BUILD)_cpp.xml...

    $(CC) -E $(CFLAGS) -DAMSS_RELOC_LC=\"$(AMSS_RELOC_DIR)/$(BUILD_LC).reloc\" -DQUARTZ_MACHINE_XML=\"../../build/ms/quartz_cfg_machine_$(BUILD).xml\" $(DMSS_CFLAGS) $(COREBSP_XALL_INCLUDES) $(ALL_INCLUDES) $(DIRNAME) -I"$(ARMINC)" -I"../../core/systemdrivers/hwio/chipset/msm7x30/inc/plat/l4" $(BUILD_VERSION) $(APPFLAGS) $(MSG_BT_SSID) $(OBJ_CMD) quartz_cfg_$(BUILD)_cpp.xml quartz_cfg.xml

    @echo Copying cleaned XML file to quartz_cfg_$(BUILD).xml...

    ./cleanup_xml.pl -i quartz_cfg_$(BUILD)_cpp.xml -o quartz_cfg_$(BUILD).xml

    rm -f quartz_cfg_$(BUILD)_cpp.xml

 

    @echo Determining AMSS link address...

    @cd $(L4_BASE_DIR); $(ELFWEAVER_CMD) merge ../../build/ms/quartz_cfg_$(BUILD).xml --ignore="AMSS" --lastphys="physical" >> ../../build/ms/$(CUSTL4SCLFILE)

    @echo "#endif" >> $(CUSTL4SCLFILE)

    @echo Done.

    @echo ------------------------------------------------------------------

。。。

 

@echo Generate AMSS Link Address file: $(CUSTL4SCLFILE).....

中的 CUSTL4SCLFILE 爲: cust_l4_scl_M.h

@echo "#ifndef CUST_L4_SCL_$(BUILD_KCFG)_H" >> $(CUSTL4SCLFILE)

@echo "#define CUST_L4_SCL_$(BUILD_KCFG)_H" >> $(CUSTL4SCLFILE)

@echo -n "#define SCL_L4_START_ADDRESS " >> $(CUSTL4SCLFILE)

@echo "#endif" >> $(CUSTL4SCLFILE)

輸出文件 ./AMSS/products/7x30/build/ms/cust_l4_scl_M.h ,內容爲:

#ifndef CUST_L4_SCL_M_H

#define CUST_L4_SCL_M_H

#define SCL_L4_START_ADDRESS 0x4864000

#endif

 

 

/home/gphone/ARM//RVCT/Programs/2.2/593/linux-pentium/tcc -E -c --cpu ARM1136J-S --apcs /noswst/interwork --littleend --force_new_nothrow -Otime -O1 -O1 -DT_ARM -D__ARMEL__ -DCUST_H="custaabbqolym.h" -D__MSMHW_APPS_PROC__=2 -D__MSMHW_MODEM_PROC__=1 -D__MSMHW_PROC_DEF__=__MSMHW_MODEM_PROC__ -DMSMHW_MODEM_PROC -DIMAGE_MODEM_PROC -DASSERT=ASSERT_FATAL -I../../core/api/systemdrivers/hwio/msm7x30/inc -I../../core/api/systemdrivers/hwio/msm7x30/inc/plat/l4/user -I../../core/api/systemdrivers/hwio/msm7x30/inc/proc/modem -I../../apps/nonpkbrew/pk/inc/msm -I../../apps/nonpkbrew/pk/inc -I../../apps/nonpkbrew/pk/src -I../../apps/nonpkbrew/pk/src/msm -I../../apps/nonpkbrew/pk/../sdk/inc -I../../apps/brew/sdk/inc -I../../apps/brew/inc -I../../apps/brew/pk/inc/msm -I../../apps/brew/pk/inc -I../../apps/brew/pk/src -I../../apps/brew/src/OEM -I../../apps/brew/pk/src/msm -I../../apps/brew/inc/OEM -I../../apps/brew/src/OEM/msm -I../../apps/brew/src/OEM/OEMNotify/inc -I../../apps/brew/src/OEM/OEMConfigItem/inc -I../../apps/brew/src/OEM/OEMSound -I../../apps/brew/src/OEM/OEMSysClock/msm -I../../apps/brew/src/OEM/OEMShellBeep -I../../apps/brew/src/OEM/OEMServingNetworks/msm -I../../apps/brew/src/OEM/OEMAnnunciatorControl -I../../multimedia/adsp_diag -I../../apps/staticextensions/inc -I../../apps/staticextensions/oem/inc -I../../apps/staticextensions/oem/src -I../../wconnect/bthost/soccfg/inc -I../../wconnect/bthost/ftm/inc -I../../modem/uim/gstk/inc -I../../modem/uim/gstk/src -I../../modem/uim/estk/inc -I../../modem/uim/estk/src -I../../apps/DynamicExtensions/IMediaVideo -I../../modem/uim/dctstk/src -I../../core/api/hwengines -I../../multimedia/api/adsprtossvc -I../../core/securemsm/ipsec/inc -I../../core/securemsm/ipsec/src -I../../core/securemsm/akaalgo/inc -I../../core/securemsm/akaalgo/src -I../../wconnect/api/rapi/wlanhs/inc -I../../wconnect/api/wlanhs --via ../../build/ms/corebsp.inc --via ../../build/ms/M7X30AABBQOLYM/M7X30AABBQOLYM.inc -I../../modem/qchat/inc -I ../../modem/wms/src/CMCNas/inc -I/home/gphone/ARM//RVCT/Data/2.2/349/include/unix -DBUILD_ASIC="7X30A" -DBUILD_TARGET="AABBQOLYM" -DBUILD_VER="1250" -o quartz_cfg_machine_AABBQOLYM_cpp.xml quartz_cfg_machine.xml

 

PLATMSDIR := ../../core/kernel/build_$(BUILD_KCFG)/ms

拷貝文件

./AMSS/products/7x30/build/ms/loadsyms_M.cmm

./AMSS/products/7x30/build/ms/loadsyms_M.men

./AMSS/products/7x30/build/ms/quartz_constants_M.cmm

 

./AMSS/products/7x30/core/kernel/build_M/ms/

 

 

------------------------------------------------------------------

Generate AMSS Link Address file: cust_l4_scl_M.h.....

------------------------------------------------------------------

Determining AMSS link address from target XML file...

Preprocessing XML file into quartz_cfg_AABBQOLYM_cpp.xml...

Preprocessing XML file into quartz_cfg_machine_AABBQOLYM_cpp.xml...

Copying cleaned XML file to quartz_cfg_machine_AABBQOLYM.xml...

Preprocessing XML file into quartz_cfg_AABBQOLYM_cpp.xml...

Copying cleaned XML file to quartz_cfg_AABBQOLYM.xml...

Determining AMSS link address...

Done.

 

1.3.3.3.5 firmware

1.3.3.4 deps規則解析

1.3.3.5 corebsp_build規則解析

corebsp_build : corebsp_build_action corebsp_create_incpaths corebsp_setup

corebsp_build 規則包括三個過程:

corebsp_build_action

corebsp_create_incpaths

corebsp_setup

通過命令 . ./make-AAABQOLYM.sh corebsp_build 可以單獨對 corebsp_build 部分進行編譯。

 

1.3.3.5.1 corebsp_build_action

corebsp_build_action :

ifeq ($(USES_COREBSP_BUILD_SYSTEM), yes)

    $(warning COREBSP Build System Enabled)

    @echo ================= COREBSP Build ====================================

    @echo COREBSP Build System and AMSS Objects

    #$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak $(MAKEFLAGS)

 

    $(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak

    #$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak -rk

    @echo COREBSP AMSS Libraries

   @if test -f $(COREBSP_BUILD)/msm7x30_lib.mak; then $(MAKE) -f $(COREBSP_BUILD)/msm7x30_lib.mak corebsplibs ; fi

    @echo ================= COREBSP Build Done ================================

else

    $(warning COREBSP Build System Disabled)

    include $(COREBSP_BUILD)/dmss_objects.min

    OBJECTS := $(OBJECTS) $(COREBSP_OBJECTS)

    QCTLIBS := $(QCTLIBS) $(COREBSP_QCTLIBS)

endif

因爲:

USES_COREBSP_BUILD_SYSTEM=yes

$(COREBSP_BUILD)/msm7x30_lib.mak  文件不存在

所以 corebsp_build_action  規則

執行語句:$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak

...

all : corebsp_scons corebsp

 

1.3.3.5.1.1 corebsp_scons 規則

./AMSS/products/7x30/core/bsp/build/dmss_rules.min 中。

 

corebsp_scons 包括三個部分:

corebsp_scons_start  顯示信息  @echo Building CoreBSP 創建目錄 mkdir -p $(COREBSP_BUILD)/data

corebsp_scons_action 主體部分

corebsp_scons_done   顯示信息  @echo Completed CoreBSP

 

1.3.3.5.1.1.1 corebsp_scons_start

2.3.3.5.1.1.1 corebsp_scons_action

corebsp_scons_action 規則在文件 ./AMSS/products/7x30/core/bsp/build/dmss_rules.min:263 中,它完成核心bsp的編譯。

./AMSS/products/7x30/core/bsp/tools/emmcbld/build/emmcbld.mbn

./AMSS/products/7x30/core/bsp/tools/flash/ehostdl/build/enandprg_AABBQOLYM.mbn

./AMSS/products/7x30/build/ms/bin/AABBQOLY/adsp.mbn

./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/AMSS_AABBQOLYM.mbn

./AMSS/products/7x30/core/bsp/tools/flash/hostdl/build/nandprg_AABBQOLYM.mbn

./AMSS/products/7x30/build/ms/bin/AABBQOLY/partition.mbn

./AMSS/products/7x30/core/bsp/bootloaders/partition/build/partition_AABBQOLYM.mbn

./AMSS/products/7x30/build/ms/bin/AABBQOLY/osbl.mbn

./AMSS/products/7x30/core/bsp/bootloaders/osbl/build/osbl_AABBQOLYM.mbn

./AMSS/products/7x30/build/ms/bin/AABBQOLY/fsbl.mbn

./AMSS/products/7x30/core/bsp/bootloaders/fsbl/build/fsbl_AABBQOLYM.mbn

./AMSS/products/7x30/build/ms/bin/AABBQOLY/dbl.mbn

./AMSS/products/7x30/core/bsp/bootloaders/dbl/build/dbl_AABBQOLYM_preamble.mbn

./AMSS/products/7x30/core/bsp/bootloaders/dbl/build/dbl_AABBQOLYM.mbn

以上各部分都是在此過程中完成。

corebsp_scons_action : corebsp_genincpaths corebsp_genuses

    @echo -------------------------------------------------------------------

    $(scons_builder)

    @echo -------------------------------------------------------------------

 

corebsp_genincpaths :

產生基於 AMSS 的頭文件信息,通過下面命令完成。

perl $(COREBSP_BUILD)/scripts/genpaths.pl -min incpaths.min -buildid $(BUILD) -makeflags "$(MAKEFLAGS)" > $(COREBSP_BUILD)/data/incpaths$(BUILD_LC).py

$(COREBSP_BUILD)/scripts/genpaths.pl        

爲文件:

./AMSS/products/7x30/core/bsp/build/scripts/genpaths.pl

$(COREBSP_BUILD)/data/incpaths$(BUILD_LC).py

爲文件:

./AMSS/products/7x30/core/bsp/build/data/incpathsaaabqmazm.py

 

corebsp_genuses:

$(scons_builder)

$(scons_builder) 的調用在文件 ./AMSS/products/7x30/core/bsp/build/dmss_rules.min:180:中

 

 

define scons_builder

        -chmod +x $(COREBSP_BUILD)/../tools/SCons/scons

        cd $(COREBSP_BUILD); \

        ../tools/SCons/scons$(SCONS_EXT) $(PLATFORM) CHIPSET=$(CHIPSET) BUILD_ID=$(BUILDID) BUILD_VER=$(VERSION) \

                MSM_ID=$(BUILD_MSM_ID) HAL_PLATFORM=$(HAL_PLAT) BUILD_ASIC=$(BUILD_ASIC) TARGET_FAMILY=$(TARGET_FAMILY) \

                --verbose=$(VERBOSE) --frommake $(MAKE_FLAGS)

endef

 

COREBSP_BUILD 等於 ${SRCROOT}/core/bsp/build

./AMSS/products/7x30/core/bsp/tools/SCons/scons

所以 scons_builder 實際執行了以下命令:

chmod +x ./AMSS/products/7x30/core/bsp/tools/SCons/scons

cd ./AMSS/products/7x30/core/bsp/build

./AMSS/products/7x30/core/bsp/tools/SCons/scons modem CHIPSET=msm7x30 BUILD_ID=AAABQMAZ BUILD_VER=1220 MSM_ID=7x30 HAL_PLATFORM=7x30 BUILD_ASIC=7X30A TARGET_FAMILY=7630 --verbose=0 –frommake

 

 

1.3.3.5.1.1.2.1 命令 pboot_gen_elf image_header pboot_add_hash 解析

pboot_gen_elf image_header pboot_add_hash 是編譯過程中用到的幾個工具

編譯過程中常用的幾個工具

命令 ./AMSS/products/7x30/tools/headergen/pboot_gen_elf 用法:

pboot_gen_elf [-d] elf_file scl_file output_elf output_hash

或者:

pboot_gen_elf [-d] elf_file output_hash

-d           - debug 模式

elf_file     - 格式爲ELF的輸入文件,它由linker生成

scl_file     - input progressive boot scatter load file

output_elf   - output ELF file

output_hash  - output hash table

例如:

PBOOT_GEN_ELF=./AMSS/products/7x30/tools/headergen/pboot_gen_elf

elf_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.pbn

output_hash=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.hash

$PBOOT_GEN_ELF  $elf_file $output_hash

 

命令 ./AMSS/products/7x30/tools/headergen/image_header  用法:

image_header flash_type header_type input_code_file output_header_file secure_type [dbl_preamble_file or elf_src_file]

flash_type         -  flash 類型:nand 或者 nor

header_type        -  頭類型可以爲: dbl, dbl_preamble, osbl, appsbl, apps, amsshash, hostdl, ehostdl, dsp1hash, dsp2hash

input_code_file    - 用於生成文件頭的輸入文件

output_header_file - 生成的文件頭

secure_type        -  'secure' or 'nonsecure'

dbl_preamble_file  - 當 header_type 等於 'dbl_preamble' 的時候指向 dbl preamble 文件的路徑

elf_src_file       - 當 header_type 等於 'hash' 的時候指向 elf file corresponding to hash table 的路徑

例如:

=============

IMAGE_HEADER=./AMSS/products/7x30/tools/headergen/image_header

flash_type=nand

header_type=amsshash

input_code_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.hash

output_header_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.hash.hd

secure_type=nonsecure

dbl_preamble_file=

elf_src_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.pbn

$IMAGE_HEADER  $flash_type $header_type $input_code_file $output_header_file $secure_type $elf_src_file

 

命令 AMSS/products/7x30/tools/headergen/pboot_add_hash 用法:

把 hash 頭和 hash 表插入到 ELF文件作爲起始段 ,在物理內存中它實際在最後。

pboot_add_hash [-d] elf_file hash_table output_elf

-d            - debug 模式

elf_file      - the ELF file

hash_table    - hash table (signed or not)

output_elf    - final output

PBOOT_ADD_HASH=./AMSS/products/7x30/tools/headergen/pboot_add_hash

elf_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.pbn

hash_table=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.hash_nonsec.mbn

output_elf=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.mbn

$PBOOT_ADD_HASH  $elf_file  $hash_table  $output_elf

 

1.3.3.5.1.1.2.2env.BinBuilder 過程解析

 

1.3.3.5.1.1.2.3 env.MbnBuilder 過程解析

mbn 類型的文件是我們最終燒寫到板子上的鏡像文件

在文件: ./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py 中有 mbn 文件的編譯規則,要注意的是,不同的 modem 源代碼版本,它裏面的規則有可能不一樣。

1220 以及之前的版本,編譯規則中有:

def mbn_generate(env):

   #-------------------------------------------------------------------------

   # MBN builder definition

   #-------------------------------------------------------------------------

   mbn_act = env.GetBuilderAction(mbn_builder)

   mbn_bld = env.Builder(action = mbn_act,

                         emitter = mbn_emitter,

                         suffix = '.mbn')

 

   env.Append(BUILDERS = {'MbnBuilder' : mbn_bld})

  

   mbn_dummy_act = env.GetBuilderAction(mbn_dummy_file_gen)

   mbn_dummy_bld = env.Builder(action = mbn_dummy_act, suffix = '.mbn')

 

   env.Append(BUILDERS = {'MbnDummyBuilder' : mbn_dummy_bld})

 

1240 後的版本爲:

def mbn_generate(env):

   env.AddMethod(mbn_builder, "MbnBuilder")

   #-------------------------------------------------------------------------

   # MBN builder definition

   #-------------------------------------------------------------------------

   stage1_mbn_act = env.GetBuilderAction(stage1_mbn_builder)

   stage1_mbn_bld = env.Builder(action = stage1_mbn_act,

                         emitter = stage1_mbn_emitter,

                         suffix = '.mbn')

 

   env.Append(BUILDERS = {'Stage1MbnBuilder' : stage1_mbn_bld})

  

   stage2_mbn_act = env.GetBuilderAction(stage2_mbn_builder)

   stage2_mbn_bld = env.Builder(action = stage2_mbn_act,

                         emitter = stage2_mbn_emitter,

                         suffix = '.mbn')

 

   env.Append(BUILDERS = {'Stage2MbnBuilder' : stage2_mbn_bld})

  

   mbn_dummy_act = env.GetBuilderAction(mbn_dummy_file_gen)

   mbn_dummy_bld = env.Builder(action = mbn_dummy_act, suffix = '.mbn')

env.Append(BUILDERS = {'MbnDummyBuilder' : mbn_dummy_bld})

 

MbnBuilder 方法,它對應的函數爲 mbn_builder, 該函數也在文件:./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py 中:

def mbn_builder(target, source, env):

   ...

   source_base = os.path.splitext(str(source[0]))[0]

   target_base = os.path.splitext(str(target[0]))[0]

   source_full = str(source[0])

   target_full = str(target[0])

1.3.3.5.1.1.2.4 env.MbnDummyBuilder 過程解析

./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py:160:  

。。。

mbn_dummy_act = env.GetBuilderAction(mbn_dummy_file_gen)

mbn_dummy_bld = env.Builder(action = mbn_dummy_act, suffix = '.mbn')

env.Append(BUILDERS = {'MbnDummyBuilder' : mbn_dummy_bld})

。。。

def mbn_dummy_file_gen(target, source, env):

   target_str = str(target[0])

   file = open (target_str, "w")

   file.write("\nDummy file created " + target_str + "\n")

   file.close()

   return None

 

# 生成 fsbl elf

FSBL_elf = env.Program('${TARGET_NAME}', FSBL_objs, LIBS=FSBL_libs, LIBPATH=libs_path)

FSBL_bin = env.BinBuilder('${TARGET_NAME}', FSBL_elf)

# Generate dummy fsbl mbn

FSBL_mbn = env.MbnDummyBuilder('${TARGET_NAME}', None)

install_target_mbn = env.InstallAs('${MBN_ROOT}/fsbl.mbn', FSBL_mbn)

 

1.3.3.5.1.1.2.5fsbl.mbn 生成過程解析

./AMSS/products/7x30/core/bsp/bootloaders/fsbl/build/SConscript:203:  

# 生成 fsbl elf

FSBL_elf = env.Program('${TARGET_NAME}', FSBL_objs, LIBS=FSBL_libs, LIBPATH=libs_path)  

# Generate fsbl bin

FSBL_bin = env.BinBuilder('${TARGET_NAME}', FSBL_elf)

# Generate fsbl mbn

#FSBL_mbn = env.MbnBuilder('${TARGET_NAME}', FSBL_bin,

#   IMAGE_TYPE="fsbl", FLASH_TYPE=env['FLASH_TYPE'])

# 生成 dummy fsbl mbn

FSBL_mbn = env.MbnDummyBuilder('${TARGET_NAME}', None)     

install_target_mbn = env.InstallAs('${MBN_ROOT}/fsbl.mbn', FSBL_mbn)

 

1.3.3.5.1.1.2.6 dbl.mbn 生成過程解析

./AMSS/products/7x30/core/bsp/bootloaders/dbl/build/SConscript:230:

DBL_elf = env.Program('${TARGET_NAME}',DBL_objs , LIBS=DBL_libs, LIBPATH=libs_path) 

   DBL_bin = env.BinBuilder('${TARGET_NAME}', DBL_elf)

   DBL_mbn = env.MbnBuilder(env.subst('${TARGET_NAME}'), DBL_bin, IMAGE_TYPE="dbl", FLASH_TYPE="nand")

1.3.3.5.1.1.2.7 AMSS_AABBQOLYM.mbn 生成過程解析

./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:252:  

target_mbn = env.MbnBuilder('${TARGET_NAME}', target_pbn, IMAGE_TYPE="amss_mbn",

1.3.3.5.1.1.2.8 adsp.mbn 生成過程解析

 

生成 adsp.mbn 的 scons 腳本爲:

./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/SConscript

   adsp_bin_path = env.subst("${BUILD_ROOT}/multimedia/adspinfo/adsp.bin")

   adsp_mbn_path = env.subst("${BUILD_ROOT}/core/bsp/amsslibs/build/qdsp5/adsp.mbn")

   install_temp_adsp_mbn = env.InstallAs(adsp_mbn_path, adsp_bin_path) 

   ADSP_mbn = env.MbnBuilder('${TARGET_NAME}', adsp_mbn_path, IMAGE_TYPE="qdsp5", FLASH_TYPE=env['TARGET_FLASH_TYPE'])     

   install_adsp_mbn = env.InstallAs('${MBN_ROOT}/adsp.mbn', ADSP_mbn)

 

首先安裝文件:

AMSS/products/7x30/multimedia/adspinfo/adsp.bin

到:

AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/adsp.mbn

此時的 adsp.mbn 僅僅是文件 adsp.bin 的拷貝。

然後調用 env.MbnBuilder 由文件 AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/adsp.mbn生成:./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/AMSS_AABBQOLYM.mbn

AMSS_AABBQOLYM.mbn 是 adsp.mbn 加了40個字節的頭信息,最後安裝此 AMSS_AABBQOLYM.mbn 到

AMSS/products/7x30/build/ms/bin/AABBQOLY/adsp.mbn

其中 env.MbnBuilder 執行的是文件:

./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py:299 中的函數:

def mbn_builder(target, source, env)

 

AMSS/products/7x30/tools/headergen/image_header nand adspq5 AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/adsp.mbn AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/AMSS_AABBQOLYM.hd nonsecure

 

flash_type: nand

header_type: adspq5

code_file_name: /home/shared/qualcommon/HY11-N1496-2_1.2.40/AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/adsp.mbn

output_file_name: /home/shared/qualcommon/HY11-N1496-2_1.2.40/AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/AMSS_AABBQOLYM.hd

secure_type: nonsecure

image_size = 0x614AB4, code_size= =0x614AB4

 

1.3.3.5.1.1.2.9osbl.mbn 生成過程解析

./AMSS/products/7x30/core/bsp/bootloaders/osbl/build/SConscript:246:  

OSBL_mbn = env.MbnBuilder('${TARGET_NAME}', OSBL_bin,

 

1.3.3.5.1.1.2.10enandprg_AABBQOLYM.mbn 生成過程解析

./AMSS/products/7x30/core/bsp/tools/flash/ehostdl/build/SConscript:389:

# Generate enandprg.elf

enandprg_elf = env.Program('${TARGET_NAME}', source=[], LIBS=libs, LIBPATH=libs_path)

env.Depends(enandprg_elf, target_scl)

Clean(enandprg_elf, env.subst('${TARGET_NAME}.map'))

Clean(enandprg_elf, env.subst('${TARGET_NAME}.sym'))

# 把生成的 elf 文件拷貝到相應位置

install_enandprg_elf = env.Install("${BUILD_ROOT}/core/storage/flash/tools/src/hostdl",enandprg_elf)

# Generate ehostdl bin

target_bin = env.BinBuilder('${TARGET_NAME}', enandprg_elf)

# 生成 ehostdl mbn

target_mbn = env.MbnBuilder('${TARGET_NAME}', target_bin, IMAGE_TYPE="ehostdl", FLASH_TYPE="nand")

1.3.3.5.1.1.2.11 nandprg_AABBQOLYM.mbn 生成過程解析

./AMSS/products/7x30/core/bsp/tools/flash/hostdl/build/SConscript:401:

# Generate nandprg.elf

nandprg_elf = env.Program('${TARGET_NAME}', source=[], LIBS=libs, LIBPATH=libs_path)

env.Depends(nandprg_elf, target_scl)

Clean(nandprg_elf, env.subst('${TARGET_NAME}.map'))

Clean(nandprg_elf, env.subst('${TARGET_NAME}.sym'))

# 把生成的 elf 文件拷貝到相應位置

install_nandprg_elf = env.Install("${BUILD_ROOT}/core/storage/flash/tools/src/hostdl", nandprg_elf)

# Generate hostdl bin

target_bin = env.BinBuilder('${TARGET_NAME}', nandprg_elf)

# Generate hostdl mbn

target_mbn = env.MbnBuilder('${TARGET_NAME}', target_bin,IMAGE_TYPE="hostdl", FLASH_TYPE="nand")

# Generate nandprg.hex

nprg_hex = env.NPRGHexBuilder('NPRG${MSM_ID}_${BUILD_ID}', target_mbn,HOSTDL_ADDR=CODE_HDR_ADDR)

install_nandprg_hex = env.InstallAs('${MBN_ROOT}/NPRG${MSM_ID}.hex', nprg_hex)

 

 

1.3.3.5.1.1.2.12 emmcbld.mbn 生成過程解析

生成 emmcbld.mbn 的 scons 腳本爲:

./AMSS/products/7x30/core/bsp/tools/emmcbld/build/SConscript:289:

libs = root_env['LIBS']

libs_path = env['LIBPATH']

# Source PATH

EMMCBLD_SRC = "${BUILD_ROOT}/core/storage/tools/emmcbld"

。。。

env.VariantDir('.', EMMCBLD_SRC, duplicate=0) 

env.Replace(TARGET_NAME = 'emmcbld')

env.Replace(TARGET_BLD_KCFG = 'M')

env.Replace(TARGET_IMAGE = 'MODEM_PROC')

# 生成 scatter load 文件

target_scl = env.SclBuilder('${TARGET_NAME}', '${BUILD_ROOT}/core/storage/tools/emmcbld/emmcbld_in.scl')

# 生成 emmcbld elf 文件

target_elf = env.Program('${TARGET_NAME}', emmcbld_obj, LIBS=libs, LIBPATH=libs_path)

env.Depends(target_elf, target_scl)

Clean(target_elf, env.subst('${TARGET_NAME}.map'))

Clean(target_elf, env.subst('${TARGET_NAME}.sym'))

# 生成 Generate emmcbld bin 文件

target_bin = env.BinBuilder('${TARGET_NAME}', target_elf)

# 生成 Generate emmcbld mbn 文件

target_mbn = env.MbnBuilder('${TARGET_NAME}', target_bin, IMAGE_TYPE="emmcbld", FLASH_TYPE="nand")

# 生成 emmcbld.hex 文件

mprg_hex = env.NPRGHexBuilder('MPRG${MSM_ID}', target_mbn, HOSTDL_ADDR=CODE_HDR_ADDR)

install_emmcbld_hex = env.InstallAs('${MBN_ROOT}/MPRG${MSM_ID}.hex', mprg_hex)

通過語句:

target_elf = env.Program('${TARGET_NAME}', emmcbld_obj, LIBS=libs, LIBPATH=libs_path) 編譯 emmcbld 相關代碼生成 ./AMSS/products/7x30/core/bsp/tools/emmcbld/build/emmcbld.elf        LIBS 爲程序需要引入的庫,庫的路徑爲 LIBPATH 例如:

如果程序引入了其它的庫,庫名爲libbar.a,庫的目錄爲/usr/local/lib:  

Program('hello',Glob("*.c"),LIBS='bar',LIBPATH='/usr/local/lib')

 

env.Depends(target_elf, target_scl)明確以來關係,表明生成 mmcbld.elf 需要 emmcbld.scl

 

Clean(target_elf, env.subst('${TARGET_NAME}.map'))

Clean(target_elf, env.subst('${TARGET_NAME}.sym'))

Clean 調用的是文件:

./AMSS/products/7x30/core/bsp/tools/SCons/Environment.py:1814:中的函數

def Clean(self, targets, files):

 

flash_type: nand

header_type: emmcbld

code_file_name: /home/shared/HY11-N1496-3_1.2.50/AMSS/products/7x30/core/bsp/tools/emmcbld/build/emmcbld.bin

output_file_name: /home/shared/HY11-N1496-3_1.2.50/AMSS/products/7x30/core/bsp/tools/emmcbld/build/emmcbld.hd

secure_type: nonsecure

image_size = 0x23E88, code_size= =0x23E88

=== Generating tool/emmcbld/MPRG7x30.hex

Install file: "/home/shared/HY11-N1496-3_1.2.50/AMSS/products/7x30/core/bsp/tools/emmcbld/build/MPRG7x30.hex" as "/home/shared/HY11-N1496-3_1.2.50/AMSS/products/7x30/build/ms/bin/AABBQOLY/MPRG7x30.hex"

 

3.3.3.5.1.1.1 corebsp_scons_done

1.3.3.5.1.2 corebsp

1.3.3.5.2 corebsp_create_incpaths

1.3.3.5.3 corebsp_setup

1.3.3.6 libs

.PHONY: setup

setup : corebsp_create_incpaths create_incpaths amsssetup amsslinkaddress firmware

...

#生成 Library

ifneq ($(USES_OBJECT_ONLY), yes)

libs : $(LIBDIR)/exist copybar firmware prereqs $(LIBRARIES)

    @if test -f dmss_lib.mak; then $(MAKE) --no-print-directory -f dmss_lib.mak; fi

else

libs : $(LIBDIR)/exist copybar $(LIBRARIES)

    @if test -f dmss_lib.mak; then $(MAKE) --no-print-directory -f dmss_lib.mak; fi

endif

...

ifeq ($(IMAGE), APPS_PROC)

$(TARGETDIR)/exist $(LIBDIR)/exist $(MBNPATH)/exist:

else

$(TARGETDIR)/exist $(LIBDIR)/exist:

endif

    @echo ---------------------------------------------------------------

    @echo Creating path for ${@D}

    @echo

    @if test ! -f $@ && test ! -d ${@D}; then mkdir -p ${@D}; mkdir -p ${@D}; fi

    @echo Building ${@D} > $@

    @echo ---------------------------------------------------------------

...

1.3.3.7 copybar規則解析

1.3.3.8 exe規則解析

1.3.3.8.1 CORELIBS_AABBQOLYM.mbn生成過程解析

1.3.3.8.2 amss.mbn 生成過程解析

   # Create PBN, MBN, etc..

   install_target_reloc = env.InstallAs(AMSS_RELOC, target_elf)

   # Build env pbn files

   target_pbn = env.PbnBuilder('${TARGET_NAME}', ["${BUILD_MS_ROOT}/quartz_cfg_${BUILD_ID}",install_target_reloc])

   install_target_pbn = env.InstallAs(BOOTING_PBN, target_pbn)

   # Build CMM scripts

   quartz_constant_cmm = env.QuartzConstBuilder('quartz_const_${TARGET_NAME}', ["${L4_ROOT}/build_${TARGET_BLD_KCFG}/ms/quartz_constants_${TARGET_BLD_KCFG}.cmm",install_target_pbn,"${BUILD_MS_ROOT}/quartz_cfg_${BUILD_ID}.xml",])

   # install scripts

   install_quartz_constant_cmm = env.InstallAs("${BUILD_MS_ROOT}/quartz_constants_${TARGET_BLD_KCFG}.cmm",quartz_constant_cmm)

   install_loadsyms_cmm = env.Install("${BUILD_MS_ROOT}","${L4_ROOT}/build_${TARGET_BLD_KCFG}/ms/loadsyms_${TARGET_BLD_KCFG}.cmm",)  

   install_loadsyms_men = env.Install("${BUILD_MS_ROOT}","${L4_ROOT}/build_${TARGET_BLD_KCFG}/ms/loadsyms_${TARGET_BLD_KCFG}.men",)

   install_cmm_scripts = [install_quartz_constant_cmm,install_loadsyms_cmm,install_loadsyms_men,]

   # Build env mbn files

   target_mbn = env.MbnBuilder('${TARGET_NAME}', target_pbn, IMAGE_TYPE="amss_mbn",FLASH_TYPE=env['TARGET_FLASH_TYPE'])

 

 

1.3.3.9 bldprod規則解析

1.3.3.10 create_mem_feat_html規則解析

此規則在 文件中

./AMSS/products/7x30/core/bsp/build/SConstruct:22:print "  

Loading CBSP build system"

./AMSS/products/7x30/core/bsp/coreimg/build/SConscript:24:  

print "   Loading CBSP Image build system"

./AMSS/products/7x30/core/bsp/tools/flash/build/SConstruct:31:

print "   Loading CBSP build system"

./AMSS/products/7x30/core/bsp/tools/boot/build/SConstruct:31:

print "   Loading CBSP build system"

./AMSS/products/7x30/core/bsp/bootloaders/build/SConstruct:31:

print "   Loading CBSP build system"

 

perl ./AMSS/products/7x30/build/ms/cleanup_xml.pl -i

 

./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/quartz_cfg_AAABQMAZM.xml

./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/quartz_cfg_machine_AAABQMAZM.xml

./AMSS/products/7x30/build/ms/quartz_cfg_AABBQMAZM.xml

./AMSS/products/7x30/build/ms/quartz_cfg_AABBQOLYM.xml

./AMSS/products/7x30/build/ms/quartz_cfg_AAABQMAZM.xml

./AMSS/products/7x30/build/ms/quartz_cfg_machine_AABBQOLYM.xml

./AMSS/products/7x30/build/ms/quartz_cfg_machine_AAABQMAZM.xml

./AMSS/products/7x30/build/ms/quartz_cfg_machine_AABBQMAZM.xml

./AMSS/products/7x30/build/ms/quartz_cfg_machine.xml

 

./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AAABQMAZM.mbn

./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AAABQMAZM.hash_nonsec.mbn

 

 

./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py

      if env.subst("$IMAGE_TYPE") != "amss_mbn":

         target_bin_nonsec = os.path.join(target_bin_base, target_bin_dir, \

            str(os.path.split(target_base)[1]) + "_nonsec.mbn")

      else:

         target_bin_nonsec = os.path.join(target_bin_base, target_bin_dir, \

            str(os.path.split(target_base)[1]) + ".hash_nonsec.mbn")

 

 

 

 

    quartz_xml = env.QuartzXMLBuilder('quartz_cfg_${TARGET_NAME}',

         ['${BUILD_MS_ROOT}/quartz_cfg.xml', quartz_machine_xml],

      #-------------------------------------------------------------------------

      # Build env pbn files

      #-------------------------------------------------------------------------

      target_pbn = env.PbnBuilder(

         '${TARGET_NAME}', [quartz_xml, install_target_reloc])

 

      # Copy qcoreimg_M.pbn to platform\l4\build_M\bootimg.pbn for RUMI */

      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 */

 

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

  /*-----------------------------------------------------------------------

   * Initialize FOTA

   *-----------------------------------------------------------------------*/

  osbl_fota_init,

#endif /* FEATURE_FOTA */

   //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 /* FEATURE_STANDALONE_MODEM */

  對於 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 )

{

...

/*從 flash 中裝載 appsbl 頭和鏡像到 RAM 中*/

    osbl_load_header_and_image_with_cookie( APPSBL_IMG, &appsbl_image_header_with_cookie );

... 

/*如果 boot loader 沒有裝載到地址 0x0, 那麼將會拷貝 appsbl 向量表到地址 0x0, appsbl 鏡像的向量表總是在在鏡像的頭 64字節中*/

 

  if ( apps_image_start_addr != 0x0 )

  {

/* 爲 L4 with kernel entry 初始化復位向量,其他的向量賦值爲 無限循環*/

復位向量的初始化值與 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;         /* Infinite loop */

    }

    *vector_ptr  = 0xE59FF018;          /* ldr pc, [pc, #0x18] */

  }

} /* osbl_load_appsbl() */

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 中:

/* one time setup */

void apps_init(void)

{

    const struct app_descriptor *app;

 

    /* call all the init routines */

    for (app = &__apps_start; app != &__apps_end; app++) {

       if (app->init)

           app->init(app);

    }

 

    /* start any that want to start on boot */

    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中的函數:

/* Read and write the bootloader command from the "misc" partition.

 * These return zero on success.

 */

從 misc 分區讀取

 

 

struct bootloader_message {

    char command[32];

    char status[32];

    char recovery[1024];

};

 

/* Read and write the bootloader command from the "misc" partition.

 * These return zero on success.

 */

int get_bootloader_message(struct bootloader_message *out);

int set_bootloader_message(const struct bootloader_message *in);

 

/* Write an update to the cache partition for update-radio or update-hboot.

 * Note, this destroys any filesystem on the cache partition!

 * The expected bitmap format is 240x320, 16bpp (2Bpp), RGB 5:6:5.

 */

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);

 

    /* TODO: create/pass atags to kernel */

        //開始引導內核

    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 )

    /* Initialize unified boot interface */

    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;       /* OS type to boot */

 

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 都有一個標準的頭,它由函數

 

  /*----------------------------------------------------------------------

    Fill up header structure

  ----------------------------------------------------------------------*/

  header[0] = id;

  header[2] = image_source;

  header[3] = image_dest;

  header[4] = image_size;/* image_size */

  header[5] = code_size; /* code_size */

  header[6] = image_dest+code_size; /* signature_ptr */

  header[7] = signature_size;            /* signature_size */

  header[8] = image_dest+code_size+signature_size;/* cert_chain_ptr */

  header[9] = cert_chain_size;                    /* cert_chain_size*/

  header[10] = UNIFIED_BOOT_COOKIE_MAGIC_NUMBER; /* boot cookie magic number */

  header[11] = 0;                         /* cookie version number */

  header[12] = boot_cookie.OS_type;       /* OS type to boot */   

  header[13] = 0;          /* start address of apps partition in storage device */

  header[14] = boot_cookie.boot_apps_size_entry; /* size in bytes of apps kernel to be loaded */

  header[15] = boot_cookie.boot_apps_ram_loc; /* location in RAM to load apps kernel */

  header[16] = 0;          /* reserve pointer */

  header[17] = 0;          /* reserve for future use */

  header[18] = 0;          /* reserve for future use */

  header[19] = 0;          /* reserve for future use */

  printf("image_size = 0x%X, code_size= =0x%X\n", image_size, code_size);

 

  /*----------------------------------------------------------------------

    Open output header file

  ----------------------------------------------------------------------*/

因爲文件:

./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 )

{

    ...

/* 獲取 elf 文件的入口點 */

     bl_shared_data->amss_entry_ptr = (amss_entry_ptr_type) boot_sec_elf_get_entry_point( bl_shared_data->amss_elf_if );

    ...  

} /* osbl 裝載 amss 鏡像文件 */

 

在 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)

。。。

        /* Jump to startup_system */

        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;

[A]

其實這個信號完全可以在CoreApp裏面,自己去註冊,然後及時更新自己的網絡狀態,就不知有沒有這種接口函數。

處理按鍵消息,其主要完成如下的工作:

打開背光;

特理按鍵到虛鍵值的轉換;

按鍵聲音的處理;

將按鍵消息傳送到AEE執行環境,由它去負責按鍵的派發;

[注]

1.背光的打開是由ui默認完成的,那這樣的話,假如我不想按鍵時有背光,是否可行?看來就得修改此處的代碼;

2.AEE的按鍵派發機制如何?它能否保證處於顯示最上層的App永遠是可以得到Key的App,即假如一個Applet將自身Hide,它是否依然可以得到Key,而其它的Applet是否就不可以得到了?很怕也像EMP一樣出現焦點丟失的情況;

處理AEE_APP_SIG信號量,完成AEE的調度工作,這個任務是ui完成的最重要的一項工作,因爲上層的App需要定時進行調度,目前看來,這個調度工作是由AEE_APP_SIG觸發的,而AEE_APP_SIG這個信號量,則由操作系統層面的一個定時器定時發送的。現在大家只要瞭解,AEE_Dispatch會定時調用就Ok了,至於更詳細的AEE調度機制,可以參考我的另外一篇《AEE運行機制深入分析與研究》;

處理AEE_SIO_SIG信號量,這個看不到代碼,暫時略過不管;

結論

通過上述對於ui_task的分析,可以看出,ui_task真正和手機功能有關係的(即可能需要定製或者修改的地方),主要就是初始化資源文件和處理按鍵消息這兩部分。至於其它部分,目前都不需要Amoi關心。手機真正功能的實現,比如說開機Logo的顯示、Sim卡的檢查、Pin碼校驗等,都是在CoreApp裏面完成的。

其它

CoreApp的深入分析

目前參考代碼裏面的CoreApp所完成的工作比較多且雜,主要說來有如下幾件事。

系統組件初始化;

開機Logo的顯示;

Sim卡檢測和Pin碼校驗;

系統狀態信息更新;

電池狀態;

網絡信號;

網絡模式;

IAnnunciator的維護與更新;

通話處理,打電話的輸入框;

主菜單處理;

手機各種設置功能的處理;

關機鍵的處理;

目前CoreApp裏面的代碼,完成了太多的事,其實完全可以剝離成不同的模塊來完成,大致可以分成如下幾個部分。

總控模塊;(CoreApp)

總控模塊,主要完成手機按下開機鍵之後的各種初始化工作,同時此模塊也是整個手機的控制中心,由它來完成手機的一些全局性工作,主要有如下幾項。

系統初始化、Sim卡檢測和Pin碼校驗;

開機Logo或者開機動畫的顯示;

底層服務程序的啓動;(WmsApp、DialApp等);

系統配置信息的統一管理;

由於寫配置信息到NV上面是一件非常慢的工作,每次上層App改變配置之後都去操作NV,很影響速度。所以,可以在內存中開一個配置信息的Buffer,上層App操作的實際上是這個Buffer,然後由Core在空閒的時候再統一寫到NV上去。

關機處理;

[注]

由於CoreApp是在Idle Applet的界面之下,所以,爲了能夠實現“一鍵回菜單”的功用,有可能需要修改ui_task裏面的Key處理函數,將所有的Key消息轉發給Core,這樣Core就可以得到所有的Key事件了。(現在的ui_task只把Key事件發送給了AEE,而AEE只會將Key事件發送給當前活動Applet)。

Idle模塊;

主要完成待機界面的畫圖工作,主要有兩部分:

系統信息指示欄;

待機界面(位圖、動畫、時鐘、日曆等);

軟鍵

[注]

Idle只負責界面工作,不負責具體的系統狀態信息的獲取工作,這個工作將由其它模塊完成。

Polling

手機狀態信息查詢模塊,主要是完成手機各種狀態信息的更新與維護。主要有如下幾種:

電池強度;

網絡信號強度;

網絡模式(C/G);

PLMN網絡名;

短消息、通話狀態、鬧鈴;(這個由專門的模塊完成,不在Polling之列);

各種外設信息;(USB、耳機插入等);

其它各種雜項信息;

Menu模塊

菜單模塊主要分兩部分,一部分是主菜單的實現,另一個子菜單的實現。一般來講,手機上的菜單系統應該是由Menu模塊去統一完成,而不是由每一個子程序去手動完成。菜單模塊一般只需要負責到主菜單、二級菜單和三級菜單就Ok了。三級菜單之後的界面,就由每一個App單獨去維護了。

其它功能App模塊;

每一個功能模塊,由一個專門的App來完成,這樣的話,模塊的獨立性強,便於單獨開發。模塊間通過App啓動和消息傳送的方式來發生關係和進行模塊間通信。

 

後記

到此爲止,Qualcomm整個手機從按下開機鍵到跑到主菜機界面,整個流程一目瞭然。對於Amoi而言,目前需要關心和定做的部分其實不多,最頭疼的 當屬CoreApp的改造工作,當然這個就是後話了,筆者將在今後的文章中加以詳述。

希望本文對於大家理解Qualcomm手機軟件的運行流程有一定的幫助,如果有什麼問題,請直接聯繫我,最後謝謝大家耐心把本文看完,謝謝。

參考文檔

a)         80-V1072-1_E_Boot_Block_Downloader.pdf

b)        80-V5316-1_K_QCT_Ext_API_RG.pdf

c)         driver/boot目錄源碼

d)        service/tmc目錄源碼

e)         app/core目錄源碼

REX啓動分析——基於Qualcomm平臺

http://hi.baidu.com/gcmao/blog/item/5ef1ea2c12da08341e308914.html

Qualcomm手機開機全過程

Qualcomm手機開機全過程大揭密(四)

http://www.1mp.cn/DataShow.aspx?id=1642

 

 

Qualcomm手機開機全過程大揭密

[email protected]

2004-11-13

摘要:

    本文試圖通過代碼來深入剖析Qualcomm手機開機的整個過程,即從按下開機鍵一直到出現待機界面,Qualcomm的手機軟件在整個流程中究竟完成了哪些工作。本文的主要目標是理清手機的初始化流程,併爲今後Amoi定做初始化工作提供一個參考。

關鍵字:開機、Rex、TMC、ui_task、CoreApp

開機的簡要流程分析

Qualcomm的平臺軟件支持兩種啓動方式:一種是Nor Flash啓動方式,另外一種就

是Nand Flash啓動方式。Nor Flash啓動方式就相當於硬件直接找到一個入口點開始執行代碼,相比較而言會 比較簡單,且Amoi沒有采用此種方式,所以本文對於這種方式不做詳細分析。另外一種就是Nand Flash啓動方式,這種方式和PC的啓動方式比較相像,也是Amoi採用的Boot方式,下面將詳細分析在此方式下面的開機過程。

    按下開機鍵之後,將產生一個時鐘中斷,從而通知AMSS主芯片的Boot Load硬件去將放置於Nand Flash上面的第一個Block(8K)裏面的Boot代碼Copy到內核內存(RAM,這個內存應該是CPU自帶的內存,同後面提到的SDRAM有一定區別,可以把它當作CPU的Cache)的0xFFFF0000地址,並開始執行Boot代碼。Boot的主要任務是完成整個系統的硬件初始化工作(類似於PC上面的BIOS所完成的硬件自檢工作,至於Boot的詳細工作機制,後文會有詳細描述)。Boot所完成的工作裏面,最重要的一件事就是會將整個手機軟件代碼(AMSS軟件包)拷貝到SDRAM中,並最後將控制權交給AMSS軟件。說白了,就是Boot執行完成之後,代碼的執行點將由Boot跳轉到AMSS軟件的的入口點函數main().(此函數在mobile.c裏實現)。

    代碼運行到了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;

[A]

其實這個信號完全可以在CoreApp裏面,自己去註冊,然後及時更新自己的網絡狀態,就不知有沒有這種接口函數。

處理按鍵消息,其主要完成如下的工作:

打開背光;

特理按鍵到虛鍵值的轉換;

按鍵聲音的處理;

將按鍵消息傳送到AEE執行環境,由它去負責按鍵的派發;

[注]

1.背光的打開是由ui默認完成的,那這樣的話,假如我不想按鍵時有背光,是否可行?看來就得修改此處的代碼;

2.AEE的按鍵派發機制如何?它能否保證處於顯示最上層的App永遠是可以得到Key的App,即假如一個Applet將自身Hide,它是否依然可以得到Key,而其它的Applet是否就不可以得到了?很怕也像EMP一樣出現焦點丟失的情況;

處理AEE_APP_SIG信號量,完成AEE的調度工作,這個任務是ui完成的最重要的一項工作,因爲上層的App需要定時進行調度,目前看來,這個調度工作是由AEE_APP_SIG觸發的,而AEE_APP_SIG這個信號量,則由操作系統層面的一個定時器定時發送的。現在大家只要瞭解,AEE_Dispatch會定時調用就Ok了,至於更詳細的AEE調度機制,可以參考我的另外一篇《AEE運行機制深入分析與研究》;

處理AEE_SIO_SIG信號量,這個看不到代碼,暫時略過不管;

結論

通過上述對於ui_task的分析,可以看出,ui_task真正和手機功能有關係的(即可能需要定製或者修改的地方),主要就是初始化資源文件和處理按鍵消息這兩部分。至於其它部分,目前都不需要Amoi關心。手機真正功能的實現,比如說開機Logo的顯示、Sim卡的檢查、Pin碼校驗等,都是在CoreApp裏面完成的。

其它

CoreApp的深入分析

目前參考代碼裏面的CoreApp所完成的工作比較多且雜,主要說來有如下幾件事。

系統組件初始化;

開機Logo的顯示;

Sim卡檢測和Pin碼校驗;

系統狀態信息更新;

電池狀態;

網絡信號;

網絡模式;

IAnnunciator的維護與更新;

通話處理,打電話的輸入框;

主菜單處理;

手機各種設置功能的處理;

關機鍵的處理;

目前CoreApp裏面的代碼,完成了太多的事,其實完全可以剝離成不同的模塊來完成,大致可以分成如下幾個部分。

總控模塊;(CoreApp)

總控模塊,主要完成手機按下開機鍵之後的各種初始化工作,同時此模塊也是整個手機的控制中心,由它來完成手機的一些全局性工作,主要有如下幾項。

系統初始化、Sim卡檢測和Pin碼校驗;

開機Logo或者開機動畫的顯示;

底層服務程序的啓動;(WmsApp、DialApp等);

系統配置信息的統一管理;

由於寫配置信息到NV上面是一件非常慢的工作,每次上層App改變配置之後都去操作NV,很影響速度。所以,可以在內存中開一個配置信息的Buffer,上層App操作的實際上是這個Buffer,然後由Core在空閒的時候再統一寫到NV上去。

關機處理;

[注]

由於CoreApp是在Idle Applet的界面之下,所以,爲了能夠實現“一鍵回菜單”的功用,有可能需要修改ui_task裏面的Key處理函數,將所有的Key消息轉發給Core,這樣Core就可以得到所有的Key事件了。(現在的ui_task只把Key事件發送給了AEE,而AEE只會將Key事件發送給當前活動Applet)。

Idle模塊;

主要完成待機界面的畫圖工作,主要有兩部分:

系統信息指示欄;

待機界面(位圖、動畫、時鐘、日曆等);

軟鍵

[注]

Idle只負責界面工作,不負責具體的系統狀態信息的獲取工作,這個工作將由其它模塊完成。

Polling

手機狀態信息查詢模塊,主要是完成手機各種狀態信息的更新與維護。主要有如下幾種:

電池強度;

網絡信號強度;

網絡模式(C/G);

PLMN網絡名;

短消息、通話狀態、鬧鈴;(這個由專門的模塊完成,不在Polling之列);

各種外設信息;(USB、耳機插入等);

其它各種雜項信息;

Menu模塊

菜單模塊主要分兩部分,一部分是主菜單的實現,另一個子菜單的實現。一般來講,手機上的菜單系統應該是由Menu模塊去統一完成,而不是由每一個子程序去手動完成。菜單模塊一般只需要負責到主菜單、二級菜單和三級菜單就Ok了。三級菜單之後的界面,就由每一個App單獨去維護了。

其它功能App模塊;

每一個功能模塊,由一個專門的App來完成,這樣的話,模塊的獨立性強,便於單獨開發。模塊間通過App啓動和消息傳送的方式來發生關係和進行模塊間通信。

 

後記

到此爲止,Qualcomm整個手機從按下開機鍵到跑到主菜機界面,整個流程一目瞭然。對於Amoi而言,目前需要關心和定做的部分其實不多,最頭疼的 當屬CoreApp的改造工作,當然這個就是後話了,筆者將在今後的文章中加以詳述。

希望本文對於大家理解Qualcomm手機軟件的運行流程有一定的幫助,如果有什麼問題,請直接聯繫我,最後謝謝大家耐心把本文看完,謝謝。

參考文檔

f)         80-V1072-1_E_Boot_Block_Downloader.pdf

g)        80-V5316-1_K_QCT_Ext_API_RG.pdf

h)        driver/boot目錄源碼

i)          service/tmc目錄源碼

j)          app/core目錄源碼

 

1.5 android 系統重啓關機流程分析

1.5.1 c語言中調用 reboot 函數

bionic/libc/unistd/reboot.c:33:

int reboot (int  mode)

{

    return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );

}

1.5.2 通過 adb 讓系統重啓

adb reboot recovery  進入 recovery 模式

adb reboot bootloader 進入 fastboot 模式

adb reboot-bootloader

adb reboot 不帶參數 系統正常重啓

adb 是pc端工具,adbd是服務端,運行在手機

adbd 讀取 socket 解析由 adb 傳過來的命令串

int service_to_fd(const char *name)

if(!strncmp(name, "reboot:", 7)) {

        void* arg = strdup(name + 7);

        if(arg == 0) return -1;

        ret = create_service_thread(reboot_service, arg);

 

system/core/adb/services.c:176:

void reboot_service(int fd, void *arg)

{

    。。。

    ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,

                    LINUX_REBOOT_CMD_RESTART2, (char *)arg);

    。。。

}

bionic/libc/kernel/common/linux/reboot.h

#define LINUX_REBOOT_CMD_RESTART 0x01234567

#define LINUX_REBOOT_CMD_HALT 0xCDEF0123

kernel/include/linux/reboot.h:33:

#define    LINUX_REBOOT_CMD_RESTART2   0xA1B2C3D4

 

arg 對應字符串: recovery  bootloader

./kernel/arch/arm/mach-msm/pm2.c

system/core/adb/commandline.c

if (!strcmp(argv[0], "reboot-bootloader"))

   snprintf(command, sizeof(command), "reboot:bootloader");

如果輸入 adb reboot-bootloader adb 會對該命令進行轉換 相當於執行 adb reboot bootloader

1.5.3 fastboot 模式下系統重啓

fastboot reboot  系統正常重啓

fastboot reboot-bootloader 重啓進入fastboot 模式

fastboot 是 appboot 提供的功能,可以用它來燒寫 system 等鏡像文件

bootable/bootloader/lk/app/aboot/aboot.c

APP_START(aboot)

    .init = aboot_init,

void aboot_init(const struct app_descriptor *app)

    。。。

    fastboot_register("reboot", cmd_reboot);

    fastboot_register("reboot-bootloader", cmd_reboot_bootloader);

    。。。

void cmd_reboot(const char *arg, void *data, unsigned sz)

{

    dprintf(INFO, "rebooting the device\n");

    fastboot_okay("");

    reboot_device(0);

}

 

void cmd_reboot_bootloader(const char *arg, void *data, unsigned sz)

{

    dprintf(INFO, "rebooting the device\n");

    fastboot_okay("");

    reboot_device(FASTBOOT_MODE);

}

bootable/bootloader/lk/target/msm7630_surf/init.c:311:

void reboot_device(unsigned reboot_reason)

bootable/bootloader/lk/target/msm7627_ffa/init.c:174:

void reboot_device(unsigned reboot_reason)

void reboot_device(unsigned reboot_reason)

{

    reboot(reboot_reason);

}

調用的是c函數:

bionic/libc/unistd/reboot.c:33:

int reboot (int  mode)

{

    return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );

}

bootable/bootloader/lk/app/aboot/aboot.c:59:

#define FASTBOOT_MODE   0x77665500

if (!strcmp(cmd, "bootloader")) {

           restart_reason = 0x77665500;

}

 

1.5.4 系統關機

正常按鍵關機

./frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java

void showGlobalActionsDialog()

  mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());

調用文件:

./frameworks/policies/base/phone/com/android/internal/policy/impl/GlobalActions.java

中的函數:

public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned)

  mDialog = createDialog();

調用本文件中的函數:

private AlertDialog createDialog()

public void onPress() {

    ShutdownThread.shutdownAfterDisablingRadio(mContext, true);

}

調用文件:

./frameworks/policies/base/phone/com/android/internal/policy/impl/ShutdownThread.java

中的函數:

public static void shutdownAfterDisablingRadio(final Context context, boolean confirm)

  beginShutdownSequence(context)

調用本文件中的函數:

private static void beginShutdownSequence(Context context)

  sInstance.start()

進入關機線程的run函數:

public void run() {

首先關藍牙,關射頻,然後再關電源

    ...

    sBluetooth.disable(false)

    ...

    sPhone.setRadio(false)

    ...

    SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);

    ...

        Power.shutdown()

}

frameworks/base/core/java/android/os/Power.java:92:   

public static native void shutdown();

frameworks/base/core/jni/android_os_Power.cpp:107:   

{ "shutdown", "()V", (void*)android_os_Power_shutdown },

jni 調用

static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)

{

    sync();

#ifdef HAVE_ANDROID_OS

    reboot(RB_POWER_OFF);

#endif

}

因爲有 bionic/libc/include/sys/reboot.h:42:

#define RB_POWER_OFF    LINUX_REBOOT_CMD_POWER_OFF

所以實際相對執行

reboot(LINUX_REBOOT_CMD_POWER_OFF);

__reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL );

 

這裏的 __reboot 是libc中的系統調用

bionic/libc/arch-x86/syscalls/__reboot.S

/* autogenerated by gensyscalls.py */

#include <sys/linux-syscalls.h>

 

    .text

    .type __reboot, #function

    .globl __reboot

    .align 4

    .fnstart

 

__reboot:

    .save   {r4, r7}

    stmfd   sp!, {r4, r7}

    ldr     r7, =__NR_reboot

    swi     #0

    ldmfd   sp!, {r4, r7}

    movs    r0, r0

    bxpl    lr

    b       __set_syscall_errno

    .fnend

 

1.5.5 內核中的系統調用 reboot

__NR_reboot 執行的是內核中的系統調用:

kernel/kernel/sys.c:310:

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,

       void __user *, arg)

{

    char buffer[256];

    int ret = 0;

 

    /* We only trust the superuser with rebooting the system. */

    if (!capable(CAP_SYS_BOOT))

       return -EPERM;

 

    /* For safety, we require "magic" arguments. */

    if (magic1 != LINUX_REBOOT_MAGIC1 ||

        (magic2 != LINUX_REBOOT_MAGIC2 &&

                    magic2 != LINUX_REBOOT_MAGIC2A &&

           magic2 != LINUX_REBOOT_MAGIC2B &&

                    magic2 != LINUX_REBOOT_MAGIC2C))

       return -EINVAL;

 

    /* Instead of trying to make the power_off code look like

     * halt when pm_power_off is not set do it the easy way.

     */

    if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)

       cmd = LINUX_REBOOT_CMD_HALT;

 

    lock_kernel();

    switch (cmd) {

    case LINUX_REBOOT_CMD_RESTART:

       kernel_restart(NULL);

       break;

 

    case LINUX_REBOOT_CMD_CAD_ON:

       C_A_D = 1;

       break;

 

    case LINUX_REBOOT_CMD_CAD_OFF:

       C_A_D = 0;

       break;

 

    case LINUX_REBOOT_CMD_HALT:

       kernel_halt();

       unlock_kernel();

       do_exit(0);

       panic("cannot halt");

 

    case LINUX_REBOOT_CMD_POWER_OFF:

       kernel_power_off();

       unlock_kernel();

       do_exit(0);

       break;

 

    case LINUX_REBOOT_CMD_RESTART2:

       if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {

           unlock_kernel();

           return -EFAULT;

       }

       buffer[sizeof(buffer) - 1] = '\0';

 

       kernel_restart(buffer);

       break;

 

#ifdef CONFIG_KEXEC

    case LINUX_REBOOT_CMD_KEXEC:

       ret = kernel_kexec();

       break;

#endif

 

#ifdef CONFIG_HIBERNATION

    case LINUX_REBOOT_CMD_SW_SUSPEND:

       ret = hibernate();

       break;

#endif

 

    default:

       ret = -EINVAL;

       break;

    }

    unlock_kernel();

    return ret;

}

void kernel_restart(char *cmd)

{

    kernel_restart_prepare(cmd);

    if (!cmd)

       printk(KERN_EMERG "Restarting system.\n");

    else

       printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);

    machine_restart(cmd);

}

kernel/kernel/sys.c:341:

void kernel_power_off(void)

{

    kernel_shutdown_prepare(SYSTEM_POWER_OFF);

    if (pm_power_off_prepare)

       pm_power_off_prepare();

    disable_nonboot_cpus();

    sysdev_shutdown();

    printk(KERN_EMERG "Power down.\n");

    machine_power_off();

}

 

./kernel/arch/arm/kernel/process.c:219:

void machine_restart(char *cmd)

{

    arm_pm_restart(reboot_mode, cmd);

}

 

void machine_power_off(void)

{

    if (pm_power_off)

       pm_power_off();

}

 

因爲./kernel/arch/arm/mach-msm/pm2.c:1740:中有:

arm_pm_restart = msm_pm_restart;

pm_power_off = msm_pm_power_off;

所以 arm_pm_restart 調用的是:

static void msm_pm_restart(char str, const char *cmd)

{

    msm_rpcrouter_close();

    msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);

 

    for (;;)

       ;

}

pm_power_off 調用的是:

static void msm_pm_power_off(void)

{

    msm_rpcrouter_close();

    msm_proc_comm(PCOM_POWER_DOWN, 0, 0);

    for (;;)

       ;

}

msm_proc_comm 是芯片級別的操作

msm_proc_comm_reset_modem_now 對modem芯片進行重啓

kernel/arch/arm/mach-msm/proc_comm.c:98:

int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2)

{

    。。。

    writel(cmd, base + APP_COMMAND);

    writel(data1 ? *data1 : 0, base + APP_DATA1);

    writel(data2 ? *data2 : 0, base + APP_DATA2);

    。。。

}

內核裏面writel是如何實現的

http://blog.chinaunix.net/u2/77776/showart_1404857.html

補充信息:

static int msm_reboot_call

    (struct notifier_block *this, unsigned long code, void *_cmd)

{

    if ((code == SYS_RESTART) && _cmd) {

       char *cmd = _cmd;

       if (!strcmp(cmd, "bootloader")) {

           restart_reason = 0x77665500;

       } else if (!strcmp(cmd, "recovery")) {

           restart_reason = 0x77665502;

       } else if (!strcmp(cmd, "eraseflash")) {

           restart_reason = 0x776655EF;

       } else if (!strncmp(cmd, "oem-", 4)) {

           unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;

           restart_reason = 0x6f656d00 | code;

       } else {

           restart_reason = 0x77665501;

       }

    }

    return NOTIFY_DONE;

}

static struct notifier_block msm_reboot_notifier = {

    .notifier_call = msm_reboot_call,

};

static int __init msm_pm_init(void)

  register_reboot_notifier(&msm_reboot_notifier);

 

內核編譯相關:

kernel/arch/arm/mach-msm/pm2.c:1701:          restart_reason = 0x77665500;

kernel/arch/arm/mach-msm/pm.c:696:        restart_reason = 0x77665500;

kernel/arch/arm/mach-msm/Makefile:84: 

ifdef CONFIG_MSM_N_WAY_SMSM

    obj-$(CONFIG_PM) += pm2.o

else

    obj-$(CONFIG_PM) += pm.o

endif

 

kernel/arch/arm/configs/msm7630-perf_defconfig:256:CONFIG_MSM_N_WAY_SMSM=y

kernel/arch/arm/configs/msm7627-perf_defconfig:247:CONFIG_MSM_N_WAY_SMSM=y

make -C kernel O=../out/target/product/msm7627_ffa/obj/KERNEL_OBJ ARCH=arm CROSS_COMPILE=arm-eabi- msm7627-perf_defconfig

out/target/product/msm7627_ffa/obj/KERNEL_OBJ/.config

CONFIG_MSM_N_WAY_SMSM=y

 

1.6 軟件調用流程分析

1.6.1 設置sim卡狀態

工程模式中顯

private void tryChangeSimLockState()

  Message callback = Message.obtain(mHandler, ENABLE_SIM_PIN_COMPLETE);

  mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback);

進入sim lock 菜單會顯示初始化pin狀態,是通過下面語句得到:

mPinToggle.setChecked(mPhone.getSimCard().getSimLockEnabled());

 

mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback)調用的是文件:

GsmSimCard.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函數:

public void setSimLockEnabled (boolean enabled,String password, Message onComplete) {

  int serviceClassX;

  serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +

                CommandsInterface.SERVICE_CLASS_DATA +

                CommandsInterface.SERVICE_CLASS_FAX;

  mDesiredPinLocked = enabled;

  phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,

                enabled, password, serviceClassX,

                obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));

phone.mCM.setFacilityLock 調用的是文件:

RIL.java (frameworks\base\telephony\java\com\android\internal\telephony\gsm)中的函數:

    public void

    setFacilityLock (String facility, boolean lockState, String password,

                        int serviceClass, Message response)

    {

        String lockString;

         RILRequest rr

                = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response);

        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

        // count strings

        rr.mp.writeInt(4);

        rr.mp.writeString(facility);

        lockString = (lockState)?"1":"0";

        rr.mp.writeString(lockString);

        rr.mp.writeString(password);

        rr.mp.writeString(Integer.toString(serviceClass));

        send(rr);

    }

設置應用程序向 rild 發送 RIL_REQUEST_SET_FACILITY_LOCK 請求的 socket消息,

android的初始源代碼中 RIL_REQUEST_SET_FACILITY_LOCK 請求,在參考實現 Reference-ril.c

(hardware\ril\reference-ril) 中沒有實現。

我們需要做得工作是:

vendor/qcom/proprietary/qcril/

vendor/qcom/proprietary/qcril/qcril_original/qcril_original.mk

LOCAL_MODULE:= libril-qc-1

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

device/qcom/msm7627_ffa/system.prop:5:

rild.libpath=/system/lib/libril-qc-1.so

 

./build/target/board/generic/system.prop

rild.libpath=/system/lib/libreference-ril.so

rild.libargs=-d /dev/ttyS0

 

 

 

 

 

 

1.6.2 設置背光

工程模式中顯示電池信息:

./hardware/msm7k/liblights/Android.mk:28:LOCAL_MODULE := lights.$(TARGET_BOARD_PLATFORM)

1.6.3 獲取電池信息

工程模式中顯示電池信息:

*#*#4636#*#* 進入android 自帶的工程模式

packages/apps/Settings/src/com/android/settings/BatteryInfo.java:88:

電壓發生變化就會收到 intent 爲 Intent.ACTION_BATTERY_CHANGED 的廣播消息:

action.equals(Intent.ACTION_BATTERY_CHANGED)

從intent 中獲取電壓值通過 TextView 來顯示

int plugType = intent.getIntExtra("plugged", 0);

mLevel.setText("" + intent.getIntExtra("level", 0));

mScale.setText("" + intent.getIntExtra("scale", 0));

mVoltage.setText("" + intent.getIntExtra("voltage", 0) + " "

                        + getString(R.string.battery_info_voltage_units));

int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);

 

./packages/apps/Settings/res/values-zh-rCN/strings.xml

<string name="battery_info_power_label" msgid="7465140230991349382">"是否已插電:"</string>

<string name="battery_info_status_label">"電池狀態:"</string>

<string name="battery_info_scale_label">"電池容量:"</string>

<string name="battery_info_level_label">"電池級別:"</string>

<string name="battery_info_voltage_label">"電池電壓:"</string>

mStatus.setText(statusString);

 

佈局文件 packages/apps/Settings/res/layout/battery_info.xml

id="@+id/status"   text="@string/battery_info_status_label"

id="@+id/power"    text="@string/battery_info_power_label"

id="@+id/level"    text="@string/battery_info_level_label"

id="@+id/scale"    text="@string/battery_info_scale_label"

id="@+id/voltage"  text="@string/battery_info_voltage_label"

 

電池狀態:

<string name="battery_info_status_charging_ac" >"(交流電)"</string>

<string name="battery_info_status_charging_usb" >"(USB 綁定選項)"</string>

<string name="battery_info_status_discharging" >"正在放電"</string>

<string name="battery_info_status_not_charging" >"未在充電"</string>

<string name="battery_info_status_full" >"已滿"</string>

 

電源狀態

switch (plugType) {

case 0:

//未插電

            mPower.setText(getString(R.string.battery_info_power_unplugged));

            break;

case BatteryManager.BATTERY_PLUGGED_AC:

        //交流電

            mPower.setText(getString(R.string.battery_info_power_ac));

            break;

case BatteryManager.BATTERY_PLUGGED_USB:

        //usb供電

            mPower.setText(getString(R.string.battery_info_power_usb));

            break;

case (BatteryManager.BATTERY_PLUGGED_AC|BatteryManager.BATTERY_PLUGGED_USB):

        // "交流電 + USB"

            mPower.setText(getString(R.string.battery_info_power_ac_usb));

            break;

default:

        // "未知"

            mPower.setText(getString(R.string.battery_info_power_unknown));

            break;

     }

 

關心電池信息的服務或者應用:

frameworks/base/services/java/com/android/server/PowerManagerService.java

frameworks/base/services/java/com/android/server/WifiService.java

frameworks/base/services/java/com/android/server/UiModeManagerService.java:324

frameworks/base/services/java/com/android/server/status/StatusBarPolicy.java

frameworks/base/services/java/com/android/server/NotificationManagerService.java

frameworks/base/services/java/com/android/server/NotificationManagerService.java

frameworks/base/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java

frameworks/base/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java

frameworks/policies/base/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java

通過 filter.addAction(Intent.ACTION_BATTERY_CHANGED);

 

 

電池服務發送電池信息的 intent

frameworks/base/services/java/com/android/server/BatteryService.java

    private final void sendIntent() {

        //  Pack up the values and broadcast them to everyone

        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);

        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY

                | Intent.FLAG_RECEIVER_REPLACE_PENDING);

        try {

            mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE, mBatteryLevel);

        } catch (RemoteException e) {

            // Should never happen.

        }

 

        int icon = getIcon(mBatteryLevel);

 

        intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryStatus);

        intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryHealth);

        intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryPresent);

        intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryLevel);

        intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);

        intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);

        intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);

        intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryVoltage);

        intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryTemperature);

        intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);

        。。。

        ActivityManagerNative.broadcastStickyIntent(intent, null);

    }

 

private synchronized final void update() {

    native_update();

    shutdownIfNoPower(); //點亮不足關機處理

    shutdownIfOverTemp();//溫度過高,關機處理

        。。。

        sendIntent();

        。。。

}

 

在電池服務啓動,或者有相關時間的時候會調用 update 得到電池信息,然後通過廣播發出去

 private UEventObserver mUEventObserver = new UEventObserver() {

        @Override

        public void onUEvent(UEventObserver.UEvent event) {

            update();

        }

    };

根據jni調用規則,native_update 實際調用的是 android_server_BatteryService_update

frameworks/base/services/jni/com_android_server_BatteryService.cpp:226:

{"native_update", "()V", (void*)android_server_BatteryService_update},

 

#define POWER_SUPPLY_PATH "/sys/class/power_supply"

struct FieldIds {

    // members

    jfieldID mAcOnline;

    jfieldID mUsbOnline;

    jfieldID mBatteryStatus;

    jfieldID mBatteryHealth;

    jfieldID mBatteryPresent;

    jfieldID mBatteryLevel;

    jfieldID mBatteryVoltage;

    jfieldID mBatteryTemperature;

    jfieldID mBatteryTechnology;

};

 

static void android_server_BatteryService_update(JNIEnv* env, jobject obj)

{

    setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);

    setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline);

    setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);

   

    setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);

    setVoltageField(env, obj, gPaths.batteryVoltagePath, gFieldIds.mBatteryVoltage);

    setIntField(env, obj, gPaths.batteryTemperaturePath, gFieldIds.mBatteryTemperature);

   

    const int SIZE = 128;

    char buf[SIZE];

   

    if (readFromFile(gPaths.batteryStatusPath, buf, SIZE) > 0)

        env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));

    else

        env->SetIntField(obj, gFieldIds.mBatteryStatus,

                         gConstants.statusUnknown);

   

    if (readFromFile(gPaths.batteryHealthPath, buf, SIZE) > 0)

        env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));

 

    if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)

        env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));

}

 

cat /sys/class/power_supply/battery/type

cat /sys/class/power_supply/battery/status

cat /sys/class/power_supply/battery/health

cat /sys/class/power_supply/battery/present

cat /sys/class/power_supply/battery/technology

cat /sys/class/power_supply/battery/capacity

cat /sys/class/power_supply/battery/voltage_now

cat /sys/class/power_supply/battery/temp

cat /sys/class/power_supply/battery/current_now

cat /sys/class/power_supply/battery/current_avg

cat /sys/class/power_supply/battery/charge_counterBattery

$ Battery

$ Charging

$ Good

$ 1

$ Li-ion

$ 100

$ 4172644

$ 296

$ 85626

$ 86229

$ 1363200

驅動層具體實現(略)

 

 

1.7 python scons 語法學習

 

1.8 python  語法學習

1.8.1 Python中文全攻略

Python 絕對簡明手冊

http://wiki.woodpecker.org.cn/moin/PyAbsolutelyZipManual

Py標準庫手冊

http://wiki.woodpecker.org.cn/moin/PythonStandardLib

 

1.8.2 推薦一款Python編輯器

1.8.3 使用 pyExcelerator 讀 Execl 文件

首先從網站下載該軟件包

http://sourceforge.net/projects/pyexcelerator/

然後解壓縮,安裝

unzip pyexcelerator-0.6.4.1.zip

cd pyexcelerator-0.6.4.1/

python setup.py install

for example:

#!/usr/bin/env python

# -*- coding: UTF-8  -*-

from random import randint

from pyExcelerator import *

def test():

    print "aaa"

    w = Workbook() #創建一個工作簿

    ws = w.add_sheet('Hey, Hades') #創建一個工作表

    ws.write(0,0,'bit') #在1行1列寫入bit

    ws.write(0,1,'huang') #在1行2列寫入huang

    ws.write(1,0,'xuan') #在2行1列寫入xuan

    w.save('mini.xls') #保存

if __name__ == '__main__':

test()

 

1.8.4 xlrd 解析 xls 文件

sudo apt-get install python-xlrd

獲取有多少表單

book = xlrd.open_workbook(filename)

#打印sheet個數

Print book.nsheets

 

1.8.5 xlrd 生成 xls 文件

# # xlsBook = xlsApp.Workbooks.Open("c:\\magictong.xls") 

# # xlsSht = xlsBook.Worksheets("sheet1") 

#  

# xlsBook = xlsApp.Workbooks.Add() 

# xlsSht = xlsBook.Sheets.Add() 

# xlsSht.Cells(2, 3).Value = "Tecent QQ" 

# xlsSht.Cells(2, 3).Font.Color = 0xff0000 

#  

# xlsSht.Name = "GCD go to bell" 

# xlsBook.SaveAs("c:\\magictong.xls") 

# xlsApp.Quit() 

 

1.9 Python 語言之 scons 工具流程分析

 

高通的modem代碼中自帶了 scons 工具,無需自己安裝。

如果自己安裝 scons 執行腳本

setup.py

class install_lib(_install_lib):

    ....

self.install_dir = '/usr/local/lib'

 

script/scons 文件的最後有:

if __name__ == "__main__":

    import SCons.Script

    # this does all the work, and calls sys.exit

    # with the proper exit status when done.

    SCons.Script.main()

表明該文件是腳本,而不是模塊。

========================

因爲 Python 腳本和模塊都是一個以.py結束的文件,那程序是如何判斷一個.py文件是作爲腳本還是模塊呢?

關鍵是一個名爲__name__的變量,如果它的值是__main__,則不能作爲模塊,只能作爲腳本直接運行。所以

在很多腳本的最後都有一段類似下面的語句,限制只能以腳本方式運行,不作爲模塊:

if __name__ == '__main__':

    main()

=========================

SCons.Script.main()實際上執行的是文件:

/usr/local/lib/scons-1.2.0/SCons/Script/Main.py

 

在 def _main(parser): 函數中有:

    ...

    scripts = []

    if options.file:

        scripts.extend(options.file)

    if not scripts:

        sfile = _SConstruct_exists(repositories=options.repository,

                                   filelist=options.file)

        if sfile:

            scripts.append(sfile)

 

    if not scripts:

        if options.help:

            # There's no SConstruct, but they specified -h.

            # Give them the options usage now, before we fail

            # trying to read a non-existent SConstruct file.

            raise SConsPrintHelpException

        raise SCons.Errors.UserError, "No SConstruct file found."

    ...

 

scons --help 答應幫助信息

執行 scons 命令,那麼通過函數 _SConstruct_exists 會在當前目錄下查找名爲 SConstruct 的文件,如果

不存在,那麼 sfile 等於 None, 如果存在 sfile 等於 SConstruct

如果 scons -f makefile 指定腳本文件,那麼 options.file 等於 ['makefile']

scripts = [] 經過 scripts.extend(options.file) 處理以後變爲: ['makefile']

 

默認情況下 options 的值爲:

{'debug_explain': False, 'debug_includes': False, '__defaults__': <Values at 0xa20652c: {'implicit_cache': False, 'cache_debug': None, 'cache_force': False, 'keep_going': False, 'random': False, 'no_builtin_rules': None, 'list_actions': None, 'list_where': None, 'no_exec': False, 'directory': [], 'file': [], 'warn_undefined_variables': None, 'help': False, 'old_file': [], 'md5_chunksize': 64, 'silent': False, 'question': False, 'duplicate': 'hard-soft-copy', 'write_filenames': None, 'override': None, 'implicit_deps_unchanged': False, 'config': 'auto', 'no_progress': False, 'stack_size': None, 'load_average': 0, 'climb_up': 0, 'cache_disable': False, 'new_file': None, 'site_dir': None, 'max_drift': 172800, 'warn': [], 'tree_printers': [], 'taskmastertrace_file': None, 'ignore_errors': False, 'cache_show': False, 'profile_file': None, 'include_dir': [], 'diskcheck': None, 'repository': [], 'p': None, 'list_derived': None, 'clean': False, 'debug': [], 'no_site_dir': False, 'num_jobs': 1, 'implicit_deps_changed': False, 'interactive': False}>, '__SConscript_settings__': {}}

 

 

開始編譯:

    ...

    taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace)

    ...

    global num_jobs

    num_jobs = options.num_jobs

    jobs = SCons.Job.Jobs(num_jobs, taskmaster)

    ...

    def jobs_postfunc(

        jobs=jobs,

        options=options,

        closing_message=closing_message,

        failure_message=failure_message

        ):

        if jobs.were_interrupted():

            progress_display("scons: Build interrupted.")

            global exit_status

            global this_build_status

            exit_status = 2

            this_build_status = 2

 

        if this_build_status:

            progress_display("scons: " + failure_message)

        else:

            progress_display("scons: " + closing_message)

        if not options.no_exec:

            if jobs.were_interrupted():

                progress_display("scons: writing .sconsign file.")

            SCons.SConsign.write()

 

    progress_display("scons: " + opening_message)

    jobs.run(postfunc = jobs_postfunc)

....

 

jobs.run 執行的是文件:

/usr/local/lib/scons-1.2.0/SCons/Job.py 中類 Jobs 的 run 函數:

 

 

Jobs 類分析:

class Jobs:

    # 一個類的實例可以初始化多個jobs,它提供了 啓動,停止,等待 這些jobs 的方法。

    def __init__(self, num, taskmaster):

        #如果 num 等於或者小於 1, 使用串行的工作方式,否則所有的工作線程將並行運行

        屬性 'num_jobs' 設置成實際的jobs數,如果 job 的請求數大於 1 ,但是 並行工作無法執行,

    那麼 'num_jobs' 將會被重置爲 1 . 初始化之後,Wrapping interfaces that

        care 將會對 'num_jobs' 值進行檢測。

 

        self.job = None

        if num > 1:

            stack_size = explicit_stack_size

            if stack_size is None:

                stack_size = default_stack_size

               

            try:

                self.job = Parallel(taskmaster, num, stack_size)

                self.num_jobs = num

            except NameError:

                pass

        if self.job is None:

            self.job = Serial(taskmaster)

            self.num_jobs = 1

 

    def run(self, postfunc=lambda: None):

        self._setup_sig_handler()

        try:

            self.job.start()

        finally:

            postfunc()

            self._reset_sig_handler()

 

    def were_interrupted(self):

        Returns whether the jobs were interrupted by a signal.

        return self.job.interrupted()

 

    def _setup_sig_handler(self):

 

        def handler(signum, stack, self=self, parentpid=os.getpid()):

            if os.getpid() == parentpid:

                self.job.taskmaster.stop()

                self.job.interrupted.set()

            else:

                os._exit(2)

 

        self.old_sigint  = signal.signal(signal.SIGINT, handler)

        self.old_sigterm = signal.signal(signal.SIGTERM, handler)

        try:

            self.old_sighup = signal.signal(signal.SIGHUP, handler)

        except AttributeError:

            pass

 

    def _reset_sig_handler(self):

        """Restore the signal handlers to their previous state (before the

         call to _setup_sig_handler()."""

 

        signal.signal(signal.SIGINT, self.old_sigint)

        signal.signal(signal.SIGTERM, self.old_sigterm)

        try:

            signal.signal(signal.SIGHUP, self.old_sighup)

        except AttributeError:

            pass

 

Scons 全局常用方法:

# The list of global functions to add to the SConscript name space

# that end up calling corresponding methods or Builders in the

# DefaultEnvironment().

GlobalDefaultEnvironmentFunctions = [

    # Methods from the SConsEnvironment class, above.

    'Default',

    'EnsurePythonVersion',

    'EnsureSConsVersion',

    'Exit',

    'Export',

    'GetLaunchDir',

    'Help',

    'Import',

    #'SConscript', is handled separately, below.

    'SConscriptChdir',

 

    # Methods from the Environment.Base class.

    'AddPostAction',

    'AddPreAction',

    'Alias',

    'AlwaysBuild',

    'BuildDir',

    'CacheDir',

    'Clean',

    #The Command() method is handled separately, below.

    'Decider',

    'Depends',

    'Dir',

    'NoClean',

    'NoCache',

    'Entry',

    'Execute',

    'File',

    'FindFile',

    'FindInstalledFiles',

    'FindSourceFiles',

    'Flatten',

    'GetBuildPath',

    'Glob',

    'Ignore',

    'Install',

    'InstallAs',

    'Literal',

    'Local',

    'ParseDepends',

    'Precious',

    'Repository',

    'Requires',

    'SConsignFile',

    'SideEffect',

    'SourceCode',

    'SourceSignatures',

    'Split',

    'Tag',

    'TargetSignatures',

    'Value',

    'VariantDir',

]

GlobalDefaultBuilders = [

    # Supported builders.

    'CFile',

    'CXXFile',

    'DVI',

    'Jar',

    'Java',

    'JavaH',

    'Library',

    'M4',

    'MSVSProject',

    'Object',

    'PCH',

    'PDF',

    'PostScript',

    'Program',

    'RES',

    'RMIC',

    'SharedLibrary',

    'SharedObject',

    'StaticLibrary',

    'StaticObject',

    'Tar',

    'TypeLibrary',

    'Zip',

    'Package',

]

 

for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:

    exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))

del name

1.9.1 Program 方法

編譯可執行程序

1.9.2 Library 方法

Scons可以用env.Library(‘liba’, ‘a.c’)的方法用環境的定義編譯靜態庫,或者用Program定義可執行程序。並且支持輸入和環境定義不同的參數,如

env.Library(‘liba’, ‘a.c’, CPPDEFINES = ['NEWMACRO'], CCFLAGS=['/Ox'])。

不過,很可惜,Builder默認是覆蓋環境中現有參數,而不是追加。所以,要用多個編譯參數稍有不同的程序和庫編譯只能用Clone後Append。

tempEnv = libEnv.Clone()

tempEnv.Append(CPPDEFINES = ['NEWMACRO'], CCFLAGS=['/Ox'])

tempEnv.Library('liba', 'a.c')

最近用scons的收穫

http://blog.chinaunix.net/u2/71769/showart_2243166.html

 

2、高通常用工具使用

2.1 QPST

QPST(Qualcomm Product Support Tool),這個工具類似電腦上的資源管理器,可用於手機和PC間的數據傳輸,手機軟件版本升級,部分內置參數如 APN的修改,上行加密,完整性保護參數設置等。

2.2 QXDM

QXDM(Qualcomm eXtensive Diagnostic Monitor),主要用於抓取up口的上,下行信令業務數據包,並可多窗口實時顯示諸如功率,速率,誤碼率等參數,是系統測試人員最常用的軟件之一。

常用功能

2.3 QCAT

QCAT(Qualcomm log Analysis Tool) ,它主要用於對 QXDM捕獲的二進制代碼文件進行解碼分析,並可轉換爲文本格式輸出。APEX(Analysis and Post-processing Expert)是QCAT的升級替換版本,功能是類似的。

 

3、工程模式

Making a Factory Image

1. To make a factory image, the file mibib.mbn must exist in the

   \build\ms\bin\<build_id> directory.

2. To verify the factory image with USB, the file \tools\mjnand.cmm must include

   the option “Program Factory Image”.

有誰用過QSC6085平臺採用NAND FLASH燒錄,具體怎麼打包燒錄文件?還有想把文件系統也打包到燒錄文件裏怎麼實現?請高手不嗇賜教!!!小弟在此謝過!!!!

用tools目錄下的qfit生成,有文檔介紹的。多看看資料。。。。。。。

 

./AMSS/products/7x30/build/ms/dmss_rules.min

genmibib:

    @echo ----------------------------------------------------------------------

    @echo Building mibib.mbn

    @pwd

    #$(BUILD_MIBIB_CMD)

    @echo ----------------------------------------------------------------------

BUILD_MIBIB_CMD 在文件 ./AMSS/products/7x30/build/ms/armtools.min:333 中

ifeq ($(BUILD_UNIX), yes)

ac_EXE=

else

ac_EXE=.exe

endif

BUILD_MIBIB_CMD = $(FLASH_NAND_TOOLS_SRC)/nand_tools$(ac_EXE) -fp $(NAND_PAGE_SIZE) -fb $(NAND_BLK_SIZE) -fd $(NAND_DEVICE_SIZE) \

                  -u partition.mbn -q qcsblhd_cfgdata.mbn -ah amsshd.mbn -m mibib.mbn -oh oemsblhd.mbn \

                  -wh appshd.mbn -bh appsboothd.mbn -p $(MIBIB_DEST_PATH)

把 genmibib 規則中的 #$(BUILD_MIBIB_CMD) 選項打開

它實際上是進入目錄: AMSS/products/7x30/build/ms  然後執行命令:

../../core/storage/flash/tools/src/nand/nand_tools -fp 4096 -fb 64 -fd 1024 -u partition.mbn -q qcsblhd_cfgdata.mbn -ah amsshd.mbn -m mibib.mbn -oh oemsblhd.mbn -wh appshd.mbn -bh appsboothd.mbn -p ../../build/ms/bin/AABBQOLY

要生成 qcsblhd_cfgdata.mbn  還必須打開文件

./AMSS/products/7x30/build/ms/dmss7X30modem.mak:49 中的

#include boot_targets_$(SEC_MODE).min 語句

 

. ./make-AAABQOLYM.sh  gencfgdata

Generating Configuration Generation Tool

make: *** ../../secboot/cfg_data: 沒有該文件或目錄。 停止。

make: *** [../../secboot/cfg_data/Config_Gen.exe] 錯誤 2

. ./make-AAABQOLYM.sh  genmibib

. ./make-AAABQOLYM.sh  gencfgdata

 

從目前的版本中可以看出,只有文件 partition.mbn 存在,其他都不存在。Oemsblhd.mbn 等這些只存在老的軟件版本中。

 

運行 QFIT 工具

Perl 工具 /opt/shared/win_exe/ActivePerl-5.6.1.638-MSWin32-x86.msi

Windows dos 窗口下,進入 qfit 目錄執行 QFIT.cmd 啓動 qfit程序

 

./AMSS/products/7x30/core/bsp/build/data/incpathsaaabqmazm.py:472:  

env.Replace(FLASH_NAND_TOOLS_CFG = "config_v2")

./AMSS/products/7x30/core/bsp/build/data/incpathsaabbqclym.py:166:  

env.Replace(FLASH_HAL_CFG = "config_v2")

 

HAL  headware abstract layer

DAL

./AMSS/products/7x30/build/ms/bin/AABBQOLY/NPRG7x30.hex

./AMSS/products/7x30/core/bsp/tools/flash/hostdl/build/NPRG7x30_AABBQOLYM.hex

 

QFIT工具的位置

./AMSS/products/7x30/tools/qfit

qfit 工具只能在 windows 環境下使用,通過 QFIT.cmd 腳本啓動 QFIT 工具

運行 QFIT.cmd 腳本之前設置環境變量:set PERL5.6.1=c:\perl\bin

qfit.pl ->

use Make_Factory_Image;

Make_Factory_Image::make_factory_image

 

生成 Factory Image

./AMSS/products/7x30/tools/qfit/QFIT.pl:1108:

make_frame('MakeFactoryImage','$tab21');

$show_layout_button = make_button("Preview\n Image Layout",$action_no_target_color,'&preview_image_layout');

$MakeFactoryButton  = make_button("Make\nFactory Image",$action_no_target_color,'&make_factory_image');

make_frame('MakeFactoryImage2','$tab21');

make_button("Select Image  \nFile",$action_not_configured_color,'&SelectFactoryFile');

make_entry_box('','$FactoryImageFileName',$file_box_size);

make_frame('MakeFactoryImage3','$tab21');

make_progress_bar('\$factory_make_percent');

 

Make_Factory_Image::make_factory_image({

                                 factory_image_file      => $FactoryImageFileName,

                                 include_partitions_ref  => \@image_include,

                                 single_partition_file   => $make_factory_image_single_partition_output_file,

                                 partition_mbn_file      => $partition_mbn_file,

                                 local_directory         => $LocalDir,

                                 include_factory_header  => $include_factory_header,

                                 make_dataio_files       => $make_dataio_files,

                                 reuse_ecc_file          => $reuse_ecc_file,

                                 abort_after_error       => $abort_after_error,

                                 percent_done_ref        => \$factory_make_percent,

                           });

Make_Factory_Image::make_factory_image 執行的是文件:

./AMSS/products/7x30/tools/qfit/Make_Factory_Image.pm:

中的函數 make_factory_image

AMSS build must contain mibib.mbn to use QFIT 1.5.02

同時需要的有:

mibib.mbn amss.mbn appsboot.mbn apps.mbn

通過 QFIT 生成 factory image 必須存在 mibib.mbn

 

燒寫 Factory Image 通過 qpst

make_frame('ProgramFactoryImage','$tab22');

$ProgramButton = make_button("Program Factory\nImage into Phone",$action_qpst_target_color,'&program_factory_image_qpst');

 

$ProgramFactoryImage_fr->Label(-text=>'   Factory image is programmed into phone using QPST') -> pack( -side => 'left');

make_frame('ProgramFactoryImage2','$tab22');

make_button("    Select Image    \nFile",$action_not_configured_color,'&SelectProgramFile');

make_entry_box('','$ImageProgramFileName',$file_box_size);

 

sub program_factory_image_qpst

exec ("perl Program_Factory_Image.pl $com_port $timeout $factory_file");

 

 

 

 

4、Android 系統更新升級總結

4.1 刷機基本知識

1. 恢復模式,用update.zip文件

2. 工程模式刷機,刷NBH文件(官方版本)

3. fastboot模式刷機(燒寫img文件)

 

第一種,這也是最常用的刷機方式。  首先,需要有testkey和ROOT,因爲絕大部分的update.zip文件都是自制的,需要有足夠的權限,才能使用測試簽名的文件。將ROM 放進SD,並改名爲update.zip,關機,按特定的鍵開機進入恢復模式。不同廠商的手機進入恢復模式的方法會不一樣。

 

第二種,通常刷官方發佈的NBH文件,刷完會失去ROOT。 NBH文件對應地區,如果沒有開發版的工程模式,只能刷與你手機地區對應的NBH文件。要刷NBH,首先格式化SD卡,選擇FAT32格式。  放入NBH文件,改名成DreaIMG.NBH,NBH是擴展名。 接着關機,按特定的鍵進入工程模式,加載完成後,按關機鍵,開始加載NBH文件,期間5-10分鐘,不用管,完成後,按任意鍵,然後特定鍵關機,重啓進入系統。

 

第三種,fastboot 模式刷機我們應該比較熟悉,在我們軟件開發階段,我們就是用這種方法來燒寫軟件的,它的原理是直接擦出、燒寫、替換分區。  手機端需要SPL支持,這裏的SPL就是我們通常所說的 appsboot.mbn , 這個文件來來自android 源代碼,編譯後通常生成爲:

out/target/product/msm7630_surf/appsboot.mbn 他的源代碼在:

android/bootable/bootloader/lk/

PC端有fastboot命令與手機端的 fastboot 進行通信,傳入特定的命令,讓手機端完成分區擦出、燒寫、重啓等任務。原理和具體使用方法參考 fastboot 刷機

 

目前我們已經能做到第一和第三種的刷機方式,第二種因爲原理還不是很明白,會根據實際情況再介紹。

 

4.1.1 各品牌代表手機刷機模式進入方法

4.1.1.1 HTC G1

Home+電源  進入recovery模式

電源+照相  進入工程模式

回鍵+電源  進入fastboot模式

4.1.1.2 三星 Galaxy i7500 

專用刷機模式  進入方法:音量向下+OK+電源

recovery模式  進入方法:音量向下+通話+電源

Fastboot模式,進入方法:通話+電源

也就是看SPL版本那個畫面

4.1.1.3 Google Nexus One

Fastboot 模式  進入方法:"電源鍵+軌跡球"

進入 fastboot 模式後,可以通過音量鍵和電源鍵在 recovery 、hboot、fastboot 集中模式間進行切換。

4.1.2 fastboot 模式

4.1.2.1 fastboot 模式概述

Fastboot 和 HBoot 模式在 appsboot.mbn 中

 

終端執行以下命令 sudo fastboot devices ,如果設備連接正常且進入fastboot 模式那麼會返回類似如下的信息:

HT849GZ58999  fastboot

Fastboot pc客戶端和手機端通常需要版本一致或者接近,否則會出現找不到設備,或者某些命令無法支持。

除了按鍵能進入 fastboot 模式外,系統重啓也可以進入。

reboot_device(FASTBOOT_MODE);

./bootloader/lk/app/aboot/aboot.c:59:#define FASTBOOT_MODE   0x77665500

./bootloader/lk/target/msm7630_surf/init.c:251:

void reboot_device(unsigned reboot_reason)

    reboot(reboot_reason);

./bootloader/lk/platform/msm_shared/proc_comm.c:243:

void reboot(unsigned reboot_reason)

 

void reboot(unsigned reboot_reason)

{

        msm_proc_comm(PCOM_RESET_CHIP, &reboot_reason, 0);

        for (;;) ;

}

 

內核中的重啓:

void machine_restart(char * __unused)

{

        arm_pm_restart(reboot_mode);

}

./kernel/kernel/sys.c:308:  machine_restart(cmd);

 

void kernel_restart(char *cmd)

{

    kernel_restart_prepare(cmd);

    if (!cmd)

       printk(KERN_EMERG "Restarting system.\n");

    else

       printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);

    machine_restart(cmd);

}

./kernel/kernel/sys.c:414:     

kernel_restart(buffer);

 

kernel/arch/alpha/kernel/process.c:102:  

if (how->mode == LINUX_REBOOT_CMD_RESTART) {

kernel/arch/alpha/kernel/process.c:146:  

if (! alpha_using_srm && how->mode != LINUX_REBOOT_CMD_RESTART) {

kernel/arch/alpha/kernel/process.c:171:  

common_shutdown(LINUX_REBOOT_CMD_RESTART, restart_cmd);

4.1.2.2 PC端fastboot 命令分析

4.1.2.2.1 命令選項 –w –s  -p –c

sudo fastboot –w

將會擦除 userdata  和 cache  分區

erasing 'userdata'... OKAY

erasing 'cache'... OKAY

如果設備未就緒提示:

< waiting for device >

 

sudo fastboot boot –s

sudo fastboot -s WH9AMP200206 getvar version

返回:

sudo fastboot -s WH9AMP200206 getvar product

返回:

 

usb_handle *usb_open(ifc_match_func callback)

{

    return find_usb_device("/dev/bus/usb", callback);

}

./system/core/fastboot/usb_linux.c

通過讀取設備文件 /dev/bus/usb/

我們的大板插入usb 進入 fastboot 模式,會有設備:

/dev/bus/usb/001/022

如果我們設備的驅動中沒有指定,那麼將顯示 '???????'

 

sudo fastboot boot –c xxxx

-c 用於啓動內核的時候指定命令行參數,覆蓋內核的命令行參數

 

jresult_t core_handle_ep0(void *core_ctx, juint8_t *buffer, device_speed_t speed)

./AMSS/products/7x30/core/wiredconnectivity/hsusb/core/src/jslave/core/jusb_core.c:1060:   

return chp9_handle_usb_command(core, buffer, core->ep0_req_tag);

chp9_handle_usb_command調用的是文件:

./AMSS/products/7x30/core/wiredconnectivity/hsusb/core/src/jslave/core/jusb_chp9.c:2057 中的函數:

jresult_t chp9_handle_usb_command(core_t *core, void *buffer, juint8_t ep0_req_tag)

if (req_type == USB_TYPE_STANDARD)

{

rc = core_usb_command(core, ctrl_req, ep0_req_tag);

if (rc != JENOTSUP)

goto Exit;

}

case USB_REQ_GET_DESCRIPTOR:

DBG_V(DSLAVE_CORE, ("CH9: Get descriptor request reached core\n"));

rc = handle_get_descriptor(core, wValue, wIndex, wLength, ep0_req_tag);

break;

 

static jresult_t handle_get_descriptor(core_t *core, juint16_t wValue,

    juint16_t wIndex, juint16_t wLength, juint8_t ep0_req_tag)

    case USB_DT_DEVICE:

        rc = send_descriptor_device(core, wLength, ep0_req_tag);

        break;

 

static jresult_t send_descriptor_device(core_t *core, juint16_t wLength,

    juint8_t ep0_req_tag)

....

    device_desc.iProduct = core->i_product;

    device_desc.iManufacturer = core->i_manufacturer;

    device_desc.iSerialNumber = core->i_serial_number;

    device_desc.idVendor        = htole16(dev_info->vendor);

    device_desc.idProduct       = htole16(dev_info->product);

 

 

4.1.2.3 手機端fastboot 命令分析

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);

4.1.2.3.1 boot

4.1.2.3.2 erase

4.1.2.3.3 flash

4.1.2.3.4 continue

4.1.2.3.5 reboot

4.1.2.3.6 reboot-bootloader

4.1.2.3.7 getvar

bootable/bootloader/lk/app/aboot/aboot.c

fastboot_publish("product", "swordfish");

fastboot_publish("kernel", "lk");

fastboot_publish("version", "0.5");

調用

sudo fastboot  getvar product

sudo fastboot  getvar kernel

sudo fastboot  getvar lk

只有 fastboot_publish 某變量以後,才能用 sudo fastboot  getvar 獲取某變量的值

4.1.2.3.8 download

dd  

4.1.2.3.9 update

4.1.2.3.9.1 system/core/fastboot/fastboot.c:294:       

4.1.2.3.9.2 fprintf(stderr, "archive does not contain '%s'\n", name);

4.1.2.4 fastboot 模式流程分析

 

4.1.3 recovery 模式

4.1.3.1 recovery 模式概述

Recovery 模式是 android 手機進行系統恢復/升級的一種方式,在設置模塊中通過菜單 ”恢復出廠設置”把系統能恢復到出廠默認狀態(會清空用戶保存在手機上的電話本,短信,電子郵件,應用程序數據等信息);通過按鍵進入該模式可以把 sdcard 上的系統升級包寫入到手機中實現系統軟件更新。

進入 recovery 模式需要一定條件,通常以下幾種方式可以進入:

1. 關機狀態下通過按鍵進入(如:同時按 HOME + 電源 進入 recovery 模式)

2. 恢復出廠設置進入 recovery 模式

3. 系統升級進入 recovery 模式

4. 開機狀態下通過重啓進入

 

進入 recovery 分區的前提是:

手機必須存在 recovery 分區,並且燒寫了 recovery.img 鏡像文件。

recovery.img 鏡像文件主要包括兩部分:

1. 標準的內核鏡像 out/target/product/msm7630_surf/kernel

2. 一個小的文件系統 out/target/product/msm7630_surf/ramdisk-recovery.img,這個小系統提供了一套字符 ui 程序,用於與用戶的交互。

 

相對於正常啓動的 ramdisk.img ,ramdisk-recovery.img 主要有如下區別:

1. init.rc 的內容進行了簡化,原始文件爲:bootable/recovery/etc/init.rc

2. sbin 目錄下多了可執行程序 /sbin/recovery  源代碼爲: bootable/recovery

3. 根目錄下多了 res 資源文件夾, 原始文件爲 bootable/recovery/res

4. 資源文件夾下有 res/keys 文件,用於軟件安裝時候的文件驗證

5. 根目錄下文件 default.prop 的內容分別來自:

out/target/product/msm7630_surf/root/default.prop out/target/product/msm7630_surf/system/build.prop

 

系統升級可以通過多種方式進行:

1. 手機開機狀態下,通過手機自帶的升級程序連接指定的網站下載特定的經過認證的軟件包進行升級,此種升級方式通常是官方自帶的,軟件包也是官方(手機軟件提供商)提供。

2. 通過按鍵進入 手機的 recovery 模式,把待升級的軟件包放在手機SD卡的根目錄,然後選擇 recovery的相應菜單進行升級。此中升級方式在 android 的破解版中很流行,目前安卓網等論壇提供的 android 手機刷機方法都推薦這種方法。

 

不管是主動還是被動進入 recovery 模式,其目的都是爲了給手機軟件升級或者恢復系統的默認設置,如果是升級系統,那麼我們就得製作升級包。

 

4.1.3.2 軟件升級包

能夠被Recovery程序識別並處理的軟件升級包通常包括一些特有的規則:

1)必須是標準的zip壓縮包;

2)recovery腳本必須存入在META-INF\com\google\android\update-script;

3)其它的一些證書和簽名信息應該都放在\META-INF\下。

 

升級一般通過運行升級包中的META-INF/com/google/android/update-script腳本來執行自定義升級,腳本中是一組recovery 系統能識別的控制命令,文件系統操作命令,例如write_raw_image(寫FLASH分區),copy_dir(複製目錄)。該包一般被下載至SDCARD

不同版本的 recovery 程序,它的 update-script 命令格式是不一樣的,例如:

Cupcake 的recovery 程序支持 copy_dir 命令,1.6以後的版本已經取消。

 

4.1.3.3 recovery v1跟recovery v2的區別

recovery v2是從donut開始出現的, 相對於recovery v1做了不少的改動,增強了原有的功能的同時,儘量將可能變化的部分隔離出來,讓各廠商可以添加自己的特性,這些體現在UI,設備功能上。 下面是從v1到v2改動的地方:

1、ui部分獨立出來放到default_recovery_ui.c

界面上的修改一般改這裏就可以了。

 

2、腳本解析器從amend切換到edify

edify支持簡單的邏輯語法,腳本語法也不兼容了,不要迷戀recovery/etc/META-INF/com/google/android/update-script,這個腳本已經

不適合recovery v2。

 

4.1.3.4 軟件升級腳本語法解析

eclair 版本的 recovery 程序支持以下腳本控制命令:

./bootable/recovery/updater/install.c   

RegisterFunction("mount", MountFn);

RegisterFunction("is_mounted", IsMountedFn);

RegisterFunction("unmount", UnmountFn);

RegisterFunction("format", FormatFn);

RegisterFunction("show_progress", ShowProgressFn);

RegisterFunction("set_progress", SetProgressFn);

RegisterFunction("delete", DeleteFn);

RegisterFunction("delete_recursive", DeleteFn);

RegisterFunction("package_extract_dir", PackageExtractDirFn);

RegisterFunction("package_extract_file", PackageExtractFileFn);

RegisterFunction("symlink", SymlinkFn);

RegisterFunction("set_perm", SetPermFn);

RegisterFunction("set_perm_recursive", SetPermFn);

RegisterFunction("getprop", GetPropFn);

RegisterFunction("file_getprop", FileGetPropFn);

RegisterFunction("write_raw_image", WriteRawImageFn);

RegisterFunction("write_firmware_image", WriteFirmwareImageFn);

RegisterFunction("apply_patch", ApplyPatchFn);

RegisterFunction("apply_patch_check", ApplyPatchFn);

RegisterFunction("apply_patch_space", ApplyPatchFn);

RegisterFunction("ui_print", UIPrintFn);

RegisterFunction("run_program", RunProgramFn);

 

./bootable/recovery/edify/expr.c:   

RegisterFunction("ifelse", IfElseFn);

RegisterFunction("abort", AbortFn);

RegisterFunction("assert", AssertFn);

RegisterFunction("concat", ConcatFn);

RegisterFunction("is_substring", SubstringFn);

RegisterFunction("stdout", StdoutFn);

RegisterFunction("sleep", SleepFn);

RegisterFunction("less_than_int", LessThanIntFn);

RegisterFunction("greater_than_int", GreaterThanIntFn);

RegisterFunction(const char* name, Function fn);

 

4.1.3.4.1.1 mount

mount 命令解析

高通 7630 分區信息:

$ cat /proc/mtd

dev:    size   erasesize  name

mtd0: 00500000 00040000 "boot"

mtd1: 06900000 00040000 "system"

mtd2: 00500000 00040000 "cache"

mtd3: 13480000 00040000 "userdata"

mtd4: 00300000 00040000 "persist"

mtd5: 00500000 00040000 "recovery"

語法爲:Mount(type, location, mount_point)

如果 type 爲 "MTD", 那麼 location 可以爲設備分區名稱,默認該分區以 "yaffs" 的方式掛載,如掛載 system 分區:

mount("MTD", "system", "/system")

如果 type 不爲 "MTD" ,那麼必須寫明具體的文件系統類型, location 必須填設備名稱,例如是sdcard ,那麼 type 爲 "vfat"  設備名稱 /dev/block/mmcblk0 :

mount("vfat","/dev/block/mmcblk0","sdcard")

 

 

system 分區掛載過程:

mount("MTD", "system", "/system")

mkdir("system", 0755);

mtd = mtd_find_partition_by_name("system");

mtd_mount_partition(mtd, "/system", "yaffs2", 0 /* rw */)

const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME;

sprintf(devname, "/dev/block/mtdblock%d", mtd->device_index);

mount(/dev/block/mtdblock, "/system", "yaffs2" , flags, NULL);

如果 mtd_mount_partition 第四個參數不爲 0,那麼以只讀方式掛載:

mount(devname, mount_point, filesystem, flags | MS_RDONLY, 0)

平時無法寫系統分區,是因爲 init 在讀取 init.rc 後,默認掛載system 爲只讀

系統更新可以寫system分區,是因爲這裏把該分區掛載成了可讀寫

 

sdcard 掛載過程:

mount("vfat","/dev/block/mmcblk0","sdcard")

mkdir("system", 0755);

mount("/dev/block/mmcblk0", "/sdcard", "vfat",MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")

 

4.1.3.4.1.2 getprop

從系統環境中獲取屬性值

如:

 

4.1.3.4.1.3 file_getprop

語法:

從屬性文件中獲取屬性值,可以爲android系統中的任意屬性配置文件

例如:

getprop ro.bootloader

 

4.1.3.4.1.4 assert

語法:

此命令相當於程序中的斷言

RegisterFunction("assert", AssertFn); 它執行的是 AssertFn 函數

assert() 函數用法

assert宏的原型定義在<assert.h>中,其作用是如果它的條件返回錯誤,則終止程序執行。

4.1.3.4.1.5 format

格式化分區

format BOOT:

format SYSTEM:

4.1.3.4.1.6 apply_patch_check

4.1.3.4.1.7 apply_patch_space

4.1.3.4.1.8 apply_patch

apply_patch_check 

apply_patch_space

apply_patch

以上命令在手機端都是執行函數 ApplyPatchFn

./bootable/recovery/updater/install.c

RegisterFunction("apply_patch", ApplyPatchFn);

RegisterFunction("apply_patch_check", ApplyPatchFn);

RegisterFunction("apply_patch_space", ApplyPatchFn);

語法:

apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)

apply_patch_check(file, sha1, ...)

apply_patch_space(bytes)

 

apply_patch_check

對升級包進行驗證,patch 包是否正確,如果不正確,異常退出

例如:

assert(apply_patch_check("/system/app/Settings.apk", "682e475c6411bb454d5999f6abff50ca8eb373f4", "196c0891869ec4b93a738519daf30a56a96c570d"));

 

apply_patch_space

檢查可用的存儲空間

bootable/recovery/updater/install.c:

char* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[])

 

對軟件包進行打patch

apply_patch("/system/app/Settings.apk", "-",

            682e475c6411bb454d5999f6abff50ca8eb373f4, 1485651,

            "196c0891869ec4b93a738519daf30a56a96c570d:/tmp/patchtmp/system/app/Settings.apk.p");

4.1.3.4.1.9 package_extract_file

pac

package_extract_file("system/app/Settings.apk", "/system/app/ Settings.apk");

4.1.3.4.1.10 ui_print

語法:

ui_print("Verifying current system...");

在屏幕上打印信息: 正在驗證當前系統...

4.1.3.4.1.11 META-INF/com/google/android/update-script 腳本分析

下面以一個升級包的實例分析系統升級具體做了些什麼?

=========================

因爲要更新系統內容,所以首先掛載系統分區爲可讀寫

mount("MTD", "system", "/system");

檢測屬性文件 /system/build.prop 中的屬性值

assert(file_getprop("/system/build.prop", "ro.build.fingerprint") == "google/passion/passion/mahimahi:2.1/ERD79/22607:user/release-keys" ||

       file_getprop("/system/build.prop", "ro.build.fingerprint") == "google/passion/passion/mahimahi:2.1-update1/ERE27/24178:user/release-keys");

檢測系統運行過程中的屬性值

assert(getprop("ro.product.device") == "passion" ||

       getprop("ro.build.product") == "passion");

assert(getprop("ro.bootloader") == "0.33.2012" ||

       getprop("ro.bootloader") == "0.33.0012");

ui_print("Verifying current system...");

show_progress(0.100000, 0);

set_progress(0.001918);

檢測 patch 需要的空間

assert(apply_patch_space(6741176));

ui_print("Unpacking patches...");

釋放 patch 目錄下的內容到 /tmp/patchtmp

package_extract_dir("patch", "/tmp/patchtmp");

刪除不需要的文件...

ui_print("Removing unneeded files...");

刪除不需要的文件...

delete("/system/app/GoogleGoggles.apk", "/system/app/GoogleGoggles.odex",

       "/system/framework/svc.jar",

       "/system/recovery.img");

show_progress(0.800000, 0);

開始打補丁...

ui_print("Patching system files...");

升級設置程序的apk文件

apply_patch("/system/app/Settings.apk", "-",

            682e475c6411bb454d5999f6abff50ca8eb373f4, 1485651,

            "196c0891869ec4b93a738519daf30a56a96c570d:/tmp/patchtmp/system/app/Settings.apk.p");

set_progress(1.000000);

package_extract_dir("recovery", "/system");

show_progress(0.100000, 10);

ui_print("Unpacking new files...");

釋放 system 目錄下的內容到系統的 /system 目錄

package_extract_dir("system", "/system");

ui_print("Symlinks and permissions...");

set_perm_recursive(0, 0, 0755, 0644, "/system");

set_perm_recursive(0, 2000, 0755, 0755, "/system/bin");

set_perm(0, 3003, 02755, "/system/bin/netcfg");

set_perm(0, 3004, 02755, "/system/bin/ping");

set_perm(1001, 1005, 0444, "/system/etc/AudioPara4.csv");

set_perm_recursive(1002, 1002, 0755, 0440, "/system/etc/bluez");

set_perm(0, 0, 0755, "/system/etc/bluez");

set_perm(1002, 1002, 0440, "/system/etc/dbus.conf");

set_perm(1014, 2000, 0550, "/system/etc/dhcpcd/dhcpcd-run-hooks");

set_perm(0, 2000, 0550, "/system/etc/init.goldfish.sh");

set_perm(0, 0, 0544, "/system/etc/install-recovery.sh");

set_perm_recursive(0, 0, 0755, 0555, "/system/etc/ppp");

ui_print("Writing radio image...");

write_firmware_image("PACKAGE:radio.img", "radio");

unmount 系統目錄

unmount("/system");show_progress(0.100000, 10);

 

 

bootable/recovery/updater/updater.c

#define SCRIPT_NAME "META-INF/com/google/android/updater-script"

 

bootable/recovery/install.c:37:

#define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary"

mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);

 

int status = install_package(SDCARD_PACKAGE_FILE);

bootable/recovery/recovery.c:487:       

status = install_package(update_package);

通過 adb 登錄 G1 的分區信息:

/ # cat /proc/mtd

dev:    size   erasesize  name

mtd0: 00040000 00020000 "misc"

mtd1: 00500000 00020000 "recovery"

mtd2: 00280000 00020000 "boot"

mtd3: 05a00000 00020000 "system"

mtd4: 01e00000 00020000 "cache"

mtd5: 059c0000 00020000 "userdata"

高通 7630 分區信息:

$ cat /proc/mtd

dev:    size   erasesize  name

mtd0: 00500000 00040000 "boot"

mtd1: 06900000 00040000 "system"

mtd2: 00500000 00040000 "cache"

mtd3: 13480000 00040000 "userdata"

mtd4: 00300000 00040000 "persist"

mtd5: 00500000 00040000 "recovery"

這些信息是在文件 ./bootable/bootloader/lk/target/msm7630_surf/init.c 中指定的:

static struct ptentry board_part_list[] = {

    {

       .start = 0,

       .length = 20  /* 5MB */,

       .name = "boot",

    },

    {

       .start = 20,

       .length = 380 /* 95MB */,

       .name = "system",

    },

    {

       .start = 400,

       .length = 20 /* 5MB */,

       .name = "cache",

    },

    {

       .start = 420,

       .length = VARIABLE_LENGTH,

       .name = "userdata",

    },

    {

       .start = DIFF_START_ADDR,

       .length = 4 /* 1MB */,

       .name = "persist",

    },

    {

       .start = DIFF_START_ADDR,

       .length = 20 /* 5MB */,

       .name = "recovery",

    },

};

系統支持哪些flash的定義在文件 bootable/bootloader/lk/platform/msm_shared/nand.c 中:

static struct flash_identification supported_flash[] =

{

    /* Flash ID   ID Mask Density(MB)  Wid Pgsz   Blksz  oobsz onenand Manuf */

    {0x00000000, 0xFFFFFFFF,    0, 0, 0,     0,  0, 0}, /*ONFI*/

    {0x1500aaec, 0xFF00FFFF, (256<<20), 0, 2048, (2048<<6), 64, 0}, /*Sams*/

    {0x5500baec, 0xFF00FFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Sams*/

    {0x1500aa98, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 0}, /*Tosh*/

    {0x5500ba98, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Tosh*/

    {0xd580b12c, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Micr*/

    {0x5590bc2c, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Micr*/

    {0x1580aa2c, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 0}, /*Micr*/

    {0x5580baad, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Hynx*/

    {0x5510baad, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Hynx*/

    {0x004000ec, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 1}, /*Sams*/

    {0x005c00ec, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 1}, /*Sams*/

    {0x005800ec, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 1}, /*Sams*/

    {0x6600bcec, 0xFF00FFFF, (512<<20), 1, 4096, (2048<<6), 128, 0}, /*Sams*/

    /* Note: Width flag is 0 for 8 bit Flash and 1 for 16 bit flash    */

    /* Note: Onenand flag is 0 for NAND Flash and 1 for OneNAND flash   */

    /* Note: The First row will be filled at runtime during ONFI probe  */

};

 

pbl -> dbl -> osbl -> appsbl ->進入 recovery 模式

系統運行到 appsbl 階段纔開始是否進入 recovery 模式的處理。

 

 

int device_toggle_display(volatile char* key_pressed, int key_code) {

    return key_code == KEY_HOME;

}

 

 

 

check if nand misc partition has boot message. If yes, fill argc/argv.

If no, get arguments from /cache/recovery/command, and fill argc/argv.

 

讀取 /cache/recovery/command 文件的內容

FILE *fp = fopen_root_path(COMMAND_FILE, "r");

 

G1 的分區信息:

# cat /proc/mtd

dev:    size   erasesize  name

mtd0: 00040000 00020000 "misc"

mtd1: 00500000 00020000 "recovery"

mtd2: 00280000 00020000 "boot"

mtd3: 05a00000 00020000 "system"

mtd4: 01e00000 00020000 "cache"

mtd5: 059c0000 00020000 "userdata"

 

recovery_init() 調用的是文件 bootable/bootloader/lk/app/aboot/recovery.c中的函數:

/* Read and write the bootloader command from the "misc" partition.

 * These return zero on success.

 */

從 misc 分區讀取

misc         0.25MB:是存放開機畫面的分區,開機時那個白色的大G1字樣(默認爲白色"T-mobile G1")

recovery    5MB:是G1的恢復模式鏡像區(即開機按Home+End進入的界面)

Boot         2.5MB:Linux操作系統內核和ramdisk鏡像一起打包後存放的分區

system      90MB:是system.img存放的分區,啓動後此鏡像掛載在根目錄下的system文件夾中。

cache        30MB:是緩存臨時文件夾,掛載爲/cache目錄,據說是除了T-mobile的OTA更新外,別無用處。

userdata     89.75MB:用戶安裝的軟件以及各種數據,掛載爲/data目錄

msm_nand     256MB:代表整個Nand Flash,不是一個分區。但是所有的分區加起來才217.5MB,小於256MB,說明還有剩餘的flash空間。(此分區在大部分機上不存在,不影響使用)

 

 

恢復模式的 init.rc 文件很簡單,只啓動了 recovery 和 adbd 服務

on init

    export PATH /sbin

    export ANDROID_ROOT /system

    export ANDROID_DATA /data

    export EXTERNAL_STORAGE /sdcard

    symlink /system/etc /etc

    mkdir /sdcard

    mkdir /system

    mkdir /data

    mkdir /cache

    mount /tmp /tmp tmpfs

on boot

    ifup lo

    hostname localhost

    domainname localdomain

    class_start default

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

 

4.1.3.4.2 Recovery 模式中 install_package 函數解析

設置模塊中系統升級和sd卡方式軟件升級會調用 install_package 函數

int status = install_package(SDCARD_PACKAGE_FILE);

status = install_package(update_package);

bootable/recovery/install.c:322:install_package(const char *root_path)

int install_package(const char *root_path)

{

    ui_set_background(BACKGROUND_ICON_INSTALLING);

    ui_print("Finding update package...\n");

    ui_show_indeterminate_progress();

    LOGI("Update location: %s\n", root_path);

 

    if (ensure_root_path_mounted(root_path) != 0) {

        LOGE("Can't mount %s\n", root_path);

        return INSTALL_CORRUPT;

    }

 

    char path[PATH_MAX] = "";

    if (translate_root_path(root_path, path, sizeof(path)) == NULL) {

        LOGE("Bad path %s\n", root_path);

        return INSTALL_CORRUPT;

    }

 

    ui_print("Opening update package...\n");

    LOGI("Update file path: %s\n", path);

 

int numKeys;

# #define PUBLIC_KEYS_FILE "/res/keys"

    RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);

    if (loadedKeys == NULL) {

        LOGE("Failed to load keys\n");

        return INSTALL_CORRUPT;

    }

    LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);

 

    // Give verification half the progress bar...

    ui_print("Verifying update package...\n");

    ui_show_progress(

            VERIFICATION_PROGRESS_FRACTION,

            VERIFICATION_PROGRESS_TIME);

 

    int err;

    err = verify_file(path, loadedKeys, numKeys);

    free(loadedKeys);

    LOGI("verify_file returned %d\n", err);

    if (err != VERIFY_SUCCESS) {

        LOGE("signature verification failed\n");

        return INSTALL_CORRUPT;

    }

 

    /* Try to open the package.

     */

    ZipArchive zip;

    err = mzOpenZipArchive(path, &zip);

    if (err != 0) {

        LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");

        return INSTALL_CORRUPT;

    }

 

    /* Verify and install the contents of the package.

     */

    int status = handle_update_package(path, &zip);

    mzCloseZipArchive(&zip);

    return status;

}

 

4.1.3.5 Recovery 流程分析

4.1.3.5.1 恢復出廠設置

addPreferencesFromResource(R.xml.privacy_settings);

菜單描述在文件 packages/apps/Settings/res/xml/privacy_settings.xml

<PreferenceScreen

                android:title="@string/master_clear_title"

                android:summary="@string/master_clear_summary">

            <intent android:action="android.intent.action.MAIN"

                    android:targetPackage="com.android.settings"

                    android:targetClass="com.android.settings.MasterClear" />

</PreferenceScreen>

恢復出廠設置執行的是 activiy MasterClear

packages/apps/Settings/src/com/android/settings/MasterClear.java

-> service.masterClear() 調用文件:

frameworks/base/services/java/com/android/server/FallbackCheckinService.java 中的函數:

public void masterClear()

RecoverySystem.rebootAndWipe()

bootCommand("--wipe_data");

    把內容 "--wipe_data" 寫入到文件 /cache/recovery/command 中

Power.reboot("recovery");

補充:

private static File RECOVERY_DIR = new File("/cache/recovery");

private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");

private static File LOG_FILE = new File(RECOVERY_DIR, "log");

命令文件: /cache/recovery/command

log文件/cache/recovery/log

 

Install: out/target/product/msm7630_surf/root/sbin/adbd

target Non-prelinked: init (out/target/product/msm7630_surf/symbols/init)

target Non-prelinked: adbd (out/target/product/msm7630_surf/symbols/sbin/adbd)

 

4.1.3.5.2 系統更新流程

在設置模塊 -> 關於手機 裏面預設了 “系統更新” 的菜單項配置, 如果安裝的軟件包裏面有過濾器爲:

<intent-filter>

<action android:name="android.settings.SYSTEM_UPDATE_SETTINGS" />

    <category android:name="android.intent.category.DEFAULT" />

</intent-filter>

的軟件包,那麼纔會顯示 ”系統更新” 的菜單項,否則沒有該項菜單。此類菜單的處理方式通過文件:

packages/apps/Settings/src/com/android/settings/Utils.java 中的函數

updatePreferenceToSpecificActivityOrRemove 來實現。

Android 源代碼中爲系統升級包預留了位置  packages/apps/Updater/ 但是沒有具體的源代碼,這個源代碼可以由廠商自己開發,這樣做是爲了方便廠商靈活的定製系統升級方式。

在 HTC 手機中該軟件包通常爲: SystemUpdater.apk 我們可以從他們的手機中提取。

 

流程應該爲:

應用模塊中調用:service.systemUpdate() 實際調用的是文件:

frameworks/base/services/java/com/android/server/FallbackCheckinService.java

中的函數:

public void systemUpdate()

{

    RecoverySystem.rebootAndUpdate();

}

 

frameworks/base/services/java/com/android/server/SystemUpdateReceiver.java

public class SystemUpdateReceiver extends BroadcastReceiver {

    private static final String TAG = "MasterClear";

    @Override

    public void onReceive(Context context, Intent intent) {

        ICheckinService service =

            ICheckinService.Stub.asInterface(

                ServiceManager.getService("checkin"));

              ...

                service.systemUpdate();

              ...

}

frameworks/base/core/java/android/os/ICheckinService.aidl

中加函數函數聲明:

void systemUpdate();

rebootAndUpdate 函數應該爲:

frameworks/base/core/java/com/android/internal/os/RecoverySystem.java

    public static void rebootAndUpdate(File update) throws IOException {

        String path = update.getCanonicalPath();

        if (path.startsWith("/cache/")) {

            path = "CACHE:" + path.substring(7);

        } else if (path.startsWith("/data/")) {

            path = "DATA:" + path.substring(6);

        } else {

            throw new IllegalArgumentException(

                    "Must start with /cache or /data: " + path);

        }

        bootCommand("--update_package=" + path);

}

getCanonicalPath() 獲取文件的絕對路徑

getAbsolutePath()和getCanonicalPath()的不同

public static void test2() throws Exception{

        File file = new File("../update.zip");

        System.out.println(file.getAbsolutePath());

        System.out.println(file.getCanonicalPath());

    }

得到的結果

/data/bin/../update.zip

/data/update.zip

 

bootCommand("--update_package=" + path) 會寫命令:

--update_package= CACHE:/cache/xxxx  或者 --update_package= DATA:/data/xxxx 到命令文件:

/cache/recovery/command

 

重啓以後,會檢查命令文件 /cache/recovery/command

    // --- if that doesn't work, try the command file

    if (*argc <= 1) {

        FILE *fp = fopen_root_path(COMMAND_FILE, "r");

        if (fp != NULL) {

            char *argv0 = (*argv)[0];

            *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);

            (*argv)[0] = argv0;  // use the same program name

 

            char buf[MAX_ARG_LENGTH];

            for (*argc = 1; *argc < MAX_ARGS; ++*argc) {

                if (!fgets(buf, sizeof(buf), fp)) break;

                (*argv)[*argc] = strdup(strtok(buf, "\r\n"));  // Strip newline.

            }

 

            check_and_fclose(fp, COMMAND_FILE);

            LOGI("Got arguments from %s\n", COMMAND_FILE);

        }

    }

static const struct option OPTIONS[] = {

  { "send_intent", required_argument, NULL, 's' },

  { "update_package", required_argument, NULL, 'u' },

  { "wipe_data", no_argument, NULL, 'w' },

  { "wipe_cache", no_argument, NULL, 'c' },

  { NULL, 0, NULL, 0 },

};

 

while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {

        switch (arg) {

        case 'p': previous_runs = atoi(optarg); break;

        case 's': send_intent = optarg; break;

        case 'u': update_package = optarg; break;

        case 'w': wipe_data = wipe_cache = 1; break;

        case 'c': wipe_cache = 1; break;

        case '?':

            LOGE("Invalid command argument\n");

            continue;

        }

}

因爲  /cache/recovery/command 內容爲 --update_package= CACHE:/cache/xxxx 所以 update_package 不爲空,

 

如果不爲空,那麼將會執行命令 install_package 對包進行安裝

if (update_package != NULL) {      

status = install_package(update_package);

升級包具體做什麼內容,完全由腳本: META-INF/com/google/android/update-script 和 包的內容所決定。具體內容參考章節 軟件升級包以及軟件升級腳本語法解析

 

 

4.1.3.5.3 通過sd卡實現刷機

首先通過特定按鍵進入 recovery 模式,符合規定的軟件升級包命名爲 update.zip 放在sd卡根目錄,

具體升級過程由升級包中的腳本決定,過程跟系統升級類似

static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip";

int status = install_package(SDCARD_PACKAGE_FILE);

 

 

fastboot 模式下燒寫 recovery 分區

 

手動打包 ramdisk-recovery.img

out/host/linux-x86/bin/mkbootfs out/target/product/msm7630_surf/recovery/root | out/host/linux-x86/bin/minigzip > out/target/product/msm7630_surf/ramdisk-recovery.img

MKBOOTFS=out/host/linux-x86/bin/mkbootfs

ROOT_DIR=out/target/product/$TARGET_PRODUCT/recovery/root

MINIGZIP=out/host/linux-x86/bin/minigzip

OUTPUT=out/target/product/$TARGET_PRODUCT/ramdisk-recovery.img

$MKBOOTFS  $ROOT_DIR | $MINIGZIP > $OUTPUT

手動生成 recovery.img

out/host/linux-x86/bin/mkbootimg  --kernel out/target/product/msm7630_surf/kernel  --ramdisk out/target/product/msm7630_surf/ramdisk-recovery.img --pagesize 4096 --cmdline "console=ttyDCC0 androidboot.hardware=qcom" --base 0x00200000 --output out/target/product/msm7630_surf/recovery.img

MKBOOTIMG=out/host/linux-x86/bin/mkbootimg

KERNEL=out/target/product/$TARGET_PRODUCT/kernel

RAMDISK=out/target/product/$TARGET_PRODUCT/ramdisk-recovery.img

PAGESIZE=4096

CMDLINE="console=ttyDCC0 androidboot.hardware=qcom"

BASE=0x00200000

OUTPUT=out/target/product/$TARGET_PRODUCT/recovery.img

$MKBOOTIMG --kernel $KERNEL --ramdisk $RAMDISK --pagesize $PAGESIZE --cmdline "$CMDLINE" --base $BASE --output $OUTPUT

sudo fastboot-eclair2.2 flash recovery out/target/product/msm7630_surf/recovery.img

 

4.1.3.6 系統升級包案例分析

可以改善G網通話質量的update.zip

http://bbs.91android.com/thread-221208-1-1.html

從此告別延遲,來電痛快接聽

http://www.nduoa.com/android_gphone_forum-viewthread-tid-4735-from-home.html

解決G3誤刷SPL無法開機卡在RA界面

http://android.tgbus.com/lab/break/201005/307573.shtml

 

4.1.4 工程模式(HBoot) 模式

工程模式又叫 hboot 模式 ,它在 appsboot.mbn 中進行處理,該部分內容暫略

4.1.4.1 HBOOT降級方法

Revert HBOOT 0.35.0017 to 0.33.0012

http://forum.xda-developers.com/showthread.php?t=726258

 

 

exec ("perl Program_Factory_Image.pl $com_port $timeout $factory_file");

 

vim system/core/rootdir/etc/init.qcom.rc

symlink /persist/qcom_wlan_nv.bin /etc/firmware/wlan/qcom_wlan_nv.bin

make  out/target/product/msm7630_surf/persist.img

out/host/linux-x86/bin/mkyaffs2image -f -s 4096 out/target/product/msm7630_surf/persist out/target/product/msm7630_surf/persist.img

chmod a+r out/target/product/msm7630_surf/persist.img

 

# cat /proc/mtd

dev:    size   erasesize  name

mtd0: 00480000 00020000 "recovery"

mtd1: 00480000 00020000 "boot"

mtd2: 00060000 00020000 "misc"

mtd3: 00c80000 00020000 "cache"

mtd4: 09600000 00020000 "system"

mtd5: 127e0000 00020000 "userdata"

mtd6: 00180000 00020000 "persist"

cat /dev/mtd/mtd0 > /sdcard/recovery.img

cat /dev/mtd/mtd1 > /sdcard/boot.img

cat /dev/mtd/mtd2 > /sdcard/misc.img

cat /dev/mtd/mtd3 > /sdcard/cache.img

cat /dev/mtd/mtd4 > /sdcard/system.img

cat /dev/mtd/mtd5 > /sdcard/userdata.img

cat /dev/mtd/mtd6 > /sdcard/persist.img

 

./external/qemu/android/main.c:1962:           

char*  out = getenv("ANDROID_PRODUCT_OUT");

external/qemu/android/avd/info.c:1176:

#define  PREBUILT_KERNEL_PATH   "prebuilt/android-arm/kernel/kernel-qemu"

external/qemu/android/main.c:2017:          

opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");

external/qemu/android/main.c:2022:           

opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");

external/qemu/android/main.c:2027:           

opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");

 

 

external/qemu/hw/goldfish_mmc.c:503:    s->dev.name = "goldfish_mmc";

 

如果不存在文件 prebuilt/android-arm/kernel/kernel-qemu 運行模擬器會彈出錯誤:

emulator: ERROR: bad workspace: cannot find prebuilt kernel in: prebuilt/android-arm/kernel/kernel-qemu

 

 

android_avdParams->skinName     = opts->skin;

android_avdParams->skinRootPath = opts->skindir;

android_avdInfo = avdInfo_newForAndroidBuild(

                            android_build_root,

                            android_build_out,

                            android_avdParams );

 

avdInfo_newForAndroidBuild -> _getBuildImagePaths ->

#define  PREBUILT_KERNEL_PATH   "prebuilt/android-arm/kernel/kernel-qemu"

return qemu_main(n, args);

4.2 如何製作升級包 update.zip

升級包可以按照自己的需求定製,只要按照它的製作規範生成就行。

一個小的升級包可能僅僅是爲了替換系統分區的某個應用(system/app/Settings.apk)或者某個配置文件(system/etc/apns-conf.xml) ,或者僅僅是執行某項操作(刪除system/app/FM.apk)。這種簡單的升級包我們完全可以通過手動的方式創建、添加然後再簽名。但是複雜一點的升級包,如系統升級,這個可能涉及到整個系統的應用,甚至framework層,可能會涉及到數百個文件,手動顯然是不現實的,而且完全替換會花費過多的資源和時間,所以這個過程我們將用源代碼中自帶的一套工具來完成。

4.2.1 手動製作升級包

4.2.2 自動製作升級包

./build/core/Makefile

# -----------------------------------------------------------------

# OTA update package

ifneq ($(TARGET_SIMULATOR),true)

ifneq ($(TARGET_PRODUCT),sdk)

#ifneq ($(TARGET_DEVICE),generic)

ifneq ($(TARGET_PRODUCT),generic)

 

name := $(TARGET_PRODUCT)

ifeq ($(TARGET_BUILD_TYPE),debug)

  name := $(name)_debug

endif

name := $(name)-ota-$(FILE_NAME_TAG)

 

INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip

 

ifeq ($(TARGET_USERIMAGES_USE_EXT2),true)

INTERNAL_OTA_PACKAGE_TARGET_MMC := $(PRODUCT_OUT)/$(name)_mmc.zip

else

INTERNAL_OTA_PACKAGE_TARGET_MMC :=

endif

 

$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)

$(INTERNAL_OTA_PACKAGE_TARGET_MMC): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)

ifeq ($(TARGET_OTA_SCRIPT_MODE),)

# default to "auto"

$(INTERNAL_OTA_PACKAGE_TARGET): scriptmode := auto

$(INTERNAL_OTA_PACKAGE_TARGET_MMC): scriptmode := auto

else

$(INTERNAL_OTA_PACKAGE_TARGET): scriptmode := $(TARGET_OTA_SCRIPT_MODE)

$(INTERNAL_OTA_PACKAGE_TARGET_MMC): scriptmode := $(TARGET_OTA_SCRIPT_MODE)

endif

 

$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS)

    @echo "Package OTA: $@"

    $(hide) ./build/tools/releasetools/ota_from_target_files \

       -m $(scriptmode) \

       -p $(HOST_OUT) \

       -k $(KEY_CERT_PAIR) \

       $(BUILT_TARGET_FILES_PACKAGE) $@

 

.PHONY: otapackage

otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)

 

$(INTERNAL_OTA_PACKAGE_TARGET_MMC): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS)

    @echo "Package OTA: $@"

    $(hide) ./build/tools/releasetools/ota_from_target_files \

       -m $(scriptmode) \

       -p $(HOST_OUT) \

       -t MMC\

       -k  $(KEY_CERT_PAIR) \

       $(BUILT_TARGET_FILES_PACKAGE) $@

 

.PHONY: otapackage_mmc

otapackage_mmc: $(INTERNAL_OTA_PACKAGE_TARGET_MMC)

 

在 ./build/core/Makefile 文件中,會通過 ota_from_target_files 命令生成系統安裝包。

./build/tools/releasetools/ota_from_target_files

  if OPTIONS.incremental_source is None:

    WriteFullOTAPackage(input_zip, output_zip)

  else:

    print "unzipping source target-files..."

    OPTIONS.source_tmp = common.UnzipTemp(OPTIONS.incremental_source)

    source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")

WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)

在源代碼中,默認情況下OPTIONS.incremental_source 是None,所以調用 WriteFullOTAPackage 生成的包是完全更新的升級包,如果我們通過參數 "-i", "--incremental_from" 指定基礎版本的 target_files 文件(通常對應:out/target/product/msm7630_surf/obj/PACKAGING/target_files_intermediates/msm7630_surf-target_files-eng.gphone.zip),那麼將會調用 WriteIncrementalOTAPackage 生成帶patch的升級包(默認路徑爲:out/target/product/msm7630_surf/msm7630_surf-ota-eng.gphone.zip)

 

 

4.3 Android 簽名機制

升級包製作完成以後,我們必須還要爲其進行簽名,否則升級認證過程會出錯。

Android提供了爲jar/zip文件簽名的程序signapk.jar 。它的用法如下:

Usage: signapk publickey.x509[.pem] privatekey.pk8 input.jar output.jar

第一個參數是公鑰,即前面第二步產生的testkey.x509.pem。

第二個參數是私鑰,即前面第三步產生的testkey.pk8。

第三個參數是要簽名的文件。

第四個參數是輸出的文件(即簽名後的文件)。

例如:

java -jar signapk.jar testkey.x509.pem testkey.pk8 update.zip update-signed.zip

signapk.jar         out/host/linux-x86/framework/signapk.jar

testkey.x509.pem   build/target/product/security/platform.x509.pem

testkey.pk8         build/target/product/security/platform.pk8

注意:

我們進行系統進行升級,必須使用源代碼中的signapk.jar testkey.x509.pem testkey.pk8

4.4 android 文件系統權限概述

關於Android系統中system.img和data.img中文件系統的權限設置

http://blog.chinaunix.net/u3/103613/showart_2218437.html

{ 04755, AID_ROOT,      AID_ROOT,      "system/bin/fota" },

 

文件系統中各目錄和文件的默認屬性定義:

./system/core/include/private/android_filesystem_config.h

#define AID_ROOT             0  /* traditional unix root user */

 

#define AID_SYSTEM        1000  /* system server */

 

#define AID_RADIO         1001  /* telephony subsystem, RIL */

#define AID_BLUETOOTH     1002  /* bluetooth subsystem */

#define AID_GRAPHICS      1003  /* graphics devices */

#define AID_INPUT         1004  /* input devices */

#define AID_AUDIO         1005  /* audio devices */

#define AID_CAMERA        1006  /* camera devices */

#define AID_LOG           1007  /* log devices */

#define AID_COMPASS       1008  /* compass device */

#define AID_MOUNT         1009  /* mountd socket */

#define AID_WIFI          1010  /* wifi subsystem */

#define AID_ADB           1011  /* android debug bridge (adbd) */

#define AID_INSTALL       1012  /* group for installing packages */

#define AID_MEDIA         1013  /* mediaserver process */

#define AID_DHCP          1014  /* dhcp client */

#define AID_SDCARD_RW     1015  /* external storage write access */

#define AID_VPN           1016  /* vpn system */

#define AID_KEYSTORE      1017  /* keystore subsystem */

#define AID_FM_RADIO   1018  /* FM radio */

#define AID_LOCATION      1019  /* Location */

 

#define AID_SHELL         2000  /* adb and debug shell user */

#define AID_CACHE         2001  /* cache access */

#define AID_DIAG          2002  /* access to diagnostic resources */

 

/* The 3000 series are intended for use as supplemental group id's only.

 * They indicate special Android capabilities that the kernel is aware of. */

#define AID_NET_BT_ADMIN  3001  /* bluetooth: create any socket */

#define AID_NET_BT        3002  /* bluetooth: create sco, rfcomm or l2cap sockets */

#define AID_INET          3003  /* can create AF_INET and AF_INET6 sockets */

#define AID_NET_RAW       3004  /* can create raw INET sockets */

#define AID_NET_ADMIN     3005  /* can configure interfaces and routing tables. */

#define AID_QCOM_ONCRPC   3006  /* can read/write /dev/oncrpc/* files .*/

 

#define AID_MISC          9998  /* access to misc storage */

#define AID_NOBODY        9999

 

#define AID_APP          10000 /* first app user */

 

{ 06755, AID_ROOT,      AID_ROOT,      "system/xbin/su" },

{ 04755, AID_ROOT,      AID_ROOT,      "system/bin/fota" },

 

獲取手機的 root 權限

ui_print("Rooting your phone...");

package_extract_file("system/bin/su", "/system/bin/su");

set_perm(0, 0, 04755, "/system/bin/su");

 

我看到F大的updater-script裏面有這麼一句話。是不是可以理解爲如果要ROOT只要把SU複製到SYSTEM/BIN/目錄下並且設置屬性爲04755就行了?

http://code.google.com/p/superuser/source/checkout

 

 

 

 

 

 

 

 

 

 

4.4.1 獲取手機root權限

root 權限

root 權限主要由 ramdisk 中 ./default.prop 文件決定

====

ro.secure=0

ro.debuggable=0

persist.service.adb.enable=1

那麼默認進入 root 模式

====

ro.secure=1

ro.debuggable=0

persist.service.adb.enable=1

默認進入的是 shell 模式,因爲 ro.debuggable=0

所以 sudo adb root 彈出錯誤:

adbd cannot run as root in production builds

====

ro.secure=0

ro.debuggable=1

persist.service.adb.enable=1

默認進入的是 shell 模式 ,因爲 ro.debuggable=1

所以可以通過 sudo adb root 切換到 root 權限模式

====

ro.secure=1

ro.debuggable=1

persist.service.adb.enable=1

默認進入的是 shell 模式 ,因爲 ro.debuggable=1

所以可以通過 sudo adb root 切換到 root 權限模式

=================================================

如果當前不是 user ,那麼adb調試模式默認開啓

 

 

三星Galaxy s i9000獲取root權限詳細教程

http://android.sj.91.com/content/2010-07-14/20100714181645219.shtml

https://github.com/cmsgs/android_device_samsung_galaxys/blob/master/extract-files.sh

冒死體驗~~~Root Explorer文件管理

http://www.hiapk.com/bbs/thread-7350-1-1.html

獲取root是否成功,可以通過 Root Explorer 軟件查看

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4.4.2 adb默認權限分析

int adb_main(int is_daemon)

{

    ...

    property_get("ro.kernel.qemu", value, "");

    if (strcmp(value, "1") != 0) {

        property_get("ro.secure", value, "");

        if (strcmp(value, "1") == 0) {

            // don't run as root if ro.secure is set...

            secure = 1;

            // ... except we allow running as root in userdebug builds

//if the service.adb.root property has been set by the "adb //root" command

            property_get("ro.debuggable", value, "");

            if (strcmp(value, "1") == 0) {

                property_get("service.adb.root", value, "");

                if (strcmp(value, "1") == 0) {

                    secure = 0;

                }

            }

        }

    }

 

    /* don't listen on port 5037 if we are running in secure mode */

    /* don't run as root if we are running in secure mode */

    if (secure) {

    ...

        gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,

                           AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW, AID_MOUNT };

        setgroups(sizeof(groups)/sizeof(groups[0]), groups);

 

        /* then switch user and group to "shell" */

        setgid(AID_SHELL);

        setuid(AID_SHELL);

    ...

    } else {

        if(install_listener("tcp:5037", "*smartsocket*", NULL)) {

            exit(1);

        }

    }

 

    ...

}

如果不是root用戶,在shell窗口執行id命令:

uid=2000(shell) gid=2000(shell) groups=1003(graphics),1004(input),1007(log),1011(adb),1015(sdcard_rw),3001(net_bt_admin),3002(net_bt),3003(inet)

如果是root用戶執行di命令的結果:

uid=0(root) gid=0(root)

./system/core/sh/var.c:185:    

vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");

 

 

4.4.3 adb root命令切換到 root 權限

if(!strncmp(name, "root:", 5)) {

        ret = create_service_thread(restart_root_service, NULL);

    }

 

void restart_root_service(int fd, void *cookie)

{

    char buf[100];

    char value[PROPERTY_VALUE_MAX];

 

    if (getuid() == 0) {

        snprintf(buf, sizeof(buf), "adbd is already running as root\n");

        writex(fd, buf, strlen(buf));

        adb_close(fd);

    } else {

        property_get("ro.debuggable", value, "");

        if (strcmp(value, "1") != 0) {

            snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");

            writex(fd, buf, strlen(buf));

            adb_close(fd);

            return;

        }

 

        property_set("service.adb.root", "1");

        snprintf(buf, sizeof(buf), "restarting adbd as root\n");

        writex(fd, buf, strlen(buf));

        adb_close(fd);

 

        // quit, and init will restart us as root

        sleep(1);

        exit(1);

    }

}

 

4.4.4 掛載系統分區爲讀寫(remount)

system/core/adb/services.c      

ret = create_service_thread(remount_service, NULL);

void remount_service(int fd, void *cookie)

  remount_system();

    system_ro = mount(source, "/system", "yaffs2", MS_REMOUNT, NULL);

要重新 mount system 分區,必須獲取 root 權限

執行命令 sudo adb root (ro.debuggable=1 才能進行該操作)

mhf@mhf-desktop:~$ sudo adb-eclair2.2 root

adbd cannot run as root in production builds

./system/core/adb/adb.c

 

 

 

在recovery模式下,在cmd.exe下輸入:

adb shell mount /system

adb shell rm /system/bin/su

adb push su /system/bin/

adb shell chmod 4755 /system/bin/su

adb shell rm /system/app/Superuser.*

adb push Superuser.apk /system/app/

adb shell reboot

 

 

package_extract_file("su", "/system/bin/su");

set_perm(0, 0, 06755, "/system/bin/su");

package_extract_file("Superuser.apk", "/system/app/Superuser.apk");

set_perm(0, 0, 0644, "/system/app/Superuser.apk");

run_program("/system/bin/toolbox", "dd", "if=/sdcard/busybox", "of=/system/bin/busybox");

run_program("/system/bin/toolbox", "dd", "if=/sdcard/busybox", "of=/sbin/busybox");

set_perm(0, 0, 0755, "/system/bin/busybox");

set_perm(0, 0, 0755, "/sbin/busybox");

run_program("/sbin/busybox", "--install", "/sbin/");

 

完整的root需要以下幾點
1,使用testkey的recovery,可以用以刷自制rom
2,在boot.img中,有個default.prop,這個文件中必須把ro.secure設置爲0,這樣後,你用adb shell連接時,就是默認的root權限了,而且諸如su等程序也能運行了
3,以上就有了root,不過大多數人爲了安全,改造了su,與Superuser 關聯了,方便管理哪些程序給root權限。

 

mhf@mhf-desktop:~$ sudo adb-eclair2.2 root

* daemon not running. starting it now *

* daemon started successfully *

adbd cannot run as root in production builds

 

 

 

system/core/adb/services.c         

snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");

system/core/adb/services.c:408:    } else if(!strncmp(name, "root:", 5)) {

system/core/init/devices.c:348:    setegid(AID_ROOT);

service.adb.root

ro.debuggable

 

 

mhf@mhf-desktop:~$ sudo adb-eclair2.2 root

adbd is already running as root

 

一鍵root就是一鍵提權,省略製作金卡,下刷機包的步驟

金卡:HTC的手機按照不同區域,內置不同的CID,升級ROM需要進行校驗,也就是說金卡是經過CUID驗證步驟,讓你刷RUU時候,不會出現131用戶驗證錯誤的提示,可以繞過去進行刷機的工具。

樓上的 是刷官方的固件不用金卡 你理解錯啦 不過現在都有一鍵無痛root的方法 不用做金卡了 還有9月份以後的機器都是S屏了 做金卡的方法好像不能對S屏的機子root 反而會變黑屏假磚

 

金卡,爲了刷官方rom而僞造的手機標識碼信息。

root,手機系統的超級超級權限,可以完全操作手機功能,包括隨意刷新rom,官方的和非官方的。

官方的rom刷過一次,就會恢復手機官方設置的權限,一般沒有root。

因此,有了root的手機,一般都是玩,一般不刷官方的。

完全的rom,完全的玩,玩的是rom。

 

而原生root權限的破解,需要我們先定製一張比較特殊的MicroSD卡,這張卡,被大家成爲GoldCard(金卡)。金卡就是一張通行證,它允許你爲Android手機刷新具有不同CID的RUU(ROM Update Utility,ROM更新工具)文件,打個比方,你有一臺oPhone手機,金卡可以讓你刷入通用的Android ROM固件而不會出現CID錯誤提示

 

金卡:

HTC的手機按照不同區域,內置不同的CID,升級ROM需要進行校驗,也就是說金卡是經過CUID驗證步驟,讓你刷RUU時候,不會出現131用戶驗證錯誤的提示,可以繞過去進行刷機的工具。

 

金卡的原理:

很多朋友第一時間下載了官方的Sense,然後就開始升級,不是臺版的機器都會提示客戶ID錯誤,這是因爲更新程序會檢測你機器的shippment,也就是銷售地區,如果和升級程序不一致,就會中斷升級,造成升級失敗。而金卡實際上就是在一張普通的TF卡上寫入一些引導信息,使得升級程序,或者說你本機 SPL的檢測跳過對客戶ID的檢查,從而達到“天下大一統”,使非官方版本的機器順利升級。

CID incorrect!

update fail!

CID 的錯誤信息是由 appsboot 程序彈出

strings hboot_8x50_0.33.0012_091210.nb0 |grep CID |grep incorrect

CID incorrect!

 

4.4.5 通過修改 boot.img 獲取 Nexus One 權限

1.  首先解壓縮 boot.img 文件

2.  修改 ramdisk 下的 default.prop 文件

3.  重新生成 boot.img

 

對於 Nexus One 在生成 boot.img 的時候必須指定 --base 0x20000000

參考文檔:

HOWTO: Unpack, Edit, and Re-Pack Boot Images

http://android-dls.com/wiki/index.php?title=HOWTO:_Unpack%2C_Edit%2C_and_Re-Pack_Boot_Images

如何解包/編輯/打包boot.img文件

http://blog.csdn.net/zhenwenxian/archive/2010/09/01/5856583.aspx

Perl 5教程

http://man.ddvip.com/web/perl/perl3.htm

 

 

4.5 系統應用移植

移植 google 服務

4.5.1 Android 2.2在線升級的移植

http://blog.lytsing.org/archives/356.html

 

從Android 2.2開始,Google服務框架 GoogleServicesFramework.apk 包自帶的系統更新處理了android.settings.SYSTEM_UPDATE_SETTINGS這個intent。我們自己做的手機,當然不可能用Google自帶的在線升級。爲了不修改 GoogleServicesFramework.apk,在Settings的AndroidManifest.xml文件,把 SYSTEM_UPDATE_SETTINGS,修改爲別的名字,比如 SYSTEM_UPGRADE_SETTINGS。 還需要同步修改這個文件:

Settings/res/xml/device_info_settings.xml

今天發神經病,花了一大早上的時候反編譯GoogleServicesFramework裏的update,看看別人如何設計的,就幾個文件:

 

[deli@athena update]$ tree .

.

├── Download.java

├── StateWatcher.java

├── SystemUpdateActivity.java

├── SystemUpdateInstallDialog.java

├── SystemUpdateService.java

└── SystemUpdateVerifierTask.java

 

4.5.2 解決donut Gtalk、Market登錄不了的問題

http://blog.lytsing.org/archives/category/android/

 

4.5.3 apk反編譯問題總結

http://www.eoeandroid.com/viewthread.php?tid=30768

er_client("battery", BATTERY_RPC_PROG,

 

4.5.4 系統重啓

此模式需要框架支持,並且提供用戶接口

./frameworks/base/core/jni/android_os_Power.cpp:82:    reboot(RB_POWER_OFF);

./frameworks/base/core/jni/android_os_Power.cpp:91:        reboot(RB_AUTOBOOT);

./frameworks/base/core/java/android/os/Power.java:102:   

public static void reboot(String reason) throws IOException

./frameworks/base/core/jni/android_os_Power.cpp:108:   

{ "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },

frameworks/base/core/jni/android_os_Power.cpp:91:       

reboot(RB_AUTOBOOT);

 

5、高通linux內核驅動開發

5.1 添加串口調試

/dev/ttyMSM2

修改device\qcom\msm7630_surf\BoardConfig.mk

中BOARD_KERNEL_CMDLINE的爲console=ttyMSM1 androidboot.hardware=qcom

(BOARD_KERNEL_CMDLINE := console=ttyMSM1 androidboot.hardware=qcom)

 

在kernel\arch\arm\configs\msm7630-perf_defconfig中添加

CONFIG_SERIAL_CORE_CONSOLE=y

CONFIG_SERIAL_MSM_CONSOLE=y

 

 

修改Board-msm7x30.c中的uart2_config_data爲否則鼠標就不能用了

static struct msm_gpio uart2_config_data[] = {

//{ GPIO_CFG(49, 2, GPIO_CFG_OUTPUT,  GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_RFR"},

        //{ GPIO_CFG(50, 2, GPIO_CFG_INPUT,   GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_CTS"},

        { GPIO_CFG(51, 2, GPIO_CFG_INPUT,   GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_Rx"},

        //{ GPIO_CFG(52, 2, GPIO_CFG_OUTPUT,  GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_Tx"},

};

5.2 Sensor 傳感器

Sensor 傳感器,內存共享

kernel/arch/arm/mach-msm/smd_rpc_sym:124:

0x30000089  vbatt_remote

./out/target/product/msm7630_surf/obj/KERNEL_OBJ/arch/arm/mach-msm/smd_rpc_sym.c

 

kernel/arch/arm/mach-msm/mkrpcsym.pl:5:

# Generate the smd_rpc_sym.c symbol file for ONCRPC SMEM Logging

kernel/arch/arm/mach-msm/Makefile:39:

$(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl

 

 

kernel/arch/arm/mach-msm/rpc_server_handset.c:35:

#define HS_RPC_PROG 0x30000091

kernel/arch/arm/mach-msm/rpc_pmapp.c:65:

#define PMAPP_RPC_PROG          0x30000060

kernel/arch/arm/mach-msm/qdsp5/snd.c:49:

#define RPC_SND_PROG 0x30000002

kernel/arch/arm/mach-msm/qdsp5/snd.c:50:

#define RPC_SND_CB_PROG  0x31000002

kernel/arch/arm/mach-msm/rpc_hsusb.c:28:

#define MSM_RPC_CHG_PROG 0x3000001a

kernel/arch/arm/mach-msm/pmic.c:150:

#define PMIC_RPC_PROG    0x30000061

kernel/drivers/power/msm_battery.c:80:

#define BATTERY_RPC_PROG 0x30000089

kernel/drivers/power/msm_battery.c:84:

#define BATTERY_RPC_CB_PROG (BATTERY_RPC_PROG | 0x01000000)

kernel/drivers/power/msm_battery.c:86:

#define CHG_RPC_PROG     0x3000001a

 

 

 

kernel/drivers/power/msm_battery.c:80:

#define BATTERY_RPC_PROG 0x30000089

kernel/drivers/rtc/rtc-msm.c:548:

rpc_client = msm_rpc_register_client("rtc", rdev->prog,

kernel/drivers/power/msm_battery.c:1426:     

msm_rpc_register_client("battery", BATTERY_RPC_PROG,

kernel/drivers/power/msm_battery.c:1436:        

msm_rpc_register_client("battery", BATTERY_RPC_PROG,

 

5.3 USB 枚舉 USB Composition

--------------------------

選項:DIAG+MODEM+NMEA+MSC

Qualcomm Android Modem 9018 –》右鍵屬性-》調制解調器 COM8

Qualcomm HS-USB Android DIAG 9018(COM7)

Qualcomm HS-USB Android GPS 9018(COM9)

 

linux dmesg 信息

連接:

[33477.105509] usb 2-2: new high speed USB device using ehci_hcd and address 107

[33477.258313] usb 2-2: configuration #1 chosen from 1 choice

[33477.259617] scsi72 : SCSI emulation for USB Mass Storage devices

[33477.260951] usb-storage: device found at 107

[33477.260956] usb-storage: waiting for device to settle before scanning

[33482.254239] usb-storage: device scan complete

[33482.254704] scsi 72:0:0:0: Direct-Access     GOOGLE   Mass Storage     ffff PQ: 0 ANSI: 2

[33482.255415] sd 72:0:0:0: Attached scsi generic sg3 type 0

[33482.257560] sd 72:0:0:0: [sdc] Attached SCSI removable disk

斷開:

[33570.056628] usb 2-2: USB disconnect, address 107

 

 

 

選項:MASS_STORAGE

無法找到驅動

linux dmesg 信息

連接:

[33570.664939] usb 2-2: new high speed USB device using ehci_hcd and address 108

[33570.823697] usb 2-2: configuration #1 chosen from 1 choice

[33570.828027] scsi73 : SCSI emulation for USB Mass Storage devices

[33570.829711] usb-storage: device found at 108

[33570.829716] usb-storage: waiting for device to settle before scanning

[33575.828346] usb-storage: device scan complete

[33575.828832] scsi 73:0:0:0: Direct-Access     GOOGLE   Mass Storage     ffff PQ: 0 ANSI: 2

[33575.829880] sd 73:0:0:0: Attached scsi generic sg3 type 0

[33575.832657] sd 73:0:0:0: [sdc] Attached SCSI removable disk

斷開:

[33688.625554] usb 2-2: USB disconnect, address 108

 

 

選項:MODEM

Qualcomm Android Modem 9018 –》右鍵屬性-》調制解調器 COM13

linux dmesg 信息

連接:

[33689.206052] usb 2-2: new high speed USB device using ehci_hcd and address 109

[33689.369016] usb 2-2: configuration #1 chosen from 1 choice

斷開:

[33780.024932] usb 2-2: USB disconnect, address 109

 

選項:DIAG:

Qualcomm HS-USB Android DIAG 901D (COM14)

linux dmesg 信息

連接:

[33900.605321] usb 2-2: new high speed USB device using ehci_hcd and address 112

[33900.761237] usb 2-2: configuration #1 chosen from 1 choice

斷開:

[33969.762217] usb 2-2: USB disconnect, address 112

 

 

選項: DIAG+MODEM

Qualcomm HS-USB Android DIAG 901D (COM14)

Qualcomm Android Modem 901D –》右鍵屬性-》調制解調器 COM16

linux dmesg 信息

連接:

[33970.344238] usb 2-2: new high speed USB device using ehci_hcd and address 113

[33970.496518] usb 2-2: configuration #1 chosen from 1 choice

斷開:

[34052.884162] usb 2-2: USB disconnect, address 113

 

 

選項: MASS_STORAGE+CDC/ECM

大容量設備無法找到驅動

CDC Ethernet Control Model (ECM) 無法找到驅動

linux dmesg 信息

連接:

[34053.477188] usb 2-2: new high speed USB device using ehci_hcd and address 114

[34053.629472] usb 2-2: configuration #1 chosen from 1 choice

[34053.635566] scsi74 : SCSI emulation for USB Mass Storage devices

[34053.636037] usb-storage: device found at 114

[34053.636041] usb-storage: waiting for device to settle before scanning

[34053.638576] usb0: register 'cdc_ether' at usb-0000:00:1d.7-2, CDC Ethernet Device, 82:1d:75:16:44:e0

[34058.634659] usb-storage: device scan complete

[34058.635230] scsi 74:0:0:0: Direct-Access     GOOGLE   Mass Storage     ffff PQ: 0 ANSI: 2

[34058.636005] sd 74:0:0:0: Attached scsi generic sg3 type 0

[34058.640541] sd 74:0:0:0: [sdc] Attached SCSI removable disk

 

 

選項: RNDIS

無法找到設備驅動

linux dmesg 信息:

[33290.719661] usb 2-2: USB disconnect, address 103

[33291.314376] usb 2-2: new high speed USB device using ehci_hcd and address 104

[33291.467065] usb 2-2: configuration #1 chosen from 1 choice

[33291.483030] usb0: register 'rndis_host' at usb-0000:00:1d.7-2, RNDIS device, 82:1d:75:16:44:e0

-----------------------------

 

5.4 USB 枚舉 USB Composition

[33291.483030] usb0: register 'rndis_host' at usb-0000:00:1d.7-2, RNDIS device, 82:1d:75:16:44:e0

 

6、從 android 源代碼製作 sdk

從 android froyo 源代碼製作 sdk

6.1 linux sdk

從 android froyo 源代碼製作 sdk

在源代碼頂層目錄直接執行命令:

make sdk

如果出現錯誤:

------------

frameworks/base/core/java/android/hardware/Camera.java:1427: error 4: @param tag with name that doesn't match the parameter list: 'latitude'

frameworks/base/core/java/android/hardware/Camera.java:1446: error 4: @param tag with name that doesn't match the parameter list: 'latitude'

frameworks/base/core/java/android/hardware/Camera.java:1464: error 4: @param tag with name that doesn't match the parameter list: 'altitude'

frameworks/base/core/java/android/hardware/Camera.java:1502: error 4: @param tag with name that doesn't match the parameter list: 'timestamp'

-------------

解決方法:

        /**

         * Sets GPS altitude reference. This will be stored in JPEG EXIF header.

         * @param altitude reference GPS altitude in meters.

         */

        public void setGpsAltitudeRef(double altRef) {

            set(KEY_GPS_ALTITUDE_REF, Double.toString(altRef));

        }

修改紅色字體 altitude 爲 altRef,保持與函數 setGpsAltitudeRef 的入參名稱一致

 

生成的 sdk 壓縮文件爲:

out/host/linux-x86/sdk/android-sdk_eng.gphone_linux-x86.zip

解壓縮,運行模擬器:

unzip out/host/linux-x86/sdk/android-sdk_eng.gphone_linux-x86.zip

cd android-sdk_eng.gphone_linux-x86

./tools/emulator  -data platforms/android-2.2/images/userdata.img

 

6.2 windows sdk

從 android froyo 源代碼製作 sdk

Windows 下 sdk 的製作使用到源代碼

development/build/tools/make_windows_sdk.sh

Current values:

- Input  SDK: missing

- Output dir: missing

- Temp   dir: /tmp

在源代碼底層目錄執行命令:

mkdir out/host/windows-x86/sdk -pv

./development/build/tools/make_windows_sdk.sh out/host/linux-x86/sdk/android-sdk_eng.gphone_linux-x86.zip out/host/windows-x86/sdk/

此命令必須在 windwos 下執行

 

 

7、程序安裝與調試

HYPERLINK "http://blog.chinaunix.net/u/26691/showart_2247039.html" 好消息,android平臺從froyo 2.2開始支持jni單步調試了

 

 

 

刪除模塊標誌

 

packages/apps/TSCalibration/Android.mk

LOCAL_MODULE_TAGS := user development eng

rm out/target/product/msm7627_ffa/system/app/SdkSetup.apk

./development/apps/SdkSetup/Android.mk

LOCAL_MODULE_TAGS := optional

rm out/target/product/msm7627_ffa/system/app/TSCalibration.apk

 

8、android 框架流程分析

8.1 屏幕顯示相關

./device/qcom/msm7627_surf/BoardConfig.mk

BOARD_BOOTIMAGE_PARTITION_SIZE := 0x00500000

BOARD_RECOVERYIMAGE_PARTITION_SIZE := 0x00500000

BOARD_SYSTEMIMAGE_PARTITION_SIZE := 0x05F00000

BOARD_USERDATAIMAGE_PARTITION_SIZE := 0x02000000

BOARD_FLASH_BLOCK_SIZE := $(BOARD_NAND_PAGE_SIZE) * 64

該內容爲聲稱到文件:

fastboot_init(target_get_scratch_address(), 120 * 1024 * 1024); 改爲:

fastboot_init(target_get_scratch_address(), 150 * 1024 * 1024);

static struct ptentry board_part_list[] = {

    {

       .start = DIFF_START_ADDR,

       .length = 105 /* In MB */,

       .name = "system",

    },

其中 105 需要改成 150

 

 

8.1.1 屏幕分辨率

QVGA       320*240像素

WQVGA400  400*240像素

WQVGA432  432*240像素

HVGA       320*480像素

VGA        640*480像素

WVGA       800*480像素

WVGA854    854*480像素

out/target/product/msm7630_surf/root/init.qcom.sh:50:            

setprop ro.sf.lcd_density 240

 

out/target/product/msm7630_surf/root/init.qcom.rc

service qcom-sh /system/bin/sh /init.qcom.sh

value=`cat /sys/devices/system/soc/soc0/hw_platform`

case "$value" in

"FFA" | "SVLTE_FFA")

。。。

        "Fluid")

         setprop ro.sf.lcd_density 240;;

        *)

       。。。。

 

out/target/product/msm7630_surf/system/build.prop:39:

ro.sf.lcd_density = 240

來自原始文件:

device/qcom/msm7630_surf/system.prop:7

ro.sf.lcd_density = 240

 

8.1.2 屏幕模式

肖像模式(Portrait Mode)、風景模式(landscape mode),其實就是垂直顯示還是水平顯示的問題

 

Android的計量單位px,in,mm,pt,dp,dip,sp

http://blog.csdn.net/hustpzb/archive/2010/11/20/6023145.aspx

 

Historically, programmers always designed computer interfaces in terms of pixels. For example, you mightmake a field 300 pixels wide, allow 5 pixels of spacing between columns, and define icons 16-by-16 pixels in size. The problem is that if you run that program on new displays with more and more dots per inch (dpi), the user interface appears smaller and smaller. At some point, it becomes too hard to read. Resolution-independent measurements help solve this problem.

Android supports all the following units:

• px (pixels): Dots on the screen.

• in (inches): Size as measured by a ruler.

• mm (millimeters): Size as measured by a ruler.

• pt (points): 1/72 of an inch.

• dp (density-independent pixels): An abstract unit based on the density of the screen. On a display with 160 dots per inch, 1dp = 1px.

• dip: Synonym for dp, used more often in Google examples.

• sp (scale-independent pixels): Similar to dp but also scaled by the user’s font size preference.

To make your interface scalable to any current and future type of display, I recommend you always use the sp unit for text sizes and the dip unit for everything else. You should also consider using vector graphics instead of bitmaps

 

如果英文不想看,看下面:

 

px:是屏幕的像素點

 

in:英寸

 

mm:毫米

 

pt:磅,1/72 英寸

 

dp:一個基於density的抽象單位,如果一個160dpi的屏幕,1dp=1px

 

dip:等同於dp

 

sp:同dp相似,但還會根據用戶的字體大小偏好來縮放。

 

建議使用sp作爲文本的單位,其它用dip

 

針對dip和px 的關係,做以下概述:

 

HVGA屏density=160;QVGA屏density=120;WVGA屏density=240;WQVGA屏density=120

density值表示每英寸有多少個顯示點,與分辨率是兩個概念。

不同density下屏幕分辨率信息,以480dip*800dip的 WVGA(density=240)爲例

 

density=120時 屏幕實際分辨率爲240px*400px (兩個點對應一個分辨率)

狀態欄和標題欄高各19px或者25dip

橫屏是屏幕寬度400px 或者800dip,工作區域高度211px或者480dip

豎屏時屏幕寬度240px或者480dip,工作區域高度381px或者775dip

 

density=160時 屏幕實際分辨率爲320px*533px (3個點對應兩個分辨率)

狀態欄和標題欄高個25px或者25dip

橫屏是屏幕寬度533px 或者800dip,工作區域高度295px或者480dip

豎屏時屏幕寬度320px或者480dip,工作區域高度508px或者775dip

 

density=240時 屏幕實際分辨率爲480px*800px (一個點對於一個分辨率)

狀態欄和標題欄高個38px或者25dip

橫屏是屏幕寬度800px 或者800dip,工作區域高度442px或者480dip

豎屏時屏幕寬度480px或者480dip,工作區域高度762px或者775dip

 

apk的資源包中,當屏幕density=240時使用hdpi 標籤的資源

當屏幕density=160時,使用mdpi標籤的資源

當屏幕density=120時,使用ldpi標籤的資源。

不加任何標籤的資源是各種分辨率情況下共用的。

佈局時儘量使用單位dip,少使用px

 

 

 

 

 

 

 

 

 

 

 

8.2 Android 開機充電

Android 開機畫面可以分爲內核和文件系統兩部分

 

 

8.3 Android 開機動畫

Android 開機畫面可以分爲內核和文件系統兩部分

1. 內核部分

內核部分的開機畫面,默認爲一個小企鵝圖標,通常在屏幕的左上角

2.文件系統默認部分

2.1 開機顯示的 ANDROID 文字

2.2 ANDROID 發光動畫

我們可以分別對以上部分進行處理,定製自己的開機動畫

替換 ANDROID 文件,只需在android文件系統根目錄下存在 initlogo.rle

替換 ANDROID 發光動畫,只需存在文件 /data/local/bootanimation.zip 或者 /system/media/bootanimation.zip 出廠設置的默認文件通常爲 /system/media/bootanimation.zip

命令:adb shell ls /system/media/ 可以看到 htc 等手機都存在 bootanimation.zip 文件

下面通過流程分析內核和android是怎樣處理開機畫面的

8.3.1 內核開機畫面

8.3.2 文件系統開機畫面

static void fbcon_init(struct vc_data *vc, int init)

    fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);

        logo_height = fb_prepare_logo(info, ops->rotate);

            fb_logo.logo = fb_find_logo(depth);

 

const struct linux_logo * __init_refok fb_find_logo(int depth)

{

    const struct linux_logo *logo = NULL;

 

    if (nologo)

       return NULL;

 

    if (depth >= 1) {

......

    }

   

    if (depth >= 4) {

#ifdef CONFIG_LOGO_LINUX_VGA16

       /* Generic Linux logo */

       logo = &logo_linux_vga16;

#endif

......

    if (depth >= 8) {

#ifdef CONFIG_LOGO_LINUX_CLUT224

       /* Generic Linux logo */

       logo = &logo_linux_clut224;

#endif

......

#ifdef CONFIG_LOGO_MAC_CLUT224

       /* Macintosh Linux logo on m68k */

       if (MACH_IS_MAC)

           logo = &logo_mac_clut224;

#endif

 

......

    }

    return logo;

}

因爲有:

kernel/arch/arm/configs/msm7627-perf_defconfig

CONFIG_LOGO_LINUX_CLUT224=y

所以使用的是圖片:

./kernel/drivers/video/logo/logo_linux_clut224.ppm

./out/target/product/msm7627_ffa/obj/KERNEL_OBJ/drivers/video/logo/logo_linux_clut224.c

It was automatically generated from kernel/drivers/video/logo/logo_linux_clut224.ppm

 

 

kernel/drivers/video/logo/Makefile 文件中有:

......

obj-$(CONFIG_LOGO_LINUX_CLUT224)   += logo_linux_clut224.o

......

pnmtologo := scripts/pnmtologo

......

$(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE

    $(call if_changed,logo)

其中 scripts/pnmtologo 爲:

./out/target/product/msm7627_ffa/obj/KERNEL_OBJ/scripts/pnmtologo

 

kernel/scripts/Makefile 文件中有:

hostprogs-$(CONFIG_LOGO)         += pnmtologo

。。。。。。

always     := $(hostprogs-y) $(hostprogs-m)

./kernel/scripts/Makefile.build:95:    $(subdir-ym) $(always)

./kernel/scripts/Makefile.build:268:targets += $(extra-y) $(MAKECMDGOALS) $(always)

8.3.2.1 開機顯示的 ANDROID 文字

開機顯示的 ANDROID 文件是由 init(內核進入文件系統後第一個被執行的程序) 程序處理,源代碼:

system/core/init/init.c

。。。

if( load_565rle_image(INIT_IMAGE_FILE) ) {

    fd = open("/dev/tty0", O_WRONLY);

    if (fd >= 0) {

        const char *msg;

            msg = "\n"

        "\n"

        "\n"

        "\n"

        "\n"

        "\n"

        "\n"  // console is 40 cols x 30 lines

        "\n"

        "\n"

        "\n"

        "\n"

        "\n"

        "\n"

        "\n"

        "             A N D R O I D ";

        write(fd, msg, strlen(msg));

        close(fd);

    }

}

。。。

system/core/init/init.h

#define INIT_IMAGE_FILE  "/initlogo.rle"

init 首先會調用 load_565rle_image(INIT_IMAGE_FILE) 去裝載根目錄下的 initlogo.rle 文件,如果該文件存在,那麼此時顯示的將是 initlogo.rle 文件的內容,如果不存在那麼會打開 /dev/tty0 設備,然後把字符串 A N D R O I D 顯示在上面。

load_565rle_image  函數在文件 system/core/init/logo.c 中。

int load_565rle_image(char *fn)

 

8.3.2.2 ANDROID 發光動畫

該動畫由後臺服務 /system/bin/bootanimation 處理,該服務在 /system/init.rc 文件中定義,開機後由 init 程序啓動,原始文件爲:./system/core/rootdir/init.rc

service bootanim /system/bin/bootanimation

bootanimation 爲 c++ 程序,相關文件和源代碼:

./frameworks/base/cmds/bootanimation/Android.mk

./frameworks/base/cmds/bootanimation/BootAnimation.h

./frameworks/base/cmds/bootanimation/bootanimation.cpp

./frameworks/base/cmds/bootanimation/bootanimation_main.cpp

int main(int argc, char** argv)

{

    。。。

    char value[PROPERTY_VALUE_MAX];

    property_get("debug.sf.nobootanimation", value, "0");

    int noBootAnimation = atoi(value);

    LOGI_IF(noBootAnimation,  "boot animation disabled");

    if (!noBootAnimation) {

        sp<ProcessState> proc(ProcessState::self());

        ProcessState::self()->startThreadPool();

        // create the boot animation object

        sp<BootAnimation> boot = new BootAnimation();

        IPCThreadState::self()->joinThreadPool();

    }

    return 0;

property_get("debug.sf.nobootanimation", value, "0");如果屬性 debug.sf.nobootanimation 等於 1 ,表明沒有開機動畫,否則調用 new BootAnimation() 顯示動畫。

BootAnimation::BootAnimation() : Thread(false)

{

    mSession = new SurfaceComposerClient();

}

status_t BootAnimation::readyToRun() {

。。。

    // create the native surface

    sp<SurfaceControl> control = session()->createSurface(

            getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);

    session()->openTransaction();

    control->setLayer(0x40000000);

    session()->closeTransaction();

。。。

    mAndroidAnimation = false;

    status_t err = mZip.open("/data/local/bootanimation.zip");

    if (err != NO_ERROR) {

        err = mZip.open("/system/media/bootanimation.zip");

        if (err != NO_ERROR) {

            mAndroidAnimation = true;

        }

    }

    return NO_ERROR;

}

bool BootAnimation::threadLoop()

{

    bool r;

    if (mAndroidAnimation) {

        r = android();

    } else {

        r = movie();

    }

    。。。

    return r;

}

readyToRun 中首先會確定是否有文件 "/data/local/bootanimation.zip" ;如果沒有,那麼再確定是否有文件 "/system/media/bootanimation.zip" 如果都不存在,那麼設置變量 mAndroidAnimation = true

動畫線程運行後,根據之前的 mAndroidAnimation  值調用系統的默認動畫 BootAnimation::android()或者自定義的動畫 BootAnimation::movie()

 

8.3.2.3 initlogo.rle 文件分析

 

RGB2565=./out/host/linux-x86/bin/rgb2565

output=./out/target/product/msm7630_surf/root/initlogo.rle

convert -depth 8 device/qcom/msm7630_surf/initlogo.png rgb:- | $RGB2565 -rle > $output

8.3.2.4 bootanimation.zip 文件分析

bootanimation.zip  由描述文件以及包含組成動畫的靜態圖片文件的文件夾

Bootanimation/{part1,part2,desc.txt}

Bootanimation/desc.txt 內容:

512 256 30

p 1 0 part0

p 0 0 part1

各字段的解釋:

'512' 動畫畫面的寬度

'256' 動畫畫面的高度

'30' 播放的幀頻,每秒30幀

'p' 定義動畫一部分的開始

'1' 定義的動畫循環播放次數

'0' 定義一個暫停 (max 10)

'part0' 包含動畫圖片的文件夾名稱

'p' 定義動畫另一部分的開始

'0' 定義動畫無限循環

'0' 定義一個暫停

'part1' 包含第二部分動畫圖片的文件夾名

 

我們無需瞭解顯示過程,只要按照 bootanimation 要求製作相應圖片即可。

參考文檔:

Bootanimation.zip File Explained

adb shell dd if=/sdcard/bootanimation.zip of=/data/local/bootanimation.zip

調用 ISurfaceComposer::createConnection()創建並返回一個ISurfaceFlingerClient的 IBinder。

./frameworks/base/include/utils/ZipFileRO.h  

./frameworks/base/libs/utils/ZipFileRO.cpp

FileMap* createEntryFileMap(ZipEntryRO entry)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

8.3.3 三星I9000 開機動畫

strings  system/bin/playlogo

/system/media/bootani.qmg

 

system/bin/playlogos1

/system/media/bootsamsung.qmg

/system/media/bootsamsungloop.qmg

 

./root/init.rc

setprop audioflinger.bootsnd 1

export ANDROID_BOOTLOGO 1

service playlogos1 /system/bin/playlogos1

    user root

oneshot

./root/lpm.rc

service playlpm /system/bin/playlpm

    user root

    oneshot

 

strings system/framework/framework.odex |grep shutdown

$//system/media/audio/ui/shutdown.ogg

//system/media/video/shutdown/

*//system/media/video/shutdown/shutdown.cfg

'//system/media/video/shutdown/shutdown_

,//system/media/video/shutdown/shutdown_1.png

Data shutdown complete.

0Data shutdown not complete. force to radio down.

&Exception during MountService shutdown

9Finding sound file : //system/media/audio/ui/shutdown.ogg

 

8.4 JNI調用流程

 

8.5 Android 開機鈴聲

StatusBar下拉Notification寬度滿屏解決方法

http://blog.csdn.net/caszhao/archive/2010/11/04/5986852.aspx

http://www.droidforums.net/forum/droid-hacking/

Android圖形系統底層實現分析

http://www.pctartarus.com/bbs/viewthread.php?tid=1673

 

 

Android系統2D/3D硬件加速分析報告

http://blog.chinaunix.net/u2/89569/showart_2359581.html

關於openGL, openGL ES, openVG及android中2D調用關係的

http://archive.cnblogs.com/a/1879877/

Copybit調研報告2

http://hi.baidu.com/aokikyon/blog/item/cda01397e76e936154fb964f.html

Copybit HAL模塊分析報告

http://www.armfans.net/viewthread.php?tid=2580

Android Copybit

http://huangchangzhuan.blog.163.com/blog/static/3563473520107931831546/

 

 

8.6 GPS 導航

8.6.1 GPS導航原理

StatusBar下拉Notification寬度滿屏解決方法

 

8.6.2 GPS導航軟件

StatusBar下拉Notification寬度滿屏解決方法

參考文檔:

凱立德地圖升級安裝說明

http://www.sh-youren.com/ty.htm

 

 

9、高通modem框架流程分析

9.1.1 添加自定義rpc調用

Playlpm

9.1.1.1 從AP端獲取modem的系統分區信息

#ifdef FEATURE_EXPORT_MISC_MODEM_APIS

  misc_modem_apis_app_init( );

#endif /* FEATURE_EXPORT_MISC_MODEM_APIS */

 

#ifdef FEATURE_EXPORT_MISC_MODEM_APIS_NONWINMOB

  misc_modem_apis_nonwinmob_app_init( );

#endif /* FEATURE_EXPORT_MISC_MODEM_APIS_NONWINMOB */

 

#ifdef FEATURE_EXPORT_MISC_APPS_APIS

  misc_apps_apiscb_app_init( );

#endif /* FEATURE_EXPORT_MISC_APPS_APIS */

 

#ifdef FEATURE_EXPORT_MISC_APPS_APIS_NONWINMOB

  misc_apps_apis_nonwinmobcb_app_init( );

#endif /* FEATURE_EXPORT_MISC_APPS_APIS_NONWINMOB */

需要關注:

misc_modem_apis_nonwinmob_app_init

misc_apps_apis_nonwinmobcb_app_init

 

#define INHERIT_FLASH_VTBL(type) \

int (*open_partition)(type *handle, const unsigned char *partition_name); \

int (*get_info)(type *handle, enum flash_info_type info_type, void *flash_info); \

int (*erase_blocks)(type *handle, struct flash_block_vector *block_vectors, uint32 block_count);\

int (*write_pages)(type* handle, enum page_write_opcode write_type, \

int (*read_pages)(type* handle, enum page_read_opcode read_type, \

    dalsys_mem_desc_list *buffer_desc, struct flash_page_iovec *page_iovec);

9.1.2 添加自定義 AT命令

在windows下用usb線連接手機

我的電腦-> 系統屬性 -> 硬件 ->設備管理 ->調制解調器

Qualcomm Android Modem 9018 –》右鍵屬性-》調制解調器

可以查看當前modem使用的串口,假設爲:COM8

 

 

10、linux 應用

10.1 嵌入式Linux通過幀緩存截圖 - Framebuffer Screenshot in Embedded Linux

 

 

10.2 Linux下右鍵燒錄文件

 解壓放到~/.gnome2/nautilus-scripts/下面

 

用法:右鍵點擊需要燒寫的文件->Scripts->Fastboot->分區

 

壓縮包內自帶fastboot命令:._fastboot(設置爲隱藏使其在右鍵菜單中不顯示)

 

如果你的機器上需要sudo命令才能進行燒寫的話,請打開壓縮包中的文件._flash.sh,在每個`dirname $0`前面加上sudo

 

10.3 Linux下右鍵svn

解壓到~/.gnome2/nautilus-scripts下就OK了

右鍵->Scripts->Subversion





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章