將AOSP加入Gerrit Server : 架設本地AOSP Gerrit Server完整指引 PART2
前言
本文在引導你如何將AOSP (Android Open Source Project)完整導入企業內部或個人Gerrit伺服器。AOSP包含近800個專案,要如何有效快速無誤的將這些專案導入Gerrit對很多IT人員來說若不知方法會是很頭痛的問題。本文是系列文的第二篇,本系列在介紹如何建立本地自有 (local host) Gerrit Server並且將AOSP (Android Open Source Project)的原始碼完整導入此Gerrit Server。
系列分為三個部份,本文是第二部份,教導如何建立AOSP Git Mirror並且同步導入自建的Gerrit Server,如果你還不知如何架設一個Gerrit Server,可以回到這系列的
第一部份:架設Gerrit Server,
第二部份:將AOSP完整導入Gerrit Server (本文)。
第三部份:如何從本地Gerrit Server建立一個AOSP Branch。
進行此AOSP導入工作的主要目的在於本人專業工作上需要修改AOSP原始碼以符合客製化的需求,但AOSP本身龐大的原始碼及代碼庫(Repository)不適合再導入公司內部原有已存在的Gerrit Server。於是乎,將AOSP導入一個新建的Gerrit Server成為一個合理的選擇。另外更重要的原因是,自身內部專案的AOSP原始碼必須能夠提供以下功能:
- 進行Code Review,確保穩定性及紀錄留存以保留技術知識。
- 同步Merge Android官方原始碼,確保官方修正的問題可以同步合入自身專案。
在完成本文中所述的任務之後,你應該可以:
- 建立基本Gerrit Server的能力
- 抓取AOSP並導入Gerrit Server的能力
- 同步AOSP並且合入官方修改的原始碼的能力
- 建立自身AOSP Branch並且修改及進行Code Review
本文在Ubuntu 18.04進行,基本上我在Ubuntu 16.04也執行過同樣任務,所以差別不大,所以你的系統是在Ubuntu 16.04,應該完全可以適用。
所需軟體
- Gerrit (version 2.16.4)
- Git
- Open JDK 8
- Apache2 (非必要)
- MySQL (非必要)
- Gerrit Delete Project Plug-in (非必要,但很好用)
概念
AOSP的相關資訊都在Android的官方網站 (https://source.android.com/),如果你還不曾完整Build過Android的Codebase (不論是AOSP,Qualcomm還是MTK),那麼你必須從:
這裏開始把Build Code的環境設定好。
AOSP是由一大堆Projects組成(本文選寫時,大約七八百個Project),利用repo這個命令管理。如果使用上一篇方法來的一個一個建立Projects,不僅曠日費時,也容易出錯。
但如果把repo命令,git mirror概念,gerrit命令的基本功能都弄清楚,則之後的導入同步及錯誤修正就不會很難。
什麼是Git Mirror?
用很簡單的直接的講法就是「完全複製一份出來」。以往利用git clone取得的Project,是針對單一branch取出原始碼。而git clone --mirror則是把所有的branches/tags都取出來。就是AOSP上所有的原始碼你可以一次性下載。那也就是我們的目的。
所以基本的做法很簡單,用以下步驟來完成轉移AOSP的工作。
- 取得一份完整的AOSP Git Repository (Git mirror)
- 把AOSP Git mirror中所有的Projects在Gerrit創建一次。
- 把所有的AOSP Git mirror中所有的branches/tags都push進Gerrit Server
- 留下AOSP Git Mirror做同步化,官方新的Patch可同步至本地Gerrit Server
概念很清楚簡單,但執行起來卻有很多細節處理。包含權限設定,錯誤處理,架構規劃,都可能會讓你卡住很久。所以我在做第一次轉移AOSP的動作時,也花了三天以上的時間。所以本文就是讓你能一次性完成,不必走一次一樣的冤枉路。
執行AOSP移轉匯入本地Gerrit Server
- 取得AOSP Git Repository (Mirror)
首先取得完整的AOSP Git Repository。取得的位址及方法在以下官網描述
https://source.android.com/setup/build/downloading
在官網中告訴你下載的方式為:repo init -u https://android.googlesource.com/platform/manifest
但這個方式是取得master branch,或是在其後加入-b <branch name>以取得其他Branch。
本文要完整取出所有的branch及tags,就必須加入--mirror參數。在本文範例中,我們先在另一台主機Gerrit Client建立一個目錄aosp_mirror,存放AOSP mirror
本文要完整取出所有的branch及tags,就必須加入--mirror參數。在本文範例中,我們先在另一台主機Gerrit Client建立一個目錄aosp_mirror,存放AOSP mirror
所以重點在--mirror這個參數,讓我們可以完整取得AOSP所有Repository。 注意,取得AOSP Repostory必須是在Gerrit Server有Administrator權限的人,在PART1中,此人為jeremychen。所以不一定要在Gerrit Server同一台執行,可以在遠端Client (以下稱之為Gerrit Client)取回AOSP Repository後,透過git push將原碼推至Gerrit Server。 最後用repo sync取得原始碼,這會花一段時間,我大概花了三個小時下載,因為大概有100 GBytes以上的資料量。
- 在Gerrit Server建立所有Projects的前期工作
建立所有的Projects之前我們先建立一個Parent Repository--AOSP。(若你還沒有Gerrit server及Gerrit Web UI,請先至PART1建立)。
在Gerrit Web UI中,點選Browse->Repositories,點擊「CREATE NEW」
輸入名稱為AOSP,在「Only server as parent for other repositories」選擇True。按下「CREATE」,完成建立。在Gerrit Web UI中,點選Browse->Repositories,點擊「CREATE NEW」
![]() |
建立管理Repository用的Repository,以利之後的權限管理 |
AOSP只是個Parent Repository,主要是要把所有AOSP下的七百多個Projects在Gerrit上的權限在統一管理。之後加入的Projects將Parent設為AOSP,我們只要在AOSP下調整權限,就可以等同調整所有Projects的權限,同時也不影響其他已存在Gerrit Server的Projects的權限。
然後我們加入兩個Group (成員群組),android-admin及android-coder,剛剛加入的Parent Project “AOSP”是把相關的Projects做一個群組,而成員群組也是同樣的概念,把人加入某一個成員群組後,該成員的權限就能統一管控。
在Gerrit Web UI中,點選Browse->Groups,點擊「CREATE NEW」,輸入android-admin,按CREATE,建立群組。
![]() |
新增Group,使用者群組 |
再重複以上動作一次,加入android-coder。因為創立者是預設member,所以點選android-admin/android-coder後,再點選左側的Memebers,就可以看到有哪些人在此群組。
android-admin顧名思義,就是管理AOSP Projects的人,包含建立/刪除/Merge/Review等管理工作,而android-coder就是把修改的Code推上Gerrit等待Review,請android-admin進行Review後Commit或Abandon。
所以接下來就是設定AOSP的權限:
1. 在Gerrit Web UI中,點選BROWSE->Repositories,選擇或搜尋AOSP。點選進入。
2. 在左側欄,點選Access。
3. 在中央主畫面中,點擊Edit。開始編輯權限
4. 此時會有第一個Preference出現,把ref/for/*改為ref/*
5. 下拉Add permission:,選擇Push,點選右邊的Add。此時有個Push權限加入。
6. 在Push下方的"add group"文字欄中,輸入android-admin,按Enter (或輸入至一半時,若跳出選單,選android-admin即可)。
7. 重覆步驟5和6,加入Forge Author Identity和Forge Committer Identity。
8. 結果如下:
![]() |
在使用者群組中,新增存取權 |
- 在Gerrit Server匯入所有Projects
接下來是把七百多個Projects都建在Gerrit Server上。回到Gerrit Client主機上,進入剛剛建立的aosp_mirror目錄中。你可以先輸入:
來看所有的Projects,這個命令repo forall -c就是「在所有Projects執行命令」,而$REPO_PROJECT這變環境變數會隨著當前的有不同的值,其值就是Project Name。
所以以上的命令就是把所有的Project Name列出來,而沒有對Git/Gerrit做任何操作。
第一步,在Gerrit上新建所有Projects
理解了上述repo forall -c及$REPO_PROJECT變數後,以下的建立Projects的命令就很容易了解。
第一個指令是建立所有Projects;第二個指令是把所有的Projects的Parent Project設為AOSP,所有的AOSP Projects的父專案就是AOSP,將來只要改變AOSP的權限就能設定所有Project存取權限。
repo forall -c是對每個Project做動作,echo是列出目前要重新建立在Gerrit Server的Project Name,如果發生了任何的Error Message,你也會比較容易知道是哪個Project出問題。 真正執行建立Project的命令是:ssh -p 29418 jeremychen@10.50.100.56 gerrit create-project --owner android-admin $REPO_PROJECT;
ssh -p 29418是用SSH的29418 Port通訊 (Gerrit Server預設Port),jeremychen是Adminstrator username, 10.50.100.56是Server IP。gerrit create-project是Gerrit命令,用來建立新的Project,--owner是Project管理者,所以是android-admin這個群組。最後repo forall替你把$REPO_PROJECT換成真正的Project Name。
以上的指令應該不會碰上什麼困難,就是把700多個Projects整個Looping一次,建立好,設定Parent Project。
此時你可以回到Gerrit Web UI,看一下所有Projects是否成功建立。
可以看出已經有一大堆Projects列在Gerrit Web UI上了。
第二步,把所有的原始碼匯入剛剛建立的Projects:
在執行全部專案原始碼匯入之前,回到Gerrit Server主機,修改aosp_review_site/etc/gerrit.config並且重啟gerrit service。 修改如下:
加入第27,28行(Highlighten),maxBatchCommits=1000000是為了解決錯誤訊息為 (more than 10000 commits, and skip-validation not set),而timeout=120m是修正在滙入時,由於Project過於龐大,造成過時問題。 做一次匯入的時間很長,所以建議先改好gerrit.config,重啟gerrit server (gerrit.sh restart)之後再進入滙入工作。 如果不改gerrit.config,在執行滙入時,就會發生類似錯誤。
可以看出錯誤訊息為 (more than 10000 commits, and skip-validation not set),而maxBatchCommits=1000000這個設定可以解決該問題。
接下來就真正進入Project滙入Gerrit Server的作業了。
對每一個AOSP Project執行git push的命令,將原始碼匯入:
此時視你內部網路及主機的效能而定,但仍需要約30分鐘至1小時以上的時間完成整個匯入的動作 (花了兩三小時才匯入也是正常)。
所以以上的命令就是把所有的Project Name列出來,而沒有對Git/Gerrit做任何操作。
第一步,在Gerrit上新建所有Projects
理解了上述repo forall -c及$REPO_PROJECT變數後,以下的建立Projects的命令就很容易了解。
第一個指令是建立所有Projects;第二個指令是把所有的Projects的Parent Project設為AOSP,所有的AOSP Projects的父專案就是AOSP,將來只要改變AOSP的權限就能設定所有Project存取權限。
repo forall -c是對每個Project做動作,echo是列出目前要重新建立在Gerrit Server的Project Name,如果發生了任何的Error Message,你也會比較容易知道是哪個Project出問題。 真正執行建立Project的命令是:ssh -p 29418 jeremychen@10.50.100.56 gerrit create-project --owner android-admin $REPO_PROJECT;
ssh -p 29418是用SSH的29418 Port通訊 (Gerrit Server預設Port),jeremychen是Adminstrator username, 10.50.100.56是Server IP。gerrit create-project是Gerrit命令,用來建立新的Project,--owner是Project管理者,所以是android-admin這個群組。最後repo forall替你把$REPO_PROJECT換成真正的Project Name。
以上的指令應該不會碰上什麼困難,就是把700多個Projects整個Looping一次,建立好,設定Parent Project。
此時你可以回到Gerrit Web UI,看一下所有Projects是否成功建立。
![]() |
所有AOSP專案項目建立完成 (尚未有原始代碼) |
可以看出已經有一大堆Projects列在Gerrit Web UI上了。
第二步,把所有的原始碼匯入剛剛建立的Projects:
在執行全部專案原始碼匯入之前,回到Gerrit Server主機,修改aosp_review_site/etc/gerrit.config並且重啟gerrit service。 修改如下:
加入第27,28行(Highlighten),maxBatchCommits=1000000是為了解決錯誤訊息為 (more than 10000 commits, and skip-validation not set),而timeout=120m是修正在滙入時,由於Project過於龐大,造成過時問題。 做一次匯入的時間很長,所以建議先改好gerrit.config,重啟gerrit server (gerrit.sh restart)之後再進入滙入工作。 如果不改gerrit.config,在執行滙入時,就會發生類似錯誤。
可以看出錯誤訊息為 (more than 10000 commits, and skip-validation not set),而maxBatchCommits=1000000這個設定可以解決該問題。
接下來就真正進入Project滙入Gerrit Server的作業了。
對每一個AOSP Project執行git push的命令,將原始碼匯入:
repo forall -c 'echo $REPO_PROJECT; git push ssh://jeremychen@10.50.100.56:29418/$REPO_PROJECT +refs/heads/*' repo forall -c 'echo $REPO_PROJECT; git push ssh://jeremychen@10.50.100.56:29418/$REPO_PROJECT +refs/heads/* +refs/tags/*'
你可以看出我用了兩個很相似的命令去匯入原始碼,第一個是只推heads (branchs) 另一個加上tags。這看起來有點瞎,但在性能不太強大的Gerrit Server主機是必須的。否則會由於效能不足(RAM?)而發生internal server error!
下完命令後,大部份的Project都可以順利被匯入gerrit server,最可能出錯的Project是platform/manifest,如果你看到以下錯誤訊息(internal server error):
以經驗而言,Gerrit Server主機端發生問題,很多的狀況是RAM不足造成的。但也不要傻傻的就跑去擴充RAM(我的Gerrit Server有8G RAM,但在push manifest時,還是出現internal server error!)。仔細檢視platform/manifest這個Projects,很明顯它的refs非常多,所以如果這是個造成問題的變數,那我們可以各別ref推入的方式來解決這個問題。
首先回到Gerrit Client,進入aosp_mirror/platform/manifest.git
一樣分兩個命令,一個把所有Branch推入,另一個把所有Tags推入。這兩個命令就是先列出所有Branch/Tag後,逐個推入,這樣就不會有因RAM不足而造成的錯誤。缺點就是比較花時間。(但一定比去擴充RAM省時省錢,至於RAM有擴到多大才夠?我也沒試過!當然也有可能是Gerrit的編程時,沒考慮如此大量的refs時的狀況,所以在gerrit server發生問題時,我們從error log也看不出什麼問題,因為也沒看見任何Exception!!這只有真的去鑽Source Code才能得到答案了。)
- 驗證,取回原始碼並且Build出Image在Emulator執行
目前我們取得的是AOSP Master branch,也就是最新的原始碼,通常都可以Build過。但如果你就這麼剛好在兩個Commit中間取出原始碼,Build Fail也不是不可能的事。
要驗證我們的Gerrit是不是沒有問題,第一步就是把AOSP整個取出,之後Build過一次:
Build好之後,執行Android Emulator,在Emulator中,Settings->System->About emulated device,檢視Build Number,是你Build的日期及user name,也就確認此Emulator是由你自己Build出來的,也確認我們把AOSP滙入再取出後是完整的AOSP Codebase。
- 同步官方AOSP
完成AOSP Mirror轉移匯入本地Gerrit Server的工作後,不要就把Gerrit Client中的aosp_mirror幹掉!因為將來和官方AOSP的同步還要靠它!例如AOSP又出了一個Android Q/R...,或是用到不同平台裝置,例如IoT/Car,的Branch。這時如果你必須同步這些Code,就在aosp_mirror下,執行repo sync,把原始碼同步後,再匯入你的gerrit server。先回到Gerrit Client的aosp_mirror目錄,同步官方的AOSP方式:
建立自有分枝Branch
一般而言,在AOSP上工作的研發人員不會在Master branch上修改Code。因為此時的Code未必穩定,而且可能Build不出來,也可能Build出來了,但常發生Crash。Master branch是最經常改Code的地方,如果在這個分枝工作,勢必常常面臨Merge Code的工作。所以一般來說我們會在相對穩定的Branch/Tag上,建立自有的分枝後,在自有分枝上工作。這也是我們需要一個自有Gerrit Server並把AOSP完整移轉過來的最初原因。
如何建立分枝,可以看PART3,建立AOSP分枝並建立在Gerrit Server。
雖然本文是要「完整的」移轉匯入AOSP,但事實上我們現在做完的移轉是不完整,而且很多Projects其實根本還沒匯入。為什麼?主要是因為AOSP Master branch並不是包含所有Projects,而是目前最新的Android版本中的Projects。例如,AOSP Master branch在本文發表時,是Android Q,而上個版本Android P中有個Project名稱為framework/data-binding,但在Android Q因架構改變,不再納入此Project。所以我們的Gerrit server沒有這個Project。那麼如果我要在Pixel 2上的Android P上修改Code,並且把這個修改納入Gerrit review,成為自己的ROM,及內部知識保留 (這也是本文一開始說的目的!)但我的Gerrit server沒有framework/data-binding這個Projects,怎麼辦?那這就是PART3要討論的部份了!
感谢,非常棒。
回覆刪除在執行
回覆刪除repo forall -c 'echo $REPO_PROJECT; ssh -p 29418 jeremychen@10.50.100.56 gerrit create-project --owner android-admin $REPO_PROJECT;'
這個指令的時候,會一直出現
Permission denied (publickey).
請問怎麼解決?
Part 1 的"加入SSH Key" 部分看一下
回覆刪除