Ubantu18.04环境下编译android源码
最近在看金泰延老师写的《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 "aaa@qq.com"
然后由于我们是通过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
上一篇: 事件分发全面认识