[Android Pro] 分析 Package manager has died

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

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

先来开看一下Crash log:

1
2
3
4
5
6
7
8
9
10
11
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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:

 

1
2
3
4
5
6
7
8
9
10
11
12
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:

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

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

给Binder分配内存的代码:

1
2
3
4
5
6
7
8
9
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来证明一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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:

1
2
3
4
5
6
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
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:

1
2
3
4
5
synchronized (MainActivity. class ){ 
     PackageInfo pi = getPackageManager() 
             .getPackageInfo(info.packageName, 
                     PackageManager.GET_ACTIVITIES); 

 

再次运行就不会Crash了。

 

分类:  Android Pro
本文转自demoblog博客园博客,原文链接http://www.cnblogs.com/0616--ataozhijia/p/6478231.html如需转载请自行联系原作者

demoblog
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值