天天看點

編譯Android系統源碼

作者:趣事聽聞

AOSP 介紹

Android 開放系統平台 (AOSP) 是公開釋出且可修改的 Android 源代碼。任何人都可以下載下傳并修改其裝置的 AOSP。AOSP 提供 Android 移動平台的完整且功能完備的實作。

AOSP 全稱 Android 開源項目(Android Open Source Project),Android 是一個适用于移動裝置的開源作業系統,也是由 Google 主導的對應開源項目。此網站和 Android 開源項目 (AOSP) 代碼庫可為您提供所需資訊和源代碼,供您建立定制的 Android OS 版本,将裝置和配件移植到 Android 平台,同時確定裝置符合相容性要求,進而讓 Android 生态系統維持良好穩健的運作環境,以便更好地服務于數百萬使用者。文檔(Android 開源項目 | Android Open Source Project (google.cn))

編譯Android系統源碼

image-20231109134634113硬體環境

AOSP 的下載下傳、編譯理論上支援 Mac和Linux,但是不建議在非 Linux 環境下嘗試編譯,坑太多了,建議使用Linux系統進行編譯。

下載下傳 Android 12 及以後的版本,需要至少100GB的硬碟空間,編譯Android 12 則需要300GB的硬碟空間和16GB以上的記憶體,低于這個配置在編譯時大機率會報錯。

本篇文章使用Android 10的AOSP版本示範

建議硬體環境如下:

如下是我的虛拟機的硬體環境:

編譯Android系統源碼

image-20231103134507171Repo源碼管理工具

安裝完Ubuntu系統後,在下載下傳Android源碼之前,要先安裝其建構工具 Repo 來初始化源碼。Repo是Android用來輔助Git工作的一個工具。(Repo指令的詳解在下一篇文章中講解)

RepoRepo 簡介

Repo是Google使用python腳本編寫的用于調用Git的腳本,主要用來下載下傳、管理Android項目的軟體倉庫。Repo不會取代Git,但是它可以讓開發者在Android環境中更加輕松的使用Git。在大多數情況下,确實可以僅使用 Git(不必使用 Repo),或結合使用 Repo 和 Git 指令以組成複雜的指令。不過,使用 Repo 執行基本的跨網絡操作可大大簡化我們的工作。

安裝 Repo

Android源碼同時使用git和repo進行管理,repo是基于git的代碼管理工具,類似github、gitee,是以需要同時安裝git和repo

第 1 步,建立一個bin目錄,并将這個目錄添加到系統的環境變量中

mkdir ~/bin
PATH=~/bin:$PATH
           

第 2 步,下載下傳 repo

curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/bin/repo
chmod +x ~/bin/repo
           

安裝完repo後需要使用source指令重新加載linux的配置環境。

GitGit 簡介

Git是一個開源的分布式版本控制系統,可以有效、高速地處理從很小到非常大的項目版本管理。也是目前使用範圍最廣的版本控制系統。

Android 使用 Git 執行本地操作,例如建立本地分支、送出、對比差異、修改。Google 最初決定使用一種分布式修訂版本控制系統,經過篩選最後選中了Git。

安裝 Git

第 1 步,執行安裝指令

sudo apt install git
           

第 2 步,配置 Git 全局環境

git config --global user.name "使用者名"
git config --global user.email "郵箱"
           

第 3 步, 生成 ssh 秘鑰(可選配置)

ssh-keygen
           

一直按回車,生成的秘鑰檔案會在 ~/.ssh目錄下載下傳,我們将~/.ssh目錄下的id_rsa.pub 裡面的内容複制到倉庫管理系統相應的SSH Key中,在後續的代碼下載下傳時就不需要再輸入使用者名和密碼。

常見的源碼倉庫管理系統是Gerrit 和 GItLab。

線上閱讀、檢索AOSP源碼

aospxref.com/ 是一個線上的 AOSP 源碼閱讀網站,在這個網站上我們可以很輕松,閱讀、檢索 Android 的源碼,而且對于車載 Android 開發而言,閱讀源碼十分的重要。

下載下傳 AOSP

下載下傳 AOSP 有以下兩種方式

中科大和清華大學提供了AOSP源碼的壓縮包,現在的包大約有60GB左右,可以使用指令行或迅雷等下載下傳工具下載下傳。

優點:下載下傳速度快,支援斷點續傳。

缺點:不貼近工作環境,實際項目中不使用這種方式。

清華大學文檔:mirrors.tuna.tsinghua.edu.cn/help/AOSP/

中科大文檔:mirrors.ustc.edu.cn/help/aosp.h…

使用repo直接同步源碼,是Android官方文檔中使用的方式。

優點:更貼近工作環境。在實際項目中也是使用這種方式同步Android源碼。

缺點:源碼太大,外網不穩定、速度很慢,容易同步失敗(實際項目中,我們使用公司内網不會存在這個問題)。

官方文檔:source.android.google.cn/docs/setup/…

由于下載下傳Android源碼非常消耗伺服器的帶寬和I/O,中科大和清華大學的文檔中都強烈要求我們使用第一種方式同步源代碼。

如果下載下傳Android官方的AOSP的源碼,UP建議使用下載下傳壓縮包的方式,如果是下載下傳公司項目的Android源碼,則隻能使用repo同步。

下面建議使用repo的方式直接同步源碼:

第 1 步,建立工作目錄

同樣的,在開始下載下傳AOSP源碼之前,需要在合适的位置建立一個目錄用于放置源碼,使用如下指令:

mkdir AOSP
cd AOSP
           

第 2 步,初始化倉庫

使用repo init 指令初始化源碼倉庫。

repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest
           

第 3 步,同步源碼

執行repo sync 指令同步源碼。

repo sync
           

repo 的運作過程中會嘗試通路官方的 git 源更新自己,如果想使用 tuna 的鏡像源進行更新,可以将如下内容複制到你的 ~/.bashrc。

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

然後執行指令:

source ~/.bashrc
           

如果需要同步指定的Android版本,隻需要在repo init之後加上-b帶上分支名稱即可。

#初始化倉庫,-b 訓示分支,這裡使用Android 10
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-10.0.0_r41
#同步遠端代碼
repo sync
           

有關repo的更多使用方式,可以詳細閱讀中科大或清華大學的官方文檔,這裡不再贅述。

Android 源碼檔案目錄結構

應用層(Application)源碼。系統應用就在這裡了,比如說系統設定,桌面,相機,電話之類的。

系統架構(Framework)層源碼。

硬體抽象(HAL)層源碼。

輸出目錄。編譯以後生成的目錄,相關的産出就在這裡了

用于建構Android系統的工具。也就是用于編譯Android系統的

編譯 AOSP配置編譯環境

編譯Android源碼會用到很多第三方庫,我們需要先将這些庫配置好,指令如下:

需要注意如果你編譯的是Android12 以下需要使用python2,如果編譯Android 12及以上則需要使用pyton3

sudo apt update
sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig python3
sudo apt install python-is-python3
sudo apt clean && sudo apt autoremove -y
           

編譯 Android 鏡像

第 1 步,加載環境變量

在Android源碼根目錄執行source build/envsetup.sh,該指令會将lunch以及其他程式和變量添加到shell環境中。

cd aosp
source build/envsetup.sh
           

第 2 步,選擇編譯的目标

這裡選擇 26.asop_x86_64-eng 進行編譯,編譯的是手機的模式

lunch
26 # 選擇手機系統
m # 自動選擇适合的線程進行編譯
emulator # 啟動模拟器使用編譯好的系統
           

如果要編譯車載系統,這裡我們選擇 car_x86_64-userdebug。

執行lunch指令之前,目前視窗的shell環境必須已經執行過source build/envsetup.sh

第 3 步,執行編譯

make 指令是aosp的編譯指令,支援并發編譯。可以使用-j指定并發編譯的線程數。電腦的CPU核心數越多,可以設定的線程數就越大,編譯速度也就越快,一般可以設為CPU線程數。如果不指定,建構系統會自動選擇目前作業系統最适合的并行線程數。

make -j16 # 指定線程數
m #自動比對線程數
           

在調用 make 指令時,如果沒有指定任何目标,則将使用預設的名稱為“droid”目标,該目标會編譯出完整的 Android 系統鏡像。

第 5 步,啟動模拟器

編譯的時長取決于電腦的性能,首次編譯約需要耗時約2-5個小時,控制台提示 build completed successfully則表示編譯成功了。然後執行emulator就可以啟動模拟器了。

emulator
           

等待開機動畫播放完畢,看到Launcher界面,就表示編譯成功了。如果編譯後出現模拟器黑屏無法啟動,可以再執行lunch sdk_car_x86_64-userdebug,然後再make一次。

編譯Android系統源碼

image.png

注意這裡用的是模拟器,選擇編号26進行編譯

下次再啟動虛拟機需要執行的指令如下:

source build/envsetup.sh
lunch 26
emulator
           

模拟器啟動,則說明AOSP編譯成功:

編譯Android系統源碼

image-20231115220137381AOSP 中的單編和整編

修改Android源碼後如何進行編譯?進入到指定的目錄使用mm或者mmm指定修改的目錄進行編譯

mm # 編譯目前子產品
mmm # 編譯指定子產品 mmm packeage/apps/Luncher3
           
m:  編譯所有的子產品 整編
mm: 編譯目前目錄下的子產品,目前目錄下要有Android.mk檔案
mmm:編譯指定路徑下的子產品,指定路徑下要有Android.mk檔案

使用這些指令前需要在android源碼根目錄執行source build/envsetup.sh腳本設定環境
舉例子,編譯Camera2子產品步驟:
1.源代碼目錄下執行source build/envsetup.sh腳本設定環境
2.直接執行mmm packages/apps/Camera2/
或者等價于
1.源代碼目錄下執行source build/envsetup.sh腳本設定環境
2.先切換目錄cd packages/apps/Camera2/
3.執行mm
最後使用make snod重新生成sysem.img步驟:
1.source build/envsetup.sh
2.lunch 然後選擇2   [[選擇2是選擇和編譯整個系統時的選擇一緻。]]
3.make snod           [[先執行lunch,不然make]] snod報錯build_image.py - ERROR。
           

清理編譯中間産物,以便重新開始編譯

1、在源碼目錄的根目錄下,執行make clean;
2、進到源碼的\linux\kernel\目錄下,執行make mrproper;
3、再退回到根目錄,執行source build/envsetup.sh, lunch, make -j16;
           

生成工程資訊檔案 支援源碼導入到AS中

依次執行以下指令,生成IDE工程資訊檔案 android.ipr 和 android.iml

source build/envsetup.sh
mmma development/tools/idegen
development/tools/idegen/idegen.sh
           

此時如果直接使用Android studio打開android.ipr,會特别慢,因為太多東西了,一直在索引。是以打開之前我們需要編輯一下android.iml配置檔案。

我們可以使用下面的配置檔案替代原始的配置檔案,加快導入速度。該配置檔案要求Android Studio隻引入package子產品的源碼。如果有需要也可以引入frameworks子產品的源碼。

<module version="4" relativePaths="true" type="JAVA_MODULE">
  <component name="FacetManager">
    <facet type="android" name="Android">
      <configuration />
    facet>
  component>
  <component name="ModuleRootManager" />
    <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR#34;>
      <sourceFolder url="file://$MODULE_DIR$/packages" />
      <excludeFolder url="file://$MODULE_DIR$/frameworks" />
      <excludeFolder url="file://$MODULE_DIR$/.repo" />
      <excludeFolder url="file://$MODULE_DIR$/external/bluetooth" />
      <excludeFolder url="file://$MODULE_DIR$/external/chromium" />
      <excludeFolder url="file://$MODULE_DIR$/external/icu4c" />
      <excludeFolder url="file://$MODULE_DIR$/external/webkit" />
      <excludeFolder url="file://$MODULE_DIR$/frameworks/base/docs" />
      <excludeFolder url="file://$MODULE_DIR$/out/eclipse" />
      <excludeFolder url="file://$MODULE_DIR$/out/host" />
      <excludeFolder url="file://$MODULE_DIR$/out/target/common/docs" />
      <excludeFolder url="file://$MODULE_DIR$/out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates" />
      <excludeFolder url="file://$MODULE_DIR$/out/target/product" />
      <excludeFolder url="file://$MODULE_DIR$/prebuilt" />
      <excludeFolder url="file://$MODULE_DIR$/external/emma" />
      <excludeFolder url="file://$MODULE_DIR$/external/jdiff" />
    content>
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="inheritedJdk" />
  component>
module>

           

android 系統映射檔案說明

img名稱作用

boot.img

核心引導啟動有關鏡像

ramdisk.img

檔案系統有關鏡像,包含android系統檔案根目錄等

system.img

android系統核心鏡像,包含framework、系統app等,挂載在/system下

userdata.img

應用程式資料鏡像,挂載在/data下

cache.img

臨時資料存放鏡像

編譯過程遇到的問題FAILED: out/target/product/generic_x86_64/system-qemu.img

如果編譯的是Android 10或以下版本使用的python2,需要注意編譯環境的python版本需要轉到檔案/android/device/generic/goldfish/tools/mk_combined_img.py并将第一行:#!/usr/bin/python更改為#!/usr/bin/python2應該可以正常編譯了.

1.以 root 身份登入,首先羅列出所有可用的python 替代版本資訊

update-alternatives --list python
           

這一步可能會報錯update-alternatives: error: no alternatives for python

2.如果出現以上所示的錯誤資訊,則表示 Python 的替代版本尚未被update-alternatives 指令識别。想解決這個問題,我們需要更新一下替代清單,将python2.7 和 python3.6 放入其中。

update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1  
update-alternatives --install /usr/bin/python python /usr/bin/python3.6 2
           

最後的1、2、3...代表序号,後面會有用

3.再次列出可用的 Python 替代版本

update-alternatives --list python
           

4.我們就可以使用下方的指令随時在列出的 Python 替代版本中任意切換了

update-alternatives --config python
           
編譯Android系統源碼

輸入數字,選擇版本.

啟動模拟器遇到的問題

emulator
           

KVM錯誤

emulator: ERROR: x86 emulation currently requires hardware acceleration!Please ensure KVM is properly installed and usable.

CPU acceleration status: KVM is not installed on this machine (/dev/kvm is missing).

egrep -c '(vmx|svm)' /proc/cpuinfo
           

先使用該指令檢視是否支援虛拟化,如果不支援的話在虛拟機的CPU選項中打開即可。

sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils
sudo adduser `id -un` libvirtd
sudo adduser `id -un` kvm
           

[[檢查是否安裝成功]]sudo kvm-ok

模拟器黑屏

emulator -partition-size 4096 -kernel ./prebuilts/qemu-kernel/x86/4.9/kernel-qemu2
           

通過使用kernel-qemu-armv7核心 解決模拟器等待黑屏問題.而-partition-size 4096則是解決警告: system partion siez adjusted to match image file (3083 MB > 800 MB)

模拟器啟動後崩潰VMware: vmw_ioctl_command error Invalid argument.Aborted (core dumped)

關閉硬體加速

export SVGA_VGPU10=0
echo "export SVGA_VGPU10=0" >> ~/.bashrc
source ~/.bashrc
           

體驗Framework開發,去掉Launcher中的Google搜尋欄

Google搜尋欄在中國是沒有辦法使用的,那麼在中國銷售的産品必定是要去掉

修改檔案packages/apps/Launcher3/res/layout/search_container_workspace.xml将fragment注釋掉

<com.android.launcher3.qsb.QsbContainerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:id="@id/search_container_workspace"
        android:padding="0dp" >

    
com.android.launcher3.qsb.QsbContainerView>
           

修改檔案packages/apps/Launcher3/src/com/android/launcher3/Workspace.java 搜尋布局檔案的名字search_container_workspace 注釋掉 最後幾行代碼即可

   public void bindAndInitFirstWorkspaceScreen(View qsb) {
        if (!FeatureFlags.QSB_ON_FIRST_SCREEN) {
            return;
        }
        // Add the first page
        CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
        // Always add a QSB on the first screen.
        if (qsb == null) {
            // In transposed layout, we add the QSB in the Grid. As workspace does not touch the
            // edges, we do not need a full width QSB.
            qsb = LayoutInflater.from(getContext())
                    .inflate(R.layout.search_container_workspace,firstPage, false);
        }

        // CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1);
        // lp.canReorder = false;
        // if (!firstPage.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true)) {
        //     Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout");
        // }
    }
           

重新編譯源碼,啟動模拟器

m
emulator
           

啟動模拟器後可以看到搜尋欄沒有了….

編譯Android系統源碼

image-20231115220720735