Android 源码集成可卸载 APP

android系统包含三类APP: 1、可自由卸载APP安装在 /data/app目录下。 2、系统APP放在 /system/app目录。 3、特权APP放在 /system/priv-app目录。

系统编译后,打包前, /data分区不起作用,因此系统打包前,可以先将APP全部拷贝到 /system分区的 /system/usr/app目录下。

1、拷贝APP暂存到 /system/usr/app 目录

在 /build/target/product/base_product.mk中添加如下命令, 会将 /apps/apps目录下的所有文件拷贝到 /system/usr/app ,将 shell脚本拷贝到 /system/bin目录

bash 复制代码
# 拷贝APP
PRODUCT_COPY_FILES += $(call find-copy-subdir-files,*,/data1/rom/android/lineageOS2/apps/apps,/system/usr/app)
# 拷贝shell
PRODUCT_COPY_FILES += $(call find-copy-subdir-files,*,/data1/rom/android/lineageOS2/apps/shell,/system/bin)

2、绕过拷贝 .apk文件时校验

注释 /build/core/Makefile 如下 apk拷贝报错代码

bash 复制代码
define check-product-copy-files
$(if $(filter %.apk, $(1)),$(error \
    Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))
endef

3、系统启动执行init.rc脚本时,拷贝APP到 /data分区

在 init.rc文件中定义如下service , 并在 on boot 事件中 执行 preinstall

bash 复制代码
service preinstall /system/bin/preinstall.sh
    class main
    user root
    group root
    oneshot
 
 
on boot
    xxxxx
    xxxxx
    .....
    start preinstall

4、shell 脚本文件如下

bash 复制代码
#!/system/bin/sh
 
CUSTOMIZED_APK=/system/usr/app
DATA_APK=/data/app
 
echo "CUSTOMIZED_APK=${CUSTOMIZED_APK}"
#获取是否已经预安装过标记位
PREINSTALL_RESULT=`getprop persist.sys.preinstall.value`
echo "PREINSTALL_RESULT=${PREINSTALL_RESULT}"
apk_files=""
#判断标记位是否为空,为空则没有预装过。然后将所有apk均copy到data/app下面。
 
if [ -z "${PREINSTALL_RESULT}" ]; then
 
cd ${CUSTOMIZED_APK}
 
apk_files=$(ls *.apk )
 
echo "apks files = ${apk_files}"
 
for apkfile in $apk_files
 
do
 
echo " apkfiles = ${apkfile} "
 
cp -vf ${CUSTOMIZED_APK}/${apkfile} ${DATA_APK}/${apkfile}
 
echo "start copy "
 
chmod 777 ${DATA_APK}/${apkfile}
 
done
 
#设置标记位
setprop persist.sys.preinstall.value 1
 
 
# 拷贝 设备改机文件
cp /system/etc/device.json /data/system/device.json
chmod 666 /data/system/device.json
# 拷贝adb公钥
cp /system/etc/adb_keys /data/system/adb_keys
chown -R shell:shell /data/system/adb_keys
chmod 666 /data/system/adb_keys
 
cd ../..
 
fi

5、添加selinux权限

file_contexts文件: system/sepolicy/private/file_contexts 添加下面一行:

bash 复制代码
/system/bin/preinstall.sh  u:object_r:preinstall_exec:s0

同目录新建文件 preinstall.te 内容如下:

bash 复制代码
type preinstall, domain;
type preinstall_exec, exec_type, file_type;
 
init_daemon_domain(preinstall)
#全部默认允许
permissive preinstall;

修改 init.te 允许读取并执行 preinstall:

bash 复制代码
#默认全部允许
allow init preinstall_exec:file {read open getattr execute};

android 11 系统 在 system/sepolicy/prebuilts/api/30.0/private 目录同步修改

TODO

最后一次拉取的android11源码 将 apk拷贝到 /data/app目录后开机没有扫描安装,原因待分析

FIXED :

在 PackageManagerService. assertPackageIsValid 方法中 ,如下代码段:

java 复制代码
// If we're only installing presumed-existing packages, require that the
// scanned APK is both already known and at the path previously established
// for it.  Previously unknown packages we pick up normally, but if we have an
// a priori expectation about this package's install presence, enforce it.
// With a singular exception for new system packages. When an OTA contains
// a new system package, we allow the codepath to change from a system location
// to the user-installed location. If we don't allow this change, any newer,
// user-installed version of the application will be ignored.
if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
    if (mExpectingBetter.containsKey(pkg.getPackageName())) {
        logCriticalInfo(Log.WARN,
                "Relax SCAN_REQUIRE_KNOWN requirement for package "
                        + pkg.getPackageName());
    } else {
        PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName());
        if (known != null) {
            if (DEBUG_PACKAGE_SCANNING) {
                Log.d(TAG, "Examining " + pkg.getCodePath()
                        + " and requiring known paths " + known.codePathString
                        + " & " + known.resourcePathString);
            }
            if (!pkg.getCodePath().equals(known.codePathString)
                    || !pkg.getCodePath().equals(known.resourcePathString)) {
                throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
                        "Application package " + pkg.getPackageName()
                        + " found at " + pkg.getCodePath()
                        + " but expected at " + known.codePathString
                        + "; ignoring.");
            }
        } else {
            // throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
            //         "Application package " + pkg.getPackageName()
            //         + " not found; ignoring.");
        }
    }
}

注释掉 INSTALL_FAILED_INVALID_INSTALL_LOCATION 异常。

同时,修改selinux权限: untrusted_app_all 增加 execute 权限:

bash 复制代码
#允许app读取/data/system目录文件 允许app 执行 data/app-libm目录下的可执行文件
allow untrusted_app_all system_data_file:file { open read execute};
相关推荐
Dnelic-36 分钟前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen3 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年10 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿13 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神14 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛14 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法15 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
NotesChapter16 小时前
Android吸顶效果,并有着ViewPager左右切换
android
_祝你今天愉快17 小时前
分析android :The binary version of its metadata is 1.8.0, expected version is 1.5.
android
暮志未晚Webgl17 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5