android throw exception 原理,Android throw DeadObjectException with LOG: Transaction failed on small p...

问题

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)

The error happened in the BroadcastQueue class, when it called scheduleRegisteredReceiver through Binder, the DeadObjectException throw. Like the LOG said: Transaction failed on small parcel; remote process probably died, but why RuntimeException throw in the com.android.systemui process if it already dead?

回答1:

I finally found the root cause, it happened in the binder kernel.

For now, I discovered two reasons for what can cause a DeadObjectException to be thrown in BroadcastQueue and therafter a RemoteServiceException in ActivityThread in the app:

There are no more asynchronous space to execute the binder transaction when AMS sends a one-way binder call to ActivityThread in order to trigger BroadcastReceiver.onReceive.

Related code shown below:

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 }

Therefore, this will not "end up destabilizing the system". It will only influences the application itself.

The user application had been force closed because BroadcastQueue send scheduleCrash binder call to ActivityThread. The root cause of this problem is that there are no binder buffer in the application side because some binder threads occupy most of it.

The bug can be triggered with the following steps:

Process1 sends large data (e.g. 980kB) to Process2, the Process2 need sleep for 30 seconds, and the large binder buffer will not be released.

Process1 sends a broadcast to Process2, consisting of e.g. 50kB data. That would go beyond the make the buffer capacity of 1016kB, since 980kB + 50kB is larger than the buffer capacity.

BroadcastQueue will throw a DeadObjectException and then pass scheduleCrash to ActivityThread in the application side.

Here is the code:

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 }

In conclusion, DeadObjectException can be thrown even if the application process haven't died.

The root cause is most likely because of full binder buffer for the application and does not influence the system.

So I think it is not necessary to make the application crash after catching a DeadObjectException in BroadcastQueue.

回答2:

Basically everything Rick Ai's answer to their own question is correct but here is a a real world example:

If your app creates and registers a whole bunch of BroadcastReceiver instances all listening to the same action--perhaps due to a leak or bug in your app--then the ActivityManagerService in the system process will invoke android.app.IApplicationThread method scheduleRegisteredReceiver for each registered instance. Notice that the binder transaction for this particular method is oneway. Since it is oneway each invocation will return immediately and the calls to the binder driver will occur very rapidly before each transaction is complete thus effectively running them all in parallel.

Lets say you have 100 receivers in your app and the broadcast being received contains 20 KiB of data. Now you've got 2 MiB trying to pass through the binder driver and it will fail due to the limit of 1 MiB.

In kernel logs you will see:

binder: 1282:1298 transaction failed 29201/-28, size 28052-8 line 3072

So beware leaking BroadcastReceiver and beware oneway binder transactions. Note that apparently the AIDL file may not declare a method oneway but it may end up that way if the AIDL compiler decides it is possible.

来源:https://stackoverflow.com/questions/45432647/android-throw-deadobjectexception-with-log-transaction-failed-on-small-parcel

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值