Android 获取 PackageInfo 引发 Crash 填坑

一般 Android 通过PackageInfo这个类来获取应用安装包信息,比如应用内包含的所有Activity名称、应用版本号之类的。PackageInfo通过PackageManager来获取,代码如下:

PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);

比如我们要获取应用版本号时:

public static int getVersionCode(Context context) {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return info.versionCode;
}

Tip: 获取应用自身版本号,推荐使用BuildConfig.VERSION_CODE 方式,这里只是为了方便举例说明问题。

一般情况下,上面的方法是可以正常拿到数据的,但是在某些情况下这也可能会引发 java.lang.RuntimeException: Package manager has died 异常。

 java.lang.RuntimeException: Package manager has died
at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:82)

为了分析引发 Package manager has died 这个问题的具体原因,我们先来看看 getPackageInfo 这个方法:

frameworks/base/core/java/android/app/ApplicationPackageManager.java:

@Override
public PackageInfo getPackageInfo(String packageName, int flags)
throws NameNotFoundException {
try {
PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId());
if (pi != null) {
return pi;
}
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
} throw new NameNotFoundException(packageName);
}

从上面可以看出,getPackageInfo 具体实现是一个 Binder 调用,造成这个的原因是因为发生了 RemoteException 。

Binder 调用为什么会造成 Exception,下面再来看看 Binder 代码frameworks/base/core/jni/android_util_Binder.cpp:

 case FAILED_TRANSACTION:
ALOGE("!!! FAILED BINDER TRANSACTION !!!");
// TransactionTooLargeException is a checked exception, only throw from certain methods.
// FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
// but it is not the only one. The Binder driver can return BR_FAILED_REPLY
// for other reasons also, such as if the transaction is malformed or
// refers to an FD that has been closed. We should change the driver
// to enable us to distinguish these cases in the future.
jniThrowException(env, canThrowRemoteException
? "android/os/TransactionTooLargeException"
: "java/lang/RuntimeException", NULL);
break;

可以看出造成 Binder crash 抛出 RuntimeException 是因为获取应用 PackageInfo 中数据量太大了,超出了 Binder 可传递的最大容量,进而导致 PackageManager 崩溃。

对于上面这种情况,考虑如果只获取versionName和versionCode两个信息,不需要Activity等信息,设法让PackageInfo的信息量小点,避免超出了 Binder 可传递的最大容量。

我们可以利用 getPackageInfo(String packageName, @PackageInfoFlags int flags) 它的第二个参数 flag ,使得该方法返回的对象容量减小,比如使用 PackageManager.GET_CONFIGURATIONS

此外,如果对与Binder的同时调用超出了限制就会抛出 TransactionTooLargeException这个异常,虽然这种场景比较少见,但是我们还是有比较避免多个线程同时来调用Binder就可以了。

优化后代码如下:

public static int getVersionCode(Context context) {
synchronized(Hold.class){
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_CONFIGURATIONS);
return info.versionCode;
}
}

Package manager has died异常PackageInfo 引发 Crash的更多相关文章

  1. [Android Pro] 分析 Package manager has died

    reference to : http://blog.csdn.net/xxooyc/article/details/50162523 这是今天遇到的一个issue,由于Binder造成的.虽然比较简 ...

  2. Visual Studio 2015 新建MVC项目 Package Manager Console不能使用 (HRESULT: 0x80131500)

    Visual studio 2015 突然新建不了MVC项目,报出错误: HRESULT: 0x80131500 在折腾了很长时间,最后在Github上看到这样一个贴 地址:https://githu ...

  3. 你需要知道的包管理器(Package Manager)

    最近我花了一点时间关注了在不同系统之中所用到的包管理器(Package Manager) .最开始的时候,我是在使用Linux操作系统时,对这种工具以及它背后的想法深深迷恋住了:这真是自由的软件世界. ...

  4. 解决VS2015启动时Package manager console崩溃的问题 - Windows PowerShell updated your execution policy successfully, but the setting is overridden by a policy defined at a more specific scope

    安装VS2015,启动以后,Package manager console崩溃,错误信息如下: Windows PowerShell updated your execution policy suc ...

  5. Error: Could not access the Package Manager. Is the system running?

    最近在搭建cordova,android 开发环境,安装android studio之后创建一个demo之后,运行想看一下效果,在运行过程中创建一个虚拟机(arm)的,等了有1分钟左右,再次运行程序, ...

  6. Visual Studio 2010 更新NuGet Package Manager出错解决办法

    在Visual Studio 2010的扩展管理器中发现NuGet Package Manger有最新版本更新提示,选择更新安装提示以下错误信息: 2013/4/25 1:11:48 - Micros ...

  7. Getting and installing the PEAR package manager

    Windows After you have downloaded and installed PHP, you have to manually execute the batch file loc ...

  8. RPM是RedHat Package Manager(RedHat软件包管理工具)

    RPM是RedHat Package Manager(RedHat软件包管理工具)类似Windows里面的“添加/删除程序” rpm 执行安装包二进制包(Binary)以及源代码包(Source)两种 ...

  9. installation - How to install Synaptic Package Manager? - Ask Ubuntu

    installation - How to install Synaptic Package Manager? - Ask Ubuntu How to install Synaptic Package ...

随机推荐

  1. CSP-J&S 游记以及总结

    前言 以前的比赛没有写什么总结,都只注重结果,没有注重过程,不知道如何才能在比赛中拿到高分,因此这次CSP才会考得一塌糊涂. 从此吸取教训,每场比赛都要总结经验,每场比赛都要尽全力考,每个题目都要尽全 ...

  2. Mongodb的几条命令

    最近.... #设置用户名密码db.createUser({user: 'root', pwd: '123456', roles: ['root']}) #开启认证nohup mongod --aut ...

  3. 【leetcode】313. Super Ugly Number

    题目如下: 解题思路:总结一下这么几点,一出一进,优先级队列排序,保证每次输出的都是当前的最小值.解法大致如图: 代码如下: #include<map> #include<queue ...

  4. LeetCode--617--合并二叉树(python)

    给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠. 你需要将他们合并为一个新的二叉树.合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 ...

  5. github上.md的编写

    # algs4 一:大标题 =========== 二:中标题 ------------ 三:1~6级标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 # ...

  6. mysql IN操作符 语法

    mysql IN操作符 语法 作用:在 WHERE 子句中规定多个值.深圳大理石平台 语法:SELECT column_name(s) FROM table_name WHERE column_nam ...

  7. [USACO17JAN]Promotion Counting 题解

    前言 巨佬说:要有线段树,结果蒟蒻打了一棵树状数组... 想想啊,奶牛都开公司当老板了,我还在这里码代码,太失败了. 话说奶牛开个公司老板不应该是FarmerJohn吗? 题解 刚看到这道题的时候竟然 ...

  8. nginx 静态资源WEB服务

    1.静态资源类型 非服务器动态运行生成的文件 类型种类 浏览器端渲染     HTML.CSS.JS 图片            JPEG.GIF.PNG 视频            FLV.MPEG ...

  9. RabbitMQ 工作图解

    (转网上的图) (原文地址 ,http://www.cnblogs.com/knowledgesea/p/5296008.html)

  10. permutation 2

    permutation 2 猜了发结论过了== $N$个数的全排列,$p_{1}=x,p_{2}=y$要求$|p_{i+1}-p_{i}|<=2|$求满足条件的排列个数. 首先考虑$x=1,y= ...