背景

最近项目开发过程中用到安装apk的功能。把从服务器下载下来的apk安装到机器中。安装过程中遇到的问题记录一下。

问题

安装过程中提示解析软件包时出现问题。


说明:本文是针对运行的apk在Manifest中声明了systemuid。如果你的应用声明了"android.uid.system",而且也遇到了这个问题,恭喜你找到了本文。

android:sharedUserId="android.uid.system"

没有声明的小伙伴可以去找别的博客了。

安装apk

首先回顾一下安装的方法,android O中大家一般这样写的。

private void installApk(String path){Intent intent = new Intent(Intent.ACTION_VIEW);Uri uri = FileProvider.getUriForFile(context,"com.****.****.fileprovider",new File(path));intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);intent.setDataAndType(uri,"application/vnd.android.package-archive");context.startActivity(intent);}

然后再Manifest中声明provider

<providerandroid:authorities="com.honeywell.depponservice.fileprovider"android:name="android.support.v4.content.FileProvider"android:grantUriPermissions="true"android:exported="false"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/filepaths" /></provider>

在xml中建一个filepaths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-path path="." name="cmexternal" />
</paths>

这种方式是没问题的,但是关机问题出在了我的app声明了SYSTEM_UID。为什么这么说呢,下面继续讲。

原因

我就是按照上面的方法去安装apk,然而总是提示解析软件包时出现问题。第一反应是从服务器下载的安装包有问题,打开文件管理器,点击下载后的安装包。发现可以安装,那就说明不是安装包的问题。没办法看log吧。

03-27 18:15:16.005  1378  2744 W ActivityManager: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{f1ea483 11298:com.android.packageinstaller/u0a19} (pid=11298, uid=10019) that is not exported from UID 1000
03-27 18:15:16.006 11298 12569 W InstallStaging: Error staging apk from content URI
03-27 18:15:16.006 11298 12569 W InstallStaging: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{f1ea483 11298:com.android.packageinstaller/u0a19} (pid=11298, uid=10019) that is not exported from UID 1000
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.os.Parcel.readException(Parcel.java:2013)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.os.Parcel.readException(Parcel.java:1959)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.app.IActivityManager$Stub$Proxy.getContentProvider(IActivityManager.java:4758)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.app.ActivityThread.acquireProvider(ActivityThread.java:5860)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2530)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1783)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1396)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1249)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.content.ContentResolver.openInputStream(ContentResolver.java:969)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at com.android.packageinstaller.InstallStaging$StagingAsyncTask.doInBackground(InstallStaging.java:180)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at com.android.packageinstaller.InstallStaging$StagingAsyncTask.doInBackground(InstallStaging.java:174)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.os.AsyncTask$2.call(AsyncTask.java:333)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
03-27 18:15:16.006 11298 12569 W InstallStaging:    at java.lang.Thread.run(Thread.java:764)

第一眼看到log时感觉是权限问题,因为有Permission Denial:字样。检查了一遍读写外部存储权限都开了啊,安装未知应用权限也打开了。可还是不行,最后索性把selinux都给关了依旧不行。无限抓狂,总之无论怎么做总会打出上面的log。在各种百度谷歌后还没有解决。一脸无奈的继续看log,看还有什么有用信息没。诶,突然发现了一行log:

ActivityManager: For security reasons, the system cannot issue a Uri permission grant to content://com.***.***.fileprovider/cmexternal/PDADownload/pda_client(4).apk [user 0]; use startActivityAsCaller() instead

最终在确认代码没问题的情况下,放大招,去源码中找答案。搜一下“For security reasons, the system cannot issue a Uri permission grant to”这段log是哪里打出来的。进到framework/base下grep.

./services/core/java/com/android/server/am/ActivityManagerService.java:9078:                Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"

十几秒后还真给搜到了。打开AMS第9078行看看。
这段log是在int checkGrantUriPermissionLocked方法中打印的,看下代码

        // Bail early if system is trying to hand out permissions directly; it// must always grant permissions on behalf of someone explicit.final int callingAppId = UserHandle.getAppId(callingUid);if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {// Exempted authority for cropping user photos in Settings app} else {Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"+ " grant to " + grantUri + "; use startActivityAsCaller() instead");return -1;}}

如果你也被这个问题折磨的很痛苦,想必看到这段代码就明白原因了吧。
这尼玛被return -1了。这段代码的意思就是如果你的应用是SYSTEM_UID或者ROOT_UID就不能用content://加fileprovider的Uri。只有settings可以用。
我们可以去看下settings里面到底有没有com.android.settings.files,这样的provider。打开settings 的AndroidManifest文件。

<providerandroid:name="android.support.v4.content.FileProvider"android:authorities="com.android.settings.files"android:grantUriPermissions="true"android:exported="false"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" />
</provider>

你会发现settings真的有。这也太坑了吧,凭什么只让settings用,所以应该怎么办呢。

  1. 去掉声明“android.uid.system”。
  2. 在AMS判断settings的地方加上你自己的uri。类似这样:
if ("com.android.settings.files".equals(grantUri.uri.getAuthority()) || "com.***.***.fileprovider".equals(grantUri.uri.getAuthority())) {
  1. 如果有人告诉你又不能去掉systemuid,又不能改framwork代码。告诉那个人:来来来,你来,你nb你来搞!

哈哈,第三条开个玩笑。这个问题当你知道答案后,感觉很简单,但是当你无论怎么调试,怎么百度谷歌都找不到原因时候,气的都要拔头发时候,不要放弃,当实在是没有办法时候就去源码里找答案,我相信总会找到答案的。希望本文可以帮到你。

最近有个新想法或许不用改源码,在声明provider时候将authorities设成settiings的:

android:authorities="com.android.settings.files"

不知道这种方式能否绕过AMS的检查,没时间去验证了,有兴趣的小伙伴可以试试,没问题的话留言说一声。如果能运行成功估计就能安装apk。

Android android.uid.system的应用调用安装apk失败相关推荐

  1. 【Android错误解决方案】解决AndroidStudio在oppo和vivo手机上安装apk失败----终极解决方案

    文章目录 [Android错误解决方案]解决AndroidStudio在oppo和vivo手机上安装apk失败---终极解决方案 问题描述 错误描述 解决方案一 解决方案二 总结 [Android错误 ...

  2. vivo X21 安装 Apk 失败问题

    兼容了Android 8.0之后,所有手机安装Apk都没有问题,就唯独vivo X21这个机型会出现安装失败. 初次推断以为是没有兼容全面屏的原因,兼容了一波OK后发现仍然不行,然后就去请教了度娘,经 ...

  3. 安装APK失败,错误代码:INSTALL_FAILED_INVALID_APK 解决方案

    安装APK失败,错误代码:INSTALL_FAILED_INVALID_APK 解决方案 参考文章: (1)安装APK失败,错误代码:INSTALL_FAILED_INVALID_APK 解决方案 ( ...

  4. 锤子手机安装Apk失败

    锤子手机安装Apk失败 如果在同一个apk在别的手机上可以正常安装,在锤子手机上总是显示安装失败,那么应该是锤子手机设置的问题. 你可以这样设置你的手机(我使用的T2举例的,不同型号的手机可能设置会不 ...

  5. Android PackageManagerService 总结(一)应用市场下载安装apk流程

    前言: 本篇文章是对系统包安装流程的总结,基于Android12 上 com.android.packageinstaller 源码的分析,第三方应用商城(华为商城,小米商城,应用宝,豌豆荚,酷安等) ...

  6. 96.android 简单的更新APP、下载安装APK(四种方式)

    //第一种 下载更新使用OKHttp+ProgressDialog进度条+第三方AlertDialog //第一步 在Manifest.xml里面写权限: <!-- 网络权限--> < ...

  7. android模拟器 uidump,解决Genymotion模拟器不能安装apk

    一.Genymontion不能安装apk的原因 Genymotion是一款基于x86架构的Android模拟器,而大部分应用是arm架构.所以两者不兼容. 对于x86的真机,X86处理器已经能够基本兼 ...

  8. Android adb 安装APK失败 error:不是内部或外部命令,也不是可运行的程序

    前言 最近在调试静默安装apk 需要调试adb install xxx.apk 结果报错不是内部或外部命令,也不是可运行的程序! 解决方法 1.保证SDK路径下的 platform-tools 文件夹 ...

  9. android studio 安装apk失败,AndroidStudio安装apk时失败时提示INSTALL_PARSE_FAILED_NO_CERTIFICATES...

    安装apk时提示INSTALL_PARSE_FAILED_NO_CERTIFICATES错误,说明要安装的apk未进行签名,需签名后方可安装. 在android studio中增加签名方法,直接在ap ...

最新文章

  1. python内置函数:iter、enumerate和next
  2. BugKuCTF 杂项 又一张图片,还单纯吗
  3. 牛客网_PAT乙级_1019旧键盘 (20)
  4. mysql触发器 多个条件_当条件为真时,如何使用MySQL触发器更新多个表?
  5. 队列的基础概念与经典题目(Leetcode题解-Python语言)
  6. C语言字符串输出函数puts()的作用是什么
  7. 项目改用GoModules管理依赖的方法和经验总结
  8. 吴恩达机器学习之线性逻辑回归实现部分
  9. arcgis合并tif影像_ARCGIS多种影像裁剪
  10. Qt学习 QVariant类(转)
  11. 9、java常用 设计模式
  12. RecycleView多布局的实现
  13. delphi7及控件安装
  14. vscode免密登录需要更改authorized_keys的权限
  15. 分布式缓存 - memCached Voldemort
  16. HEVC编码技术简介
  17. python输出26个大写字母_python 一句话输出26个英文字母
  18. m8 windows android,HTC M8 WP版正式发布 通刷Android和WP8.1
  19. python:小鱼的航程
  20. 高中历史教师资格证考试成功通过前辈备考经验分享

热门文章

  1. 北京“721灾难”风险管控分析
  2. 说没有学历焦虑都是假的
  3. VUE写一个本地教室管理系统
  4. 欢迎Slashdot!
  5. 手机连wifi,电脑把手机当热点上网
  6. 5种不同的仓储堆垛机哪个更好用,海格里斯告诉你!
  7. Python练手小程序—统计英文文件中单词出现的的个数
  8. Apple ID密保问题是个梗
  9. 视觉特效转场插件集Boris Continuum Complete 2019 for FCPX v12.0.1破解版
  10. DATA2001 期末知识点概括Week 2 - Week 12