最近在看金泰延老師寫的《Android 框架揭祕》一書,第一章就是下載並編譯android源碼,書中內容較爲陳舊,所以不得不到網上收羅各種資料,最後總算是大功告成,現在總結如下。
1、安裝git和repo並配置
安裝git通過下面命令實現
sudo apt-get install git
另外還需要配置好git的user.email和user.name,這個自己隨便寫就行了
git config --global user.name "your name"
git config --global user.email "[email protected]"
然後由於我們是通過repo來拉取android源碼的,git配置好後,還得安裝配置repo
git clone https://aosp.tuna.tsinghua.edu.cn/git-repo/
chmod a+x git-repo/repo
然後添加repo(路徑目錄如:~/git-repo/repo)到PATH環境變量
export PATH=~/git-repo:$PATH
然後到打開~/git-repo/repo文件,將REPO_URL替換爲清華鏡像地址,以避免下載android源碼時可能出現的無法連接到 gerrit.googlesource.com問題。
REPO_URL = 'https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
2、下載andriod源碼
首先創建一個自己存放源碼的目錄,我是放在~/Android/source路徑下的,然後cd到對應的路徑下執行下面命令
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest
然後執行如下命令可以查看可以下載的android源碼分支,目前我看到的已經可以獲取android-9.x的分支了。
cd .repo/manifests.git/
git branch -a
這裏同步android-8.1.0_r41分支並拉取對應分支源碼
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-8.1.0_r41
repo sync
這個過程時間較長,可能需要幾個小時,期間該幹嘛幹嘛。
3、Ubuntu 18.04編譯環境配置
首先得配置java8
sudo apt-get install openjdk-8-jdk
sudo apt-get install openjdk-8-jre
注意這裏是配置openjdk,不要弄錯了,我之前是按照一篇教程配置了android studio環境,結果配置的jdk不是openjdk,執行java -version時有如下提示
實際上在執行java -version有如下的openjdk提示時(版本號不一定相同),纔算是jdk配置成功
然後配置在ubantu 18.04中編譯android源碼需要的一些依賴,這些依賴包在ubantu 16.04中編譯android源碼時也是需要的
sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib
sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386
sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386
sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
sudo apt-get install git-core gnupg flex bison gperf build-essential
sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib
sudo apt-get install libc6-dev-i386
sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev
sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
sudo apt-get install lib32z-dev ccache
到這裏編譯環境配置就算是完成了。
4、編譯Android源碼
這裏到了最關鍵也是最容易出問題的一步了,首先cd到應的源碼目路,初始化編譯環境
. build/envsetup.sh
初始化編譯環境後,引入了一些執行腳本,其中就包括馬上要使用的lunch指令。通過lunch指令可以設置編譯目標,所謂的編譯目標就是生成的鏡像要運行在什麼樣的設備上。這裏我們設置的編譯目標是aosp_arm64-eng,因此執行指令
lunch aosp_arm64-eng
簡單的說明下,aosp表示Android Open Source Project,arm64表示是使用arm64 cpu的設備,eng表示engineer版本,其直接開放了一些root等權限。當然直接使用lunch命令會列出所有可選的編譯目標。
最後,我們便可通過如下命令來開始編譯andriod源碼
make -j8
這裏的j8表示可以開啓8個線程來參與編譯源碼,這裏指定的線程數一般應該遵從cpu內核數的2倍這個規律,可以通過cat /proc/cpuinfo查看相關cpu信息。
5、編譯錯誤集錦
如果以爲第四小節的三步走戰略就可以直接編譯出可用的Android image來那就too young啦,實際上在編譯過程中,我遇到很多故障,同時由於編譯過程需要話費很多時間,所以整個編譯花費了我大把時間,這個童鞋們一定要作好心理準備。下面是我在編譯過程遇到的問題以及解決辦法總結
故障1:You are attemping to build with the incorrect version
這個就是在編譯高版本android源碼時,可能出現的jdk版本問題,我之前是使用上面命令介紹的方式配置了openjdk卻在java -version發現還是不是open jdk版本,究其原因竟是我在更之前配置android studio時在/etc/profile 中配置了另一個jdk版本導致該問題發生,後面在/etc/profile中刪除對應配置就好了。
故障2:Out of memory error
這個問題是因爲編譯過程中JVM heap size太小而導致的,解決辦法比較簡單
export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4096m"
~/Android/source/prebuilts/sdk/tools/jack-admin kill-server
~/Android/source/prebuilts/sdk/tools/jack-admin start-server
通過這個配置可以講JVM heap size調整爲4g,這個應該是夠用的,這裏我們看到了jack-admin工具,後面可能還會使用這個工具,所以這裏直接建議配置jack-admin的環境變量
export PATH=$PATH:~/Android/source/prebuilts/sdk/tools
之後就可以直接使用如下命令來啓動jack-admin了
jack-admin start-server
故障3:sizeof (_nl_value_type_LC_TIME[0]))’ ???
這裏圖片我是從其它博客哪裏拷過來的,但是的確碰到這個故障,通過下面配置去除本地化配置解決
export LC_ALL=C
故障4:No Jack server running. Try ‘jack-admin start-server’
這個錯誤碰到的還不止一次,看到這個提示我們都知道是jack-admin沒有啓動的原因,重啓便可
jack-admin kill-server
jack-admin start-server
比較奇怪的是,有時自己明明開啓了jack-admin,但是在編譯的過程中,jack-admin卻掛掉了,這個得多注意。
我在編譯過程中主要是遇到了以上幾個故障,實際上其它博客上還有一些其它故障可以參考的,也只能在遇到具體故障的時候再百度google了,總之是編譯android源碼需要一定的耐心。
6、運行模擬器
在完成編譯後,我們可以直接通過emulator命令來運行模擬器
emulator
運行模擬器實際上需要四個組件
1、Linux Kernel
2、system.img
3、userdata.img
4、ramdisk.img
如果你在使用lunch命令時選擇的是aosp_arm-eng,那麼在執行不帶參數的emualtor命令時,Linux Kernel默認使用的是/source/prebuilds/qemu-kernel/arm/kernel-qemu目錄下的kernel-qemu文件。而android鏡像文件則是默認使用source/out/target/product/generic目錄下的system.img、userdata.img和ramdisk.img,也就是我們剛剛編譯出來的鏡像文件。
上面我在使用lunch命令時選擇的是aosp_arm64-eng,因此linux默認使用的/source/prebuilds/qemu-kernel/arm64/kernel-qemu下的kernel-qemu,而其他文件則是使用的source/out/target/product/generic64目錄下的system.img、userdata.img和ramdisk.img。
在使用emulator命令後,正常的話,我們可以啓動模擬器,我這裏啓動的模擬器信息如下
這裏可以看出啓動的是我們編譯時指定的aosp_arm64-eng模擬器,實際上emulator還有很多其它指令可以選擇,這個可以通過它的help命令來查看
emulator -help
7、單獨編譯模塊及SDK
除了通過make命令編譯可以整個android源碼外,Google也爲我們提供了相應的命令來支持單獨模塊的編譯。
編譯環境初始化(即執行. build/envsetup.sh)之後,我們可以得到一些有用的指令,除了上邊用到的lunch,在envsetup.sh文件中我們還可以找到如下的指令
其中的mmm指令就可以用來編譯指定模塊,
mmm packages/apps/StorageManager/
稍等一會之後,如果提示編譯完成,此時便可在out/target/product/gereric_arm64/system/priv-app就可以找到編譯的StorageManager.apk文件了。
編譯好指定模塊後,如果我們想要將該模塊對應的apk集成到系統鏡像中,需要藉助make snod指令重新打包系統鏡像,這樣我們新生成的system.img中就包含了剛纔編譯的Launcher2模塊了,重啓模擬器之後生效。
我們在不斷的修改某些模塊,總不能每次編譯完成後都要重新打包system.img,然後重啓手機吧?有沒有什麼簡單的方法呢?
在編譯完後,藉助adb install命令直接將生成的apk文件安裝到設備上即可,相比使用make snod,會節省很多時間。
直接執行make是不包括make sdk的,如果要編譯自己的sdk則十分簡單,只需要執行如下命令便可
. build/envsetup.sh
lunch sdk-eng
make sdk
如果編譯成功,不出意外,在out/host/linux-x86/sdk就可以看到了。
補充
我們簡單的來介紹out/target/product/generic_arm64/system目錄下的常用目錄:
Android系統自帶的apk文件都在out/target/product/generic_arm64/system/priv-app目錄下
一些可執行文件(比如C編譯的執行),放在out/target/product/generic_arm64/system/bin目錄下
動態鏈接庫放在out/target/product/generic_arm64/system/lib目錄下
硬件抽象層文件都放在out/targer/product/generic_arm64/system/lib/hw目錄下
這裏需要注意的就是由於我們這裏編譯的是aosp_arm64-eng編譯目標,所以這裏的路徑中是generic_arm64,如果是編譯的其它目標路徑可能不一樣,比如當編譯的是aosp_arm-eng時,則路徑中就是generic。
到這裏Ubantu18.04環境下編譯android源碼基本介紹就算完成了。
參考文獻
1、自己動手編譯Android 8.0源碼
2、Ubuntu 18.04編譯Android8.1 automotive
3、自己動手編譯最新Android源碼及SDK(Ubuntu)
4、Linux Out of memory error
5、 Android 編譯命令
6、通過清華大學鏡像下載Android源碼並編譯源碼
7、Ubuntu環境中的Android源代碼下載
8、ERROR: No Jack server running