2012年9月26日 星期三

把玩"魔術師" -- 編譯 AOSP 2.1 (Eclair) 原始碼

把玩"魔術師" -- 編譯 AOSP 2.1 (Eclair) 原始碼

This document is provided as is. You are welcomed to use it for non-commercial purpose.
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu
請勿轉貼
看其他教材

為了達到第一個目標 -- 自己編譯 AOSP(Android Open Source Project),便開始收集 資料,目前進度極緩慢,所以先把一些有用的資料集結在此,做個筆記,有機會再讓它 成為一篇完整的文章。在慢慢達成目標的過程,分成幾個階段,分別描述如下: 第一階段主要是參考 [HOW-TO] Compile AOSP Froyo + [ROM] Latest AOSP Froyo for Sapphire 這一串討論文。在編譯過程充滿了一些完全不知道要如何處理的困難(看起來基本功 不紮實),就算勉強解決了,可惜編譯出來的 image 檔無法在 Magic 上執行,也找不到 答案。這個階段有幾次想放棄,想想看:都這麼老了還玩?有沒有搞錯? 雖然這一階段的挫折最大,但是以下的文件也有不少是來自這一串討論文。 第二階段主要是參考 編譯 android 2.1 (eclair) 源碼 For HTC G1,這個文章是編譯給 HTC Dream 的,基本上這篇文章是參考一篇日文的文章 EclaironADP1andADP2,雖然看不懂日文,但是從指令可以看出想要編譯給 ADP2 (根據 Android FAQ,ADP2 是 Magic 32B),應該也可行。看文章跟著做的過程中,有不懂得就順便 Google 一下找答案,有 答案的,我會順便把它筆記下來。
這一次的編譯,過程輕鬆多了,從頭到尾只 碰到如下的錯誤訊息
target StaticLib: libwebcore (out/target/product/sapphire-open/obj/STATIC_LIBRARIES/libwebcore_intermediates/libwebcore.a)
make: execvp: /bin/bash: Argument list too long (中文的錯誤訊息是"引數列項目過長")
make: *** [out/target/product/sapphire-open/obj/STATIC_LIBRARIES/libwebcore_intermediates/libwebcore.a]
根據網路搜尋的結果,這應該是環境變數的空間太小的關係。根據 Build error on Ubuntu 9.04 (Eclair branch) 二樓的說明,解決方式為執行以下指令:
(cd external/webkit ; git cherry-pick 18342a41ab72e2c21931afaaab6f1b9bdbedb9fa)
什麼是 git cherry-pick 呢?google 了一下,應該是某些人已經做好的 修正(commit)把它抓回來;而 commit 過的東西是以一個 id 來代表,因此指令 後面一長串的字就是 commit 的 id。 太棒了,經過漫長的等待終於編譯完畢,試著在模擬器中 執行,也成功的開機了;執行模擬器的指令如下:
emulator -avd Magic -system system.img -data userdata.img -ramdisk ramdisk.img
其中,-avd 後代表模擬器中虛擬的 2.1 機器代碼,在我的電腦上設的名稱是 Magic。 從畫面中,我們可以看出,新編出來的 ROM 有繁體中文,有一些基本的 Google 軟體, 例如 Calendar,其他的就還蠻單純的;喔,有一個小小的缺失,那就是 Calendar 會 FC(就是所謂的強迫關閉)。從右邊畫面中,可以看出編譯過程中加入的一些設定值, 由此可以確定這個 ROM 是自己編的,而不是系統預設的。
把產生的 image 檔刷到"魔術師",刷的指令就是把剛剛編譯好的 image 檔經由 fastboot 模式刷入,刷入的步驟與指令如下:
fastboot erase system -w
fastboot erase boot
fastboot flash boot boot.img
fastboot flash system system.img
fastboot flash userdata userdata.img
喔,由於刷的時候,手機的 radio 是 new radio(也就是 radio 6.35.x),所以 就試著直接刷 image,雖然我知道這些 image 應該是給 old radio(也就是 radio 3.22.x),可是如果是同樣的 APIs,應該沒問題不是嗎?只可惜結果是只看到開機的 第一個畫面就停住了,連 adb logcat 也看不到任何訊息。 再來,就是把 new radio 降成 old radio,這些基本動作網路上有很多資料就不在 贅述。由於編譯完的 image 檔是給 Magic 32B 的,而不是給 Magic 32A(台灣出售的 都是屬於 32A),由於兩者的硬體結構不同(請參考 Running Android AOSP on HTC Magic 32A Phones),所以還需要多刷一個 kernel patch,我使用的是 CM 5.0.8 的 patch;請仔細比較上圖中"核心版本"和下圖中的核心版本是不同的,上圖是 AOSP 編譯出來的 kernel,而下圖的 kernel 是 CM 5.0.8 的 patch。 喔,如果不刷這個 patch,我也試過,開機還是會停在第一個畫面。 一旦 image 檔和 patch 刷完了之後,就可以成功開機了,提供兩個畫面以供參考。 開機後測試了一下,發現 除了之前說的 Calendar 會 FC 之後,Music 和簡訊也會,電話可以撥出去,但是 打不進來,無線上網功能正常,相機雖然可以啟動,但是畫面充滿了白與黑的方格子。
在整個編譯的學習過程中,有些想法說一說: 依照現在的情形來看,kernel 的修正以及驅動程式的修正都有蠻大的空間,可是 我有興趣再深入的發掘嗎?多想想! 既然能編譯出一個堪用的 HTC Magic 32A ROM,自然要把過程寫一下給有興趣的人試試看。 不過,這絕對不是一份任何人都一定看得懂的(我有些部分也還在摸索);因為 是給自己當筆記,我只能先假設你懂一些 Linux 的基本概念。我把編譯的過程 分成幾個步驟來說:(以下的步驟絕大部分都是在 Ubuntu/Linux 上執行)
  1. 你需要幫自己安裝一部執行 Linux 的電腦,AOSP 的文件建議使用 Ubuntu,而我安裝的是 Ubuntu 10.04 x86 32 bit 版。為了不影響平常的 使用,我是將 Ubuntu 安裝在一個名為 VirtualBox 的虛擬機器上;VirtualBox 是一套 Windows 的免費軟體,當在 VirtualBox 內執行 Ubuntu 的時候,電腦 基本上就同時執行 Windows 和 Ubuntu。當你將 Ubuntu 安裝完後,記得先用 "更新管理員"將所有軟體進行更新。
  2. 在編譯 AOSP 原始碼之前,我們必須先安裝一些套件。這些步驟主要是參考 dferreira 發表的 [HOW-TO] Compile AOSP Froyo + [ROM] Latest AOSP Froyo for Sapphire
    1. /etc/apt/sources.list 檔案的最後加上下列兩行:
        deb http://pl.archive.ubuntu.com/ubuntu/ jaunty multiverse
        deb http://pl.archive.ubuntu.com/ubuntu/ jaunty universe
        
    2. 檔案修改完後,請執行下列指令來該新 apt 的資料庫:
        sudo apt-get update
        
    3. 請執行下列指令(只有一行)來安裝必要的軟體:
        sudo apt-get install git-core gnupg sun-java5-jdk flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl libncurses5-dev zlib1g-dev valgrind libreadline5-dev gcc-multilib g++-multilib libc6-dev libncurses5-dev x11proto-core-dev libx11-dev libreadline5-dev libz-dev
        
    4. 請在自己的家目錄($HOME)底下新增一個 bin 目錄,並將 repo 安裝到 bin 內。安裝後可以登出然後登入,剛安裝的 repo 就可以開始使用。
        cd ~
        mkdir bin
        curl http://android.git.kernel.org/repo >~/bin/repo
        chmod a+x ~/bin/repo
        
    5. 決定 AOSP 原始碼放置的目錄,並建立該目錄。假設目錄的名稱是 eclair,且 位於 $HOME,以下為執行並進入 eclair 目錄:
        mkdir ~/eclair
        cd ~/eclair
        
  3. 軟硬體的環境設定好了之後,我們就開始要從 AOSP 的網站把原始碼抓下來。
    1. 由於 Android 的版本眾多,你必須定義出究竟是哪一個版本是你要的。 由於我們參考的 文件是編譯 Android 2.1 版的,因此我們的指令如下:
      repo init -u git://android.git.kernel.org/platform/manifest.git -b android-2.1_r2
      
      請特別注意以上指令的綠色部分:因為編譯的是 Android 2.1 版的,所以我們使用 android-2.1_r2,那麼如果有一天我要編譯 2.2 或者 3.0 版呢?它的值應該是什麼 呢?其實,這個資料可以從 http://android.git.kernel.org/ 的網頁上找尋 platform/manifest.git,然後在它之後的 summary 連結上點一下,就可以知道。 在 http://android.git.kernel.org/?p=platform/manifest.git;a=summary 網頁的 下方的 tags 部分就可以看到所有可能的值。
    2. 新增一個如下的 local_manifest.xml 檔案在 .repo 目錄內。
      <?xml version="1.0" encoding="UTF-8"?>
      <manifest>
      <project path="kernel" name="kernel/msm" revision="refs/heads/android-msm-2.6.29-donut"/>
      <project path="vendor/htc/common-open" name="platform/vendor/htc/common-open" revision="master"/>
      <project path="vendor/htc/dream-open" name="platform/vendor/htc/dream-open" revision="master"/>
      <project path="vendor/htc/prebuilt-open" name="platform/vendor/htc/prebuilt-open" revision="master"/>
      <project path="vendor/htc/sapphire-open" name="platform/vendor/htc/sapphire-open" revision="master"/>
      <project path="vendor/qcom/android-open" name="platform/vendor/qcom/android-open" revision="master"/>
      <project path="vendor/qcom/proprietary-open" name="platform/vendor/qcom/proprietary-open" revision="master"/>
      <project path="vendor/pv-open" name="platform/vendor/pv-open" revision="master"/>
      <project path="vendor/aosp" name="platform/vendor/aosp" revision="master"/>
      <project path="hardware/htc/dream" name="platform/hardware/htc/dream" revision="master"/>
      </manifest>
      
      根據 Using the local_manifest.xml file in repo to customize your Android project setup 的說法,定義一個 local_manifest.xml 檔的 原因是由於 AOSP 上包含了許多的版本;以 Andoird 2.1 版而言,它就有給各式各樣 硬體結構(大多以 CPU 和生產 Android 的手機廠商而分),對於需要編譯 AOSP 的 開發人員似乎不需要把所有的原始碼都載回家,所以開發人員就可以利用 local_manifest.xml 把你個人特別的需求定義在檔案中。請稍微看一下檔案內容, 你會發現它主要定義了兩個項目: 一個是 CPU 的結構,由於 HTC Magic 是採用 msm 的 CPU,它選擇了 android-msm-2.6.29-donut,至於這個值的選擇方式跟之前的說法 類似,有興趣的人,可以到 projects / kernel/msm.git / summary 去看看。第二個部份 是有關於手機廠商的部份,由於是給 HTC 用的,所以就把所有跟 HTC 相關的 原始碼也載回來。
    3. 執行 repo sync 把定義好的原始碼抓回來,這個可能會等待比較久的 時間。
  4. 編譯 kernel 以及無線網路的驅動程式。我們先說明編譯的步驟,再說明我認為這個 步驟其實可以省略的原因以及如何取得"可用"的 binary。
    1. 先到 ~/eclair/kernel 目錄:cd ~/eclair/kernel
    2. 產生設定檔:make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- msm_defconfig
    3. (這個步驟可省略)修改設定檔 .config。請將檔案內的 CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX=384000 改成 CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX=528000,這個動作可以幫 CPU 的處理速度加快。
    4. 編譯 kernel:make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-
    5. 到 ~/eclair/system/wlan/ti/sta_dk_4_0_4_32 編譯無線網路的驅動程式,指令為
        cd ~/eclair/system/wlan/ti/sta_dk_4_0_4_32
        make ARCH=arm CROSS_COMPILE=~/eclair/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- KERNEL_DIR=~/eclair/kernel
        
    6. 把新編譯的 kernel 和無線網路的驅動程式複製到適當的位置 -- ~/eclair/vendor/htc/sapphire-open/。指令為
        cp ~/eclair/kernel/arch/arm/boot/zImage ~/eclair/vendor/htc/sapphire-open/kernel
        cp ~/eclair/system/wlan/ti/sta_dk_4_0_4_32/wlan.ko ~/eclair/vendor/htc/sapphire-open/wlan.ko
        
    雖然編譯的過程一切順利,可是必須再強調一次,這個編譯完的 kernel 是給 Magic 32B 用的,而這個 kernel 就算刷進 Magic 32A 內也是無法正常開機的,所以之前的刷機 過程我借用了 Cyanogenmod 系列的 kernel 修正檔,如此才能正常開機。因此我認為 在這裡就可以把適當的 kernel 以及無線網路的驅動程式複製進來(有機會我再試試看)。
  5. 編譯 Android 平台,編譯成功的話,會產生必要的 image 檔。
    1. 設定編譯的平台,包含以下指令:
        source build/envsetup.sh
        lunch aosp_sapphire_us-eng  # 也可以執行 lunch 並選擇平台
        
      lunch 指令後面那一串字包含一些重要資訊,我們把它拆開來看:第一個 aosp 也可以是 full,目前我不清楚它的差異;第二個 sapphire 代表 Magic 32A,可以是 dream, 也可以是 generic(代表基本型,僅適用模擬器);第三個是 us(代表美國),另一個 是 eu(代表歐洲);最後一個是 eng(代表有 root 權限),也可以是 userdebug(代表一般環境)。
    2. 取得 HTC 的檔案,並解壓縮。HTC 的檔案內含多個重要的程式庫,這些程式庫 必須存在才能順利的編譯 Android,但是由於抓取的(或者說 HTC 提供的)都已經是 舊版的(明確的說是 1.6 版),所以常常造成編譯 出來的 image 檔雖然能夠在手機上執行,但是也造成許多程式(如之前提到的 Calendar 和 Music 等)無法順利執行的原因。抓取並解壓縮檔案的指令為
        wget --referer=http://developer.htc.com/google-io-device.html http://member.america.htc.com/download/RomCode/ADP/signed-google_ion-ota-14721.zip?
        cd ~/eclair/vendor/htc/sapphire-open
        ./unzip-files.sh
        
    3. 加入繁體以及簡體中文,指令如下:
        cd ~/eclair
        
      並新增 buildspec.mk 檔案,在該檔案內加入
        CUSTOM_LOCALES:=zh_TW zh_CN
        
    4. 執行 make -j2 編譯 image 檔;這會需要一段時間,完成後在 ~/eclair/out/target/product/sapphire-open 內可以看到 image 檔。
在幾個階段中,共同有的疑問是:
  1. 為什麼 AOSP 抓下來的原始碼編譯後,只能在 old radio(也就是 2.22 或者是 3.22)執行呢?台版 HTC 官方的 radio 卻是 new radio(也就是 6.35),難道 AOSP 的原始碼沒有給 new radio 的嗎?

Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu

沒有留言:

張貼留言