В некоторый момент обработка MessageQueue зацикливается на потоке пользовательского интерфейса - PullRequest
1 голос
/ 09 марта 2020

Я работаю над программной клавиатурой, и многие клиенты жаловались, что приложение (клавиатура) зависает в какой-то момент, и они больше не могут его использовать, пока не убьют приложение.

После выполнения дампа обработчика, связанного с главным петлителем, я заметил, что MessageQueue содержит более двух тысяч сообщений, и первое (которое, очевидно, блокирует обработку) - barrier .

Вот как выглядит файл дампа:

MainHandlerPrefixHandler (android.os.Handler) {3ff4640} @ 263606865
MainHandlerPrefix  Looper (main, tid 2) {989979}
MainHandlerPrefix    Message 0: { when=-6m23s60ms barrier=79218 }
MainHandlerPrefix    Message 1: { when=-6m23s60ms callback=my.package.MyService$6 target=android.view.ViewRootImpl$ViewRootHandler }
MainHandlerPrefix    Message 2: { when=-6m23s60ms callback=my.package.-$$Lambda$MyService$1$ubKmTRTmp1KgOJNPNWqMqGvEn4w target=android.view.ViewRootImpl$ViewRootHandler }
MainHandlerPrefix    Message 3: { when=-6m23s60ms callback=my.package.-$$Lambda$MyService$j8NCLWjGRK01foVLc7iUIBP0CK4 target=android.view.ViewRootImpl$ViewRootHandler }
MainHandlerPrefix    Message 4: { when=-6m22s762ms callback=my.package.-$$Lambda$MyService$3PQrgbrUtIie519YhF12lIH8KUQ target=android.os.Handler }
MainHandlerPrefix    Message 5: { when=-6m22s761ms callback=my.package.MyService$5 target=android.os.Handler }
...
MainHandlerPrefix    Message 2232: { when=-32ms callback=my.package.-$$Lambda$MyService$3PQrgbrUtIie519YhF12lIH8KUQ target=android.os.Handler }
MainHandlerPrefix    Message 2233: { when=0 callback=my.package.-$$Lambda$MyService$ct9EhzRGhNjeTqThcka4z4DVWy0 target=android.os.Handler }
MainHandlerPrefix    (Total messages: 2234, polling=true, quitting=false)

Как видно из дампа, "барьерное" сообщение находилось в очереди более шести минут.

Вот как инициализируется основной обработчик:

private void initMainHandler() {
    mainHandler = new Handler(this.getMainLooper());
}

А вот как Runnable отправляется основному обработчику:

 private void runOnUiThread(Runnable r, String message) {

        try {
            if (Thread.currentThread() == getMainHandler().getLooper().getThread()) {
                r.run();
            } else {
                getMainHandler().post(r);
            }
        } catch (Exception e) {
            Log.d(TAG, "", e);
        }
    }

Пример Использование:

public void loadKeyboard() {
     runOnUiThread(() -> {
                containerFacade.requestLayout();
                containerFacade.layoutOverlay();
     }, "example");
}

К сожалению, я не могу воспроизвести эту проблему, я только что получил журнал от клиента, который пожаловался на это.

Есть ли у вас какие-либо идеи, что может вызвать эту блокировку? Заранее спасибо.

ОБНОВЛЕНИЕ

Кажется, что Looper.removeSyncBarrier(int token), где token - это значение сообщения (barrier) из MessageQueue с индексом '0' (из дампа) никогда не вызывается, поэтому поток, связанный с l oop, заблокирован, а приложение зависает.

...