分析 Package manager has died
来源:互联网 发布:知乎 1024地址 编辑:程序博客网 时间:2024/06/01 10:31
这是今天遇到的一个issue,由于Binder造成的。虽然比较简单,还是保持记录下吧。
先来开看一下Crash log:
E/HpnsService(24810): HPNS Version is 5.0java.lang.RuntimeException: Package manager has diedE/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.TransactionTooLargeExceptionE/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 @Override103 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 }113114 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_TRANSACTION686 // but it is not the only one. The Binder driver can return BR_FAILED_REPLY687 // for other reasons also, such as if the transaction is malformed or688 // refers to an FD that has been closed. We should change the driver689 // to enable us to distinguish these cases in the future.690 jniThrowException(env, canThrowRemoteException691 ? "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 {@Overrideprotected 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() {@Overridepublic 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:271E/yanchen (21180): yanchen threadid:4097,i:272E/yanchen (21180): yanchen threadid:4097,i:273E/yanchen (21180): yanchen threadid:4097,i:274E/yanchen (21180): yanchen threadid:4097,i:275E/yanchen (21180): yanchen threadid:4097,i:276
此时也如预期发生了Crash:
E/JavaBinder(31244): !!! FAILED BINDER TRANSACTION !!!E/AndroidRuntime(31244): FATAL EXCEPTION: Thread-4798E/AndroidRuntime(31244): Process: com.example.testdl, PID: 31244E/AndroidRuntime(31244): java.lang.RuntimeException: Package manager has diedE/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.TransactionTooLargeExceptionE/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 moreD/EnterpriseDeviceManagerService( 3021): isMana
解决方式:
其实只要避免多个线程同时来调用Binder就可以了,毕竟一个线程用了会释放,所以理论上是很难发生的。
修改后的Demo:
synchronized(MainActivity.class){PackageInfo pi = getPackageManager().getPackageInfo(info.packageName,PackageManager.GET_ACTIVITIES);}
再次运行就不会Crash了。
- 分析 Package manager has died
- 分析 Package manager has died
- 分析 Package manager has died
- RuntimeException: Package manager has died
- Android "Package manager has died"
- java.lang.RuntimeException: Package manager has died
- java.lang.RuntimeException: Package manager has died
- Package manager has died at android.app.ApplicationPackageManager.getInstalledPackages
- Android-java.lang.RuntimeException: Package manager has died问题
- process XXX has died的log分析
- 从Process xxxx (pid xxx) has died分析
- Android 开机Process xxx (pid xxxx) has died问题分析
- Android 分析:Process xxxxx (pid 30262) has died .
- PackageManager has died
- Process com.xxxxxxxx has died
- Package Manager
- package Manager
- The Haskell process `xx’ has died issue
- Android 快速开发系列 打造万能的ListView GridView 适配器
- android ProgressBar 实现自定义进度条
- hdu1269 强连通分量
- HTTP文件断点上传
- Premiere Pro CS6基础视频教程
- 分析 Package manager has died
- 利用DataURL技术在网页上显示图片
- 大数加法
- Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:]
- (四十一)auto命令
- iOS开之代理传值
- 2015-12-03 AndroidStudio模拟器运行失败的问题
- 从小白慢慢往上爬的历程--几种简单的流程控制语句
- SQL语句中别名中有括号的情况