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};
相关推荐
松仔log1 小时前
Java中级——组合和继承
android·java·开发语言
我命由我123454 小时前
Jetpack Compose - MaterialExpressiveTheme 与 MaterialTheme、ColorScheme
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
lilian2335 小时前
Harmony os 技术实战|拼豆制图06:收藏 ID、生成记录与重启恢复怎么不打架
android·java·数据库·harmonyos
2601_955759625 小时前
ClaudeAPI成本中心与业务标签设计指南
android·java·数据库
余衫马5 小时前
2026最新版!Android Studio 极速安装与配置指南
android·ide·android studio
AFinalStone5 小时前
Android 7系统异常问题排查(五)Framework层(下)—System Server崩溃
android·tombstone·系统异常
AFinalStone5 小时前
Android 7系统异常问题排查(八)系统追踪—Trace机制与性能诊断
android·系统异常
极客猴子9 小时前
Android录音转写频繁卡顿?多款APP长时间会议场景稳定性实测
android·人工智能·智能手机·飞书
Kapaseker9 小时前
Boolean 变量到底该怎么命名?
android·kotlin
AFinalStone9 小时前
Android 7系统异常问题排查(六)应用异常(上)—ANR机制全解
android·系统异常