android.os.MessageQueue.nativePollOnce 的 ANR

问题描述 投票:0回答:5

我们在应用程序的不同部分看到了此 ANR。 想了解导致此 ANR 的原因吗?

main (native): tid=1 systid=31940
#00 pc 0x5431c libc.so 
#01 pc 0x1313a5 libart.so 
#02 pc 0x2ab05b libart.so 
#03 pc 0x3659 libnativehelper.so 
#04 pc 0x9dee9 libandroid_runtime.so 
#05 pc 0x65c45 libgui.so 
#06 pc 0x11dcd libutils.so 
#07 pc 0x11abf libutils.so 
#08 pc 0xbcc7d libandroid_runtime.so 
       at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
       at android.os.MessageQueue.next(MessageQueue.java:339)
       at android.os.Looper.loop(Looper.java:199)
       at android.app.ActivityThread.main(ActivityThread.java:8276)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)

这就是 firebase 对于此 ANR 的说法 -

发生ANR时该线程处于空闲状态。我们没有足够的 确定根本原因的信息。

android firebase performance android-anr-dialog android-looper
5个回答
21
投票

NativePollOnce:

当CPU等待新任务/消息时出现。

原因:

  1. 如果BroadCast Receiver在10秒内没有完成执行,可能会出现ANR。
  2. 5秒内没有响应输入事件
  3. 当应用程序尝试错误地显示对话框但调用不是来自主线程时,可能会导致 ANR。 (注意:验证UI线程中对UI View的所有调用)
  4. 可能是内存泄漏导致的。
  5. Handler.postDelayed 可能会产生问题
  6. 这种类型的崩溃很常见,当发生堆栈转储时,某些应用程序的堆栈跟踪可能会在实际 ANR 时间之后很长一段时间内转储
  7. 它可能会发生在 SCREEN_ON BROADCAST 上,并且 Google 广告正在使用 SCREEN_ON BROADCAST。
  8. 它可能发生在垃圾收集过程中(由
    埃兹奎尔·阿德里安评论)

收集ANR的方式:

  1. 看门狗
  2. 捕获本机 SIGQUIT
  3. ApplicationExitInfo(由 crashalytics 使用)
  4. 从 Google Play 管理中心收集
  5. Firebase(Firebase 仅从 Android 11 及以上版本收集)

解决ANR的挑战:

揭开 ANR 之谜。 链接

解决方案:

  1. 优化初始化和广告加载。 链接
  2. 如果你正在使用Media,那么在IO线程中释放它
  3. 使用泄漏金丝雀或 Android 查找内存泄漏并进行追踪 分析器
  4. 将firebase降级至28.4.2(不会收集ANR,但并不意味着不会发生)
  5. 验证 UI 线程中对 UI View 的所有调用
  6. 来自问题跟踪器
  7. 的更多信息
  8. 更多信息堆栈答案

8
投票

面临同样的问题 - 我读到它与 Admob 或 unity 广告有关,并且谷歌有一个开放线程:https://issuetracker.google.com/issues/230950647?pli=1


3
投票

在最新版本的 Cloud Messaging 依赖项 v23.0.7 Firebase 中提到此版本可能会减少 ANR。这是他在其文档中提到的话。

消息广播现在在绑定到服务后立即完成。此更改应该会减少出现 ANR 的机会


1
投票

就我而言,这是 firebase 云消息传递库中的错误。该错误已在2022年12月8日发布的最新版本23.1.1中修复。

https://firebase.google.com/support/release-notes/android#messaging_v23-1-1

希望对您有帮助。


0
投票

可能的原因:UI 线程被同步屏障阻塞。

如果 UI 线程的

MessageQueue
有同步屏障,所有消息都将被阻塞(异步消息除外),直到同步屏障被移除。

什么会导致这个问题?

如果您在非 UI 线程中使视图无效,则可能会遇到此问题。

为什么?

// View.java
public void invalidate() {
    invalidate(true);
}
public void invalidate(boolean invalidateCache) {
    invalidateInternal(...);
}
void invalidateInternal(...) {
    final ViewParent p = mParent;
    p.invalidateChild(this, damage);
}

// ViewGroup.java
public final void invalidateChild(View child, final Rect dirty) {
    onDescendantInvalidated(child, child);
}

public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
    //...
    if (mParent != null) {
        mParent.onDescendantInvalidated(this, target);
    }
}

ViewRootImpl
是最上面的
ViewParent

public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
    // TODO: Re-enable after camera is fixed or consider targetSdk checking this
    // checkThread();
    invalidate();
}
void invalidate() {
    scheduleTraversals();
}
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
    }
}

void unscheduleTraversals() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    }
}

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
}

注意上面代码片段中的

postSyncBarrier
removeSyncBarrier

这里在

onDescendantInvalidated
ViewRootImpl
中,它没有检查它是否在UI线程中。

因此,如果您偶尔在非 ui 线程中

invalidate
查看视图,则可能会在消息队列中留下同步屏障,而稍后不会被删除,然后您就会遇到此问题。

我是否

invalidate
我的视图脱离了ui线程?

就我而言,我向许多视图提供

BitmapDrawable
,然后我可能会在工作线程中更改
bitmap
BitmapDrawable
。这将导致使用
BitmapDrawable
的视图在工作线程中失效。

如何检查非ui线程中是否有视图失效?

在视图层次结构的最顶层

ViewGroup
中,覆盖
onDescendantInvalidated
:

override fun onDescendantInvalidated(child: View, target: View) {
    super.onDescendantInvalidated(child, target)
    if (Looper.getMainLooper() != Looper.myLooper()) {
        throw RuntimeException("no ui thread")
    }
}

问题的典型症状

  1. RecyclerView
    ListView
    可以正常滚动,但任何视图的点击监听器都不起作用。
  2. ANR 可能会在 CPU 过载较低且主线程的堆栈跟踪包含
    MessageQueue.nativePollOnce
  3. 时发生
  4. ANR 可能是
    BroadcastTimeout
    anr 或
    ServiceTimeout
    anr,但不是
    KeyDispatchTimeout
    anr
© www.soinside.com 2019 - 2024. All rights reserved.