这篇博客我们接上面一篇博客,回答上篇博客中,最后的connection对象是如何来的。
一、InputManagerService的registerInputChannel方法
我们先从InputManagerService的registerInputChannel方法分析:
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}
再来看看nativeRegisterInputChannel函数
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
......
sp<InputWindowHandle> inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
......
}
最后调用了NativeInputManager的registerInputChannel函数
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}
而这个函数,最终是调用了InputDispatcher的registerInputChannel函数:
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);//新建了一个connection
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);//把connection加入列表中
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);//加入epoll检测中
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
在这个函数中创建了一个Connection对象,并把这个对象加入列表中。如果有多个Connection,那么分发的消息是发给那个Connection呢,前面dispatchKeyLocked函数会调用函数findFocusedWindowTargetsLocked得到当前拥有焦点的窗口的InputChannel信息,然后再调用getConnectionIndexLocked函数得到mConnectionsByFd列表中和InputChannel关联的Connection对象的index。
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->inputChannel.get() == inputChannel.get()) {
return connectionIndex;
}
}
return -1;
}
有了这个index也就得到了conection对象了,现在我们知道了上篇博客最后startDispatchCycleLocked函数中使用的Connection对象其实是和当前有焦点的窗口关联的对象。
下面我们继续分析它的inputPublisher成员的publishKeyEvent函数:
status_t InputPublisher::publishKeyEvent(
......
InputMessage msg;
msg.header.type = InputMessage::TYPE_KEY;
......
return mChannel->sendMessage(&msg);
}
publishKeyEvent函数调用了mChannel的sendMessage函数,这个mChannel是创建Connection对象时的参数InputChannel。
这边的InputChannel是前面nativeRegisterInputChannel中的android_view_InputChannel_getInputChannel函数中获取。
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
throwInputChannelNotInitialized(env);
return;
}
sp<InputWindowHandle> inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
if (status) {
String8 message;
message.appendFormat("Failed to register input channel. status=%d", status);
jniThrowRuntimeException(env, message.string());
return;
}
if (! monitor) {
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
}
我们再来看下android_view_InputChannel_getInputChannel方法
sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
}
static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
jobject inputChannelObj) {
jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
return reinterpret_cast<NativeInputChannel*>(longPtr);
}
最后NativeInputChannel对象的指针保存在java层的InputChannel对象的mPtr中。
于是我们知道最后InputDispatcher发送按键消息到应用进程的对象,是java层的InputChannel对象对应的native层的NativeInputChannel对象的sendMessage函数发送消息。
二、InputChannel的从创建
接下来我们再来看看java层的InputChannel是什么时候创建的呢?
ViewRootImpl的setView中有这段代码:
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
setView方法中如果Window的属性能接受输入,而且还没有创建InputChannel,则会新创建一个InputChannel对象。这个对象会通过mWindowSession的addToDisplay方法传递到WindowManagerService中,最后再会调用WMS的addWindow方法,addWindow有下面这段代码:
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
阿灾addWIndow方法中先调用了InputChannel的openInputChannelPair来返回一个InputChannel对象的数组,然后将inputChannel[0]设置到win中去。接着inputChannel[1]转换成和客户端传递过来的outInputChannel对象,最后调用了InputManagerService中的registerInputChannel方法。现在整个脉络都清晰了。
先来看下openInputChannelPair函数
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);
}
调用了nativeOpenInputChannelPair函数:
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars);
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);//创建socketpair
if (result) {
String8 message;
message.appendFormat("Could not open input channel pair. status=%d", result);
jniThrowRuntimeException(env, message.string());
return NULL;
}
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
if (env->ExceptionCheck()) {
return NULL;
}
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
上面函数现在InputChannel::openInputChannelPair创建了socketpair,我们来看下:
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {//创建socketpair
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.string(), errno);
outServerChannel.clear();
outClientChannel.clear();
return result;
}
int bufferSize = SOCKET_BUFFER_SIZE;
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));
String8 serverChannelName = name;
serverChannelName.append(" (server)");
outServerChannel = new InputChannel(serverChannelName, sockets[0]);//返回值
String8 clientChannelName = name;
clientChannelName.append(" (client)");
outClientChannel = new InputChannel(clientChannelName, sockets[1]);//返回值
return OK;
}
然后又调用了android_view_InputChannel_createInputChannel(env, new NativeInputChannel(serverChannel));
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
NativeInputChannel* nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);//创建java层的InputChannel对象
if (inputChannelObj) {
android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
}
return inputChannelObj;
}
android_view_InputChannel_setNativeInputChannel函数
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
NativeInputChannel* nativeInputChannel) {
env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast<jlong>(nativeInputChannel));
}
android_view_InputChannel_setNativeInputChannel函数包native层的NativeInputChannel对象指针保存到了java层的InputChannel对象的mPtr成员变量中。
前面我们还看到WMS的addWindow方法会调用InputChannel[1]的transferTo方法:
public void transferTo(InputChannel outParameter) {
if (outParameter == null) {
throw new IllegalArgumentException("outParameter must not be null");
}
nativeTransferTo(outParameter);
}
android_view_InputChannel_nativeTransferTo函数的功能就是将调用对象的mPtr的值放到参数对象的mPtr中,并将调用对象的mPtr设置为NULL。
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;
}
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, obj);
android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}
这样最后WMS调用addWindow后,outChannel中的值就是sockpair的客户端。
三、应用进程接受按键消息
前面最后会调用InputChannel的sendMessage函数,最后实际是调用了sockpair的一个fd的send函数,这样另外一个fd也就是应用端的进程会有响应。
前面ViewRootImpl的setView函数调用了addToDisplay得到InputChannel对象后,创建了WindowInputEventReceiver对象。
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
我们先来看下InputEventReceiver的构造函数:
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();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
nativeInit中新建了NativeInputEventReceiver对象,然后调用了initialize函数:
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
jniThrowRuntimeException(env, "InputChannel is not initialized.");
return 0;
}
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
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());
}
NativeInputEventReceiver::initialize函数
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
setFdEvents函数又调用的addFd函数,这个之前分析过就不分析了,是将这个fd加入到线程的epoll中,并且把this作为回调。
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);
}
}
}
因此handleEvent是作为回调函数被epoll回调
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
// This error typically occurs when the publisher has closed the input channel
// as part of removing a window or finishing an IME session, in which case
// the consumer will soon be disposed as well.
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. "
"events=0x%x", getInputChannelName(), events);
}
return 0; // remove the callback
}
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;
}
然后这个函数中调用了consumeEvents函数,有如下一段代码:
if (inputEventObj) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
}
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching input event.");
skipCallbacks = true;
}
这函数中又调用了java层的WindowInputEventReceiver的dispatchInputEvent函数,因为WindowInputEventReceiver没有dispatchInputEvent函数就调用了父类的dispatchInputEvent函数
@SuppressWarnings("unused")
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
最后调用了ViewRootImpl中的WindowInputEventReceiver 的onInputEvent函数:
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();
}
}
这样到应用进程的流程分析结束了,下面就是将上层应用进程是如何处理这按键消息的,这个要后续分析了。