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

Ric*_* Ai 8 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)
Run Code Online (Sandbox Code Playgroud)

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

sat*_*ine 9

基本上,艾瑞克对自己问题的回答都是正确的,但这是一个现实世界的例子:

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

假设您的应用程序中有 100 个接收器,并且接收到的广播包含 20 KiB 的数据。现在,您有 2 MiB 尝试通过活页夹驱动程序,但由于 1 MiB 的限制,它将失败。

在内核日志中您将看到:

binder: 1282:1298 transaction failed 29201/-28, size 28052-8 line 3072
Run Code Online (Sandbox Code Playgroud)

因此要小心泄漏BroadcastReceiver并小心oneway活页夹交易。请注意,显然 AIDL 文件可能不会声明方法oneway,但如果 AIDL 编译器认为这是可能的,那么最终可能会这样。


Ric*_* Ai 6

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

到目前为止,我发现了导致DeadObjectException抛出到BroadcastQueue中并导致应用程序中ActivityThread抛出RemoteServiceException之后的两个原因:

  1. 当AMS向ActivityThread发送单向活页夹调用以触发BroadcastReceiver.onReceive时,不再有异步空间来执行活页夹事务。

相关代码如下所示:

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    }
Run Code Online (Sandbox Code Playgroud)

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

  1. 该用户应用程序已被强制关闭,因为BroadcastQueue将scheduleCrash绑定程序调用发送到ActivityThread。此问题的根本原因是在应用程序端没有绑定程序缓冲区,因为某些绑定程序线程占据了大部分缓冲区。

该错误可以通过以下步骤触发:

  1. Process1将大数据(例如980kB)发送到Process2,Process2需要休眠30秒,并且不会释放大的绑定程序缓冲区。
  2. Process1向Process2发送一个广播,其中包含50kB数据。这将超出使缓冲区容量为1016kB的范围,因为980kB + 50kB大于缓冲区容量。
  3. BroadcastQueue将抛出DeadObjectException,然后将scheduleCrash传递给应用程序端的ActivityThread。

这是代码:

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    }
Run Code Online (Sandbox Code Playgroud)

总之,即使应用程序进程尚未终止,也可能引发DeadObjectException。

根本原因很可能是因为应用程序具有完整的绑定程序缓冲区,并且不影响系统。

因此,我认为在BroadcastQueue中捕获DeadObjectException之后不必使应用程序崩溃。