Android高版本P/Q/R源碼編譯指南
Android源碼編譯系列博客:linux
Android.bp你真的瞭解嗎
Android.bp入門指南之Android.mk轉換成Android.bp
Android.bp入門指南之淺析Android.bp語法
Android.bp正確姿式添加宏控制編譯指南
Android高版本P/Q/R源碼編譯指南android
引言
時代在進步,第三套少兒廣播體操!很差意思,搞錯頻道了,重來!時代在進步,Android的版本也是快速的進行着迭代着,從咱們之前最多見的Android 4.4一直髮展到了今天的Android 11版本(即Android K到Android R),Android版本的快速迭代對於消費者來講是一件普天同慶的大好事情,可是對於咱們開發者來講各類適配各類改造有時候吃翔的心情都有了。而對於Android版本的適配和各類改造的第一步就是從編譯Android源碼開始,但是不幸的是隨着Android版本的迭代連編譯Android源碼的相關流程都發生了翻天覆地的變化,正所謂工欲利其事必先利器,因此咱們今天的這篇博客將帶領讀者一塊兒來捯飭捯飭Android各個版本的源碼編譯發展和編譯具體操做步驟!web
這裏咱們須要注意一下Android各個版本的對應關係以下:json
- Android 5.x (Lollipop)簡稱Android L版本
- Android 6.0 (MarshMallow) 簡稱Android M版本
- Android 7.x (Nougat)簡稱Android N版本
- Android 8.x (Oreo)簡稱Android O版本
- Android 9.0 (Pie)簡稱Android P版本
- Android 10.0 (Q)簡稱Android Q版本
- Android 11.0 (R)簡稱Android R版本
而且這裏還有一點須要特別注意,本文演示的Android R版本是以高通平臺爲基準進行的。windows
一.Android編譯環境的構建以及常見命令
俗話說天時地利人和缺一不可,而這其中的地利翻譯過來講的就是環境因素了,人的成長離不開環境因素,而咱們的Android編譯也離不開編譯環境的構建!雖然咱們本篇博客的主題是Android源碼編譯指南,可是咱們仍是有必要抽出一個章節來簡單說明下Android編譯環境的構建和初始化過程,以及初始化完畢後常見的命令。api
1.1 Android編譯環境的構建
本章節重點偏向的是Android編譯環境的構建,而不是編譯環境構建的原理分析(若是是原理分析,那內容就多了)。bash
雖然Android的版本一直在迭代着,可是Android編譯環境的構建步驟仍是比較良心的依然沒有多大的變化(注意這裏的措辭,只是步驟),對於有過Android源碼開發經驗的讀者來講是再爲熟悉不過的了,一般是以下二部曲:app
$ source build/envsetup.sh
$ lunch aosp-eng
雖然各位對上述的命令應該已經爛熟於心了,可是這裏我仍是簡單說明一下:框架
-
第一行命令」source build/envsetup.sh」引入了build/envsetup.sh 腳本。該腳本的做用是初始化編譯環境,並引入一些輔助的Shell函數,這其中就包括第二步使用 lunch 函數ide
-
第二行命令」lunch aosp-eng」是調用 lunch 函數,並指定參數爲」aosp-eng」。lunch 函數的參數用來指定這次編譯的目標設備以及編譯類型。在這裏,這兩個值分別是」aosp」和」eng」。」aosp」是 Android 源碼中已經定義好的一種產品,是爲模擬器而設置的。而編譯類型會影響最終系統中包含的模塊。若是在調用lunch函數的時候沒有指定參數,那麼該函數將輸出列表以供選擇,列表內容不一樣Android版本,不一樣廠家的基線源碼會有所不一樣,以下:
這裏補充一點對Android的源碼編譯類型簡單說明一下,它能夠分爲以下三種功能,每種類型的特色以下:
1.2 Android編譯各類常見命令
在編譯環境初始化完成後,咱們就可使用各類各類編譯環境提供的指令和make編譯命令族來開啓Android的構建之旅了,這裏我簡單的總結了下,咱們在Android編譯中可能會用到的編譯環境提供的指令和make編譯命令族,以下:
1.2.1 常見的Android命令指令
指令 | 說明 |
---|---|
croot | 切到Android源碼樹的根目錄(當你深刻Android源碼樹的子目錄,想回到根目錄的時候此命令就很是實用了) |
m | 至關於在源碼樹的根目錄執行make,而且該命令不必定要在根目錄下執行 |
mm | 編譯當前目錄路徑下的全部模塊(包括include進來的,可是不包括存在依賴關係模塊) |
mma | 編譯當前目錄路徑下的全部模塊(包括include進來的,且包括存在依賴關係模塊) |
mmm[module_path] | 編譯指定目錄路徑下的全部模塊(包括include進來的,可是不包括存在存在依賴關係模塊) |
mmma[module_path] | 編譯指定目錄路徑下的全部模塊(包括include進來的,包括存在存在依賴關係模塊) |
cgrep | 對C/C++文件執行grep(即grep的時候只搜尋C/C++文件類型,注意這裏也包括.h文件類型) |
jgrep | 對Java文件執行grep(即grep的時候只搜尋Java文件類型) |
resgrep | 在全部res/.xml文件上執行 grep即grep的時候只搜尋res/.xml文件類型) |
printconfig | 顯示當前Android編譯的相關配置信息 |
add_lunch_combo | 在lunch命令的的菜單中添加一個條目 |
這裏咱們對上述表格中的不包括存在依賴關係模塊::
1.依賴關係模塊這個要怎麼說呢,這裏咱們舉個栗子!譬如模塊A的編譯須要依賴模塊B,此時的B是一個so庫。
2.假如咱們經過mm或者mmm編譯模塊A的時候,此時B模塊尚未編譯那麼此時就會報錯
3.假如咱們使用的是mma或者mmma編譯模塊A,假如依賴的模塊B尚未編譯,那麼會先將模塊B編譯OK,而後編譯模塊A(固然這裏只是舉栗子,可能A還依賴C,D同理也會先編譯)
1.2.2 make編譯命令族
Android的Build編譯系統處理常見的make單命令以外,還提供了其它的一系列make命令族,這裏咱們簡單過下:
指令 | 說明 |
---|---|
make update-api | 更新API文件,在framework API改動以後,須要首先執行該命令來更新API,公開的API記錄在frameworks/base/api目錄下 |
make | Android默認系統編譯指令,會編譯出整個系統的全部鏡像(其實質最終執行的是make droid) |
make droid | 同上 |
make sdk | 編譯出Android的SDK開發套件 |
make clean-sdk | 清理SDK的編譯產物 |
make dist | 執行整個編譯,並將 MAKECMDGOALS變量定義的輸出文件拷貝到 /out/dist目錄下, 這個命令在實際中用的比較少 |
make all | 編譯全部內容,無論當前產品的定義中是否會包含,官方解釋以下: builds everything make droid does,plus everything whose LOCAL_MODULE_TAGS do not include the 「droid」 tag. The build server runs this to make sure that everything that is in the tree and has an Android.mk builds. |
make help | 幫助信息命令,顯示當前Android版本主要支持的make命令 |
make snod | 從已經編譯出的包快速構建系統鏡像(譬如你從新單獨編譯了某個模塊,而後想快速進行打包到system.img,可使用此命令加快速度) |
make clean-$(LOCAL_MODULE) | Let you selectively clean one target. For example, you can type make clean-libutils and t will delete libutils.so and all of the intermediate files. 即清理掉一個指定模塊的編譯結果和中間產物 |
make clean-$(LOCAL_PACKAGE_NAME) | Let you selectively clean one target. For example, you can type make clean-Home and it will clean just the Home app… 即清理掉一個指定模塊的編譯結果和中間產物 |
make clean | deletes all of the output and intermediate files for this configuration. This is the same as rm -rf out/<configuration>/ 一般刪除的是整個Android源碼工程的out/*目錄 |
make clobber | deletes all of the output and intermediate files for all configurations. This is the same as rm -rf out/. 這個命令在實際中,應用得比較少 |
make dataclean | deletes contents of the data directory inside the current combo directory. This is especially useful on the simulator and emulator, where the persistent data remains present between builds. 這個命令在實際中應用得也比價少 |
make installclean | 當咱們在執行切換編譯目標時能夠執行make installclean,用以清除以前編譯生成的文件,可是又不會將整個out目錄清空,這樣能夠加快編譯目標的構建速度 |
make LOCAL_MODULE | 編譯一個指定的模塊,LOCAL_MODULE 爲模塊的名稱,這種編譯方法一般運用在整個Android工程沒有構建,可是想快速編譯一個模塊時可使用,能夠加快單個模塊構建速度 |
make targets | will print a list of all of the LOCAL_MODULE names you can make. |
make libandroid_runtime | 編譯全部JNI framework內容。 |
make framework | 編譯全部Javaframework內容(作Android framework開發的小夥們對這條命令應該是再熟悉不過的了)。 |
make services | 編譯系統服務和相關內容 |
make bootimage | 編譯生成boot.img |
make recoveryimage | 編譯生成recovey.img |
make cacheimage | 編譯生成cache.img |
make systemimage | 編譯生成system.img |
make vendorimage | 編譯生成vendor.img |
make superimage | 編譯生成superi.img |
對上述的make命令有幾點須要注意:
1.可能在不一樣的Android版本有不一樣表現,且有的可能已經不支持了
2.讀者最好對於每一個make編譯命令,自行使用一番,而後慢慢品嚐
二.Android編譯的發展史簡介
有過必定Android開發經驗的讀者應該知道Android最初是用Android.mk配置來編譯源碼的(這裏的Android.mk本質上有點相似Makefile文件)。可是隨着Android版本的迭代,源碼工程文件愈來愈大,包含的模塊愈來愈多,而以Android.mk組織的項目編譯花費的時間愈來愈多。面對這個嚴峻的問題,Android的媽咪谷歌終於在在Android7.0開始引入了ninja編譯系統。相對於make來講ninja在大的項目管理中速度和並行方面有突出的優點,所以Google採用了ninja來取代以前使用的make。因爲Android.mk的數量巨大且複雜,不可能把全部的Android.mk改寫成ninja的構建規則,所以Google搞了個kati工具,用於將Androd.mk轉換成ninja的構建規則文件build.ninja,再使用ninja來進行構建工做。
Android編譯的發展依然沒有中止進化,果不其然Android8.0開始,Google引入了Android.bp文件來替代以前的Android.mk文件,Android.bp只是純粹的配置文件,不包括分支、循環等流程控制,本質上就是一個json配置文件。同時還引入Soong這個工具,用於將Android.bp轉換爲ninja的構建規則文件build.ninja,再使用ninja來進行構建工做。但以前的模塊所有是用Android.mk來定義的,google不可能一會兒把全部模塊都修改爲Android.bp,只能逐步替換。不管是Android.mk仍是Android.bp最後都是轉化成ninja的構建規則,再進行編譯的。
若是你對上述的概述,仍是以爲太麻煩了,這裏咱們總體來歸納一下Android build系統隨着Android版本相應的發展演變過程:
- Android 7.0引入ninja和kati
- Android 8.0使用Android.bp來替換Android.mk,引入Soong
- Android 9.0強制使用Android.bp
2.1 Soong、Blueprint、Kati、Ninja關係
前面一頓咔咔,咱們簡單介紹了Android編譯系統的範展現,其中忽然一會兒冒出了許多的概念,這裏咱們先暫且不對其中涉及的概念講述,咱們先說說Soong、Blueprint、Kati、Ninja之間的關係,以下:
上圖是總體的關係圖,同時在Android源碼工程構建過程當中的轉換關係以下:
若是對上述的關係仍是沒有捯飭清楚的,咱們再來講說,說說:
- 首先經過Kati將Android.mk轉換成ninja格式的文件
- 經過androidmk將將Android.mk轉換成Android.bp,可是隻針對沒有分支、循環等流程控制的Android.mk纔有效,若是對於有控制流的就必須手動了具體能夠想見博客Android.bp正確姿式添加宏控制編譯指南
- 經過Blueprint+ Soong將Android.bp轉換成ninja格式的文件
不容易啊,這裏咱們對涉及到Ninja, kati, Soong, bp關係搞清楚了(各類三角戀)!那麼關於它們的概念,接下來咱們也得簡單介紹介紹,安排上才行!
2.2 Kati簡介
Kati是專爲Android開發的一個基於Golang和C++的工具,主要功能是把Android中的Android.mk文件轉換成 Ninja文件。代碼路徑是build/kati,編譯後的產物是ckati。
Kati代碼是開源的,能夠把它clone下來,若是感興趣能夠查看下其實現原理
這裏咱們構建一個經過Android.mk配置的LOCAL_MODULE模塊,而後經過top命令就能夠查看在編譯的過程當中執行了ckati的命令。
2.3 Ninja簡介
ninja是一個編譯框架,會根據相應的ninja格式的配置文件進行編譯,可是ninja文件通常不會手動修改,而是經過將Android.bp文件轉換成ninja格文件來編譯。
2.4 Android.bp簡介
Android.bp的出現就是爲了替換Android.mk文件。而bp跟mk文件不一樣,它是純粹的配置,沒有分支、循環等流程控制,不能作算數邏輯運算。若是須要控制邏輯,那麼只能經過Go語言編寫。Android的媽咪谷歌爲了讓開發者能更加的快速掌握Android.bp特地提供了androidmk命令(關於它的詳細介紹能夠參見博客Android.bp入門指南之Android.mk轉換成Android.bp,這裏就不過多的戲說了)用於Android.mk轉換成Android.bp使用,以下轉換命令:
$ androidmk Android.mk > Android.bp
2.5 Blueprint和Soong構建編譯系統
2,5.1 Soong簡介
Soong相似於以前的Makefile編譯系統的核心,負責提供Android.bp語義解析,並將之轉換成Ninja文件。Soong還會編譯生成一個androidmk命令,用於將Android.mk文件轉換爲Android.bp文件,不過這個轉換功能僅限於沒有分支、循環等流程控制的Android.mk纔有效。
2.5.2 Blueprint簡介
Blueprint是生成、解析Android.bp的工具,是Soong的一部分。Soong負責Android編譯而設計的工具,而Blueprint只是解析文件格式,Soong解析內容的具體含義。Blueprint和Soong都是由Golang寫的項目,從Android 7.0,prebuilts/go/目錄下新增Golang所需的運行環境,在編譯時使用。而且由於Soong和Blueprint是Google谷歌爲Android.bp特別定製的工具,因此不須要要摘出來單獨來操做。
三.高版本P/Q/R源碼編譯
經過前面的章節咱們瞭解Android編譯環境的基本構建和編譯的發展史,那麼本章節將重點分析Android O以後高階版本的編譯的不一樣之處。而且本文的博客前年也有說到是以高通版本的Android爲基線的。因此在開始本章節的博客前,有兩個知識點須要提早介紹下,一個是Android Q以及以後的動態分區,以及qssi的概念!
3.1 Android動態分區
動態分區是Android的用戶空間分區系統。使用此分區系統,您能夠在無線下載(OTA)更新期間建立、銷燬分區或者調整分區大小。藉助動態分區,供應商無需擔憂各個分區(例如system、vendor和product)的大小。取而代之的是,設備分配一個super分區,其中的子分區可動態地調整大小。單個分區映像再也不須要爲未來的OTA預留空間。相反,super中剩餘的可用空間還可用於全部動態分區(關於動態分區詳見谷歌官方Android實現動態分區)。
3.2 什麼是QSSI
QSSI 是 Qualcomm Single System Image 的縮寫,而且高通平臺從Android Q開始支持。而且其編譯也和Android原生編譯有差異,其差異以下:
3.3 具備QSSI特性Android關鍵的總體編譯流程
經過前面看到QSSI特性的固件編譯流程也和通用版本的有必定的區別,這裏的編譯分爲兩種模式,第一種Android的標準編譯模式,另一種就是高通提供的編譯腳本。
這裏須要注意的的是通用版本的Android仍是能夠直接經過make相關的分區進行直接編譯的,譬如make superimage或者直接執行make編譯
3.3.1 經過Android內置make命令編譯
source build/envsetup.sh
- 編譯 system.img
lunch qssi-userdebug
make target-files-package- 編譯除system.img外的其餘img
lunch xx-userdebug
make target-files-package
3.2.2 高通提供的build.sh腳本進行編譯
- 編譯全部img,包括system和其它img
source build/envsetup.sh
lunch XX-userdebug
./build.sh dist -j32
- 編譯system.img,產物在qssi目錄下
source build/envsetup.sh
lunch xx-userdebug
./build.sh dist qssi_only -j32
- 編譯super.img
source build/envsetup.sh
lunch xx-userdebug
./build.sh dist merge_only -j32
- 編譯其它img,例如vendorimage,若是不指定會編譯其它全部img,產物在XX目錄下
source build/envsetup.sh
lunch xx-userdebug
./build.sh vendorimage dist target_only -j32
3.4 非QSSI特性的總體編譯流程
非QSSI特性的編譯流程,依然和之前的版本Android編譯變化不大,一般是以下的步驟:
source build/envsetup.sh lunch xx-userdebug make
3.5 動態分區刷機的方法
Android Q版本以及以上將system和vendor分區合併爲super分區,沒法經過adb reboot bootloader模式單獨刷動態分區裏面的img,例如system,vendor,product,odm,只能刷super.img和其餘的,可是fastboot模式下能夠單獨刷動態分區裏面的img,其方法以下:
#推薦進入fastboot模式刷機: adb reboot fastboot fastboot getvar is-userspace is-userspace: yes Finished. Total time: 0.002s fastboot flash vendor vendor.img fastboot flash system system.img fastboot flash vbmeta vbmeta.img fastboot flash vbmeta_system vbmeta_system.img #fastbootd是用戶空間的代碼,由於動態的邏輯分區只能在應用空間識別
1.若是是在linux下fastboot刷機出現權限問題,須要將fastboot的全部者屬性改爲root
sudo chown root:root fastboot
sudo chmod +s fastboot
2.若是是在windows環境下使用fastboot,很大機率可能不識別fastboot,此時推薦下載360的手機助手藉助它安裝對應的驅動,這樣就能進行相關的識別了,此處是我的經驗
3.6.Framework編譯
如今Android R之上的Framework的編譯已經和以前有所不一樣,具體參見下面解釋:
- Android R以前單獨編譯framework和service命令爲:
make -j8 framework make -j8 services
- Android R以後的命令爲:
make -j8 framework-minus-apex make -j8 services
四.Android爲啥要引入動態分區
在前面咱們簡單說了下動態分區的概念,即在Android Q以及之後得編譯包中,咱們找不到了對應的system,vendor等img文件,可是多了一個super.img,system,vendor,product,ODM合併爲super分區,這個就是動態分區了。簡單來講就是爲了在ota的時候可以靈活建立分區和修改分區大小,將system,vendor,odm,product合併成super分區,並在super分區上預留出必定量的free space,這樣就能夠動態調整這些分區的大小,解決了ota的時候分區不足,以及調整分區的風險.。
當OTA升級以後,須要從新調整分區大小:
寫在最後
好了今天的博客Android高版本P/Q/R源碼編譯指南就到這裏了,因爲這是一篇實戰類型的博客因此也沒有多少總結的了,跟着幹就好了。總之,青山不改綠水長流先到這裏了。若是本博客對你有所幫助,麻煩關注或者點個贊,若是以爲很爛也能夠踩一腳!謝謝各位了!!好了,青山不改綠水長流,各位江湖見!固然各位讀者的點贊和關注是我寫做路上前進的最大動力了,若是有啥不對或者不爽的也能夠踩一踩也無妨!
最後附上參考文檔路徑AndroidP/Q/R編譯系統,這裏我對作了簡化,而且加上了本身實際開發中的一些理解,主要是爲了方便你們快速入手Android高版本編譯。
本文同步分享在 博客「IT先森」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。