Android系统开发入门-4.添加自定义模块

早期的Android系统都是采用Android.mk的配置来编译源码,从Android 7.0开始引入Android.bp。很明显Android.bp的出现就是为了替换掉Android.mk。如果你从 Android7.0 的代码一路看到 Android10.0,你就会发现系统的各个模块正在逐步替换成 Android.bp。既然官方都在逐步弃用 Android.mk 了,那我们也跟随官方的脚步使用 Android.bp 来创建新模块。

1. 可执行文件:cc_binary

下面我们以一个 hello world 模块为例来初步认识一下一个 Android.bp 模块的相关概念。
在 device/qiushao/pure 目录下创建一个 hello 目录,创建 hello.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
#include <cstdio>
#include <android/log.h>

#define LOG_TAG "qiushao"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG ,__VA_ARGS__)

int main() {
printf("hello qiushao\n");
LOGD("hello qiushao");
return 0;
}

在 hello 目录下创建 Android.bp

1
2
3
4
5
6
7
8
cc_binary {              //模块类型为可执行文件
name: "hello", //模块名hello
srcs: ["hello.cpp"], //源文件列表
vendor: true, //编译出来放在/vendor目录下(默认是放在/system目录下)
shared_libs: [ //编译依赖的动态库
"liblog",
],
}

至此一个模块就已经添加完成了,接下来我们可以在 hello 目录下用 mm 命令测试一下是否可以编译通过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
qiushao@qiushao-pc:~/source/android-10/device/qiushao/pure/hello$ mm -j
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
TARGET_PRODUCT=pure
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_ARCH=x86_64
TARGET_ARCH_VARIANT=x86_64
TARGET_2ND_ARCH=x86
TARGET_2ND_ARCH_VARIANT=x86_64
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.0.0-37-generic-x86_64-Ubuntu-18.04.3-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QD1A.190821.011
OUT_DIR=out
============================================
[100% 7/7] Install: out/target/product/pure/vendor/bin/hello

#### build completed successfully (1 seconds) ####

qiushao@qiushao-pc:~/source/android-10/device/qiushao/pure/hello$

在 device/qiushao/pure/pure.mk 中添加配置

1
PRODUCT_PACKAGES += hello

添加这个配置之后,编译系统时就会自动编译并打包这个模块到系统里面。
我们完整编译一下系统,运行虚拟机,然后连接 adb shell 执行刚刚添加的模块:

1
2
3
4
5
6
qiushao@qiushao-pc:~/source/android-10$ adb shell
pure:/ # hello
hello qiushao
pure:/ # which hello
/vendor/bin/hello
pure:/ #

我们来回顾一下 Android.bp 的内容,也就几行配置而已,非常简单。当然其实还有非常多的配置我们并没有使用到。
具体的配置项可以参考以下文档 cc_binary

2. c/c++ 库:cc_library

1
2
3
4
5
6
7
8
9
10
11
cc_library {               //模块类型为c/c++库, 会同时编译动态库和静态库, 
//如果要指定编译动态库或者静态库,则应该要用 cc_library_shared 或者 cc_library_static
name: "libpure_utils", //模块名
vendor: true, //安装到 vendor 分区
export_include_dirs: ["include"], //导出头文件目录,这样其他模块要使用本模块的时候,就不需要用 include_dirs 指定头文件目录了。
srcs: ["src/pure_log.cpp", "src/pure_thread.cpp"], //源文件列表, 如果不想要一个一个列出来,
//可以使用 srcs: ["**/*.cpp"] 这种方式来查找所有的 cpp 文件。
shared_libs: [ //依赖的动态库
"liblog",
],
}

3. java 库:java_library

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java_library {         //模块类型为 java 库,这个类型与 java_library_static 是完全一样的
name: "api.pure", //模块名
installable: true, //下面详细说明
enabled: true, //是否编译这个模块,有时候我们需要根据某些条件,关闭某个模块。
dex_preopt: {
enabled: false, //不做 preopt,
},
srcs: [
"java/**/*.java", //文件列表
],
libs: [
"android.hidl.manager-V1.0-java", //依赖的其他 java 库
],
}

其中 installable 配置有必要作下说明,官方文档是这么写的:

java_library builds and links sources into a .jar file for the device, and possibly for the host as well. By default, a java_library has a single variant that produces a .jar file containing .class files that were compiled against the device bootclasspath. This jar is not suitable for installing on a device, but can be used as a static_libs dependency of another module. Specifying installable: true will product a .jar file containing classes.dex files, suitable for installing on a device.

简单的说就是如果不指定 installable: true, 则编译出来的 jar 包里面是 .class 文件。这种包是没法安装到系统上的,只能给其他 java 模块作为 static_libs 依赖。
指定 installable: true, 则编译出来的 jar 包里面是 classes.dex 文件。这种才是 Android 虚拟机可以加载的格式。

上面的这几个例子是最常见的模块。Android 系统中还有非常多种类型的模块。这里面就不一一举例了,需要定义其他类型的模块时,可以参考以下文档 soong。或者参考系统已有的 Android.bp 模块。

4. 模块编译输出分区

前面的几个例子,我们只有输出到 system 或者 vendor 分区这两种选择, 其实系统还有其它几个目录可以输出的,下面对这些目录的作用及怎么指定模块的输出分区作下说明:

  • system :主要包含 Android 框架, google 官方实现
    • Android.mk 默认就是输出到 system 分区,不用指定
    • Android.bp 默认就是输出到 system 分区,不用指定
  • vendor :SoC芯片商分区(系统级核心厂商,如高通), 为他们提供一些核心功能和服务,由 soc 实现
    • Android.mk LOCAL_VENDOR_MODULE := true
    • Android.bp vendor: true
  • odm :设备制造商分区(如华为、小米),为他们的传感器或外围设备提供一些核心功能和服务
    • Android.mk LOCAL_ODM_MODULE := true
    • Android.bp device_specific: true
  • product :产品机型分区
    • Android.mk LOCAL_PRODUCT_MODULE := true
    • Android.bp product_specific