Android генерирует DeadObjectException с LOG: транзакция не удалась для небольшой посылки; удаленный процесс, вероятно, умер

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, когда он вызвал scheduleRegisteredReceiver через Binder, бросок DeadObjectException. Как сказано в журнале: транзакция не удалась для небольшой посылки; удаленный процесс, вероятно, умер, но почему RuntimeException выбрасывает в процесс com.android.systemui, если он уже мертв?

1 ответ

Я наконец нашел основную причину, это произошло в ядре связующего.

На данный момент я обнаружил две причины того, что может вызвать исключение DeadObjectException в BroadcastQueue, а затем исключение RemoteServiceException в ActivityThread в приложении:

  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    }

Следовательно, это не приведет к "дестабилизации системы". Это повлияет только на само приложение.

  1. Пользовательское приложение было принудительно закрыто, потому что BroadcastQueue отправляет вызов связывания scheduleCrash в ActivityThread. Основная причина этой проблемы заключается в том, что на стороне приложения нет буфера связывания, поскольку некоторые потоки связывания занимают большую его часть.

Ошибка может быть вызвана следующими шагами:

  1. Process1 отправляет большие данные (например, 980 КБ) в Process2, Process2 нуждается в спящем режиме в течение 30 секунд, и большой буфер связующего не освобождается.
  2. Process1 отправляет широковещательную рассылку Process2, состоящую, например, из данных размером 50 КБ. Это превысило бы емкость буфера make в 1016 КБ, так как 980 КБ + 50 КБ больше, чем емкость буфера.
  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    }

В заключение, DeadObjectException может быть выброшено, даже если процесс приложения не умер.

Основная причина наиболее вероятна из-за полного буфера связывания для приложения и не влияет на систему.

Поэтому я думаю, что нет необходимости вызывать сбой приложения после перехвата DeadObjectException в BroadcastQueue.

По сути, все ответы Рика Ай на их собственный вопрос верны, но вот пример из реальной жизни:

Если ваше приложение создает и регистрирует целую кучу BroadcastReceiver все экземпляры, прослушивающие одно и то же действие - возможно, из-за утечки или ошибки в вашем приложении - затем активируют ActivityManagerService в системном процессе android.app.IApplicationThread метод scheduleRegisteredReceiver для каждого зарегистрированного экземпляра. Обратите внимание, что транзакция связывания для этого конкретного метода oneway, Так как это oneway каждый вызов будет возвращаться немедленно, и вызовы драйвера связывателя будут происходить очень быстро до завершения каждой транзакции, таким образом эффективно выполняя их все параллельно.

Допустим, в вашем приложении 100 приемников, а принимаемая трансляция содержит 20 КБ данных. Теперь у вас есть 2 МБ, пытающиеся пройти через драйвер связывателя, и он потерпит неудачу из-за ограничения в 1 МБ.

В логах ядра вы увидите:

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

Так что остерегайтесь утечки BroadcastReceiver и остерегайтесь oneway Связующие транзакции. Обратите внимание, что, очевидно, файл AIDL может не объявлять метод oneway но это может закончиться таким образом, если компилятор AIDL решит, что это возможно.

Другие вопросы по тегам