欢迎关注微信公众号和哔哩哔哩账号 ZZH的Android
微信公众号回复 加群,可以一起进群交流Android系统开发相关内容。
背景
有些场景需要我们内置一些可卸载的应用,也就是出厂时默认安装,但是用户可以自行卸载。
本篇文章的思路是,在开机后使用一个后台服务调用pm install 进行apk的安装。
需要说明的是,这种方法并不完美,具体问题文章末尾会进行说明,但是在某些项目上也是可行的一个选择。
我们以Pixel5 Android13版本为例进行演示。
代码
// 找到自己项目配置文件,Pixel5 Android13是下面的文件
// device/google/redfin/device-redfin.mk
// 在文件末尾加入下面的内容,
// 这个是配置内置应用的
-include vendor/redfin/third_apps/preinstall_apps.mk
// 这个是配置selinux权限的
SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS += vendor/redfin/sepolicy/public
// 新建目录: vendor/redfin/third_apps
// 创建如下文件
// vendor/redfin/third_apps/preinstall_apps.mk
// 编译选项,后面会有对应的Android.mk
PRODUCT_PACKAGES += \
preinstall_app.sh
// 将应用安装脚本文件和要内置的apk放到/system目录
// 这里的apk以MT Manager为例
PRODUCT_COPY_FILES += \
vendor/redfin/third_apps/preinstall_app.sh:$(TARGET_COPY_OUT_SYSTEM)/bin/preinstall_app.sh \
vendor/redfin/third_apps/MTManager.apk:$(TARGET_COPY_OUT_SYSTEM)/preinstall/MTManager.apk
// vendor/redfin/third_apps/Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := preinstall_app.sh
LOCAL_SRC_FILES := preinstall_app.sh
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)
// 这里思路是,开机后用pm install -r命令安装
// /system/preinstal目录下的apk,安装完成后
// 建立一个文件标志,这样下次开机的时候就不需要
// 再次安装了。
// vendor/redfin/third_apps/preinstall_app.sh
#!/system/bin/sh
APPS=/system/preinstall
FILE_LIST=$(ls ${APPS}/)
if [ ! -f /data/app/did ]; then
for FILE in ${FILE_LIST}; do
pm install -r ${APPS}/${FILE}
done
echo 1 > /data/app/did
fi
文件目录如下
zzh@ubuntu:~/work/android/aosp/android-13.0.0_r40/vendor/redfin/third_apps$ ll
total 21976
drwxrwxr-x 2 zzh zzh 4096 11月 9 00:15 ./
drwxrwxr-x 4 zzh zzh 4096 11月 10 22:25 ../
-rw-rw-r-- 1 zzh zzh 214 11月 9 00:02 Android.mk
-r--r--r-- 1 zzh zzh 22480181 11月 7 23:09 MTManager.apk
-rwxrwxr-x 1 zzh zzh 371 11月 7 23:10 preinstall_app.sh*
-rw-rw-r-- 1 zzh zzh 276 11月 9 00:15 preinstall_apps.mk
开机时init进程启动上面的脚本
// system/core/rootdir/init.rc
// 开机完成后,启动安装服务
on property:sys.boot_completed=1
start preinstall_app
// 安装服务就是执行preinstall_app.sh脚本
service preinstall_app /system/bin/preinstall_app.sh
class main
user root
group root
seclabel u:r:preinstall_app:s0
disabled
selinux权限
// vendor/redfin/sepolicy/public
// 这个目录下有两个文件
zzh@ubuntu:~/work/android/aosp/android-13.0.0_r40/vendor/redfin/sepolicy/public$ ll
total 16
drwxrwxr-x 2 zzh zzh 4096 11月 10 23:39 ./
drwxrwxr-x 3 zzh zzh 4096 11月 10 22:27 ../
-rw-rw-r-- 1 zzh zzh 72 11月 10 23:13 file_contexts
-rw-rw-r-- 1 zzh zzh 158 11月 10 23:14 preinstall_app.te
// vendor/redfin/sepolicy/public/file_contexts
/system/bin/preinstall_app.sh u:object_r:preinstall_app_exec:s0
// vendor/redfin/sepolicy/public/preinstall_app.te
type preinstall_app, domain;
type preinstall_app_exec, system_file_type, exec_type, file_type;
allow preinstall_app app_data_file:file{ read write getattr };
本以为上面改完就可以了,但是启动时发现还是有一堆selinux权限问题,再经过了漫长时间的配置后,我决定关闭selinux。
主要原因是需要修改很多的neverallow机制,但是这样会影响Google认证。如果不需要认证的可以进行neverallow的修改,这里就
不贴代码了,大姐可以根据提示自行添加。再或者如果不需要selinux的,也可以选择直接关闭。
下面看下如何关闭selinux
// system/core/init/
diff --git a/init/selinux.cpp b/init/selinux.cpp
index be8c5542f..f46f1b8de 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -123,6 +123,9 @@ EnforcingStatus StatusFromProperty() {
}
bool IsEnforcing() {
// 这个函数直接返回false即可关闭selinux
+ if (true) {
+ return false;
+ }
if (ALLOW_PERMISSIVE_SELINUX) {
return StatusFromProperty() == SELINUX_ENFORCING;
}
编译刷机,开机后可以看到MT Manager安装成功,也能正常打开。
后记
正如文章开头所说,此方法是不完美的,但是某些场景下也是可用的。
后面在分析完PackageManagerService之后,我们会介绍另一种比较标准的内置可卸载应用的方法,请内心等待。