android mFocusedWindow更新異常引起的anr

anr問題

最近新開發(fā)的功能引起第三方app頻繁anr,解決問題過程中發(fā)現(xiàn)本次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信息發(fā)現(xiàn)有兩個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出現(xiàn)問題,從dump信息然后結合代碼就可以看到mFocusedWindow更新流程異常。由于公司代碼就不上傳具體調用過程。
查到focused異常這個bug就很好調查和解決了

不過這個bug很明顯的一個的問題是我們將key事件傳遞給了一個NOT_FOCUSABLE NOT_TOUCHABLE的window。那么猜測即使focused錯誤了,如果這個window接受key事件,那么也應該不會anr,于是我們寫了一個demo,將activity設置為not_focusable.然后加減音量也復現(xiàn)了相同的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);

繼續(xù)調查一下keyEvent的下發(fā)異常導致anr流程,在發(fā)生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下發(fā)流程,找到關鍵日志打印,這里我們還可以打印一下
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更新出錯,也不會出現(xiàn)anr的。不過具體關系我沒有調查,還需要一點時間來理一理。

mFocusedWindow更新流程

據(jù)此我們繼續(xù)調查了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)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容