再次回到InputMonitor#updateInputWindows(),调用SurfaceControl.Transaction#merge,之后,当WindowAnimator.java的animate()时发起apply();可以是线程"android.anim"或"binder"线程;
@frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
updateFocusedWindowLocked
// 向InputMonitor中设置焦点窗口
@frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) { getInputMonitor().setInputFocusLw(newFocus, updateInputWindows); }
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d", newWindow, mDisplayId); //这里log打印要切到那个窗口
final IBinder focus = newWindow != null ? newWindow.mInputChannelToken : null; // 更新当前焦点窗口
setUpdateInputWindowsNeededLw() // 更新当前焦点窗口 使mUpdateInputWindowsNeeded设置为true
mUpdateInputWindowsNeeded = true;
if (updateInputWindows) { updateInputWindowsLw(false /*force*/); } // 更新所有inputwindow
if (!force && !mUpdateInputWindowsNeeded) { return; }
scheduleUpdateInputWindows();
//mUpdateInputWindowsPending只是用来保证post执行不被重复执行,配合锁实现
if (!mUpdateInputWindowsPending) mUpdateInputWindowsPending = true; mHandler.post(mUpdateInputWindows); }
UpdateInputWindows::run()
if (mDisplayRemoved) { return; } //没有display的话return
final boolean inDrag = mService.mDragDropController.dragDropActiveLocked(); // 是否正在拖拽
mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag); // 在默认显示上添加所有窗口。
//显式创建的特殊InputConsumer对象
mPipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP); // 用于处理Nav相关input事件
mWallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER); // 用于处理壁纸相关input事件
mRecentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION) // 用于处理最近的动画输入相关input事件
resetInputConsumers(mInputTransaction); // 重置mInputTransaction
// 如果处于活动状态,则更新最近的输入消费者层
final ActivityRecord activeRecents = getWeak(mActiveRecentsActivity);
if (mAddRecentsAnimationInputConsumerHandle && getWeak(mActiveRecentsActivity) != null) {
final WindowContainer layer = getWeak(mActiveRecentsLayerRef);
mRecentsAnimationInputConsumer.show(mInputTransaction, layer != null ? layer : getWeak(mActiveRecentsActivity));
mAddRecentsAnimationInputConsumerHandle = false;
}
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */); // 遍历窗口更新inputInfo
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
@frameworks/base/services/core/java/com/android/server/wm/WindowState.java
if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
forAllWindowTopToBottom(callback);
if (applyInOrderWithImeWindows(callback, true /* traverseTopToBottom */)) {
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
if (callback.apply(this)
@frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
mConsumer.accept(w);
// 获取WindowState的InputWindowHandle对象,WindowState里保存着InputWindowHandle,每次复用,判断changes,减少同步
final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle;
//判断窗口mInputChannelToken是否为空;窗口是否销毁;窗口是否可以接受input事件
if (w.mInputChannelToken == null || w.mRemoved || !w.canReceiveTouchInput()) {
if (w.mWinAnimator.hasSurface()) {
// 确保输入信息无法接收输入事件。可以省略。遮挡检测取决于类型或是否是可信覆盖。
populateOverlayInputInfo(inputWindowHandle, w);
setInputWindowInfoIfNeeded(mInputTransaction, w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);}
return; // 跳过此窗口,因为它不可能接收输入。
final RecentsAnimationController recentsAnimationController = mService.getRecentsAnimationController(); // 最近任务是否存在
if (w.inPinnedWindowingMode()) { if (mAddPipInputConsumerHandle) { mPipInputConsumer.mWindowHandle.replaceTouchableRegionWithCrop( rootTask.getSurfaceControl()); } } // 处理处于PIP模式时的input事件
if (mAddWallpaperInputConsumerHandle) { mWallpaperInputConsumer.show(mInputTransaction, w); } // mWallpaperInputConsumer处理壁纸input事件
if (mInDrag && w.isVisible() && w.getDisplayContent().isDefaultDisplay) { mService.mDragDropController.sendDragStartedIfNeededLocked(w); } // 是否处于拖拽过程中
mService.mKeyInterceptionInfoForToken.put(w.mInputChannelToken, w.getKeyInterceptionInfo()); // 注册密钥拦截信息
if (w.mWinAnimator.hasSurface()) {
@frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
populateInputWindowHandle(inputWindowHandle, w); // 填充InputWindowHandle
@frameworks/base/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
inputWindowHandle.setFocusable(focusable);
inputWindowHandle.setSurfaceInset(w.mAttrs.surfaceInsets.left);
inputWindowHandle.setTouchableRegionCrop(touchableRegionCrop);
setInputWindowInfoIfNeeded(mInputTransaction, w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle); //提交inputWindowHandle
@frameworks/base/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
inputWindowHandle.applyChangesToSurface(t, sc);
@frameworks/base/core/java/android/view/SurfaceControl.java
t.setInputWindowInfo(sc, mHandle);
@frameworks/base/core/jni/android_view_SurfaceControl.cpp
nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
@frameworks/native/libs/gui/SurfaceComposerClient.cpp
// native层也有对应的surfacecontrol,刚刚封装的WindowInfo也被传递进来
transaction->setInputWindowInfo(ctrl, *handle->getInfo());
layer_state_t* s = getLayerState(sc); //获取surfaceControl对应的layer_state_t(surfaceflinger的一个图层)
s.state.layerId = sc->getLayerId();
//用于执行apply时,把所有的layer操作一起同步到底层SurfaceFlinger
mComposerStates[handle] = s
s->windowInfoHandle = new WindowInfoHandle(info); // 把对应的WindowInfo数据设置相应的参数给layer_state_t,就是surface里面的layer
s->what |= layer_state_t::eInputInfoChanged; //在SurfaceFlinger会按照flag来解析改变数据
|| applyImeWindowsIfNeeded(callback, traverseTopToBottom)) {
updateInputFocusRequest(mRecentsAnimationInputConsumer); //调用到Focus Request
// 当应用程序获得焦点但其窗口尚未显示时,请从当前窗口中删除输入焦点,这强制输入焦点匹配 mDisplayContent.mCurrentFocus。
//但是,如果发现更多特殊情况,即输入焦点和 mDisplayContent.mCurrentFocus 预计不匹配,则需要检查如何以及何时撤销焦点的整个逻辑。
if (mDisplayContent.mFocusedApp != null && mInputFocus != null) {
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "App %s is focused," + " but the window is not ready. Start a transaction to remove focus from" + " the window of non-focused apps.", mDisplayContent.mFocusedApp.getName());
mInputTransaction.removeCurrentInputFocus(mDisplayId) //从具有输入焦点的当前窗口中移除输入焦点。仅当当前聚焦的应用程序没有响应并且当前聚焦的窗口不属于当前聚焦的应用程序时才应调用。
final IBinder focusToken = focus != null ? focus.mInputChannelToken : null; //mInputChannelToken在openInputChannel的时候创建mInputChannelToken = mInputChannel.getToken();
//如果当前焦点窗口没有surface或者当前窗口无法聚焦则return
if (!focus.mWinAnimator.hasSurface() || !focus.mInputWindowHandle.isFocusable()) {
mInputFocus = null;
return;
requestFocus(focusToken, focus.getName()); //将包装出来的InputChannelToken(focusToken)信息向native层进行同步
mInputFocus = focusToken;
mInputFocusRequestTimeMillis = SystemClock.uptimeMillis(); //输入焦点请求时间 用于anr的计算
@frameworks/base/core/java/android/view/SurfaceControl.java
//如果窗口可聚焦,则将焦点设置在由输入 {@code token} 标识的窗口上,否则请求将被丢弃。如果窗口不可见,则请求将排队,直到窗口变得可见或该请求被另一个请求覆盖
//当前聚焦的窗口将立即失去焦点。这是为了向新获得焦点的窗口发送在完成其第一次绘制时发生的任何焦点调度事件
mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId);
@frameworks/base/core/jni/android_view_SurfaceControl.cpp
nativeSetFocusedWindow(mNativeObject, token, windowName, null /* focusedToken */, null /* focusedWindowName */, displayId);
sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj));
request.displayId = displayId;
@frameworks/native/libs/gui/SurfaceComposerClient.cpp
transaction->setFocusedWindow(request); //上面就是一些focusToken的异常检测,没问题,会调用这个方法
mInputWindowCommands.focusRequests.push_back(request);
//在这里打印要请求进入的窗口Focus request
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", windowName);
// 将mInputTransaction合并到mPendingTransaction上进行提交
if (!mUpdateInputWindowsImmediately) {
@frameworks/base/core/java/android/view/SurfaceControl.java
mDisplayContent.getPendingTransaction().merge(mInputTransaction);
@frameworks/base/core/jni/android_view_SurfaceControl.cpp
nativeMergeTransaction(mNativeObject, other.mNativeObject);
@frameworks/native/libs/gui/SurfaceComposerClient.cpp
transaction->merge(std::move(*otherTransaction));
mComposerStates[handle].state.merge(composerState.state);
mInputWindowCommands.merge(other.mInputWindowCommands);
mDisplayContent.scheduleAnimation(); }