高通平臺android開發總結

Lidong_Zhou發表於2012-05-24

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/ 合法使用者登入

使用者名稱: mohuifu@gmail.com  密碼: 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手機開機全過程大揭密

chh@amoi.com.cn

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

相關文章