android mFocusedWindow更新异常引起的anr

anr问题

最近新开发的功能引起第三方app频繁anr,解决问题过程中发现本次anr与mFocusedWindow有十分密切关系,记录如下:
问题:anr,用户在加减音量的时候会引起anr,如果是touch事件则不会anr。
日志:

12-01 16:01:10.669  1256  2171 I am_anr  : [0,30522,com.ggp.ggpdemo,552124230,Input dispatching timed out (Application does not have a focused window)]

"main" prio=5 tid=1 Native
  | group="main" sCount=1 ucsCount=0 flags=1 obj=0x71b8f6e8 self=0xb400007c2bee2c00
  | sysTid=30522 nice=-10 cgrp=top-app sched=0/0 handle=0x7c2d5444f8
  | state=S schedstat=( 211713206 24400522 338 ) utm=18 stm=2 core=1 HZ=100
  | stack=0x7fe65a4000-0x7fe65a6000 stackSize=8188KB
  | held mutexes=
  native: #00 pc 00000000000e8f0c  /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+12)
  native: #01 pc 0000000000017ea8  /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
  native: #02 pc 0000000000017d84  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+116)
  native: #03 pc 00000000001562b4  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+48)
  at android.os.MessageQueue.nativePollOnce(Native method)
  at android.os.MessageQueue.next(MessageQueue.java:335)
  at android.os.Looper.loopOnce(Looper.java:173)
  at android.os.Looper.loop(Looper.java:379)
  at android.app.ActivityThread.main(ActivityThread.java:9052)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1018)

看当前的dump信息发现有两个mFocusedWindow

λ adb shell dumpsys window |grep mFocus
  mFocusedApp=ActivityRecord{8fe14de u0 com.ggp.ggpdemo/.MainActivity t47}
    mFocusedWindow=Window{ace421d u0 com.ggp.ggpdemo/com.ggp.ggpdemo.MainActivity}
  mFocusedApp=ActivityRecord{21ff021 u0 com.ggp.ggpdemo/.MainActivity t50}
    mFocusedWindow=Window{64a4587 u0 com.ggp.ggpdemo/com.ggp.ggpdemo.MainActivity}

很明显当前的mFocusedWindow出现问题,从dump信息然后结合代码就可以看到mFocusedWindow更新流程异常。由于公司代码就不上传具体调用过程。
查到focused异常这个bug就很好调查和解决了

不过这个bug很明显的一个的问题是我们将key事件传递给了一个NOT_FOCUSABLE NOT_TOUCHABLE的window。那么猜测即使focused错误了,如果这个window接受key事件,那么也应该不会anr,于是我们写了一个demo,将activity设置为not_focusable.然后加减音量也复现了相同的anr问题。

        setContentView(R.layout.activity_main);
        //getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
        //getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

继续调查一下keyEvent的下发异常导致anr流程,在发生anr的时候有两行很明显的日志

12-01 18:23:57.858  1263  2416 W InputDispatcher: Waiting because no window has focus but ActivityRecord{dca0e8f u0 com.ggp.ggpdemo/.MainActivity t77} may eventually add a window when it finishes starting up. Will wait for 5000ms
12-01 18:24:02.861  1263  2416 E InputDispatcher: Dropping KEY event because there is no focused window
12-01 18:24:02.949  1263  2416 W InputDispatcher: Waiting because no window has focus but ActivityRecord{dca0e8f u0 com.ggp.ggpdemo/.MainActivity t77} may eventually add a window when it finishes starting up. Will wait for 5000ms

找到InputDispatch.cpp,查看一keyEvent下发流程,找到关键日志打印,这里我们还可以打印一下
inputDispatcher->dispatchOnceInnerLocked() -> dispatchKeyLocked() -> findFocusedWindowIargetsLocked()

InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked(
        nsecs_t currentTime, const EventEntry& entry, std::vector<InputTarget>& inputTargets,
        nsecs_t* nextWakeupTime) {
    std::string reason;

    sp<InputWindowHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
    std::shared_ptr<InputApplicationHandle> focusedApplicationHandle =
            getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);


   //日志注释很明确,no focused window ANR

    // Compatibility behavior: raise ANR if there is a focused application, but no focused window.
    // Only start counting when we have a focused event to dispatch. The ANR is canceled if we
    // start interacting with another application via touch (app switch). This code can be removed
    // if the "no focused window ANR" is moved to the policy. Input doesn't know whether
    // an app is expected to have a focused window.
    if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) {
        if (!mNoFocusedWindowTimeoutTime.has_value()) {
            // We just discovered that there's no focused window. Start the ANR timer
            std::chrono::nanoseconds timeout = focusedApplicationHandle->getDispatchingTimeout(
                    DEFAULT_INPUT_DISPATCHING_TIMEOUT);
            mNoFocusedWindowTimeoutTime = currentTime + timeout.count();
            mAwaitedFocusedApplication = focusedApplicationHandle;
            mAwaitedApplicationDisplayId = displayId;
            ALOGW("Waiting because no window has focus but %s may eventually add a "
                  "window when it finishes starting up. Will wait for %" PRId64 "ms",
                  mAwaitedFocusedApplication->getName().c_str(), millis(timeout));
            *nextWakeupTime = *mNoFocusedWindowTimeoutTime;
            return InputEventInjectionResult::PENDING;
        } else if (currentTime > *mNoFocusedWindowTimeoutTime) {
            // Already raised ANR. Drop the event
            ALOGE("Dropping %s event because there is no focused window",
                  NamedEnum::string(entry.type).c_str());
            return InputEventInjectionResult::FAILED;
        } else {
            // Still waiting for the focused window
            return InputEventInjectionResult::PENDING;
        }
    }


    return InputEventInjectionResult::SUCCEEDED;
}

focusedwindowHandle获取
没调查,不知道,不晓得,有兴趣的可以自己看一下。。。

focusedwindowHandle与mFocusedWindow必然是有一定的关系的,否则即使mFocusedWindow更新出错,也不会出现anr的。不过具体关系我没有调查,还需要一点时间来理一理。

mFocusedWindow更新流程

据此我们继续调查了mFocusedWindow的调用流程,代码不做输入,堆栈记录如下:

情景一

当前touch事件落在focusedWindow之外会引起一次mFocusedWindow更新,一般来说都是多窗口操作会引起这一步切换,比如pip,分屏,freeform

2021-12-01 12:23:08.986 1256-2126/system_process D/ggpff: focusChangedLw lastFocus = Window{6252892 u0 com.ss.android.ugc.aweme/com.ss.android.ugc.aweme.splash.SplashActivity} newFocus = Window{d3750ff u0 cn.nubia.mms/cn.nubia.mms.tab.MmsMainActivity}java.lang.Throwable
        at com.android.server.wm.DisplayPolicy.focusChangedLw(DisplayPolicy.java:2656)
        at com.android.server.wm.DisplayContent.updateFocusedWindowLocked(DisplayContent.java:3649)
        at com.android.server.wm.RootWindowContainer.updateFocusedWindowLocked(RootWindowContainer.java:493)
        at com.android.server.wm.WindowManagerService.updateFocusedWindowLocked(WindowManagerService.java:6307)
        at com.android.server.wm.ActivityTaskManagerService.setResumedActivityUncheckLocked(ActivityTaskManagerService.java:4936)
        at com.android.server.wm.TaskDisplayArea.positionChildTaskAt(TaskDisplayArea.java:483)
        at com.android.server.wm.TaskDisplayArea.positionChildAt(TaskDisplayArea.java:423)
        at com.android.server.wm.Task.moveToFront(Task.java:5731)
        at com.android.server.wm.ActivityRecord.moveFocusableActivityToTop(ActivityRecord.java:2945)
        at com.android.server.wm.ActivityTaskManagerService.setFocusedTask(ActivityTaskManagerService.java:2209)
        at com.android.server.wm.WindowManagerService.handleTaskFocusChange(WindowManagerService.java:9071)
        at com.android.server.wm.WindowManagerService.onPointerDownOutsideFocusLocked(WindowManagerService.java:9035)
        at com.android.server.wm.WindowManagerService.access$1600(WindowManagerService.java:345)
        at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5742)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:238)
        at android.os.Looper.loop(Looper.java:379)
        at android.os.HandlerThread.run(HandlerThread.java:67)
        at com.android.server.ServiceThread.run(ServiceThread.java:44)
情景二

startActivity必然会引起mFocusedWindow切换,这个切换过程有两步,第一步是切换为null,第二步切换为新window(切换为null必然是有原因的,为什么没有直接切换到新window,具体什么原因我没有调查)
第一步,切换为null

2021-12-01 15:35:32.395 1256-3319/system_process D/ggpff: focusChangedLw lastFocus = Window{db4af75 u0 com.ggp.ggpdemo/com.ggp.ggpdemo.MainActivity} newFocus = nulljava.lang.Throwable
        at com.android.server.wm.DisplayPolicy.focusChangedLw(DisplayPolicy.java:2656)
        at com.android.server.wm.DisplayContent.updateFocusedWindowLocked(DisplayContent.java:3649)
        at com.android.server.wm.RootWindowContainer.updateFocusedWindowLocked(RootWindowContainer.java:493)
        at com.android.server.wm.WindowManagerService.updateFocusedWindowLocked(WindowManagerService.java:6307)
        at com.android.server.wm.ActivityTaskManagerService.setResumedActivityUncheckLocked(ActivityTaskManagerService.java:4936)
        at com.android.server.wm.Task.onActivityStateChanged(Task.java:2297)
        at com.android.server.wm.ActivityRecord.setState(ActivityRecord.java:5050)
        at com.android.server.wm.Task.minimalResumeActivityLocked(Task.java:5795)
        at com.android.server.wm.ActivityTaskSupervisor.realStartActivityLocked(ActivityTaskSupervisor.java:1044)
        at com.android.server.wm.ActivityTaskSupervisor.startSpecificActivity(ActivityTaskSupervisor.java:1115)
        at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:6910)
        at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:6353)
        at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2659)
        at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2645)
        at com.android.server.wm.Task.completePauseLocked(Task.java:6139)
        at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:5731)
        at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:173)
        at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:549)
        at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:119)
        at android.os.Binder.execTransactInternal(Binder.java:1198)

第二步,切换为新window

2021-12-01 15:35:32.459 1256-2003/system_process D/ggpff: focusChangedLw lastFocus = null newFocus = Window{5f5716a u0 com.ggp.ggpdemo/com.ggp.ggpdemo.SecondActivity}java.lang.Throwable
        at com.android.server.wm.DisplayPolicy.focusChangedLw(DisplayPolicy.java:2656)
        at com.android.server.wm.DisplayContent.updateFocusedWindowLocked(DisplayContent.java:3649)
        at com.android.server.wm.RootWindowContainer.updateFocusedWindowLocked(RootWindowContainer.java:493)
        at com.android.server.wm.WindowManagerService.updateFocusedWindowLocked(WindowManagerService.java:6307)
        at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2619)
        at com.android.server.wm.Session.relayout(Session.java:235)
        at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:735)
        at com.android.server.wm.Session.onTransact(Session.java:169)
        at android.os.Binder.execTransactInternal(Binder.java:1198)
        at android.os.Binder.execTransact(Binder.java:1157)
2021-12-01 15:47:27.557 1256-9937/system_process D/ggpff: focusChangedLw lastFocus = Window{43cbe9e u0 com.ggp.ggpdemo/com.ggp.ggpdemo.MainActivity} newFocus = Window{aa6ebef u0 com.ggp.ggpdemo/com.ggp.ggpdemo.MainActivity}java.lang.Throwable
        at com.android.server.wm.DisplayPolicy.focusChangedLw(DisplayPolicy.java:2656)
        at com.android.server.wm.DisplayContent.updateFocusedWindowLocked(DisplayContent.java:3649)
        at com.android.server.wm.RootWindowContainer.updateFocusedWindowLocked(RootWindowContainer.java:493)
        at com.android.server.wm.WindowManagerService.updateFocusedWindowLocked(WindowManagerService.java:6307)
        at com.android.server.wm.WindowManagerService.addWindow(WindowManagerService.java:1929)
        at com.android.server.wm.Session.addToDisplayAsUser(Session.java:204)
        at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:636)
        at com.android.server.wm.Session.onTransact(Session.java:169)
        at android.os.Binder.execTransactInternal(Binder.java:1198)
        at android.os.Binder.execTransact(Binder.java:1157)
情景三

add或者remove window也必然会引起mFocusedWindow切换

2021-12-01 15:47:39.353 1256-9937/system_process D/ggpff: focusChangedLw lastFocus = Window{aa6ebef u0 com.ggp.ggpdemo/com.ggp.ggpdemo.MainActivity EXITING} newFocus = Window{43cbe9e u0 com.ggp.ggpdemo/com.ggp.ggpdemo.MainActivity}java.lang.Throwable
        at com.android.server.wm.DisplayPolicy.focusChangedLw(DisplayPolicy.java:2656)
        at com.android.server.wm.DisplayContent.updateFocusedWindowLocked(DisplayContent.java:3649)
        at com.android.server.wm.RootWindowContainer.updateFocusedWindowLocked(RootWindowContainer.java:493)
        at com.android.server.wm.WindowManagerService.updateFocusedWindowLocked(WindowManagerService.java:6307)
        at com.android.server.wm.WindowState.setupWindowForRemoveOnExit(WindowState.java:2698)
        at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2666)
        at com.android.server.wm.WindowState.removeIfPossible(WindowState.java:2544)
        at com.android.server.wm.WindowManagerService.removeWindow(WindowManagerService.java:2126)
        at com.android.server.wm.Session.remove(Session.java:218)
        at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:691)
        at com.android.server.wm.Session.onTransact(Session.java:169)
        at android.os.Binder.execTransactInternal(Binder.java:1198)
        at android.os.Binder.execTransact(Binder.java:1157)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容