[Android Pro] 分析 Package manager has died

來源:互聯網
上載者:User

標籤:nbsp   5.0   work   比較   大小   jni   多個   tar   change   

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    @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_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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.