有时间来整理一下Android系统编译的内容,本文从三方面展开:编译过程、常用的编译配置和命令
一. 编译过程步骤
1.初始化编译环境
source ./build/envsetup.sh它主要作用:
-
定义m\mm\mmm\lunch 等函数
-
添加编译目标:将以下文件搜索并source进来
device//vendorsetup.sh
vendor/ /vendorsetup.shproduct/*/vendorsetup.sh
2. 选择编译目标 lunch xxtarget
-
可新建device/company/product/AndroidProducts.mk文件并在AndroidProducts.mk中通过COMMON_LUNCH_CHOICES新增编译目标选项,注意:编译目标需要有合法的配置信息。
-
lunch xxtarget选择编译目标后,会确定TARGET_PRODUCT、TARGET_BUILD_VARIANT、TARGET_PLATFORM_VERSION、TARGET_BUILD_TYPE等变量的值
3. 编译 make -j8
Android根目录的Makefile include进来一个编译核心文件:build/make/core/main.mk
main.mk主要功能:
- include 包含众多mk文件;
- include config.mk, config.mk 中定义了在Android.mk中编译目标时会用到的常量;
- include /build/core/envsetup.sh,然后通过include product_config.mk检索所有Product,并做目标有效性检查,然后根据lunch时选择的目标设置TARGET_DEVICE,然后在envsetup.sh中根据TARGET_DEVICE查找BoardConfig.mk文件进行Board相关配置,查找KERNEL_HEADER,配置编译工具链;
- definitions.mk中定义了all_makefiles_under等用来检索文件的函数;
- 将所有子目录下的Android.mk文件收集 并include进来,将相应的Android.mk中定义的目标包含进编译模块中。
- include build/core/Makefile文件,定义bootimage,systemimage等依赖目标,然后通过make编译目标就可以编译系统了。
二. 常用配置
Android 7.0 之后逐渐用 Android.bp 替换 Android.mk
1.编译动态库
java
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
cJSON.c
LOCAL_MODULE:= libmycjson
include $(BUILD_SHARED_LIBRARY)
- Android.bp
java
cc_library_shared { //编译成动态库,类似于 Android.mk 中的 BUILD_SHARED_LIBRARY
name: "libcamera_client",
aidl: {
export_aidl_headers: true, //是否导出 aidl 头文件路径
local_include_dirs: ["aidl"], //将[指定的目录列表]加入 aidl 搜索头文件路径。
// ["aidl"]表示当前目录下的 aidl 目录
include_dirs: [ //指定搜索外部 aidl 头文件的路径
"frameworks/native/aidl/gui",
],
},
srcs: [ //源文件,类似于 Android.mk 中的 LOCAL_SRC_FILES
// AIDL files for camera interfaces
// The headers for these interfaces will be available to any modules that
// include libcamera_client, at the path "aidl/package/path/BnFoo.h"
":libcamera_client_aidl", //引用了另外一个模块中定义的源文件。在当前 bp 文件的第 81 行
// Source for camera interface parcelables, and manually-written interfaces
"Camera.cpp",
"CameraMetadata.cpp",
"CameraParameters.cpp",
"CaptureResult.cpp",
"CameraParameters2.cpp",
"ICamera.cpp",
"ICameraClient.cpp",
"ICameraRecordingProxy.cpp",
"ICameraRecordingProxyListener.cpp",
"camera2/CaptureRequest.cpp",
"camera2/OutputConfiguration.cpp",
"camera2/SessionConfiguration.cpp",
"camera2/SubmitInfo.cpp",
"CameraBase.cpp",
"CameraUtils.cpp",
"VendorTagDescriptor.cpp",
],
shared_libs: [ //编译所依赖的动态库,类似于 Android.mk 中的 LOCAL_SHARED_LIBRARIES
"libcutils",
"libutils",
"liblog",
"libbinder",
"libgui",
"libcamera_metadata",
"libnativewindow",
],
include_dirs: [//用户指定的头文件查找路径,类似于 Android.mk 中的 LOCAL_C_INCLUDES
"system/media/private/camera/include",
"frameworks/native/include/media/openmax",
],
export_include_dirs: [//将当前的路径导出,如果有其他模块引用当前模块,就不需要指定头文件路径
"include",
"include/camera"
],
export_shared_lib_headers: ["libcamera_metadata"],//将 libcamera_metadata 模块对应的头文件路径列表导出
cflags: [//编译 flag,类似于 Android.mk 中的 LOCAL_CFLAGS
"-Werror",
"-Wall",
"-Wextra",
],
}
2. 编译可执行程序
java
LOCAL_PATH:= $(call my-dir)
curdir=$(LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
main.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/libcjson
LOCAL_SHARED_LIBRARIES += \
libmycjson \
LOCAL_CFLAGS += \
-Wno-error \
-Wno-unused-parameter
LOCAL_MODULE:= cjson_test
LOCAL_MODULE_TAGS := optional
LOCAL_MULTILIB := 64
include $(BUILD_EXECUTABLE)
include $(curdir)/libcjson/Android.mk
- Android.bp
java
cc_binary {
name: "reboot",
srcs: ["reboot.c"],
shared_libs: ["libcutils"],
cflags: ["-Werror"],
}
3.编译Java动态库
java
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_JAVA_LIBRARIES := libmytest
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := TestDemo
include $(BUILD_JAVA_LIBRARY)
- Android.bp
java
java_library { //编译成 java 库
name: "services",//编译出的模块的名称
dex_preopt: {
app_image: true, //是否为当前模块生成 app image(.art)文件
profile: "art-profile",//指定与当前 Android.bp 相关的配置文件路径
},
srcs: [ //源文件
"java/**/*.java",
],
// The convention is to name each service module 'services.$(module_name)'
static_libs: [
//编译所依赖的静态库
"services.core",
"services.accessibility",
"services.appwidget",
"services.autofill",
"services.backup",
"services.companion",
"services.coverage",
"services.devicepolicy",
"services.midi",
"services.net",
"services.print",
"services.restrictions",
"services.usage",
"services.usb",
"services.voiceinteraction",
"android.hidl.base-V1.0-java",
],
libs: [//链接的动态库
"android.hidl.manager-V1.0-java",
],
// Uncomment to enable output of certain warnings (deprecated, unchecked)
//javacflags: ["-Xlint"],
}
4. apk(含源码,不含源码的可参考预编译)
java
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, app/src/main/java)
LOCAL_PACKAGE_NAME := StorageTest
LOCAL_SDK_VERSION := current
#LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_CERTIFICATE := platform
LOCAL_USE_AAPT2 := true
# 指定 Manifest 文件
LOCAL_MANIFEST_FILE := app/src/main/AndroidManifest.xml
LOCAL_RESOURCE_DIR := \
$(addprefix $(LOCAL_PATH)/, app/src/main/res)
# 需要的 jar,否则无法找到系统相关资源
LOCAL_STATIC_JAVA_LIBRARIES := \
androidx.appcompat_appcompat \
include $(BUILD_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
- Android.bp
java
android_app {
name: "Music",
srcs: [
"src/**/*.java",
"src/com/android/music/IMediaPlaybackService.aidl",
],
sdk_version: "current",
product_specific: true, //安装到 product 分区
optimize: {
proguard_flags_files: ["proguard.flags"],
},
certificate: "platform",
}
5.预编译
java
#预编译配置文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := Vendor_5135_Product_0005.idc
LOCAL_SRC_FILES := Vendor_5135_Product_0005.idc
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/idc
include $(BUILD_PREBUILT)
java
# 预编译动态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES :=libglib-2.0.so
LOCAL_MODULE_SUFFIX := .so
LOCAL_MODULE := libglib-2.0
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MULTILIB := 32
include $(BUILD_PREBUILT)
java
# 预编译可执行程序
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := busybox_aarch64
LOCAL_MODULE := busybox_aarch64
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)
java
#预编译APK
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Hello
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
#定义编译完成之后的类型:除了APPS,还有ETC,EXECUTABLES(.bin)SHARED_LIBRARIES(.so) 等选择值
LOCAL_MODULE_CLASS := APPS
#定义编译完成之后模块的后缀
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
#定义使用原app签名可用选择项platform,shared,media
LOCAL_CERTIFICATE := PRESIGNED
#将apk编进"/system/priv-app/目录",如果为false,或者不加这句话,就会编进"/system/app" 目录, 二者区别在于前者的权限要高于后者,即不可卸载
LOCAL_PRIVILEGED_MODULE := true
#不进行odex化
LOCAL_DEX_PREOPT := false
# 定义编译出来的目标文件,如动态库,静态库,jar包以及apk
include $(BUILD_PREBUILT)
- Android.bp
java
//预编译etc配置文件
prebuilt_etc {
name: "Vendor_my_idc",
src: "Vendor_5135_Product_0005.idc",
filename_from_src: true,
sub_dir:"usr",
}
java
//预编译可执行文件
cc_prebuilt_binary {
name: "logpersist.start",
srcs: ["logpersist"],
init_rc: ["logcatd.rc"],
required: ["logcatd"],
symlinks: [
"logpersist.stop",
"logpersist.cat",
],
strip: {
none: true,
},
}
java
//预编译动态库
cc_prebuilt_library_shared {
name: "libmycjson-pre.so",
srcs: ["x86_64/libmycjson-pre.so"],
compile_multilib : "64",
}
三. 常用命令
1. 编译命令
1.1 m命令
- m 源码树的根目录执行编译,编译的是根目录下所有的代码;
- mm 编译当前路径下所有模块,但不包含依赖关系的模块;
- mmm [module_path] 编译指定路径下的所有模块,但不包含依赖关系的模块;
- mma 编译当前路径下所有模块,且包含依赖关系的模块;
- mmma [module_path] 编译指定路径下的所有模块,且包含依赖关系的模块;
1.2make命令
- make [module_name] 无参数,则表示编译整个Android代码,如果有module_name,是会遍历module,编译指定的module;
常见module编译例:
{模块} make命令 | mmm命令
{init} make init | mmm system/core/init
{zygote} make app_process | mmm frameworks/base/cmds/app_process
{system_server} make services | mmm frameworks/base/services
{java framework} make framework | mmm frameworks/base
{framework资源} make framework-res | mmm frameworks/base/core/res
{jni framework} make libandroid_runtime | mmm frameworks/base/core/jni
{binder} make libbinder | mmm frameworks/native/libs/binder
{RefBase等} make libutils | mmm framworks/base/libs/utils
{Looper等} make framework | mmm framworks/base
{AudioTrack} make libmedia | mmm framworks/base/media/kibmedia
{AudioFlinger} make libaudiofliginger | mmm framworks/base/libs/audioflinger
{AudioPolicyService} make libaudiopolicy | mmm hardware/msm7k/libaudio-qsd8k
{SurfaceFlinger} make libsurfaceflinger | mmm frameworks/base/libs/surfaceflinger
{Vold} make vold | mmm system/vold
{Rild} make rild | mmm hardware/ril/rild
{MediaProvider} make MediaProvider | mmm packages/providers/MediaProvider
{Phone} make phone | mmm packages/apps/Phone - make clean:执行清理操作,等价于 rm -rf out/
- make update-api:更新API,在framework API改动后需执行该指令,Api记录在目录frameworks/base/api;
- make sdk 编译出 Android 的 SDK;
- make clean-sdk 清理 SDK 的编译产物;
- make help 帮助信息,显示主要的 make 目标;
- make snod 从已经编译出的包快速重建系统镜像;
- make clean- 清理一个指定模块的编译结果;
- make dump-products 显示所有产品的编译配置信息;
- make libandroid_runtime 编译所有 JNI framework 内容
- make framework 编译所有 Java framework 内容
- make services 编译系统服务和相关内容。
- make bootimage 生成 boot.img
- make systemimage 编译生成system.img
- make recoveryimage 生成 recovery.img
- make userdataimage 生成 userdata.img
- make cacheimage 生成 cache.img
- make otapackage 生成升级包
- make dist 执行 Build,并将 MAKECMDGOALS 变量定义的输出文件拷贝到 /out/dist 目录。
2. 编译配置和搜索命令
- add_lunch_combo [product] 将某个产品加入到用户选项中
- print_lunch_menu 查询lunch可选的product
- check_product [product] 检查产品是否有效
- printconfig 打印当前选择的产品配置
- get_build_var [build_var] 查找编译时各种变量值;
- get_abs_build_var [build_var] 获取系统中的编译变量的值
- cgrep [keyword] 所有 C/C++文件执行搜索操作
- jgrep [keyword] 所有 Java 文件执行搜索操作
- ggrep [keyword] 所有 Gradle 文件执行搜索操作
- mgrep [keyword] 所有 Android.mk 文件执行搜索操作
- mangrep [keyword] 所有AndroidManifest.xml文件执行搜索操作
- sepgrep [keyword] 所有 sepolicy 文件执行搜索操作
- resgrep [keyword] 所有本地res/*.xml文件执行搜索操作
3. 导航命令
-
croot 切换至Android根目录
-
godir [filename] 跳转到包含某个文件的目录
👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀