【Bash百宝箱】Android源码下载及编译

tip:下文基于Android 6.0 Marshmallow,后续版本可能稍有不同。

0、版本管理

在分析Android源码之前,首先要了解一下相关的版本管理工具。Git工具是一种分布式的版本管理系统,最初被设计用于Linux内核的版本控制。Git功能强大,但也有之不便之处,Android中有许多项目,用git来统一管理就显得力不从心了,为此Google用Python开发了一套专门用来管理整个Android系统的工具repo。

使用repo的基本流程——

a. 使用repo init创建分支。
b. 使用repo sync更新代码。
c. 在本地作代码修改。
e. 使用git add将修改的代码暂存。
f. 使用git commit将修改的代码提交仓库。
g. 使用git push或repo upload将修改的代码提交服务器。

几个简单的repo/git命令——

$ repo sync [PROJECT-LIST]

同步所有项目,使本地代码与服务器保持一致,也可以只同步指定的项目。

$ repo start <BRANCH_NAME>

在所有git仓库下创建分支。

$ repo branch

查看当前所有的分支,branch关键字等同于branches。

$ git branch

查看当前git仓库的分支。

$ git checkout <BRANCH_NAME>

切换当前git仓库的分支。

$ repo status

查看“git commit”前的工作区状态,对应的还有“git status”。

$ repo diff

查看“git add”前的代码区别,对应的还有“git diff”。

$ git add

添加本地修改到暂存区。

$ git commit

提交变更记录到版本库。

$ repo upload

提交代码修改到服务器。

这里只列举了一些常用的命令,其它命令的详细用法可通过“repo help”或“git help”查看。

1、环境准备

搭建Android编译环境首先要满足下列条件——

a. Linux或者Mac OS系统,有时候可能是工作在Windows上的Linux虚拟机,这时要保证至少16GB的RAM/swap和100GB的磁盘空间。
b. Gingerbread(2.3.x)版本及以后的版本,开发环境基于64位操作系统,此前的版本可以使用32位的操作系统。
c. 至少100G的磁盘空间,编译单个产品时需150G的磁盘空间,编译多个产品时需200GB的磁盘空间,如果使用了ccache(如果经常使用“make clean”或者在多个产品间切换时可使用ccache加快编译速度),磁盘空间还需要更多。
d. Python 2.6-2.7,安装见:https://www.python.org/downloads/
e. GNU Make 3.81-3.82,安装见:http://ftp.gnu.org/gnu/make/
f. 安卓开源项目AOSP上的master分支使用JDK 7,从Gingerbread到KitKat的版本使用JDK 6,Cupcake到Froyo的版本使用JDK 5。
g. Git 1.7或者更新的版本,安装见:http://git-scm.com/download

对于不同的Linux版本或者Mac OS系统,还需要安装一些工具,请参考官网介绍——

http://source.android.com/source/initializing.html

2、源码下载

下载源码之前,首先要安装repo。下面是安装repo的参考步骤——

$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo

初始化repo——

$ mkdir /home/AndroidPro && cd /home/AndroidPro
$ repo init -u https://android.googlesource.com/platform/manifest [-b BRANCH]

init命令用于初始化repo并得到近期的版本更新信息,获取非master分支的代码可通过-b指定某个分支,分支tag(如android-6.0.1_r10)可在如下官网查看:
http://source.android.com/source/build-numbers.html#source-code-tags-and-builds

初始化成功后会在当前目录下添加.repo目录,并如下提示:

repo has been initialized in /home/AndroidPro

更新代码——

$ repo sync

首次更新可能需要很长时间,更新完之后“du -sh”看了下,约占据62G的磁盘空间,使用“tree -a -L 1 .”看了下源码结构,有如下26个目录和一个Makefile:

这里写图片描述

Android系统源码中并不包括Linux Kernel源码,需要单独下载(git clone),代码仓库可参照官网:
https://android.googlesource.com/

3、源码编译

Anroid系统通常是运行于类似Arm这样的嵌入式平台上,涉及交叉编译,需要依赖于宿主机(如Linux)编译成目标文件,宿主机为Linux时的交叉编译器是arm-linux-gcc,Android源码自带了对应的编译器。下面是编译的几个步骤。

$ source build/envsetup.sh

首先执行build目录下的envsetup.sh脚本,这个脚本会设置一些环境变量,记录着编译过程中所需要的各种函数实现,例如接下来将要用到的lunch,这些函数可以直接在shell终端调用,脚本执行可使用source命令,也可以使用“.”点命令。

$ lunch <TARGET>

这个lunch就是上一步envsetup.sh中的函数,意思是选择一个目标进行编译,TARGET由两部分组成,BUILD和BUILDTYPE,即BUILD-BUILDTYPE例如“aosp_arm-eng”,BUILD表示具体的设备,BUILDTYPE表示具体的应用场景,后者有三个参数,分别是eng、user和userdebug。eng是开发版,user是最终发布的版本,有一定的权限限制,userdebug有root权限,用于debug。如果不知道lunch目标的话,可以直接输入lunch后回车,系统会给出提示。

$ make [-jN]

最后直接make编译,可使用-j编译参数加快编译速度,N是个常数,取决于计算机的CPU数、每个CPU的核心数、每个核心的线程数,如果有2个CPU,每个CPU4个核心,每个核心2个线程,那么想要加快编译速度时,N的取值范围是[16,32]。

编译成功后,我们就可以使用emulator命令运行模拟器了。

$ emulator

我们还可以编译sdk——

$ . build/envsetup.sh
$ lunch sdk-eng
$ make sdk

4、产品定制

在Android源码中有个device目录,里面有一些厂商名录,如asus、google、htc、huawei、moto等,还有一个sample目录。那么我们如何定制自己的产品呢?

一般规则是在device目录下新建一个以公司命名的文件夹,然后在此文件夹中建立产品,产品相关的东西都会优先放在这里。为了能够正常编译一款产品,我们还需要准备一些配置文件,如硬件架构Architecture、电路核心板Board、外围设备Device、释出产品Product,最熟悉的就是Makefile了,下面会介绍到。

vendorsetup.sh——

添加vendorsetup.sh,这个脚本的作用就是告诉Android编译系统我们添加了一个产品,以device/htc/flounder/vendorsetup.sh为例,只有下面一行内容:

add_lunch_combo aosp_flounder-userdebug

add_lunch_combo是前面提到的envsetup.sh脚本中的一个函数,作用是添加aosp_flounder-userdebug这个产品到系统变量,源码如下:

# Clear this variable.  It will be built up again when the vendorsetup.sh
# files are included at the end of this file.
unset LUNCH_MENU_CHOICES
function add_lunch_combo()
{
    local new_combo=$1
    local c
    for c in ${LUNCH_MENU_CHOICES[@]} ; do
        if [ "$new_combo" = "$c" ] ; then
            return
        fi
    done
    LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
}
# add the default one here
add_lunch_combo aosp_arm-eng
add_lunch_combo aosp_arm64-eng
add_lunch_combo aosp_mips-eng
add_lunch_combo aosp_mips64-eng
add_lunch_combo aosp_x86-eng
add_lunch_combo aosp_x86_64-eng

add_lunch_combo函数实现中,首先会遍历LUNCH_MENU_CHOICES数组变量中是否包含aosp_flounder-userdebug,没有的话就添加上去,同时也看出系统会添加几个默认的产品。那么vendorsetup.sh脚本是什么时候执行的呢?就是在执行envsetup.sh脚本的时候,源码如下:

# Execute the contents of any vendorsetup.sh files we can find.
for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
         `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
         `test -d product && find -L product -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort`
do
    echo "including $f"
    . $f
done
unset f

envsetup.sh会遍历device 、vendor 、product 几个目录下的vendorsetup.sh,需要注意的是find查找的最大深度为4,切勿将vendorsetup.sh放到更深的目录中。

AndroidProducts.mk——

添加AndroidProducts.mk,记录了产品的具体属性,编译时系统会查找产品目录下的这个文件,为了便于管理,这个文件只是指向了其它的.mk文件,以device/htc/flounder/AndroidProducts.mk为例:

PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/aosp_flounder.mk \
    $(LOCAL_DIR)/aosp_flounder64.mk \
    $(LOCAL_DIR)/aosp_flounder32.mk \
    $(LOCAL_DIR)/aosp_flounder_64_only.mk

PRODUCT_MAKEFILES添加了4个不同的.mk文件,以aosp_flounder.mk为例:

# This file is the build configuration for an aosp Android
# build for flounder hardware. This cleanly combines a set of
# device-specific aspects (drivers) with a device-agnostic
# product configuration (apps). Except for a few implementation
# details, it only fundamentally contains two inherit-product
# lines, aosp and flounder, hence its name.
# Live Wallpapers
PRODUCT_PACKAGES += \
        rild \
        CarrierConfig \
        Launcher3
PRODUCT_PROPERTY_OVERRIDES := \
        net.dns1=8.8.8.8 \
        net.dns2=8.8.4.4
# Inherit from those products. Most specific first.
$(call inherit-product, device/htc/flounder/product.mk)
$(call inherit-product, device/htc/flounder/device-lte.mk)
$(call inherit-product-if-exists, vendor/htc/flounder_lte/device-vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_base.mk)
PRODUCT_NAME := aosp_flounder
PRODUCT_DEVICE := flounder
PRODUCT_BRAND := Android
PRODUCT_MODEL := AOSP on Flounder
PRODUCT_MANUFACTURER := HTC
PRODUCT_RESTRICT_VENDOR_FILES := owner path

aosp_flounder.mk中多是一些以PRODUCT_开头的系统变量,以及一些函数调用,用来描述产品信息。下面介绍一些常用的以PRODUCT_开头的系统变量。

PRODUCT_NAME:产品名称。
PRODUCT_DEVICE:设备名称。
PRODUCT_BRAND:产品品牌。
PRODUCT_MODEL:产品型号。
PRODUCT_MANUFACTURER:产品生产商。
PRODUCT_PACKAGES:系统预装程序。
PRODUCT_PROPERTY_OVERRIDES:重载系统属性。
PRODUCT_LOCALES:支持的国家语言。
PRODUCT_POLICY:产品策略。
PRODUCT_TAGS:产品描述标签。

BoardConfig.mk——

添加BoardConfig.mk,这个文件用于填写目标架构、硬件设备属性、编译器的条件标志、分区布局、boot地址、ramdisk大小等一系列参数,系统变量多以TARGET_和BOARD_开头,以及一些其它类型的的系统变量,不过各大厂商的BoardConfig.mk大同小异,可以互相参考。

Android.mk——

添加Android.mk,这个是Android系统编译某个模块的标准Makefile文件,一款产品下会有许多这样的Android.mk,以device/htc/flounder/Android.mk为例:

ifneq ($(filter flounder%, $(TARGET_DEVICE)),)
LOCAL_PATH := $(call my-dir)
# if some modules are built directly from this directory (not subdirectories),
# their rules should be written here.
include $(call all-makefiles-under,$(LOCAL_PATH))
endif

这个Makefile inlude了其目录下的所有Makefile,以device/htc/flounder/health/Android.mk为例:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := system/core/healthd
LOCAL_SRC_FILES := healthd-flounder.cpp
LOCAL_MODULE := libhealthd.flounder
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)

上面的Makefile是Android系统编译某个模块的标准用法,BUILD_STATIC_LIBRARY表明编译结果为一个静态库。至此,一个定制产品的基本配置就完成了。

5、系统image

对于一款产品,编译完成后,会在out/target/product/[PRODUCT_NAME]目录下生成一些系统image,如system.img、ramdisk.img、userdata.img等,下面作简单介绍。

boot.img:包含内核启动参数、内核等多个元素。源码路径在system/core/mkbootimg,其下有3个文件,分别是Android.mk(指定了mkbootimg为prebuilt)、bootimg.h(定义了bootimg的结构)、mkbootimg(一个python文件)。
ramdisk.img:一个小型的文件系统,是Android系统启动的关键。
system.img:Android系统的运行程序包,将被挂载到设备的/system目录下。
userdata.img:各程序的数据存储所在,将被挂载到/data目录下。
recovery.img:设备进入恢复模式时所需要的image。
misc.img:包含各种杂项资源。
cache.img:缓冲区,将被挂载到/cache目录下。

image文件——
image文件其实是一个压缩包,我们可以使用file命令查看(以ramdisk.img为例)。

$ file ramdisk.img
ramdisk.img: gzip compressed data, from Unix

可见,ramdisk.img是使用gzip压缩过的一个压缩包,既然是压缩包,那么就可以解压缩看看里面的东西。

$ move ramdisk.img ramdisk.img.gz
$ gzip -d ramdisk.img.gz
$ file ramdisk.img
ramdisk.img: ASCII cpio archive (SVR4 with no CRC)

ramdisk.img变成了一个cpio文件,继续执行下面的命令。

$ cpio -i -F ramdisk.img
这样,所有的文件就解压到了当前文件夹。

ramdisk.img这个压缩文件还原时相对简单点,有些文件如system.img还原时就要使用其它方法了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值