1.1. 1、 \Andorid Build 系统**
1.1.1. 2.1 Make 文件介绍
Android Build 系统用来编译 Android 系统,Android SDK 以及相关文档。该系统主要由 Make 文件,Shell 脚本以及 Python 脚本组成,其中最主要的是 Make 文件。
Build 系统中最主要的处理逻辑都在 Make 文件中,整个 Build 系统中的 Make 文件
可以分为三类:
第一类是 Build 系统核心文件,此类文件定义了整个 Build 系统的框架,而其他所有 Make 文件都是在这个框架的基础上编写出来的。下图是Android源码的目录结构,Build 系统核心文件全部位于 /build/core(本文所提到的所有路径都是以 Android 源码树作为背景的,“/”指的是源码树的根目录,与文件系统无关)目录下。
第二类是针对某个产品(一个产品可能是某个型号的手机或者平板电脑)的 Make 文件,这些文件通常位于 device 目录下,该目录下又以公司名以及产品名分为两级目录,图 2 是 device 目录下子目录的结构。对于一个产品的定义通常需要一组文件,这些文件共同构成了对于这个产品的定义。例如,/device/sony/it26 目录下的文件共同构成了对于 Sony LT26 型号手机的定义。
第三类是针对某个模块(关于模块后文会详细讨论)的 Make 文件。整个系统中,包含了大量的模块,每个模块都有一个专门的 Make 文件,这类文件的名称统一为“Android.mk”,该文件中定义了如何编译当前模块。Build 系统会在整个源码树中扫描名称为“Android.mk”的文件并根据其中的内容执行模块的编译。
在Andorid系统中build系统很重要,里面包含了很多编译指令,下面介绍一些重要的指令。
在编译Android系统时,第一行命令“source build/envsetup.sh”引入了 build/envsetup.sh脚本。该脚本的作用是初始化编译环境,并引入一些辅助的 Shell 函数,这其中就包括第二步使用 lunch 函数。
build/envsetup.sh 中定义的常用函数
第二行命令“lunch full-eng”是调用 lunch 函数,并指定参数为“full-eng”。lunch 函数的参数用来指定此次编译的目标设备以及编译类型。在这里,这两个值分别是“full”和“eng”。“full”是 Android 源码中已经定义好的一种产品,是为模拟器而设置的。而编译类型会影响最终系统中包含的模块。如果调用 lunch 函数的时候没有指定参数,那么该函数将输出列表以供选择。
如果有名称,格式为“
lunch主要作用就是根据用户输入或选择的产品的名来设置与产品相关的环境变量。这些环境变量与产品编译相关的主要有:
TARGET_PRODUCT:所编译的产品名称。
TARGET_BUILD_VARIANT:表示编译产品的类型。可能值有 eng ,user .userdebug。
TARGET_BUILD_TYPE:表示编译的类型,可选值为release和debug当选择debug版本时,系统会加入调式信息,方便追踪。
第三行命令“make -j8”才真正开始执行编译。make 的参数“-j”指定了同时编译的 Job 数量,这是个整数,该值通常是编译主机 CPU 支持的并发线程总数的 1 倍或 2 倍(例如:在一个 4 核,每个核支持两个线程的 CPU 上,可以使用 make -j8 或 make -j16)。在调用 make 命令时,如果没有指定任何目标,则将使用默认的名称为“droid”目标,该目标会编译出完整的 Android 系统镜像。
Build系统主要编译脚本简介,如下:
main.mk:Android Build系统的主控文件。主要作用是包含进其他mk文件,以及定义几个最重要的编译目标,如droid、sdk、ndk等。同时检查编译工具的版本,如make、gcc、javac等。
help.mk:Android Build系统的帮助。文件中定义了一个名为help的编译目标,因此,输入“make help”会打印出Build系统的使用说明。
config.mk:Android Build系统的配置文件。主要定义了许多常量来负责不同类型模块的编译,定义编译器参数并引入产品的BoardConfig.mk文件来配置产品参数,同时也定义了一些编译工具的路径,如aapt、javajar等。
pathmap.mk:将许多头文件的路径通过名值对的方式定义为映射表,并通过include-path-for函数来获取。例如,通过 $(callinclude-path-for, frameworks-native)便可以获取到 framework 本地代码需要的头文件路径。
envsetup.sh:包含进product_config.mk文件并根据其内容设置编译产品所需要的环境变量,如TARGET_PRODUCT等,并检查这些变量值的合法性,同时还指定了各种编译结果的输出路径。
product_config.mk:包含进了系统中所有AndroidProduct.mk文件,并根据当前产品的配置文件来设置产品编译相关的变量。
product.mk:定义product_config.mk文件中使用的各种函数。
version_default.mk:定义系统版本相关的变量。
build_id.mk:定义环境变量BUILD_ID。
Makefile:定义了系统最终编译完成所需要的各种目标和规则。
1.1.2. 2.2 Build 结果的目录结构
所有的编译产物都将位于 /out 目录下,该目录下主要有以下几个子目录:
/out/host/:该目录下包含了针对主机的 Android 开发工具的产物。即 SDK 中的各种工具,例如:emulator,adb,aapt 等。
/out/target/common/:该目录下包含了针对设备的共通的编译产物,主要是 Java 应用代码和 Java 库。
/out/target/product/
/out/dist/:包含了为多种分发而准备的包,通过“make disttarget”将文件拷贝到该目录,默认的编译目标不会产生该目录。
1.1.3. 2.3 Build 生成的镜像文件
Build 的产物中最重要的是三个镜像文件,它们都位于 /out/target/product/
这三个文件是:
system.img:包含了 Android OS 的系统文件,库,可执行文件以及预置的应用程序,将被挂载为根分区。
ramdisk.img:在启动时将被 Linux 内核挂载为只读分区,它包含了 /init 文件和一些配置文件。它用来挂载其他系统镜像并启动 init 进程。
userdata.img:将被挂载为 /data,包含了应用程序相关的数据以及和用户相关的数据。
1.1.4. 2.4 Build 系统中添加新的产品
当我们要开发一款新的 Android 产品的时候,我们首先就需要在 Build 系统中添加对于该产品的定义。在 Android Build 系统中对产品定义的文件通常位于 device 目录下, 通常,对于一个产品的定义通常至少会包括四个文件:AndroidProducts.mk,产品版本定义文件,BoardConfig.mk 以及 verndorsetup.sh。下面我们来详细说明这几个文件。
(1)AndroidProducts.mk:该文文件中的内容很简单,其中只需要定义一个变量,名称为“PRODUCT_MAKEFILES”,该变量的值为产品版本定义文件名的列表,例如:
(2)产品版本定义文件:顾名思义,该文件中包含了对于特定产品版本的定义。该文件可能不只一个,因为同一个产品可能会有多种版本(例如,面向中国地区一个版本,面向美国地区一个版本)。该文件中可以定义的变量以及含义说明如下所示:
通常情况下,我们并不需要定义所有这些变量。Build 系统的已经预先定义好了一些组合,它们都位于 /build/target/product 下,每个文件定义了一个组合,我们只要继承这些预置的定义,然后再覆盖自己想要的变量定义即可。例如:
(3)BoardConfig.mk:该文件用来配置硬件主板,它其中定义的都是设备底层的硬件特性。例如:该设备的主板相关信息,Wifi 相关信息,还有 bootloader,内核,radioimage 等信息。对于该文件的示例,请参看 Android 源码树已经有的文件。
(4)vendorsetup.sh:该文件中作用是通过 add_lunch_combo 函数在 lunch 函数中添加一个菜单选项。该函数的参数是产品名称加上编译类型,中间以“-”连接,例如:add_lunch_combo full_lt26-userdebug。/build/envsetup.sh 会扫描所有 device 和 vender 二 级目 录下的名称 为"vendorsetup.sh"文件,并根据其中的内容来确定 lunch 函数的 菜单选项。
在配置了以上的文件之后,便可以编译出我们新添加的设备的系统镜像了。
1.1.5. 2.5 Build系统中添加新的模块
在源码树中,一个模块的所有文件通常都位于同一个文件夹中。为了将当前模块添加到整个 Build 系统中,每个模块都需要一个专门的 Make 文件,该文件的名称为“Android.mk”。Build 系统会扫描名称为“Android.mk”的文件,并根据该文件中内容编译出相应的产物。
Android.mk 文件介绍,为了方便模块的编译,Build 系统设置了很多的编译环境变量。要编译一个模块,只要在编译之前根据需要设置这些变量然后执行编译即可。它们包括:
LOCAL_SRC_FILES:当前模块包含的所有源代码文件。
LOCAL_MODULE:当前模块的名称,这个名称应当是唯一的,模块间的依赖关系就是通过这个名称来引用的。
LOCAL_C_INCLUDES:C 或 C++ 语言需要的头文件的路径。
LOCAL_STATIC_LIBRARIES:当前模块在静态链接时需要的库的名称。
LOCAL_SHARED_LIBRARIES:当前模块在运行时依赖的动态库的名称。
LOCAL_CFLAGS:提供给 C/C++ 编译器的额外编译参数。
LOCAL_JAVA_LIBRARIES:当前模块依赖的 Java 共享库。
LOCAL_STATIC_JAVA_LIBRARIES:当前模块依赖的 Java 静态库。
LOCAL_PACKAGE_NAME:当前 APK 应用的名称。
LOCAL_CERTIFICATE:签署当前应用的证书名称。
LOCAL_MODULE_TAGS:当前模块所包含的标签,一个模块可以包含多个标签。标签的值可能是 debug, eng, user,development 或者 optional。其中,optional 是默认标签。标签是提供给编译类型使用的。不同的编译类型会安装包含不同标签的模块,关于编译类型的说明如下所示:
除此以外,Build 系统中还定义了一些便捷的函数以便在 Android.mk 中使用,包括:
$(call my-dir):获取当前文件夹路径。
$(call all-java-files-under,
$(call all-c-files-under,
$(call all-Iaidl-files-under,
$(call all-makefiles-under,
$(call intermediates-dir-for,
1、 编译一个APK文件
2、 编译一个库
1.1.6. 2.6 编译出的产物介绍
1、boot.img
boot.img是一种Android自定义的文件格式。该格式包括了一个2*1024大小的文件头,后面是用gzip压缩过的kernel镜像,在后面是ramdisk映像,最后是一个加载器程序。
2、recovery.img
相当于一个小型文本界面的Linux系统,有自己的内核和文件系统,作用是恢复或升级系统。
3、 system.img
是设备中system目录的镜像,包含了Android系统主要的目录和文件。
app目录:一般的apk文件。
bin目录:一些Linux工具。
etc目录:系统的配置文件。
framework目录:系统平台所有jar包和资源文件包
lib目录:系统共享库
media目录:系统的多媒体资源,主要是铃声
priv-app目录:系统核心的apk文件
usr目录:键盘布局、时间区域文件
build.prop目录:系统属性的定义文件
tts目录:系统的语音合成文件
4、userdata.img
是设备中data目录的镜像,初始时一般不包含任何文件。Android系统初始化时会在/data目录创建一些子目录和文件。
1.2. \3、framework定制机编译**
framework开发工作方式与应用开发的工作方式是完全不同的,framework开发是基于Android源代码进行的开发,版本管理主要使用:git,repo两种工具。如果想要学习framework开发,必须需要下载一套Android源码。
修改 android 的 framework 层需要以下四个步骤:
\1. 首先要在工程目录下运行: . ./build/envsetup.sh 这样在之后就可以使用mm命令了
2.例如要修改services下的文件那么编辑完成后
cd frameworks/base/services/
mm
3.替换修修改的文件
编译后用生成的包替换手机上 /system/framework/ 中相应的文件
$ adb remount
$ cd out/target/product/general/system/framework/
$ adb push services.jar /system/framework/
4.让新的文件运行:
方式1: adb reboot 重启
方式2:杀死 services.jar 进程,使系统重新启动,这种方法速度快
$ ps
找到 services.jar对应的 pid, 假设它为 1219
$ kill 1219