高通平臺android開發總結
1、高通平臺android開發總結
1.1 搭建高通平臺環境開發環境
在高通開發板上燒錄檔案系統
建立高通平臺開發環境
高通平臺,android和 modem 編譯流程分析
高通平臺 7620 啟動流程分析
qcril 流程分析,設定sim卡鎖
python scons 語法學習
Python 語言之 scons 工具流程分析:
1.2 搭建高通平臺環境開發環境
高通android智慧平臺概述
選擇合適的原始碼以及工具
建立 Android 開發環境(部分略)
建立 modem 開發環境
1.2.1 高通android智慧平臺概述
高通 7230 android 智慧手機解決方案的軟體包括兩個部分
1. 以linux 作業系統為基礎的 android 系統
2. 以 L4,REX為基礎的 Modem 部分
在高通7系列的架構中,一個IC內部整合有兩個ARM處理器,一個ARM9(或者arm11),專門負責處理通訊協議,射頻以及GPIO等,軟體架構採用 AMSS, 另外一個是ARM11,用來處理多媒體,上層應用,以及其他的一些任務,執行的系統是 android 系統,這兩個處理器之間通過共享記憶體的硬體方式來進行通訊。
1.2.1.1 什麼是L4,REX,BREW,AMSS以及相互之間的關係
L4是一組計算機程式,是最初由Jochen Liedtke設計的微核心構架的作業系統核心,現在已經形成一個微核心家族。L4這個微核心系統由於其出色的效能和很小的體積而開始被計算機工業所認知,被移植到了許多不同的硬體構架上。高通的 L4 提供了作業系統最基本的操作,是買別人的。
早期的作業系統絕大多數是 Monolithic Kernel, 意思是整個作業系統 - 包括Scheduling (排程), File system (檔案系統), Networking (網路), Device driver (裝置驅動程式), Memory management (儲存管理), Paging(儲存頁面管理) - 都在核心中完成.一直到現在廣泛應用的作業系統,如UNIX,Linux,和Windows還大都是monolithic kernel作業系統.但隨著作業系統變得越來越複雜(現代作業系統的核心有一兩百萬行C程式是很常見的事情),把所有這些功能都放在核心中使設計難度迅速增加.
微核心是一個與Monolithic Kernel相反的設計理念.它的目的是使核心縮到最小,把所有可能的功能模組移出核心.理想情況下,核心中僅留下Address Space Support(地址空間支援),IPC (Inter-Process Communication,程式間通訊),和Scheduling(排程),其他功能模組做為使用者程式執行。
REX 是在 L4 之上封裝的服務,是一個搶佔式,多工的RTOS,所有的任務都以task的形式存在,REX提供包括任務建立,同步,互斥,計時器,中斷控制等功能的 API,這裡的task實際上就是我們的執行緒,每個 task對應著一個執行緒。REX維護一個task list(雙向連結串列),始終執行高優先順序的task。products裡面所有的服務包括3g協議棧等都是以task的形式跑在rex之上的。
而Brew的話是執行的環境,跟Java 有點兒類似,相當於是一個虛擬機器。
AMSS――高階的移動使用者軟體(Advanced Mobile Subscriber Software)技術,是一種新的軟體架構,是對原來軟體架構 DMSS 的升級。 AMSS原始碼實際上是QC BREW(Binary Runtime Environment For Wireless)平臺的的底層部分,去掉了為應用程式提供介面的AEE(application execution environment)部分,高通在Dual Proc晶片上的其他平臺基本上都是採用的這樣的架構。
參考文件:
微核心作業系統及L4概述
http://wenku.baidu.com/view/90929762caaedd3383c4d311.html
MSM平臺上的AMSS
http://blog.csdn.net/yili_xie/archive/2010/01/04/5129469.aspx
1.2.2 選擇合適的原始碼以及工具
要編譯出可供燒寫使用的映象檔案需要三部分程式碼:
1) 獲取經過高通打補丁的 android 原始碼
2) 獲取高通針對不同處理器的 vendor 原始碼
3) 獲取 modem 原始碼
1.2.2.1 獲取經過高通打補丁的android 原始碼
網址:
https://www.codeaurora.org/wiki/QAEP#Branch_Releases
https://www.codeaurora.org/xwiki/bin/QAEP/eclair
https://www.codeaurora.org/xwiki/bin/QAEP/eclair_caramel
https://www.codeaurora.org/xwiki/bin/QAEP/froyo_almond
目前使用的 android 分支:
Android 2.1 版本 eclair
M7630AABBQMLZA1150 msm7630 eclair M7630AABBQMLZA1150.xml 2010年02月01日
M7630AABBQMLZA1200 msm7630 eclair M7630AABBQMLZA1200.xml 2010年03月30日
M7630AABBQMLZA2010 msm7630 éclair M7630AABBQMLZA2010.xml July 02, 2010
M7630AABBQMLZA1240 msm7630 eclair_caramel M7630AABBQMLZA1240.xml 2010年05月31日
M7630AABBQMLZA1250 msm7630 eclair_caramel M7630AABBQMLZA1250.xml 2010年06月15日
M7630AABBQMLZA1280 msm7630 eclair_caramel M7630AABBQMLZA1280.xml 2010年08月03日
M76XXTSNCJNLYA5340 msm7627 eclair_chocolate M76XXTSNCJNLYA5340.xml 2010年06月04
Android 2.2 版本 froyo
M7630AABBQMLZA2020 msm7630 froyo M7630AABBQMLZA2020.xml 2010年09月01
M76XXTSNCJNLYA6050 msm7627 froyo_almond M76XXTSNCJNLYA6050.xml 2010年10月29日
以下命令獲取程式碼:
https://www.codeaurora.org/xwiki/bin/QAEP/froyo_almond
ac_root=/home/shared/qualcomm
ac_root=/mnt/shared/qualcomm/
ac_date=20101105
ac_branch=froyo_almond
build_id=M76XXTSNCJNLYA6050
ac_xml=M76XXTSNCJNLYA6050.xml
mkdir -pv $ac_root/$ac_branch-$build_id-$ac_date
cd $ac_root/$ac_branch-$build_id-$ac_date
repo init -u git://codeaurora.org/platform/manifest.git -b $ac_branch -m $ac_xml
nohup repo sync&
1.2.2.2 獲取高通針對不同處理器的vendor原始碼
根據選擇的 Android 原始碼分支不同, vendor 程式碼的選擇也是不一樣的,BUILD ID 必須一致
M7630AABBQMLZA1150 對應 HY11-VR881-5.zip
M7630AABBQMLZA1250 對應 HY11-VR881-11.zip
M7630AABBQMLZA2020 對應 HY11-N1627-3.zip AMSS 7X30 LINUX RELEASE 2.0.20
M76XXTSNCJNLYA6050 對應 HY11-N1188-6.zip AMSS 7X27 LINUX REL 6.0.50
vendor 程式碼通過有效的高通帳號登入 HYPERLINK "https://support.cdmatech.com/login/" https://support.cdmatech.com/login/ 網站獲取
1.2.2.3 獲取 modem 原始碼
根據硬體配置情況,選擇不同的 BUILD ID, 然後根據 BUILD ID 選擇相近的原始碼
modem 程式碼通過有效的高通帳號登入 HYPERLINK "https://support.cdmatech.com/login/" https://support.cdmatech.com/login/ 網站獲取
BUILD ID 是一組字母的組合,如:AAABQOLYM
以下分別對各個欄位進行說明:
第三個字母 A 表示 LPDDR2 #USES_LPDDR2=yes
第三個字母 B 表示 LPDDR1
第六個字母 M 表示 Multimode
第六個字母 C 表示 CDMA
第六個字母 D 表示 JCDMA #相對於C多了:USES_UMTS=yes USES_DSHDR_JCDMA_APIS=yes
第六個字母 O 表示 UMTS only #相對於C多了:USES_UMTS=yes USES_SUPPORT_UMTS_GPS_PROTOCOLS=yes
#相對於C少了:USES_CDMA=yes USES_HDR=yes USES_REL_C=yes USES_CDMA2000=yes
#USES_EXPORT_MCCMEID=yes USES_SUPPORT_CDMA_GPS_PROTOCOLS=yes
第7,8個字母為 AZ 表示 NADN boot
第7,8個字母為 LY 表示 eMMC boot #相對於AZ多了選項: USES_SDCC_BOOT=yes USES_HSU_MS_FD_BOOT=yes
最後一個字母為 M 表示 modem
最後一個字母為 A 表示 app
以上為 7x30 平臺的一些規律,具體參考文件,7227 參考相應的 release note:
<<80-VR192-1_E_AMSS_Linux_Software_Users_Manual.pdf>>
第1個字母
第2個字母 F: 基於ffa參考設計 S: 基於surf的參考設計
第3個字母
第4個字母
第5個字母 K /J
K 相對於 J 多了以下選項
USES_HSU_CHG_BOOT=yes
USES_HSU_FAST_CHARGE=yes
USES_CHARGER=yes
USES_EBI1_TURBO_FFA=yes
第6個字母 O/ N / P
O表示只支援 UMTS(WCDMA)
------------------
USES_IPHC=yes
USES_PDCP=yes
USES_SUPPORT_UMTS_GPS_PROTOCOLS=yes
USES_UMTS=yes
-----------------
P表示只支援 CDMA/CDMA2000
USES_CDMA=yes
USES_CDMA2000=yes
USES_REL_C=yes
USES_SUPPORT_CDMA_GPS_PROTOCOLS=yes
USES_EXPORT_MCCMEID=yes
USES_HDR=yes
-----------------
N表示既支援 UMTS(WCDMA) 且支援 CDMA/CDMA2000
第7個字母
第8個字母
surf和ffa的區別
generally speaking surf have FPGA and don't have battery.
and FFA don't have FPGA but have battery.
msm7627_surf and msm7627_ffa and msm7627_7x_surf means different hardware reference design. please check with your hardware engineer on which qualcomm hardware reference you use and then select the right build command.
4.6 Build commands
To create an AMSS build, run the command script with the build ID matching the build
configuration desired. The command scripts may be executed from the build/ms subdirectory or
from the AMSS root directory using the full path to the command script as in the following
examples:
./AMSS/products/<asic>/build/ms/MSNCJNLYM.cmd – For SURF multimode build
./AMSS/products/<asic>/build/ms/MSNCJOLYM.cmd – For SURF UMTS only build
./AMSS/products/<asic>/build/ms/MSNCJPLYM.cmd – For SURF 1X only build
./AMSS/products/<asic>/build/ms/MFNCKNLYM.cmd – For FFA multimode and for reference only
以高通的開發板子為例,看如何選擇原始碼,通過 QPST 連線高通的開發板,我們可以看到他的配置資訊如下:
高通 demo 版的配置情況:SURF-MSM7630 7X30A-AAABQMAZM-1200
從配置情況來看只有 HY11-N0216-3_1.2.00 HY11-N0216-4_1.2.20 滿足要求
HY11-N0216-3_1.2.00/AMSS/products/7x30/build/ms/AAABQMAZM.cmd
HY11-N0216-4_1.2.20/AMSS/products/7x30/build/ms/AAABQMAZM.cmd
後期我們要跟據實際情況來選擇 BUILD ID,如我們的手機的配置情況為:
LPDDR2 ,WCDMA,eMMC 啟動(NAND備選),那麼modem 的BUILD ID為:
AAABQOLYM 或者 AAABQOAZM
AAABQOLYM HY11-N0723-2_1.2.20/AMSS/products/7x30/build/ms/AAABQOLYM.cmd
AAABQOAZM HY11-N1122-1_1.2.20/AMSS/products/7x30/build/ms/AAABQOAZM.cmd (NABD boot 備選)
高通的Android第一人曉峰不建議我們第一次就用eMMC,而應該用Nand,目前只有HTC在用eMMC。高通在eMMC上面提供了參考程式碼,但是是未經過驗證。終端廠商在使用過程中,一定會有很多問題需要自己解。
補充資訊:
現在可能用到 BUILD ID 以及相應的 modem 和 vendor 原始碼。
modem程式碼:
BUILD ID modem 原始碼 modem映象 說明文件
M7630AABBQMAZM1200 HY11-N0216-3.zip HK11-N0216-3.zip HT11-N0216-3.zip
M7630AABBQMAZM1220 HY11-N0216-4.zip HK11-N0216-4.zip HT11-N0216-4.zip
--
M7630AABBQMLYM1200 HY11-N0723-1.zip HK11-N0723-1.zip HT11-N0723-1.zip
M7630AABBQMLYM1220 HY11-N0723-2.zip HK11-N0723-2.zip HT11-N0723-2.zip
--
M7630AAABQCAZM1220 HY11-N1122-1.zip HK11-N1122-1.zip HT11-N1122-1.zip
M7630AAABQCAZM1240 HY11-N1122-2.zip HK11-N1122-2.zip HT11-N1122-2.zip
M7630AAABQCAZM1250 HY11-N1122-3.zip HK11-N1122-3.zip HT11-N1122-3.zip
M7630AAABQCAZM1260 HY11-N1122-4.zip HK11-N1122-4.zip HT11-N1122-4.zip
M7630AAABQCAZM1280 HY11-N1122-5.zip HK11-N1122-5.zip HT11-N1122-5.zip
M7630AAABQCAZM1290 HY11-N1122-6.zip HK11-N1122-6.zip HT11-N1122-6.zip
--
M7630AAABQMAZM1240 HY11-N1496-2.zip HK11-N1496-2.zip HT11-N1496-2.zip
M7630AAABQMAZM1250 HY11-N1496-3.zip HK11-N1496-3.zip HT11-N1496-3.zip
80-N0216-3_B_M7630AABBQMAZM1200.pdf
5.3.2.1 LPDDR1 NAND boot Multimode AABBQMAZM.cmd
5.3.2.2 LPDDR1 eMMC boot Multimode AABBQMLYM.cmd
5.3.2.3 LPDDR1 eMMC boot UMTS only AABBQOLYM.cmd
5.3.2.4 LPDDR1 NAND boot JCDMA AABBQDAZM.cmd
5.3.2.5 LPDDR2 NAND boot Multimode AAABQMAZM.cmd
5.3.2.6 LPDDR2 eMMC boot Multimode AAABQMLYM.cmd
80-N0216-4_A_M7630AABBQMAZM1220.pdf
5.3.2 Build instructions and commands
5.3.2.1 LPDDR1 NAND boot Multimode AABBQMAZM.cmd
5.3.2.2 LPDDR1 eMMC boot Multimode AABBQMLYM.cmd
5.3.2.3 LPDDR1 eMMC boot UMTS only AABBQOLYM.cmd
5.3.2.4 LPDDR1 NAND boot JCDMA AABBQDAZM.cmd
5.3.2.5 LPDDR2 NAND boot Multimode AAABQMAZM.cmd
5.3.2.6 LPDDR2 eMMC boot Multimode AAABQMLYM.cmd
5.3.2.7 LPDDR2 eMMC boot UMTS only AAABQOLYM.cmd
5.3.2.8 LPDDR2 NAND boot C2K Only AAABQCAZM.cmd
5.3.2.9 LPDDR1 eMMC boot C2K Only AABBQCLYM.cmd
5.3.2.10 LPDDR2 NAND boot JCDMA AAABQDAZM.cmd
5.3.2.11 LPDDR2 NAND boot UMTS only AAABQOAZM.cmd
80-N1665-1_B_M7630AAABQ_AZM1240.pdf
5.3.2 Build instructions and commands
5.3.2.1 LPDDR1/LPDDR2 eMMC boot Multimode AABBQMLYM.cmd
5.3.2.2 LPDDR1/LPDDR2 eMMC boot UMTS only AABBQOLYM.cmd
5.3.2.3 LPDDR1/LPDDR2 eMMC boot C2K only AABBQCLYM.cmd
5.3.2.4 LPDDR2/LPDDR1 NAND boot Multimode AAABQMAZM.cmd
5.3.2.5 LPDDR1/LPDDR2 NAND boot JCDMA AABBQDAZM.cmd
5.3.2.6 LPDDR2/LPDDR1 NAND boot C2K only AAABQCAZM.cmd
5.3.2.7 LPDDR2/LPDDR1 NAND boot UMTS only AAABQOAZM.cmd
The same build ID will now work for LPDDR1 as well as LPDDR2.
從以上的釋出資訊,只有 LPDDR2 和 LPDDR1 不同的情況下可以使用同一個 build ID。
對於我們的硬體配置情況(LPDDR2 eMMC boot UMTS only) 可以使用的編譯命令檔案為:
AAABQOLYM.cmd AABBQOLYM.cmd
選擇 modem 程式碼 M7630AAABQMAZM1250 HK11-N1496-3.zip
如果是支援 BREW 平臺,通常多下面的選項:
USES_BREW_4.0=yes
USES_BREW=yes
USES_BREW_APPMGR=yes
或者 USES_BREW_USB_HID=yes
沒有 USES_DIAG_SMD_SUPPORT=yes
專案 PD1007
OEM/Target Equipment (FeaturePhone,Smartphone,Datacard): Smartphone
Anticipated Launch Date: April 1 2011
Target market (such as China Telecom): China Open market
Current Software (such as Q6270BKPRZL1505): froyo-M76XXTSNCJNLYA7010
Bluetooth IC/Module (vendor name and module if support BT): BTS4025
WLAN IC/Module (vendor and module if support WLAN ):WCN1312
Chipset (such as QSC6270):MSM7227-1
RF chipset (such as RGR6240):RTR6285
PMIC chipset (such as PM7540):PM7540
WCMDA Supported Bands (900,1900,2100…. if support WCDMA):2100
CMDA Supported Bands (450,850,1900,2100… if support CDMA ):not suport
OS (Brew,BMP,Android,WM,ThinUI(no UI)…):android froyo
OS version (Android Donuts…): android froyo
1.2.2.3.1 高通 modem 原始碼編譯前的修正
從高通獲取的原始碼直接編譯會存在一些問題,以下為可能的問題以及解決方法:
1) 為相應的指令碼加上編譯選項
vim ./AMSS/products/7x30/build/ms/xxxxxx.cmd
加上: BUILD_UNIX=yes
2) 如果編譯過程出現 .pl 檔案沒有執行許可權而退出,那麼為工程下面所有的 pl 檔案加上可執行屬性,命令:
find ./ -name "*.pl" |xargs chmod 755
3) 無法找到需要的 pl 指令碼解析器
vim ./AMSS/products/7x30/tools/build/depgen.pl
修改
#!/pkg/perl/5.6.1/bin/perl -w
為
#!/usr/bin/perl -w
4) 如果出現錯誤: "AMSS/products/7x30/core/bsp/build/data/incpathsaaabqmlym.py", line 14
IndentationError: expected an indented block
修改檔案:./AMSS/products/7x30/core/bsp/build/scripts/genpaths.pl 內容:
#if ($line =~ /^# makefile \(from/)
為:
if ($line =~ /^# makefile /)
原因分析:
genpaths.pl 會對編譯過程的中間資訊 :
...
line=# makefile (from'incpaths.min',line 363)
line=QVPCODEC_AUDIOINC = $(QVPCODEC)/audio/inc
...
等資訊進行解析,由於我們使用的是中文系統,所以以上內容變為:
line=# makefile (從'incpaths.min',行 363)
line=QVPCODEC_AUDIOINC = $(QVPCODEC)/audio/inc
所以導致:
#if ($line =~ /^# makefile \(from/) 判斷條件為為 false
無法正確生成 incpathsaaabqmlym.py,python 在解析該檔案的時候認為存在語法錯誤。
在 modem 程式碼 M7630AABBQMAZM2020(HY11-N2280-2.zip)中開始使用 genincpaths.py 產生
./AMSS/products/7x30/core/bsp/build/data/incpathsaaabqoazm.py 檔案,所以修改檔案
amend-source-code-qualcomm-modem.sh 在指令碼中需要加入以下內容:
incpathsxxx_py=$PRODUCT_DIR/core/bsp/build/scripts/genincpaths.py
if test -f $incpathsxxx_py; then
PERL=`which /usr/bin/perl`
sed -i "s/(from//g" $incpathsxxx_py
fi
./AMSS/products/7x30/multimedia/audio/drivers/Adie/AdieCodecDb/src/DALAdieCodecDb.c
#DalAdieCodecDbInternal.h 改為:
#include "DALAdieCodecDbInternal.h"
5) 如果出現 make: execvp: ../../../../platform/cs/bin/cifc: Permission denied 錯誤,執行以下命令:
chmod -R 755 AMSS/platform/cs/bin/*
1.2.3 建立 Android 開發環境
(略)
curl http://android.git.kernel.org/repo >~/bin/repo
chmod a+x ~/bin/repo
export PATH=~/bin:$PATH
1) 安裝基本軟體
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl sun-java5-jdk zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev
2) 安裝 sun-java5-jdk
ubuntu 下通過命令: sudo apt-get install sun-java5-jdk 將會安裝下面的包
sun-java5-bin sun-java5-demo sun-java5-jdk sun-java5-jre sun-java5-plugin
如果ubuntu 釋出版本中沒有 sun-java5-jdk 那麼
sudo vim /etc/apt/source.list
#for sun-java5-jdk
deb http://us.archive.ubuntu.com/ubuntu/ jaunty multiverse
deb http://us.archive.ubuntu.com/ubuntu/ jaunty-updates multiverse
sudo apt-get update
sudo apt-get sun-java5-jdk
或者,如果 ubuntu 版中不支援 apt-get ,那麼用手動安裝:
sudo mount -t nfs 172.20.127.15:/home/shared /mnt
sudo dpkg -i /mnt/tools/debs/java-1.5.0-sun/sun-java5-*
3) 配置usb
cd /etc/udev/rules.d/
sudo vi 50-android.rules
# adb single interface device
SUBSYSTEM=="usb_device", SYSFS{idVendor}=="18d1", SYSFS{idProduct}=="d00d",
MODE="0664", GROUP="plugdev"
# adb composite interface device
SUBSYSTEM=="usb_device", SYSFS{idVendor}=="18d1", SYSFS{idProduct}=="deed",
MODE="0664", GROUP="plugdev"
# Sooner low-level bootloader
BUS=="usb", SYSFS{idVendor}=="0bb4", SYSFS{idProduct}=="0a51",
MODE="0664",GROUP="plugdev"
sudo /etc/init.d/udev restart
1.2.4 建立 modem 開發環境
與android 原始碼不同,modem 編譯工具使用的是 RVDS ,實際上只用到其中的 RVCT 編譯器, 高通不提供該工具,我們必須從arm公司獲取相應的授權,RVDS 是 ADS 的升級版本,從 ADS 1.2 開始到 RVDS 3.1 我們公司都有其授權,按照高通的要求我們目前必須使用 RVDS 2.2 並且使用他的 349 patch。
RVDS 2.2 安裝以及使用步驟如下:
1). RVDS 2.2 共享在 172.20.127.15:/home/shared/ 目錄
sudo mount -t nfs 172.20.127.15:/home/shared/ /mnt
cd /mnt/qualcommon/RVDS-2.2/
linux下rvds2.2的安裝程式為:
./rvds2.2_linux-pentium/setuplinux.bin
執行以上命令,按照預設步驟安裝,安裝路徑為:~/ARM
注意事項:
安裝過程如果出現錯誤:
..................java.lang.UnsatisfiedLinkError: /tmp/ismp001/6073753.tmp: libstdc++-libc6.2-2.so.3:
cannot open shared object file: No such file or directory
從網上下載 libstdc++-libc6.2-2.so.3 拷貝到 /usr/lib 目錄 ,或者從下面地址獲取:
http://172.20.127.15/repositories/DocsAndTools/Tools/Qualcomm/RVDS-2.2-patch/patch/libstdc++-libc6.2-2.so.3
工具的安裝通過指令碼進行了簡化,具體過程請參考文件:
80-N0216-2_A_M7630AABBQMAZM1170.pdf
80-VR881-7_B_M7630AABBQMLZA1200.pdf
80-VR192-1_C_AMSS_Linux_Software_Users_Guide.pdf
80-VR192-1_D_AMSS_Linux_Software_Users_Guide.pdf
2) 安裝高通指定的 593 patch
cd /mnt/qualcommon/RVDS2.2/下執行命令:
./setup-patch-rvct2.2-bin593-lib349.sh
目前版本只支援 32 位的系統
1.2.4.1 補充
vim ./AMSS/products/7x30/core/bsp/build/scripts/defaults.py 定義了工作執行緒
#num_jobs = num_cpu * 2 modified by mhf
num_jobs = 2
if num_jobs < 4:
num_jobs = 2
if num_jobs > 8:
num_jobs = 8
env.SetOption('num_jobs', num_jobs)
―――――――
獲取 RVDS
官方網站下載評估版本
https://silver.arm.com/browse
http://www.arm.com/products/tools/software-development-tools.php
https://silver.arm.com/download/eval_download.tm
https://silver.arm.com/userguides/Web_Licensing_Portal_User_Guide.pdf (Licensing 需要通過 host id 註冊)
―――――――
1.2.4.1.1 獲取 licenses
RVDS 的 licenses 從其官方網站獲取
https://silver.arm.com/licensing/
https://silver.arm.com/licensing/generate.tm
http://www.keil.com/support/man/docs/license/license_sul_install.htm
入口 https://silver.arm.com/licensing/ 合法使用者登入
使用者名稱: 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
相關文章
- 高通Android平臺開發Android
- 高通MDM平臺開發入門
- 總結低程式碼開發平臺的特徵特徵
- 測試平臺開發教程【提測平臺】階段總結(三)
- 最新高通平臺驅動開發參考文件
- 高通平臺手機開發之Bring-up
- 自動化平臺開發的幾點總結
- 高通平臺開發環境搭建、編譯、燒錄(android5.1以上系統)開發環境編譯Android
- 微信公眾平臺開發(十) 訊息回覆總結
- Android推送平臺試用總結報告Android
- Android開發經驗總結Android
- Android TV開發總結【RecycleView】AndroidView
- Android 開發功能模組總結Android
- Android高通平臺處理器間通訊驅動Android
- 騰訊後臺開發面試總結面試
- Flutter實現Android、iOS跨平臺經驗總結FlutterAndroidiOS
- Android 日常開發問題總結Android
- Android開發技術面總結Android
- android開發之svg全面總結AndroidSVG
- Android 開發知識點總結Android
- Android開發常用知識總結Android
- Android藍芽開發全面總結Android藍芽
- 綠茵面家平臺開發(開發平臺)
- 工作總結--ESB工作平臺
- 自動化平臺開發小結(六)
- 自動化平臺開發小結(五)
- 自動化平臺開發小結(四)
- 自動化平臺開發小結(三)
- Android平臺Camera開發實踐指南Android
- 手遊開發Android平臺周邊工具介紹Android
- 高通晶片平臺進9008埠晶片
- Android Flutter混合開發問題總結AndroidFlutter
- OPPO Android開發技術面總結Android
- Android混合開發之WebView使用總結AndroidWebView
- 如何開發直播平臺,直播平臺開發需要CDN嗎
- 谷歌開發Android Pay 搭建移動支付平臺谷歌Android
- PlayJam: 60%開發商將選擇Android平臺Android
- Web快速開發平臺,基於二次開發平臺Web