http://zke1ev3n.me/2016/08/25/Ubuntu16-04%E7%BC%96%E8%AF%91android6-0%E6%BA%90%E4%BB%A3%E7%A0%81/
因为最近经常编译android,每次都要去网上搜索教程,这里把自己编译的步骤记录下来,方便以后查询。
安装好了后配置下用户名和邮箱地址。
1 2 3 |
$ sudo apt-get install git $ git config --global user.name "Your Name" $ git config --global user.email "[email protected]" |
1
|
$ sudo apt-get install curl
|
repo是google为方便管理android源码编写的一系列python脚本。
1 2 |
$ mkdir ~/bin $ PATH=~/bin:$PATH |
1 2 |
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo $ chmod a+x ~/bin/repo |
创建源码目录:
1 2 |
$ mkdir android-6.0.1_r46 cd android-6.0.1_r46 |
使用repo init指定要同步的代码版本。你可以在这里找到目前所有android源码的版本:
https://source.android.com/source/build-numbers.html
1
|
$ repo init -u https://android.googlesource.com/platform/manifest -b android-6.0.1_r1
|
这里使用google的镜像服务器上同步代码,如果你没有工具或者下载很慢的话可以使用国内的源,比如清华的,像下面这样修改~/bin/repo中的REPO_URL。
1
|
REPO_URL = 'https://gerrit-google.tuna.tsinghua.edu.cn/git-repo'
|
然后同样使用repo init来执行同步的版本。
1
|
$ repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-6.0.1_r46
|
然后使用下面的命令下载源码。因为源码比较大,所以下载时间会很长,android6.0.1的代码大概有46G左右。repo支持断线重连,所以直接挂在哪里就可以了。
1
|
$ repo sync
|
android源码编译有一些环境要求,具体可以查看下面的网址:
https://source.android.com/source/requirements.html
我们这里编译的是android6.0.1,需要先安装openjdk。
1 2 3 |
$ sudo add-apt-repository ppa:openjdk-r/ppa $ sudo apt-get update $ sudo apt-get install openjdk-7-jdk |
但是在日常使用中,我们更经常使用oracle-jdk,所以如果电脑上安装了其他版本的jdk的话,可以使用下面的命令来切换当前使用的jdk版本。
1 2 |
$ sudo update-alternatives --config java $ sudo update-alternatives --config javac |
不同的系统版本需要的依赖可以在这里找到:
https://source.android.com/source/initializing.html
但是这个网址上只有14.04需要的依赖,经过实验发现在16.04上不成功。下面是我在网上找到的16.04所需的依赖:
1 2 3 4 5 6 7 8 9 10 |
$ sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386 $ sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib $ 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 lib32z-dev ccache $ sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4 |
我在编译源码的过程中,编译到libartd.so时出现了如下错误:
1
|
clang: error: linker command failed with exit code
|
后来经过搜索,发现修改art/build/Android.common_build.mk文件中的:
1
|
ifneq ($(WITHOUT_HOST_CLANG),true)
|
为
1
|
ifeq ($(WITHOUT_HOST_CLANG),false)
|
然后重新编译即可。
为了提高编译效率,设置编译器高速缓存。
1 2 |
$ echo export USE_CCACHE=1 >> ~/.bashrc $ prebuilts/misc/linux-x86/ccache/ccache -M 50G |
导入编译Android源码需要的环境变量和其他参数:
1
|
$ source build/envsetup.sh
|
使用lunch命令选择需要编译的目标:
1
|
$ lunch
|
我这里选择的是1。然后使用make命令开始编译。可以使用make -j 来设置参与编译的线程数量,一般来说设置为cpu核心数的两倍。可以使用如下命令查看当前电脑的cpu核心数量:
1
|
$ cat /proc/cpuinfo
|
大概几个小时后,就可以编译成功了。使用emulator命令就可以启动编译好的模拟器。
1
|
$ emulator
|
如图:
因为我们导入的环境变量在关闭shell后就失效了,所以我们不能直接用emulator命令来启动模拟器。每次启动模拟器前要先导入环境变量。
1 2 3 |
$ source build/envsetup $ lunch #这里选择编译时选择的版本 $ emulator |
运行android模拟器时,
emulator -avd test -no-skin -no-audio -no-window
‘-no-skin’表示移除模拟按钮
‘-no-audio’ 表示禁用音频
‘-no-window’ 表示禁用图形窗口
除了通过make命令编译可以整个android源码外,Google也为我们提供了相应的命令来支持单独模块的编译.
编译环境初始化(即执行source build/envsetup.sh)之后,我们可以得到一些有用的指令,除了上边用到的lunch,还有以下:
其中mmm指令就是用来编译指定目录.通常来说,每个目录只包含一个模块.比如这里我们要编译Launcher2模块,执行指令:
1
|
mmm packages/apps/Launcher2/
|
稍等一会之后,如果提示:
1
|
### make completed success fully ###
|
即表示编译完成,此时在out/target/product/gereric/system/app就可以看到编译的Launcher2.apk文件了.
编译好指定模块后,如果我们想要将该模块对应的apk集成到系统镜像中,需要借助make snod指令重新打包系统镜像,这样我们新生成的system.img中就包含了刚才编译的Launcher2模块了.重启模拟器之后生效.
一些模块位置:
有时候我们需要自己编译一个sdk,比如有时候需要使用系统隐藏的api,可以将源代码目录中隐藏api的@hide注解去掉,然后使用下面的命令编译。
1
|
make sdk
|
更多的时候我们需要的不是使用模拟器,而是使用真机调试。这个时候我们可以在lunch命令中选择适用于Nexus设备的镜像。比如我这里选择的是使用于nexus5的aosp-hammerhead-userdebug, 这样直接编译出来的镜像刷入手机是无法成功使用的,因为没有驱动。所以我们需要到官网上下载对应的驱动。你可以在这里选择对应源码镜像版本的驱动:
https://developers.google.com/android/nexus/drivers
下载3个压缩包拷贝到源码目录,然后分别解压获得3个sh脚本,分别运行这3个脚本文件,在源码目录会出现一个vendor的文件夹,里面就包含了nexus5的驱动文件。
重新编译源码,如果你之前已经编译过一次,那么这次会很快完成。编译完成后,我们就可以刷入设备了。首先手机进入fastboot模式,可以使用音量上下键+电源键或者在连接到adb时使用”adb reboot bootloader”进入。然后电脑端进入到/out/host/linux-x86/bin目录,运行
1
|
$ ./fastboot -w flashall
|
就可以刷入了。刷入完成后手机会自动重启。这里的命令表示清空用户数据然后全部刷入,当然也可以只刷入一部分。
android的源码目录下没有内核代码,需要自己手动下载。下载很简单,使用git clone即可。
在这里可以找到对应机型的内核版本:
https://source.android.com/source/building-kernels.html
这里可以找到更详细的信息:
https://android.googlesource.com/kernel/
比如我要编译的是nexus5的内核镜像。通过第一个网址我们可以知道它对应的内核版本为’kernel/msm’。在源码目录新建kernel目录,然后git clone。
1 2 |
$ mkdir kernel $ git clone https://android.googlesource.com/kernel/msm.git #这一步需要代理 |
内核源代码大小大概有1个多G。clone完后进入msm目录,可以发现里面什么都没有,因为我们还没有选择分支。使用
1
|
$ git branch -a
|
来查看所有分支。如下图:
这里因为我们编译nexus5 6.0.1的内核,所以使用如下命令:
1
|
git checkout -b android-msm-hammerhead-3.4-marshmallow-mr2 remotes/origin/android-msm-hammerhead-3.4-marshmallow-mr2
|
然后配置一些环境变量:
1 2 3 4 |
$ export ARCH=arm $ export SUBARCH=arm $ export CROSS_COMPILE=arm-eabi- $ make hammerhead_defconfig |
然后使用
1
|
$ make
|
编译。编译成功后会在arch/arm/boot目录下生成一个zImage文件。将这个文件替换掉device/lge/hammerhead-kernel中的zImage。或者导出环境变量
1
|
$ export TARGET_PREBUILT_KERNEL="zImage文件路径"
|
然后使用
1
|
$make bootimage
|
重新编译boot.img。再刷入手机就可以了。