Android之input app通信篇(一)服务端业务梳理
2022-01-27 本文已影响0人
锄禾豆
简介
只要带窗口的应用,都离不开ViewRootImpl的使用。关于触摸或按键事件的交互,关注ViewRootImpl的协调。
提示:
不管是Activity还是其他都可以从WindowManager.addView入手分析
分析
1.ViewRootImpl.setView
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
···
//初始化InputChannel
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
···
try {
···
//将InputChannel发送给wms
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
···
} finally {
···
}
···
//创建InputChannel的客户端
if (mInputChannel != null) {
···
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
···
//初始化InputChannel客户端回调数据涉及的业务处理对象
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
···
}
}
}
(1)创建InputChannel对象,并初始化InputChannel客户端的接收器WindowInputEventReceiver
(2)将InputChannel对象发送给wms
这里我们知道了客户端的创建及监听,接下来我们分析服务端的创建及监听
2.mWindowSession.addToDisplay
mWindowSession为Binder对象,实现类为Session
com.android.server.wm.Session
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
//mService为WMS
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
从Session转入WindowManagerService分析
com.android.server.wm.WindowManagerService
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
···
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
···
}
从WindowManagerService转入WindowState分析
com.android.server.wm.WindowState
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = makeInputChannelName();
//创建InputChannel数组
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
//获取InputChannel服务端
mInputChannel = inputChannels[0];
//获取InputChannel客户端
mClientChannel = inputChannels[1];
mInputWindowHandle.inputChannel = inputChannels[0];
if (outInputChannel != null) {
//把app的inputChannel切换成客户端
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
// If the window died visible, we setup a dummy input channel, so that taps
// can still detected by input monitor channel, and we can relaunch the app.
// Create dummy event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
//把服务端注册到InputManagerService中
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}
(1)WindowManagerService创建了用于InputChannel通信的数组
(2)将app的InputChannel设置成客户端
(3)将InputManagerService的设置成服务端
3.关注InputChannel服务端的数据来源
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
com.android.server.input.InputManagerService
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}
将InputChannel注册到native层
com_android_server_input_InputManagerService.cpp
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}
mInputManager->getDispatcher()即InputDispatcher,把InputChannel注册到InputDispatcher
InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
···
{ // acquire lock
AutoMutex _l(mLock);
···
//将inputChannel跟Connection绑定起来
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
//将connection加入容器mConnectionsByFd
mConnectionsByFd.add(fd, connection);
···
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
//唤醒InputDispatcher线程
mLooper->wake();
return OK;
}
(1)需要进一步分析Connection和InputChannel怎么结合
(2)容器mConnectionsByFd用来做什么
先看容器mConnectionsByFd的目的,我们知道触摸或者按键最终来到InputDispatcher.dispatchEventLocked
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
···
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
//从容器mConnectionsByFd获取connection,从而分发处理
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
···
}
}
}
(1)InputManagerService.registerInputChannel将服务端InputChannel传递到InputDispatcher
实现方式:将InputChannel包裹成Connection插入到容器mConnectionsByFd
(2)InputReader从EventHub读取的数据分发给InputDispatcher
(3)InputDispatcher分发数据的时候,从容器mConnectionsByFd获取InputChannel进行业务处理
4.分析Connection
InputDispatcher.cpp
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
monitor(monitor),
inputPublisher(inputChannel), inputPublisherBlocked(false) {
}
将Connection将inputChannel赋值给InputPublisher
InputTransport.cpp
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
mChannel(channel) {
}
status_t InputPublisher::publishKeyEvent(
uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
int32_t flags,
int32_t keyCode,
int32_t scanCode,
int32_t metaState,
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime) {
···
InputMessage msg;
···
return mChannel->sendMessage(&msg);
}
status_t InputPublisher::publishMotionEvent(
uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
int32_t actionButton,
int32_t flags,
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
float xOffset,
float yOffset,
float xPrecision,
float yPrecision,
nsecs_t downTime,
nsecs_t eventTime,
uint32_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
···
InputMessage msg;
···
return mChannel->sendMessage(&msg);
}
InputPublisher承载的InputChannel的目的就是调用mChannel->sendMessage(&msg)
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
···
return OK;
}
这就是真正意义上的通信源头
5.分析InputDispatcher.prepareDispatchCycleLocked
这里只做流程分析
prepareDispatchCycleLocked --> enqueueDispatchEntriesLocked --> startDispatchCycleLocked
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
···
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
···
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
···
// Publish the key event.
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId, keyEntry->source,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
break;
}
case EventEntry::TYPE_MOTION: {
···
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
break;
}
default:
ALOG_ASSERT(false);
return;
}
···
}
}
InputDispatcher分发后来到了InputPublisher
总结
InputChannel服务端的业务处理,可通过如下注册:
InputManagerService.registerInputChannel
即将服务端InputChannel传递到InputDispatcher,从而实现客户端和服务端的通信