Android 系统应用重名install安装失败分析解决

news/2024/12/15 15:17:08/

Android 系统应用重名install安装失败分析解决

文章目录

  • Android 系统应用重名install安装失败分析解决
    • 一、前言
      • 1、Android Persistent apps 简单介绍
    • 二、系统 persistent 应用直接安装需求分析解决
      • 1、系统应用安装报错返回的信息
      • 2、分析解决
    • 三、其他
      • 1、persistent系统应用install安装调试小结
      • 2、安装persistent系统应用报错在系统源码中简要分析
        • (1)logcat 过滤查看安装apk相关日志:
        • (2)安装失败报错的具体代码位置
      • 3、Android Studio 直接安装persistent系统应用报错分析处理
        • (1) Android Studio 中弹框显示的错误
      • (2)app\build.gradle 适配
        • (3)修改 applicationId
        • (4)dumpsys package 验证安装的apk
      • 4、Android14 Bluetooth系统蓝牙应用调试
        • (1)查看蓝牙应用的安装目录
        • (2)apex目录apk 无法直接替换!
        • (4)蓝牙应用可以直接install 安装成功
        • (5)dumpsys 查看蓝牙应用安装替换情况
      • 5、系统应用设置 persistent="true" 的作用
      • 5、判断应用是否是persistent类型的系统应用
        • (1)AndroidManifest.xml 代码判断签名和属性
        • (2)应用apk文件反编译分析
        • (3)运行环境dumpsys package分析
      • 6、普通应用设置 persistent="true" 有用吗?

一、前言

系统开发过程中,你会发现一些系统应用编译后无法直接安装成功,为啥?
具体是为啥导致无法正常安装?如果要正常安装需要怎么处理?

刚开始我以为是系统应用重名不能直接安装,但是发现有些系统应用是可以直接安装的;
所以还是要研究看看。

本文简单分析解决一下这个问题!

后面复现关键就是 Android 的 persistent 属性,
persistent(翻译:持久的) 属性是系统应用用来保活的应用和服务的。

声明了 android:persistent="true"的系统应用就表示该应用是持久的,无法进行安装。

这种持久系统应用情况,除了替换apk重启或者编译系统大包,如何才能直接替换安装apk调试呢?

下面进行分析一下。这个对系统应用的调试有一定的帮助作用。

1、Android Persistent apps 简单介绍

Persistent apps(持久化应用)是指那些被标记为具有android:persistent="true"属性的应用;
这个属性是定义的AndroidManifest.xml 的 application 标签中;
这种应用一般是系统应用,该进程在系统运行过程中会被特殊对待,kill掉后马上会被系统拉起;

目前系统一些Persistent apps 应用:

系统核心服务应用:SystemUI,输入法框架
关键通信和同步应用:电话应用,短信应用,同步服务应用
还有一些自定义的关键应用

简单的定义 persistent 属性的代码:

    <applicationandroid:name=".base.MyApplication"...android:persistent="true" //持久化android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/SettingsDialog"tools:replace="android:appComponentFactory">

如果未定义persistent属性,就是默认的false。普通应用都是未定义这个属性的。

如果普通应用定义这个属性为true,会发生什么呢?最后结论有揭晓。

二、系统 persistent 应用直接安装需求分析解决

并不是Android的所有系统应用都是无法install 安装,
有部分应用是可以直接install安装的,
无法直接install安装的应用,除了 persistent 这种情况,
可能还有其他情况,比如版本兼容,版本号定义等情况,下面只是针对persistent这种情况进行分析处理。

1、系统应用安装报错返回的信息

C:\Users\As11040>adb install E:\Android14\311D2\apk\DebugSystemUI\DebugSystemUI.apk
Performing Streamed Install
adb: failed to install E:\Android14\311D2\apk\DebugSystemUI\DebugSystemUI.apk: 
Failure [INSTALL_FAILED_INVALID_APK: Package com.debug.SystemUI is a persistent app. Persistent apps are not updateable.]C:\Users\As11040>

这里可以看到报错提示是:Persistent apps 无法更新。

那咋搞?下面就提供一些调试persistent应用的思路。

2、分析解决

下面给出三种解决方案:

第一种方法(每次重启):系统remount后,替换DebugSystemUI后,重启就会自动安装替换;
第二种方法(不用重启):Android Studio 修改DebugSystemUI的包名,编译这个 应用,修改包名后,就可以安装调试;
第三种方法(重启一次):去除系统应用代码的persistent属性,重新编译,按照第一种方法替换apk后,后面不用修改应用的包名,就可以直接安装替换apk调试。

上面看起来好像没有一种是非常简单的。实际开发中,调试系统应用可能还会更麻烦。

下面对比一下几种调试手段:

第一种调试方法:比较保守,大部分系统开发的都是这样处理的;这种调试方法适用于次数较少,简单代码修改的调试;每次都要重启比较麻烦耗时。第二种调试方法:Android Studio 中重命名应用包名 applicationId "com.debug.settings2",不用修改其他包名相关的地方,就可以直接安装了;这种调试方法适用于次数较多或者复杂的代码修改的调试;但是这种方法不一定适用于所有应用,自定义开发的应用比较好适配,可以直接用Studio编译;有些系统应用不一定能导入到Android Studio中进行编译,或者要适配过程是非常麻烦的;系统应用还有导入系统签名,系统framework包和其他相关包;如果是非常麻烦的情况就没必要搞了,有些情况不一定能搞得定。第三种调试方法:这种方法比较中和;如果既要多次修改,又无法使用Android Studio 进行编译代码的情况;第三种调试方法没有用到Android Studio,源码编译就行。

具体情况,使用具体方式就行调试吧。怎么方便怎么搞就行。

上面其实就是说了一下persistent系统应用无法直接安装,
具体要怎么调试就看当时的调试条件了。

三、其他

1、persistent系统应用install安装调试小结

系统代码中限制了persistent的系统应用无法进行直接安装调试;
大概是因为persistent是一直运行的,无法stop或者kill;
如果要调试安装persistent系统应用,大概有三种方法:

(1)替换系统应用apk,重启
(2)把apk源码弄到Android Studio中,修改包名后,直接安装
(3)去系统应用的persistent属性,替换重启后,后面安装调试就不用每次重启了

第二种方法看起来比较简单,虽然不用remount设备,但是有些大型应用适配是非常麻烦的;
第一种和第三种方法都是要解锁设备,remount后才能执行的;
第三种方法是比较简单方便多次调试的。

2、安装persistent系统应用报错在系统源码中简要分析

上面是解决了调试问题,但是不妨分析一下系统源代码,加深一下印象。

(1)logcat 过滤查看安装apk相关日志:
//这里过来安装或者应用管理相关日志信息
console:/ # logcat | grep -i -E "install|PackageManager"12-10 18:25:08.591 32730 32730 I abb     : StartCommandInProcess(7061636b61676500696e7374616c6c00 package.install. [truncated])
12-10 18:25:08.794   891   955 E PackageManager: No required verifiers
12-10 18:25:08.815   891   955 I PackageManager: Integrity check passed for file:///data/app/vmdl1963375571.tmp
//源码代码中报错的信息:
12-10 18:25:08.828   891   955 W PackageManager: Package com.skg.SystemUI is a persistent app. Persistent apps are not updateable.
//返回到cmd窗口中打印的信息:
12-10 18:25:08.831   891   955 D PackageInstallerSession: Marking session 1963375571 as failed: 
INSTALL_FAILED_INVALID_APK: Package com.skg.SystemUI is a persistent app. Persistent apps are not updateable.

从上面大致可以看到报错的信息,
然后就可以从源码中看看具体发生错误的具体代码位置。

查找过程就不展开说明了,可以源码中grep找到关键字筛选可能的位置。

(2)安装失败报错的具体代码位置

Android14 源码:

framework/base/services/core/java/com/android/server/pm/InstallPackageHelper.java


final class InstallPackageHelper {private final PackageManagerService mPm;...@GuardedBy("mPm.mInstallLock")private void preparePackageLI(InstallRequest request) throws PrepareFailure {final int installFlags = request.getInstallFlags();final boolean onExternal = request.getVolumeUuid() != null;...// Prevent persistent apps from being updatedif (oldPackage.isPersistent()&& ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,"Package " + oldPackage.getPackageName() + " is a persistent app. "+ "Persistent apps are not updateable.");}...

从上面Java代码确实看到了logcat中的报错信息。
上面逻辑看到是安装应用的时候判断了isPersistent()和 installFlags 后就抛出这个异常错误。

isPersistent() 方法很容易理解就是是否定义了 persistent属性的应用;
installFlags 属性应该是一些列属性相关的值,比如是否系统应用,系统签名都是相关的,
这里不继续进行分析,有兴趣的可以看看。

3、Android Studio 直接安装persistent系统应用报错分析处理

这个相当于接上面第二种调试方法展开说明一下。

(1) Android Studio 中弹框显示的错误
Error running 'app' The application could not be installed:
INSTALL_FAILED_INVALID_APK The APKs are invalid. List of apks: [0]
'E:\Studio\project\Android14_311D2\DebugSettings\app\build\intermediates\apk\debug\app-debug.apk

从上面查看并未发现为啥报错,只显示了apk不可用!
哈哈,这种情况咋分析?

其实还得看logcat日志,同样的过滤install|PackageManager是可以看到persistent应用无法替换的错误提示。

这里介绍一下,修改Android Studio 系统应用包名的处理。

(2)app\build.gradle 适配

原本的包名定义:

android {namespace 'com.debug.settings'compileSdk 34defaultConfig {applicationId "com.debug.settings"minSdk 30targetSdk 34versionCode 1versionName "1.0"}//系统签名、证书信息在这里配置}...

上面可以看到有个namespace 和 applicationId 都是定义的应用包名。
其中 namespace 是跟系统资源绑定的,不能随便改,
如果要修改namespace,Java代码里面的定义都要修改,否则会报错;

applicationId 是一个封装的包名,可以随便修改!

(3)修改 applicationId

如果要重新安装这个系统应用的封装包名,修改applicationId 的包名就行:

applicationId "com.debug.settings2"

安装调试发现,会重新生成另外一个 com.debug.settings2 包名的应用,之前的应用是不影响。

(4)dumpsys package 验证安装的apk

同时dumpsys package 查看也是验证查看这个新的包名:


IWB:/ $ dumpsys package com.debug.settings | grep pathpath: /system/priv-app/DebugSettings/DebugSettings.apk
IWB:/ $
IWB:/ $ dumpsys package com.debug.settings2 | grep pathpath: /data/app/~~w3MWD86p2cPawWc2MJun7A==/com.debug.settings2-S3W73_reyyTmvIiB-Vaggg==/base.apkIWB:/ $ dumpsys package com.debug.settings2 | grep versionversionCode=1 minSdk=30 targetSdk=34versionName=3.0
IWB:/ $

从上面日志看,第一次dumps 这个应用的包名和路径是 system 目录的;
安装系统应用后,重新dumpsys 这个应用的包名和路径是data 目录下的;
说明这个系统应用是安装上去的。还可以查看version 或者time 确认。

另外要注意的是:

在Android Studio编译的apk version版本是在app\build.gradle 里面定义使能的,
AndroidManifest.xml定义是没用的,会被覆盖!

4、Android14 Bluetooth系统蓝牙应用调试

蓝牙应用可能调试的人不多,我之前是偶尔要调试的;
但是发现蓝牙apk应用无法替换,因为Android14 开始有些应用是apex目录下的,无法remount这个目录!
所以一般都是编译整个大包进行调试的;
但是通过上面的知识了解后,发现蓝牙apk是可以直接install的,
以前白走了冤枉路,所以有更多知识储备是很有必要的,虽然有时候不一定马上用得上。

下面就是分析系统蓝牙应用的安装替换过程:

(1)查看蓝牙应用的安装目录
console:/ # dumpsys package com.android.bluetooth | grep pathpath: /apex/com.android.btservices/app/Bluetooth@UP1A.231105.001.B2/Bluetooth.apk

蓝牙apk 居然在apex目录!
这个是从Android14 开发才会这样的,有些模块系统放在了apex目录下;

Android13 或者更低的版本都是放在system或者system_ext目录下的。是可以解锁后替换apk的。

调试发现 apex 目录默认是不开放的,无法解锁替换!

(2)apex目录apk 无法直接替换!
C:\Users\As11040>adb root
restarting adbd as rootC:\Users\As11040>adb remount
Verity is already disabled
Remounted /system as RW
Remounted /system_ext as RW
Remounted /system_dlkm as RW
Remounted /vendor as RW
Remounted /product as RW
Remounted /odm as RW
Remounted /vendor_dlkm as RW
Remounted /odm_dlkm as RW
Remounted /oem as RW
Remount succeededC:\Users\As11040>adb shell
IWB:/ # cd /apex/com.android.btservices/app
IWB:/apex/com.android.btservices/app # mkdir aa
mkdir: 'aa': Read-only file system
1|IWB:/apex/com.android.btservices/app #
1|IWB:/apex/com.android.btservices/app # cd ../../..
IWB:/ # cd system/priv-app/
IWB:/system/priv-app # mkdir aa
IWB:/system/priv-app #

上面执行命令代码可以看到即使root和remount,也是无法获取到apex目录的修改权限。
adb push 是试过的,也是报错提示:Read-only file system
没有其他办法的情况,只能编译大包进行调试了。

但是通过上面的persistent知识,获取到了灵感,
感觉可以试试直接install看看是否报错,即使报错也是可以解决的。

####(3)查看蓝牙应用是否是 persistent 应用

系统蓝牙apk应用声明persistent情况:

release\packages\modules\Bluetooth\android\app\AndroidManifest.xml

   <!-- For PBAP Owner Vcard Info --><uses-permission android:name="android.permission.READ_PROFILE"/><application android:name="com.android.bluetooth.btservice.AdapterApp"android:icon="@mipmap/bt_share"android:persistent="false"android:label="@string/app_name"android:supportsRtl="true"android:usesCleartextTraffic="false"android:directBootAware="true"android:defaultToDeviceProtectedStorage="true"android:memtagMode="async">

这里查看蓝牙应用设置persistent为false,那么应该是可以直接安装的。
如果persistent为true,可以设置为false编译一次,后面就可以一直调试。

尝试直接安装是成功的:

(4)蓝牙应用可以直接install 安装成功
C:\Users\As11040>adb install Bluetooth.apk
Performing Streamed Install
Success

成功了,哈哈。

(5)dumpsys 查看蓝牙应用安装替换情况
console:/ # dumpsys package com.android.bluetooth | grep pathpath: /apex/com.android.btservices/app/Bluetooth@UP1A.231105.001.B2/Bluetooth.apkconsole:/ # dumpsys package com.android.bluetooth | grep pathpath: /data/app/~~zptgNMJxOrNyEASJFt3HKg==/com.android.bluetooth-KHInQ7LVcEAHQhjYOSEcJw==/base.apk
console:/ # 

从上面日志看,蓝牙应用确实是从系统应用,变成一个应该普通的install的应用。

这里蓝牙应用 persistent=“false” 是可以直接install 安装的关键。

这里讲解蓝牙只是一个参考,Android14 后面估计还会有很多系统应用会放到apex目录下,
比如nfc等,所以多学掉调试手段是有用的。

5、系统应用设置 persistent=“true” 的作用

确实起到了保活作用,
am force-stop 不会有反应,pid没变;应该是上层拦截了!但是看不到任何相关日志!

kill pid,后应用马上就又被拉起来了。

下面是一些命令调试验证日志:

130|console:/ # 
//(1)查看应用进程情况,包含进程id,父进程,启动时间,应用包名等信息
130|console:/ # ps -eff | grep com.skg.settings
system        6317  5441 0 11:01:28 ?     00:00:02 com.skg.settings//(2)强制停止应用
console:/ # am force-stop com.skg.settings
console:/ # 
//(3))强制停止后,查看进程信息是没有变化的
console:/ # ps -eff | grep com.skg.settings                                    
system        6317  5441 0 11:01:29 ?     00:00:02 com.skg.settings
console:/ # 
//(4)杀死进程id试试
console:/ # kill 6317
console:/ # 
//(5)杀死进程id后,进程是有重新启动的,会生成新的进程id
console:/ # ps -eff | grep com.skg.settings                       
system       20485  5441 10 11:28:12 ?    00:00:00 com.skg.settings
console:/ # 
//(6)杀死父进程id试试
console:/ # kill 5441
console:/ # 
//(7)杀死进程id后,父进程和进程都会重新生成,系统会黑屏一下,估计是系统上层重启了,
//所以最好不要杀父进程,有可能会导致系统重启,或者无法正常开机,一般断开上电可以恢复
console:/ # ps -eff | grep com.skg.settings
system       24353 23431 41 11:34:08 ?    00:00:01 com.skg.settings
console:/ # 

从上面日志看,
am force-stop 是无法停止应用的;
直接kill进程是可以杀死应用,但是马上就会重启启动新的进程;
所以

如果应用有继承Application,可以看到应用重开拉起来的时候有执行onCreate,可以重新初始化自己需要的东西。

上面说了那么多好像没说怎么从非代码手段判断一个应用是是否是 persistent的系统应用。
其实只要有apk或者运行环境,也是可以判断的。

5、判断应用是否是persistent类型的系统应用

下面从三个维度判断这个应用是否是persistent类型的系统应用,
源码下、应用apk文件、运行环境。

(1)AndroidManifest.xml 代码判断签名和属性
1、查看根目录是否声明了系统签名权限:android:sharedUserId="android.uid.system"
2、查看Application 是否声明了:persistent="true"
(2)应用apk文件反编译分析

apk咋判断?其实就是反编译,查看 AndroidManifest.xml 文件,这个和第一个方式类似。
大部分系统文件都是没有经过复杂混淆的,看AndroidManifest里面的基本信息是没啥问题的。

反编译工具命令就不展示了,其实Android Studio 就可以简单反编译,
把apk拖到一个Studio的项目,就会反编译看到AndroidManifest的内容:

简单示例如下:
uid信息:
在这里插入图片描述

persistent信息:
在这里插入图片描述

上面就相当于看到了源码的整个 AndroidManifest 的信息。
声明的权限、Acitivity和Service那些四大组件信息都是有的,想看啥就看啥。

(3)运行环境dumpsys package分析

dumpsys package 可以看到应用的很多具体信息,
比如签名情况,安装时间,安装路径,版本号,应用获取到的权限等信息,persistent 也是可以看到的。

下面是判断判断过滤appid和persistent的示例日志:

//1、查看系统uid签名的应用appid都是1000;flags里面查看是否有 PERSISTENT 属性
console:/ # 
console:/ # dumpsys package com.dubug.settings | grep -i -E "appid|persistent"appId=1000flags=[ SYSTEM DEBUGGABLE HAS_CODE PERSISTENT ALLOW_CLEAR_USER_DATA UPDATED_SYSTEM_APP TEST_ONLY ALLOW_BACKUP ]pkgFlags=[ SYSTEM DEBUGGABLE HAS_CODE PERSISTENT ALLOW_CLEAR_USER_DATA UPDATED_SYSTEM_APP TEST_ONLY ALLOW_BACKUP ]appId=1000appId=1000
console:/ # //2、查看蓝牙应用,可以看到是不是uid签名,其实是bluetooth签名,也没有PERSISTENT属性
console:/ # dumpsys package com.android.bluetooth | grep -i -E "appid|persistent"appId=1002appId=1002appId=1002
console:/ # 
//3、查看一个普通应用,appId id不是1000,有没有PERSISTENT已经不重要了!
console:/ # dumpsys package com.demo.listdemo | grep -i -E "appid|persistent"appId=10070
console:/ # 
console:/ # 
//后面尝试在普通应用加入persistent="true"声明,在apk的flags里面也是未发现有PERSISTENT属性标签,
//说明PERSISTENT属性生效是有一定条件的,比如需要系统签名权限。

6、普通应用设置 persistent=“true” 有用吗?

其实没啥用,我试过了。可以直接安装,,不会安装失败,也不会保活。
这个应该就是 InstallPackageHelper.java里面判断了是否系统应用,否则这个persistent属性没啥意义。

本文只是想说系统应用声明persistent="true"会导致无法直接安装,没想到附带了这么多小知识。


http://www.ppmy.cn/news/1555327.html

相关文章

HTML和JavaScript实现简单OA系统

下面是一个包含登录页面和人事管理功能的简单OA系统示例。这个系统使用HTML和JavaScript实现。 1.页面展示 登录页面 首先&#xff0c;我们创建一个简单的登录页面。 OA系统页面 接下来是登录成功后的OA系统页面&#xff0c;包含新增、删除、修改公司人员的基本信息等功能…

jenkins pipeline打包流程

Jenkins Pipeline 是 Jenkins 提供的一种用于持续集成和持续交付&#xff08;CI/CD&#xff09;的脚本化流程工具。它允许你通过编写一个 Jenkinsfile 文件来定义整个构建、测试和部署的流程。本文介绍打包springcloud项目&#xff0c;react项目为docker镜像 文章目录 1.项目结…

外卖开发(九)——Excel数据报表ApachePOI

外卖开发&#xff08;九&#xff09;——Excel数据报表 一、ApachePOI二、入门案例三、导出运营数据报表1、ReportController2、ReportService 一、ApachePOI Apache POl是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是&#xff0c;我们可以使用POI在Java程…

LabVIEW面向对象编程有什么特点?

LabVIEW面向对象编程&#xff08;OOP&#xff09;的特点主要体现在它如何结合传统面向对象编程&#xff08;OOP&#xff09;的理念与LabVIEW的图形化编程模式&#xff0c;提供灵活的抽象和模块化的功能。以下是LabVIEW面向对象编程的几个主要特点&#xff1a; ​ 1. 类&#x…

在ArcGISPro中创作精美地图

建议从数据下载到最后的出图都跟着走一下&#xff0c;提供了一个完整且全面的教程&#xff0c;建议从数据下载开始&#xff0c;这样可以对ArcGISPro制图流程有一个全面的感触和认知。 1. 绘制北极海冰地图 20 世纪&#xff0c;气候变化导致极地海冰迅速减少。 自 1978 年以来…

Jetpack Compose赋能:以速破局,高效打造非凡应用

Android Compose 是谷歌推出的一种现代化 UI 框架&#xff0c;基于 Kotlin 编程语言&#xff0c;旨在简化和加速 Android 应用开发。它以声明式编程为核心&#xff0c;与传统的 View 系统相比&#xff0c;Compose 提供了更直观、更简洁的开发体验。以下是对 Android Compose 的…

android studio kotlin 本地c++工程添加oboe库的方法

1.新建本地c++的kotlin工程hellohao 如图 2.把开源的oboe源文件src、include、CMakelists.txt、debug-utils复制hellohao目录下 3.修改hellohao\app目录下的CMakelists.txt cmake_minimum_required(VERSION 3.22.1) project(hellohao LANGUAGES C CXX)get_filename_component…

从YOLOv5到训练实战:易用性和扩展性的加强

文章目录 前言一、模型介绍二、YOLOv5网络结构1.Input&#xff08;输入端&#xff09;&#xff1a;智能预处理与优化策略2.Backbone&#xff08;骨干网络&#xff09;&#xff1a;高效特征提取3.NECK&#xff08;颈部&#xff09;&#xff1a;特征增强与多尺度融合4.Prediction…