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. java复习(4)异常

    1.Java异常的分类和类结构图 1.Throwable是整个java异常体系的超类,所有的异常类都派生自这个类,包含Error和Exception这两个直接的子类,概括了所有能被当做异常跑出来的东西 ...

  2. 出现( linker command failed with exit code 1)错误总结(http://blog.csdn.net/hengshujiyi/article/details/21182813)

    这种问题,通常出现在添加第三方库文件或者多人开发时. 这种问题一般是找不到文件而导致的链接错误. 我们可以从如下几个方面着手排查. 1.以如下错误为例,如果是多人开发,你同步完成后发现出现如下的错误. ...

  3. SVN更新报错:Checksum mismatch for 解决办法

    问题: Checksum mismatch while updating '……'; expected: '3f9fd4dd7d1a0304d8020f73300a3e07', actual: 'cd ...

  4. VB程序设计中Combobox的取值问题

    Private a As Double   Private Sub Combo1_Click()    '1位小数,系数用10    a = Combo1.ItemData(Combo1.ListIn ...

  5. C#索引器2 字符串作为索引号

    6.索引器   字符串作为索引号 public class Demo { private Hashtable name = new Hashtable(); public string this[st ...

  6. Azure IoT 技术研究系列3

    上篇博文中我们将模拟设备注册到Azure IoT Hub中:我们得到了设备的唯一标识. Azure IoT 技术研究系列2-设备注册到Azure IoT Hub 本文中我们继续深入研究,设备到云.云到 ...

  7. ipsec概念理解

    互联网安全协议(英语:Internet Protocol Security,缩写:IPsec): 本质上一个协议包,透过对IP协议的分组进行加密和认证来保护IP协议的网络传输协议族(一些相互关联的协议 ...

  8. java web 增加信息课堂测试00

    按照图片要求设计添加新课程界面.(0.5分)在后台数据库中建立相应的表结构存储课程信息.(0.5分)实现新课程添加的功能.要求判断任课教师为王建民.刘立嘉.刘丹.王辉.杨子光五位教师的其中一位.(0. ...

  9. Oracle RAC业务bug导致部分数据丢失处理

    问题描述:业务部门在10月26日发现某张基础表中丢失部分数据,系为9月份录入系统的基础数据丢失 Oracle RAC环境做的RMAN备份,10月18日做过expdp数据泵备份,丢失数据表名为T_GL_ ...

  10. HDU 4027 Can you answer these queries? (线段树成段更新 && 开根操作 && 规律)

    题意 : 给你N个数以及M个操作,操作分两类,第一种输入 "0 l r" 表示将区间[l,r]里的每个数都开根号.第二种输入"1 l r",表示查询区间[l,r ...