從 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