Android核心原理与系统级应用高效开发
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 Android编译的板级支持

Android的开源代码默认是支持仿真器的。如果需要使用Android的开源代码支持一个特定的设备,除了具体的代码实现之外,还需要对Android的编译系统做出一些更改。这种编译的板级支持可以作为附加的方式被添加到Android系统之中。

2.3.1 支持一个板的工作

从Android开源代码到一个板(特定设备)的支持,变化的部分就是更改部分代码和增加板级支持目录。更改完成后,Android编译系统按照一定的顺序进行处理。

Android对特定板的支持的处理流程如图2-1所示。

图2-1 Android编译的板级支持的处理流程

Android对特定板的编译支持主要分成以下几个步骤。

● Make的时候传入TARGET_PRODUCT宏。

● Android的编译系统根据TARGET_PRODUCT宏找到目标板的配置目录。

● 在目标板配置目录中的板级配置文件得到若干配置宏。

● (系统编译流程)各个模块根据配置宏进行编译。

● 处理目标板中的其他特定配置文件。

Android编译流程主要涉及以下的一些文件。

● buildspec.mk:根目录中的文件,指定板名称。

● vendersetup.sh:专用设置文件。

● BoardConfig.mk:板级全局配置。

● AndroidBoard.mk:当前板的特殊配置。

● AndroidProducts.mk:产品的配置。

buildspec.mk和vendersetup.sh两个文件执行的是同一种功能,也就是目标产品名称的定义,二者可以取其一(实际上也可以有其他定义方式)。

在make配置后,系统可以开始进行构建。构建的前面就是找到目标产品的配置目录,并使用其中的几个文件:BoardConfig.mk中定义的内容可以被系统的每一个部分使用(传递到每一个Android.mk);AndroidBoard.mk和AndroidProducts.mk是配置文件,可以引用默认的内容。板级的编译支持目录中也可以具有自己的Android.mk文件,与普通的用法类似。

2.3.2 buildspec.mk文件的作用

将buildspec.mk增加到源代码TOP目录,可以完成配置工作。Android在执行make的时候,将找到TOP目录中的buildspec.mk,取出其中定义的内容进行配置。buildspec.mk的作用实际上就是为了定义几个宏,作为Make第一步使用的环境变量。

一个buildspec.mk的写法如下所示:

ifndef TARGET_PRODUCT
#TARGET_PRODUCT:=generic
Endif
ifndef TARGET_BUILD_VARIANT
#TARGET_BUILD_VARIANT:=user
#TARGET_BUILD_VARIANT:=userdebug
#TARGET_BUILD_VARIANT:=eng
endif

其中,最重要的一个宏是TARGET_PRODUCT,表示目标产品的名称;TARGET_BUILD_VARIANT则表示编译的类型,分成user(用户模式)、userdebug(用户调试模式)、eng(工程模式),这个宏将主要影响系统是否具有root权限等方面。

当编译不进行定义时,或者TARGET_PRODUCT的数值本身就是“generic”,将使用“generic”板(也就是仿真器)的配置,其路径为:build/target/product。

提示:Android的仿真器默认情况下也是ARM体系结构的目标,仿真器QEMU仿真执行了ARM代码,因此generic目标和实际的产品差别并不大。

当TARGET_PRODUCT宏被正式定义时,将在自定义板的路径找到名称为其值的目录,作为板级编译支持目录。可以使用的板级编译支持目录有以下两个。

● device/*/<TARGET_PRODUCT>

● vendor/*/<TARGET_PRODUCT>

其含义为TOP目录中的device或者vendor目录中的某个子目录中的下一级目录作为板级编译支持目录。也就是说板级编译支持目录必须是Android三级子目录,且必须在device或者vendor目录中,二级子目录没有要求,一般是公司的名称。

两个产品的板级编译支持目录如下所示。

● device/htc/passion/:Nexus One手机(Google和HTC合作出品)。

● device/samsung/crespo/:Nexus S手机(Google和三星合作出品)。

2.3.3 vendersetup.sh和lunch命令

vendersetup.sh文件可以提供另外一种编译配置方法,这也是较新版本的Android系统推荐的方法。其职能实际上也是配置几个宏,作为Make时的环境变量。

在编译之前,可以使用envsetup.sh脚本进行编译的配置,配置的过程中,将会调用每一个板的vendersetup.sh文件,内容如下所示:

$ . build/envsetup.sh
including device/htc/passion/vendorsetup.sh
including device/samsung/crespo/vendorsetup.sh

此时的配置,实际是一个“遍历”的过程,将会调用device/*/和vendor/*/目录中每一个板的vendersetup.sh文件。只要板级支持目录中有vendersetup.sh文件,就会被调用。调用后实际上将为增加系统可以选择的目标产品,这个影响将在使用lunch命令进行选择产品时有所体现,内容如下所示:

$ lunch
You're building on Linux
Lunch menu... pick a combo:
    1. generic-eng
    2. simulator
    3. full_passion-userdebug
    4. full_crespo-userdebug
Which would you like? [generic-eng] 1
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=2.3.4
TARGET_PRODUCT=generic
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=GRJ22
============================================

在lunch时出现的菜单项目(combo)中,出现了4个选项,可以使用数字进行选择。从中可见,除了默认的generic-eng和simulator两个选择之外,full_passion-userdebug和full_crespo-userdebug就是来自于自定义板级支持的文件。

device/htc/passion/中的vendersetup.sh文件如下所示:

add_lunch_combo full_passion-userdebug

device/samsung/crespo/中的vendersetup.sh文件如下所示:

add_lunch_combo full_crespo-userdebug

其中full_passion和full_crespo也就是所定义的TARGET_PRODUCT宏的名称。在lunch时选择了数字后,实际上得到的结果也是设置TARGET_PRODUCT等宏。

2.3.4 BoardConfig.mk文件的作用

BoardConfig.mk文件是一个平台全局配置的文件,这些配置的内容可以在各个工程的Android.mk文件中得到。BoardConfig.mk只是进行配置的定义,其中不能包含实际执行的命令。

例如,BoardConfig.mk文件可以进行定义:

BOARD_USES_GENERIC_AUDIO := false

BOARD_USES_GENERIC_AUDIO等宏的数值就可以在每一个编译文件(Android.mk)中被读出。

BoardConfig.mk文件中也可以使用-include包含其他的板级配置宏。

例如,device/samsung/crespo/中的BoardConfig.mk文件包含了如下的片断:

-include vendor/samsung/crespo/BoardConfigVendor.mk
TARGET_CPU_ABI := armeabi-v7a               # CPU体系结构的二进制格式
BOARD_HAVE_BLUETOOTH := true                # 是否具有蓝牙
TARGET_NO_BOOTLOADER := true                # 是否具有BootLoader
TARGET_NO_KERNEL := false                   # 是否具有Linux内核

BoardConfig.mk文件中既可以使用TARGET_CPU_ABI等编译系统使用的宏,也可以定义自己使用的宏。

2.3.5 AndroidProducts.mk文件

AndroidProducts.mk为当前板的配置文件,其中可以使用一些宏定制最终在目标系统中需要的安装内容。在实际的板级支持过程中,通常需要在AndroidProducts.mk中包含同类文件,进行大部分默认的定义,然后再对不同配置进行覆盖(Override)定义。

AndroidProducts.mk需要定义几个宏,用于表示当前产品的信息: PRODUCT_NAME(产品名称),PRODUCT_DEVICE(产品设备)。

其中build/target/product/目录中的AndroidProducts.mk是默认的产品配置文件,内容如下所示。

ifneq ($(TARGET_BUILD_APPS),)
PRODUCT_MAKEFILES := \
  $(LOCAL_DIR)/core.mk \
  $(LOCAL_DIR)/generic.mk
else
PRODUCT_MAKEFILES := \
  $(LOCAL_DIR)/core.mk \
  $(LOCAL_DIR)/generic.mk \
  $(LOCAL_DIR)/generic_x86.mk \
  $(LOCAL_DIR)/full.mk \
  $(LOCAL_DIR)/sdk.mk \
  $(LOCAL_DIR)/sim.mk
endif

其中指定的PRODUCT_MAKEFILES实际上就是被其包含的文件。full.mk也在build/target/product/目录中,其中具有如下内容。

PRODUCT_NAME := full
PRODUCT_BRAND := generic
PRODUCT_DEVICE := generic
PRODUCT_MODEL := Full Android

这里的PRODUCT_NAME等宏的定义也就是产品名称等信息,这里进行了定义后,在系统中通过部分的函数可以读取这些信息,并可以提供给程序和用户。

其中另一个功能是定义系统预安装的包。例子如下所示:

PRODUCT_PACKAGES := \
  OpenWnn \
  PinyinIME \
  VoiceDialer \
  libWnnEngDic \
  libWnnJpnDic \
  libwnndict

在包被增加到PRODUCT_PACKAGES宏之后,这个包将会被预装到系统中,作为系统映像的一部分。

系统预装文件使用PRODUCT_COPY_FILES宏来定义。例子如下所示:

PRODUCT_COPY_FILES := \
  development/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
  development/data/etc/vold.conf:system/etc/vold.conf

在PRODUCT_COPY_FILES的各项内容中,“:”前面的为源文件,“:”后面的为目标机的文件(为out/target/product/<产品名称>目录加上后面的路径),编译时将源文件复制为目标文件。如果目标文件的目录没有,也会进行自动创建。因此,这是另外一种像目标系统中预装文件的方法。

另外一个可以定义的内容是系统语言区域的定义,在build/target/product/目录中的languages_<XXX>.mk文件中进行定义,类似具有如下的内容:

PRODUCT_LOCALES := en_US en_GB fr_FR it_IT de_DE es_ES

这里使用的是ISO 639-1定义的语言码和ISO 3166-1-alpha-2定义的区域码。

例如,device/samsung/crespo/中的AndroidProducts.mk文件包含了同目录的full_crespo.mk文件,full_crespo.mk的主要内容如下所示:

$(call inherit-product, $(SRC_TARGET_DIR)/product/languages_full.mk)
$(call inherit-product, device/samsung/crespo/device.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/full.mk)
PRODUCT_NAME := full_crespo
PRODUCT_DEVICE := crespo
PRODUCT_MODEL := Full Android on Crespo

此时除了PRODUCT_NAME等宏的定义之外,也可以包含其他的同类文件,包含的languages_full.mk和full.mk就是系统默认的文件,在这里被复用,而device.mk是当前目录中的另外一个文件。

2.3.6 AndroidBoard.mk文件

AndroidBoard.mk用于板级一些编译内容的定义,这个文件通常是可选的。AndroidBoard.mk的功能和语法类似一般的Android.mk文件。

例如,build/target/board/generic/中的AndroidBoard.mk文件如下所示:

LOCAL_PATH := $(call my-dir)
file := $(TARGET_OUT_KEYLAYOUT)/tuttle2.kl
ALL_PREBUILT += $(file)
$(file) : $(LOCAL_PATH)/tuttle2.kl | $(ACP)
    $(transform-prebuilt-to-target)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := tuttle2.kcm
include $(BUILD_KEY_CHAR_MAP)

这里进行了两个工作:一个是将按键布局的文件tuttle2.kl复制到目标系统中,一个是调用BUILD_KEY_CHAR_MAP模板对按键字符映像的tuttle2.kcm文件进行编译处理。由于每一个Android板的输入设备通常都不同,因此在一个特定设备的构建过程中,按键相关的定制处理也是经常需要进行的工作。

AndroidBoard.mk不是必需的,例如,在crespo的配置目录device/samsung/crespo/中,就没有AndroidBoard.mk文件,而具有Android.mk文件。

2.3.7 编译中的层叠加

在一个Android的板级构建过程中,有一种不更改源代码文件,而实现构建出不同内容的方法,这就是通过编译中层叠加(overlay)的机制来实现的。使用这种方式可以基于同样的源代码,为了不同的硬件或不同产品构建出不同的系统。

在板级配置目录中,可以有一个名称为overlay的子目录,这个目录表示的就是一个代码叠加层。这个overlay目录对应于Android源代码的TOP目录,在编译的过程中将使用overlay目录中的内容替换TOP目录中的内容。

例如,在Nexus S(crespo)的板级配置的目录device/samsung/crespo/overlay/下面的一个目录结构如下所示:

device/samsung/crespo/overlay/frameworks/base/core/
`-- res
  `-- res
        |-- drawable-hdpi
        |   `-- default_wallpaper.jpg
        |-- values
        |   `-- config.xml
        `-- xml
            `-- power_profile.xml

此时,将把TOP目录中的frameworks/base/core/res/res/drawable-hdpi中的default_wallpaper.jpg替换成overlay对应目录的同名文件。这个文件实际上是系统默认的墙纸,由此,进行完如此的定义后,相当于crespo编译的系统将替换默认的墙纸。

Android系统中很多模块比较适合使用这种替换方式,例如应用程序包中的资源文件等。尤其值得注意的是,一旦使用overlay进行层替换,原有的源文件将不再起作用。