【问题标题】:IllegalThreadStateException OneSignal crash workaroundIllegalThreadStateException OneSignal 崩溃解决方法
【发布时间】:2020-06-15 10:35:15
【问题描述】:

根据 OneSignal 的 github issues 中提到的错误,我们的应用每天会收到大约 1k 次崩溃。


错误说明:

很遗憾,我无法重现此问题。所有的崩溃都来自 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

堆栈跟踪:

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 个月的错误。就因为这个问题,我们的生命体征正在折腾。这让我们付出了很多。

是否存在可以临时解决问题的解决方法?


附注:

如果需要,我准备提供更多相关信息。提前致谢!

【问题讨论】:

  • 对我来说最明显的解释是你正在启动一个已经启动的线程。可能还有其他解释,但这对我来说似乎是最有可能的。
  • @PiRocks 我只是使用 OneSignal 库,我没有启动任何线程
  • 您使用的是最新的 OneSignal 吗?
  • @PiRocks 最新版本 3.12.6

标签: android multithreading push-notification thread-safety onesignal


【解决方案1】:

您有可能(如果不太可能)拥有旧版本的 OneSignal,其中 synchronized void startDelayedWrite() 不是 synchronized。在这种情况下,我会更新,看看是否能解决问题。如果没有看到以下内容:

有问题的例外发生在这里:

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

Thread.start 的 Javadoc 声明如下:

多次启动一个线程是不合法的。特别是,线程一旦完成执行就可能不会重新启动。

从这个和Thread.start的实现,我们可以推断出有问题的线程被启动了两次。

this要在startDelayedWrite中启动两次,new Handler(getLooper())需要抛出异常,否则我们不会再次进入这个if语句。我看不到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,旨在成为从消息队列中读取的半无限循环。

注意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 可能会在更早的某个时间点崩溃。

为了缓解这种情况,我将在mHandler = new Handler(getLooper()); 周围添加一个try{} finally{} 块,以处理Looper 已经退出的情况。或者我可能错了,这种竞争条件可能是由完全不同的东西引起的。

【讨论】:

  • 我昨天打算发布相同的答案,不幸的是,没有解决方法。这个答案的某些部分与start() 一样准确,但我不认为这是一个looper 问题,因为再次启动线程的条件应用在处理程序上,为if (mHandler == null) { 所以如果处理程序为空,那么它将再次启动它并导致异常,许多人提到他们正在使用带有synchronized 修复的3.12.6 版本。 PS:即使消息队列相当,handler实例也不会变成null吧?
  • >我昨天打算发布相同的答案,不幸的是,没有解决方法。是的,如果他们无法编辑库源,我认为没有任何好的解决方法,尽管反射可能会有所作为。
  • 重点是mHandlerstart();mHandler = new Handler(getLooper());之后仍然为null,因为Handler的构造函数抛出了异常。
  • >PS:即使消息队列相当,handler实例也不会变成null,对吧?如果消息队列在Handler 实例创建之前退出,则它保持为空。
  • 他们确实发布了一个带有synchronized 修复的版本(前面提到过),但它仍然被调用了两次。其次,我没有任何尝试捕获来处理异常,所以如果发生异常,它应该在不在start() 方法上之后崩溃。对于解决方案,问题是根本原因是什么?旧版本的使用已被排除(基于 github cmets),因此留下了静态线程对象和类的实例 i/e mhandler 初始化问题。 Handler instance is created, then it remains null 它将如何将处理程序重置为 null
【解决方案2】:

错误已修复


IllegalThreadStateException 将不再被抛出 3.13.0 发布。您现在将看到引发的根异常 而是这样可以进一步诊断这些崩溃。

【讨论】:

    猜你喜欢
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-23
    • 2011-03-27
    • 1970-01-01
    相关资源
    最近更新 更多