blog of faywong

备案号: 浙ICP备2025185971号

  menu
41 文章
0 浏览
1 当前访客
ღゝ◡╹)ノ❤️

通过PackageManager query应用信息时出现java.lang.RuntimeException: Package manager has died

这属于android中最常见的TransactionTooLargeException的后果表现之一。

该问题较多出现在使用PackageManager查询系统的应用的信息,通过Intent来过滤匹配目标应用组件(android四大组件)时,典型堆栈如下:

java.lang.RuntimeException: Package manager has died
at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:78)

......
Caused by: android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:1393)
at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:73)
... 17 more
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:1393)
at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:73)

这是Java层的堆栈,原始抛出异常的地方在于文件frameworks/base/core/jni/android_util_Binder.cpp:

case FAILED_TRANSACTION:
 LOGE("!!! 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;

该FAILED_TRANSACTION错误码定义于:
/bionic/libc/kernel/common/linux/binder.h中的BR_FAILED_REPLY

enum BinderDriverReturnProtocol {
BR_ERROR = _IOR_BAD('r', 0, int),

BR_OK = _IO('r', 1),

BR_TRANSACTION = _IOR_BAD('r', 2, struct binder_transaction_data),
BR_REPLY = _IOR_BAD('r', 3, struct binder_transaction_data),

BR_ACQUIRE_RESULT = _IOR_BAD('r', 4, int),

BR_DEAD_REPLY = _IO('r', 5),

BR_TRANSACTION_COMPLETE = _IO('r', 6),

BR_INCREFS = _IOR_BAD('r', 7, struct binder_ptr_cookie),
BR_ACQUIRE = _IOR_BAD('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR_BAD('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR_BAD('r', 10, struct binder_ptr_cookie),

BR_ATTEMPT_ACQUIRE = _IOR_BAD('r', 11, struct binder_pri_ptr_cookie),

BR_NOOP = _IO('r', 12),

BR_SPAWN_LOOPER = _IO('r', 13),

BR_FINISHED = _IO('r', 14),

BR_DEAD_BINDER = _IOR_BAD('r', 15, void *),

BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR_BAD('r', 16, void *),

BR_FAILED_REPLY = _IO('r', 17),

};

其原因总结如下,首先Android系统对于Binder IPC每进程的事务buffer上限是1M(为所有Binder事务共享,且不区分目标系统的ram配置等因素),在通过PackageManager中获取系统内应用时,比如应用的Icon是个bitmap,且不同应用所制作Icon的品质(像素数)上差异很大。会占用大量内存导致Binder事务内存超过上限。

Binder事务buffer的尺寸定义在ProcessState.cpp:

#define BINDER_VM_SIZE((1 * 1024 * 1024) - (4096 * 2))
......
ProcessState::ProcessState(): mDriverFD(open_driver()), mVMStart(MAP_FAILED), mManagesContexts(false), mBinderContextCheckFunc(NULL), mBinderContextUserData(NULL), mThreadPoolStarted(false), mThreadPoolSeq(1) {
    if (mDriverFD >= 0) {
        // XXX Ideally, there should be a specific define for whether we
        // have mmap (or whether we could possibly have the kernel module
        // availabla).
        #
        if !defined(HAVE_WIN32_IPC)
            // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
            close(mDriverFD);
            mDriverFD = -1;
        }#
        else
            mDriverFD = -1;#
        endif
    }

    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}

App icon对应的数据模型如下:

class AppInfo {

......

private BitmapDrawable icon

......

}

该问题是android系统的限制,只能通过上层来捕获该异常来绕过。当然也不仅限于PackageManager,其他系统服务,应用间的Binder调用也可以带来这一问题。

最后的最后,由于在c++向java层抛出这个异常的场景有多种(见上边c++代码中“FAILED_TRANSACTION”处的注释),所以当你收到了TransactionTooLargeException的时候,不意味着真正的Transaction is Too Large。


标题:通过PackageManager query应用信息时出现java.lang.RuntimeException: Package manager has died
作者:faywong8888
地址:https://blog.fay.wang/articles/2025/08/10/1754806340736.html