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. 内存分析工具MAT(Memory Analyzer Tool)从安装到使用

    一.安装 首先,你得有一个Eclipse(因为MAT是Eclipse的插件) 然后,你要在Eclipse上安装MAT,步骤如下: 1.点击Help,Install New Soft,就出现了以下Ins ...

  2. Foundation框架下的常用类(NSNumber, NSValue, NSDate,NSDateFormatter)

    1.NSNumber 将基础数类型数据转成对象数据(比如int  float double BOOL  long等等) //通过NSNumber将基础数类型数据转成对象数据. NSNumber * i ...

  3. Result window is too large, from + size must be less than or equal to: [10000] but was [78440]. See the scroll api for a more efficient way to request large data sets

    {"error":{"root_cause":[{"type":"query_phase_execution_exception& ...

  4. 【转】/etc/inittab文件详解

    转自:https://www.cnblogs.com/ricks/p/10020886.html Linux在完成核内引导(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就 ...

  5. 算法学习 howto

    入门: The Most Important Algorithms http://www.risc.jku.at/people/ckoutsch/stuff/e_algorithms.html Alg ...

  6. Thymeleaf静态资源引入方式及公共页面代码抽取

    静态资源引入 Thymeleaf模板引擎url问题,要用如下的方式写,确保在任何情况下都能访问到 <!-- Bootstrap core CSS --> <link href=&qu ...

  7. 【UOJ#207】共价大爷游长沙

    题目链接 题目描述 火车司机出秦川,跳蚤国王下江南,共价大爷游长沙.每个周末,勤劳的共价大爷都会开车游历长沙市. 长沙市的交通线路可以抽象成为一个 \(n\) 个点 \(n−1\) 条边的无向图,点编 ...

  8. [洛谷P4823] TJOI2013 拯救小矮人

    问题描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口. 对于每一个小矮人,我们知道他从 ...

  9. 【leetcode】1175. Prime Arrangements

    题目如下: Return the number of permutations of 1 to n so that prime numbers are at prime indices (1-inde ...

  10. Java各种锁机制简述

    线程安全是多线程领域的问题,线程安全可以简单理解为一个方法或者一个实例可以在多线程环境中使用而不会出现问题. 在 Java 多线程编程当中,提供了多种实现 Java 线程安全的方式: 最简单的方式,使 ...