Android Telephony原理解析与开发指南
上QQ阅读APP看书,第一时间看更新

2.2 Android源代码下载及编译过程

前面已经完成了Ubuntu Linux、OpenJDK和编译Android源码所需的系统工具包的安装和配置,接下来开始下载和编译Android 8.1.0源代码,这个过程简单但花费的时间比较长。

2.2.1 工作目录设置

Android 8.0的代号为Oreo,简称O,中文名称奥利奥。采用名称Oreo作为本书选用Android 8.1.0版本源代码的根目录,在用户根目录下新建代码根目录Oreo文件夹,并设置此目录为工作目录,在.bashrc中增加export $oreo=~/code/Oreo。

注意

在Android开发过程中,配置工作目录的环境变量有利于提升工作效率,主要体现在一些Android工具命令、代码路径、编译结果路径等配合工作目录的环境变量使用会简化操作,读者在使用过程中可逐步体会;后续涉及的$oreo即是Android 8.1.0源代码的根目录路径。

2.2.2 源代码下载

Android 8.1.0源代码的本地目录已经建立,接下来就要开始下载代码了,相关操作及说明如下:

repo脚本是Android项目编写的Python脚本,用来统一管理Android项目的代码仓库

$ sudo apt-get install python
$ curl https://storage.googleapis.com/git-repo-downloads/repo > repo
$ chmod a+x repo

注意

在~/用户主目录下新建一个bin目录,并将此目录设置在PATH目录中;我们将在此目录下保存常用的一些脚本或二进制可执行程序,以后不必更新系统环境变量就能在任意目录执行这些脚本或可执行程序。

$ mkdir ~/bin
$ vi ~/.bashrc
//在文件最后一行增加PATH=~/bin:$PATH,保存退出
$ source .bashrc//立即生效配置的PATH目录
$ mv repo ~/bin/
$ cd $oreo
//配置git个人信息
$ git config --global user.name android_tele
$ git config --global user.email android_tele @163.com
//查看配置的git信息
$ cat ~/.gitconfig
[user]
         name = android_tele
         email = android_tele @163.com
[color]
         ui = auto
//获取Android源码分支信息
$ repo init -u https://android.googlesource.com/platform/manifest
  ......
  * [new tag]            android-8.0.0_r32 -> android-8.0.0_r32
  * [new tag]            android-8.0.0_r33 -> android-8.0.0_r33
  * [new tag]            android-8.0.0_r34 -> android-8.0.0_r34
  * [new tag]            android-8.0.0_r35 -> android-8.0.0_r35
  * [new tag]            android-8.0.0_r36 -> android-8.0.0_r36
  * [new tag]            android-8.0.0_r4 -> android-8.0.0_r4
  * [new tag]            android-8.0.0_r7 -> android-8.0.0_r7
  * [new tag]            android-8.0.0_r9 -> android-8.0.0_r9
  * [new tag]            android-8.1.0_r1 -> android-8.1.0_r1
  ......
//读者可根据实际情况,选择最新的Android源码分支下载,本书选择android-8.1.0_r1分支下载
$ repo init -u https://android.googlesource.com/platform/manifest -b android-8.1.0_r1
 repo has been initialized in /home/android/Oreo
$ repo sync –j8 //开始下载Android O源码,工作进程数量,本例中使用8个,读者可以根据网络带宽进行调整

//这个过程花费的时间很长,视网络情况而定;建议读者在晚上下载,如果中途代码下载中断了,也不必担心,
//repo sync支持续传

2.2.3 开始编译Android源代码

Android 8.1.0源代码下载完成后,可以开始编译源码,详情见如下操作及相关说明。

$ cd $oreo
$ source build/envsetup.sh //或者. build/envsetup.sh //加载编译脚本
//使用第二种方法需要注意,build前有一个空格
including device/asus/fugu/vendorsetup.sh
including device/generic/car/vendorsetup.sh
including device/generic/mini-emulator-arm64/vendorsetup.sh
......
including device/huawei/angler/vendorsetup.sh
including device/lge/bullhead/vendorsetup.sh
including sdk/bash_completion/adb.bash
$ lunch //选择编译的产品信息

You're building on Linux

Lunch menu...... pick a combo:
     1. aosp_arm-eng
     2. aosp_arm64-eng
     3. aosp_mips-eng
     4. aosp_mips64-eng
     5. aosp_x86-eng
     6. aosp_x86_64-eng
     ......
     28. aosp_angler-userdebug
     29. aosp_bullhead-userdebug
     30. aosp_bullhead_svelte-userdebug
     31. hikey-userdebug
     32. hikey960-userdebug

Which would you like? [aosp_arm-eng] aosp_arm64-eng
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=8.1.0 //Android O版本
TARGET_PRODUCT=aosp_arm64 //lunch选择aosp_arm64-eng
TARGET_BUILD_VARIANT=eng
......
BUILD_ID=OPM1.171019.011 //编译号
OUT_DIR=out
AUX_OS_VARIANT_LIST=
============================================
$ make –j8
//编译时间长,编译过程中输出的日志很大,这里对编译日志进行了省略
//以下是编译成功日志信息,可以看出成功编译出system.img镜像文件
encoding RS(255, 253) to '/tmp/tmpGZPyrs_verity_images/verity_fec.img' for input files:
        1: 'out/target/product/angler/obj/PACKAGING/systemimage_intermediates/system.img'
        2: '/tmp/tmpGZPyrs_verity_images/verity.img'
appending /tmp/tmpGZPyrs_verity_images/verity_fec.img to
 /tmp/tmpGZPyrs_verity_images/verity.img
Running:  append2simg
out/target/product/angler/obj/PACKAGING/systemimage_intermediates/system.img/tmp/
tmpGZPyrs_verity_images/verity.img

 [100% 89721/89721] Install system fs image: out/target/product/generic_arm64/system.img
 out/target/product/angler/system.img+out/target/product/generic_arm64/obj/PACKAGING/
recovery_patch_intermediates/recovery_from_boot.p maxsize=3288637440 blocksize=135168
total=1048456853 reserve=33251328

#### build completed successfully (02:26:35 (hh:mm:ss)) ####

第一次编译时间较长,不同的计算机花费的时间不同。作者使用较老的笔记本电脑(酷睿 2 代i7+8GB)编译Android O源码,共使用了6.5小时。如果计算机处理能力较强,可使用更多的工作进程,比如:make –j16,增加编译工作进程数从而减少编译时间。编译完成后,进入$oreo/out/target/product/generic_arm64目录,关注此目录下的system.img、ramdisk.img、userdata.img三个IMG镜像文件,以及data、obj、root、system等目录。请读者自己查看,编译完成后究竟生成了一些什么文件,这里重点关注system目录,其主要目录结构如下。

• app/priv-app(应用apk文件,如TeleService.apk、Mms.apk等)

• bin(可执行文件,app_process32/64、toybox、netd等)

• etc(系统配置信息)

• fonts(字体文件)

• framework(主要保存一些jar包,framework.jar、telephony-common.jar等)

• lib/lib64(主要保存一些so动态链接库文件,libbrillo.solibsurfaceflinger.so等)

• usr(用户配置信息)

• xbin(系统的一些可执行文件)

2.2.4 编译单个模块

整个Android编译环境搭建已经完成了60%。在前面曾经谈到为什么要搭建这样的编译环境,那就是能够调试、运行修改的内容。如果在Telephony应用里修改了Android源码增加日志打印功能,是不是也要通过make来编译呢?这样的话,在编译方面就需要花很多时间。在Android中能够按照模块进行模块的单独编译,可减少不必要的编译时间开销。

注意

在进行分模块编译之前,必须先完成整体编译后才能进行,否则不能成功编译需要单个编译的模块。

分模块编译主要有三种方式。第一种,在$oreo代码根目录下执行mmm module path命令;第二种,进入对应的应用模块代码所在目录执行mm命令;第三种,在$oreo代码根目录下执行make module name命令,详情见如下操作及相关说明。

$ cd $oreo
$ source build/envsetup.sh //或者. build/envsetup.sh
//使用第二种方法需要注意build前有一个空格
$ mmm packages/service/Telephony/      //编译TeleService应用
$ mmm frameworks/base/                 //编译framework.jar

$ cd packages/service/Telephony        //TeleService应用代码目录
$ mm                                   //编译TeleService模块
$ cd $oreo
$ cd frameworks/base                   //进入framework代码目录
$ mm                                   //编译framework
$ cd $oreo
$ make TeleService                     //编译TeleService应用
$ make framework                       //编译framework.jar应用

不论采用什么方式编译单个模块,编译成功后,均有类似如下的日志。

[100% 10/10] Install:
out/target/product/generic_arm64/system/priv-app/TeleService/TeleService.apk
#### build completed successfully (01:16 (mm:ss)) ####
[100% 131/31] Install:
out/target/product/generic_arm64/system/framework/arm64/boot.art
#### build completed successfully (05:28 (mm:ss)) ####

注意

建议使用make module name和mmm方式分模块编译,编译过程不涉及目录的切换,可以减少工作量。而这两种方式中优先选择mmm的编译方式,因为比起make module name方式,它更加省时。