马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
概述
作甚核心窗口?顾名思义就是有核心窗口,要留意和view的核心概念要做区分,两个不是一个层面上的概念。为什么窗口要拥有核心呢,下面都是我的明白,有不对的地方接待讨论:核心窗口重要利用在InputDispachar分发按键事故——keyevent阶段,在keyevent分发阶段,此时的核心窗口就是该事故应该分发给的窗口。不像触摸事故,在分发过程中可以通过触摸的坐标推断给事故应该分发给谁人窗口,keyeven来自物理按键,没有对应的坐标,只能通过核心窗口确定发送给谁人窗口。
表明完毕核心窗口的作用,在来简朴先容下一种常见的ANR,即no focus anr,这种anr发生就是由于在分发一次keyEvent时,没有找到核心窗口,便开始了anr计时,5s之后,分发事故的过程中发仍旧没有对应的核心窗口,便会发生无核心ANR。
核心窗口的更新流程在Android12之后,涉及到了三个模块:WMS, Surfaceflinger, InputDispachar,下文将会分析具体得人更新核心窗口流程。
起首明白三个概念:
1. 顶部核心屏幕:mTopFocusedDisplayId,这个变量的声明位于窗口的根节点RootWindowContainer中.
这个变量代表了相应没有指明屏幕的key大概pointer范例的event的屏幕的id。- frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
- // The ID of the display which is responsible for receiving display-unspecified key and pointer
- // events.
- private int mTopFocusedDisplayId = INVALID_DISPLAY;
复制代码 2. 核心app:mFocusedApp代表了一个DisplayContent上正处于前台的ActivityRecord,一样寻常这个ActivityRecord下的窗口将会成为核心窗口,存在当核心app属于该ActivityRecord,但是核心窗口不属于该ActivityRecord下属的窗口的情况。- frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
- /**
- * The foreground app of this display. Windows below this app cannot be the focused window. If
- * the user taps on the area outside of the task of the focused app, we will notify AM about the
- * new task the user wants to interact with.
- */
- ActivityRecord mFocusedApp = null;
复制代码 3. 核心窗口:mCurrentFocus,当前正在与用户交互的窗口。此窗口负责吸取来自用户的键事故和指针事故。- frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
- /**
- /**
- * Window that is currently interacting with the user. This window is responsible for receiving
- * key events and pointer events from the user.
- */
- WindowState mCurrentFocus = null;
复制代码 mTopFocusedDisplayId界说在根节点RootWindowContainer中,这表明整个Android体系中只能有一个顶部核心屏幕,mFocusedApp和mCurrentFocus界说在DisplayContent中,表明每个屏幕都有自己的核心app和核心窗口。
在WindowState的构建过程中,会构建出一个范例为InputWindowHandle的对象,该对象的重要作用是生存窗口的一些信息,随后发送给InputDispatcher,InputWindowHandle在input系代表该应用窗口的对象,用于辨认以及分发事故。
先来总结一下核心窗口的产生过程,这个流程筹划到WMS,surfaceflinger,InputDispatcher:核心窗口的天生过程可以说是一个选拔,选送的过程,在窗口发生一些改变的时间会触发到wms去- frameworks/base/services/core/java/com/android/server/wm/WindowState.java
- WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
- WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
- int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
- PowerManagerWrapper powerManagerWrapper) {
- super(service);
- mTmpTransaction = service.mTransactionFactory.get();
- mSession = s;
- mClient = c;
- mAppOp = appOp;
- mToken = token;
- mActivityRecord = mToken.asActivityRecord();
- mOwnerUid = ownerId;
- mShowUserId = showUserId;
- mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
- mWindowId = new WindowId(this);
- mAttrs.copyFrom(a);
- mLastSurfaceInsets.set(mAttrs.surfaceInsets);
- mViewVisibility = viewVisibility;
- mPolicy = mWmService.mPolicy;
- mContext = mWmService.mContext;
- DeathRecipient deathRecipient = new DeathRecipient();
- mPowerManagerWrapper = powerManagerWrapper;
- mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
- // 如下:
- mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
- mActivityRecord != null
- ? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
- getDisplayId()));
- mInputWindowHandle.setOwnerPid(s.mPid);
- mInputWindowHandle.setOwnerUid(s.mUid);
- mInputWindowHandle.setName(getName());
- mInputWindowHandle.setPackageName(mAttrs.packageName);
- mInputWindowHandle.setLayoutParamsType(mAttrs.type);
复制代码- frameworks/base/services/core/java/com/android/server/wm/WindowState.java
- /**
- * Functions as a handle for a window that can receive input.
- * Enables the native input dispatcher to refer indirectly to the window manager's window state.
- * @hide
- */
- public final class InputWindowHandle {
- // Pointer to the native input window handle.
- // This field is lazily initialized via JNI.
- @SuppressWarnings("unused")
- private long ptr;
- // The input application handle.
- public InputApplicationHandle inputApplicationHandle;
- // The token associates input data with a window and its input channel. The client input
- // channel and the server input channel will both contain this token.
- public IBinder token;
- // The window name.
- public String name;
- // Window layout params attributes. (WindowManager.LayoutParams)
- public int layoutParamsFlags;
- public int layoutParamsType;
- // Dispatching timeout.
- public long dispatchingTimeoutMillis;
- // Window frame.
- public int frameLeft;
- public int frameTop;
- public int frameRight;
- public int frameBottom;
- public int surfaceInset;
- // Global scaling factor applied to touch events when they are dispatched
- // to the window
- public float scaleFactor;
复制代码- frameworks/base/core/java/android/view/InputApplicationHandle.java
- /**
- * Functions as a handle for an application that can receive input.
- * Enables the native input dispatcher to refer indirectly to the window manager's
- * application window token.
- * @hide
- */
- public final class InputApplicationHandle {
- // Pointer to the native input application handle.
- // This field is lazily initialized via JNI.
- @SuppressWarnings("unused")
- private long ptr;
- // Application name.
- public final @NonNull String name;
- // Dispatching timeout.
- public final long dispatchingTimeoutMillis;
- public final @NonNull IBinder token;
- private native void nativeDispose();
- public InputApplicationHandle(@NonNull IBinder token, @NonNull String name,
- long dispatchingTimeoutMillis) {
- this.token = token;
- this.name = name;
- this.dispatchingTimeoutMillis = dispatchingTimeoutMillis;
- }
- public InputApplicationHandle(InputApplicationHandle handle) {
- this.token = handle.token;
- this.dispatchingTimeoutMillis = handle.dispatchingTimeoutMillis;
- this.name = handle.name;
- }
- @Override
- protected void finalize() throws Throwable {
- try {
- nativeDispose();
- } finally {
- super.finalize();
- }
- }
- }
复制代码 一.WMS端革新流程
在framework中,触发核心窗口更新的流程的入口是WMS.updateFocusedWindowLocked,触发该函数的位置在fw中非常的多,比如在窗口布局过程中,窗口添加过程中,窗口的移除过程中:
updateFocusedWindowLocked
可见该函数的参数有两个,第一个参数代表更新核心的场景,如下,共5个场景,可以简朴代表调用updateFocusedWindowLocked的场景,第二个参数代表在更新核心窗口的过程是否顺道更新一下InputWindows信息。
在wms的updateFocusedWindowLocked方法中进一步调用了RootWindowContainer的updateFocusedWindowLocked- frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
- static final int UPDATE_FOCUS_NORMAL = 0;
- /** Caller will assign layers */
- static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
- /** Caller is performing surface placement */
- static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
- /** Caller will performSurfacePlacement */
- static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
- /** Indicates we are removing the focused window when updating the focus. */
- static final int UPDATE_FOCUS_REMOVING_FOCUS = 4;
- 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;
- }
复制代码 在RootWindowContainer方法中可见随即遍历了每一个DisplayContent,开始选拔每个DisplayContent上的核心窗口:dc.updateFocusedWindowLocked(mode, updateInputWindows, topFocusedDisplayId);
todo 去形貌一下topFocusedDisplayId的革新过程- frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
- boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
- mTopFocusedAppByProcess.clear();
- boolean changed = false;
- // 先初始化一下topFocusedDisplayId
- int topFocusedDisplayId = INVALID_DISPLAY;
- 遍历RootWindowContainer下的每一个DisplayContent
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final DisplayContent dc = mChildren.get(i);
- // 调用每一DisplayContent上的updateFocusedWindowLocked,去更新每一个DisplayContent上的焦点窗口
- changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows, topFocusedDisplayId);
- final WindowState newFocus = dc.mCurrentFocus;
- if (newFocus != null) {
- final int pidOfNewFocus = newFocus.mSession.mPid;
- if (mTopFocusedAppByProcess.get(pidOfNewFocus) == null) {
- mTopFocusedAppByProcess.put(pidOfNewFocus, newFocus.mActivityRecord);
- }
- if (topFocusedDisplayId == INVALID_DISPLAY) {
- topFocusedDisplayId = dc.getDisplayId();
- }
- } else if (topFocusedDisplayId == INVALID_DISPLAY && dc.mFocusedApp != null) {
- // The top-most display that has a focused app should still be the top focused
- // display even when the app window is not ready yet (process not attached or
- // window not added yet).
- topFocusedDisplayId = dc.getDisplayId();
- }
- }
- // 选了一圈下来,如果topFocusedDisplayId == INVALID_DISPLAY,就把topFocusedDisplayId = DEFAULT_DISPLAY
- if (topFocusedDisplayId == INVALID_DISPLAY) {
- topFocusedDisplayId = DEFAULT_DISPLAY;
- }
- if (mTopFocusedDisplayId != topFocusedDisplayId) {
- mTopFocusedDisplayId = topFocusedDisplayId;
- mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
- mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId);
- ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d", topFocusedDisplayId);
- }
- return changed;
- }
复制代码- frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
- /**
- * Update the focused window and make some adjustments if the focus has changed.
- *
- * @param mode Indicates the situation we are in. Possible modes are:
- * {@link WindowManagerService#UPDATE_FOCUS_NORMAL},
- * {@link WindowManagerService#UPDATE_FOCUS_PLACING_SURFACES},
- * {@link WindowManagerService#UPDATE_FOCUS_WILL_PLACE_SURFACES},
- * {@link WindowManagerService#UPDATE_FOCUS_REMOVING_FOCUS}
- * @param updateInputWindows Whether to sync the window information to the input module.
- * @param topFocusedDisplayId Display id of current top focused display.
- * @return {@code true} if the focused window has changed.
- */
- boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows,
- int topFocusedDisplayId) {
- WindowState newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
- if (mCurrentFocus == newFocus) {
- // add by sd. fix not trust virtual display binder leak.
- if (newFocus == null && !isTrusted()) {
- mWinRemovedSinceNullFocus.clear();
- mWinAddedSinceNullFocus.clear();
- }
- // end
- return false;
- }
-
- 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.
- getInputMonitor().setInputFocusLw(newFocus, updateInputWindows);
- }
- adjustForImeIfNeeded();
- // We may need to schedule some toast windows to be removed. The toasts for an app that
- // does not have input focus are removed within a timeout to prevent apps to redress
- // other apps' UI.
- scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);
- if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
- pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
- }
- // Notify the accessibility manager for the change so it has the windows before the newly
- // focused one starts firing events.
- // TODO(b/151179149) investigate what info accessibility service needs before input can
- // dispatch focus to clients.
- if (mWmService.mAccessibilityController != null) {
- mWmService.mH.sendMessage(PooledLambda.obtainMessage(
- this::updateAccessibilityOnWindowFocusChanged,
- mWmService.mAccessibilityController));
- }
- mLastFocus = mCurrentFocus;
- return true;
- }
复制代码- frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
- /**
- * Looking for the focused window on this display if the top focused display hasn't been
- * found yet (topFocusedDisplayId is INVALID_DISPLAY) or per-display focused was allowed.
- *
- * @param topFocusedDisplayId Id of the top focused display.
- * @return The focused window or null if there isn't any or no need to seek.
- */
- WindowState findFocusedWindowIfNeeded(int topFocusedDisplayId) {
- return (mWmService.mPerDisplayFocusEnabled || topFocusedDisplayId == INVALID_DISPLAY)
- ? findFocusedWindow() : null;
- }
- WindowState findFocusedWindow() {
- mTmpWindow = null;
- forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
- if (mTmpWindow == null) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows, display=%d",
- getDisplayId());
- return null;
- }
- return mTmpWindow;
- }
复制代码 如下会从上到下遍历该DisplayContent上的全部WindowState,如果找到符合条件的窗口,那么该窗口,则将该窗口生存在mTmpWindow,并返回ture。由于是从上往下遍历,以是层级越高的窗口越偶然机成为核心窗口。
起首不满足canReceiveKeys条件的是不能成为核心窗口的.其他成为核心窗口的条件不赘述。- frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
- 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 */));
- // 焦点窗口首先要满足 canReceiveKeys,否则无法成为焦点窗口。
- if (!w.canReceiveKeys()) {
- return false;
- }
- // 输入法相关,暂时不分析
- if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null
- || !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) {
- return false;
- }
- if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG && mImeLayeringTarget != null
- && !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME)
- && mImeLayeringTarget.isAnimating(PARENTS | TRANSITION,
- ANIMATION_TYPE_APP_TRANSITION)) {
- return false;
- }
- // 获取当前窗口所属的ActivityRecord
- final ActivityRecord activity = w.mActivityRecord;
- //
- if (focusedApp == null) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
- "findFocusedWindow: focusedApp=null using new focus @ %s", w);
- mTmpWindow = w;
- return true;
- }
- if (!focusedApp.windowsAreFocusable()) {
- // Current focused app windows aren't focusable...
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: focusedApp windows not"
- + " focusable using new focus @ %s", w);
- mTmpWindow = w;
- return true;
- }
- // Descend through all of the app tokens and find the first that either matches
- // win.mActivityRecord (return win) or mFocusedApp (return null).
- //如果当前所遍历到的窗口的层级位于focusedApp之下且该窗口属于activity的窗口,则把焦点窗口置为null。然后返回。
- if (activity != null && w.mAttrs.type != TYPE_APPLICATION_STARTING) {
- if (focusedApp.compareTo(activity) > 0) {
- // App root task below focused app root task. No focus for you!!!
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
- "findFocusedWindow: Reached focused app=%s", focusedApp);
- mTmpWindow = null;
- return true;
- }
- }
- // 以上条件都不符合
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: Found new focus @ %s", w);
- mTmpWindow = w;
- return true;
- };
复制代码 canReceiveKeys == true的条件- frameworks/base/services/core/java/com/android/server/wm/WindowState.java
- boolean canReceiveKeys() {
- return canReceiveKeys(false /* fromUserTouch */);
- }
- public String canReceiveKeysReason(boolean fromUserTouch) {
- return "fromTouch= " + fromUserTouch
- + " isVisibleOrAdding=" + isVisibleOrAdding()
- + " 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 = isVisibleOrAdding()
- && (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();
- }
- @Override
- public boolean canShowWhenLocked() {
- final boolean showBecauseOfActivity =
- mActivityRecord != null && mActivityRecord.canShowWhenLocked();
- final boolean showBecauseOfWindow = (getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
- return showBecauseOfActivity || showBecauseOfWindow;
- }
- /**
- * @return {@code true} if this window can receive touches based on among other things,
- * windowing state and recents animation state.
- **/
- boolean canReceiveTouchInput() {
- if (mActivityRecord == null || mActivityRecord.getTask() == null) {
- return true;
- }
- return !mActivityRecord.getTask().getRootTask().shouldIgnoreInput()
- && mActivityRecord.mVisibleRequested
- && !isRecentsAnimationConsumingAppInput();
- }
复制代码 回到DisplayCpntent.updateFocusedWindowLocked- frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
- /**
- * Update the focused window and make some adjustments if the focus has changed.
- *
- * @param mode Indicates the situation we are in. Possible modes are:
- * {@link WindowManagerService#UPDATE_FOCUS_NORMAL},
- * {@link WindowManagerService#UPDATE_FOCUS_PLACING_SURFACES},
- * {@link WindowManagerService#UPDATE_FOCUS_WILL_PLACE_SURFACES},
- * {@link WindowManagerService#UPDATE_FOCUS_REMOVING_FOCUS}
- * @param updateInputWindows Whether to sync the window information to the input module.
- * @param topFocusedDisplayId Display id of current top focused display.
- * @return {@code true} if the focused window has changed.
- */
-
- boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows,
- int topFocusedDisplayId) {
- // 此时的newFocus为找到的新焦点窗口
- WindowState newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
- // 如该Displaycontent上的焦点窗口没有发生变化,则不用去更新,返回
- if (mCurrentFocus == newFocus) {
- // add by sd. fix not trust virtual display binder leak.
- if (newFocus == null && !isTrusted()) {
- mWinRemovedSinceNullFocus.clear();
- mWinAddedSinceNullFocus.clear();
- }
- // end
- return false;
- }
-
- 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;
- // 如果更新模式不是UPDATE_FOCUS_WILL_ASSIGN_LAYERS,则把刚才选举出的焦点窗口设置给getInputMonitor,随后会交给surfaceflinger。
- if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
- // If we defer assigning layers, then the caller is responsible for doing this part.
- getInputMonitor().setInputFocusLw(newFocus, updateInputWindows);
- }
- .....
- mLastFocus = mCurrentFocus;
- return true;
- }
复制代码- frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
- void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d",
- newWindow, mDisplayId);
- final IBinder focus = newWindow != null ? newWindow.mInputChannelToken : null;
- // 没有发生改变 返回
- if (focus == mInputFocus) {
- return;
- }
- if (newWindow != null && newWindow.canReceiveKeys()) {
- // Displaying a window implicitly causes dispatching to be unpaused.
- // This is to protect against bugs if someone pauses dispatching but
- // forgets to resume.
- newWindow.mToken.paused = false;
- }
- // 设置 mUpdateInputWindowsNeeded = true;
- setUpdateInputWindowsNeededLw();
- if (updateInputWindows) {
- updateInputWindowsLw(false /*force*/);
- }
- }
复制代码- frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
- /* Updates the cached window information provided to the input */
- void updateInputWindowsLw(boolean force) {
- if (!force && !mUpdateInputWindowsNeeded) {
- return;
- }
- scheduleUpdateInputWindows();
- }
- private void scheduleUpdateInputWindows() {
- if (mDisplayRemoved) {
- return;
- }
- if (!mUpdateInputWindowsPending) {
- mUpdateInputWindowsPending = true;
- mHandler.post(mUpdateInputWindows);
- }
- }
复制代码- frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
- private class UpdateInputWindows implements Runnable {
- @Override
- public void run() {
- synchronized (mService.mGlobalLock) {
- mUpdateInputWindowsPending = false;
- mUpdateInputWindowsNeeded = false;
- if (mDisplayRemoved) {
- return;
- }
- // Populate the input window list with information about all of the windows that
- // could potentially receive input.
- // As an optimization, we could try to prune the list of windows but this turns
- // out to be difficult because only the native code knows for sure which window
- // currently has touch focus.
- // If there's a drag in flight, provide a pseudo-window to catch drag input
- final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
- // Add all windows on the default display.
- mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
- }
- }
- }
复制代码- frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
- private void updateInputWindows(boolean inDrag) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
- mPipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP);
- mWallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER);
- mRecentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
- mAddPipInputConsumerHandle = mPipInputConsumer != null;
- mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null;
- mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null;
- mDisableWallpaperTouchEvents = false;
- mInDrag = inDrag;
- resetInputConsumers(mInputTransaction);
- // 遍历对应屏幕上的所有WindowState,更新他们的InputWindowHandle,随后发送给SurfaceFlinger
- mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
- // 更新焦点窗口信息给SurfaceFlinger
- updateInputFocusRequest(mRecentsAnimationInputConsumer);
- if (!mUpdateInputWindowsImmediately) {
- mDisplayContent.getPendingTransaction().merge(mInputTransaction);
- mDisplayContent.scheduleAnimation();
- }
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
复制代码 更新全部窗口的InputWindowHandle信息- public void accept(WindowState w) {
- ......
- if (w.mWinAnimator.hasSurface()) {
- //更新该窗口的inputWindowHandle信息
- populateInputWindowHandle(inputWindowHandle, w);
- // 将更新后的inputWindowHandle发送给Surfaceflinger
- setInputWindowInfoIfNeeded(mInputTransaction,
- w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
- }
- }
- }
复制代码 更新全部核心窗口- private void updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer) {
- final WindowState focus = mDisplayContent.mCurrentFocus;
- ......
- requestFocus(focusToken, focus.getName());
- }
- }
复制代码- private void requestFocus(IBinder focusToken, String windowName) {
- if (focusToken == mInputFocus) {
- return;
- }
- mInputFocus = focusToken;
- 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);
- }
复制代码 二.SurfaceFlinger端革新流程
SurfaceFlinger中省略了处置处罚Trasnaction的流程,直接分析SurfaceFlinger向InputDispatcher更新layer的信息和核心信息.
1.网络windowInfos 遍历SurfaceFlinger 当前绘制的Layer聚集mDrawingState,当对应的layer有inputChannel时把该layer的 信息封装后 生存在 windowInfos. 网络 全部的display信息,添加到 displayInfos中.
2.更新 WindowInfo等信息 到相干的监听,InputDispatcher 便是此中的监听之一
3.更新 FocusedWindow信息至 inputFlinger.- void SurfaceFlinger::updateInputFlinger() {
- ATRACE_CALL();
- if (!mInputFlinger) {
- return;
- }
- std::vector<WindowInfo> windowInfos;
- std::vector<DisplayInfo> displayInfos;
- bool updateWindowInfo = false;
- // 只有当有mVisibleRegionsDirty || mInputInfoChanged变化的之后才去收集 windowInfos 和displayInfos
- if (mVisibleRegionsDirty || mInputInfoChanged) {
- mInputInfoChanged = false;
- updateWindowInfo = true;
- // 1.收集windowInfos 遍历SurfaceFlinger 当前绘制的Layer集合mDrawingState,当对应的layer有inputChannel时
- // 把该layer的 信息封装后 保存在 windowInfos
- // 2.收集 所有的display信息,添加到 displayInfos中
- buildWindowInfos(windowInfos, displayInfos);
- }
- // 当 上层 有请求 焦点窗口时, mInputWindowCommands 不为空
- if (!updateWindowInfo && mInputWindowCommands.empty()) {
- return;
- }
- BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo,
- windowInfos = std::move(windowInfos),
- displayInfos = std::move(displayInfos),
- inputWindowCommands =
- std::move(mInputWindowCommands),
- inputFlinger = mInputFlinger, this]() {
- ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
- if (updateWindowInfo) {
- // 更新 WindowInfo等信息 到相关的监听,InputDispatcher 便是其中的监听之一
- mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
- inputWindowCommands.syncInputWindows);
- } else if (inputWindowCommands.syncInputWindows) { // syncInputWindows 在特殊情况下为 false,普通更新信息 都为false
- // If the caller requested to sync input windows, but there are no
- // changes to input windows, notify immediately.
- windowInfosReported();
- }
- // 更新 FocusedWindow信息至 inputFlinger,当上层有请求新的焦点窗口时 inputWindowCommands.focusRequests 就有值
- for (const auto& focusRequest : inputWindowCommands.focusRequests) {
- inputFlinger->setFocusedWindow(focusRequest);
- }
- }});
- mInputWindowCommands.clear();
- }
复制代码 至此Surfaceflinger的相干分析完毕.
三.InputFlinger端核心革新流程
1.更新InputFlinger端的InputWindowInfo信息
1.更新Display信息到 mDisplayInfos
2.更新 WindowInfoHandle 到 mWindowHandlesByDisplay中- frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
- void InputDispatcher::onWindowInfosChanged(const gui::WindowInfosUpdate& update) {
- // 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 : update.windowInfos) {
- handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
- handlesPerDisplay[info.displayId].push_back(sp<WindowInfoHandle>::make(info));
- }
- { // acquire lock
- std::scoped_lock _l(mLock);
- // Ensure that we have an entry created for all existing displays so that if a displayId has
- // no windows, we can tell that the windows were removed from the display.
- for (const auto& [displayId, _] : mWindowHandlesByDisplay) {
- handlesPerDisplay[displayId];
- }
-
-
- // 更新Display信息到 mDisplayInfos
- mDisplayInfos.clear();
- for (const auto& displayInfo : update.displayInfos) {
- mDisplayInfos.emplace(displayInfo.displayId, displayInfo);
- }
-
- // 将会更新 WindowInfoHandle 到 mWindowHandlesByDisplay中
- for (const auto& [displayId, handles] : handlesPerDisplay) {
- setInputWindowsLocked(handles, displayId);
- }
- if (update.vsyncId < mWindowInfosVsyncId) {
- ALOGE("Received out of order window infos update. Last update vsync id: %" PRId64
- ", current update vsync id: %" PRId64,
- mWindowInfosVsyncId, update.vsyncId);
- }
- mWindowInfosVsyncId = update.vsyncId;
- }
- // Wake up poll loop since it may need to make new input dispatching choices.
- mLooper->wake();
- }
复制代码 2.更新InputFlinger端的核心信息点窗口:
该过程中重要做了两件事:
- 在更新 屏幕–核心map,返回更新结果的布局体,struct FocusChanges { sp<IBinder> oldFocus; sp<IBinder> newFocus; int32_t displayId; std::string reason;
可见该布局体包罗原始核心信息,更新的核心窗口信息,屏幕id,核心改变缘故起因。
- 把更新结果关照到窗口端
- frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
- void InputDispatcher::setFocusedWindow(const FocusRequest& request) {
- { // acquire lock
- std::scoped_lock _l(mLock);
- // 去更新对应屏幕上的焦点信息,并返回更新结果的结构体
- std::optional<FocusResolver::FocusChanges> changes =
- mFocusResolver.setFocusedWindow(request, getWindowHandlesLocked(request.displayId));
- // change不为空,说明更新成功,接下把更新结果通知到窗口端
- if (changes) {
- onFocusChangedLocked(*changes);
- }
- } // release lock
- // Wake up poll loop since it may need to make new input dispatching choices.
- mLooper->wake();
- }
复制代码 2.1 在更新 屏幕–核心map,返回更新结果的布局体
- frameworks/native/services/inputflinger/dispatcher/FocusResolver.cpp
- std::optional<FocusResolver::FocusChanges> FocusResolver::setFocusedWindow(
- const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& 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;
- }
- // request.focusedToken 一般为null,跳过
- 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;
- }
- 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;
- 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.
- return updateFocusedWindow(displayId, "Waiting for window because " + NamedEnum::string(result),
- nullptr);
- }
复制代码 如下将会更新对应屏幕上的核心窗口:
在更新完 屏幕–核心map后,返回更新结果的布局体,struct FocusChanges { sp<IBinder> oldFocus; sp<IBinder> newFocus; int32_t displayId; std::string reason;
可见该布局体包罗原始核心信息,更新的核心窗口信息,屏幕id,核心改变缘故起因。- frameworks/native/services/inputflinger/dispatcher/FocusResolver.cpp
- 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;
- }
- if (newFocus) {
- // 如果设置的新焦点不为空,则更新 屏幕--焦点map
- mFocusedWindowTokenByDisplay[displayId] = {tokenName, newFocus};
- } else {
- // 如果设置的新焦点为空,则删除屏幕--焦点map中该屏幕的焦点信息
- mFocusedWindowTokenByDisplay.erase(displayId);
- }
- /* 返回struct FocusChanges {
- sp<IBinder> oldFocus;
- sp<IBinder> newFocus;
- int32_t displayId;
- std::string reason;
- };结构体*/
- return {{oldFocus, newFocus, displayId, reason}};
- }
复制代码 2.2 把更新结果关照到窗口端
如被骗InputFlinger的核心窗口完成改变时将会调用到该函数:
- 天生核心脱离旧的核心窗口的天生,随后该事故会发给旧的核心窗口。
- 天生核心进入新的窗口的事故,这个事故稍后会发送给新的核心窗口。
- frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
- void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& changes) {
- if (changes.oldFocus) {
- // 如果旧的焦点窗口的InputChannel还可用
- 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);
- }
复制代码 发送InputDiapatchar端核心改变的事故给应用端,紧接着会打印对应的event log:
核心撤出: input_focus: [Focus leaving 7d52ce4 NotificationShade (server),reason=setFocusedWindow]
核心进入: input_foc: [Focus entering 106fc21 com.android.settings/com.android.settings.Settings$ConnectedDeviceDashboardActivity (server),reason=setFocusedWind- frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
- void InputDispatcher::(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);
- // 打印event log
- android_log_event_list(LOGTAG_INPUT_FOCUS) << message << reason << LOG_ID_EVENTS;
- // 分发焦点事件
- dispatchEventLocked(currentTime, entry, {target});
- }
复制代码 至此 ,分析完毕
增补更新核心app的流程- 解锁时:
- newFocus:ActivityRecord{807c8eb u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t7}
- java.lang.Exception
- at com.android.server.wm.DisplayContent.setFocusedApp(DisplayContent.java:3848)
- at com.android.server.wm.ActivityTaskManagerService.setLastResumedActivityUncheckLocked(ActivityTaskManagerService.java:
- at com.android.server.wm.ActivityTaskSupervisor.updateTopResumedActivityIfNeeded(ActivityTaskSupervisor.java:2130)
- at com.android.server.wm.TaskFragment.setResumedActivity(TaskFragment.java:520)
- at com.android.server.wm.TaskFragment.onActivityStateChanged(TaskFragment.java:816)
- at com.android.server.wm.ActivityRecord.setState(ActivityRecord.java:5639)
- at com.android.server.wm.TaskFragment.resumeTopActivity(TaskFragment.java:1421)
- at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:5017)
- at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:4947)
- at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:4966)
- at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:4998)
- at com.android.server.wm.RootWindowContainer.lambda$applySleepTokens$20(RootWindowContainer.java:2369)
- at com.android.server.wm.RootWindowContainer.$r8$lambda$95qC-1ZUnz4HFKq9TM8jsgele88(Unknown Source:0)
- at com.android.server.wm.RootWindowContainer$$ExternalSyntheticLambda18.accept(Unknown Source:8)
- at com.android.server.wm.Task.forAllRootTasks(Task.java:3182)
- at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2066)
- at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2066)
- at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2066)
- at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2066)
- at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2066)
- at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2066)
- at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2059)
- at com.android.server.wm.RootWindowContainer.applySleepTokens(RootWindowContainer.java:2354)
- at com.android.server.wm.ActivityTaskManagerService.updateSleepIfNeededLocked(ActivityTaskManagerService.java:4787)
- at com.android.server.wm.RootWindowContainer.removeSleepToken(RootWindowContainer.java:2624)
- at com.android.server.wm.ActivityTaskManagerService$SleepTokenAcquirerImpl.release(ActivityTaskManagerService.java:4762)
- at com.android.server.wm.KeyguardController.updateKeyguardSleepToken(KeyguardController.java:518)
- at com.android.server.wm.KeyguardController.updateKeyguardSleepToken(KeyguardController.java:509)
- at com.android.server.wm.KeyguardController.keyguardGoingAway(KeyguardController.java:270)
- at com.android.server.wm.ActivityTaskManagerService.lambda$keyguardGoingAway$4(ActivityTaskManagerService.java:3479)
- at com.android.server.wm.ActivityTaskManagerService.$r8$lambda$3ir4F8YeWgNCplL0b7P4iAJf_NI(Unknown Source:0)
- at com.android.server.wm.ActivityTaskManagerService$$ExternalSyntheticLambda1.accept(Unknown Source:6)
- at com.android.server.wm.RootWindowContainer.forAllDisplays(RootWindowContainer.java:1258)
- at com.android.server.wm.ActivityTaskManagerService.keyguardGoingAway(ActivityTaskManagerService.java:3478)
- at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1721)
- at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5335)
- at android.os.Binder.execTransactInternal(Binder.java:1280)
- at android.os.Binder.execTransact(Binder.java:1244)
复制代码 冷启动应用时:- newFocus:ActivityRecord{39b5e82 u0 com.android.settings/.Settings} t8}
- java.lang.Exception
- at com.android.server.wm.DisplayContent.setFocusedApp(DisplayContent.java:3848)
- at com.android.server.wm.ActivityTaskManagerService.setLastResumedActivityUncheckLocked(ActivityTaskManagerService.java:4716)
- at com.android.server.wm.ActivityTaskSupervisor.updateTopResumedActivityIfNeeded(ActivityTaskSupervisor.java:2130)
- at com.android.server.wm.TaskFragment.setResumedActivity(TaskFragment.java:520)
- at com.android.server.wm.TaskFragment.onActivityStateChanged(TaskFragment.java:816)
- at com.android.server.wm.ActivityRecord.setState(ActivityRecord.java:5639)
- at com.android.server.wm.Task.minimalResumeActivityLocked(Task.java:4760)
- at com.android.server.wm.ActivityTaskSupervisor.realStartActivityLocked(ActivityTaskSupervisor.java:981)
- at com.android.server.wm.ActivityTaskSupervisor.startSpecificActivity(ActivityTaskSupervisor.java:1048)
- at com.android.server.wm.TaskFragment.resumeTopActivity(TaskFragment.java:1542)
- at com.android.server.wm.Task.resumeTopActivityInnerLocked(Task.java:5017)
- at com.android.server.wm.Task.resumeTopActivityUncheckedLocked(Task.java:4947)
- at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2281)
- at com.android.server.wm.RootWindowContainer.resumeFocusedTasksTopActivities(RootWindowContainer.java:2267)
- at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1800)
- at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:6243)
- at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:190)
- at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:609)
- at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:127)
- at android.os.Binder.execTransactInternal(Binder.java:1280)
- at android.os.Binder.execTransact(Binder.java:1244)
复制代码 |