Android使用LOG抛出DeadObjectException:小包裹上的交易失败;远程过程可能已经死亡

时间:2017-08-01 08:26:13

标签: android broadcastreceiver

07-22 04:38:07.933  1579  3338 E JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 352)
07-22 04:38:07.933  1579  3338 W BroadcastQueue: Can't deliver broadcast to com.android.systemui (pid 2160). Crashing it.
07-22 04:38:07.934  1579  3338 W BroadcastQueue: Failure sending broadcast Intent { act=android.intent.action.TIME_TICK flg=0x50000014 (has extras) }
07-22 04:38:07.934  1579  3338 W BroadcastQueue: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at android.os.BinderProxy.transactNative(Native Method)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at android.os.BinderProxy.transact(Binder.java:618)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at android.app.ApplicationThreadProxy.scheduleRegisteredReceiver(ApplicationThreadNative.java:1211)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at com.android.server.am.BroadcastQueue.performReceiveLocked(BroadcastQueue.java:489)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at com.android.server.am.BroadcastQueue.deliverToRegisteredReceiverLocked(BroadcastQueue.java:702)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at com.android.server.am.BroadcastQueue.processNextBroadcast(BroadcastQueue.java:1002)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at com.android.server.am.BroadcastQueue.processNextBroadcast(BroadcastQueue.java:799)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at com.android.server.am.ActivityManagerService.finishReceiver(ActivityManagerService.java:19153)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:528)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2909)
07-22 04:38:07.934  1579  3338 W BroadcastQueue:    at android.os.Binder.execTransact(Binder.java:565)
07-22 04:38:07.937  2160  2160 D AndroidRuntime: Shutting down VM
07-22 04:38:07.953  2160  2625 E JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 136)
--------- beginning of crash
07-22 04:38:07.972  2160  2160 E AndroidRuntime: FATAL EXCEPTION: main
07-22 04:38:07.972  2160  2160 E AndroidRuntime: Process: com.android.systemui, PID: 2160
07-22 04:38:07.972  2160  2160 E AndroidRuntime: android.app.RemoteServiceException: can't deliver broadcast
07-22 04:38:07.972  2160  2160 E AndroidRuntime:    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1690)
07-22 04:38:07.972  2160  2160 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:102)
07-22 04:38:07.972  2160  2160 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:160)
07-22 04:38:07.972  2160  2160 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:6252)
07-22 04:38:07.972  2160  2160 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
07-22 04:38:07.972  2160  2160 E AndroidRuntime:    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898)
07-22 04:38:07.972  2160  2160 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:788)

错误发生在BroadcastQueue类中,当它通过Binder调用scheduleRegisteredReceiver时,DeadObjectException抛出。就像LOG说的那样:小包裹上的交易失败;远程进程可能已经死了,但是为什么RuntimeException会抛出com.android.systemui进程,如果它已经死了?

2 个答案:

答案 0 :(得分:5)

我终于找到了根本原因,它发生在绑定器内核中。

目前,我发现可能导致在BroadcastQueue中抛出DeadObjectException的两个原因以及应用程序中ActivityThread中的RemoteServiceException:

  1. 当AMS向ActivityThread发送单向活页夹调用以触发BroadcastReceiver.onReceive时,没有更多异步空间来执行活页夹事务。
  2. 相关代码如下所示:

    kernel/msm-4.4/drivers/android/binder_alloc.c
    290     if (is_async &&
    291            alloc->free_async_space < size + sizeof(struct binder_buffer)) {
    292           binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
    293                         "%d: binder_alloc_buf size %zd failed, no async space left\n",
    294                           alloc->pid, size);
    295            eret = ERR_PTR(-ENOSPC);
    296              goto error_unlock;
    297    }
    

    因此,这不会“最终破坏系统稳定性”。它只会影响应用程序本身。

    1. 用户应用程序已强制关闭,因为BroadcastQueue发送scheduleCrash绑定器调用ActivityThread。这个问题的根本原因是应用程序端没有绑定缓冲区,因为一些绑定程序线程占据了大部分。
    2. 可以通过以下步骤触发错误:

      1. Process1向Process2发送大量数据(例如980kB),Process2需要休眠30秒,并且不会释放大型活页夹缓冲区。
      2. Process1向Process2发送广播,包括例如: 50kB数据。这将超出使缓冲容量达到1016kB,因为980kB + 50kB大于缓冲容量。
      3. BroadcastQueue将抛出一个DeadObjectException,然后将scheduleCrash传递给应用程序端的ActivityThread。
      4. 以下是代码:

        kernel/msm-4.4/drivers/android/binder_alloc.c
         315     if (best_fit == NULL) {
        ...
        341         pr_err("%d: binder_alloc_buf size %zd failed, no address space\n",
        342                   alloc->pid, size);
        343         pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n",
        344                       total_alloc_size, allocated_buffers, largest_alloc_size,
        345                  total_free_size, free_buffers, largest_free_size);
        346            eret = ERR_PTR(-ENOSPC);
        347              goto error_unlock;
        348    }
        

        总之,即使应用程序进程尚未死亡,也可能抛出DeadObjectException。

        根本原因很可能是因为应用程序的完整活页夹缓冲区并且不会影响系统。

        所以我认为在BroadcastQueue中捕获DeadObjectException后没有必要使应用程序崩溃。

答案 1 :(得分:0)

基本上,艾克(Rick Ai)对自己的问题的回答都是正确的,但这是一个真实的例子:

如果您的应用创建并注册了一大堆BroadcastReceiver实例,所有实例都在监听相同的操作(可能是由于应用中的泄漏或错误所致),那么系统进程中的ActivityManagerService将调用{{每个已注册实例的1}}方法android.app.IApplicationThread。注意,此特定方法的活页夹事务为scheduleRegisteredReceiver。由于它是oneway,因此每次调用将立即返回,并且对绑定程序驱动程序的调用将在每个事务完成之前非常迅速地发生,从而有效地并行运行它们。

假设您的应用程序中有100个接收器,接收到的广播包含20 KiB数据。现在,您有2个MiB试图通过活页夹驱动程序,它将失败due to the limit of 1 MiB

在内核日志中,您将看到:

oneway

因此,请注意泄漏binder: 1282:1298 transaction failed 29201/-28, size 28052-8 line 3072 并注意BroadcastReceiver活页夹交易。请注意,显然AIDL文件可能未声明方法oneway,但如果AIDL编译器认为有可能,它可能会以这种方式结束。