Android系统开发入门-5.添加预编译模块

在实际的系统开发过程中,有很多文件都是预先编译好的,比如第三方APK,so库, jar包, bin 文件,配置文件等。我们需要在系统编译时能把这些文件打包编译到系统镜像里面。我们有两种方法可以达到我们的目的: PRODUCT_COPY_FILES 和 定义 prebuilt 模块。

  • 如果这个文件只需要预置到指定目录就可以了,那我们就可以简单的将其加入 PRODUCT_COPY_FILES 变量就行, 比如一些 bin 文件, 配置文件。
  • 如果这个文件有其他模块编译依赖,或者这个文件需要系统签名,那我们就得定义一个预编译模块,比如一些 so 库,APK 文件, jar 包等。

1. PRODUCT_COPY_FILES

我们先来学习简单的方式 PRODUCT_COPY_FILES。
PRODUCT_COPY_FILES 变量值可以在 $product.mk 文件里面设置, 在我们这个例子里面是 pure.mk 文件。
但如果我们需要内置的文件很多,全部都写在 $product.mk 里面的话,可能就会很乱。
所以为了维护方便,我们一般把 PRODUCT_COPY_FILES 的设置提取到一个单独的文件。在 $product.mk 里面 include 就行。
下面以内置一个 busybox bin 文件为例子。

1.1 建立 prebuilt 目录层级

我们把 prebuilt 的文件都放到 device/qiushao/pure/prebuilt 目录,
prebuilt 目录也建立不同层级的目录,放置不同类型的文件:

1
2
3
4
5
6
prebuilt
├── apk # 预置 apk 模块
├── libs # 预置库模块,so 库, jar 包等
└── vendor # PRODUCT_COPY_FILES 类型预置,按实际输出路径组织
└── bin
└── busybox-i686

1.2 下载 busybox bin 文件

把 busybox 放在 prebuilt/vendor/bin 目录

1
2
cd prebuilt/vendor/bin
wget https://busybox.net/downloads/binaries/1.21.1/busybox-i686

1.3 添加 product_copy_files.mk

在 device/qiushao/pure 目录下新建 product_copy_files.mk 文件,内容如下:

1
2
3
4
5
6
# product copy files

LOCAL_PREBUILD_DIR := device/qiushao/pure/prebuilt

PRODUCT_COPY_FILES += \
$(LOCAL_PREBUILD_DIR)/vendor/bin/busybox-i686:vendor/bin/busybox

然后在 pure.mk 里面include

1
include device/qiushao/pure/product_copy_files.mk

这样就添加完啦,以后只要在 product_copy_files.mk 增加要预置的文件即可。
编译验证一下,发现 adb shell 可以用 busybox 命令了。

2. 定义 prebuilt 模块

定义一个预编译模块和上一节中定义一个普通的编译模块格式相似,不同的是 srcs 变量指定的不是源文件,而是二进制文件的路径。下面是常见预编译模块的写法。

2.1 java 库

1
2
3
4
5
6
7
8
9
10
java_import {
name: "api.pure",
installable: true,
jars: [
"api.pure.jar",
],
libs: [
"framework",
],
}

如果这个 jar 包需要安装到系统,则需要配置 installable 为 true。如果只是作为编译时提供接口而已, 则不需要设置 installable。
更多的设置选项请参考 java_import

2.2 c/c++ 库

Android.bp 形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cc_prebuilt_library_shared {
name: "libpure_api",
export_include_dirs: ["include"],
vendor: true,
target: {
android_arm: {
srcs: ["prebuilt/lib/libpure_api.so"],
},
android_arm64: {
srcs: ["prebuilt/lib64/libpure_api.so"],
},
},
shared_libs: [
"liblog",
],
}

Android.mk 形式:

1
2
3
4
5
6
7
8
9
include $(CLEAR_VARS)
LOCAL_MODULE := libpure_api
#32位、64位两者都编译
LOCAL_SRC_FILES_32 := prebuilt/lib/libpure_api.so
LOCAL_SRC_FILES_64 := prebuilt/lib64/libpure_api.so
LOCAL_MULTILIB := both #取值为 32 / 64 / both
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := .so
include $(BUILD_PREBUILT)

2.3 APK 文件

目前我还不知道怎么使用 Android.bp 来定义一个 prebuilt apk 模块,查了一下资料也没有查到如何使用 Android.bp 来定义 prebuilt 模块。所以只能使用 Android.mk 来定义了。

1
2
3
4
5
6
7
8
9
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := NetMusic
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS #模块类型为 apk
LOCAL_CERTIFICATE := platform #使用系统签名
LOCAL_MODULE_SUFFIX := .apk
include $(BUILD_PREBUILT)

如果没有 so 库的话,就这么简单了。有 so 库的话,相对来说要麻烦一点,后面再专门讨论。