Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
496 views
in Technique[技术] by (71.8m points)

broadcastreceiver - Android throw DeadObjectException with LOG: Transaction failed on small parcel; remote process probably died

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

  1. 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
",
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.

  1. 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:

  1. 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.
  2. 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.
  3. 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
",
342                   alloc->pid, size);
343         pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)
",
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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...