在前一节中,InputDispatcher 的事件派发工作调用 InputChannel sendMessage 方法标志着 InputDispatcher 一个周期的工作结束。但意味着事件找到对应的窗口处理的开始。
上一节中 mFocusedWindowHandle 是 InputDispatcher 的成员变量,它是确定发送事件消息的关键。我们以它为突破口寻找“出路”。mFocusedWindowHandle 在 setInputWindows 方法中进行了赋值,我们需要反推一下。
frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
{ // acquire lock
AutoMutex _l(mLock);
Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
mWindowHandles = inputWindowHandles;
sp<InputWindowHandle> newFocusedWindowHandle;
bool foundHoveredWindow = false;
for (size_t i = 0; i < mWindowHandles.size(); i++) {
const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
mWindowHandles.removeAt(i--);
continue;
}
if (windowHandle->getInfo()->hasFocus) {
// 找到焦点窗口句柄
newFocusedWindowHandle = windowHandle;
}
......
}
......
if (mFocusedWindowHandle != newFocusedWindowHandle) {
if (mFocusedWindowHandle != NULL) {
sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
if (focusedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(
focusedInputChannel, options);
}
}
// mFocusedWindowHandle 赋值焦点窗口句柄
mFocusedWindowHandle = newFocusedWindowHandle;
}
......
} // release lock
// 唤醒 Looper 循环,因为它可能需要作出新的输入派发选择。
mLooper->wake();
}
- 将 windowHandleObjArray java 数组对象的每个元素转化为 InputWindowHandle native 对象;
- 调用 InputDispatcher 类的 setInputWindows 方法。
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
Vector<sp<InputWindowHandle> > windowHandles;
if (windowHandleObjArray) {
jsize length = env->GetArrayLength(windowHandleObjArray);
for (jsize i = 0; i < length; i++) {
jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
if (! windowHandleObj) {
break; // found null element indicating end of used portion of the array
}
// 将数组中的 java 对象转化为 native 对象
sp<InputWindowHandle> windowHandle =
android_server_InputWindowHandle_getHandle(env, windowHandleObj);
if (windowHandle != NULL) {
//push 到容器中
windowHandles.push(windowHandle);
}
env->DeleteLocalRef(windowHandleObj);
}
}
// 调用 InputDispatcher setInputWindows 方法
mInputManager->getDispatcher()->setInputWindows(windowHandles);
......
}
setInputWindows 有是在 nativeSetInputWindows 中调用的。
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobjectArray windowHandleObjArray) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
im->setInputWindows(env, windowHandleObjArray);
}
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static JNINativeMethod gInputManagerMethods[] = {
/* name, signature, funcPtr */
......
{ "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;)V",
(void*) nativeSetInputWindows },
......
};
不难知道 nativeSetInputWindows 对应 jni 中的 java 层的方法是在 InputManagerService 类中。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public class InputManagerService extends IInputManager.Stub
implements Watchdog.Monitor {
......
private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
......
public void setInputWindows(InputWindowHandle[] windowHandles) {
nativeSetInputWindows(mPtr, windowHandles);
}
......
}
到这里还没有关联到对应的窗口,但可以确信的一点是,窗口和 InputDispatcher 关联,必须要调用 InputManagerService 类中的 setInputWindows 方法。下面我们正向推理,先得从 Activity setContentView 说起。
getWindow() 返回的是一个 PhoneWindow 对象,现在转入 PhoneWindow 类的 setContentView 方法。
frameworks/base/core/java/android/app/Activity.java
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback {
......
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
......
}
PhoneWindow 类的 setContentView 会调用 installDecor() 来生成 DecorView,方便后续纳入 WindowManager 管理。
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
......
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
......
}
......
}
......
}
installDecor() 方法调用了 generateDecor() 生成 DecorView。
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
......
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
......
}
......
}
......
}
在 Activity 启动流程分析中,我们知道启动一个 Activity 当调用了 ActivityThread 中 handleLaunchActivity 方法后,马上就会调用 handleResumeActivity 方法,奥秘就在这里!
- 获取 Window 和 DecorView 对象;
- 设置 DecorView 为不可见;
- 获取 WindowManager 对象;
- 将 DecorView 添加到 ViewManager。
frameworks/base/core/java/android/app/ActivityThread.java
public final class ActivityThread {
......
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
......
// TODO Push resumeArgs into the activity for consideration
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
......
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
// 设置 DecorView 为不可见
decor.setVisibility(View.INVISIBLE);
// 获取 WindowManager 对象
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
// 将 DecorView 添加到 ViewManager
wm.addView(decor, l);
}
} else if (!willBeVisible) {
......
}
......
// 告诉活动管理器我们已经恢复。
if (reallyResume) {
try {
ActivityManagerNative.getDefault().activityResumed(token);
} catch (RemoteException ex) {
}
}
} else {
......
}
}
......
}
上一步 wm 局部变量实际指向 WindowManagerImpl 对象,所以实际调用了 WindowManagerImpl 类的 addView 方法。此处有调用了 WindowManagerGlobal 单例的 addView 方法。
frameworks/base/core/java/android/view/WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
......
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
......
}
- 创建 ViewRootImpl 对象;
- 调用 ViewRootImpl 类 setView 方法。
frameworks/base/core/java/android/view/WindowManagerImpl.java
public final class WindowManagerGlobal {
......
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
......
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
......
root = new ViewRootImpl(view.getContext(), display);
......
}
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
......
}
}
......
}
- 创建 InputChannel 对象;
- 远程调用 Session addToDisplay 方法;
- 创建接收输入事件者 WindowInputEventReceiver。
frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
......
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
......
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
......
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
......
} finally {
......
}
......
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 接收输入事件
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
......
}
}
}
......
}
我们重点关注 Session 类 addToDisplay 方法。
Session 类表示活动的客户端会话。通常,每个与窗口管理器交互的进程都有一个 Session 对象。
addToDisplay 方法实际工作由 WindowManagerService 类 addWindow 方法完成。
frameworks/base/services/core/java/com/android/server/wm/Session.java
final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
final WindowManagerService mService;
......
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
......
}
addWindow 方法首先调用 setUpdateInputWindowsNeededLw() 方法将 InputMonitor 类中的成员变量 mUpdateInputWindowsNeeded 置为 true,然后调用其 updateInputWindowsLw 方法。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
......
final InputMonitor mInputMonitor = new InputMonitor(this);
......
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
......
synchronized(mWindowMap) {
......
mInputMonitor.setUpdateInputWindowsNeededLw();
......
// 更新当前焦点窗口
if (focusChanged) {
mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
}
mInputMonitor.updateInputWindowsLw(false /*force*/);
......
}
......
}
......
}
updateInputWindowsLw 中只要 force 和 mUpdateInputWindowsNeeded 有一个为 true,就会继续执行下面的代码,由于上一步设置了 mUpdateInputWindowsNeeded 为 true,因此一定会向下执行,所以接着就会运行 WindowManagerService 类成员变量 mInputManager 的 setInputWindows 方法。实际上就是调用 InputManagerService 类 setInputWindows 方法。这就回到了我们起初逆向分析的地方了,打通了整个窗口关联的过程。
frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
private final WindowManagerService mService;
......
public void updateInputWindowsLw(boolean force) {
if (!force && !mUpdateInputWindowsNeeded) {
return;
}
mUpdateInputWindowsNeeded = false;
......
mService.mInputManager.setInputWindows(mInputWindowHandles);
......
}
......
}
下面是整个流程的时序图。