1.addWindow函数(InputChannel创建注册):
通过上一篇的分析,我们发现InputDispatcherThread调用InputChannel的sendMessage函数发送了一条消息,但是我们不知道谁在接收这条输入事件消息。在这里提前告诉大家是APP在接收这些消息。这篇我们将讲解消息到底是怎么发送到app的。
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
//最终通过socketpair发送出去,根据之前带代码可以知道是通过wms发给app了。
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
}
有发送就一定有接收以及初始化函数这样很自然就会关注到:InputChannel::openInputChannelPair函数.通过搜索代码关键字可以得到如下的函数关系图:
app都是带Activity的,调用startActivity(Intent), 会通过Binder IPC机制, 最终调用到ActivityThread中的handleLaunchActivity方法开始分析,下图的流程显示了启动过程中的函数调用关系:
根据上面的的分析可以从 addWindow()函数入手分析调用过程。
根据这个时序图可以看出WindowManagerService.java中 给addWindow函数传入了outInputChannel变量对象。使用InputChannel.openInputChannelPair(name);在native层创建的 InputChannel[] inputChannels会调用mInputManager.registerInputChannel函数 -> com_android_server_input_InputManagerService.cpp 中的static void nativeRegisterInputChannel -> InputDispatcher::registerInputChannel注册到native c++层。InputDispatcher要能够发送事件数据,必须的要让其知道对应的window的InputChannel,这个通过注册实现的。同时调用inputChannels[1].transferTo(outInputChannel);把native其中的一个inputChannels[1]转换到java层的outInputChannel,包含socketpair文件句柄。(outInputChannel是在app启动过程中java层NEW出来的后面会分析)
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
toString(monitor));
#endif
{ // acquire lock
AutoMutex _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}
//这个将inputWindowHandle对应的inputChannel封装为Connection
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
//这个就是unix socket文件句柄
int fd = inputChannel->getFd();
//将connection保存到映射表中
mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
上面这段代码中的fd网络文件句柄和connection是通信发送事件的关键;上一篇我们已经分析分发过程了:其中部分代码:
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
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;
}
可以看到操作的都是connection对象,可以总结一下:上一篇分析的InputChannel::sendMessage方式输入事件到目前为止是发送到了WindowManagerService.java中使用InputChannel.openInputChannelPair(name);创建的 InputChannel[] inputChannels.其中的inputChannels[1]转换到java层的outInputChannel。
2. app启动过程如何触发addWindow函数执行的:
///
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.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
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;
wm.addView(decor, l);//decor是view类,wm是个ViewManager接口
}
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
}
public interface ViewManager//接口
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
public interface WindowManager extends ViewManager {
}
WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Display mDisplay;
private final Window mParentWindow;
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
}
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
root.setView(view, wparams, panelParentView);//root是ViewRootImpl类
}
ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
final IWindowSession mWindowSession;
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();//第一次需要创建InputChannel导致native层创建socketpair
}
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
}
}
//通过AIDL跨进程通信机制最终调用到WindowManagerService的addWindow();
//IWindowSession.aidl
interface IWindowSession {
int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets,
out InputChannel outInputChannel);
}
// ./common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowSession.java
@Override public int addToDisplay(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId, android.graphics.Rect outContentInsets, android.view.InputChannel outInputChannel) throws android.os.RemoteException
{
mRemote.transact(Stub.TRANSACTION_addToDisplay, _data, _reply, 0);
}
// framework/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,
InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outInputChannel);
}
}
// WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, InputChannel outInputChannel) {
}
通过上的关键代码可以看到使用了接口,继承,AIDL跨进程通信机制,handleResumeActivity函数最终是触发了WindowManagerService.java的 public int addWindow函数的调用。
3.APP启动创建的 InputChannel监听器初始化:
ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
final IWindowSession mWindowSession;
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
if (mInputChannel != null) {//mInputChannel 指向native层创建的inputChannels[1]
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
//为InputChannel注册监听器
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
@Override
public void onBatchedInputEventPending() {
if (mUnbufferedInputDispatch) {
super.onBatchedInputEventPending();
} else {
scheduleConsumeBatchedInput();
}
}
@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}
WindowInputEventReceiver mInputEventReceiver;
InputEventReceiver.java
public abstract class InputEventReceiver {
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
}
android_view_InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
//通过inputChannelObj 获取native层的InputChannel
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
//获取java层InputEventReceiver对象的native层的消息队列
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
//使用inputChannel和messageQueue创建native对应的InputEventReceiver对象
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize input event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}
receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jlong>(receiver.get());
}
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
//用looper监听inputChannel对应的socketpair文件句柄
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
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) {
{ // acquire lock
AutoMutex _l(mLock);
Request request;
request.fd = fd;
request.ident = ident;
//这个很重要,当被监听的文件发生变化时就会调用该callback函数
request.callback = callback;
request.data = data;
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
mRequests.add(fd, request);
}
} // release lock
return 1;
}
通过上面的关键代码分析,这段代码完成了epoll对 “WindowManagerService.java中使用InputChannel.openInputChannelPair(name);创建的 InputChannel[] inputChannels.其中的inputChannels[1]转换到java层的outInputChannel"完成了监听初始化动作。下面看看是如何监听有可读 数据接收的。
4.APP端的InputChannel中的事件接收
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
while (mResponseIndex < mResponses.size()) {
const Response& response = mResponses.itemAt(mResponseIndex++);
int ident = response.request.ident;
if (ident >= 0) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
if (outFd != NULL) *outFd = fd;
if (outEvents != NULL) *outEvents = events;
if (outData != NULL) *outData = data;
return ident;
}
}
result = pollInner(timeoutMillis);
}
}
int Looper::pollInner(int timeoutMillis) {
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
//睡眠等待消息
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
awoken();
}
} else {
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex >= 0) {
int events = 0;
if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
//将输入事件push到队列上
pushResponse(events, mRequests.valueAt(requestIndex));
}
}
}
Done: ;
//处理response事件
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.ident == ALOOPER_POLL_CALLBACK) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
// 下面的callback就是 NativeInputEventRecieverd
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
removeFd(fd);
}
response.request.callback.clear();
result = ALOOPER_POLL_CALLBACK;
}
}
return result;
}
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
//处理消费事件
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
return 1;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
//从buffer取出事件
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
if (!skipCallbacks) {
jobject inputEventObj;
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
//转换为java层的InputEvent
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<keyevent*>(inputEvent));
break;
}
if (inputEventObj) {
//会调用到java层的函数InputEventReceiver->dispatchInputEvent
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq,
inputEventObj);
}
}
}
}
再来看看InputEventReceiver.java文件中的:
// Called from native code.
@SuppressWarnings("unused")
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);//处理event
}
public void onInputEvent(InputEvent event) {
finishInputEvent(event, false);
}
public final void finishInputEvent(InputEvent event, boolean handled) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to finish an input event but the input event "
+ "receiver has already been disposed.");
} else {
int index = mSeqMap.indexOfKey(event.getSequenceNumber());
if (index < 0) {
Log.w(TAG, "Attempted to finish an input event that is not in progress.");
} else {
int seq = mSeqMap.valueAt(index);
mSeqMap.removeAt(index);
nativeFinishInputEvent(mReceiverPtr, seq, handled);
}
}
event.recycleIfNeededAfterDispatch();
}
分析到这里,输入事件已经传递到java层了。具体事件怎么分发流动还要看当前app是如何写的,以及是什么按键。输入事件并不是全部被window的view处理了,比如返回键,如果此时系统输入法是显示的处于最上面,back键首先会去关闭输入法,而window的view是接收不到这个键。一般来说对应Global/system按键是systemserver系统进程处理的并且处理完不会发送到app。对于user按键则最终会调用ViewGroup的:
public final boolean dispatch(Callback receiver, DispatcherState state,
Object target) {
switch (mAction) {
case ACTION_DOWN: {
mFlags &= ~FLAG_START_TRACKING;
boolean res = receiver.onKeyDown(mKeyCode, this);
return res;
}
}
return false;
}
对于按键是系统处理还是app处理可以参考这篇文章:https://blog.csdn.net/qianhaifeng2012/article/details/51737370