在某个项目中,有一个需求,需要新增一个xxx分区,这个分区类似于vendor/oem分区,名字为指定的。此处有点好奇,为什么不直接使用oem分区,而是另外弄一个分区名出来。
功能实现点
在root目录下新增分区的挂载目录,将自定义分区的内容生成一个img。
配置方案,将需要拷进自动以分区的模块、文件等配置好。
在dts中加入xxx分区的支持。
增加init解析rc的路径,支持xxx/etc/init下的rc文件。
修改PackageManagerService,启动时包扫描增加xxx/app下的apk支持。
修改PATH环境变量,使xxx/bin在PATH环境路径下。
修改Android library路径,使JNI能找到xxx/lib中的so。
修改烧写分区,使刷入到flash中。
Android custom images
AndroidP提供了build_custom_images的task,Makefile的路径如下:
android/build/make/core/tasks/build_custom_images.mk
android/build/make/core/tasks/tools/build_custom_image.mk
第一个Makefile定义了custom_images这个目标,已经声明了一些需要设置的参数:
custom_image_parameter_variables := \
CUSTOM_IMAGE_MOUNT_POINT \
CUSTOM_IMAGE_PARTITION_SIZE \
CUSTOM_IMAGE_FILE_SYSTEM_TYPE \
CUSTOM_IMAGE_DICT_FILE \
CUSTOM_IMAGE_MODULES \
CUSTOM_IMAGE_COPY_FILES \
CUSTOM_IMAGE_SELINUX \
CUSTOM_IMAGE_SUPPORT_VERITY \
CUSTOM_IMAGE_SUPPORT_VERITY_FEC \
CUSTOM_IMAGE_VERITY_BLOCK_DEVICE \
CUSTOM_IMAGE_AVB_HASH_ENABLE \
CUSTOM_IMAGE_AVB_ADD_HASH_FOOTER_ARGS \
CUSTOM_IMAGE_AVB_HASHTREE_ENABLE \
CUSTOM_IMAGE_AVB_ADD_HASHTREE_FOOTER_ARGS \
CUSTOM_IMAGE_AVB_KEY_PATH \
CUSTOM_IMAGE_AVB_ALGORITHM \
这些变量的含义在代码的上方有注释,其中PRODUCT_CUSTOM_IMAGE_MAKEFILES这个变量是自定义的分区image的mk文件,image(分区)的名字就是mk的名字。然后调用第二个Makefile文件去编译生成img。
在这里,原生的Makefile中没找到自动添加custom_images这个目标的方式,只能通过`make custom_images`的方式去生成。为了在make的时候自动生成custom_images,可做以下修改:
diff --git a/core/tasks/build_custom_images.mk b/core/tasks/build_custom_images.mk
index c9b07da57..93c06ab1d 100644
--- a/core/tasks/build_custom_images.mk
+++ b/core/tasks/build_custom_images.mk
@@ -50,7 +50,10 @@
#
# To build all those images, run "make custom_images".
-ifneq ($(filter $(MAKECMDGOALS),custom_images),)
+# ifneq ($(filter $(MAKECMDGOALS),custom_images),)
+ifneq ($(PRODUCT_CUSTOM_IMAGE_MAKEFILES),)
+
+$(DEFAULT_GOAL): custom_images
在$(DEFAULT_GOAL)中添加custom_images这个目标,在core/tasks/build_custom_images.mk中修改判断条件,当PRODUCT_CUSTOM_IMAGE_MAKEFILES变量非空时即生成custom_images这个目标。
core/tasks/tools/build_custom_image.mk中的my_staging_dir是指定生成custom_images中间文件目录的地方,默认是方案out目录下obj/PACKAGING/xxxx_intermediates/xxx下,我改到方案out目录下的xxx目录下。
custom_image mk配置
在中增加PRODUCT_CUSTOM_IMAGE_MAKEFILES的配置,如下:
PRODUCT_CUSTOM_IMAGE_MAKEFILES += device/xxx/xxx/
BOARD_ROOT_EXTRA_FOLDERS += xxx
BOARD_ROOT_EXTRA_FOLDERS变量的值是指在root目录下创建一个目录,这个主要是为xxx分区提供好挂载点。
然后就是我们需要根据自己的需求写,这里xxx就是我们的分区名:
CUSTOM_IMAGE_MOUNT_POINT := xxx
CUSTOM_IMAGE_PARTITION_SIZE := 11111111111
CUSTOM_IMAGE_FILE_SYSTEM_TYPE := ext4
CUSTOM_IMAGE_SELINUX := true # 支持编译时指定好selinux权限
CUSTOM_IMAGE_MODULES += \
aaaaa \
bbbbb
CUSTOM_IMAGE_COPY_FILES += \
aaaaaaaa/:etc/init/
这些配置变量可参考注释。注意,如果我们的分区是有一些服务的,那么此时最好配置好selinux,CUSTOM_IMAGE_SELINUX设置为true,然后在中BOARD_SEPOLICY_DIRS加入自己的selinux配置,在file_contexts中将整个分区的所有内容默认设置为oemfs(方便使用,oemfs是已定义的selinux规则):
/xxx(/.*)? u:object_r:oemfs:s0
分区的挂载
AndroidP比较特殊,使用了system as root,因此如果自定义分区中有一些rc文件,那么此时就需要在first state挂载上,如果没有rc文件, 无需在init解析rc前挂载,则只需在fstab上挂载即可。
first state挂载是需要将分区信息写入到dts中,如下:
firmware {
android {
fstab {
compatible = "android,fstab";
name = "fstab";
vendor {
compatible = "android,vendor";
dev = "/dev/block/by-name/vendor";
fsmgr_flags = "wait,recoveryonly";
mnt_flags = "ro,barrier=1";
name = "vendor";
status = "ok";
type = "ext4";
};
xxx {
compatible = "android,xxx";
dev = "/dev/block/by-name/XXX";
fsmgr_flags = "wait,recoveryonly";
mnt_flags = "ro,barrier=1";
name = "xxx";
status = "ok";
type = "ext4";
};
};
};
};
增加rc文件扫描路径
如果自定义分区中有需要增加的rc文件,可修改init的代码,如下:
diff --git a/init/ b/init/
index e51a09301..69eb5c28c 100644
--- a/init/
+++ b/init/
@@ -125,6 +125,9 @@ static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_
if (!("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
+ if (!("/xxx/etc/init")) {
+ late_import_paths.emplace_back("/xxx/etc/init");
+ }
} else {
(bootscript);
}
增加包扫描路径
如果自定义分区中有放入预装的app,则可修改PackageManagerService的源码,增加包扫描的路径:
diff --git a/services/core/java/com/android/server/pm/ b/services/core/java/com/android/server/pm/
index cf35d0a6d3c..f20873576ee 100644
--- a/services/core/java/com/android/server/pm/
+++ b/services/core/java/com/android/server/pm/
@@ -2660,6 +2660,15 @@ public class PackageManagerService extends
| SCAN_AS_SYSTEM,
0);
+ // Collect ordinary ctc packages.
+ final File ctcAppDir = new File("/xxx", "app");
+ scanDirTracedLI(ctcAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM,
+ 0);
+
// Collect privileged vendor packages.
File privilegedVendorAppDir = new File((), "priv-app");
try {
在这里,由于我自定义分区的app需要具有与system同等的权限,因此参数与扫描system下的APP一样。
新增PATH路径
如果自定义分区中有一些可执行文件可被其他人执行,可将该路径添加到PATH变量下:
diff --git a/libc/include/ b/libc/include/
index 922d1ceeb..e5fbcc99c 100644
--- a/libc/include/
+++ b/libc/include/
@@ -38,7 +38,7 @@
#define _PATH_BSHELL "/system/bin/sh"
#endif
#define _PATH_CONSOLE "/dev/console"
-#define _PATH_DEFPATH "/sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
+#define _PATH_DEFPATH "/sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin:/xxx/bin"
#define _PATH_DEV "/dev/"
#define _PATH_DEVNULL "/dev/null"
#define _PATH_KLOG "/proc/kmsg"
这个宏在init启动的时候使用到了。
或者在rc文件中使用export的方式修改:
on init
export PATH /sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin:/xxx/bin
ext4的分区,在打包成img时,部分文件目录的权限会被修改,如bin这种需要可执行的权限,还需修改打包时权限的设置:
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 5b79b1d7d..8f3fe41dc 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -203,6 +203,7 @@ static const struct fs_path_config android_files[] = {
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" },
+ { 00755, AID_ROOT, AID_SHELL, 0, "ctc/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
// clang-format on
新增Android libraries路径
如果自定义分区支持App,则还需考虑apk加载jni库的路径。Android的jni库加载的路径,是在android/bionic/linker/中加载的,同时还会去读取中的配置,具体的过程可以去分析中的源码。
因此我们需要做以下的修改:
android/bionic仓库下:
diff --git a/linker/ b/linker/
index c78b9aba6..750ab39a3 100644
--- a/linker/
+++ b/linker/
@@ -96,6 +96,7 @@ static const char* const kLdConfigVndkLiteFilePath = "/system/etc/
static const char* const kSystemLibDir = "/system/lib64";
static const char* const kOdmLibDir = "/odm/lib64";
static const char* const kVendorLibDir = "/vendor/lib64";
+static const char* const kCtcLibDir = "/ctc/lib64";
static const char* const kAsanSystemLibDir = "/data/asan/system/lib64";
static const char* const kAsanOdmLibDir = "/data/asan/odm/lib64";
static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib64";
@@ -103,6 +104,7 @@ static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib64";
static const char* const kSystemLibDir = "/system/lib";
static const char* const kOdmLibDir = "/odm/lib";
static const char* const kVendorLibDir = "/vendor/lib";
+static const char* const kCtcLibDir = "/ctc/lib";
static const char* const kAsanSystemLibDir = "/data/asan/system/lib";
static const char* const kAsanOdmLibDir = "/data/asan/odm/lib";
static const char* const kAsanVendorLibDir = "/data/asan/vendor/lib";
@@ -114,6 +116,7 @@ static const char* const kDefaultLdPaths[] = {
kSystemLibDir,
kOdmLibDir,
kVendorLibDir,
+ kCtcLibDir,
nullptr
};
android/system/core仓库下:
diff --git a/rootdir/etc/ b/rootdir/etc/
index 42dc7abe7..936757b08 100644
--- a/rootdir/etc/
+++ b/rootdir/etc/
@@ -39,6 +39,7 @@ = sphal,vndk,rs
= true
= /system/${LIB}
+ += /ctc/${LIB}
+= /%PRODUCT%/${LIB}
库的路径已经增加上,还有prebuilt的jni库需要拷贝到自定义分区下的模块目录下,修改build下的Makefile:
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index ce917590b..6638b1d5b 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -369,7 +369,7 @@ ifneq (true,$(my_generate_dm))
$(my_all_targets): $(installed_odex) $(installed_vdex) $(installed_art)
else
ALL_MODULES.$(my_register_name).INSTALLED += $(my_installed_dm)
- ALL_MODULES.$(my_register_name).BUILT_INSTALLED += $(my_built_dm) $(my_installed_dm)
+ ALL_MODULES.$(my_register_name).BUILT_INSTALLED += $(my_built_dm):$(my_installed_dm)
# Make sure to install the .dm when you run "make <module_name>"
$(my_all_targets): $(installed_dm)
diff --git a/core/install_jni_libs_internal.mk b/core/install_jni_libs_internal.mk
index a99d88ad7..5b1bbaf6b 100644
--- a/core/install_jni_libs_internal.mk
+++ b/core/install_jni_libs_internal.mk
@@ -95,7 +95,8 @@ my_jni_shared_libraries += $(my_prebuilt_jni_libs)
else # not my_embed_jni
# Install my_prebuilt_jni_libs as separate files.
$(foreach lib, $(my_prebuilt_jni_libs), \
- $(eval $(call copy-one-file, $(lib), $(my_app_lib_path)/$(notdir $(lib)))))
+ $(eval $(call copy-one-file, $(lib), $(my_app_lib_path)/$(notdir $(lib))))\
+ $(eval ALL_MODULES.$(my_register_name).PREBUILT_INSTALLED += $(lib):$(my_app_lib_path)/$(notdir $(lib))))
$(LOCAL_INSTALLED_MODULE) : $(addprefix $(my_app_lib_path)/, $(notdir $(my_prebuilt_jni_libs)))
endif # my_embed_jni
diff --git a/core/tasks/tools/build_custom_image.mk b/core/tasks/tools/build_custom_image.mk
index a1151e908..49033b74f 100644
--- a/core/tasks/tools/build_custom_image.mk
+++ b/core/tasks/tools/build_custom_image.mk
@@ -26,7 +26,7 @@ my_custom_image_name := $(basename $(notdir $(my_custom_imag_makefile)))
intermediates := $(call intermediates-dir-for,PACKAGING,$(my_custom_image_name))
my_built_custom_image := $(intermediates)/$(my_custom_image_name).img
-my_staging_dir := $(intermediates)/$(CUSTOM_IMAGE_MOUNT_POINT)
+my_staging_dir := $(PRODUCT_OUT)/$(CUSTOM_IMAGE_MOUNT_POINT)
# Collect CUSTOM_IMAGE_MODULES's installd files and their PICKUP_FILES.
my_built_modules :=
@@ -38,6 +38,8 @@ $(foreach m,$(CUSTOM_IMAGE_MODULES),\
$(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).PICKUP_FILES)))\
$(eval _built_files := $(strip $(ALL_MODULES.$(m).BUILT_INSTALLED)\
$(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).BUILT_INSTALLED)))\
+ $(eval _prebuilt_files := $(strip $(ALL_MODULES.$(m).PREBUILT_INSTALLED)\
+ $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).PREBUILT_INSTALLED)))\
$(if $(_pickup_files)$(_built_files),,\
$(warning Unknown installed file for module '$(m)'))\
$(eval my_pickup_files += $(_pickup_files))\
@@ -52,6 +54,17 @@ $(foreach m,$(CUSTOM_IMAGE_MODULES),\
$(eval my_copy_dest := $(wordlist 2,999,$(my_copy_dest)))\
$(eval my_copy_dest := $(subst $(space),/,$(my_copy_dest)))\
$(eval my_copy_pairs += $(bui):$(my_staging_dir)/$(my_copy_dest)))\
+ )\
+ $(foreach i, $(_prebuilt_files),\
+ $(eval prebui_ins := $(subst :,$(space),$(i)))\
+ $(eval ins := $(word 2,$(prebui_ins)))\
+ $(if $(filter $(TARGET_OUT_ROOT)/%,$(ins)),\
+ $(eval prebui := $(word 1,$(prebui_ins)))\
+ $(eval my_copy_dest := $(patsubst $(PRODUCT_OUT)/%,%,$(ins)))\
+ $(eval my_copy_dest := $(subst /,$(space),$(my_copy_dest)))\
+ $(eval my_copy_dest := $(wordlist 2,999,$(my_copy_dest)))\
+ $(eval my_copy_dest := $(subst $(space),/,$(my_copy_dest)))\
+ $(eval my_copy_pairs += $(prebui):$(my_staging_dir)/$(my_copy_dest)))\
))
刷写分区
各个厂商的实现不一样,这里不展开。
总结
经过上面的修改后,一个自定义的分区基本可以完成我们需要的功能,后续有遇到问题再进行修正。
————————————————
版权声明:本文为****博主「chongyuzhao」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:/zcyxiaxi/article/details/119113593