讲解 焦点窗口如何表现以及如何检察当前焦点窗口
相关知识点
- 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
执行后部分内容如下
- WINDOW MANAGER LAST ANR 打印出上次 ANR的原因,也会包含ANR时间的窗口信息,如 mCurrentFocus,mFocusedApp
- mCurrentFocus 表示当前焦点窗口
- mFocusedApp 表示当前焦点应用
- WINDOW MANAGER LAST ANR (dumpsys window lastanr)
- ANR time: 2025年2月21日 上午6:36:09
- Application at fault: ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity
- Reason: Application does not have a focused window
- Windows added in display #0 since null focus: [Window{87d5194 u0 com.example.mysystemdialog/com.example.mysystemdialog.MainActivity}]
- Windows removed in display #0 since null focus: [Window{26b1193 u0 Splash Screen com.example.mysystemdialog}]
- ....
- WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)
- mLastOrientationSource=WindowedMagnification:0:31@59915038
- deepestLastOrientationSource=ActivityRecord{d4b3e0 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t14}
- 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}
- Display: mDisplayId=0 rootTasks=4
- init=1440x2960 560dpi cur=1440x2960 app=1440x2792 rng=1440x1356-2792x2708
- deferred=false mLayoutNeeded=false mTouchExcludeRegion=SkRegion((0,0,1440,2960))
- mLayoutSeq=636
- mCurrentFocus=Window{ea70127 u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}
- mFocusedApp=ActivityRecord{d4b3e0 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t14}
复制代码 如果只想检察 ANR 也可以直接执行如下命令检察.
- WINDOW MANAGER LAST ANR (dumpsys window lastanr)
- ANR time: 2025年2月21日 上午6:36:09
- Application at fault: ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity
- Reason: Application does not have a focused window
- Windows added in display #0 since null focus: [Window{87d5194 u0 com.example.mysystemdialog/com.example.mysystemdialog.MainActivity}]
- Windows removed in display #0 since null focus: [Window{26b1193 u0 Splash Screen com.example.mysystemdialog}]
- ...
- Last ANR continued
- WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)
- mLastOrientationSource=WindowedMagnification:0:31@59915038
- deepestLastOrientationSource=ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19}
- 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}
- Display: mDisplayId=0 rootTasks=5
- init=1440x2960 560dpi cur=1440x2960 app=1440x2792 rng=1440x1356-2792x2708
- deferred=false mLayoutNeeded=false mTouchExcludeRegion=SkRegion((0,0,1440,2960))
复制代码 1.2 dump input
执行如下命令
打印内容如下
- FocusedApplications 表示当前焦点的应用
- FocusedWindows 表示当前的焦点窗口
- Input Dispatcher State at time of last ANR 开始记录上一次ANR的状态
- Input Dispatcher State:
- DispatchEnabled: true
- DispatchFrozen: false
- InputFilterEnabled: false
- FocusedDisplayId: 0
- FocusedApplications:
- displayId=0, name='ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19}', dispatchingTimeout=5000ms
- FocusedWindows:
- displayId=0, name='577c5c1 Application Not Responding: com.example.mysystemdialog'
- FocusRequests:
- displayId=0, name='577c5c1 Application Not Responding: com.example.mysystemdialog' result='OK'
- Input Dispatcher State at time of last ANR:
- ANR:
- Time: 2025-02-21 06:36:09
- Reason: ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19} does not have a focused window
- Window: ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19}
- ...
- FocusedApplications:
- displayId=0, name='ActivityRecord{7f16991 u0 com.example.mysystemdialog/.MainActivity t19}', dispatchingTimeout=5000ms
- FocusedWindows: <none>
复制代码 1.3 input Events 日志
也可以过滤日志检察当前的焦点
- adb shell logcat -b events | grep input_focus
复制代码 执行后可以看到如下日志
- Focus leaving 表示输入正在取消
- Focus request 表示输入哀求
- Focus entering 表示输入焦点在这个window
- 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]
- 02-21 06:36:10.304 6677 6700 I input_focus: [Focus request 577c5c1 Application Not Responding: com.example.mysystemdialog,reason=UpdateInputWindows]
- 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 检察关键的日志
打开对应的日志命令
- adb shell wm logging enable-text WM_DEBUG_SCREEN_ON WM_DEBUG_APP_TRANSITIONS WM_DEBUG_FOCUS
复制代码 过滤日志关键词
- adb shell logcat | grep -IE "Changing focus from|findFocusedWindow: No focusable|setFocusedApp|setAppVisibility|Relayout "
复制代码 2 更新当前焦点应用
当窗口的弹出,并不会改变当前焦点应用。只有改变应用切换才会触发,各种情况触发堆栈如3.1 打印。以是存在如焦点窗口是systemUi, 焦点应用是应用等情况。触发变化大部分都是从 ActivityTaskManagerService 的 setResumedActivityUncheckLocked 当更改ActivityReord 状态为resume状态的时间。
- void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
- ....
- mLastResumedActivity = r;
- // 通过设置可见的时候,就会执行displayContent的setFocusedApp方法去更新当前焦点的mFocusedApp变量
- // 拉出状态栏等操作并不会改变该焦点应用
- final boolean changed = r.mDisplayContent.setFocusedApp(r);
- if (changed) {
- mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
- true /*updateInputWindows*/);
- }
复制代码 会调用 displayContent 的 setFocusedApp 设置当前焦点的APP,如果有改变 则又会调 WindowManagerService 的 updateFocusedWindowLocked 进行更新窗口焦点
- boolean setFocusedApp(ActivityRecord newFocus) {
- ...
- final Task oldTask = mFocusedApp != null ? mFocusedApp.getTask() : null;
- final Task newTask = newFocus != null ? newFocus.getTask() : null;
- mFocusedApp = newFocus;
- if (oldTask != newTask) {
- if (oldTask != null) oldTask.onAppFocusChanged(false);
- if (newTask != null) newTask.onAppFocusChanged(true);
- }
- ...
- }
复制代码 接着又调用
- boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
- boolean changed = mRoot.updateFocusedWindowLocked(mode, updateInputWindows);
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- return changed;
- }
复制代码 3 更新当前焦点窗口
当启动一个activity的时间 会经历2个阶段,焦点为null ,到焦点存在。
当 新Activity 启动的时间 进入 resume 和 上一个Activity就会进入 onPause 状态
3.1 焦点丢失
当进入桌面onPause的时间,会通过 setVisibility 设置桌面应用不可见
- 将对应打开中和关闭中的app移除,后续在根据可见状态添加
- 调用 setVisibleRequested 设置对应的变量
- void setVisibility(boolean visible, boolean deferHidingClient) {
- ...
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
- appToken, visible, appTransition, isVisible(), mVisibleRequested,
- Debug.getCallers(6));
- final DisplayContent displayContent = getDisplayContent();
- // 先将要打开的app和关闭的app移除,后面在根据visible
- displayContent.mOpeningApps.remove(this);
- displayContent.mClosingApps.remove(this);
- waitingToShow = false;
- // 当前设置是否可见的时候,会将mVisibleRequested赋值,用于判断canReceiveKeys是否可触摸
- setVisibleRequested(visible);
- ...
- }
复制代码 setVisibleRequested 方法重要将 mVisibleRequested 设置为false ,后续判断是否可见吸收事件会用到该变量
- private void setVisibleRequested(boolean visible) {
- if (visible == mVisibleRequested) {
- return;
- }
- // 设置可见的请求
- mVisibleRequested = visible;
- setInsetsFrozen(!visible);
- if (app != null) {
- mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
- }
- logAppCompatState();
- }
复制代码 对应的日志打印包括堆栈如下
- 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开始探求对应的 窗口,看是否改变
- void onActivityStateChanged(ActivityRecord record, ActivityRecord.State state,
- String reason) {
- warnForNonLeafTaskFragment("onActivityStateChanged");
- if (record == mResumedActivity && state != RESUMED) {
- setResumedActivity(null, reason + " - onActivityStateChanged");
- }
- if (state == RESUMED) {
- if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
- Slog.v(TAG, "set resumed activity to:" + record + " reason:" + reason);
- }
- setResumedActivity(record, reason + " - onActivityStateChanged");
- if (record == mRootWindowContainer.getTopResumedActivity()) {
- mAtmService.setResumedActivityUncheckLocked(record, reason);
- }
- mTaskSupervisor.mRecentTasks.add(record.getTask());
- }
- }
复制代码 setResumedActivityUncheckLocked 方法会调用 displayContent的 setFocusedApp 方法设置焦点
- void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
- ...
- mLastResumedActivity = r;
- // 通过设置可见的时候,就会执行displayContent的setFocusedApp方法去更新当前焦点的mFocusedApp变量
- // 拉出状态栏等操作并不会改变该焦点应用
- final boolean changed = r.mDisplayContent.setFocusedApp(r);
- if (changed) {
- mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
- true /*updateInputWindows*/);
- }
- ...
- }
复制代码 接着又调用 RootWindowContainer的updateFocusedWindowLocked
- boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
- boolean changed = mRoot.updateFocusedWindowLocked(mode, updateInputWindows);
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- return changed;
- }
复制代码 又会遍历各自的displayContent 的 updateFocusedWindowLocked 更新焦点
- boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
- mTopFocusedAppByProcess.clear();
- boolean changed = false;
- int topFocusedDisplayId = INVALID_DISPLAY;
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final DisplayContent dc = mChildren.get(i);
- // 更新对应窗口焦点
- changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows, topFocusedDisplayId);
- }
- }
复制代码 updateFocusedWindowLocked
- 会先通过 findFocusedWindowIfNeeded 遍历获取对应的窗口
- 判断是否和当前一样,是的话返回false,否则将新的窗口赋值给 mCurrentFocus
- boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows,
- int topFocusedDisplayId) {
- // 查找新焦点,如果界面setVisibility为false则没焦点
- WindowState newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
- // 如果是一样的则返回
- if (mCurrentFocus == newFocus) {
- return false;
- }
- ...
- // 赋值新的焦点给mCurrentFocus变量
- ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
- mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
- final WindowState oldFocus = mCurrentFocus;
- mCurrentFocus = newFocus;
- }
复制代码 findFocusedWindowIfNeeded 方法通过 findFocusedWindow 方法(判断实现为 mFindFocusedWindow)遍历获取,并将符合条件的保存到 mTmpWindow, 并返回。
- WindowState findFocusedWindowIfNeeded(int topFocusedDisplayId) {
- return (mWmService.mPerDisplayFocusEnabled || topFocusedDisplayId == INVALID_DISPLAY)
- ? findFocusedWindow() : null;
- }
- WindowState findFocusedWindow() {
- mTmpWindow = null;
- // 开始从上到下遍历查找,查找到保存到 mTmpWindow 变量
- forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
- if (mTmpWindow == null) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows, display=%d",
- getDisplayId());
- return null;
- }
- return mTmpWindow;
- }
复制代码 mFindFocusedWindow 重要通过 WindowState的canReceiveKeys 方法
- private final ToBooleanFunction<WindowState> mFindFocusedWindow = w -> {
- // 当前聚焦的应用
- final ActivityRecord focusedApp = mFocusedApp;
- ProtoLog.v(WM_DEBUG_FOCUS, "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
- w, w.mAttrs.flags, w.canReceiveKeys(),
- w.canReceiveKeysReason(false /* fromUserTouch */));
- // 判断当前是否能接收事件,主要依靠mVisibleRequested属性
- // 而该属性在 setVisisable设置,表示是否可见
- if (!w.canReceiveKeys()) {
- return false;
- }
- }
复制代码 canReceiveKeys 方法判断如下,通过isVisibleRequestedOrAdding,可见和是否没带 FLAG_NOT_FOCUSABLE等变量判断
- public String canReceiveKeysReason(boolean fromUserTouch) {
- return "fromTouch= " + fromUserTouch
- + " isVisibleRequestedOrAdding=" + isVisibleRequestedOrAdding()
- + " mViewVisibility=" + mViewVisibility
- + " mRemoveOnExit=" + mRemoveOnExit
- + " flags=" + mAttrs.flags
- + " appWindowsAreFocusable="
- + (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
- + " canReceiveTouchInput=" + canReceiveTouchInput()
- + " displayIsOnTop=" + getDisplayContent().isOnTop()
- + " displayIsTrusted=" + getDisplayContent().isTrusted();
- }
- public boolean canReceiveKeys(boolean fromUserTouch) {
- final boolean canReceiveKeys = isVisibleRequestedOrAdding()
- && (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
- && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
- && (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
- && canReceiveTouchInput();
- if (!canReceiveKeys) {
- return false;
- }
- // Do not allow untrusted virtual display to receive keys unless user intentionally
- // touches the display.
- return fromUserTouch || getDisplayContent().isOnTop()
- || getDisplayContent().isTrusted();
- }
复制代码 而 isVisibleRequestedOrAdding 方法 重要就是依赖刚才的变量 mVisibleRequested
- boolean isVisibleRequestedOrAdding() {
- final ActivityRecord atoken = mActivityRecord;
- return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
- && isVisibleByPolicy() && !isParentWindowHidden()
- && (atoken == null || atoken.mVisibleRequested)
- && !mAnimatingExit && !mDestroying;
- }
复制代码 以是 因为桌面设置了不可见 和新启动的windowState是 Splash Screen 固然可见,但是携带了 FLAG_NOT_FOCUSABLE ,以是遍历下来,此时没有可聚焦的窗口,就会返回null.。这样 当前的 mCurrentFocus 变为了 null
3.2 获得窗口焦点
- 当对应的Activity启动后,进入realStartActivityLocked方法 时间,就会触发 setVisibility,将变量 mVisibleRequested 设置为true
详细日志如下
- 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
- public int relayoutWindow(...){
- // 如果可见不一样 或者flagFLAG_NOT_FOCUSABL有变化
- boolean focusMayChange = win.mViewVisibility != viewVisibility
- || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
- || (!win.mRelayoutCalled);
- // 如果窗口改变则执行该方法去更新对应屏幕的焦点窗口
- if (focusMayChange) {
- if (updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/)) {
- imMayMove = false;
- }
- }
- }
复制代码 updateFocusedWindowLocked 上面已讲解,此时 目标应用 已经为可见可触摸 ,以是可以查询到 ,以是焦点会变更为 桌面焦点。这样焦点就规复了
4 窗口信息到InputDispatcher
当WMS保存了对应的焦点应用和窗口后,也要同步到 Input端。DisplayContent 负责传输的类是InputMonitor 。
4.1 焦点应用通知InputDispatcher
从上面流程可以看出 displayContent的时间会调用 InputMonitor对应的 setFocusedAppLw 方法开始通知
- boolean setFocusedApp(ActivityRecord newFocus) {
- ///
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "setFocusedApp %s displayId=%d Callers=%s",
- newFocus, getDisplayId(), Debug.getCallers(4));
- final Task oldTask = mFocusedApp != null ? mFocusedApp.getTask() : null;
- final Task newTask = newFocus != null ? newFocus.getTask() : null;
- mFocusedApp = newFocus;
- if (oldTask != newTask) {
- if (oldTask != null) oldTask.onAppFocusChanged(false);
- if (newTask != null) newTask.onAppFocusChanged(true);
- }
- // 将新的焦点通过mInputMonitor传递给input
- getInputMonitor().setFocusedAppLw(newFocus);
- }
复制代码 而 setFocusedAppLw 直接调用 InputManagerService 的 setFocusedApplication 方法。
getInputApplicationHandle 在 ActivityRecord 构造了 InputApplicationHandle 对象,用于跟native交互。内里的token 为 ActivityRecord 的appToken,属于ibinder对象
- void setFocusedAppLw(ActivityRecord newApp) {
- // Focused app has changed.
- // 构建 InputApplicationHandle对象,将ActivityRecord的AIDL对象appToken传递进去
- mService.mInputManager.setFocusedApplication(mDisplayId,
- newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null);
- }
复制代码 InputManagerService 又会调用 native方法 nativeSetFocusedApplication
- public void setFocusedApplication(int displayId, InputApplicationHandle application) {
- nativeSetFocusedApplication(mPtr, displayId, application);
- }
复制代码 检察 com_android_server_input_InputManagerService.cpp 文件的 nativeSetFocusedApplication 方法,又会调用 NativeInputManager 的 setFocusedApplication
- static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */,
- jlong ptr, jint displayId, jobject applicationHandleObj) {
- NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- im->setFocusedApplication(env, displayId, applicationHandleObj);
- }
复制代码 NativeInputManager 又会继续调用 inputDIspatcher的 setFocusedApplication
- void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
- jobject applicationHandleObj) {
- if (!applicationHandleObj) {
- return;
- }
- std::shared_ptr<InputApplicationHandle> applicationHandle =
- android_view_InputApplicationHandle_getHandle(env, applicationHandleObj);
- applicationHandle->updateInfo();
- // 调用 inputDispater的setFocusedApplication方法
- mInputManager->getDispatcher()->setFocusedApplication(displayId, applicationHandle);
- }
复制代码 InputDispatcher 又会调用 setFocusedApplicationLocked
- void InputDispatcher::setFocusedApplication(
- int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
- if (DEBUG_FOCUS) {
- ALOGD("setFocusedApplication displayId=%" PRId32 " %s", displayId,
- inputApplicationHandle ? inputApplicationHandle->getName().c_str() : "<nullptr>");
- }
- { // acquire lock
- std::scoped_lock _l(mLock);
- // 设置当前对应的Application
- setFocusedApplicationLocked(displayId, inputApplicationHandle);
- } // release lock
- // Wake up poll loop since it may need to make new input dispatching choices.
- mLooper->wake();
- }
复制代码 该方法会从 mFocusedApplicationHandlesByDisplay 根据displayId 获取之前聚焦的应用,如果相等不处理,不相等的话则替换放到 mFocusedApplicationHandlesByDisplay, 为空的话则移除
- void InputDispatcher::setFocusedApplicationLocked(
- int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
- // 从mFocusedApplicationHandlesByDisplay获取当前的已聚焦的应用
- std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle =
- getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
- // 判断是否相等
- if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) {
- return; // This application is already focused. No need to wake up or change anything.
- }
- // Set the new application handle.
- // r如果为空则移除,否则就根据displayId 保存inputApplicationHandle
- if (inputApplicationHandle != nullptr) {
- mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
- } else {
- mFocusedApplicationHandlesByDisplay.erase(displayId);
- }
- // No matter what the old focused application was, stop waiting on it because it is
- // no longer focused.
- resetNoFocusedWindowTimeoutLocked();
- }
复制代码 这样就将当前聚焦的应用传递到InputDispatcher
4.2 焦点窗口通知InputDispatcher
相对于聚焦应用的通知,窗口通知比较复杂,需要先从WMS通知到 SurfaceFlinger,SurfaceFlinger 在通知到 InputDispatcher。
当焦点有改变的时间如上面流程就会调用到 DisplayContent 的 updateFocusedWindowLocked
- boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows,
- int topFocusedDisplayId) {
- // 查找新焦点,如果界面setVisibility为false则没焦点
- WindowState newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
- // 如果是一样的则返回
- if (mCurrentFocus == newFocus) {
- return false;
- }
- ...
- // 赋值新的焦点给mCurrentFocus变量
- ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
- mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
- final WindowState oldFocus = mCurrentFocus;
- mCurrentFocus = newFocus;
- ...
- if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
- // If we defer assigning layers, then the caller is responsible for doing this part.
- // 当焦点改变,通过 inputMonitor通知 setInputFocusLw
- getInputMonitor().setInputFocusLw(newFocus, updateInputWindows);
- }
- }
复制代码 setInputFocusLw 会调用对应的 updateInputWindowsLw 方法 ,该方法又会通过 scheduleUpdateInputWindows 启动 mUpdateInputWindows 使命
- void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d",
- newWindow, mDisplayId);
- ...
- if (updateInputWindows) {
- updateInputWindowsLw(false /*force*/);
- }
- }
- void updateInputWindowsLw(boolean force) {
- if (!force && !mUpdateInputWindowsNeeded) {
- return;
- }
- // 启动mUpdateInputWindows任务
- scheduleUpdateInputWindows();
- }
-
- private void scheduleUpdateInputWindows() {
- if (mDisplayRemoved) {
- return;
- }
- if (!mUpdateInputWindowsPending) {
- mUpdateInputWindowsPending = true;
- mHandler.post(mUpdateInputWindows);
- }
- }
复制代码 UpdateInputWindows 重要执行了 UpdateInputForAllWindowsConsumer的 updateInputWindows 方法
- private class UpdateInputWindows implements Runnable {
- @Override
- public void run() {
- synchronized (mService.mGlobalLock) {
- ...
- // Add all windows on the default display.
- mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
- }
- }
- }
复制代码 UpdateInputForAllWindowsConsumer 重要工作
- 调用 disolayContent的forAllWindows,遍历所有windowState,去更新对应的信息
- 调用 updateInputFocusRequest 去申请输入焦点,要通过requestFocus 申请了,才会在InputDispatcher 有数据,这样才会在后续的焦点更新那从request数据中获取到,不然一直会是null,没输入事件
- private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
- ...
- private void updateInputWindows(boolean inDrag) {
- ...
- // 遍历所有窗口信息,因为传入的为this,遍历的时候会调用的accept方法
- mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
- // 更新所有焦点,只要通过requestFocus 申请了,才会在InputDispatcher 有数据,
- // 这样才会在后续的焦点更新那从request数据中获取到,不然一直会是null,没输入事件
- updateInputFocusRequest(mRecentsAnimationInputConsumer);
- if (!mUpdateInputWindowsImmediately) {
- // 合并对应的事务
- mDisplayContent.getPendingTransaction().merge(mInputTransaction);
- mDisplayContent.scheduleAnimation();
- }
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- @Override
- public void accept(WindowState w) {
- // InputWindowHandleWrapper 包含displayId和InputApplicationHandle
- final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle;
- ...
- if (w.mInputChannelToken == null || w.mRemoved
- || (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
- // 如果不可输入但是拥有 Surface,调用populateOverlayInputInfo重置下信息,如token重置
- // 在 openInputChannel的时候会赋值
- if (w.mWinAnimator.hasSurface()) {
- // Make sure the input info can't receive input event. It may be omitted from
- // occlusion detection depending on the type or if it's a trusted overlay.
- populateOverlayInputInfo(inputWindowHandle, w);
- setInputWindowInfoIfNeeded(mInputTransaction,
- w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
- return;
- }
- // Skip this window because it cannot possibly receive input.
- return;
- }
- ...
- // 有surface
- if (w.mWinAnimator.hasSurface()) {
- // 构造对应的inputWindowHandle信息,用于native传输
- populateInputWindowHandle(inputWindowHandle, w);
- // 调用 InputTransaction事务将InputWindowHandleWrapper放进去
- setInputWindowInfoIfNeeded(mInputTransaction,
- w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
- }
- }
- }
复制代码 因为 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 方法提交到事务
- static void setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc,
- InputWindowHandleWrapper inputWindowHandle) {
- if (DEBUG_INPUT) {
- Slog.d(TAG_WM, "Update InputWindowHandle: " + inputWindowHandle);
- }
- // 只要有设置就会为true
- if (inputWindowHandle.isChanged()) {
- inputWindowHandle.applyChangesToSurface(t, sc);
- }
- }
复制代码 内里会调用事务的 setInputWIndowInfo
- void applyChangesToSurface(@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl sc) {
- // 调用Transaction的setInputWindowInfo将setInputWindowInfo保存进入
- t.setInputWindowInfo(sc, mHandle);
- mChanged = false;
- }
复制代码 调用 nativeSetInputWindowInfo 将 对应 InputWindowHandle 信息传递给 SurfaceControl
- public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
- checkPreconditions(sc);
- nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
- return this;
- }
复制代码 nativeSetInputWindowInfo 内容如下
- 通过 android_view_InputWindowHandle_getHandle 构建出 NativeInputWindowHandle 对象
- 调用 updateInfo 方法,将 java的inputWindowHandler属性拿出,拷贝到 NativeInputWindowHandle变量
- 调用 SurfaceComposerClient的setInputWindowInfo 更新窗口信息到数组
- // transactionObj参数是Transaction的指针,而nativeObject是SurfaceControl的指针
- static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactionObj,
- jlong nativeObject, jobject inputWindow) {
- auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- // 创建 NativeInputWindowHandle 对象
- sp<NativeInputWindowHandle> handle = android_view_InputWindowHandle_getHandle(
- env, inputWindow);
- // 将 java的inputWindowHandler属性拿出,拷贝到 NativeInputWindowHandle变量
- handle->updateInfo();
- // 获取SurfaceControl
- auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
- // 调用 SurfaceComposerClient的setInputWindowInfo,会保存到 mComposerStates 数组,后续apply事务的时候就会从该数据遍历
- transaction->setInputWindowInfo(ctrl, *handle->getInfo());
- }
复制代码 android_view_InputWindowHandle_getHandle 方法。会根据ptr属性获取,如果不为空则直接获取,否则在创建,并设置到对应ptr属性
- sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
- JNIEnv* env, jobject inputWindowHandleObj) {
- if (!inputWindowHandleObj) {
- return NULL;
- }
- AutoMutex _l(gHandleMutex);
- jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr);
- NativeInputWindowHandle* handle;
- // 获取对应的指针如果不为空则直接获取,否则在创建,并设置到对应ptr属性。
- if (ptr) {
- handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
- } else {
- jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
- handle = new NativeInputWindowHandle(objWeak);
- handle->incStrong((void*)android_view_InputWindowHandle_getHandle);
- env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
- reinterpret_cast<jlong>(handle));
- }
- return handle;
- }
复制代码 updateInfo 进行深拷贝
- bool NativeInputWindowHandle::updateInfo() {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject obj = env->NewLocalRef(mObjWeak);
- ...
- // windowState的token
- jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token);
- if (tokenObj) {
- mInfo.token = ibinderForJavaObject(env, tokenObj);
- env->DeleteLocalRef(tokenObj);
- } else {
- mInfo.token.clear();
- }
- ...
- // 获取对应的 AIDL token(IWindow AIDL接口,用于wms和应用交互通知,如viewRootImpl的W)
- // 通过 ibinderForJavaObject 转换放到 windowToken
- jobject windowTokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.windowToken);
- if (windowTokenObj) {
- mInfo.windowToken = ibinderForJavaObject(env, windowTokenObj);
- env->DeleteLocalRef(windowTokenObj);
- } else {
- mInfo.windowToken.clear();
- }
- env->DeleteLocalRef(obj);
- return true;
- }
复制代码 setInputWindowInfo 方法,
- 通过 getLayerState 创建对应 layer_state_t,该方法很紧张会将对应的信息保存到 mComposerStates
- 将windowInfo放到WindowInfoHandle,并赋值给 layer_state_t
- SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
- const sp<SurfaceControl>& sc, const WindowInfo& info) {
- // 获取对应的 layer_state_t
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- // 将windowInfo放到WindowInfoHandle,并赋值给 layer_state_t
- s->windowInfoHandle = new WindowInfoHandle(info);
- // 记录变化的
- s->what |= layer_state_t::eInputInfoChanged;
- return *this;
- }
复制代码 getLayerState 会获取
- SurfaceControl 对应的 binder对象。从mComposerStates数组判断是否存在
- 不包含则创建,将对应信息放进去layer_state_t 并根据handler为key,放进mComposerStates
- 返回 layer_state_t
- layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
- // 获取SurfaceControl的binder
- auto handle = sc->getLayerStateHandle();
- // 判断 mComposerStates 是否包含,不包含则创建,并根据handler为key,放进mComposerStates
- // 后续事务提交的时候,会从mComposerStates该数组遍历
- if (mComposerStates.count(handle) == 0) {
- // we don't have it, add an initialized layer_state to our list
- ComposerState s;
- // 放进 layer_state_t 中
- s.state.surface = handle;
- s.state.layerId = sc->getLayerId();
- mComposerStates[handle] = s;
- }
- // 返回 layer_state_t
- return &(mComposerStates[handle].state);
- }
复制代码 4.2.1.2 SurfaceFlinger 到 InputDIspatcher
事务在 提交的时间,就会调用 apply方法。又会调用过 nativeApplyTransaction 方法。
- public void apply(boolean sync) {
- applyResizedSurfaces();
- notifyReparentedSurfaces();
- nativeApplyTransaction(mNativeObject, sync);
- }
复制代码 native 又会调用 SurfaceComposerClient 的 apply 方法。
- static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
- auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- // 调用 SurfaceComposerClient 的apply
- transaction->apply(sync);
- }
复制代码 apply方法
- 获取 SurfaceFlinger的Binder代理sf
- 开始遍历 mComposerStates, 添加到 composerStates
- 跨历程调用SurfaceFlinger的setTransactionState把composerStates作为参数
- status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
- if (mStatus != NO_ERROR) {
- return mStatus;
- }
- // 获取SurfaceFlinger的Binder代理sf,单例
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- ...
- // 开始遍历 mComposerStates, 添加到 composerStates
- for (auto const& kv : mComposerStates){
- composerStates.add(kv.second);
- }
- ...
- // 如果已经有则直接用,否则创建TransactionCompletedListener
- sp<IBinder> applyToken = mApplyToken
- ? mApplyToken
- : IInterface::asBinder(TransactionCompletedListener::getIInstance());
- // 跨进程调用SurfaceFlinger的setTransactionState把composerStates作为参数
- sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
- mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
- {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
- hasListenerCallbacks, listenerCallbacks, mId);
-
- }
复制代码 setTransactionState 会创建 TransactionState 对象,并调用 queueTransaction 方法,将事务(Transaction)参加队列。
- status_t SurfaceFlinger::setTransactionState(
- const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
- bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
- ...
- // 将参数放到 TransactionState 对象中。
- TransactionState state{frameTimelineInfo, states,
- displays, flags,
- applyToken, inputWindowCommands,
- desiredPresentTime, isAutoTimestamp,
- uncacheBuffer, postTime,
- permissions, hasListenerCallbacks,
- listenerCallbacks, originPid,
- originUid, transactionId};
- ...
- // 把TransactionState放入队列,且会启动对应的scheduleCommit
- queueTransaction(state);
- // Check the pending state to make sure the transaction is synchronous.
- if (state.transactionCommittedSignal) {
- waitForSynchronousTransaction(*state.transactionCommittedSignal);
- }
- return NO_ERROR;
- }
复制代码 在每次SurfaceFlinger主线程进行commit操纵的时间,都会调用一次updateInputFlinger方法去更新一遍需要派发给InputDispatcher的窗口信息。
updateInputFlinger 方法会调用 notifyWindowInfos 方法开始通知 给inputDispatcher
- void SurfaceFlinger::updateInputFlinger() {
- ATRACE_CALL();
- if (!mInputFlinger) {
- return;
- }
- if (mVisibleRegionsDirty || mInputInfoChanged) {
- mInputInfoChanged = false;
- // 调用通知给inputDispatcher
- notifyWindowInfos();
- }
- ...
- for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
- mInputFlinger->setFocusedWindow(focusRequest);
- }
- ;
- }
复制代码 notifyWindowInfos
- 通过 traverseInReverseZOrder 开始遍历,判断是否需要,通过layer内里的 hasInputInfo 方法,hasInputInfo通过inputInfo的token是否为空判断,并将放到 windowInfos 数组尾部
- 通过 mWindowInfosListenerInvoker 开始触发通知,给 InputDispatcher
- void SurfaceFlinger::notifyWindowInfos() {
- std::vector<WindowInfo> windowInfos;
- // 开始遍历,过滤需要的windowInfos
- mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
- // 判断是否需要,通过layer里面的 hasInputInfo 方法,hasInputInfo通过inputInfo的token是否为空判断
- if (!layer->needsInputInfo()) return;
- sp<DisplayDevice> display = enablePerWindowInputRotation()
- ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer))
- : nullptr;
- // When calculating the screen bounds we ignore the transparent region since it may
- // result in an unwanted offset.
- // 根据layer填满outWindowInfos信息
- windowInfos.push_back(layer->fillInputInfo(display));
- });
- // 开始触发通知,给 InputDispatcher
- mWindowInfosListenerInvoker->windowInfosChanged(windowInfos,
- mInputWindowCommands.syncInputWindows);
- }
复制代码 WindowInfosListenerInvoker 的 windowInfosChanged方法又会遍历listner,内里实在就是 InputDispather
- void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
- bool shouldSync) {
- ...
- // 这里listener其实就是InputDispather
- for (const auto& listener : windowInfosListeners) {
- listener->onWindowInfosChanged(windowInfos,
- shouldSync ? mWindowInfosReportedListener : nullptr);
- }
- }
复制代码 检察 InputDispather 的 onWindowInfosChanged 方法
- void InputDispatcher::onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) {
- // The listener sends the windows as a flattened array. Separate the windows by display for
- // more convenient parsing.
- std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
- for (const auto& info : windowInfos) {
- handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
- handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
- }
- setInputWindows(handlesPerDisplay);
- }
复制代码 setInputWindows 重要更新 内容
- 调用 updateWindowHandlesForDisplayLocked,更新mWindowHandlesByDisplay对应该屏幕下的数据
- 调用 FocusResolver 的 setInputWindows 开始设置焦点窗口
- void InputDispatcher::setInputWindowsLocked(
- const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {
- if (DEBUG_FOCUS) {
- ...
- ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str());
- }
- ...
- // 比较更旧的windowInfo,更新mWindowHandlesByDisplay对应该屏幕下的数据
- updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);
-
- // 判断是否改变窗口焦点
- std::optional<FocusResolver::FocusChanges> changes =
- mFocusResolver.setInputWindows(displayId, windowHandles);
- if (changes) {
- onFocusChangedLocked(*changes);
- }
- ...
- }
复制代码 FocusResolver 的 setInputWindows 方法
- 通过getFocusedWindowToken(通过mFocusedWindowTokenByDisplay数组) 获取还没更新前的焦点窗口
- 调用 isTokenFocusable,判断下当前窗口是否可以聚焦,如果还聚焦的话,则继续授予其焦点。返回null,表示不需要改变。
- 通过 getFocusRequest(通过 mFocusRequestByDisplay 数组)方法获取哀求的焦点窗口,需要调用 (requestFocus),如果没哀求过的话,则表示没焦点。
- 如果哀求过,则再次通过 isTokenFocusable ,判断该窗口是否符合,如何的话则调用 updateFocusedWindow 方法进行更新,如果不符合的话,则传入null,将当前屏幕设置为没焦点。
- std::optional<FocusResolver::FocusChanges> FocusResolver::setInputWindows(
- int32_t displayId, const std::vector<sp<WindowInfoHandle>>& windows) {
- std::string removeFocusReason;
- // Check if the currently focused window is still focusable.
- // 通过 mFocusedWindowTokenByDisplay(mFocusedWindowTokenByDisplay数组) 检查下当前还没更新的焦点是否还在,这时候还没更新,所以获取的是旧的
- const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
- if (currentFocus) {
- Focusability result = isTokenFocusable(currentFocus, windows);
- // 返回ok,表示当前窗口仍可以聚焦,那么我们将继续授予其焦点
- if (result == Focusability::OK) {
- return std::nullopt;
- }
- removeFocusReason = NamedEnum::string(result);
- }
- // We don't have a focused window or the currently focused window is no longer focusable. Check
- // to see if we can grant focus to the window that previously requested focus.
- // 请求的requestFocus((mFocusRequestByDisplay数组))是否存在,如果没请求,那 updateFocusedWindow 只会传入null
- const std::optional<FocusRequest> request = getFocusRequest(displayId);
- if (request) {
- sp<IBinder> requestedFocus = request->token;
- const Focusability result = isTokenFocusable(requestedFocus, windows);
- const Focusability previousResult = mLastFocusResultByDisplay[displayId];
- mLastFocusResultByDisplay[displayId] = result;
- // 如果可以 则调用 updateFocusedWindow 更新当前聚焦焦点
- if (result == Focusability::OK) {
- return updateFocusedWindow(displayId,
- "Window became focusable. Previous reason: " +
- NamedEnum::string(previousResult),
- requestedFocus, request->windowName);
- }
- }
- // Focused window is no longer focusable and we don't have a suitable focus request to grant.
- // Remove focus if needed.
- // 因为没请求,传入为空的对象更新为空的,让其失去焦点
- return updateFocusedWindow(displayId, removeFocusReason, nullptr);
- }
复制代码 isTokenFocusable 判断是否符合条件 ,遍历表示是否可见,是否可聚焦。
- FocusResolver::Focusability FocusResolver::isTokenFocusable(
- const sp<IBinder>& token, const std::vector<sp<WindowInfoHandle>>& windows) {
- bool allWindowsAreFocusable = true;
- bool visibleWindowFound = false;
- bool windowFound = false;
- for (const sp<WindowInfoHandle>& window : windows) {
- // 遍历到相等才执行判断
- if (window->getToken() != token) {
- continue;
- }
- windowFound = true;
- // 至少有一个窗口可见
- if (window->getInfo()->visible) {
- // Check if at least a single window is visible.
- visibleWindowFound = true;
- }
- // 检查所有窗口是否可聚焦
- if (!window->getInfo()->focusable) {
- // Check if all windows with the window token are focusable.
- allWindowsAreFocusable = false;
- break;
- }
- }
- if (!windowFound) {
- return Focusability::NO_WINDOW;
- }
- if (!allWindowsAreFocusable) {
- return Focusability::NOT_FOCUSABLE;
- }
- if (!visibleWindowFound) {
- return Focusability::NOT_VISIBLE;
- }
- return Focusability::OK;
- }
复制代码 updateFocusedWindow 方法
- 会获取当前的窗口和要更新的窗口是否一致,是的话返回为空,表示不需要改变。
- 在判断 newFocus 是否为空,不为空的则更新到 mFocusedWindowTokenByDisplay 数组,否则调用 errase 方法移除。丢失焦点。
- std::optional<FocusResolver::FocusChanges> FocusResolver::updateFocusedWindow(
- int32_t displayId, const std::string& reason, const sp<IBinder>& newFocus,
- const std::string& tokenName) {
- // 获取之前的焦点窗口,如果一样则返回空。
- sp<IBinder> oldFocus = getFocusedWindowToken(displayId);
- if (newFocus == oldFocus) {
- return std::nullopt;
- }
- // 如果传入参数不为空,则更新到 mFocusedWindowTokenByDisplay 数据
- // 为空则调用 errase,移除。
- if (newFocus) {
- mFocusedWindowTokenByDisplay[displayId] = {tokenName, newFocus};
- } else {
- mFocusedWindowTokenByDisplay.errase(displayId);
- }
- return {{oldFocus, newFocus, displayId, reason}};
- }
复制代码 这样就完成了到 InputDispatcher的聚焦窗口更新。
4.2.2 哀求窗口焦点
更新聚焦窗口,需要request数组有对应的哀求,之前的 InputMonitor 遍历后更新窗口信息,又会调用 updateInputFocusRequest 方法。又会调用 requestFocus 方法
4.2.2.1 WMS通知到SurfaceFlinger
- private void updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer) {
- ...
- // mInputChannelToken是否为空可以判断是否聚焦输入
- final IBinder focusToken = focus != null ? focus.mInputChannelToken : null;
- if (focusToken == null) {
- mInputFocus = null;
- return;
- }
- ...
- // 请求输入焦点
- requestFocus(focusToken, focus.getName());
- }
复制代码 requestFocus 会打印哀求的日志和 调用事务 Transaction 的 setFocusedWindow 方法。
- private void requestFocus(IBinder focusToken, String windowName) {
- if (focusToken == mInputFocus) {
- return;
- }
- mInputFocus = focusToken;
- // 将对应焦点token设置到事务
- mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId);
- // 请求日志
- EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + windowName,
- "reason=UpdateInputWindows");
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", windowName);
- }
复制代码 而 setFocusedWindow 又会调用 nativeSetFocusedWindow 方法。
- public Transaction setFocusedWindow(@NonNull IBinder token, String windowName,
- int displayId) {
- nativeSetFocusedWindow(mNativeObject, token, windowName,
- null /* focusedToken */, null /* focusedWindowName */, displayId);
- return this;
- }
复制代码 nativeSetFocusedWindow 会创建对应的 FocusRequest 对象,并调用 setFocusedWindow 方法。
- static void nativeSetFocusedWindow(JNIEnv* env, jclass clazz, jlong transactionObj,
- jobject toTokenObj, jstring windowNameJstr,
- jobject focusedTokenObj, jstring focusedWindowNameJstr,
- jint displayId) {
- auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- if (toTokenObj == NULL) return;
- // 转换对应的binder对象
- sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj));
- sp<IBinder> focusedToken;
- if (focusedTokenObj != NULL) {
- focusedToken = ibinderForJavaObject(env, focusedTokenObj);
- }
- // 创建 FocusRequest对象
- FocusRequest request;
- request.token = toToken;
- if (windowNameJstr != NULL) {
- ScopedUtfChars windowName(env, windowNameJstr);
- request.windowName = windowName.c_str();
- }
- request.focusedToken = focusedToken;
- if (focusedWindowNameJstr != NULL) {
- ScopedUtfChars focusedWindowName(env, focusedWindowNameJstr);
- request.focusedWindowName = focusedWindowName.c_str();
- }
- request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
- request.displayId = displayId;
- // 调用 SurfaceComposerClient的setFocusedWindow
- transaction->setFocusedWindow(request);
- }
复制代码 setFocusedWindow 方法又会将对应的request 放到 mInputWindowCommands的focusRequests 数组
- SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow(
- const FocusRequest& request) {
- // 添加 mInputWindowCommands 到 focusRequests
- mInputWindowCommands.focusRequests.push_back(request);
- return *this;
- }
复制代码 跟上面一样 apply的时间 调用 SurfaceFlinger的 setTransactionState 时间 将 mInputWindowCommands 带已往给
- status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
- ...
- // 如果已经有则直接用,否则创建TransactionCompletedListener
- sp<IBinder> applyToken = mApplyToken
- ? mApplyToken
- : IInterface::asBinder(TransactionCompletedListener::getIInstance());
- // 跨进程调用SurfaceFlinger的setTransactionState把composerStates作为参数
- // apply的时候 也会将 mInputWindowCommands 带过去
- sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
- mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
- {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
- hasListenerCallbacks, listenerCallbacks, mId);
- }
复制代码 4.2.2.2 SurfaceFlinger 到 InputDIspatcher
同样 inputWindowCommands 也会放在 TransactionState 中,并调用 queueTransaction 放进队列,最终也会调用到 updateInputFlinger,会遍历对应的数组,然后调用 InputFlinger 的setFocusedWindow方法,也便是 InputManager 的 setFocusedWindow
- // 更新对应的
- void SurfaceFlinger::updateInputFlinger() {
- ATRACE_CALL();
- if (!mInputFlinger) {
- return;
- }
- if (mVisibleRegionsDirty || mInputInfoChanged) {
- mInputInfoChanged = false;
- // 调用通知给inputDispatcher
- notifyWindowInfos();
- }
- ...
- // 开始遍历每一个焦点请求,调用 mInputFlinger
- for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
- mInputFlinger->setFocusedWindow(focusRequest);
- }
- mInputWindowCommands.clear();
- }
复制代码- class InputManager : public InputManagerInterface, public BnInputFlinger {
- protected:
- ~InputManager() override;
复制代码 inputManger 又会调用 mDispatcher 的setFocusedWindow
- binder::Status InputManager::setFocusedWindow(const FocusRequest& request) {
- mDispatcher->setFocusedWindow(request);
- return binder::Status::ok();
- }
复制代码 InputDispatcher内里 又会调用 FocusResolver的setFocusedWindow
- void InputDispatcher::setFocusedWindow(const FocusRequest& request) {
- { // acquire lock
- std::scoped_lock _l(mLock);
- // 又会调用 FocusResolver的setFocusedWindow
- std::optional<FocusResolver::FocusChanges> changes =
- mFocusResolver.setFocusedWindow(request, getWindowHandlesLocked(request.displayId));
- if (changes) {
- onFocusChangedLocked(*changes);
- }
- } // release lock
- // Wake up poll loop since it may need to make new input dispatching choices.
- mLooper->wake();
- }
复制代码 FocusResolver 的 setFocusedWindow 方法
- 获取当前的窗口焦点**,如果和当前的一样,则直接返回空,表示无变化**
- 如果哀求聚焦已经是聚焦的的情况下进入,如果 跟当前的不一致,则用当前的即可,如果当前request是可用的话,则调用 updateFocusedWindow 更新,否则也返回空,抛弃该哀求
- 如果是可用的窗口,将对应的信息保存到 mFocusRequestByDisplay 中,在 setInputWindows 中可用
- 再次判断是否可用,不可用则调用 updateFocusedWindow,否则传入null 丢失窗口,因为保存在 mFocusRequestByDisplay 中,等待下一次窗口状态改变哀求。
- std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow(
- const FocusRequest& request, const std::vector<sp<WindowInfoHandle>>& windows) {
- const int32_t displayId = request.displayId;
- // 获取当前的窗口焦点
- const sp<IBinder> currentFocus = getFocusedWindowToken(displayId);
- if (currentFocus == request.token) {
- ALOGD_IF(DEBUG_FOCUS,
- "setFocusedWindow %s on display %" PRId32 " ignored, reason: already focused",
- request.windowName.c_str(), displayId);
- return std::nullopt;
- }
- // Handle conditional focus requests, i.e. requests that have a focused token. These requests
- // are not persistent. If the window is no longer focusable, we expect focus to go back to the
- // previously focused window.
- // 如果请求聚焦已经是聚焦的的情况下进入,(正常请求的时候,并还没聚焦)
- if (request.focusedToken) {
- // 跟当前的不一致,则用当前的即可
- if (currentFocus != request.focusedToken) {
- ALOGW("setFocusedWindow %s on display %" PRId32
- " ignored, reason: focusedToken %s is not focused",
- request.windowName.c_str(), displayId, request.focusedWindowName.c_str());
- return std::nullopt;
- }
- // 是否可聚焦,是的话更新窗口信息
- Focusability result = isTokenFocusable(request.token, windows);
- if (result == Focusability::OK) {
- return updateFocusedWindow(displayId, "setFocusedWindow with focus check",
- request.token, request.windowName);
- }
- // 已经不符合可聚焦了,无需设置 返回空指针
- ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: %s",
- request.windowName.c_str(), displayId, NamedEnum::string(result).c_str());
- return std::nullopt;
- }
- // 如果是可用的窗口,将对应的信息保存到 mFocusRequestByDisplay 中,在 setInputWindows 中可用
- Focusability result = isTokenFocusable(request.token, windows);
- // Update focus request. The focus resolver will always try to handle this request if there is
- // no focused window on the display.
- mFocusRequestByDisplay[displayId] = request;
- mLastFocusResultByDisplay[displayId] = result;
- // 如果结果是ok,更新对应的焦点窗口
- if (result == Focusability::OK) {
- return updateFocusedWindow(displayId, "setFocusedWindow", request.token,
- request.windowName);
- }
- // The requested window is not currently focusable. Wait for the window to become focusable
- // but remove focus from the current window so that input events can go into a pending queue
- // and be sent to the window when it becomes focused.
- // 当前request不是符合的窗口 传入null 设置当前为没焦点窗口,后续 窗口改变,通过 setInputWindows 可用
- return updateFocusedWindow(displayId, "Waiting for window because " + NamedEnum::string(result),
- nullptr);
- }
复制代码 这样就完成了 焦点的哀求流程
5 打印 Focus entering" 或 Focus leaving
从上面流程 调用 setFocusedWindow 或者 setInputWindowsLocked 有改变后就会调用 onFocusChangedLocked 方法。
- // 判断是否改变窗口焦点
- std::optional<FocusResolver::FocusChanges> changes =
- mFocusResolver.setInputWindows(displayId, windowHandles);
- if (changes) {
- onFocusChangedLocked(*changes);
- }
复制代码- // 又会调用 FocusResolver的setFocusedWindow
- std::optional<FocusResolver::FocusChanges> changes =
- mFocusResolver.setFocusedWindow(request, getWindowHandlesLocked(request.displayId));
- if (changes) {
- onFocusChangedLocked(*changes);
- }
复制代码 onFocusChangedLocked 会根据传进来的 oldFocus 和 newFocus,分别调用 enqueueFocusEventLocked 方法,发送 focus的event事件
- void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& changes) {
- // 如果有改变,分别调用 旧焦点和新焦点,传入 enqueueFocusEventLocked 方法
- // 旧的
- if (changes.oldFocus) {
- std::shared_ptr<InputChannel> focusedInputChannel = getInputChannelLocked(changes.oldFocus);
- if (focusedInputChannel) {
- CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
- "focus left window");
- synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options);
- enqueueFocusEventLocked(changes.oldFocus, false /*hasFocus*/, changes.reason);
- }
- }
- // 新的
- if (changes.newFocus) {
- enqueueFocusEventLocked(changes.newFocus, true /*hasFocus*/, changes.reason);
- }
- ...
- }
复制代码 构造对应event type为 EventEntry::Type::FOCUS 的事件,插入到 mInboundQueue 即 IQ队列
- void InputDispatcher::enqueueFocusEventLocked(const sp<IBinder>& windowToken, bool hasFocus,
- const std::string& reason) {
- if (mPendingEvent != nullptr) {
- // Move the pending event to the front of the queue. This will give the chance
- // for the pending event to get dispatched to the newly focused window
- mInboundQueue.push_front(mPendingEvent);
- mPendingEvent = nullptr;
- }
- std::unique_ptr<FocusEntry> focusEntry =
- std::make_unique<FocusEntry>(mIdGenerator.nextId(), now(), windowToken, hasFocus,
- reason);
- // This event should go to the front of the queue, but behind all other focus events
- // Find the last focus event, and insert right after it
- std::deque<std::shared_ptr<EventEntry>>::reverse_iterator it =
- std::find_if(mInboundQueue.rbegin(), mInboundQueue.rend(),
- [](const std::shared_ptr<EventEntry>& event) {
- return event->type == EventEntry::Type::FOCUS;
- });
- // Maintain the order of focus events. Insert the entry after all other focus events.
- mInboundQueue.insert(it.base(), std::move(focusEntry));
- }
复制代码 下一次循环叫醒的时间,就会执行 dispatchOnce 方法。和之前一样队列有东西 就会调用 dispatchOnceInnerLocked。该方法会从 IQ队列获取,判断到类型为 EventEntry::Type::FOCUS 就会调用 dispatchFocusLocked 方法。
- void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
- switch (mPendingEvent->type) {
- case EventEntry::Type::FOCUS: {
- std::shared_ptr<FocusEntry> typedEntry =
- std::static_pointer_cast<FocusEntry>(mPendingEvent);
- dispatchFocusLocked(currentTime, typedEntry);
- done = true;
- dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
- break;
- }
- }
- }
复制代码 dispatchFocusLocked 就会打印对应的窗口脱离和进入日志。
- void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry) {
- std::shared_ptr<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
- if (channel == nullptr) {
- return; // Window has gone away
- }
- InputTarget target;
- target.inputChannel = channel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- entry->dispatchInProgress = true;
- // 打印对应的信息
- std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
- channel->getName();
- std::string reason = std::string("reason=").append(entry->reason);
- android_log_event_list(LOGTAG_INPUT_FOCUS) << message << reason << LOG_ID_EVENTS;
- dispatchEventLocked(currentTime, entry, {target});
- }
复制代码 3 堆栈
3.1 setFocusApp
启动App堆栈
- setFocusedApp:3655, DisplayContent (com.android.server.wm)
- setResumedActivityUncheckLocked:4539, ActivityTaskManagerService (com.android.server.wm)
- onActivityStateChanged:579, TaskFragment (com.android.server.wm)
- setState:5163, ActivityRecord (com.android.server.wm)
- minimalResumeActivityLocked:4783, Task (com.android.server.wm)
- realStartActivityLocked:938, ActivityTaskSupervisor (com.android.server.wm)
- startSpecificActivity:1005, ActivityTaskSupervisor (com.android.server.wm)
- resumeTopActivity:1348, TaskFragment (com.android.server.wm)
- resumeTopActivityInnerLocked:5037, Task (com.android.server.wm)
- resumeTopActivityUncheckedLocked:4971, Task (com.android.server.wm)
- resumeFocusedTasksTopActivities:2398, RootWindowContainer (com.android.server.wm)
- resumeFocusedTasksTopActivities:2383, RootWindowContainer (com.android.server.wm)
- completePause:1608, TaskFragment (com.android.server.wm)
- activityPaused:5734, ActivityRecord (com.android.server.wm)
- activityPaused:176, ActivityClientController (com.android.server.wm)
- onTransact:548, IActivityClientController$Stub (android.app)
- onTransact:121, ActivityClientController (com.android.server.wm)
- execTransactInternal:1179, Binder (android.os)
- execTransact:1143, Binder (android.os)
复制代码 按home建,回退的时间
- setFocusedApp:3655, DisplayContent (com.android.server.wm)
- setResumedActivityUncheckLocked:4539, ActivityTaskManagerService (com.android.server.wm)
- moveFocusableActivityToTop:3001, ActivityRecord (com.android.server.wm)
- moveTaskToFront:5581, Task (com.android.server.wm)
- setTargetRootTaskIfNeeded:2733, ActivityStarter (com.android.server.wm)
- recycleTask:2062, ActivityStarter (com.android.server.wm)
- startActivityInner:1762, ActivityStarter (com.android.server.wm)
- startActivityUnchecked:1594, ActivityStarter (com.android.server.wm)
- executeRequest:1195, ActivityStarter (com.android.server.wm)
- execute:674, ActivityStarter (com.android.server.wm)
- startHomeActivity:179, ActivityStartController (com.android.server.wm)
- startHomeOnTaskDisplayArea:1604, RootWindowContainer (com.android.server.wm)
- lambda$startHomeOnDisplay$12$RootWindowContainer:1545, RootWindowContainer (com.android.server.wm)
- apply:-1, RootWindowContainer$$ExternalSyntheticLambda10 (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:554, TaskDisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:2091, WindowContainer (com.android.server.wm)
- startHomeOnDisplay:1544, RootWindowContainer (com.android.server.wm)
- startHomeOnDisplay:5839, ActivityTaskManagerService$LocalService (com.android.server.wm)
- startDockOrHome:5106, PhoneWindowManager (com.android.server.policy)
- startDockOrHome:5111, PhoneWindowManager (com.android.server.policy)
- launchHomeFromHotKey:3254, PhoneWindowManager (com.android.server.policy)
- launchHomeFromHotKey:3211, PhoneWindowManager (com.android.server.policy)
- handleShortPressOnHome:1351, PhoneWindowManager (com.android.server.policy)
- access$2200:240, PhoneWindowManager (com.android.server.policy)
- lambda$handleHomeButton$0$PhoneWindowManager$DisplayHomeButtonHandler:1501, PhoneWindowManager$DisplayHomeButtonHandler (com.android.server.policy)
- run:-1, PhoneWindowManager$DisplayHomeButtonHandler$$ExternalSyntheticLambda0 (com.android.server.policy)
- handleCallback:938, Handler (android.os)
- dispatchMessage:99, Handler (android.os)
- loopOnce:201, Looper (android.os)
- loop:288, Looper (android.os)
- run:67, HandlerThread (android.os)
- run:44, ServiceThread (com.android.server)
- run:45, UiThread (com.android.server)
复制代码- setFocusedApp:3655, DisplayContent (com.android.server.wm)
- setResumedActivityUncheckLocked:4539, ActivityTaskManagerService (com.android.server.wm)
- onActivityStateChanged:579, TaskFragment (com.android.server.wm)
- setState:5163, ActivityRecord (com.android.server.wm)
- resumeTopActivity:1227, TaskFragment (com.android.server.wm)
- resumeTopActivityInnerLocked:5037, Task (com.android.server.wm)
- resumeTopActivityUncheckedLocked:4971, Task (com.android.server.wm)
- resumeTopActivityUncheckedLocked:4985, Task (com.android.server.wm)
- resumeFocusedTasksTopActivities:2398, RootWindowContainer (com.android.server.wm)
- resumeTargetRootTaskIfNeeded:2788, ActivityStarter (com.android.server.wm)
- recycleTask:2113, ActivityStarter (com.android.server.wm)
- startActivityInner:1762, ActivityStarter (com.android.server.wm)
- startActivityUnchecked:1594, ActivityStarter (com.android.server.wm)
- executeRequest:1195, ActivityStarter (com.android.server.wm)
- execute:674, ActivityStarter (com.android.server.wm)
- startHomeActivity:179, ActivityStartController (com.android.server.wm)
- startHomeOnTaskDisplayArea:1604, RootWindowContainer (com.android.server.wm)
- lambda$startHomeOnDisplay$12$RootWindowContainer:1545, RootWindowContainer (com.android.server.wm)
- apply:-1, RootWindowContainer$$ExternalSyntheticLambda10 (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:554, TaskDisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:392, DisplayArea (com.android.server.wm)
- reduceOnAllTaskDisplayAreas:2091, WindowContainer (com.android.server.wm)
- startHomeOnDisplay:1544, RootWindowContainer (com.android.server.wm)
- startHomeOnDisplay:5839, ActivityTaskManagerService$LocalService (com.android.server.wm)
- startDockOrHome:5106, PhoneWindowManager (com.android.server.policy)
- startDockOrHome:5111, PhoneWindowManager (com.android.server.policy)
- launchHomeFromHotKey:3254, PhoneWindowManager (com.android.server.policy)
- launchHomeFromHotKey:3211, PhoneWindowManager (com.android.server.policy)
- handleShortPressOnHome:1351, PhoneWindowManager (com.android.server.policy)
- access$2200:240, PhoneWindowManager (com.android.server.policy)
- lambda$handleHomeButton$0$PhoneWindowManager$DisplayHomeButtonHandler:1501, PhoneWindowManager$DisplayHomeButtonHandler (com.android.server.policy)
- run:-1, PhoneWindowManager$DisplayHomeButtonHandler$$ExternalSyntheticLambda0 (com.android.server.policy)
- handleCallback:938, Handler (android.os)
- dispatchMessage:99, Handler (android.os)
- loopOnce:201, Looper (android.os)
- loop:288, Looper (android.os)
- run:67, HandlerThread (android.os)
- run:44, ServiceThread (com.android.server)
- run:45, UiThread (com.android.server)
复制代码 退却键
- setFocusedApp:3655, DisplayContent (com.android.server.wm)
- setResumedActivityUncheckLocked:4539, ActivityTaskManagerService (com.android.server.wm)
- moveFocusableActivityToTop:3001, ActivityRecord (com.android.server.wm)
- moveHomeActivityToTop:1880, TaskDisplayArea (com.android.server.wm)
- adjustFocusToNextFocusableTask:2484, Task (com.android.server.wm)
- finishIfPossible:3144, ActivityRecord (com.android.server.wm)
- finishActivity:451, ActivityClientController (com.android.server.wm)
- onTransact:688, IActivityClientController$Stub (android.app)
- onTransact:121, ActivityClientController (com.android.server.wm)
- execTransactInternal:1184, Binder (android.os)
- execTransact:1143, Binder (android.os)
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |