IllegalThreadStateException OneSignal cra sh обходной путь - PullRequest
6 голосов
/ 03 марта 2020

Наше приложение ежедневно получает около 1 тыс. Сбоев на основе ошибки, упомянутой в проблемах с github * OneSignal .


Объяснение ошибки:

К сожалению, я не могу воспроизвести эту проблему. Все аварии происходят из отчетов Crashlytics. SDK версии 3.12.4

Устройства:

1) Samsung: Galaxy A5(2017), Galaxy S8, Galaxy A50, Galaxy S10+, Galaxy S10  
2) Xiaomi: Mi A2, Mi A2 lite, Mi A1, Mi A3, Redmi Note 5 Pro 
3) Oneplus: ONEPLUS A6010, OnePlus5T, GM191011, GM19008, OnePlus58

Stacktrace:

Caused by java.lang.IllegalThreadStateException
       at java.lang.Thread.start(Thread.java:724)
       at com.onesignal.OneSignalPrefs$WritePrefHandlerThread.startDelayedWrite(OneSignalPrefs.java:117)
       at com.onesignal.OneSignalPrefs.startDelayedWrite(OneSignalPrefs.java:183)
       at com.onesignal.OneSignal.setAppContext(OneSignal.java:601)
       at com.onesignal.OneSignalSyncServiceUtils.doBackgroundSync(OneSignalSyncServiceUtils.java:175)
       at com.onesignal.SyncJobService.onStartJob(SyncJobService.java:40)
       at android.app.job.JobService$1.onStartJob(JobService.java:62)
       at android.app.job.JobServiceEngine$JobHandler.handleMessage(JobServiceEngine.java:108)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:280)
       at android.app.ActivityThread.main(ActivityThread.java:6748)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Вопрос:

Основная проблема заключается в том, что они отметили его как средний приоритет, и ошибка существует около 3 месяцев. Наши жизненно важные силы собираются на жеребьевку, только из-за этой проблемы. Это дорого стоит нам.

Существует ли какое-либо временное решение, которое может временно решить проблему?


PS:

Я готов предоставить дополнительную информацию , если необходимо. Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 06 марта 2020

Возможно (если маловероятно), что у вас есть старая версия OneSignal, где synchronized void startDelayedWrite() не synchronized. В этом случае я бы обновил, и посмотреть, исправит ли это вещи. Если не видите следующее:

Здесь возникает указанное исключение:

synchronized void startDelayedWrite() {
            if (mHandler == null) {
                start();
                mHandler = new Handler(getLooper());
            }
//rest of function irrelevant.

В Javado c для Thread.start указано следующее:

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

Исходя из этого и реализации Thread.start, мы можем сделать вывод, что рассматриваемый поток запускается дважды.

Для this, запускаемого дважды в startDelayedWrite, new Handler(getLooper()) необходимо вызвать исключение, в противном случае мы не будем вводить это, если оператор снова. Я не вижу способа для getLooper() вызвать исключение, но new Handler, конечно, может, если getLooper() равно нулю.

Реализация getLooper() выглядит следующим образом:

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
//rest omitted b/c irrelevant

Единственный способ, которым мог завершиться рассматриваемый поток, это если Thread.run завершился раньше.

Реализация выполнения потока выглядит следующим образом:

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

Looper.loop, предназначена для того, чтобы быть полубесконечным l oop, который читает из очереди сообщений.

Обратите внимание на следующее в Looper.loop:

for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

Так что если msg == null, то наш поток завершается быстро, что может вызвать исключение в mHandler = new Handler(getLooper());, в результате чего Thread.start будет звонил дважды.

Есть и другие правдоподобные объяснения. Например, возможно, что Looper.loop аварийно завершится в некоторой более ранней точке.

Чтобы смягчить это, я бы добавил блок try{} finally{} вокруг mHandler = new Handler(getLooper());, чтобы обработать случай, когда Looper уже вышел. В качестве альтернативы я могу ошибаться, и это состояние гонки может быть вызвано чем-то совершенно другим.

0 голосов
/ 25 марта 2020

Исправлена ​​ошибка


IllegalThreadStateException больше не будет выбрасываться в 3.13.0 Release. Теперь вы увидите, что вместо этого возникает исключение root, поэтому эти сбои можно диагностировать дальше.

...