建立AOSP Branch : 架設本地AOSP Gerrit Server完整指引 PART3

建立自有AOSP Branch


概觀

本文引導如何從現有的AOSP Branch建立另一個Branch以進行AOSP的客製化,以便將企業及自身的技術知識管理及保留。

本系列介紹如何建立本地自有 (Local) Gerrit Server並且將AOSP (Android Open Source Project)的原始碼完整導入此Gerrit Server。

若你已完成了

我們就會有了一台Gerrit Server主機,執行gerrit service,並且已經擁有完整AOSP主幹(master branch)的所有Projects在Gerrit Server中可供管理。

接下來我會以一個實例來進行建立自有AOSP Branch的工作,本文以Emulator驗證自行建立的Branch,並且進行原始碼的修改及執行。在之後的文章中,我會再用Pixel2來驗證自行建立的Branch再Build出的Image是可以燒錄。

主文的主要目的是指引你如何進行Android AOSP分枝建立及利用git push/repo upload來進行Code Review/Submit。這些工作在本文中都以Emulator來完成。所以在AOSP的世界,即使你沒有Pixel系統的實機(或Android One),還是可以好好享受探索Android OS!

建立Android P Branch


同步Android P官方原始碼


如同PART2的狀態,我們的Gerrit Server保有的是AOSP Master branch,那麼,我們第一步就是從官網抓回Android P (撰寫本文時,master branch是Android P的預覽版本)。但不是要整個重新抓回來,那太耗時也耗資源。我們同樣在Gerrit Client的目錄下工作,把不足的部份補回來就行了。

首先先要了解自己要抓回的版本是什麼。例如本文是想要在Pixel2上修改,所以我就要抓回Pixel2最新穩定版本。在官方上,例出的重要Branch/Tag


在本文發表時,Pixel2最新的Branch為android-9.0.0_r32。所以,決定了,就是你!我們以這個版本做為基底Baseline,再由它來做出Branch。
首先進入AOSP Mirror目錄中,在PART2,該目錄位於Gerrit Client主機的aosp_mirror目錄下。
在aosp_mirror目錄下,進行branch切換

repo init -b android-9.0.0_r32
repo sync -j8

這樣就能把一些在Master branch (Android Q)已經由Google官方從master branch移除掉,但仍包含在Android P (android-9.0.0_r32)的Projects抓回來本地的Mirror。
接下來把缺失的Projects一次匯入:

repo forall -c 'echo $REPO_PROJECT; ssh -p 29418 jeremychen@10.50.100.56 gerrit create-project --owner android-admin $REPO_PROJECT' #若有新的Project,就建立它,已經存在的Projects會回應Fatal error,這是正常的,無視
repo forall -c 'echo $REPO_PROJECT; ssh -p 29418 jeremychen@10.50.100.56 gerrit set-project-parent --parent AOSP $REPO_PROJECT' #若有新的Project,將Parent設為AOSP
repo forall -c 'echo $REPO_PROJECT; git push ssh://jeremychen@10.50.100.56:29418/$REPO_PROJECT +refs/heads/*' #匯入所有新增的Code,先匯入branch
repo forall -c 'echo $REPO_PROJECT; git push ssh://jeremychen@10.50.100.56:29418/$REPO_PROJECT +refs/heads/* +refs/tags/*' #再匯入所有tags,完成同步

這和同步匯入的命令是一樣的,建立Project,設定Parent Project,匯入Branch,匯入Tags。



接下來就是把原始碼從Gerrit Server抓出一份android-9.0.0_r32
重新從Gerrit Server抓取,例如我們把它放在myaosp這個目錄:

mkdir myaosp
cd myaosp
repo init -u ssh://jeremychen@10.50.100.56:29418/platform/manifest
repo sync
source ./build/envsetup.sh
lunch aosp_x86_64-eng #官方Build出X86 Emulator的方法
make -j16 #開始執行Build

或是,如果之前在PART2已經抓過整份Codebase並Build出X86 Emulator,只要重新切換至android-9.0.0_r32,這當然省時很多

repo init -b android-9.0.0_r32 #切換branch
repo sync #取得新的projects, 同時刪掉不需要的projects.
bash #重新進入一個shell以清除Environment Variables
source ./build/envsetup.sh
lunch aosp_x86_64-eng #官方Build出X86 Emulator的方法
make -j16 #開始執行Build

以上無論是重新取得一份Codebase或切換Branch的方式,最後Build出Emulator後,在shell下執行emulator (如果遇到CPU acceleration status: This user doesn't have permissions to use KVM (/dev/kvm),請執行 sudo chown `echo $USER` -R /dev/kvm,請/dev/kvm的權限設定好,再執行次emulator的命令即可)

執行自Build的Android模擬器
完成Emulator編譯及執行,檢視Build Nubmer
可以看見以上的Emulator的Android Version為9 (就是Android P),而Build number也顯示username,所以能確認是自行Build出來的版本。

有了一個穩定可執行的版本,接下來就要進行自建Branch的動作。
(當然,你可以先建立新的Branch再抓取出來驗證,這樣比較省時,我的習慣是先確定原本的Baseline是好的,再建立新的Branch,這樣的步驟有助於萬一出現問題比較容易偵錯)。

建立Branch

要建立Branch首先進入AOSP Mirror目錄中,在PART2,該目錄位於Gerrit Client主機的aosp_mirror目錄下。
首先進入aosp_mirror,建立自己的Branch。

repo forall -c 'echo $REPO_PROJECT; ssh -p 29418 jeremychen@10.50.100.56 gerrit create-branch $REPO_PROJECT my_android-9 android-9.0.0_r32'

此命令是要求所有在AOSP的Projects (當前的Manifest)基於android-9.0.0_r32這個Branch重新在Gerrit Server上再建立另一個Branch,my_android-9。建立Branch在Git而言原本就是非常快速的事,所以重建Branch應該很快就執行完畢。
完成後你可以在Gerrit Web UI上的BROWSE->Repositories中,任選一個Projects,例如platform/manifest,點選左側的Branches,搜尋my,就可以看到你新建的my_android-9這個Branch。

修改manifest.xml,首次Code Review

接下來就要進行第一次的Code Review及Commit。
首先要理解manifest.xml。在AOSP Codebase,myaosp/.repo目錄下有個檔案manifest.xml。這是repo command最重要的依據。裏面記載這個Codebase包含的所有Projects,抓取後要放置的目錄,以及同步原始碼的Review Server。我們的Codebase基於Android官方釋出的Codebase,所以同步原始碼的Review Server是指向Google官網,這也是我們主要要修改的部份。

編輯.repo/manifest.xml
<?xml version="1.0" encoding="UTF-8"?>
<manifest>

  <remote  name="aosp"
           fetch=".."
           review="https://android-review.googlesource.com/" />
  <default revision="refs/tags/android-9.0.0_r32"
           remote="aosp"
           sync-j="4" />
Highlight的部份,第6及第7行,是我們要修改的部份。第6行是review URL必須改至我們自建的Gerrit Server,而第7行是從Gerrit Server取出的Branch name。 修改後的結果。
<?xml version="1.0" encoding="UTF-8"?>
<manifest>

  <remote  name="aosp"
           fetch=".."
           review="http://10.50.100.56:8080/" />
  <default revision="refs/heads/my_android-9"
           remote="aosp"
           sync-j="4" />

轉換目錄至.repo/manifests,輸入git status .,可以看到你修改的diff
diff --git a/default.xml b/default.xml
index 5a85017..33bca8a 100644
--- a/default.xml
+++ b/default.xml
@@ -3,8 +3,8 @@
 
   <remote  name="aosp"
            fetch=".."
-           review="https://android-review.googlesource.com/" />
-  <default revision="refs/tags/android-9.0.0_r32"
+           review="http://10.50.100.56:8080/" />
+  <default revision="refs/heads/my_android-9"
            remote="aosp"
            sync-j="4" />

然後利用git push推上你的patch,進行第一次Code Review。
git add .
git commit -m "My android 9.0 (P)  branch"
git push ssh://jeremychen@10.50.100.56:29418/platform/manifest HEAD:refs/for/my_android-9
Counting objects: 1, done.
Writing objects: 100% (1/1), 237 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
remote: Processing changes: refs: 1, new: 1, done    
remote: 
remote: SUCCESS
remote: 
remote: New Changes:
remote:   http://10.50.100.56:8080/c/platform/manifest/+/1 My android 9.0 (P)  branch
To ssh://jeremychen@10.50.100.56:29418/platform/manifest
 * [new branch]      HEAD -> refs/for/my_android-9

成功之後,回到Gerrit Web UI,點選CHANGES->Open,可以看到第一個Code Review出現:

自行建立AOSP Branch,將manifest.xml上傳到Gerrit
Gerrit Web UI審視manifest.xml

圖中的Subject是我們剛才使用git commit -m的訊息,Owner/Branch都符合我們想要的結果。
點擊進入之後,可以檢視修改的部份(這也是Review最重要的部份),如果都沒有問題,點擊右上角的「CODE-REVIEW+2」,再點擊「SUMMIT」實際上將Code上傳。完成第一次Code Review及Commit。
如此,我們就完成了自建一個AOSP Branch/Codebase的動作。如果你是個個性謹慎IT人員,那就會把它重新抓取一次以確認整個Codebase的完整性:

mkdir my_android-9
cd my_android-9
repo init -u ssh://jeremychen@10.50.100.56:29418/platform/manifest -b my_android-9
repo sync
source ./build/envsetup.sh
lunch aosp_x86_64-eng #官方Build出X86 Emulator的方法
make -j16 #開始執行Build

重點在第3行,在取出manifest時,加入參數-b my_android-9,則之後repo sync整個AOSP Codebase就會取出所有Project的my_android-9branch。 所以也可以理解,其實repo的branch管理概念很簡單,就是同一個branch name的集合,即為整個repo branch,包含在當前repo的manifest中的所有Project必須擁有同名稱的branch name。

第二次Code Review,告訴我耳機插入了!!

剛剛的Code Review/Commit,使用git push命令將Code Change推上伺服器的動作對AOSP工程師而言很少用,AOSP工程師主要還是用repo upload來進行上Code的動作。以git push上Code的使用情境大概只有在修改manifest.xml及建立branch時才會用上。而這些工作對於中大型研發單位而言比較偏向IT人員或所謂CM (Code Management)人員才會做的事。

一般而言,AOSP工程師是使用「repo upload」這個命令來上Code。只是在使用repo upload之前,我們必須先把所有的tracking branch指向aosp/my_android-9(或你指定的branch),這一步很重要,要做這個動作後,之後使用repo upload時才能把Code推向Gerrit。

repo forall -c 'echo $REPO_PROJECT;git checkout -b my_android-9 aosp/my_android-9'

以上的命令會花上一段時間。

實作一個小功能


為了第二次上Code,我們來做簡單的一個小功能(其實只是小改一下),功能為「插入耳機時,在Status Bar顯示耳機Icon」,像這樣:

Android P顯示耳機圖示
耳機插入小圖示

你可以看到在插入耳機後,在Wi-Fi信號左邊一個耳機圖示。這是在耳機插入時才會顯示。在Google的原生AOSP設計中,預設是不顯示這個Icon,AOSP可能認為「你自己有沒有插入耳機難道不知道,要系統提醒你?」。但很多使用者的想法是,「有些耳機就怪怪的,插入了沒偵測到,或插不夠深,結果一放音樂直接從Speaker出聲音,就吵到人了。」,想想都有點道理!

在Android 8.0時,你可以下拉Status Bar後,長按設定鍵(齒輸小Icon),進入System Tuner UI,然後手動將耳機Headset圖示開啟。但Android 9.0之後,System Tuner的功能預設關掉了,所以我們的工作就是把它找回來!!

因為本文不是教你怎麼寫AOSP Framework相關的Code,所以就不描述要如何找到需要改變的Code的所在位置的思路。直接把要改的部份就寫出來。首先開啟:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
把第三行的Code從false改為true:

public class SettingsButton extends AlphaOptimizedImageButton {

    private static final boolean TUNER_ENABLE_AVAILABLE = true; //原始AOSP的值為false

    private static final long LONG_PRESS_LENGTH = 1000;
    private static final long ACCEL_LENGTH = 750;;

再重新下make命令再Build一次,然後執行emulator。完成後下拉Status Bar,長按右下角的設定鍵會發現小齒輪一直轉動(如下圖指標所示),放開後進入Settings畫面。

開啟Android P System UI Tunner設定
開啟System UI Tuner,客製圖示顯示設定

進入Settings之後,進入System->Advanced->System UI Tunner->Status bar後,開啟Headset。在實機上當然就是找個耳機插入了(廢話!),在Emulator中,開啟Extend Control,在右方選擇Microphone,開啟virtual headset plug inserted來模擬耳機插入。此時就能看到耳機Icon出現。

用repo upload將改變推向Gerrit

接下來就容易了,直接在你改Code的目錄下,輸入git status,以檢視目前project的狀態。這裏告訴你有個檔案SettingsButton.java改變了。然後用git commit進行Commit動作,最後執行repo upload ,把Code推向Gerrit進行Code Review。

repo upload --no-verify .
Upload project frameworks/base/ to remote branch refs/heads/my_android-9:
  branch my_android-9 ( 1 commit, Wed Apr 3 17:58:27 2019 +0800):
         5857f894 enable system ui tuner
to http://10.50.100.56:8080/ (y/N)? y
remote: Processing changes: refs: 1, new: 1, done    
remote: 
remote: SUCCESS
remote: 
remote: New Changes:
remote:   http://10.50.100.56:8080/c/platform/frameworks/base/+/21 enable system ui tuner
To ssh://jeremychen@10.50.100.56:29418/platform/frameworks/base
 * [new branch]      my_android-9 -> refs/for/my_android-9

注意1:repo upload --no-verify的--no-verify這個選項是避開repo hook的檢查功能之用。詳述可見:https://android.googlesource.com/platform/tools/repohooks/#Bypassing。如果你覺得麻煩,要關閉repohook的功能,就把manifest.xml中的“<repo-hooks in-project="platform/tools/repohooks" enabled-list="pre-upload" />“刪除即可!

注意2:repo upload是以user.email設定的email前綴做為user name。例如你的gerrit account名為foo,你的email就必須是foo@xxx.xx,因為repo upload是以email而不是以git config中的user.name做為帳號的判斷,這個設計上的考量我就想不通了!也許Google在repo上有其考量點只是我不懂,不過也許以後repo會改善。

最後回到Gerrit Web UI上,將Code進行最後Submit,就完成了Code Review及Commit。

審視Gerrit的Code Review SettingsButton.java

repo upload後,進行代碼審視後入庫

你可以看到Code Review的畫面,點選CODE-REVIEW+2再SUBMIT後,就完成了使用repo upload上傳Code至Gerrit的任務。

後記


「架設Gerrit Server並移轉AOSP Codebase」這系列的三篇文章主要是本身工作需求下,到處找相關文章,Tutorial,及和同事討論結果的筆記,再經過整理寫在Blog上。文章不像有些Quick Start完全不講原因,反正照抄照Key能成功就行,也不像很多完整的官方文件過於細節。這些文章就是給一些在工作上有同樣需求的IT/RD人員一個可以參照的範本,能省去大家一些摸索的時間,理解一些相關議題的訣竅,快一點完成自己的工作那也就夠了。至於真的要成為Gerrit/Git大師,恐怕還是得好好下苦功去鑽研官方文件了!






留言

張貼留言

這個網誌中的熱門文章

完整指引如何編譯AOSP (Build Android P),整合GMS及刷機 (Pixel 2)

架設Gerrit Server : 架設本地AOSP Gerrit Server完整指引 PART1

將AOSP加入Gerrit Server : 架設本地AOSP Gerrit Server完整指引 PART2