Android系统源码编译

6,220 阅读3分钟

前言

AOSP包含了Android系统的整个源码,要想系统的了解Android系统就必须熟悉AOSP。比如Android系统的启动流程,Binder机制,Handler机制等,而熟悉这些知识都需要深入到AOSP中,今天就从AOSP的编译开始,一步步的深入了解。

环境要求

参数
系统Ubuntu16.04
硬盘250G(越多越好)
内存16G(越大越好)
cpu核数8核
编译的Android版本6.0
java版本openjdk7

安装Jdk

如果使用的OpenJDK7,由于Ubuntu 16.04没有OpenJDK7的源,因此要先添加源,然后在安装OpenJDK7,按下面的命令操作即可:

sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-7-jdk

注意如果编译的是Android6.0只能使用openjdk7,具体的版本可以参考这里

安装依赖

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

下载源码

Android的源码是使用我们熟悉的Git和Repo两种代码管理工具共同管理的,Git不用介绍了,大家都很熟悉,说说Repo,它是用python开发的一个整合Git仓库的工具,在管理Android源码时,使用Repo往往会简化我们代码管理的工作。

下载repo工具

  • Google源(需要能科学上网)
mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

如果不能翻墙的同学可以使用清华大学的镜像

  • 清华源
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/bin/repo
chmod +x ~/bin/repo

有时候repo也需要更新,为了使用清华源更新需要将源地址配置到环境变量中。

export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'

将上面的内容配置到~/.bashrc文件中,source ~/.bashrc 环境变量就生效了。

初始化仓库

mkdir ~/aosp
cd aosp
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-6.0.1_r79

如果想初始化某个特定的android版本可以参考这个列表, 但是要注意jdk的版本,要不一会可能编不过。

同步代码

repo sync

这个时候,代码就开始下载了,一般情况下需要几个小时,如果中间出错重复上面的命令就可以了。

编译源码

设置环境

source build/envsetup.sh

envsetup.sh 脚本中导入了一些很有用的命令,我们可以通过下面的命令查看envsetup中提供的全部命令工具

hmm
- lunch:   lunch <product_name>-<build_variant>
- tapas:   tapas [<App1> <App2> ...] [arm|x86|mips|armv5|arm64|x86_64|mips64] [eng|userdebug|user]
- croot:   Changes directory to the top of the tree.
- m:       Makes from the top of the tree.
- mm:      Builds all of the modules in the current directory, but not their dependencies.
- mmm:     Builds all of the modules in the supplied directories, but not their dependencies.
           To limit the modules being built use the syntax: mmm dir/:target1,target2.
- mma:     Builds all of the modules in the current directory, and their dependencies.
- mmma:    Builds all of the modules in the supplied directories, and their dependencies.
- cgrep:   Greps on all local C/C++ files.
- ggrep:   Greps on all local Gradle files.
- jgrep:   Greps on all local Java files.
- resgrep: Greps on all local res/*.xml files.
- mangrep: Greps on all local AndroidManifest.xml files.
- sepgrep: Greps on all local sepolicy files.
- sgrep:   Greps on all local source files.
- godir:   Go to the directory containing a file.

下面简单的介绍一下这几个命令:

  • lunch

    选择编译的类型,直接执行lunch命令,就会列出要编译的类型。编译类型分为下面的类型

编译类型使用情况
user权限受限,不能调试,没有root;适用于生产环境
userdebug与“user”类似,但具有 root 权限和调试功能;是进行调试时的首选编译类型
eng具有额外调试工具的开发配置
  • m

    同make, 编译所有的模块

  • mm

    编译单独的模块,需要切换到模块所在的目录

  • mmm

    编译单独的模块,不需要切换到模块所在的目录

  • croot

    回到源码的根目录

开始编译

make -j 8

-j 参数可以设置并发任务的数量,这个值一般和系统的核心数有关

经过两个多小时的编译,就可以看到编译成功的提示了。

查看生产的镜像文件:

cfp@cfp:~/aosp/out/target/product/generic$ ls -l *.img
-rw-r--r-- 1 cfp cfp   69206016 Oct  1 16:50 cache.img
-rw-rw-r-- 1 cfp cfp     899484 Sep 22 20:40 ramdisk.img
-rw-r--r-- 1 cfp cfp 1610612736 Oct  1 16:48 system.img
-rw-r--r-- 1 cfp cfp  576716800 Sep 22 20:40 userdata.img
-rw------- 1 cfp cfp  576716800 Oct  1 16:52 userdata-qemu.img

启动模拟器,运行我们编译出来的系统镜像。


emulator

这样就看到我们编译出来的效果了。

如果想启动emulator,但是不想显示界面的话,可以使用下面的命令:

emulator -no-window -noaudio > /dev/null 2>&1 &

单独编译模块

有时候我们修改源码的时候,可能只改了某一个模块,是否需要将整个系统编译一遍呢,google怎么可能会做这种蠢事,答案当然是否定的。

例如我们想重新编译Launcher2应用,只需要执行下面的命令

mmm /packages/apps/Launcher2/

之后,重新打包一下system.img文件

make snod

这个命令的作用是快速的构建一个镜像文件,但是,不是所有的情况都使用,它不会检查依赖,如果我们修改了framework层的代码,这种方式就不适用了,因为它有可能会影响到其他的app而不只是Launcher2。

make clean和clobber的区别

这两个命令都是清除编译生产的文件,但是clobber更加的严格。 怎么个严格呢?

make clean

等同于

rm -rf $OUT
cfp@cfp:~$ echo $OUT
/home/cfp/aosp/out/target/product/generic

而 

make clobber

命令等同于

rm -rf out/

错误解决

  • 错误1

    build/core/host_shared_library_internal.mk:51: recipe for target 'out/host/linux-x86/obj/lib/libart.so' failed
    

    解决方法:

    在 art/build/Android.common_build.mk 中,找到WITHOUT_HOST_CLANG,将clang关闭
    
    # Host.
    ART_HOST_CLANG := false
    ifneq ($(WITHOUT_HOST_CLANG),true)
      # By default, host builds use clang for better warnings.
      ART_HOST_CLANG := false
    
    

    关于我

  • 公众号: CodingDev qrcode_for_gh_0e16b0c63d2d_258.jpg