reference to : http://blog.csdn.net/xxooyc/article/details/50162523

这是今天遇到的一个issue,由于Binder造成的。虽然比较简单,还是保持记录下吧。

先来开看一下Crash log:

    E/HpnsService(24810): HPNS Version is 5.0java.lang.RuntimeException: Package manager has died
E/HpnsService(24810): at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:111)
E/HpnsService(24810): at com.xx.xxx.util.AppUtil.checkInstalledPackageVersionCode(AppUtil.java:568)
E/HpnsService(24810): at com.xx.xxx.util.AppUtil.checkAppStatus(AppUtil.java:653)
E/HpnsService(24810): at com.xx.xxx.view.AppListView$LoadingAppThread.run(AppListView.java:723)
E/HpnsService(24810): Caused by: android.os.TransactionTooLargeException
E/HpnsService(24810): at android.os.BinderProxy.transactNative(Native Method)
E/HpnsService(24810): at android.os.BinderProxy.transact(Binder.java:496)
E/HpnsService(24810): at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:1786)
E/HpnsService(24810): at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:106)
E/HpnsService(24810): ... 3 more

为什么会发生Package manager has died?

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

102    @Override
103 public PackageInfo getPackageInfo(String packageName, int flags)
104 throws NameNotFoundException {
105 try {
106 PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId());
107 if (pi != null) {
108 return pi;
109 }
110 } catch (RemoteException e) {
111 throw new RuntimeException("Package manager has died", e);
112 }
113
114 throw new NameNotFoundException(packageName);
115 }

这是一个Binder调用,造成这个的原因是因为发生了RemoteException。

那为什么友会发生RemoteException?

其实也就是下面的这句Caused by: android.os.TransactionTooLargeException造成的。

为什么会造成TransactionTooLargeException?

frameworks/base/core/jni/android_util_Binder.cpp:

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

可以看出如果Binder的使用超出了一个进程的限制就会抛出TransactionTooLargeException这个异常。

如果是其他原因造成Binder crash的话就会抛出RuntimeException。

那一个进程的Binder内存限制是多少?

frameworks/native/libs/binder/ProcessState.cpp:

44 #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))

这便是一个进程中binder的大小,大约1M。

给Binder分配内存的代码:

    349#if !defined(HAVE_WIN32_IPC)
350 // mmap the binder, providing a chunk of virtual address space to receive transactions.
351 mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
352 if (mVMStart == MAP_FAILED) {
353 // *sigh*
354 ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
355 close(mDriverFD);
356 mDriverFD = -1;
357 }

通过上面的清理,知道了如果一个进程中使用的Binder内容超过了1M,就会crash.

而如果这时候恰巧在用getPackageManager()做事情,就会提示Package manager has died。

可以事实真的是这样的吗?

写了个demo来证明一下:

    public class MainActivity extends Activity {  

        @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
test();
} private void test() {
for (int i = 0; i < 2; i++) {
new Thread() {
@Override
public void run() {
int count = 0;
List<PackageInfo> list = getPackageManager()
.getInstalledPackages(10000);
for (PackageInfo info : list) {
if(count >=1000){
break;
}
try {
PackageInfo pi = getPackageManager()
.getPackageInfo(info.packageName,
PackageManager.GET_ACTIVITIES);
Log.e("yanchen", "yanchen threadid:"+Thread.currentThread().getId()
+ ",i:" + count++);
} catch (NameNotFoundException e) {
}
}
}
}.start();
}
}
}

这个Demo就是同时创建两个线程来进行Binder调用.

运行打印的log:

    E/yanchen (21180): yanchen threadid:4097,i:271
E/yanchen (21180): yanchen threadid:4097,i:272
E/yanchen (21180): yanchen threadid:4097,i:273
E/yanchen (21180): yanchen threadid:4097,i:274
E/yanchen (21180): yanchen threadid:4097,i:275
E/yanchen (21180): yanchen threadid:4097,i:276

此时也如预期发生了Crash:

    E/JavaBinder(31244): !!! FAILED BINDER TRANSACTION !!!
E/AndroidRuntime(31244): FATAL EXCEPTION: Thread-4798
E/AndroidRuntime(31244): Process: com.example.testdl, PID: 31244
E/AndroidRuntime(31244): java.lang.RuntimeException: Package manager has died
E/AndroidRuntime(31244): at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:155)
E/AndroidRuntime(31244): at com.example.testdl.MainActivity$1.run(MainActivity.java:40)
E/AndroidRuntime(31244): Caused by: android.os.TransactionTooLargeException
E/AndroidRuntime(31244): at android.os.BinderProxy.transactNative(Native Method)
E/AndroidRuntime(31244): at android.os.BinderProxy.transact(Binder.java:496)
E/AndroidRuntime(31244): at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:2208)
E/AndroidRuntime(31244): at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:150)
E/AndroidRuntime(31244): ... 1 more
D/EnterpriseDeviceManagerService( 3021): isMana

解决方式:

其实只要避免多个线程同时来调用Binder就可以了,毕竟一个线程用了会释放,所以理论上是很难发生的。

修改后的Demo:

    synchronized(MainActivity.class){
PackageInfo pi = getPackageManager()
.getPackageInfo(info.packageName,
PackageManager.GET_ACTIVITIES);
}

再次运行就不会Crash了。

[Android Pro] 分析 Package manager has died的更多相关文章

  1. Package manager has died异常PackageInfo 引发 Crash

    Android 获取 PackageInfo 引发 Crash 填坑 一般 Android 通过PackageInfo这个类来获取应用安装包信息,比如应用内包含的所有Activity名称.应用版本号之 ...

  2. xamarin调试android部署到模拟器错误记录:Deployment failed Mono.AndroidTools.InstallFailedException: Unexpected install output: Error: Could not access the Package Manager. Is the system running?

    问题记录: 1.生成 ok. 2.昨天也是能部署到模拟器的. 但是今天部署的时候就报了这样的一个错误 Deployment failed Mono.AndroidTools.InstallFailed ...

  3. Android 核心分析 之七Service深入分析

    Service深入分析 上一章我们分析了Android IPC架构,知道了Android服务构建的一些基本理念和原理,本章我们将深入分析Android的服务.Android体系架构中三种意义上服务: ...

  4. Android Launcher分析和修改3——Launcher启动和初始化

    前面两篇文章都是写有关Launcher配置文件的修改,代码方面涉及不多,今天开始进入Launcher代码分析. 我们开机启动Launcher,Launcher是由Activity Manager启动的 ...

  5. Cannot find `aapt.exe`. Please install the Android SDK Build-tools package

    Google has updated their SDK tools ("Android SDK Tools" Rev. 23) in a way that also requir ...

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

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

  7. [Android Pro] PackageManager#getPackageSizeInfo (hide)

    referce to : http://www.baidufe.com/item/8786bc2e95a042320bef.html 计算Android App所占用d的手机内存(RAM)大小.App ...

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

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

  9. Android架构分析之使用自定义硬件抽象层(HAL)模块

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:2.3.7_r1 Linux内核版本:android-goldfish-2.6.29 在上一篇博 ...

随机推荐

  1. jquery li a 样式

    jQuery(".CwebtopNavContainer").find("li:last a").css("color","red ...

  2. 使用亚马逊云服务器EC2做深度学习(三)配置TensorFlow

    这是<使用亚马逊云服务器EC2做深度学习>系列的第三篇文章. (一)申请竞价实例  (二)配置Jupyter Notebook服务器  (三)配置TensorFlow  (四)配置好的系统 ...

  3. day4 递归原理及解析

    递归 递归是一种调用自身的方法,在函数执行过程中重复不断的调用自身的过程,递归的规模每次都要缩小,一般前一步的程序作为后一步的参数.但是必须有递归结束条件. 递归算法是一种直接或者间接地调用自身算法的 ...

  4. 06易普优APS行业方案:包装印刷行业高级计划排程

    易普优APS行业方案:包装印刷行业高级计划排程 一.包装印刷行业发展概况 网络购物催生包装印刷行业迅猛发展,目前已具有万亿市场规模,全国包装印刷企业总数达30万家,其中规模以上企业只有2万多家,已然成 ...

  5. 十四 oracle 视图

    一.介绍视图是一张虚拟表,其内容由查询定义,同真实的表一样,视图包含一系列带有名称的列和行数据.但是,视图并不在数据库中以存储的数据值集形式存在.行和列数据来自由定义视图的查询所引用的表,并且在引用视 ...

  6. 二十三 使用@property

    在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改: s = Student() s.score = 这显然不合逻辑.为了限制score的范围,可以 ...

  7. linux java环境变量设置

    下载JRE或者JDK后解压,设置以下环境变量 JAVA_HOME=/home/zm/jdk1.8.0_181JRE_HOME=/home/zm/jdk1.8.0_181/jreCLASSPATH=.: ...

  8. php源码审计

    转:http://www.jb51.net/article/31898.htm 针对PHP的网站主要存在下面几种攻击方式: 1.命令注入(Command Injection) 2.eval注入(Eva ...

  9. 长安大学第四届ACM-ICPC“迎新杯”程序设计竞赛-重现赛 D - 新卡片游戏

    题目描述

  10. BNUOJ 52516 Just A String

    $KMP$. 枚举每一个后缀,去原串中进行匹配,每次匹配到原串到$i$位置的后缀与这次枚举的后缀的前缀,更新答案. #include<bits/stdc++.h> using namesp ...