從 0 開始編譯 Android 系統原始碼

語言: CN / TW / HK

前言

在開始學習 Android Framework 的知識前,準備好相關的原始碼環境是非常有必要的。可以選擇直接在 https://cs.android.com/ 網站線上看,但是跳轉這些還是不如在 IDE 下來的方便。或者也可以下載好指定版本的原始碼,並通過 IDE 來檢視,但是這樣無法編譯原始碼,所以也就無法修改原始碼後編譯檢視效果。

所以這篇文章主要是為了後續編譯 Android 原始碼來做準備的,由於編譯原始碼最好是在 Linux 環境下進行(因為 Android 官方就是在 Linux 環境下編譯的,為了省事),但是我的裝置是 Windows,所以為了在不影響原系統的情況下,可以通過安裝虛擬機器並在虛擬機器中安裝 Linux 系統。或者有一種更方便的方式是安裝 Docker,在 Docker 下安裝別人已經準備好的 Linux 環境,但是後者在這篇文章中就不介紹了。

當前文章所使用的環境和版本資訊:

使用裝置:Windows 10 64 位 x86 系統 VirtualBox:7.0.2 版本 Ubuntu:22.04.1 LTS 版本

準備工作

  1. 下載並安裝 VirtualBox 虛擬機器軟體:https://www.virtualbox.org/wiki/Downloads
  2. 下載 Linux 的 Ubuntu 發行版:https://cn.ubuntu.com/download/desktop

VirtualBox 的安裝很簡單,直接下一步、下一步就可以了。所以後面主要介紹下 Ubuntu 的安裝和配置。

安裝 Ubuntu

  1. 開啟 VirtualBox,點選“新建”按鈕,並填寫虛擬機器的名稱:

image.png

注:此時不需要選擇 ISO Image,這樣就是手動安裝了,手動安裝可以選擇系統語言。

  1. 分配記憶體和執行緒數(建議分配最少 4G 記憶體):

image.png

  1. 分配磁碟大小(建議最少 200G 起):

image.png

  1. 點選完成。

接下來會進入系統的安裝流程,語言可以選擇中文,輸入使用者名稱和密碼,根據提示直接一步步安裝即可。

注意:進入系統的引導安裝頁面後,螢幕的解析度很低,可能會導致顯示不完整的情況,例如沒有顯示出下一步的按鈕。此時可以用快捷鍵 Win + 滑鼠左鍵拖動安裝頁面,將顯示不全的頁面展示出來。

配置 Ubuntu

  1. 修改解析度:由於預設的解析度太低,看起來不是很舒服,所以可以進入設定頁面調整解析度到合適的大小。
  2. 安裝增強工具:從而可以使用共享目錄、共享貼上板和拖放功能。
  3. 點選“裝置”-> “安裝增強工具”,此時檔案系統中會出現 VBox_GAs_xxx 目錄
  4. 進入該目錄,並右鍵選擇在當前目錄開啟終端
  5. 在終端中輸入:sudo ./VBoxLinuxAdditions.run並回車,即可安裝增強工具
  6. 開啟共享目錄:在“裝置”-> “共享資料夾”中可以新增要共享的資料夾。注意:只需要勾選“自動掛載”和“固定分配”。當重啟系統後,就可以在檔案系統中看到 sf_xxx的目錄,該目錄就是共享的目錄。如果點選檢視該目錄出現許可權問題,可以使用 sudo adduser [username] vboxsf命令將當前使用者新增到 vboxsf使用者組(注意替換為你設定的使用者名稱)。
  7. 設定“共享貼上板”和“拖放”為雙向。
  8. 配置網路代理:即便我們在 Windows 系統上安裝好了 FQ 軟體,但是在 Ubuntu 系統中還是無法訪問外網的。所以我們需要配置好代理,從而在後續下載 Android 原始碼時更方便。例如(IP 地址為 Windows 系統上的 IP,埠為 FQ 軟體上設定的埠):

image.png

注意:在完成配置後,最好重啟下系統,從而讓配置生效。

準備原始碼環境

安裝 Repo

Android 專案很大,是一個超級專案。所以為了更好的管理程式碼,Android 官方做了一個叫做 Repo 的工具,用來在 Android 環境中更好的使用 Git 來管理程式碼。因此我們要獲取 Android 原始碼,首先需要準備好該工具。

在終端中執行以下命令來安裝 Repo 工具: bash sudo apt-get update sudo apt-get install repo 檢查是否安裝成功: bash repo version 如果出現和以下類似的輸出,則說明安裝成功: ``` [email protected]:~$ repo version

repo launcher version 2.17

(from /usr/bin/repo) ```

初始化 Repo

由於眾多周知的原因,如果不適用映象的話會出現網路問題,下載速度也不理想。因此可以選擇用清華大學或其他組織提供的映象地址來解決問題。這裡以清華大學的映象為例:

  1. 安裝 curl 工具: bash sudo apt-get install curl

  2. 下載 repo 到 bin 目錄並設定許可權: bash mkdir ~/bin curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/bin/repo chmod +x ~/bin/repo

  3. repo 的執行過程中會嘗試訪問官方的 Git 源更新自己,如果想使用映象源進行更新,可以將如下內容複製到你的 ~/.bashrc裡(使用 sudo nano ~/.bashrc命令進入 nano 編輯器修改): ```bash

https://mirrors.tuna.tsinghua.edu.cn/help/git-repo/

export PATH=~/bin:$PATH export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo' ```

  1. 使用 source ~/.bashrc讓其立即生效。

下載原始碼

  1. 建立一個目錄用來存放原始碼: bash mkdir <dir_name> cd <dir_name>

  2. 使用真實使用者名稱和郵件地址配置 Git: bash git config --global user.name YourName git config --global user.email [email protected]

  3. 初始化 repo: bash repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest 如果需要指定版本,可以使用 -b 選項指定分支(該連結中包含所有的分支資訊:https://source.android.com/docs/setup/about/build-numbers#source-code-tags-and-builds): bash repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-10.0.0_r47

  4. 同步原始碼: basic repo sync 如果需要加快同步速度,可以傳遞 -c(當前分支)和 -jthreadcount 標誌: bash repo sync -c -j4

    以 Android 10 原始碼為例,下載完大小大約為 100G 左右。

編譯原始碼

安裝所需工具

在編譯的過程中需要用到一些工具,所以提前安裝好它們避免編譯失敗: bash sudo apt install m4 libncurses5 python-is-python3

執行 envsetup 指令碼

envsetup.sh指令碼用於初始化環境,其中記錄著編譯過程中所需的各種函式實現,例如 lunch、m、mm、mmm等等。在下載好的原始碼目錄下通過一下命令執行該指令碼: bash source ./build/envsetup.sh 或者也可以使用以下命令: bash . ./build/envsetup.sh

注意:每次重新開啟終端後都需要再次執行該命令。另外,使用 hmm 可檢視可用命令的完整列表。

選擇編譯目標

通過 lunch <product_name>-<build_variant>命令可以選擇要構建的目標。其中 product_name指定要構建的產品,build_variant指定要構建的變體。

所有構建目標都採用 BUILD-BUILDTYPE形式,其中 BUILD是指代特定功能組合的代號。 BUILDTYPE是以下之一:

| BUILD TYPE | 備註 | | --- | --- | | user | 編譯出的系統有許可權限制,適用於生產環境 | | userdebug | 編譯出的系統有 root 許可權,除錯首選 | | eng | 優先考慮開發生產力,帶有附加除錯工具並關閉了優化 |

如果不知道該如何選擇目標產品,可以只使用 lunch 命令列出可用的產品列表。例如: ```bash [email protected]:~/aosp$ lunch

You're building on Linux

Lunch menu... pick a combo: 1. aosp_arm-eng 2. aosp_arm64-eng 3. aosp_blueline-userdebug 4. aosp_bonito-userdebug 5. aosp_car_arm-userdebug 6. aosp_car_arm64-userdebug 7. aosp_car_x86-userdebug 8. aosp_car_x86_64-userdebug 9. aosp_cf_arm64_phone-userdebug 10. aosp_cf_x86_64_phone-userdebug ...... `` 此時可以直接輸入對應的序號來選擇,後續也可以直接通過產品名來直接選擇,例如:lunch aosp_arm-eng`。

執行編譯命令

編譯指令根據使用場景不同有好幾種,下表中列出了這些編譯指令:

| 編譯指令 | 備註 | | --- | --- | | m | 在原始碼樹的根目錄執行編譯 | | mm | 編譯當前路徑下所有模組,但不包含依賴 | | mmm [module_path] | 編譯指定路徑下所有模組,但不包含依賴 | | mma | 編譯當前路徑下所有模組,幷包含依賴 | | mmma [module_path] | 編譯指定路徑下所有模組,幷包含依賴 | | make [module_name] | 當不指定引數時則表示編譯整個 Android 原始碼(包含依賴) |

注:m、mm、mmm、mma、mmma 這些命令都是通過 make 方式來完成的。

一般首次的情況下會使用 make指令來編譯,相當於進行一次全量編譯。為了加快編譯速度,可以使用 -j引數指定執行緒數,例如: bash make -j8 編譯成功後,終端會顯示 build completed successfully。同時,在原始碼根目錄下的 /home/airsaid/aosp/out/target/product/<product_name>目錄中會出現編譯後的產物。其中比較重要的有以下三個映象檔案:

  • system.img:系統映象。裡面包含了 Android 系統主要的目錄和檔案,通過 init.c進行解析並 mount掛載到 /system目錄下。
  • userdata.img:使用者映象。是 Android 系統中存放使用者資料的,通過 init.c進行解析並 mount掛載到 /data目錄下。
  • ramdisk.img:根檔案系統映象。包含一些啟動 Android 系統的重要檔案,例如 init.rc

在編譯的過程中可能會遇到以下問題,可以按照對應的解決方法來解決:

  1. 找不到 /usr/bin/python檔案或目錄: bash /bin/bash: device/generic/goldfish/tools/mk_combined_img.py:/usr/bin/python:直譯器錯誤: 沒有那個檔案或目錄

  2. python 指令碼語法錯誤(由於原始碼中部分 python 指令碼用到了 python2 的語法導致的): ```bash File "/home/airsaid/aosp/device/generic/goldfish/tools/mk_combined_img.py", line 48

    print "'%s' cannot be converted to int" % (line[2])

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? 解決方法:沒有安裝 python2 則先安裝,並建立軟連線將 python 指向 python2:bash sudo apt install python2 sudo ln -s /usr/bin/python2 /usr/bin/python ```

  1. 記憶體溢位: bash Exception in thread “main” java.lang.OutOfMemoryError: Java heap space 解決方法:通過修改 _JAVA_OPTIONS環境變數配置,指定更大的記憶體。將下面的程式碼新增到 .bashrc檔案: bash export _JAVA_OPTIONS=-Xmx4096m

其他

為 VirtualBox 中的 Ubuntu 擴容

  1. 在關閉虛擬機器的前提下,通過 cmd 進入 VirtualBox 的安裝目錄,例如: bash cd /d D:\virtualbox\

  2. 檢視 VirtualBox 的虛擬硬碟,並記下 UUID 資訊: bash D:\virtualbox>VBoxManage list hdds UUID: 279063de-8822-48c2-97d9-67964fb90b18 Parent UUID: base State: created Type: normal (base) Location: G:\VirtualBoxVMs\Ubuntu\Ubuntu.vdi Storage format: VDI Capacity: 225280 MBytes Encryption: disabled

  3. 根據指定 UUID 修改對應虛擬機器的容量大小,例如下面的示例中重新分配了 51200 MB(50G): bash VBoxManage modifyhd 279063de-8822-48c2-97d9-67964fb90b18 --resize 51200

  4. 開啟虛擬機器,安裝 gparted分割槽工具: bash sudo apt-get install gparted

  5. 開啟分割槽工具,並將多出來的磁碟分到對應磁碟上。

    注意:如果出現 Unable to resize read-only file system 可以參照該文章進行解決:https://blog.csdn.net/ningmengzhihe/article/details/127295333