本文介绍了调用“DisplayManagerGlobal.getDisplayInfo()";导致应用中的应用无响应 (ANR)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

显然,应用程序中的某些东西从不同的线程(主线程和绑定线程)调用了该方法,这导致了内部 ANR.它经常发生,我不知道它在哪里发生,因为我无法在模拟器或我拥有的测试设备上重现它.

Apparently, something in the application calls the method from different threads (both main and a binder thread) which causes an internal ANR. It happens quite frequently and I don't have an idea as to where it happens because I cannot reproduce it on emulators or the test devices that I have got.

应用功能:它是一个应用储物柜应用,在应用叠加上绘制全屏锁定视图并要求输入密码(图案),还支持指纹解锁机制.要成功监听指纹,我们还必须使用透明的 Activity 使应用程序进入前台",然后等待指纹输入,否则指纹机制不会监听,也没有回调.也许这就是原因,因为活动在每个锁定的应用上频繁启动和结束.

What the app does: It is an app locker application, which draws a full screen lock view on application overlay and asks for a password (pattern), which also supports fingerprint unlock mechanism. To successfully listen the fingerprint, we also have to use a transparent activity to make the app go "foreground", and then wait for the fingerprint input, as otherwise, fingerprint mechanism does not listen and it doesn't have a callback for it either. Maybe that is the cause, because the activity starts and finishes frequently, on every locked app.

ANR 在两个方面被报告:

ANR is reported under two matters:

意图广播{ act=android.intent.action.SCREEN_ON flg=0x50200010(有额外内容)}意图广播 { act=android.intent.action.SCREEN_OFF flg=0x50200010(有额外的)}

对此,应用有一个一直运行的前台服务,因为它需要随时锁定应用,并从动态广播接收器中监听这些事件.但是,它们中没有任何阻塞调用或同步调用,只是一个用于检查当前前台应用程序的连续工作线程的启停机制.

Regarding to this, the app has a foreground service that always runs, because it needs to lock apps at any time as a requirement, and it listens to these events from a dynamic broadcast receiver. However, there are no blocking calls or synchronized calls in any of them, just a start-stop mechanism for the continuous worker thread that checks the current foreground app.

完整的 ANR 报告

相关 ANR 报告(相关部分,来自 Android 10 设备、API 29 的报告):

Related ANR report (related section, reported from Android 10 device, API 29):

"main" prio=5 tid=1 Blocked
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x71773f98 self=0x7f95a7d000
  | sysTid=28841 nice=-4 cgrp=default sched=0/0 handle=0x7f96febee8
  | state=S schedstat=( 151471598466 24930775143 453988 ) utm=9534 stm=5612 core=3 HZ=100
  | stack=0x7fddb4d000-0x7fddb4f000 stackSize=8192KB
  | held mutexes=
  at android.hardware.display.DisplayManagerGlobal.getDisplayInfo (DisplayManagerGlobal.java:177)
- waiting to lock <0x038dbdd7> (a java.lang.Object) held by thread 6
  at android.view.Display.updateDisplayInfoLocked (Display.java:1214)
  at android.view.Display.updateDisplayInfoLocked (Display.java:1209)
  at android.view.Display.getState (Display.java:1174)
- locked <0x053b6aeb> (a android.view.Display)
  at android.view.ViewRootImpl$1.onDisplayChanged (ViewRootImpl.java:1601)
  at android.hardware.display.DisplayManagerGlobal$DisplayListenerDelegate.handleMessage (DisplayManagerGlobal.java:1417)
  at android.os.Handler.dispatchMessage (Handler.java:107)
  at android.os.Looper.loop (Looper.java:237)
  at android.app.ActivityThread.main (ActivityThread.java:7811)
  at java.lang.reflect.Method.invoke (Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1068)

"Binder:28841_6" prio=5 tid=6 Runnable
  | group="main" sCount=0 dsCount=0 flags=0 obj=0x132c19b0 self=0x7f08d9a400
  | sysTid=29512 nice=0 cgrp=default sched=0/0 handle=0x7f0133ed50
  | state=R schedstat=( 673333745225 29381013522 76199 ) utm=67111 stm=221 core=7 HZ=100
  | stack=0x7f01248000-0x7f0124a000 stackSize=991KB
  | held mutexes= "mutator lock"(shared held)
  at android.os.MessageQueue.enqueueMessage (MessageQueue.java:581)
- locked <0x0306e956> (a android.os.MessageQueue)
  at android.os.Handler.enqueueMessage (Handler.java:754)
  at android.os.Handler.sendMessageAtTime (Handler.java:703)
  at android.os.Handler.sendMessageDelayed (Handler.java:673)
  at android.os.Handler.sendMessage (Handler.java:611)
  at android.hardware.display.DisplayManagerGlobal$DisplayListenerDelegate.sendDisplayEvent (DisplayManagerGlobal.java:1403)
  at android.hardware.display.DisplayManagerGlobal.handleDisplayEvent (DisplayManagerGlobal.java:408)
- locked <0x038dbdd7> (a java.lang.Object)
  at android.hardware.display.DisplayManagerGlobal.access$100 (DisplayManagerGlobal.java:70)
  at android.hardware.display.DisplayManagerGlobal$DisplayManagerCallback.onDisplayEvent (DisplayManagerGlobal.java:1354)
  at android.hardware.display.IDisplayManagerCallback$Stub.onTransact (IDisplayManagerCallback.java:119)
  at android.os.Binder.execTransactInternal (Binder.java:1021)
  at android.os.Binder.execTransact (Binder.java:994)

我不确定是什么原因导致这种情况,因为在任何线程中都没有应用程序本身的堆栈跟踪.我可以看到主线程由于 waiting to lock 而被阻塞,因为绑定线程已经锁定了它:locked 但没有释放

I'm not exactly sure what causes this, as there are no stack traces to the app itself, in any threads. And I can see that main thread is blocked due to waiting to lock <0x038dbdd7>, since the binder thread already locked it: locked <0x038dbdd7> but did not release it.

对这件事有什么意见吗?感谢您的帮助,非常感谢.

Any opinions on this matter? I appreciate any help, thank you very much.

推荐答案

好吧,我找到了问题所在.这是由于 Android 的 WindowManagerGlobal 类下的内部内存泄漏引起的.原因如下:

Well, I've found the problem. It is caused because of an internal memory leak under Android's WindowManagerGlobal class. Here is what it caused it:

该应用正在使用覆盖权限,因此我们要求用户授予权限,并在用户授予权限时自动检测.在此之后,我们还创建了一个前台服务,它以 2 秒的间隔循环运行,永不停止,并检查其间的权限.由于我遇到了一些关于 Settings.canDrawOverlays(Context) 方法的错误,我决定寻找答案,并找到了 这个答案 导致了巨大的内存泄漏.

The app is using the overlay permission, and doing so we were asking the users to give permission, and automatically detect it if the user gives one. After this, we've also been creating a foreground service that runs in between 2 seconds of interval in a loop, never stopping, also checking the permission in between. Since I've encountered some bugs regarding to Settings.canDrawOverlays(Context) method, I've decided to look up for an answer, and found this answer which lead to the huge memory leak.

您看,将绘图称为不可见的覆盖部分会造成泄漏.它将视图根添加到内存中,但在此期间,由于 SecurityException 而无法添加覆盖层,并且视图永远不会被删除.由于该代码每次都会创建一个新视图来检查权限、新视图根、新显示和新的监听器来调用 onDisplayChanged.经过调试,我终于能够看到这一点并抓住了内存泄漏.删除该代码完全解决了问题,现在看不到与其相关的 ANR.

You see, calling the drawing an invisible overlay part creates a leak. It adds the view root into the memory, but in between, fails to add the overlay because of a SecurityException and the view never gets removed. Since that code creates a new view each time to check the permission, new view roots, new displays and new listeners to the call onDisplayChanged. After debugging, I was finally able to see this and caught the memory leak. Removing that code resolved the issue entirely, no ANRs relating to it are visible now.

如果 addView 失败,我也尝试删除调用 WindowManager.removeView(view) 的视图,但不管要添加的失败视图仍保留在侦听器中,并且记忆.所以,我想说无论如何都应该避免这种方法,应该找到另一种替代方法.

I've also tried to remove the view calling WindowManager.removeView(view) if addView fails, but regardless the failed view to be added remained in the listener and memory. So, I'd say this approach should be avoided in any case and another alternative should be found.

这篇关于调用“DisplayManagerGlobal.getDisplayInfo()";导致应用中的应用无响应 (ANR)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 17:12
查看更多