[RK3568][Android12.0]

您所在的位置:网站首页 内置卸载app [RK3568][Android12.0]

[RK3568][Android12.0]

2024-07-13 11:27| 来源: 网络整理| 查看: 265

Platform: RK3568 OS: Android 12.0 Kernel: 4.19

Rockchip默认提供了机制来预置第三方APK, 方法很简单: 1. 在device/rockchip/rk3568创建preinstall目录(如果要可卸载,那就创建preinstall_del目录) 2. 将你要预安装的APK放进此目录即可

preinstall 不可卸载

preinstall_del 可卸载,回复出厂可恢复

preinstall_del_forever 可卸载 恢复出厂不可恢复

下面看下实现原理过程: device/rockchip/common/device.mk中有:

# Prebuild apps $(call inherit-product, device/rockchip/common/modules/preinstall.mk)

 device\rockchip\common\modules\preinstall.mk

# Include this makefile to support prebuild apps ifneq ($(strip $(TARGET_PRODUCT)), ) $(shell python device/rockchip/common/auto_generator.py $(TARGET_DEVICE_DIR) preinstall bundled_persist-app $(TARGET_ARCH)) $(shell python device/rockchip/common/auto_generator.py $(TARGET_DEVICE_DIR) preinstall_del bundled_uninstall_back-app $(TARGET_ARCH)) $(shell python device/rockchip/common/auto_generator.py $(TARGET_DEVICE_DIR) preinstall_del_forever bundled_uninstall_gone-app $(TARGET_ARCH)) -include $(TARGET_DEVICE_DIR)/preinstall/preinstall.mk -include $(TARGET_DEVICE_DIR)/preinstall_del/preinstall.mk -include $(TARGET_DEVICE_DIR)/preinstall_del_forever/preinstall.mk endif

auto_generator.py是个python脚本,用于生成Android.mk和preinstall.mk文件,

def main(argv):     preinstall_dir = os.path.join(argv[1] + '/' + argv[2])     if os.path.exists(preinstall_dir):         #Use to define modules for install         makefile_path = preinstall_dir + '/Android.mk'         #Use to include modules         include_path = preinstall_dir + '/preinstall.mk'

        if os.path.exists(makefile_path):             os.remove(makefile_path)         if os.path.exists(include_path):             os.remove(include_path)

        makefile = file(makefile_path, 'w')         includefile = file(include_path, 'w')

        makefile.write("LOCAL_PATH := $(my-dir)\n\n")         for root, dirs, files in os.walk(preinstall_dir):             for file_name in files:                 p = re.compile(r'\S*(?=.apk\b)')                 found = p.search(file_name)                 if found:                     makefile.write(templet %(found.group(), argv[2]))                     includefile.write('PRODUCT_PACKAGES += %s\n' %found.group())         makefile.close()         includefile.close()

   

Android.mk用于制定编译规则,如我在preinstall目录下放了个AVSourceTester.apk,那么生成的文件内容是

LOCAL_PATH := $(my-dir)

include $(CLEAR_VARS) LOCAL_MODULE := AVSourceTester LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_PATH := $(TARGET_OUT)/preinstall LOCAL_SRC_FILES := $(LOCAL_MODULE)$(COMMON_ANDROID_PACKAGE_SUFFIX) LOCAL_CERTIFICATE := PRESIGNED LOCAL_DEX_PREOPT := false LOCAL_MODULE_TAGS := optional LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) include $(BUILD_PREBUILT)

preinstall.mk内容如下: PRODUCT_PACKAGES += AVSourceTester

编译系统之后,生成路径是 out/target/product/rk3568/system/preinstall/AVSourceTester/AVSourceTester.apk

系统开机之后会调用

frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java

preinstallThirdPartyAPK(packageParser,executorService,scanFlags); private void preinstallThirdPartyAPK(PackageParser2 packageParser, ExecutorService executorService,int scanFlags){ preinstallPrebundledpersist(packageParser,executorService,scanFlags); preinstallPrebundledUninstallBack(packageParser,executorService,scanFlags); preinstallPrebundledUninstallGone(packageParser,executorService,scanFlags); } private void preinstallPrebundledpersist(PackageParser2 packageParser, ExecutorService executorService,int scanFlags){ scanDirTracedLI(new File(BUNDLED_PERSIST_DIR), mDefParseFlags | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR | ParsingPackageUtils.PARSE_IS_PREINSTALL, scanFlags | SCAN_AS_PREINSTALL | SCAN_AS_SYSTEM, 0,packageParser, executorService); } private void preinstallPrebundledUninstallBack(PackageParser2 packageParser, ExecutorService executorService,int scanFlags){ scanDirTracedLI(Environment.getPrebundledUninstallBackDirectory(), mDefParseFlags | ParsingPackageUtils.PARSE_IS_PREBUNDLED_DIR, scanFlags | SCAN_AS_PREBUNDLED_DIR, 0,packageParser, executorService); } private void preinstallPrebundledUninstallGone(PackageParser2 packageParser, ExecutorService executorService,int scanFlags){ scanDirTracedLI(Environment.getPrebundledUninstallGoneDirectory(), mDefParseFlags | ParsingPackageUtils.PARSE_IS_PREBUNDLED_DIR, scanFlags | SCAN_AS_PREBUNDLED_DIR, 0,packageParser, executorService); } private static final String BUNDLED_PERSIST_DIR = "/odm/bundled_persist-app"; private static final String BUNDLED_UNINSTALL_GONE_DIR = "/odm/bundled_uninstall_gone-app"; private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime, PackageParser2 packageParser, ExecutorService executorService) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]"); try { scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime, PackageParser2 packageParser, ExecutorService executorService) { final File[] files = scanDir.listFiles(); if (ArrayUtils.isEmpty(files)) { Log.d(TAG, "No files in app dir " + scanDir); return; } if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags + " flags=0x" + Integer.toHexString(parseFlags)); } ArrayList list = new ArrayList(); boolean isPrebundled = (parseFlags & ParsingPackageUtils.PARSE_IS_PREBUNDLED_DIR) != 0; if (isPrebundled) { synchronized (mPackages) { mSettings.readPrebundledPackagesLPr(); } } if (scanDir.getAbsolutePath().contains(BUNDLED_UNINSTALL_GONE_DIR)) { if (!readDeleteFile(list)) { Log.e(TAG, "read data failed"); return; } } ParallelPackageParser parallelPackageParser = new ParallelPackageParser(packageParser, executorService); // Submit files for parsing in parallel int fileCount = 0; for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { // Ignore entries which are not packages continue; } if (file.getAbsolutePath().contains(BUNDLED_UNINSTALL_GONE_DIR)) { if (list != null && list.size() > 0) { final boolean isdeleteApk = isDeleteApk(file,parseFlags,list); if (isdeleteApk) { // Ignore deleted bundled apps continue; } } } parallelPackageParser.submit(file, parseFlags); fileCount++; } // Process results one by one for (; fileCount > 0; fileCount--) { ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); Throwable throwable = parseResult.throwable; int errorCode = PackageManager.INSTALL_SUCCEEDED; String errorMsg = null; if (throwable == null) { // TODO(toddke): move lower in the scan chain // Static shared libraries have synthetic package names if (parseResult.parsedPackage.isStaticSharedLibrary()) { renameStaticSharedLibraryPackage(parseResult.parsedPackage); } try { addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime, null); if (isPrebundled) { final PackageParser.Package pkg; try { pkg = new PackageParser().parsePackage(parseResult.scanFile, parseFlags); } catch (PackageParserException e) { throw PackageManagerException.from(e); } synchronized (mPackages) { mSettings.markPrebundledPackageInstalledLPr(pkg.packageName); } } } catch (PackageManagerException e) { errorCode = e.error; errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage(); Slog.w(TAG, errorMsg); } } else if (throwable instanceof PackageParserException) { PackageParserException e = (PackageParserException) throwable; errorCode = e.error; errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage(); Slog.w(TAG, errorMsg); } else { throw new IllegalStateException("Unexpected exception occurred while parsing " + parseResult.scanFile, throwable); } if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) { mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg); } // Delete invalid userdata apps if ((scanFlags & SCAN_AS_SYSTEM) == 0 && errorCode != PackageManager.INSTALL_SUCCEEDED) { logCriticalInfo(Log.WARN, "Deleting invalid package at " + parseResult.scanFile); removeCodePathLI(parseResult.scanFile); } } if (isPrebundled) { synchronized (mPackages) { mSettings.writePrebundledPackagesLPr(); } } }

 

关键函数是copyPackagesToAppInstallDir(),它会把preinstall目录下的安装文件copy到安装目录。 这样安装就成功了。

安装preinstall和preinstall_del的区别在于后者在安装完之后会删除系统目录下的apk,因此要是做了恢复出厂设置或者卸载动作,那就不能恢复了。

删除函数是deletePreinstallDir(),通过init中的ctl命令实现。

    private void deletePreinstallDir(File dir) {         String[] files = dir.list();         if (files != null) {             Slog.d(TAG, "Ready to cleanup preinstall");             SystemProperties.set("ctl.start", "preinst_clr");         }     }

不过在source code中并没有找到preinst_clr这个service,可以在init.rc中自己添加下, 参考的是 Nu3001/device_rockchip_rksdk

service preinst_clr /system/bin/preinstall_cleanup.sh     disabled     oneshot

preinstall_cleanup.sh这个文件默认是有的,本质是直接删除apk。

#!/system/bin/sh log -t PackageManager "Start to clean up /system/preinstall_del/" mount -o rw,remount -t ext4 /system rm system/preinstall_del/*.* mount -o ro,remount -t ext4 /system  



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3