[RK3568][Android12.0]--- 系统自带预置第三方APK方法

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<String> list = new ArrayList<String>();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 parallelint fileCount = 0;for (File file : files) {final boolean isPackage = (isApkFile(file) || file.isDirectory())&& !PackageInstallerService.isStageName(file.getName());if (!isPackage) {// Ignore entries which are not packagescontinue;}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 appscontinue;}}}parallelPackageParser.submit(file, parseFlags);fileCount++;}// Process results one by onefor (; 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 namesif (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 appsif ((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
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/192611.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[SIGGRAPH2023-best]3D Gaussian Splatting for Real-Time Radiance Field Rendering

标题&#xff1a;3D Gaussian Splatting for Real-Time Radiance Field Rendering 链接&#xff1a;https://arxiv.org/pdf/2308.04079.pdf 本文提出了一种基于3D高斯体进行场景重建的方案&#xff0c;并提供了高效的渲染器实现。其重建精度&#xff0c;训练速度和推理速度均…

社区分享|杭银消费金融基于MeterSphere开展接口自动化测试

杭银消费金融有限公司&#xff08;以下简称“杭银消费金融”&#xff09;成立于2015年12月&#xff0c;是经中国银保监会批准&#xff0c;由杭州银行作为主发起人&#xff0c;联合滴滴出行、中国银泰等企业组建的持牌消费金融机构&#xff0c;注册资本为25.61亿元。杭银消费金融…

【C语法学习】23 - strlen()函数

文章目录 1 函数原型2 参数3 返回值4 示例4.1 示例1 1 函数原型 strlen()&#xff1a;计算指针str所指向的字符串的长度&#xff0c;函数原型如下&#xff1a; size_t strlen(const char *str);2 参数 strlen()函数只有一个参数str&#xff1a; 参数str是指向待计算长度的字…

Web安全:Vulfocus 靶场搭建.(漏洞集成平台)

Web安全&#xff1a;Vulfocus 靶场搭建.&#xff08;漏洞集成平台&#xff09; Vulfocus 是一个包含了多种漏洞靶场的镜像。每个靶场都有具体的漏洞环境和攻击点。Vulfocus 的靶场包括了 Web 安全漏洞、系统安全漏洞、网络安全漏洞、密码学漏洞等多种类型。通关这个靶场我们可以…

Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks - 翻译学习

知识密集型NLP任务的检索增强生成 - 论文学习 文章目录 Abstract1 Introduction2 Methods2.1 Models2.2 Retriever: DPR2.3 Generator: BART2.4 Training2.5 Decoding 3 Experiments3.1 Open-domain Question Answering3.2 Abstractive Question Answering3.3 Jeopardy Questio…

十方影视后期“领进门”,成长与成就还得靠自身

在这个充满视觉冲击的时代&#xff0c;影视后期制作已经成为了一种炙手可热的艺术形式。而在这个领域&#xff0c;Adobe After Effects&#xff08;AE&#xff09;这款软件无疑是王者之一。十方影视后期作为十方教育科技旗下的艺术设计学科&#xff0c;不仅培养了数万名优秀的后…

Windows如何正确设置PHP环境变量以在Git Bash中运行命令

1、随便找一个目录&#xff0c;鼠标右键打开git bash here 2、cd的根目录 3、找到php安装目录 4、 在根目录下打开 vim .bash_profile &#xff0c;添加环境变量&#xff0c;php地址根据自己的本地地址而定 PATH$PATH:/d/phpstudy_pro/Extensions/php/php7.3.4nts 添加后保存…

算法笔记——递归(1)

这里写目录标题 递归的思想序列求最大值翻转字符串斐波那契数列数塔回文字符串上楼汉诺塔棋盘覆盖问题数字螺旋矩阵盒分形 递归的思想 子问题须与原始问题为同样的事&#xff0c;且更为简单。 不能无限制地调用本身&#xff0c;须有个出口&#xff0c;化简为非递归状况处理 序…

【原创】java+swing+mysql车辆维修管理系统设计与实现

摘要&#xff1a; 车辆维修管理系统是一个用于管理和追踪车辆维修过程的系统&#xff0c;它能够提高效率&#xff0c;减少错误&#xff0c;并提供详细的车辆历史记录&#xff0c;可以帮助车辆维修企业实现信息化管理&#xff0c;提高工作效率和客户满意度&#xff0c;降低运营…

系列八、Mybatis一对多查询,只查询出了一条记录

一、Mybatis一对多查询&#xff0c;只查询出了一条记录 1.1、问题说明 典型的权限管理框架的数据库表中&#xff0c;一般会存在这样3种角色的表&#xff0c;即用户表、角色表、用户角色关联表&#xff0c;表设计好之后&#xff0c;往这三张表中初始化了一些测试数据&#xff0…

在抖音电商,他们帮女性实现了L码自由

“很多&#xff08;女装&#xff09;店铺只做到L&#xff0c;甚至L&#xff08;其实&#xff09;是M码。”身高1米6、体重60公斤的达人鸭嗓明明120斤 在抖音上吐槽道&#xff0c;“尤其是夏天的连衣裙&#xff0c;胸围很多不超过85厘米&#xff0c;那它的意思就是你可以胖&…

Elasticsearch docker-compose 使用 Logstash 从 JSON 文件中预加载数据

在我们创建 Elasticsearch 进行开发时&#xff0c;最简单的办法就是在本地使用 docker-compose 来一键部署一个 Elasticsearch 集群。有时&#xff0c;特别是在准备测试环境时&#xff0c;开发人员希望从一开始就创建包含一些测试数据的数据库容器。我们可以使用 Logstash 来很…

3分钟带你了解前端缓存-HTTP缓存

前情提要 前端缓存分为下面三大类&#xff0c;本文主要讲解HTTP缓存~ 1. HTTP缓存 强缓存协商缓存 2. 浏览器缓存 本地小容量缓存本地大容量缓存 3. 应用程序缓存 HTML5应用程序缓存 缓存作用 减少了冗余的数据传输减少服务器的负担提高了网站的性能加快加载网页速度 …

IDEA 2023搭建 SpringMVC +FreeMarker+JDBC

1.IDEA的版本&#xff0c;目前最新是2023&#xff0c;要选择旗舰版。笔者曾选择社区版&#xff0c;发现少了很多功能。只能重新安装。 2.安装好以后的第1件事&#xff0c;是设置Maven&#xff0c;并将下载地址改为淘定站&#xff0c;参照这篇一次包会——最新IDEA配置Maven指南…

嵌入式LINUX——环境搭建 windows、虚拟机、开发板 互ping

摘要&#xff1a; 本文包含&#xff0c;如何设置linux开发板和虚拟机、windows 互ping成功 以及设置过程中出现的虚拟机、开发板查询不到eth0 windows ping开发板出项丢包等问题的解决方式。 windows端设置 windows端插入USB转网卡 打开windows桌面下右下角的网络标识 打…

51单片机+DS1302设计一个电子钟(LCD1602显示时间)

一、前言 电子钟是一种能够准确显示时间的设备&#xff0c;广泛应用于家庭、办公场所和公共场所&#xff0c;为人们提供了方便和准确的时间信息。本项目设计一个基于51单片机的电子钟&#xff0c;使用DS1302作为RTC时钟芯片&#xff0c;LCD1602作为显示屏&#xff0c;并通过串…

uniapp开发ios上线(在win环境下使用三方)

苹果 1、win环境下无法使用苹果os编译器所以使用第三方上传工具&#xff0c;以下示例为 初雪云 &#xff08;单次收费&#xff0c;一元一次&#xff09; 初雪云&#xff08;注册p12证书&#xff09;&#xff1a;https://www.chuxueyun.com/#/pages/AppleCertificate 苹果开发者…

Postman常见报错与解决方法,持续更新~

postman中文文档 基本操作&#xff1a;从控制台查看请求报错 如果 Postman 无法发送你的请求&#xff0c;或者如果它没有收到你发送请求的 API 的响应&#xff0c;你将收到一条错误消息。此消息将包含问题概述和指向控制台的链接&#xff0c;你可以在其中访问有关请求的详细信…

Visual Studio Code安装和设置中文

文章目录 Visual Studio Code安装Visual Studio Code设置中文 步骤如下: Visual Studio Code安装 1.下载安装包 VS Code的官网 下载链接中的“az764295.vo.msecnd.net” 替换为国内镜像地址“vscode.cdn.azure.cn”&#xff0c;下载速度直接飙升至几十 Mb/s。(在官网下载速度…

【OpenCV(3)】linux arm aarch 是 opencv 交叉编译与使用

文章目录 1、直接找github 别人编译好的2、自主编译参考 3使用CMake检查 参考 1、直接找github 别人编译好的 测试很多&#xff0c;找到一个可用的。 https://github.com/dog-qiuqiu/libopencv 它用了超级模块&#xff01; OpenCV的world模块也称为超级模块&#xff08;supe…