frameworks 之 Focus window

打印 上一主题 下一主题

主题 856|帖子 856|积分 2568

讲解 焦点窗口如何表现以及如何检察当前焦点窗口
相关知识点

  • SurfaceFlinger是Android体系中负责合成各个层(Layer)并将其表现到屏幕上的服务。应用通过SurfaceComposerClient与SurfaceFlinger通信,Transaction则是用来网络一批图层状态变更,然后一次性提交,这样可以提高效率,淘汰多次IPC调用的开销
涉及到的类如下


  • frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
  • frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
  • frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
  • frameworks/base/services/core/java/com/android/server/wm/WindowState.java
  • frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
  • frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
  • frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
  • frameworks/base/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
  • frameworks/base/core/java/android/view/SurfaceControl.java
  • frameworks/native/libs/gui/SurfaceComposerClient.cpp
  • frameworks/base/core/jni/android_view_SurfaceControl.cpp
  • rameworks/base/core/jni/android_hardware_input_InputWindowHandle.cpp
  • frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
  • frameworks/native/services/surfaceflinger/WindowInfosListenerInvoker.cpp
  • frameworks/native/services/inputflinger/dispatcher/FocusResolver.cpp
  • frameworks/native/services/inputflinger/InputManager.cpp
相关流程图,引用 该博客文章 《Android焦点之FocusWindow切换》 和 《Android焦点之SurfaceFlinger传递给InputFinger》
哀求窗口焦点

设置窗口信息

1 检察当前焦点窗口

1.1 dump window

  1. adb shell dumpsys window
复制代码
执行后部分内容如下

  • WINDOW MANAGER LAST ANR 打印出上次 ANR的原因,也会包含ANR时间的窗口信息,如 mCurrentFocus,mFocusedApp
  • mCurrentFocus 表示当前焦点窗口
  • mFocusedApp 表示当前焦点应用
  1. WINDOW MANAGER LAST ANR (dumpsys window lastanr)
  2.   ANR time: 2025年2月21日 上午6:36:09
  3.   Application at fault: ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity
  4.   Reason: Application does not have a focused window
  5.   Windows added in display #0 since null focus: [Window{87d5194 u0 com.example.mysystemdialog/com.example.mysystemdialog.MainActivity}]
  6.   Windows removed in display #0 since null focus: [Window{26b1193 u0 Splash Screen com.example.mysystemdialog}]
  7. ....
  8. WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)
  9.   mLastOrientationSource=WindowedMagnification:0:31@59915038
  10.   deepestLastOrientationSource=ActivityRecord{d4b3e0 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t14}
  11.   overrideConfig={1.0 310mcc260mnc [zh_CN_#Hans,en_US] ldltr sw411dp w411dp h773dp 560dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1440, 2960) mAppBounds=Rect(0, 0 - 1440, 2792) mMaxBounds=Rect(0, 0 - 1440, 2960) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} as.2 s.30 fontWeightAdjustment=0}
  12.   Display: mDisplayId=0 rootTasks=4
  13.     init=1440x2960 560dpi cur=1440x2960 app=1440x2792 rng=1440x1356-2792x2708
  14.     deferred=false mLayoutNeeded=false mTouchExcludeRegion=SkRegion((0,0,1440,2960))
  15.   mLayoutSeq=636
  16.   mCurrentFocus=Window{ea70127 u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}
  17.   mFocusedApp=ActivityRecord{d4b3e0 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t14}
复制代码
如果只想检察 ANR 也可以直接执行如下命令检察.
  1. WINDOW MANAGER LAST ANR (dumpsys window lastanr)
  2.   ANR time: 2025年2月21日 上午6:36:09
  3.   Application at fault: ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity
  4.   Reason: Application does not have a focused window
  5.   Windows added in display #0 since null focus: [Window{87d5194 u0 com.example.mysystemdialog/com.example.mysystemdialog.MainActivity}]
  6.   Windows removed in display #0 since null focus: [Window{26b1193 u0 Splash Screen com.example.mysystemdialog}]
  7. ...
  8. Last ANR continued
  9. WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)
  10.   mLastOrientationSource=WindowedMagnification:0:31@59915038
  11.   deepestLastOrientationSource=ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19}
  12.   overrideConfig={1.0 310mcc260mnc [zh_CN_#Hans,en_US] ldltr sw411dp w411dp h773dp 560dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1440, 2960) mAppBounds=Rect(0, 0 - 1440, 2792) mMaxBounds=Rect(0, 0 - 1440, 2960) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} as.2 s.30 fontWeightAdjustment=0}
  13.   Display: mDisplayId=0 rootTasks=5
  14.     init=1440x2960 560dpi cur=1440x2960 app=1440x2792 rng=1440x1356-2792x2708
  15.     deferred=false mLayoutNeeded=false mTouchExcludeRegion=SkRegion((0,0,1440,2960))
复制代码
1.2 dump input

执行如下命令
  1. adb shell dumpsys input
复制代码
打印内容如下

  • FocusedApplications 表示当前焦点的应用
  • FocusedWindows 表示当前的焦点窗口
  • Input Dispatcher State at time of last ANR 开始记录上一次ANR的状态
  1. Input Dispatcher State:
  2.   DispatchEnabled: true
  3.   DispatchFrozen: false
  4.   InputFilterEnabled: false
  5.   FocusedDisplayId: 0
  6.   FocusedApplications:
  7.     displayId=0, name='ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19}', dispatchingTimeout=5000ms
  8.   FocusedWindows:
  9.     displayId=0, name='577c5c1 Application Not Responding: com.example.mysystemdialog'
  10.   FocusRequests:
  11.     displayId=0, name='577c5c1 Application Not Responding: com.example.mysystemdialog' result='OK'
  12. Input Dispatcher State at time of last ANR:
  13.   ANR:
  14.     Time: 2025-02-21 06:36:09
  15.     Reason: ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19} does not have a focused window
  16.     Window: ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19}
  17. ...
  18.   FocusedApplications:
  19.     displayId=0, name='ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19}', dispatchingTimeout=5000ms
  20.   FocusedWindows: <none>
复制代码
1.3 input Events 日志

也可以过滤日志检察当前的焦点
  1. adb shell logcat -b events | grep input_focus
复制代码
执行后可以看到如下日志

  • Focus leaving 表示输入正在取消
  • Focus request 表示输入哀求
  • Focus entering 表示输入焦点在这个window
  1. 02-21 06:36:02.570  6677  6764 I input_focus: [Focus leaving ea70127 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher (server),reason=NO_WINDOW]
  2. 02-21 06:36:10.304  6677  6700 I input_focus: [Focus request 577c5c1 Application Not Responding: com.example.mysystemdialog,reason=UpdateInputWindows]
  3. 02-21 06:36:10.371  6677  6764 I input_focus: [Focus entering 577c5c1 Application Not Responding: com.example.mysystemdialog (server),reason=Window became focusable. Previous reason: NOT_VISIBLE]
复制代码
1.4 dump SurfaceFlinger

执行如下命令可以检察,表现如下,HWC是决定表现的图层,背面打 * 号 表示当前的焦点

1.5 检察关键的日志

打开对应的日志命令
  1. adb shell wm logging enable-text WM_DEBUG_SCREEN_ON WM_DEBUG_APP_TRANSITIONS WM_DEBUG_FOCUS
复制代码
过滤日志关键词
  1. adb shell logcat | grep -IE "Changing focus from|findFocusedWindow: No focusable|setFocusedApp|setAppVisibility|Relayout "
复制代码
2 更新当前焦点应用

当窗口的弹出,并不会改变当前焦点应用。只有改变应用切换才会触发,各种情况触发堆栈如3.1 打印。以是存在如焦点窗口是systemUi, 焦点应用是应用等情况。触发变化大部分都是从 ActivityTaskManagerServicesetResumedActivityUncheckLocked 当更改ActivityReord 状态为resume状态的时间。
  1. void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
  2.         ....
  3.         mLastResumedActivity = r;
  4.         // 通过设置可见的时候,就会执行displayContent的setFocusedApp方法去更新当前焦点的mFocusedApp变量
  5.         // 拉出状态栏等操作并不会改变该焦点应用
  6.         final boolean changed = r.mDisplayContent.setFocusedApp(r);
  7.         if (changed) {
  8.             mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
  9.                     true /*updateInputWindows*/);
  10.         }
复制代码
会调用 displayContent 的 setFocusedApp 设置当前焦点的APP,如果有改变 则又会调 WindowManagerServiceupdateFocusedWindowLocked 进行更新窗口焦点
  1. boolean setFocusedApp(ActivityRecord newFocus) {
  2.         ...
  3.         final Task oldTask = mFocusedApp != null ? mFocusedApp.getTask() : null;
  4.         final Task newTask = newFocus != null ? newFocus.getTask() : null;
  5.         mFocusedApp = newFocus;
  6.         if (oldTask != newTask) {
  7.             if (oldTask != null) oldTask.onAppFocusChanged(false);
  8.             if (newTask != null) newTask.onAppFocusChanged(true);
  9.         }
  10.         ...
  11.     }
复制代码
接着又调用
  1. boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
  2.         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
  3.         boolean changed = mRoot.updateFocusedWindowLocked(mode, updateInputWindows);
  4.         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
  5.         return changed;
  6.     }
复制代码
3 更新当前焦点窗口

当启动一个activity的时间 会经历2个阶段,焦点为null ,到焦点存在。
当 新Activity 启动的时间 进入 resume 和 上一个Activity就会进入 onPause 状态
3.1 焦点丢失

当进入桌面onPause的时间,会通过 setVisibility 设置桌面应用不可见

  • 将对应打开中和关闭中的app移除,后续在根据可见状态添加
  • 调用 setVisibleRequested 设置对应的变量
  1. void setVisibility(boolean visible, boolean deferHidingClient) {
  2.         ...
  3.         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
  4.                 "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
  5.                 appToken, visible, appTransition, isVisible(), mVisibleRequested,
  6.                 Debug.getCallers(6));
  7.         final DisplayContent displayContent = getDisplayContent();
  8.         // 先将要打开的app和关闭的app移除,后面在根据visible
  9.         displayContent.mOpeningApps.remove(this);
  10.         displayContent.mClosingApps.remove(this);
  11.         waitingToShow = false;
  12.         // 当前设置是否可见的时候,会将mVisibleRequested赋值,用于判断canReceiveKeys是否可触摸
  13.         setVisibleRequested(visible);
  14.         ...
  15.     }
复制代码
setVisibleRequested 方法重要将 mVisibleRequested 设置为false ,后续判断是否可见吸收事件会用到该变量
  1. private void setVisibleRequested(boolean visible) {
  2.         if (visible == mVisibleRequested) {
  3.             return;
  4.         }
  5.         // 设置可见的请求
  6.         mVisibleRequested = visible;
  7.         setInsetsFrozen(!visible);
  8.         if (app != null) {
  9.             mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
  10.         }
  11.         logAppCompatState();
  12.     }
复制代码
对应的日志打印包括堆栈如下
  1. 02-23 01:19:35.788   561  9003 V WindowManager: setAppVisibility(Token{5253e43 ActivityRecord{3fcedf9 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t25}}, visible=false): mNextAppTransitionRequests=[TRANSIT_OPEN, TRANSIT_OPEN], mNextAppTransitionFlags= visible=true mVisibleRequested=true Callers=com.android.server.wm.ActivityRecord.setVisibility:4784 com.android.server.wm.ActivityRecord.makeInvisible:5488 com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState:224 com.android.server.wm.EnsureActivitiesVisibleHelper.process:140 com.android.server.wm.TaskFragment.updateActivityVisibilities:979 com.android.server.wm.Task.lambda$ensureActivitiesVisible$15:4866
复制代码
在进入onPause的时间,又让对应的应用变为onResume状态,此时启动的应用也会调用对应的 setVisibility将变量 mVisibleRequested 设置为true注意此时启动的会启动的windowState是闪屏页,目标的Activity还没创建AddView
在设置 状态onActivityStateChanged的时间,如果是onResume 即会进入setResumedActivityUncheckLocked开始探求对应的 窗口,看是否改变
  1.         void onActivityStateChanged(ActivityRecord record, ActivityRecord.State state,
  2.             String reason) {
  3.         warnForNonLeafTaskFragment("onActivityStateChanged");
  4.         if (record == mResumedActivity && state != RESUMED) {
  5.             setResumedActivity(null, reason + " - onActivityStateChanged");
  6.         }
  7.         if (state == RESUMED) {
  8.             if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
  9.                 Slog.v(TAG, "set resumed activity to:" + record + " reason:" + reason);
  10.             }
  11.             setResumedActivity(record, reason + " - onActivityStateChanged");
  12.             if (record == mRootWindowContainer.getTopResumedActivity()) {
  13.                 mAtmService.setResumedActivityUncheckLocked(record, reason);
  14.             }
  15.             mTaskSupervisor.mRecentTasks.add(record.getTask());
  16.         }
  17.     }
复制代码
setResumedActivityUncheckLocked 方法会调用 displayContent的 setFocusedApp 方法设置焦点
  1. void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
  2.         ...
  3.         mLastResumedActivity = r;
  4.         // 通过设置可见的时候,就会执行displayContent的setFocusedApp方法去更新当前焦点的mFocusedApp变量
  5.         // 拉出状态栏等操作并不会改变该焦点应用
  6.         final boolean changed = r.mDisplayContent.setFocusedApp(r);
  7.         if (changed) {
  8.             mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
  9.                     true /*updateInputWindows*/);
  10.         }
  11.         ...
  12.     }
复制代码
接着又调用 RootWindowContainer的updateFocusedWindowLocked
  1.         boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
  2.         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
  3.         boolean changed = mRoot.updateFocusedWindowLocked(mode, updateInputWindows);
  4.         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
  5.         return changed;
  6.     }
复制代码
又会遍历各自的displayContentupdateFocusedWindowLocked 更新焦点
  1.         boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
  2.         mTopFocusedAppByProcess.clear();
  3.         boolean changed = false;
  4.         int topFocusedDisplayId = INVALID_DISPLAY;
  5.         for (int i = mChildren.size() - 1; i >= 0; --i) {
  6.             final DisplayContent dc = mChildren.get(i);
  7.             // 更新对应窗口焦点
  8.             changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows, topFocusedDisplayId);
  9.         }
  10.      }
复制代码
updateFocusedWindowLocked

  • 会先通过 findFocusedWindowIfNeeded 遍历获取对应的窗口
  • 判断是否和当前一样,是的话返回false,否则将新的窗口赋值给 mCurrentFocus
  1.         boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows,
  2.             int topFocusedDisplayId) {
  3.         // 查找新焦点,如果界面setVisibility为false则没焦点
  4.         WindowState newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
  5.         // 如果是一样的则返回
  6.         if (mCurrentFocus == newFocus) {
  7.             return false;
  8.         }
  9.         ...
  10.         // 赋值新的焦点给mCurrentFocus变量
  11.         ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
  12.                 mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
  13.         final WindowState oldFocus = mCurrentFocus;
  14.         mCurrentFocus = newFocus;
  15.      }
复制代码
findFocusedWindowIfNeeded 方法通过 findFocusedWindow 方法(判断实现为 mFindFocusedWindow)遍历获取,并将符合条件的保存到 mTmpWindow, 并返回。
  1.         WindowState findFocusedWindowIfNeeded(int topFocusedDisplayId) {
  2.         return (mWmService.mPerDisplayFocusEnabled || topFocusedDisplayId == INVALID_DISPLAY)
  3.                     ? findFocusedWindow() : null;
  4.     }
  5.     WindowState findFocusedWindow() {
  6.         mTmpWindow = null;
  7.         // 开始从上到下遍历查找,查找到保存到 mTmpWindow 变量
  8.         forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
  9.         if (mTmpWindow == null) {
  10.             ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows, display=%d",
  11.                     getDisplayId());
  12.             return null;
  13.         }
  14.         return mTmpWindow;
  15.     }
复制代码
mFindFocusedWindow 重要通过 WindowState的canReceiveKeys 方法
  1.         private final ToBooleanFunction<WindowState> mFindFocusedWindow = w -> {
  2.         // 当前聚焦的应用
  3.         final ActivityRecord focusedApp = mFocusedApp;
  4.         ProtoLog.v(WM_DEBUG_FOCUS, "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
  5.                 w, w.mAttrs.flags, w.canReceiveKeys(),
  6.                 w.canReceiveKeysReason(false /* fromUserTouch */));
  7.         // 判断当前是否能接收事件,主要依靠mVisibleRequested属性
  8.         // 而该属性在 setVisisable设置,表示是否可见
  9.         if (!w.canReceiveKeys()) {
  10.             return false;
  11.         }
  12.         }
复制代码
canReceiveKeys 方法判断如下,通过isVisibleRequestedOrAdding,可见和是否没带 FLAG_NOT_FOCUSABLE等变量判断
  1.         public String canReceiveKeysReason(boolean fromUserTouch) {
  2.         return "fromTouch= " + fromUserTouch
  3.                 + " isVisibleRequestedOrAdding=" + isVisibleRequestedOrAdding()
  4.                 + " mViewVisibility=" + mViewVisibility
  5.                 + " mRemoveOnExit=" + mRemoveOnExit
  6.                 + " flags=" + mAttrs.flags
  7.                 + " appWindowsAreFocusable="
  8.                 + (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
  9.                 + " canReceiveTouchInput=" + canReceiveTouchInput()
  10.                 + " displayIsOnTop=" + getDisplayContent().isOnTop()
  11.                 + " displayIsTrusted=" + getDisplayContent().isTrusted();
  12.     }
  13.     public boolean canReceiveKeys(boolean fromUserTouch) {
  14.         final boolean canReceiveKeys = isVisibleRequestedOrAdding()
  15.                 && (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
  16.                 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
  17.                 && (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
  18.                 && canReceiveTouchInput();
  19.         if (!canReceiveKeys) {
  20.             return false;
  21.         }
  22.         // Do not allow untrusted virtual display to receive keys unless user intentionally
  23.         // touches the display.
  24.         return fromUserTouch || getDisplayContent().isOnTop()
  25.                 || getDisplayContent().isTrusted();
  26.     }
复制代码
isVisibleRequestedOrAdding 方法 重要就是依赖刚才的变量 mVisibleRequested
  1. boolean isVisibleRequestedOrAdding() {
  2.         final ActivityRecord atoken = mActivityRecord;
  3.         return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
  4.                 && isVisibleByPolicy() && !isParentWindowHidden()
  5.                 && (atoken == null || atoken.mVisibleRequested)
  6.                 && !mAnimatingExit && !mDestroying;
  7.     }
复制代码
以是 因为桌面设置了不可见 和新启动的windowState是 Splash Screen 固然可见,但是携带了 FLAG_NOT_FOCUSABLE ,以是遍历下来,此时没有可聚焦的窗口,就会返回null.。这样 当前的 mCurrentFocus 变为了 null
3.2 获得窗口焦点


  • 当对应的Activity启动后,进入realStartActivityLocked方法 时间,就会触发 setVisibility将变量 mVisibleRequested 设置为true
    详细日志如下
  1. 02-23 01:19:35.951   561  9003 V WindowManager: setAppVisibility(Token{279e3b3 ActivityRecord{b8ad70 u0 com.android.gallery3d/.app.GalleryActivity t34}}, visible=true): mNextAppTransitionRequests=[], mNextAppTransitionFlags= visible=true mVisibleRequested=true Callers=com.android.server.wm.ActivityRecord.setVisibility:4784 com.android.server.wm.ActivityRecord.completeResumeLocked:5695 com.android.server.wm.Task.minimalResumeActivityLocked:4784 com.android.server.wm.ActivityTaskSupervisor.realStartActivityLocked:938 com.android.server.wm.RootWindowContainer.startActivityForAttachedApplicationIfNeeded:2017 com.android.server.wm.RootWindowContainer.$r8$lambda$auelgeOhCvbItmS_07q5VFEb1ac:0
复制代码

  • 当窗口焦点丢失后,启动的Activity启动后,就会通过 addview 触发3部曲中的 relayout
    WMS的 relayoutWindow 方法当检测到窗口从不可见变为可见,可见性有变化的时间或者flag有变化,focusMayChange 即会变为 true。以是就会调用 updateFocusedWindowLocked
  1. public int relayoutWindow(...){
  2.                         // 如果可见不一样 或者flagFLAG_NOT_FOCUSABL有变化
  3.             boolean focusMayChange = win.mViewVisibility != viewVisibility
  4.                     || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
  5.                     || (!win.mRelayoutCalled);
  6.                         // 如果窗口改变则执行该方法去更新对应屏幕的焦点窗口
  7.             if (focusMayChange) {
  8.                 if (updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/)) {
  9.                     imMayMove = false;
  10.                 }
  11.             }
  12. }
复制代码
updateFocusedWindowLocked 上面已讲解,此时 目标应用 已经为可见可触摸 ,以是可以查询到 ,以是焦点会变更为 桌面焦点。这样焦点就规复了
4 窗口信息到InputDispatcher

当WMS保存了对应的焦点应用和窗口后,也要同步到 Input端。DisplayContent 负责传输的类是InputMonitor
4.1 焦点应用通知InputDispatcher

从上面流程可以看出 displayContent的时间会调用 InputMonitor对应的 setFocusedAppLw 方法开始通知
  1. boolean setFocusedApp(ActivityRecord newFocus) {
  2.                 ///
  3.                 ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "setFocusedApp %s displayId=%d Callers=%s",
  4.                 newFocus, getDisplayId(), Debug.getCallers(4));
  5.         final Task oldTask = mFocusedApp != null ? mFocusedApp.getTask() : null;
  6.         final Task newTask = newFocus != null ? newFocus.getTask() : null;
  7.         mFocusedApp = newFocus;
  8.         if (oldTask != newTask) {
  9.             if (oldTask != null) oldTask.onAppFocusChanged(false);
  10.             if (newTask != null) newTask.onAppFocusChanged(true);
  11.         }
  12.         // 将新的焦点通过mInputMonitor传递给input
  13.         getInputMonitor().setFocusedAppLw(newFocus);
  14. }
复制代码
而 setFocusedAppLw 直接调用 InputManagerService 的 setFocusedApplication 方法。
getInputApplicationHandle 在 ActivityRecord 构造了 InputApplicationHandle 对象,用于跟native交互内里的token 为 ActivityRecord 的appToken,属于ibinder对象
  1.         void setFocusedAppLw(ActivityRecord newApp) {
  2.         // Focused app has changed.
  3.         // 构建 InputApplicationHandle对象,将ActivityRecord的AIDL对象appToken传递进去
  4.         mService.mInputManager.setFocusedApplication(mDisplayId,
  5.                 newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null);
  6.     }
复制代码
InputManagerService 又会调用 native方法 nativeSetFocusedApplication
  1.         public void setFocusedApplication(int displayId, InputApplicationHandle application) {
  2.         nativeSetFocusedApplication(mPtr, displayId, application);
  3.     }
复制代码
检察 com_android_server_input_InputManagerService.cpp 文件的 nativeSetFocusedApplication 方法,又会调用 NativeInputManager 的 setFocusedApplication
  1. static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */,
  2.         jlong ptr, jint displayId, jobject applicationHandleObj) {
  3.     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
  4.     im->setFocusedApplication(env, displayId, applicationHandleObj);
  5. }
复制代码
NativeInputManager 又会继续调用 inputDIspatcher的 setFocusedApplication
  1. void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
  2.         jobject applicationHandleObj) {
  3.     if (!applicationHandleObj) {
  4.         return;
  5.     }
  6.     std::shared_ptr<InputApplicationHandle> applicationHandle =
  7.             android_view_InputApplicationHandle_getHandle(env, applicationHandleObj);
  8.     applicationHandle->updateInfo();
  9.     // 调用 inputDispater的setFocusedApplication方法
  10.     mInputManager->getDispatcher()->setFocusedApplication(displayId, applicationHandle);
  11. }
复制代码
InputDispatcher 又会调用 setFocusedApplicationLocked
  1. void InputDispatcher::setFocusedApplication(
  2.         int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
  3.     if (DEBUG_FOCUS) {
  4.         ALOGD("setFocusedApplication displayId=%" PRId32 " %s", displayId,
  5.               inputApplicationHandle ? inputApplicationHandle->getName().c_str() : "<nullptr>");
  6.     }
  7.     { // acquire lock
  8.         std::scoped_lock _l(mLock);
  9.         // 设置当前对应的Application
  10.         setFocusedApplicationLocked(displayId, inputApplicationHandle);
  11.     } // release lock
  12.     // Wake up poll loop since it may need to make new input dispatching choices.
  13.     mLooper->wake();
  14. }
复制代码
该方法会从 mFocusedApplicationHandlesByDisplay 根据displayId 获取之前聚焦的应用,如果相等不处理,不相等的话则替换放到 mFocusedApplicationHandlesByDisplay为空的话则移除
  1. void InputDispatcher::setFocusedApplicationLocked(
  2.         int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
  3.     // 从mFocusedApplicationHandlesByDisplay获取当前的已聚焦的应用
  4.     std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle =
  5.             getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
  6.     // 判断是否相等
  7.     if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) {
  8.         return; // This application is already focused. No need to wake up or change anything.
  9.     }
  10.     // Set the new application handle.
  11.     // r如果为空则移除,否则就根据displayId 保存inputApplicationHandle
  12.     if (inputApplicationHandle != nullptr) {
  13.         mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
  14.     } else {
  15.         mFocusedApplicationHandlesByDisplay.erase(displayId);
  16.     }
  17.     // No matter what the old focused application was, stop waiting on it because it is
  18.     // no longer focused.
  19.     resetNoFocusedWindowTimeoutLocked();
  20. }
复制代码
这样就将当前聚焦的应用传递到InputDispatcher
4.2 焦点窗口通知InputDispatcher

相对于聚焦应用的通知,窗口通知比较复杂,需要先从WMS通知到 SurfaceFlinger,SurfaceFlinger 在通知到 InputDispatcher
当焦点有改变的时间如上面流程就会调用到 DisplayContent 的 updateFocusedWindowLocked
  1.         boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows,
  2.             int topFocusedDisplayId) {
  3.         // 查找新焦点,如果界面setVisibility为false则没焦点
  4.         WindowState newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
  5.         // 如果是一样的则返回
  6.         if (mCurrentFocus == newFocus) {
  7.             return false;
  8.         }
  9.        ...
  10.         // 赋值新的焦点给mCurrentFocus变量
  11.         ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
  12.                 mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
  13.         final WindowState oldFocus = mCurrentFocus;
  14.         mCurrentFocus = newFocus;
  15.                 ...
  16.         if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
  17.             // If we defer assigning layers, then the caller is responsible for doing this part.
  18.             // 当焦点改变,通过 inputMonitor通知 setInputFocusLw
  19.             getInputMonitor().setInputFocusLw(newFocus, updateInputWindows);
  20.         }
  21.    }
复制代码
setInputFocusLw 会调用对应的 updateInputWindowsLw 方法 ,该方法又会通过 scheduleUpdateInputWindows 启动 mUpdateInputWindows 使命
  1.         void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
  2.         ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d",
  3.                 newWindow, mDisplayId);
  4.                ...
  5.         if (updateInputWindows) {
  6.             updateInputWindowsLw(false /*force*/);
  7.         }
  8.     }
  9.         void updateInputWindowsLw(boolean force) {
  10.         if (!force && !mUpdateInputWindowsNeeded) {
  11.             return;
  12.         }
  13.         // 启动mUpdateInputWindows任务
  14.         scheduleUpdateInputWindows();
  15.     }
  16.    
  17.         private void scheduleUpdateInputWindows() {
  18.         if (mDisplayRemoved) {
  19.             return;
  20.         }
  21.         if (!mUpdateInputWindowsPending) {
  22.             mUpdateInputWindowsPending = true;
  23.             mHandler.post(mUpdateInputWindows);
  24.         }
  25.     }
复制代码
UpdateInputWindows 重要执行了 UpdateInputForAllWindowsConsumer的 updateInputWindows 方法
  1. private class UpdateInputWindows implements Runnable {
  2.         @Override
  3.         public void run() {
  4.             synchronized (mService.mGlobalLock) {
  5.                 ...
  6.                 // Add all windows on the default display.
  7.                 mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
  8.             }
  9.         }
  10.     }
复制代码
UpdateInputForAllWindowsConsumer 重要工作

  • 调用 disolayContent的forAllWindows,遍历所有windowState,去更新对应的信息
  • 调用 updateInputFocusRequest 去申请输入焦点,要通过requestFocus 申请了,才会在InputDispatcher 有数据,这样才会在后续的焦点更新那从request数据中获取到,不然一直会是null,没输入事件
  1. private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
  2.         ...
  3.         private void updateInputWindows(boolean inDrag) {
  4.             ...
  5.             // 遍历所有窗口信息,因为传入的为this,遍历的时候会调用的accept方法
  6.             mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
  7.             // 更新所有焦点,只要通过requestFocus 申请了,才会在InputDispatcher 有数据,
  8.             // 这样才会在后续的焦点更新那从request数据中获取到,不然一直会是null,没输入事件
  9.             updateInputFocusRequest(mRecentsAnimationInputConsumer);
  10.             if (!mUpdateInputWindowsImmediately) {
  11.                 // 合并对应的事务
  12.                 mDisplayContent.getPendingTransaction().merge(mInputTransaction);
  13.                 mDisplayContent.scheduleAnimation();
  14.             }
  15.             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
  16.         }
  17.         @Override
  18.         public void accept(WindowState w) {
  19.             // InputWindowHandleWrapper 包含displayId和InputApplicationHandle
  20.             final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle;
  21.             ...
  22.             if (w.mInputChannelToken == null || w.mRemoved
  23.                     || (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
  24.                 // 如果不可输入但是拥有 Surface,调用populateOverlayInputInfo重置下信息,如token重置
  25.                 // 在 openInputChannel的时候会赋值
  26.                 if (w.mWinAnimator.hasSurface()) {
  27.                     // Make sure the input info can't receive input event. It may be omitted from
  28.                     // occlusion detection depending on the type or if it's a trusted overlay.
  29.                     populateOverlayInputInfo(inputWindowHandle, w);
  30.                     setInputWindowInfoIfNeeded(mInputTransaction,
  31.                             w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
  32.                     return;
  33.                 }
  34.                 // Skip this window because it cannot possibly receive input.
  35.                 return;
  36.             }
  37.             ...
  38.             // 有surface
  39.             if (w.mWinAnimator.hasSurface()) {
  40.                     // 构造对应的inputWindowHandle信息,用于native传输
  41.                 populateInputWindowHandle(inputWindowHandle, w);
  42.                 // 调用 InputTransaction事务将InputWindowHandleWrapper放进去
  43.                 setInputWindowInfoIfNeeded(mInputTransaction,
  44.                         w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
  45.             }
  46.         }
  47.     }
复制代码
因为 forAllWindows 传入的是 this,以是会触发 accept 方法。该方法重要

  • 如果不可输入但是拥有 Surface,调用populateOverlayInputInfo重置下信息,如token重置为null(在 openInputChannel的时间会赋值)
  • 最后有Surface的时间 调用 populateInputWindowHandle ,构造对应的inputWindowHandle信息,用于native传输
4.2.1 更新窗口信息 setInputWindowInfo

4.2.1.1 WMS通知到SurfaceFlinger

通过 populateInputWindowHandle 设置好之后,就会调用 setInputWindowInfoIfNeeded,因为设置过以是 isChanged 返回true。以是会调用 applyChangesToSurface 方法提交到事务
  1.         static void setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc,
  2.             InputWindowHandleWrapper inputWindowHandle) {
  3.         if (DEBUG_INPUT) {
  4.             Slog.d(TAG_WM, "Update InputWindowHandle: " + inputWindowHandle);
  5.         }
  6.         // 只要有设置就会为true
  7.         if (inputWindowHandle.isChanged()) {
  8.             inputWindowHandle.applyChangesToSurface(t, sc);
  9.         }
  10.     }
复制代码
内里会调用事务的 setInputWIndowInfo
  1.         void applyChangesToSurface(@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl sc) {
  2.         // 调用Transaction的setInputWindowInfo将setInputWindowInfo保存进入
  3.         t.setInputWindowInfo(sc, mHandle);
  4.         mChanged = false;
  5.     }
复制代码
调用 nativeSetInputWindowInfo 将 对应 InputWindowHandle 信息传递给 SurfaceControl
  1.                 public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
  2.             checkPreconditions(sc);
  3.             nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
  4.             return this;
  5.         }
复制代码
nativeSetInputWindowInfo 内容如下

  • 通过 android_view_InputWindowHandle_getHandle 构建出 NativeInputWindowHandle 对象
  • 调用 updateInfo 方法,将 java的inputWindowHandler属性拿出,拷贝到 NativeInputWindowHandle变量
  • 调用 SurfaceComposerClient的setInputWindowInfo 更新窗口信息到数组
  1. // transactionObj参数是Transaction的指针,而nativeObject是SurfaceControl的指针
  2. static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactionObj,
  3.         jlong nativeObject, jobject inputWindow) {
  4.     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
  5.     // 创建 NativeInputWindowHandle 对象
  6.     sp<NativeInputWindowHandle> handle = android_view_InputWindowHandle_getHandle(
  7.             env, inputWindow);
  8.     // 将 java的inputWindowHandler属性拿出,拷贝到 NativeInputWindowHandle变量
  9.     handle->updateInfo();
  10.     // 获取SurfaceControl
  11.     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
  12.     // 调用 SurfaceComposerClient的setInputWindowInfo,会保存到 mComposerStates 数组,后续apply事务的时候就会从该数据遍历
  13.     transaction->setInputWindowInfo(ctrl, *handle->getInfo());
  14. }
复制代码
android_view_InputWindowHandle_getHandle 方法。会根据ptr属性获取,如果不为空则直接获取,否则在创建,并设置到对应ptr属性
  1. sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
  2.         JNIEnv* env, jobject inputWindowHandleObj) {
  3.     if (!inputWindowHandleObj) {
  4.         return NULL;
  5.     }
  6.     AutoMutex _l(gHandleMutex);
  7.     jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr);
  8.     NativeInputWindowHandle* handle;
  9.     // 获取对应的指针如果不为空则直接获取,否则在创建,并设置到对应ptr属性。
  10.     if (ptr) {
  11.         handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
  12.     } else {
  13.         jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
  14.         handle = new NativeInputWindowHandle(objWeak);
  15.         handle->incStrong((void*)android_view_InputWindowHandle_getHandle);
  16.         env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
  17.                 reinterpret_cast<jlong>(handle));
  18.     }
  19.     return handle;
  20. }
复制代码
updateInfo 进行深拷贝
  1. bool NativeInputWindowHandle::updateInfo() {
  2.     JNIEnv* env = AndroidRuntime::getJNIEnv();
  3.     jobject obj = env->NewLocalRef(mObjWeak);
  4.     ...
  5.         // windowState的token
  6.     jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token);
  7.     if (tokenObj) {
  8.         mInfo.token = ibinderForJavaObject(env, tokenObj);
  9.         env->DeleteLocalRef(tokenObj);
  10.     } else {
  11.         mInfo.token.clear();
  12.     }
  13.         ...
  14.     // 获取对应的 AIDL token(IWindow AIDL接口,用于wms和应用交互通知,如viewRootImpl的W)
  15.     // 通过 ibinderForJavaObject 转换放到 windowToken
  16.     jobject windowTokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.windowToken);
  17.     if (windowTokenObj) {
  18.         mInfo.windowToken = ibinderForJavaObject(env, windowTokenObj);
  19.         env->DeleteLocalRef(windowTokenObj);
  20.     } else {
  21.         mInfo.windowToken.clear();
  22.     }
  23.     env->DeleteLocalRef(obj);
  24.     return true;
  25. }
复制代码
setInputWindowInfo 方法,

  • 通过 getLayerState 创建对应 layer_state_t,该方法很紧张会将对应的信息保存到 mComposerStates
  • windowInfo放到WindowInfoHandle,并赋值给 layer_state_t
  1. SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
  2.         const sp<SurfaceControl>& sc, const WindowInfo& info) {
  3.     // 获取对应的 layer_state_t
  4.     layer_state_t* s = getLayerState(sc);
  5.     if (!s) {
  6.         mStatus = BAD_INDEX;
  7.         return *this;
  8.     }
  9.     // 将windowInfo放到WindowInfoHandle,并赋值给 layer_state_t
  10.     s->windowInfoHandle = new WindowInfoHandle(info);
  11.     // 记录变化的
  12.     s->what |= layer_state_t::eInputInfoChanged;
  13.     return *this;
  14. }
复制代码
getLayerState 会获取

  • SurfaceControl 对应的 binder对象。从mComposerStates数组判断是否存在
  • 不包含则创建,将对应信息放进去layer_state_t 并根据handler为key,放进mComposerStates
  • 返回 layer_state_t
  1. layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
  2.     // 获取SurfaceControl的binder
  3.     auto handle = sc->getLayerStateHandle();
  4.     // 判断 mComposerStates 是否包含,不包含则创建,并根据handler为key,放进mComposerStates
  5.     // 后续事务提交的时候,会从mComposerStates该数组遍历
  6.     if (mComposerStates.count(handle) == 0) {
  7.         // we don't have it, add an initialized layer_state to our list
  8.         ComposerState s;
  9.         // 放进 layer_state_t 中
  10.         s.state.surface = handle;
  11.         s.state.layerId = sc->getLayerId();
  12.         mComposerStates[handle] = s;
  13.     }
  14.     // 返回 layer_state_t
  15.     return &(mComposerStates[handle].state);
  16. }
复制代码
4.2.1.2 SurfaceFlinger 到 InputDIspatcher

事务在 提交的时间,就会调用 apply方法。又会调用过 nativeApplyTransaction 方法。
  1.                 public void apply(boolean sync) {
  2.             applyResizedSurfaces();
  3.             notifyReparentedSurfaces();
  4.             nativeApplyTransaction(mNativeObject, sync);
  5.         }
复制代码
native 又会调用 SurfaceComposerClient 的 apply 方法。
  1. static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
  2.     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
  3.     // 调用 SurfaceComposerClient 的apply
  4.     transaction->apply(sync);
  5. }
复制代码
apply方法

  • 获取 SurfaceFlinger的Binder代理sf
  • 开始遍历 mComposerStates, 添加到 composerStates
  • 跨历程调用SurfaceFlingersetTransactionState把composerStates作为参数
  1. status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
  2.     if (mStatus != NO_ERROR) {
  3.         return mStatus;
  4.     }
  5.     // 获取SurfaceFlinger的Binder代理sf,单例
  6.     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
  7.     ...
  8.     // 开始遍历 mComposerStates, 添加到 composerStates
  9.     for (auto const& kv : mComposerStates){
  10.         composerStates.add(kv.second);
  11.     }
  12.     ...
  13.         // 如果已经有则直接用,否则创建TransactionCompletedListener
  14.     sp<IBinder> applyToken = mApplyToken
  15.             ? mApplyToken
  16.             : IInterface::asBinder(TransactionCompletedListener::getIInstance());
  17.     // 跨进程调用SurfaceFlinger的setTransactionState把composerStates作为参数
  18.     sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
  19.                             mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
  20.                             {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
  21.                             hasListenerCallbacks, listenerCallbacks, mId);
  22.    
  23. }
复制代码
setTransactionState 会创建 TransactionState 对象,并调用 queueTransaction 方法,将事务(Transaction)参加队列。
  1. status_t SurfaceFlinger::setTransactionState(
  2.         const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
  3.         const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
  4.         const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
  5.         bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
  6.         const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
  7.     ...
  8.     // 将参数放到 TransactionState 对象中。
  9.     TransactionState state{frameTimelineInfo,  states,
  10.                            displays,           flags,
  11.                            applyToken,         inputWindowCommands,
  12.                            desiredPresentTime, isAutoTimestamp,
  13.                            uncacheBuffer,      postTime,
  14.                            permissions,        hasListenerCallbacks,
  15.                            listenerCallbacks,  originPid,
  16.                            originUid,          transactionId};
  17.     ...
  18.     // 把TransactionState放入队列,且会启动对应的scheduleCommit
  19.     queueTransaction(state);
  20.     // Check the pending state to make sure the transaction is synchronous.
  21.     if (state.transactionCommittedSignal) {
  22.         waitForSynchronousTransaction(*state.transactionCommittedSignal);
  23.     }
  24.     return NO_ERROR;
  25. }
复制代码
在每次SurfaceFlinger主线程进行commit操纵的时间,都会调用一次updateInputFlinger方法去更新一遍需要派发给InputDispatcher的窗口信息。
updateInputFlinger 方法会调用 notifyWindowInfos 方法开始通知 给inputDispatcher
  1. void SurfaceFlinger::updateInputFlinger() {
  2.     ATRACE_CALL();
  3.     if (!mInputFlinger) {
  4.         return;
  5.     }
  6.     if (mVisibleRegionsDirty || mInputInfoChanged) {
  7.         mInputInfoChanged = false;
  8.         // 调用通知给inputDispatcher
  9.         notifyWindowInfos();
  10.     }
  11.         ...
  12.     for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
  13.         mInputFlinger->setFocusedWindow(focusRequest);
  14.     }
  15. ;
  16. }
复制代码
notifyWindowInfos

  • 通过 traverseInReverseZOrder 开始遍历,判断是否需要,通过layer内里的 hasInputInfo 方法,hasInputInfo通过inputInfo的token是否为空判断,并将放到 windowInfos 数组尾部
  • 通过 mWindowInfosListenerInvoker 开始触发通知,给 InputDispatcher
  1. void SurfaceFlinger::notifyWindowInfos() {
  2.     std::vector<WindowInfo> windowInfos;
  3.     // 开始遍历,过滤需要的windowInfos
  4.     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
  5.         // 判断是否需要,通过layer里面的 hasInputInfo 方法,hasInputInfo通过inputInfo的token是否为空判断
  6.         if (!layer->needsInputInfo()) return;
  7.         sp<DisplayDevice> display = enablePerWindowInputRotation()
  8.                 ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer))
  9.                 : nullptr;
  10.         // When calculating the screen bounds we ignore the transparent region since it may
  11.         // result in an unwanted offset.
  12.         // 根据layer填满outWindowInfos信息
  13.         windowInfos.push_back(layer->fillInputInfo(display));
  14.     });
  15.     // 开始触发通知,给 InputDispatcher
  16.     mWindowInfosListenerInvoker->windowInfosChanged(windowInfos,
  17.                                                     mInputWindowCommands.syncInputWindows);
  18. }
复制代码
WindowInfosListenerInvoker 的 windowInfosChanged方法又会遍历listner,内里实在就是 InputDispather
  1. void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
  2.                                                     bool shouldSync) {
  3.     ...
  4.     // 这里listener其实就是InputDispather
  5.     for (const auto& listener : windowInfosListeners) {
  6.         listener->onWindowInfosChanged(windowInfos,
  7.                                        shouldSync ? mWindowInfosReportedListener : nullptr);
  8.     }
  9. }
复制代码
检察 InputDispather 的 onWindowInfosChanged 方法
  1. void InputDispatcher::onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) {
  2.     // The listener sends the windows as a flattened array. Separate the windows by display for
  3.     // more convenient parsing.
  4.     std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
  5.     for (const auto& info : windowInfos) {
  6.         handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
  7.         handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
  8.     }
  9.     setInputWindows(handlesPerDisplay);
  10. }
复制代码
setInputWindows 重要更新 内容

  • 调用 updateWindowHandlesForDisplayLocked,更新mWindowHandlesByDisplay对应该屏幕下的数据
  • 调用 FocusResolver 的 setInputWindows 开始设置焦点窗口
  1. void InputDispatcher::setInputWindowsLocked(
  2.         const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {
  3.     if (DEBUG_FOCUS) {
  4.         ...
  5.         ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str());
  6.     }
  7.     ...
  8.     // 比较更旧的windowInfo,更新mWindowHandlesByDisplay对应该屏幕下的数据
  9.     updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);
  10.    
  11.     // 判断是否改变窗口焦点
  12.     std::optional<FocusResolver::FocusChanges> changes =
  13.             mFocusResolver.setInputWindows(displayId, windowHandles);
  14.     if (changes) {
  15.         onFocusChangedLocked(*changes);
  16.     }
  17.     ...
  18. }
复制代码
FocusResolver 的 setInputWindows 方法

  • 通过getFocusedWindowToken(通过mFocusedWindowTokenByDisplay数组) 获取还没更新前的焦点窗口
  • 调用 isTokenFocusable,判断下当前窗口是否可以聚焦,如果还聚焦的话,则继续授予其焦点。返回null,表示不需要改变。
  • 通过 getFocusRequest(通过 mFocusRequestByDisplay 数组)方法获取哀求的焦点窗口,需要调用 (requestFocus),如果没哀求过的话,则表示没焦点
  • 如果哀求过,则再次通过 isTokenFocusable ,判断该窗口是否符合,如何的话则调用 updateFocusedWindow 方法进行更新,如果不符合的话,则传入null,将当前屏幕设置为没焦点
  1. std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows(
  2.         int32_t displayId, const std::vector<sp<WindowInfoHandle>>& windows) {
  3.     std::string removeFocusReason;
  4.     // Check if the currently focused window is still focusable.
  5.     // 通过 mFocusedWindowTokenByDisplay(mFocusedWindowTokenByDisplay数组) 检查下当前还没更新的焦点是否还在,这时候还没更新,所以获取的是旧的
  6.     const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
  7.     if (currentFocus) {
  8.         Focusability result = isTokenFocusable(currentFocus, windows);
  9.         // 返回ok,表示当前窗口仍可以聚焦,那么我们将继续授予其焦点
  10.         if (result == Focusability::OK) {
  11.             return std::nullopt;
  12.         }
  13.         removeFocusReason = NamedEnum::string(result);
  14.     }
  15.     // We don't have a focused window or the currently focused window is no longer focusable. Check
  16.     // to see if we can grant focus to the window that previously requested focus.
  17.     // 请求的requestFocus((mFocusRequestByDisplay数组))是否存在,如果没请求,那 updateFocusedWindow 只会传入null
  18.     const std::optional<FocusRequest> request = getFocusRequest(displayId);
  19.     if (request) {
  20.         sp<IBinder> requestedFocus = request->token;
  21.         const Focusability result = isTokenFocusable(requestedFocus, windows);
  22.         const Focusability previousResult = mLastFocusResultByDisplay[displayId];
  23.         mLastFocusResultByDisplay[displayId] = result;
  24.         // 如果可以 则调用 updateFocusedWindow 更新当前聚焦焦点
  25.         if (result == Focusability::OK) {
  26.             return updateFocusedWindow(displayId,
  27.                                        "Window became focusable. Previous reason: " +
  28.                                                NamedEnum::string(previousResult),
  29.                                        requestedFocus, request->windowName);
  30.         }
  31.     }
  32.     // Focused window is no longer focusable and we don't have a suitable focus request to grant.
  33.     // Remove focus if needed.
  34.     // 因为没请求,传入为空的对象更新为空的,让其失去焦点
  35.     return updateFocusedWindow(displayId, removeFocusReason, nullptr);
  36. }
复制代码
isTokenFocusable 判断是否符合条件 ,遍历表示是否可见,是否可聚焦
  1. FocusResolver::Focusability FocusResolver::isTokenFocusable(
  2.         const sp<IBinder>& token, const std::vector<sp<WindowInfoHandle>>& windows) {
  3.     bool allWindowsAreFocusable = true;
  4.     bool visibleWindowFound = false;
  5.     bool windowFound = false;
  6.     for (const sp<WindowInfoHandle>& window : windows) {
  7.         // 遍历到相等才执行判断
  8.         if (window->getToken() != token) {
  9.             continue;
  10.         }
  11.         windowFound = true;
  12.         // 至少有一个窗口可见
  13.         if (window->getInfo()->visible) {
  14.             // Check if at least a single window is visible.
  15.             visibleWindowFound = true;
  16.         }
  17.         // 检查所有窗口是否可聚焦
  18.         if (!window->getInfo()->focusable) {
  19.             // Check if all windows with the window token are focusable.
  20.             allWindowsAreFocusable = false;
  21.             break;
  22.         }
  23.     }
  24.     if (!windowFound) {
  25.         return Focusability::NO_WINDOW;
  26.     }
  27.     if (!allWindowsAreFocusable) {
  28.         return Focusability::NOT_FOCUSABLE;
  29.     }
  30.     if (!visibleWindowFound) {
  31.         return Focusability::NOT_VISIBLE;
  32.     }
  33.     return Focusability::OK;
  34. }
复制代码
updateFocusedWindow 方法

  • 会获取当前的窗口和要更新的窗口是否一致,是的话返回为空,表示不需要改变。
  • 在判断 newFocus 是否为空,不为空的则更新到 mFocusedWindowTokenByDisplay 数组,否则调用 errase 方法移除。丢失焦点
  1. std::optional<FocusResolver::FocusChanges> FocusResolver::updateFocusedWindow(
  2.         int32_t displayId, const std::string& reason, const sp<IBinder>& newFocus,
  3.         const std::string& tokenName) {
  4.     // 获取之前的焦点窗口,如果一样则返回空。
  5.     sp<IBinder> oldFocus = getFocusedWindowToken(displayId);
  6.     if (newFocus == oldFocus) {
  7.         return std::nullopt;
  8.     }
  9.     // 如果传入参数不为空,则更新到 mFocusedWindowTokenByDisplay 数据
  10.     // 为空则调用 errase,移除。
  11.     if (newFocus) {
  12.         mFocusedWindowTokenByDisplay[displayId] = {tokenName, newFocus};
  13.     } else {
  14.         mFocusedWindowTokenByDisplay.errase(displayId);
  15.     }
  16.     return {{oldFocus, newFocus, displayId, reason}};
  17. }
复制代码
这样就完成了到 InputDispatcher的聚焦窗口更新。
4.2.2 哀求窗口焦点

更新聚焦窗口,需要request数组有对应的哀求,之前的 InputMonitor 遍历后更新窗口信息,又会调用 updateInputFocusRequest 方法。又会调用 requestFocus 方法
4.2.2.1 WMS通知到SurfaceFlinger

  1. private void updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer) {
  2.         ...
  3.         // mInputChannelToken是否为空可以判断是否聚焦输入
  4.         final IBinder focusToken = focus != null ? focus.mInputChannelToken : null;
  5.         if (focusToken == null) {
  6.             mInputFocus = null;
  7.             return;
  8.         }
  9.                 ...
  10.         // 请求输入焦点
  11.         requestFocus(focusToken, focus.getName());
  12.     }
复制代码
requestFocus 会打印哀求的日志和 调用事务 Transaction 的 setFocusedWindow 方法。
  1. private void requestFocus(IBinder focusToken, String windowName) {
  2.         if (focusToken == mInputFocus) {
  3.             return;
  4.         }
  5.         mInputFocus = focusToken;
  6.         // 将对应焦点token设置到事务
  7.         mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId);
  8.         // 请求日志
  9.         EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + windowName,
  10.                 "reason=UpdateInputWindows");
  11.         ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", windowName);
  12.     }
复制代码
而 setFocusedWindow 又会调用 nativeSetFocusedWindow 方法。
  1.         public Transaction setFocusedWindow(@NonNull IBinder token, String windowName,
  2.                 int displayId) {
  3.             nativeSetFocusedWindow(mNativeObject, token,  windowName,
  4.                     null /* focusedToken */, null /* focusedWindowName */, displayId);
  5.             return this;
  6.         }
复制代码
nativeSetFocusedWindow 会创建对应的 FocusRequest 对象,并调用 setFocusedWindow 方法
  1. static void nativeSetFocusedWindow(JNIEnv* env, jclass clazz, jlong transactionObj,
  2.                                    jobject toTokenObj, jstring windowNameJstr,
  3.                                    jobject focusedTokenObj, jstring focusedWindowNameJstr,
  4.                                    jint displayId) {
  5.     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
  6.     if (toTokenObj == NULL) return;
  7.     // 转换对应的binder对象
  8.     sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj));
  9.     sp<IBinder> focusedToken;
  10.     if (focusedTokenObj != NULL) {
  11.         focusedToken = ibinderForJavaObject(env, focusedTokenObj);
  12.     }
  13.     // 创建 FocusRequest对象
  14.     FocusRequest request;
  15.     request.token = toToken;
  16.     if (windowNameJstr != NULL) {
  17.         ScopedUtfChars windowName(env, windowNameJstr);
  18.         request.windowName = windowName.c_str();
  19.     }
  20.     request.focusedToken = focusedToken;
  21.     if (focusedWindowNameJstr != NULL) {
  22.         ScopedUtfChars focusedWindowName(env, focusedWindowNameJstr);
  23.         request.focusedWindowName = focusedWindowName.c_str();
  24.     }
  25.     request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
  26.     request.displayId = displayId;
  27.     // 调用 SurfaceComposerClient的setFocusedWindow
  28.     transaction->setFocusedWindow(request);
  29. }
复制代码
setFocusedWindow 方法又会将对应的request 放到 mInputWindowCommands的focusRequests 数组
  1. SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow(
  2.         const FocusRequest& request) {
  3.     // 添加 mInputWindowCommands 到  focusRequests
  4.     mInputWindowCommands.focusRequests.push_back(request);
  5.     return *this;
  6. }
复制代码
跟上面一样 apply的时间 调用 SurfaceFlinger的 setTransactionState 时间 将 mInputWindowCommands 带已往给
  1. status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
  2.         ...
  3.         // 如果已经有则直接用,否则创建TransactionCompletedListener
  4.     sp<IBinder> applyToken = mApplyToken
  5.             ? mApplyToken
  6.             : IInterface::asBinder(TransactionCompletedListener::getIInstance());
  7.     // 跨进程调用SurfaceFlinger的setTransactionState把composerStates作为参数
  8.     // apply的时候 也会将 mInputWindowCommands 带过去
  9.     sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
  10.                             mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
  11.                             {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
  12.                             hasListenerCallbacks, listenerCallbacks, mId);
  13. }
复制代码
4.2.2.2 SurfaceFlinger 到 InputDIspatcher

同样 inputWindowCommands 也会放在 TransactionState 中,并调用 queueTransaction 放进队列,最终也会调用到 updateInputFlinger,会遍历对应的数组,然后调用 InputFlingersetFocusedWindow方法,也便是 InputManager 的 setFocusedWindow
  1. // 更新对应的
  2. void SurfaceFlinger::updateInputFlinger() {
  3.     ATRACE_CALL();
  4.     if (!mInputFlinger) {
  5.         return;
  6.     }
  7.     if (mVisibleRegionsDirty || mInputInfoChanged) {
  8.         mInputInfoChanged = false;
  9.         // 调用通知给inputDispatcher
  10.         notifyWindowInfos();
  11.     }
  12.     ...
  13.     // 开始遍历每一个焦点请求,调用 mInputFlinger
  14.     for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
  15.         mInputFlinger->setFocusedWindow(focusRequest);
  16.     }
  17.     mInputWindowCommands.clear();
  18. }
复制代码
  1. class InputManager : public InputManagerInterface, public BnInputFlinger {
  2. protected:
  3.     ~InputManager() override;
复制代码
inputManger 又会调用 mDispatcher 的setFocusedWindow
  1. binder::Status InputManager::setFocusedWindow(const FocusRequest& request) {
  2.     mDispatcher->setFocusedWindow(request);
  3.     return binder::Status::ok();
  4. }
复制代码
InputDispatcher内里 又会调用 FocusResolver的setFocusedWindow
  1. void InputDispatcher::setFocusedWindow(const FocusRequest& request) {
  2.     { // acquire lock
  3.         std::scoped_lock _l(mLock);
  4.         // 又会调用 FocusResolver的setFocusedWindow
  5.         std::optional<FocusResolver::FocusChanges> changes =
  6.                 mFocusResolver.setFocusedWindow(request, getWindowHandlesLocked(request.displayId));
  7.         if (changes) {
  8.             onFocusChangedLocked(*changes);
  9.         }
  10.     } // release lock
  11.     // Wake up poll loop since it may need to make new input dispatching choices.
  12.     mLooper->wake();
  13. }
复制代码
FocusResolver 的 setFocusedWindow 方法

  • 获取当前的窗口焦点**,如果和当前的一样,则直接返回空,表示无变化**
  • 如果哀求聚焦已经是聚焦的的情况下进入,如果 跟当前的不一致,则用当前的即可,如果当前request是可用的话,则调用 updateFocusedWindow 更新,否则也返回空,抛弃该哀求
  • 如果是可用的窗口,将对应的信息保存到 mFocusRequestByDisplay 中,在 setInputWindows 中可用
  • 再次判断是否可用,不可用则调用 updateFocusedWindow,否则传入null 丢失窗口,因为保存在 mFocusRequestByDisplay 中,等待下一次窗口状态改变哀求
  1. std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow(
  2.         const FocusRequest& request, const std::vector<sp<WindowInfoHandle>>& windows) {
  3.     const int32_t displayId = request.displayId;
  4.     // 获取当前的窗口焦点
  5.     const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
  6.     if (currentFocus == request.token) {
  7.         ALOGD_IF(DEBUG_FOCUS,
  8.                  "setFocusedWindow %s on display %" PRId32 " ignored, reason: already focused",
  9.                  request.windowName.c_str(), displayId);
  10.         return std::nullopt;
  11.     }
  12.     // Handle conditional focus requests, i.e. requests that have a focused token. These requests
  13.     // are not persistent. If the window is no longer focusable, we expect focus to go back to the
  14.     // previously focused window.
  15.     // 如果请求聚焦已经是聚焦的的情况下进入,(正常请求的时候,并还没聚焦)
  16.     if (request.focusedToken) {
  17.         // 跟当前的不一致,则用当前的即可
  18.         if (currentFocus != request.focusedToken) {
  19.             ALOGW("setFocusedWindow %s on display %" PRId32
  20.                   " ignored, reason: focusedToken %s is not focused",
  21.                   request.windowName.c_str(), displayId, request.focusedWindowName.c_str());
  22.             return std::nullopt;
  23.         }
  24.         // 是否可聚焦,是的话更新窗口信息
  25.         Focusability result = isTokenFocusable(request.token, windows);
  26.         if (result == Focusability::OK) {
  27.             return updateFocusedWindow(displayId, "setFocusedWindow with focus check",
  28.                                        request.token, request.windowName);
  29.         }
  30.         // 已经不符合可聚焦了,无需设置 返回空指针
  31.         ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: %s",
  32.               request.windowName.c_str(), displayId, NamedEnum::string(result).c_str());
  33.         return std::nullopt;
  34.     }
  35.     // 如果是可用的窗口,将对应的信息保存到 mFocusRequestByDisplay 中,在 setInputWindows 中可用
  36.     Focusability result = isTokenFocusable(request.token, windows);
  37.     // Update focus request. The focus resolver will always try to handle this request if there is
  38.     // no focused window on the display.
  39.     mFocusRequestByDisplay[displayId] = request;
  40.     mLastFocusResultByDisplay[displayId] = result;
  41.     // 如果结果是ok,更新对应的焦点窗口
  42.     if (result == Focusability::OK) {
  43.         return updateFocusedWindow(displayId, "setFocusedWindow", request.token,
  44.                                    request.windowName);
  45.     }
  46.     // The requested window is not currently focusable. Wait for the window to become focusable
  47.     // but remove focus from the current window so that input events can go into a pending queue
  48.     // and be sent to the window when it becomes focused.
  49.     // 当前request不是符合的窗口 传入null 设置当前为没焦点窗口,后续 窗口改变,通过 setInputWindows 可用
  50.     return updateFocusedWindow(displayId, "Waiting for window because " + NamedEnum::string(result),
  51.                                nullptr);
  52. }
复制代码
这样就完成了 焦点的哀求流程
5 打印 Focus entering" 或 Focus leaving

从上面流程 调用 setFocusedWindow 或者 setInputWindowsLocked 有改变后就会调用 onFocusChangedLocked 方法。
  1.         // 判断是否改变窗口焦点
  2.     std::optional<FocusResolver::FocusChanges> changes =
  3.             mFocusResolver.setInputWindows(displayId, windowHandles);
  4.     if (changes) {
  5.         onFocusChangedLocked(*changes);
  6.     }
复制代码
  1.                 // 又会调用 FocusResolver的setFocusedWindow
  2.         std::optional<FocusResolver::FocusChanges> changes =
  3.                 mFocusResolver.setFocusedWindow(request, getWindowHandlesLocked(request.displayId));
  4.         if (changes) {
  5.             onFocusChangedLocked(*changes);
  6.         }
复制代码
onFocusChangedLocked 会根据传进来的 oldFocus 和 newFocus,分别调用 enqueueFocusEventLocked 方法,发送 focus的event事件
  1. void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& changes) {
  2.     // 如果有改变,分别调用 旧焦点和新焦点,传入 enqueueFocusEventLocked 方法
  3.     // 旧的
  4.     if (changes.oldFocus) {
  5.         std::shared_ptr<InputChannel> focusedInputChannel = getInputChannelLocked(changes.oldFocus);
  6.         if (focusedInputChannel) {
  7.             CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
  8.                                        "focus left window");
  9.             synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options);
  10.             enqueueFocusEventLocked(changes.oldFocus, false /*hasFocus*/, changes.reason);
  11.         }
  12.     }
  13.     // 新的
  14.     if (changes.newFocus) {
  15.         enqueueFocusEventLocked(changes.newFocus, true /*hasFocus*/, changes.reason);
  16.     }
  17.     ...
  18. }
复制代码
构造对应event type为 EventEntry::Type::FOCUS 的事件,插入到 mInboundQueue 即 IQ队列
  1. void InputDispatcher::enqueueFocusEventLocked(const sp<IBinder>& windowToken, bool hasFocus,
  2.                                               const std::string& reason) {
  3.     if (mPendingEvent != nullptr) {
  4.         // Move the pending event to the front of the queue. This will give the chance
  5.         // for the pending event to get dispatched to the newly focused window
  6.         mInboundQueue.push_front(mPendingEvent);
  7.         mPendingEvent = nullptr;
  8.     }
  9.     std::unique_ptr<FocusEntry> focusEntry =
  10.             std::make_unique<FocusEntry>(mIdGenerator.nextId(), now(), windowToken, hasFocus,
  11.                                          reason);
  12.     // This event should go to the front of the queue, but behind all other focus events
  13.     // Find the last focus event, and insert right after it
  14.     std::deque<std::shared_ptr<EventEntry>>::reverse_iterator it =
  15.             std::find_if(mInboundQueue.rbegin(), mInboundQueue.rend(),
  16.                          [](const std::shared_ptr<EventEntry>& event) {
  17.                              return event->type == EventEntry::Type::FOCUS;
  18.                          });
  19.     // Maintain the order of focus events. Insert the entry after all other focus events.
  20.     mInboundQueue.insert(it.base(), std::move(focusEntry));
  21. }
复制代码
下一次循环叫醒的时间,就会执行 dispatchOnce 方法。和之前一样队列有东西 就会调用 dispatchOnceInnerLocked。该方法会从 IQ队列获取,判断到类型为 EventEntry::Type::FOCUS 就会调用 dispatchFocusLocked 方法。
  1. void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
  2.         switch (mPendingEvent->type) {
  3.                 case EventEntry::Type::FOCUS: {
  4.             std::shared_ptr<FocusEntry> typedEntry =
  5.                     std::static_pointer_cast<FocusEntry>(mPendingEvent);
  6.             dispatchFocusLocked(currentTime, typedEntry);
  7.             done = true;
  8.             dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
  9.             break;
  10.         }
  11.         }
  12. }
复制代码
dispatchFocusLocked 就会打印对应的窗口脱离和进入日志
  1. void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry) {
  2.     std::shared_ptr<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
  3.     if (channel == nullptr) {
  4.         return; // Window has gone away
  5.     }
  6.     InputTarget target;
  7.     target.inputChannel = channel;
  8.     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
  9.     entry->dispatchInProgress = true;
  10.     // 打印对应的信息
  11.     std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
  12.             channel->getName();
  13.     std::string reason = std::string("reason=").append(entry->reason);
  14.     android_log_event_list(LOGTAG_INPUT_FOCUS) << message << reason << LOG_ID_EVENTS;
  15.     dispatchEventLocked(currentTime, entry, {target});
  16. }
复制代码
3 堆栈

3.1 setFocusApp

启动App堆栈
  1. setFocusedApp:3655, DisplayContent (com.android.server.wm)
  2. setResumedActivityUncheckLocked:4539, ActivityTaskManagerService (com.android.server.wm)
  3. onActivityStateChanged:579, TaskFragment (com.android.server.wm)
  4. setState:5163, ActivityRecord (com.android.server.wm)
  5. minimalResumeActivityLocked:4783, Task (com.android.server.wm)
  6. realStartActivityLocked:938, ActivityTaskSupervisor (com.android.server.wm)
  7. startSpecificActivity:1005, ActivityTaskSupervisor (com.android.server.wm)
  8. resumeTopActivity:1348, TaskFragment (com.android.server.wm)
  9. resumeTopActivityInnerLocked:5037, Task (com.android.server.wm)
  10. resumeTopActivityUncheckedLocked:4971, Task (com.android.server.wm)
  11. resumeFocusedTasksTopActivities:2398, RootWindowContainer (com.android.server.wm)
  12. resumeFocusedTasksTopActivities:2383, RootWindowContainer (com.android.server.wm)
  13. completePause:1608, TaskFragment (com.android.server.wm)
  14. activityPaused:5734, ActivityRecord (com.android.server.wm)
  15. activityPaused:176, ActivityClientController (com.android.server.wm)
  16. onTransact:548, IActivityClientController$Stub (android.app)
  17. onTransact:121, ActivityClientController (com.android.server.wm)
  18. execTransactInternal:1179, Binder (android.os)
  19. execTransact:1143, Binder (android.os)
复制代码
按home建,回退的时间
  1. setFocusedApp:3655, DisplayContent (com.android.server.wm)
  2. setResumedActivityUncheckLocked:4539, ActivityTaskManagerService (com.android.server.wm)
  3. moveFocusableActivityToTop:3001, ActivityRecord (com.android.server.wm)
  4. moveTaskToFront:5581, Task (com.android.server.wm)
  5. setTargetRootTaskIfNeeded:2733, ActivityStarter (com.android.server.wm)
  6. recycleTask:2062, ActivityStarter (com.android.server.wm)
  7. startActivityInner:1762, ActivityStarter (com.android.server.wm)
  8. startActivityUnchecked:1594, ActivityStarter (com.android.server.wm)
  9. executeRequest:1195, ActivityStarter (com.android.server.wm)
  10. execute:674, ActivityStarter (com.android.server.wm)
  11. startHomeActivity:179, ActivityStartController (com.android.server.wm)
  12. startHomeOnTaskDisplayArea:1604, RootWindowContainer (com.android.server.wm)
  13. lambda$startHomeOnDisplay$12$RootWindowContainer:1545, RootWindowContainer (com.android.server.wm)
  14. apply:-1, RootWindowContainer$$ExternalSyntheticLambda10 (com.android.server.wm)
  15. reduceOnAllTaskDisplayAreas:554, TaskDisplayArea (com.android.server.wm)
  16. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  17. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  18. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  19. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  20. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  21. reduceOnAllTaskDisplayAreas:2091, WindowContainer (com.android.server.wm)
  22. startHomeOnDisplay:1544, RootWindowContainer (com.android.server.wm)
  23. startHomeOnDisplay:5839, ActivityTaskManagerService$LocalService (com.android.server.wm)
  24. startDockOrHome:5106, PhoneWindowManager (com.android.server.policy)
  25. startDockOrHome:5111, PhoneWindowManager (com.android.server.policy)
  26. launchHomeFromHotKey:3254, PhoneWindowManager (com.android.server.policy)
  27. launchHomeFromHotKey:3211, PhoneWindowManager (com.android.server.policy)
  28. handleShortPressOnHome:1351, PhoneWindowManager (com.android.server.policy)
  29. access$2200:240, PhoneWindowManager (com.android.server.policy)
  30. lambda$handleHomeButton$0$PhoneWindowManager$DisplayHomeButtonHandler:1501, PhoneWindowManager$DisplayHomeButtonHandler (com.android.server.policy)
  31. run:-1, PhoneWindowManager$DisplayHomeButtonHandler$$ExternalSyntheticLambda0 (com.android.server.policy)
  32. handleCallback:938, Handler (android.os)
  33. dispatchMessage:99, Handler (android.os)
  34. loopOnce:201, Looper (android.os)
  35. loop:288, Looper (android.os)
  36. run:67, HandlerThread (android.os)
  37. run:44, ServiceThread (com.android.server)
  38. run:45, UiThread (com.android.server)
复制代码
  1. setFocusedApp:3655, DisplayContent (com.android.server.wm)
  2. setResumedActivityUncheckLocked:4539, ActivityTaskManagerService (com.android.server.wm)
  3. onActivityStateChanged:579, TaskFragment (com.android.server.wm)
  4. setState:5163, ActivityRecord (com.android.server.wm)
  5. resumeTopActivity:1227, TaskFragment (com.android.server.wm)
  6. resumeTopActivityInnerLocked:5037, Task (com.android.server.wm)
  7. resumeTopActivityUncheckedLocked:4971, Task (com.android.server.wm)
  8. resumeTopActivityUncheckedLocked:4985, Task (com.android.server.wm)
  9. resumeFocusedTasksTopActivities:2398, RootWindowContainer (com.android.server.wm)
  10. resumeTargetRootTaskIfNeeded:2788, ActivityStarter (com.android.server.wm)
  11. recycleTask:2113, ActivityStarter (com.android.server.wm)
  12. startActivityInner:1762, ActivityStarter (com.android.server.wm)
  13. startActivityUnchecked:1594, ActivityStarter (com.android.server.wm)
  14. executeRequest:1195, ActivityStarter (com.android.server.wm)
  15. execute:674, ActivityStarter (com.android.server.wm)
  16. startHomeActivity:179, ActivityStartController (com.android.server.wm)
  17. startHomeOnTaskDisplayArea:1604, RootWindowContainer (com.android.server.wm)
  18. lambda$startHomeOnDisplay$12$RootWindowContainer:1545, RootWindowContainer (com.android.server.wm)
  19. apply:-1, RootWindowContainer$$ExternalSyntheticLambda10 (com.android.server.wm)
  20. reduceOnAllTaskDisplayAreas:554, TaskDisplayArea (com.android.server.wm)
  21. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  22. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  23. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  24. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  25. reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
  26. reduceOnAllTaskDisplayAreas:2091, WindowContainer (com.android.server.wm)
  27. startHomeOnDisplay:1544, RootWindowContainer (com.android.server.wm)
  28. startHomeOnDisplay:5839, ActivityTaskManagerService$LocalService (com.android.server.wm)
  29. startDockOrHome:5106, PhoneWindowManager (com.android.server.policy)
  30. startDockOrHome:5111, PhoneWindowManager (com.android.server.policy)
  31. launchHomeFromHotKey:3254, PhoneWindowManager (com.android.server.policy)
  32. launchHomeFromHotKey:3211, PhoneWindowManager (com.android.server.policy)
  33. handleShortPressOnHome:1351, PhoneWindowManager (com.android.server.policy)
  34. access$2200:240, PhoneWindowManager (com.android.server.policy)
  35. lambda$handleHomeButton$0$PhoneWindowManager$DisplayHomeButtonHandler:1501, PhoneWindowManager$DisplayHomeButtonHandler (com.android.server.policy)
  36. run:-1, PhoneWindowManager$DisplayHomeButtonHandler$$ExternalSyntheticLambda0 (com.android.server.policy)
  37. handleCallback:938, Handler (android.os)
  38. dispatchMessage:99, Handler (android.os)
  39. loopOnce:201, Looper (android.os)
  40. loop:288, Looper (android.os)
  41. run:67, HandlerThread (android.os)
  42. run:44, ServiceThread (com.android.server)
  43. run:45, UiThread (com.android.server)
复制代码
退却键
  1. setFocusedApp:3655, DisplayContent (com.android.server.wm)
  2. setResumedActivityUncheckLocked:4539, ActivityTaskManagerService (com.android.server.wm)
  3. moveFocusableActivityToTop:3001, ActivityRecord (com.android.server.wm)
  4. moveHomeActivityToTop:1880, TaskDisplayArea (com.android.server.wm)
  5. adjustFocusToNextFocusableTask:2484, Task (com.android.server.wm)
  6. finishIfPossible:3144, ActivityRecord (com.android.server.wm)
  7. finishActivity:451, ActivityClientController (com.android.server.wm)
  8. onTransact:688, IActivityClientController$Stub (android.app)
  9. onTransact:121, ActivityClientController (com.android.server.wm)
  10. execTransactInternal:1184, Binder (android.os)
  11. execTransact:1143, Binder (android.os)
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表