Android throw DeadObjectException with LOG: Transaction failed on small parcel;远程进程可能已经死了
Posted
技术标签:
【中文标题】Android throw DeadObjectException with LOG: Transaction failed on small parcel;远程进程可能已经死了【英文标题】:Android throw DeadObjectException with LOG: Transaction failed on small parcel; remote process probably died 【发布时间】:2017-08-01 08:26:13 【问题描述】: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。就像日志说的:小包裹交易失败;远程进程可能已经死了,但是如果com.android.systemui进程已经死了,为什么RuntimeException会抛出呢?
【问题讨论】:
【参考方案1】:终于找到了根本原因,发生在binder内核中。
目前,我发现了两个可能导致在 BroadcastQueue 中引发 DeadObjectException 并在应用程序的 ActivityThread 中引发 RemoteServiceException 的原因:
-
当 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
因此,这不会“最终导致系统不稳定”。它只会影响应用程序本身。
-
用户应用程序已被强制关闭,因为 BroadcastQueue 将 scheduleCrash binder 调用发送到 ActivityThread。这个问题的根本原因是应用端没有 binder 缓冲区,因为一些 binder 线程占据了大部分。
可以通过以下步骤触发该错误:
-
Process1 向 Process2 发送大数据(例如 980kB),Process2 需要休眠 30 秒,不会释放大的 binder 缓冲区。
Process1 向 Process2 发送广播,包括例如50kB 数据。这将超出 1016kB 的缓冲容量,因为 980kB + 50kB 大于缓冲容量。
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
总之,即使应用程序进程没有死亡,也可以抛出 DeadObjectException。
根本原因很可能是因为应用程序的绑定缓冲区已满,并且不会影响系统。
所以我认为在BroadcastQueue中捕捉到DeadObjectException后,没有必要让应用程序崩溃。
【讨论】:
您好,我也遇到了同样的问题,您有解决办法吗? @chopchop 是的,正如我的回答所示,缓冲区暂时已满,并使您的应用无法使用 Binder IPC,即每当您调用 Binder 调用方法时,它都会向您抛出 DeadObjectException。为了解决您的问题,您可以使用 Binder 传输较少的数据,这样 Binder 缓冲区就不会很容易被填满,这也可以避免这个问题。【参考方案2】:Rick Ai 对他们自己问题的回答基本上都是正确的,但这里有一个真实的例子:
如果您的应用程序创建并注册了一大堆BroadcastReceiver
实例,它们都在监听相同的操作——可能是由于您的应用程序中的泄漏或错误——那么系统进程中的 ActivityManagerService 将调用android.app.IApplicationThread
方法scheduleRegisteredReceiver
用于每个已注册的实例。请注意,此特定方法的活页夹事务是oneway
。因为它是oneway
,所以每次调用都会立即返回,并且在每个事务完成之前对绑定驱动程序的调用将非常迅速地发生,因此可以有效地并行运行它们。
假设您的应用中有 100 个接收器,并且正在接收的广播包含 20 KiB 的数据。现在你有 2 MiB 试图通过 binder 驱动程序,它将失败 due to the limit of 1 MiB。
在内核日志中你会看到:
binder: 1282:1298 transaction failed 29201/-28, size 28052-8 line 3072
所以要小心泄露BroadcastReceiver
并小心oneway
binder 事务。请注意,显然 AIDL 文件可能不会声明方法 oneway
,但如果 AIDL 编译器认为它是可能的,它可能会以这种方式结束。
【讨论】:
以上是关于Android throw DeadObjectException with LOG: Transaction failed on small parcel;远程进程可能已经死了的主要内容,如果未能解决你的问题,请参考以下文章
Phonegap/Cordova build android node_modules/q/q.js throw e;
android throw java.lang.IllegalStateException 上的 Http Url Connection 问题:已连接
Android Studio 查看源码出现throw new RuntimeException("Stub!"); 解决办法
Android throw DeadObjectException with LOG: Transaction failed on small parcel;远程进程可能已经死了
event.js:174 throw er// 未处理的“错误”事件操作不允许
错误记录Visual Studio 中编译 NDK 报错 ( error : cannot use ‘throw‘ with exceptions disabled )