Android Makefle

Android 平台的编译系统,其实就是用 Makefile 写出来的一个独立项目。它定义了编译的规则,实现了“自动化编译”,不仅把分散在数百个 Git 库中的代码整合起来、统一编译, 而且还把产物分门别类地输出到一个目录,打包成手机 ROM,还可以生成应用开发时所使用的 SDK、NDK 等。因此,采用 Makefile 编写的编译系统,也可以称为 Makefile 编译系统。

Android.mk 文件用来告知 NDK Build 系统关于 Source 的信息。 它是 GNU Makefile 的一部分,且将被 Build System 解析一次或多次。

相关概念

Android.mk、Ninja、Soong、Blueprint、kati、Android.bp 的概念之间的联系为:

makefile

  • Android.mk
    Makefile 编译系统的一部分,定义了一个模块的必要参数,使模块随着平台编译。通俗来讲就是告诉编译系统,以什么样的规则编译你的源代码,并生成对应的目标文件。
  • Ninja
    Ninja 是一个致力于速度的小型编译系统,如果把其他的编译系统看作高级语言,那么 Ninja 目标就是汇编。
  • Soong
    Soong 是谷歌用来替代此前的 Makefile 编译系统的替代品,负责解析 Android.bp 文件,并将之转换为 Ninja 文件
  • Blueprint
    Blueprint 用来解析 Android.bp 文件翻译成 Ninja 语法文件。
  • kati
    kati 是谷歌专门为了 Android 而开发的一个小项目,基于 Golang 和 C++。 目的是把 Android 中的 Makefile,转换成 Ninja 文件。
  • Android.bp
    Android.bp,是用来替换 Android.mk 的配置文件。

编译命令

  1. mm:编译当前目录下的模块,不编译它所依赖的其它模块。
  2. mma:编译当前目录下的模块及其依赖项。
  3. mmm:编译指定目录下的模块,不编译它所依赖的其它模块。
  4. mmma:编译指定路径下所有模块,并且包含依赖。

镜像

  1. system.img:系统镜像,里面包含了 Android 系统主要的目录和文件,通过 init.c 进行解析并 mount 挂载到/system 目录下。
  2. userdata.img:用户镜像,是 Android 系统中存放用户数据的,通过 init.c 进行解析并 mount 挂载到/data 目录下。
  3. ramdisk.img:根文件系统镜像,包含一些启动 Android 系统的重要文件,比如 init.rc。

Android.mk 文件

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#代表mk当前文档路径
LOCAL_PATH := $(call my-dir)

# 清楚除LOCAL_PATH 以外的变量
include $(CLEAR_VARS)

# user: 指该模块只在user版本下才编译
# eng: 指该模块只在eng版本下才编译
# tests: 指该模块只在tests版本下才编译
# optional:指该模块在所有版本下都编译
LOCAL_MODULE_TAGS := optional

# 系统签名
LOCAL_CERTIFICATE := platform

# 指定 src 目录
LOCAL_SRC_FILES := $(call all-java-files-under, src)

# 指定 res 目录
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res

# 默认的目录为 system/app/{LOCAL_PACKAGE_NAME}/{LOCAL_PACKAGE_NAME}.apk
# $(TARGET_OUT) 代表 /system
LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app
# 生成的 apk 放到 system/priv-app
# LOCAL_PRIVILEGED_MODULE := true
# 生成的 apk 就会放到 data/app 目录下
# LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)/

LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
--version-name "$(version_name_package)" \
--version-code $(version_code_package) \

LOCAL_USE_AAPT2 := true

# 应用名称
LOCAL_PACKAGE_NAME := Camera2

# 混淆配置
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_PROGUARD_FLAG_FILES := proguard.flags

#签名配置
LOCAL_CERTIFICATE := platform

#引用当前app的资源
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res

#声明当前app的代码目录
src_dirs := java/

#引用当前app的代码
LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))

#设置version版本
#设置版本号和名字,如果不写会默认使用系统api的版本号25 --7.1.1
version_code = 24
version_name := 4.0.0.1

#打apk包
include $(BUILD_PACKAGE)

#调用子目录的mk文件
include $(call all-makefiles-under,$(LOCAL_PATH))

编译打包的 5 中方式:

  1. APK 程序编译打包生成 apk 文件
    include $(BUILD_PACKAGE)
    out/target/product/generic/obj/APPS/XXX_intermediates
  2. JAVA 库编译打包生成 jar 文件
    include $(BUILD_STATIC_JAVA_LIBRARY)
    out/target/product/generic/obj/JAVA_LIBRARIES/ XXX_intermediates
  3. 可执行的 C/C++应用程序
    include $(BUILD_EXECUTABLE)
    out/target/product/generic/obj/EXECUTABLE/XXX_intermediates
  4. C\C++静态库并打包成.a 文件
    include $(BUILD_STATIC_LIBRARY)
    out/target/product/generic/obj/STATIC_LIBRARY
    XXX_static_intermediates
  5. C\C++共享库
    include $(BUILD_SHARED_LIBRARY)
    编译生成共享库(动态链接库),并打包成 .so 文件, 有且只有共享库才能被安装/复制到您的应用软件(APK)包中。
    out/target/product/generic/obj/SHARED_LIBRARY/XXX_shared_intermediates

签名配置

在 build/target/product/security 目录中有四组默认签名供,Android.mk 在编译 APK 使用:

  1. testkey:普通 APK,默认情况下使用。
  2. platform:该 APK 完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的 APK 所在进程的 UID 为 system。
  3. shared:该 APK 需要和 home/contacts 进程共享数据。
  4. media:该 APK 是 media/download 系统中的一环。

示例:

1
2
3
4
5
6
7
8
9
10
11
系统中所有使用android.uid.system作为共享UID的APK,
都会首先在manifest节点中增加android:sharedUserId="android.uid.system",
然后在Android.mk中增加LOCAL_CERTIFICATE := platform。可以参见Settings等

系统中所有使用android.uid.shared作为共享UID的APK,
都会在manifest节点中增加android:sharedUserId="android.uid.shared",
然后在Android.mk中增加LOCAL_CERTIFICATE := shared。可以参见Launcher等

系统中所有使用android.media作为共享UID的APK,
都会在manifest节点中增加android:sharedUserId="android.media",
然后在Android.mk中增加LOCAL_CERTIFICATE := media。可以参见Gallery等。

找到平台签名文件“platform.pk8”和“platform.x509.pem”,文件位置 android/build/target/product/security/。

参考 安卓系统签名转 keystore

引入 aar

1
2
3
4
5
6
7
8
9
10
11
12
# 引用 aar 的别名
LOCAL_STATIC_JAVA_AAR_LIBRARIES:= <aar alias>

# 指定生成 apk 文件
include $(BUILD_PACKAGE)

include $(CLEAR_VARS)

# 定义 aar 别名和文件路径
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := <aar alias>:libs/<lib file>.aar

include $(BUILD_MULTI_PREBUILT)

参考

[1] Android.mk 引用 aar 文件
[2] Android.mk 打包 apk
[3] Android 编译系统 Makefile