一 概述
前面介绍了 InputReader 和 InputDispatcher 两个线程的工作过程。在 InputDispatcher 的工作过程中讲到调用 InputChanel 通过 socket 与远程进程通信,本文便展开讲解这个 socket 是如何建立的。
对于 InputReader 和 InputDispatcher 都是运行在 system_server 进程; 用户点击的界面,往往可能是在某一个 app 中,而每个 app 一般都运行在自己的进程里,这里就涉及到跨进程通信,也就是 app 进程是如何与 system_server 进程建立通信的?答案就是 InputChannel,我们看看 InputChannel 的注释:
/**
* An input channel specifies the file descriptors used to send input events to
* a window in another process. It is Parcelable so that it can be sent
* to the process that is to receive events. Only one thread should be reading
* from an InputChannel at a time.
* @hide
*/
public final class InputChannel implements Parcelable {
.....
}
说它是用来将输入事件发送到其他进程的窗口的一个通道,并且它实现了 Parcelable,可以将其发送到需要接收输入事件的进程,从注释中我们就能清楚地知道 InputChannel 的作用。
要了解 InputChannel 是何时建立起来的,需要从 Activity 最基本的创建过程开始说起。我们都知道,一般地一个 Activity 对应一个应用窗口,每一个窗口对应一个 ViewRootImpl。窗口是如何添加到 Activity 的,一切需要从 Activity.onCreate() 为起点讲解。
二 UI线程
我们已经知道,Activity 生命周期的回调方法,都是运行在主线程的,主线程也称之为 UI 线程,所有 UI 相关的操作都需要运行在该线程。本文题目虽然是 UI 线程,但并非只介绍所有运行在 UI 线程的流程,文中还涉及 binder thread。
2.1 Activity.onCreate
Activity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
}
Activity 的启动是由 system_server 进程控制的:(参考 Android四大组件系列2 Activity启动流程(上))
- handleLaunchActivity():会调用 Activity.onCreate(),该方法内再调用 setContentView(),经过 AMS 与 WMS 的各种交互,层层调用后,进入 handleResumeActivity()
- handleResumeActivity():会调用 Activity.makeVisible(),该方法继续调用,便会执行到 WindowManagerImpl.addView(),该方法内部再调用 WindowManagerGlobal.addView()
2.2 WindowManagerGlobal.addView
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
......
ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
root.setView(view, wparams, panelParentView);
......
}
2.3 ViewRootImpl
ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
mContext = context;
// 获取 IWindowSession 的代理类,为单例模式
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mThread = Thread.currentThread(); // 主线程
// IWindow.Stub 的实现类,用于服务端向客户端通信
mWindow = new W(this);
mChoreographer = Choreographer.getInstance();
......
}
2.3.1 WindowManagerGlobal.getWindowSession
WindowManagerGlobal.java
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
// 获取 WMS 的代理类
IWindowManager windowManager = getWindowManagerService();
// 经过 Binder 调用,最终调用 WMS
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
...
}
}
return sWindowSession
}
}
2.3.2 WMS.openSession
public IWindowSession openSession(IWindowSessionCallback callback) {
return new Session(this, callback);
}
再次经过 Binder 将数据返回给 app 进程,则获取的便是 Session 的代理对象。
2.3.3 ViewRootImpl.setView
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs,
View panelParentView) {
synchronized (this) {
......
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel(); // 关键核心点:创建 InputChannel 对象
}
// 通过 Binder 调用,进入 system_server 进程的 Session
// 注意把 mInputChannel 作为参数传递给了 WMS
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
......
if (view instanceof RootViewSurfaceTaker) {
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 创建 WindowInputEventReceiver 对象
// 注意也是把 mInputChannel 作为参数传递给了 WindowInputEventReceiver
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
}
}
该方法主要功能:
- 创建 APP 端 Java 层的 InputChannel 对象 mInputChannel
- 把这个 mInputChannel 通过 Binder 跨进程传递给 WMS,在 WMS 中通过 openInputChannelPair 创建 socket pair,将其中的 socket 客户端赋值给 mInputChannel
- 创建 WindowInputEventReceiver 对象,并把 mInputChannel 传入其中,用来接收输入事件
需要注意的是:这里仅仅是 new 了一个 InputChanel,并未对其成员变量填充任何数据,也就是说这只是个空的 InputChanel,它的具体赋值是在 WMS 中完成的。
跨进程调用,进入 binder thread 执行如下方法:
2.4 Session.addToDisplay
public int addToDisplay(IWindow window, int seq, ......) {
return mService.addWindow(this, window, seq, ......);
}
2.5 WMS.addWindow
public int addWindow(Session session, IWindow client, int seq, ......) {
......
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
// 创建 WindowState,表示一个窗口
final WindowState win = new WindowState(this, session, client, token,
parentWindow, appOp[0], seq, attrs, viewVisibility,
session.mUid, session.mCanAddInternalSystemWindow);
......
// 这里的 outInputChannel 就是 APP 端传递过来的 InputChannel
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel); // 创建 InputChannel
}
......
boolean focusChanged = false;
if (win.canReceiveKeys()) {
// 新添加 window 能接收按下操作,则更新聚焦窗口。
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
}
......
if (focusChanged) {
displayContent.getInputMonitor().setInputFocusLw(
displayContent.mCurrentFocus, false /*updateInputWindows*/);
}
// 设置当前聚焦窗口
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
}
2.5.1 WindowState.openInputChannel
WindowState.java
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = getName(); // 窗口名称
// 创建一对 InputChannel
InputChannel[] inputChannels =
InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0]; // socket 服务端
mClientChannel = inputChannels[1]; // socket 客户端
// token 唯一标识了接收 input 事件的窗口
mInputWindowHandle.token = mClient.asBinder();
if (outInputChannel != null) {
// socket 客户端传递给 app 进程的 outInputChannel
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
......
}
// 利用 socket 服务端作为参数
mWmService.mInputManager.registerInputChannel(mInputChannel,
mClient.asBinder());
}
这个方法是重点,主要构造一对 InputChannel,分为 “server” 和 “client”,“server” 最后会被注册到 InputDispatcher 中,而 “client” 会返回给 APP 进程的 ViewRootImpl。
inputChannels 数组:
- inputChannels[0] 对应 InputChannel 服务端
- inputChannels[1] 对应 InputChannel 客户端
其中:
- 服务端 inputChannels[0] 保存到 WindowState 的 mInputChannel 中
- 客户端 inputChannels[1] 传递给 outInputChannel,最终传递给 ViewRootImpl 的 mInputChannel
2.5.2 WindowState初始化
WindowState(WindowManagerService service, Session s, ......) {
......
super(service);
mSession = s;
mClient = c;
mAppOp = appOp;
mToken = token;
mAppToken = mToken.asAppWindowToken();
......
// 创建 InputWindowHandle 对象
mInputWindowHandle = new InputWindowHandle(
mAppToken != null ? mAppToken.mInputApplicationHandle : null, c,
getDisplayId());
}
2.5.3 updateInputWindowsLw
InputMonitor.java
void updateInputWindowsLw(boolean force) {
if (!force && !mUpdateInputWindowsNeeded) {
return;
}
scheduleUpdateInputWindows();
}
private void scheduleUpdateInputWindows() {
if (mDisplayRemoved) {
return;
}
if (!mUpdateInputWindowsPending) {
mUpdateInputWindowsPending = true;
mHandler.post(mUpdateInputWindows);
}
}
private final Runnable mUpdateInputWindows = new Runnable() {
@Override
public void run() {
synchronized (mService.mGlobalLock) {
mUpdateInputWindowsPending = false;
mUpdateInputWindowsNeeded = false;
if (mDisplayRemoved) {
return;
}
final boolean inDrag =
mService.mDragDropController.dragDropActiveLocked();
final boolean inPositioning =
mService.mTaskPositioningController.isPositioningLocked();
if (inPositioning) {
if (DEBUG_TASK_POSITIONING) {
Log.d(TAG_WM, "Inserting window handle for repositioning");
}
mService.mTaskPositioningController.showInputSurface(
mInputTransaction, mDisplayId);
} else {
mService.mTaskPositioningController.hideInputSurface(
mInputTransaction, mDisplayId);
}
// Add all windows on the default display.
mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
}
}
};
最后通过 SurfaceComposerClient 更新到 SurfaceFlinger,然后最终更新到 InputDispatcher
2.6 InputChannel.openInputChannelPair
InputChannel.java
public static InputChannel[] openInputChannelPair(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
if (DEBUG) {
Slog.d(TAG, "Opening input channel pair '" + name + "'");
}
return nativeOpenInputChannelPair(name);
}
2.6.1 nativeOpenInputChannelPair
android_view_InputChannel.cpp
tatic jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
ScopedUtfChars nameChars(env, nameObj);
std::string name = nameChars.c_str();
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
// 创建一对 native 层 InputChannel
status_t result = InputChannel::openInputChannelPair(
name, serverChannel, clientChannel);
......
// 构造一个 java 层 InputChannel 类型数组
jobjectArray channelPair = env->NewObjectArray(2,
gInputChannelClassInfo.clazz, NULL);
if (env->ExceptionCheck()) {
return NULL;
}
// 将 native 层 InputChannel 转换为 java 层 InputChannel
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
std::make_unique<NativeInputChannel>(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
// 将 native 层 InputChannel 转换为 java 层 InputChannel
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
std::make_unique<NativeInputChannel>(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
// 将转换的 java 层 InputChannel 存到前面构造的数组中
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
这个函数很简单,主要是通过 openInputChannelPair 构造了一对 native 层的 InputChannel,然后再根据其创建 java 层的 InputChannel,最后返回给 java 层。
2.6.2 InputChannel::openInputChannelPair
status_t InputChannel::openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
// 关键核心:真正创建 socketpair 的地方
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.c_str(), errno);
outServerChannel.clear();
outClientChannel.clear();
return result;
}
int bufferSize = SOCKET_BUFFER_SIZE; // 32KB
// 设置 socket 发送和接收缓冲区大小为 bufferSize
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
std::string serverChannelName = name;
serverChannelName += " (server)";
// server 端 InputChannel 保存了 server 端 socket 的 fd
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
std::string clientChannelName = name;
clientChannelName += " (client)";
// client 端 InputChannel 保存了 client 端 socket 的 fd
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}
该方法主要功能:
- 创建 socket pair (非阻塞式的 socket )
- 设置两个 socket 的接收和发送的 buffer上限为 32KB
- 创建 client 和 server 的 Native 层 InputChannel 对象
创建 InputChannel 对象位于文件 InputTransport.cpp,如下:
InputChannel::InputChannel(const std::string& name, int fd) :
mName(name) {
setFd(fd);
}
void InputChannel::setFd(int fd) {
if (mFd > 0) {
::close(mFd);
}
mFd = fd;
if (mFd > 0) {
// 将 socket 设置成非阻塞方式
int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
}
}
另外,创建 NativeInputChannel 对象位于文件 android_view_InputChannel.cpp,如下:
NativeInputChannel::NativeInputChannel(const sp<InputChannel>& inputChannel) :
mInputChannel(inputChannel), mDisposeCallback(NULL) {
}
2.6.3 android_view_InputChannel_createInputChannel
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
std::unique_ptr<NativeInputChannel> nativeInputChannel) {
// 创建 Java 的 InputChannel
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
// 将 nativeInputChannel 保存到 Java 层的 InputChannel 的成员变量 mPtr
android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
nativeInputChannel.release());
}
return inputChannelObj;
}
static void android_view_InputChannel_setNativeInputChannel(
JNIEnv* env, jobject inputChannelObj,
NativeInputChannel* nativeInputChannel) {
env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast<jlong>(nativeInputChannel));
}
此处:
- gInputChannelClassInfo.clazz 是指 Java 层的 InputChannel 类
- gInputChannelClassInfo.ctor 是指 Java 层的 InputChannel 构造方法
- gInputChannelClassInfo.mPtr 是指 Java 层的 InputChannel 的成员变量 mPtr
2.7 InputChannel.transferTo
public void transferTo(InputChannel outParameter) {
if (outParameter == null) {
throw new IllegalArgumentException("outParameter must not be null");
}
nativeTransferTo(outParameter);
}
2.7.1 nativeTransferTo
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
jobject otherObj) {
if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Other object already has a native input channel.");
return; // 当 Java 层的 InputChannel.mPtr 不为空,则返回
}
// 将当前 inputChannels[1] 的 mPtr 赋值给 nativeInputChannel
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, obj);
// 将该 nativeInputChannel 保存到 outInputChannel 的参数
android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}
static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
jobject inputChannelObj) {
jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
return reinterpret_cast<NativeInputChannel*>(longPtr);
}
inputChannels[1].transferTo(outInputChannel) 主要功能:
- 如果 outInputChannel.mPtr 不为空(初始状态是空的),则直接返回;否则进入 step2
- 将 inputChannels[1].mPtr 的值赋给 outInputChannel.mPtr
- 清空 inputChannels[1].mPtr 值
也就是将 socket 客户端 inputChannels[1] 传递给 outInputChannel
2.8 IMS.registerInputChannel
public void registerInputChannel(InputChannel inputChannel, IBinder token) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
if (token == null) {
token = new Binder();
}
// 这个 inputChannel 保存了这个窗口的 token (IWindow,对应 app 端 W)
inputChannel.setToken(token);
nativeRegisterInputChannel(mPtr, inputChannel, Display.INVALID_DISPLAY);
}
inputChannel 是指 inputChannels[0],即 socket 服务端
2.8.1 nativeRegisterInputChannel
com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jint displayId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == nullptr) {
throwInputChannelNotInitialized(env);
return;
}
status_t status = im->registerInputChannel(env, inputChannel, displayId);
if (status) {
std::string message;
message +=
StringPrintf("Failed to register input channel. status=%d", status);
jniThrowRuntimeException(env, message.c_str());
return;
}
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
2.8.2 NativeInputManager::registerInputChannel
com_android_server_input_InputManagerService.cpp
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel, int32_t displayId) {
ATRACE_CALL();
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, displayId);
}
2.8.3 InputDispatcher::registerInputChannel
InputDispatcher.cpp
核心重点函数
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
int32_t displayId) {
{ // acquire lock
std::scoped_lock _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().c_str());
return BAD_VALUE;
}
// 核心关键点:创建 Connection,并把 inputChannel 作为参数
sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);// 以 socket 文件名为索引添加 connection
// 以 token 为索引添加 inputChannel
mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
// 将该 socket fd 添加到 Looper 监听
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();//connection改变, 则唤醒looper
return OK;
}
- 新创建 connection,并以 socket fd 为 key 保存到 mConnectionsByFd 成员变量中
- 以 inputChannel 的 token 为 key,保存 inputChannel 到 mInputChannelsByToken 中
- InputDispatcher 线程的 Looper 添加对 socket 服务端 fd 的监听功能,这样当该 socket 有消息时便会唤醒该线程
到此 InputChannel ”server端“ 的注册过程已经完成。
2.8.4 初始化Connection
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor) :
status(STATUS_NORMAL), inputChannel(inputChannel),
monitor(monitor),
inputPublisher(inputChannel), inputPublisherBlocked(false) {
}
其中 InputPublisher 初始化位于文件 InputTransport.cpp
InputPublisher:: InputPublisher(const sp<InputChannel>& channel) :
mChannel(channel) {
}
此处 inputChannel 是指前面 openInputChannelPair 创建的 socket 服务端,将其同时保存到 Connection.inputChannel 和 InputPublisher.mChannel 中。
2.8.5 Looper.addFd
system/core/libutils/Looper.cpp
int Looper::addFd(int fd, int ident, int events,
Looper_callbackFunc callback, void* data) {
// 此处的 callback 为 handleReceiveCallback
return addFd(fd, ident, events, callback ?
new SimpleLooperCallback(callback) : NULL, data);
}
int Looper::addFd(int fd, int ident, int events,
const sp<LooperCallback>& callback, void* data) {
{
AutoMutex _l(mLock);
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback; // 是指 SimpleLooperCallback
request.data = data;
if (mNextRequestSeq == -1) mNextRequestSeq = 0;
struct epoll_event eventItem;
request.initEventItem(&eventItem);
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
// 通过 epoll 监听 fd
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
......
mRequests.add(fd, request); // 该 fd 的 request 加入到 mRequests 队列
} else {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
......
mRequests.replaceValueAt(requestIndex, request);
}
}
return 1;
}
此处 Loop 便是 InputDispatcher 线程的 Looper,将 socket 服务端的 fd 采用 epoll 机制注册监听。
小节
ViewRootImpl 的 setView() 过程:
1.创建 socket pair,作为 InputChannel
- socket 服务端保存到 system_server 中的 WindowState 的 mInputChannel
- socket 客户端通过 binder 传回到远程进程的 UI 主线程 ViewRootImpl 的 mInputChannel
2.IMS.registerInputChannel() 注册 InputChannel,监听 socket 服务端
- Loop 便是 InputDispatcher 线程的 Looper
- 回调方法 handleReceiveCallback
三 WindowInputEventReceiver
ViewRootImpl.java
3.1 WindowInputEventReceiver初始化
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel,
Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event) {
List<InputEvent> processedEvents;
try {
processedEvents =
mInputCompatProcessor.processInputEventForCompatibility(event);
} finally {
......
}
if (processedEvents != null) {
if (processedEvents.isEmpty()) {
// InputEvent consumed by mInputCompatProcessor
finishInputEvent(event, true);
} else {
for (int i = 0; i < processedEvents.size(); i++) {
enqueueInputEvent(
processedEvents.get(i), this,
QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
}
}
} else {
enqueueInputEvent(event, this, 0, true);
}
}
@Override
public void onBatchedInputEventPending() {
if (mUnbufferedInputDispatch) {
super.onBatchedInputEventPending();
} else {
scheduleConsumeBatchedInput();
}
}
@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}
3.2 InputEventReceiver
public abstract class InputEventReceiver {
......
private long mReceiverPtr;
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null");
}
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue(); // UI 线程消息队列
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
......
}
3.3 nativeInit
android_view_InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel =
android_view_InputChannel_getInputChannel(env,
inputChannelObj);
......
// 获取 UI 主线程的消息队列
sp<MessageQueue> messageQueue =
android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
......
// 创建 NativeInputEventReceiver 对象
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
......
}
// retain a reference for the object
receiver->incStrong(gInputEventReceiverClassInfo.clazz);
return reinterpret_cast<jlong>(receiver.get());
}
3.4 NativeInputEventReceiver
class NativeInputEventReceiver : public LooperCallback {
InputConsumer mInputConsumer;
sp<MessageQueue> mMessageQueue;
int mFdEvents;
bool mBatchedInputEventPending;
......
};
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<InputChannel>& inputChannel,
const sp<MessageQueue>& messageQueue) :
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mInputConsumer(inputChannel), mMessageQueue(messageQueue),
mBatchedInputEventPending(false), mFdEvents(0) {
......
}
3.4.1 InputConsumer
InputTransport.cpp
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
mResampleTouch(isTouchResamplingEnabled()),
mChannel(channel), mMsgDeferred(false) {
}
3.5 NativeInputEventReceiver::initialize
android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
3.6 NativeInputEventReceiver::setFdEvents
android_view_InputEventReceiver.cpp
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
3.6.1 Looper.addFd
system/core/libutils/Looper.cpp
int Looper::addFd(int fd, int ident, int events,
const sp<LooperCallback>& callback, void* data) {
{
AutoMutex _l(mLock);
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback; // 是指 NativeInputEventReceiver
request.data = data;
if (mNextRequestSeq == -1) mNextRequestSeq = 0;
struct epoll_event eventItem;
request.initEventItem(&eventItem);
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
// 通过 epoll 监听 fd
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
......
mRequests.add(fd, request); // 该fd 的 request 加入到 mRequests 队列
} else {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
......
mRequests.replaceValueAt(requestIndex, request);
}
}
return 1;
}
此处的 Looper 便是 UI 主线程的 Looper,将 socket 客户端的 fd 添加到 UI 线程的 Looper 来监听,回调方法为 NativeInputEventReceiver。
四 总结
4.1 小结
- 首先当一个 APP 启动时,会将自己的 Window 添加到 WMS,并传递一个空 InputChannel 过去
- WMS 端,通过 openInputChannel 方法会创建一对 InputChannel,是在 native 层完成的,这对 InputChannel 被分为 “client” 端和 “server” 端,其内部又会创建一对 socket,和这对 InputChannel 一一对应
- “server” 端 InputChannel 会被注册到 InputDispatcher 中,注册的原理就是将 InputChannel 内部的 socket 添加到其 Looper 进行监听,注册过程中还会创建一个 Connection 对象,Connection 用来描述 InputDispatcher 与此次注册 InputChannel 的窗口的连接
- “client” 端 InputChannel 会被设置到 APP 进程中,接着通过 InputEventReceiver 注册到 APP UI 线程,同样是将 InputChannel 内部的 socket 添加到 UI 线程的 Looper 进行监听
- 对于 InputDispatcher 线程,在接收到 “client” 端 socket 的消息时会回调其 handleReceiveCallback 函数,对于 APP UI 线程,在接收到 “server” 端 socket 的消息时会回调 InputEventReceiver 对应的 native 层对象 NativeInputEventReceiver 的 handleEvent 函数
4.2 流程图
有了这些架构的实现,InputDispatcher 和 UI 主线程便可以进行跨进程通信与交互了。如有问题欢迎留言,谢谢!