Android系统开发入门-6.删除Android原生内置APK

Android 系统内置了很多应用,比如说通信录,日历,计算器,相机等, 对于 TV 来说,这些应用是没有什么用的,只是占用系统空间而已。为了节剩一下系统空间,我们在编译系统时要把这些模块给去掉。以下介绍两种方法来达到我们的目的。

1. 直接从 PRODUCT_PACKAGES 中删除

比如说我们要删除通信录 Contacts 这个应用,我们可以查找一下这个应用是在哪里加入到 PRODUCT_PACKAGES 的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
qiushao@qiushao-PC:~/source/android-8.1$ mgrep Contacts
./build/make/target/product/core_tiny.mk:22: ContactsProvider \
./build/make/target/product/core_base.mk:24: ContactsProvider \
./build/make/target/product/core.mk:33: Contacts \
./device/google/atv/products/atv_base.mk:32: ContactsProvider \
./platform_testing/build/tasks/tests/instrumentation_test_list.mk:35: ContactsProviderTests \
./platform_testing/build/tasks/tests/instrumentation_test_list.mk:36: ContactsProviderTests2 \
./packages/services/Car/car_product/build/car_base.mk:23: ContactsProvider \
./packages/services/Telephony/Android.mk:3:# Build the Phone app which includes the emergency dialer. See Contacts
./packages/apps/Contacts/CleanSpec.mk:50:$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Contacts_intermediates)
./packages/apps/Contacts/tests/Android.mk:13:LOCAL_PACKAGE_NAME := ContactsTests
./packages/apps/Contacts/tests/Android.mk:15:LOCAL_INSTRUMENTATION_FOR := Contacts
./packages/apps/Contacts/Android.mk:53:LOCAL_PACKAGE_NAME := Contacts
./packages/providers/ContactsProvider/tests2/Android.mk:23: ContactsProviderTestUtils \
./packages/providers/ContactsProvider/tests2/Android.mk:32:LOCAL_PACKAGE_NAME := ContactsProviderTests2
./packages/providers/ContactsProvider/tests2/Android.mk:35:LOCAL_INSTRUMENTATION_FOR := ContactsProvider
./packages/providers/ContactsProvider/test_common/Android.mk:29:LOCAL_MODULE := ContactsProviderTestUtils
./packages/providers/ContactsProvider/tests/Android.mk:8: ContactsProviderTestUtils \
./packages/providers/ContactsProvider/tests/Android.mk:18:LOCAL_PACKAGE_NAME := ContactsProviderTests
./packages/providers/ContactsProvider/tests/Android.mk:21:LOCAL_INSTRUMENTATION_FOR := ContactsProvider
./packages/providers/ContactsProvider/Android.mk:22:LOCAL_PACKAGE_NAME := ContactsProvider
./cts/tests/tests/contactsproviderwipe/Android.mk:35:LOCAL_PACKAGE_NAME := CtsContactsProviderWipe

看一下搜索的结果应该可以知道是 ./build/make/target/product/core.mk 这个文件里面添加了 Contacts 应用。 很多系统原生的应用也是在这里面添加的。我们可以直接在这里面删除即可。

2. 通过 LOCAL_OVERRIDES_PACKAGES 删除

虽然通过前面的方法基本上可以满足我们的需求了,但是需要修改系统原生的配置,不好维护。后来发现一种更好维护的方法。在 device/qiushao 目录下添加 Android.mk 里面添加一个模块 remove_unused_module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
include $(CLEAR_VARS)
LOCAL_MODULE := remove_unused_module
LOCAL_MODULE_TAGS := optional

LOCAL_MODULE_CLASS := FAKE
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)

LOCAL_OVERRIDES_PACKAGES += \
Contacts \
Email

include $(BUILD_SYSTEM)/base_rules.mk

$(LOCAL_BUILT_MODULE):
$(hide) echo "Fake: $@"
$(hide) mkdir -p $(dir $@)
$(hide) touch $@

PACKAGES.$(LOCAL_MODULE).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))

这里需要注意的是 $(hide) echo "Fake: $@" 前面是 TAB,不是空格, Makefile 语法的要求。

然后在 device/qiushao/pure/pure.mk 里面添加

1
PRODUCT_PACKAGES += remove_unused_module

将要去掉的模块添加到 LOCAL_OVERRIDES_PACKAGES 就可以了,统一管理,很方便。
下面来验证一下。把 out/target/product/pure/system 目录删除,然后重新编译,运行,发现Contacts,Email这两个应用的确是不见了。

3. LOCAL_OVERRIDES_PACKAGES 原理

LOCAL_MODULE_CLASS := FAKE 指定编译输出的目录为 $(PRODUCT_OUT)/fake_packages, 也就是不会打包到系统里面。
LOCAL_OVERRIDES_PACKAGES 定义本模块要覆盖的模块,也就是本模块被编译的话,被覆盖的模块就不会被编译了。

3.1 Android 8.0

Android 8.0 版本的代码在 main.mk 里面有对 OVERRIDES_PACKAGES 进行处理:

1
2
3
4
5
6
7
8
9
# Some packages may override others using LOCAL_OVERRIDES_PACKAGES.
# Filter out (do not install) any overridden packages.
overridden_packages := $(call get-package-overrides,$(modules_to_install))
ifdef overridden_packages
# old_modules_to_install := $(modules_to_install)
modules_to_install := \
$(filter-out $(foreach p,$(overridden_packages),$(p) %/$(p).apk %/$(p).odex %/$(p).vdex), \
$(modules_to_install))
endif

modules_to_install 是所有要编译的模块,
overridden_packages 就是指要覆盖的模块了,一般来说是通过在各模块的 Android.mk 里面通过 LOCAL_OVERRIDES_PACKAGES 指定的。
filter-out 就是过滤掉。
这段代码的意思就是将 overridden_packages 从 modules_to_install 中删除掉。

3.2 Android 10.0

Android 10.0 的时候对 main.mk 进行了大修改。对 OVERRIDES_PACKAGES 进行处理为:

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
# Lists most of the files a particular product installs, including:
# - PRODUCT_PACKAGES, and their LOCAL_REQUIRED_MODULES
# - PRODUCT_COPY_FILES
# The base list of modules to build for this product is specified
# by the appropriate product definition file, which was included
# by product_config.mk.
# Name resolution for PRODUCT_PACKAGES:
# foo:32 resolves to foo_32;
# foo:64 resolves to foo;
# foo resolves to both foo and foo_32 (if foo_32 is defined).
#
# Name resolution for LOCAL_REQUIRED_MODULES:
# If a module is built for 2nd arch, its required module resolves to
# 32-bit variant, if it exits. See the select-bitness-of-required-modules definition.
# $(1): product makefile
define product-installed-files
$(eval _mk := $(strip $(1))) \
$(eval _pif_modules := \
$(PRODUCTS.$(_mk).PRODUCT_PACKAGES) \
$(if $(filter eng,$(tags_to_install)),$(PRODUCTS.$(_mk).PRODUCT_PACKAGES_ENG)) \
$(if $(filter debug,$(tags_to_install)),$(PRODUCTS.$(_mk).PRODUCT_PACKAGES_DEBUG)) \
$(if $(filter tests,$(tags_to_install)),$(PRODUCTS.$(_mk).PRODUCT_PACKAGES_TESTS)) \
$(if $(filter asan,$(tags_to_install)),$(PRODUCTS.$(_mk).PRODUCT_PACKAGES_DEBUG_ASAN)) \
$(call auto-included-modules) \
) \
$(eval ### Filter out the overridden packages and executables before doing expansion) \
$(eval _pif_overrides := $(call module-overrides,$(_pif_modules))) \
$(eval _pif_modules := $(filter-out $(_pif_overrides), $(_pif_modules))) \
$(eval ### Resolve the :32 :64 module name) \
$(eval _pif_modules_32 := $(patsubst %:32,%,$(filter %:32, $(_pif_modules)))) \
$(eval _pif_modules_64 := $(patsubst %:64,%,$(filter %:64, $(_pif_modules)))) \
$(eval _pif_modules_rest := $(filter-out %:32 %:64,$(_pif_modules))) \
$(eval ### Note for 32-bit product, 32 and 64 will be added as their original module names.) \
$(eval _pif_modules := $(call get-32-bit-modules-if-we-can, $(_pif_modules_32))) \
$(eval _pif_modules += $(_pif_modules_64)) \
$(eval ### For the rest we add both) \
$(eval _pif_modules += $(call get-32-bit-modules, $(_pif_modules_rest))) \
$(eval _pif_modules += $(_pif_modules_rest)) \
$(call expand-required-modules,_pif_modules,$(_pif_modules),$(_pif_overrides)) \
$(filter-out $(HOST_OUT_ROOT)/%,$(call module-installed-files, $(_pif_modules))) \
$(call resolve-product-relative-paths,\
$(foreach cf,$(PRODUCTS.$(_mk).PRODUCT_COPY_FILES),$(call word-colon,2,$(cf))))
endef

其中 _pif_modules 变量保存了所有要安装到系统的模块。_pif_overrides 变量保存了所有被 overridden 的模块。
$(eval _pif_modules := $(filter-out $(_pif_overrides), $(_pif_modules)))
这行的意思就是把 _pif_overrides 模块从 _pif_modules 模块中删除。

获取所有被 overridden 的模块方法:

1
2
3
define module-overrides
$(foreach m,$(1),$(PACKAGES.$(m).OVERRIDES) $(EXECUTABLES.$(m).OVERRIDES) $(SHARED_LIBRARIES.$(m).OVERRIDES))
endef

从这个函数来看目前我们可以 OVERRIDES 的模块类型有 PACKAGES, EXECUTABLES, SHARED_LIBRARIES。如果我们需要 OVERRIDES 其他类型的模块的话,扩展 module-overrides 这个函数就行。