以TouchEvent为主,看一下View和ViewGroup内部是如何处理Input Events的;
首先来看事件的产生来源:
事件的来源可以分为“软件”,“硬件”两种;
主要的事件包含有:
按键事件(KeyEvent) :即物理按键按下产生的事件,相关的常用物理按键一般有HOME,BACK等
触摸事件(TouchEvent):
鼠标事件(MouseEvent)、轨迹球事件(TrackBallEvent)(这两个已经不常见);
针对所有事件的共性抽象出了InputEvent接口;其有两个子类:KeyEvent,MotionEvent;
1>源信息采集
对“硬件源”产生的原始信息进行收集;它需要Linux内核驱动的支持,Android系统通过/dev/input下的节点来访问当前发生的事件。
2>前期处理
对收集到信息进行筛选以及格式转化
3>WMS分配
WMS是窗口的Manager,同时也是InputEvent的派发者。
4>应用程序处理
WMS会先把事件传递到对应ViewRootImpl,ViewRootImpl分发事件,传递给相应的DecorView,DecorView在调用Activity中的Window.Callback将事件传递给Activity;然后Activity在通过dispatchTouchEvent分发事件,下面就来到熟悉的View事件分发机制;具体见《View机制深入学习(四)View的事件分发机制》
InputManagerService同样也是有SystemServer进程启动,这个在Android启动过程——init.rc,Zygote,SystemServer中已经提到过,
系统启动后创建init进程(pid=1),init进程创建出Zygote进程,然后Zygote进程孵化出SystemServer进程,在SystemServer进程中创建IMS:
/** @path: \frameworks\base\services\java\com\android\server\SystemServer.java */
class ServerThread extends Thread {
@Override
public void run() {
// 可以看到IMS和WMS是紧密相关的
......
// @value InputManagerService inputManager
inputManager = new InputManagerService(context, wmHandler);
Slog.i(TAG, "Window Manager");
// @value WindowManagerService wm
wm = WindowManagerService.main(context, power, display, inputManager,
uiHandler, wmHandler,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
ActivityManagerService.self().setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
.....
}
}
/** \frameworks\base\services\core\java\com\android\server\input\InputManagerService.java **/
public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
// 指向native端IMS类对象的地址
private final long mPtr;
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
// 创建native IMS对象
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
}
可以看到Java层的IMS实际上只是对Native层的InputManager的一层包装;其创建主要是native层进行创建,并把native层的InputManager地址赋值给InputManagerService的mPtr变量;
而且注意nativeInit中传入了Looper中的MessageQueue变量;
/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface
static jlong nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
// 创建一个Message Queue
sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
// 可以看到NativeInputManager中包含有一个Looper,用以进行事件分派
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
// 返回创建的IMS实例对象的地址(强制转化为long类型)
return reinterpret_cast(im);
}
可以看到首先通过android_os_MessageQueue_getMessageQueue函数获取到本地端的MessageQueue,这个在Handler机制中的本地解析《Handler机制深入解析》中已经提到,该NativeMessageQueue对象在java层创建Looper时创建实例,然后将地址指针赋值为Looper对应的MessageQueue中的ptr变量中,这里根据指针来获取该NativeMessageQueue对象;
根据NativeMessageQueue对象获取其中对应的Looper(native),用以创建NativeInputManger;来看NativeInputManager的构造函数:
/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
// 全局引用
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
}
// 创建EventHUb
sp eventHub = new EventHub();
// 创建InputManager实例
mInputManager = new InputManager(eventHub, this, this);
}
NativeInputManager中保存了Looper(native)实例;并且创建了EventHub,以及InputManager两个重要的对象;
EventHub从名字就可以看出,它是用来收集以及存储外部的输入事件的;
而InputManager则是对Event事件进行处理分发;
先来看EventHub:
/*\frameworks\native\services\inputflinger\EventHub*/
static const char *DEVICE_PATH = "/dev/input";
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
// 创建epoll对象
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
// 采用inotify机制监听文件或目录的移动、读取、写入或删除等事件
// 创建一个inotify对象
mINotifyFd = inotify_init();
// 把监控项添加到mINotifyFd对象的监控列表中
// 这里监听的文件路径为"/dev/input"
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
// 把inotify对象mINotifyFd添加到epoll对象的兴趣列表中,此处采用inotify与epoll机制结合起来检查文件
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
// 创建pipe
result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
// 设置为非阻塞
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
// 添加到epoll的兴趣列表中
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
int major, minor;
getLinuxRelease(&major, &minor);
// EPOLLWAKEUP was introduced in kernel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
在前面进行了一系列的变量的初始化;
然后epoll_create创建了一个epoll对象,可以看到和Handler中一样,IMS中也用到了epoll机制进行监听;
而后可以看到IMS是INotify机制和Epoll机制同时使用的:inotify_init创建iNotify对象,inotify_add_watch则将”/dev/input”路径添加到监听列表中;当”/dev/input”中文件发生变化,将会产生响应;
了解INotifiy文件系统监听机制:
《inotify – Linux 2.6 内核中的文件系统变化通知机制》
《Inotify: 高效、实时的Linux文件系统事件监控框架》
然后将iNotify对象添加到Epoll的兴趣列表中,进行监听;
然后同Handler机制,创建一个Pipe,然后设置为非阻塞形式,然后添加到epoll的兴趣列表中;下面就注意在何时调用epoll_wait来开启监听即可;这里仅进行了初始化;
/** \frameworks\native\services\inputflinger\InputManager.cpp **/
class InputManagerInterface : public virtual RefBase {
private:
sp mReader;
sp mReaderThread;
sp mDispatcher;
sp mDispatcherThread;
// 构造函数
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
// 创建InputDispatcher
mDispatcher = new InputDispatcher(dispatcherPolicy);
// 创建InputReader
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
/*** 进行初始化 **/
void InputManager::initialize() {
// 创建两个Thread的实例
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
};
InputManager中传入了前面创建的EventHub对象;然后初始化了两个中重要的类,InputDispatcher,以及InputReader;
显然从名字可以看出 InputReader用来读取EventHub中的事件,然后通过InputDiapatcher进行分发(InputReader中持有InputDisptcher的引用);
先看InputDispatcher:
继承关系:
class InputDispatcher : public InputDispatcherInterface
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface
构造函数:
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
InputDispatcher::InputDispatcher(const sp& policy) :
mPolicy(policy),
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
// 可以看到这里创建了一个Looper
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
}
在构造函数中创建了一个Looper(native),注意这里是新创建了一个Looper对象,和ThreadLocal中该线程中的Looper是没有关系的;
再来看InputReader
class InputReader : public InputReaderInterface
class InputReaderInterface : public virtual RefBase
构造函数:
/** \frameworks\native\services\inputflinger\InputReader.cpp **/
InputReader::InputReader(const sp& eventHub, // 前面提到的创建的EventHub
const sp& policy,
const sp& listener) : // 即传入进来的InputDispatcher
mContext(this), mEventHub(eventHub), mPolicy(policy), // 一系列初始化
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
// 创建一个QueuedInputListener对象,赋值给mQueuedListener
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
InputReader中包含了前面创建的EventHub,以及用以分发事件的InputDispatcher;在InputReader内部,将其封装成了QueuedInputListener类;
继续InputManager构造函数中内容,initialize进行初始化:
/*** 进行初始化 **/
void InputManager::initialize() {
// 创建两个Thread的实例
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
新创建了两个对象,这两个类都是继承Thread的,即对应地使用InputReader,以及InputDispatcher为参数创建了两个线程;
分别来看:
2.1.1)InputReaderThread类:
/** \frameworks\native\services\inputflinger\InputReader.h **/
/** 无限循环从event hub中读取event,然后读取processes他们 */
class InputReaderThread : public Thread {
public:
InputReaderThread(const sp& reader);
virtual ~InputReaderThread();
private:
sp mReader;
/** 继承Thread的子类必须实现该函数,因为这个其实是Thread的真正执行函数 **/
// Derived class must implement threadLoop(). The thread starts its life
// here. There are two ways of using the Thread object:
// 1) loop: if threadLoop() returns true, it will be called again if
// requestExit() wasn't called.
// 2) once: if threadLoop() returns false, the thread will exit upon return.
virtual bool threadLoop();
};
可以看到InputReaderThread是一个Thread类,它的线程函数入口为threadLoop;
2.1.2)InputReaderThread类构造函数:
/** \frameworks\native\services\inputflinger\InputReader.cpp **/
InputReaderThread::InputReaderThread(const sp& reader) :
Thread(/*canCallJava*/true), mReader(reader) {
// 这里初始化重要变量sp mReader
}
bool InputReaderThread::threadLoop() {
// 调用mReader中的loopOnce函数,可以看出InputReaderInterface是该类的核心
mReader->loopOnce();
return true;
}
InputReaderThread的核心逻辑为调用InputReader的loopOnce函数;暂且停在这里,因为Thread只是创建,并未运行,等分析到具体运行代码时再作分析;
/* \frameworks\native\services\inputflinger\InputDispatcher.h */
class InputDispatcherThread : public Thread {
public:
explicit InputDispatcherThread(const sp& dispatcher);
~InputDispatcherThread();
private:
virtual boolthreadLoop();
sp mDispatcher;
};
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
该类同样是一个Thread,其主要运行逻辑即调用InputDispatcher中的dispatchOnce函数;
回到InputManagerService在SystemServer进程中的创建过程知道,接下来创建WindowManagerService,然后将InputManagerService实例传递给WMS,然后调用InputManagerService.start开始工作。
/** \frameworks\base\services\core\java\com\android\server\input\InputManagerService.java **/
public void start() {
......
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
......
}
private static native void nativeStart(long ptr);
可以看到start仅是对nativeStart本地方法进行封装,继续通过JNI来调用本地端的start函数;注意这里创建了WatchDog看门狗线程,并且把InputManagerService实例添加到WatchDog的监听;系统创建看门狗线程,每隔一段时间向管道中写入数据唤醒InputReader线程(后面会提到)去读取事件,看门狗WatchDog实际上也是一个线程,只不过会定时发送消息给InputReader线程读取输入事件。
/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
// ptr为创建的IMS实例的地址,这里将其强制转化成为NativeInputManager类
NativeInputManager* im = reinterpret_cast(ptr);
// 这里进一步调用InputManager的star方法
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
// @value sp mInputManager;
inline sp getInputManager() const { return mInputManager; }
可以看到这里进一步调用了InputManager的start方法;IMS在Native层的主要实现实体其实是InputManager。
/** \frameworks\native\services\inputflinger\InputManager.cpp **/
class InputManagerInterface : public virtual RefBase {
private:
sp mReader;
sp mReaderThread;
sp mDispatcher;
sp mDispatcherThread;
// start函数
status_t InputManager::start() {
// 可以看到这里会开启两个线程mDispatcherThread,与mReaderThread
// 分别对应InputReaderThread,InputDispatcherThread
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
......
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
mDispatcherThread->requestExit();
return result;
}
return OK;
}
};
回到InputManager中来,来看start函数中所做的工作,在start中调用两个thread的run函数正是开启线程;由Thread的线程入口为threadLoop;前面已经提到了这两个Thread的入口函数,这里来看其中的具体工作逻辑;
InputDispatcherThread#threadLoop:
由前面知InputDispatcherThread中主要通过调用InputDispatcher的dispathOnce来实现的;
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// 在没有等待的commands事运行一个dispatch loop,这个loop之后可能enqueue commands
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
// 如果有等待的commands的话,就运行所有的commands
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
初始状态下是没有事件的,来到mLooper->pollOnce,了解Handler机制的native层知道,在pollOnce中调用epoll_wait对前面设置的兴趣事件进行监听,然后InputDispatchThread进入休眠等待唤醒;可想而知下面策略是InputReaderThread来对其进行唤醒;
InputReaderThread#threadLoop:
InputReaderThread中的主要逻辑是调用InputReader中的loopOnce函数
/** \frameworks\native\services\inputflinger\InputReader.h **/
class InputReaderInterface : public virtual RefBase
class InputReader : public InputReaderInterface
/** \frameworks\native\services\inputflinger\InputReader.cpp **/
// loopOnce即事件处理函数
void InputReader::loopOnce() {
......
// 其实是通过mEventHub来获取Events的
// @value sp mEventHub;
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
......
// @value sp mQueuedListener;
mQueuedListener->flush();
}
可以看到这里通过EventHub的getEvents来获取/dev/input中的Event事件,然后用到前面提到的封装了InputDispatcher的QueueListener来分发事件;
EventHub获取Events的具体流程:Android按键事件传递流程(一)
主要工作流程是注册这些监听的devices,然后调用epoll_wait使得InputReaderThread等待唤醒;
获取Events的过于复杂,直接跳过,来看事件的传递;当获取到Event之后,调用mQueuedListener的flush来传递消息;
前面提到使用EventHub的getEvents来获取Events之后,通过mQueuedListener的flush开始消息的分发;
/** \frameworks\native\services\inputflinger\InputListener.h **/
class QueuedInputListener : public InputListenerInterface {
protected:
virtual ~QueuedInputListener();
public:
QueuedInputListener(const sp& innerListener);
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
virtual void notifyKey(const NotifyKeyArgs* args);
virtual void notifyMotion(const NotifyMotionArgs* args);
virtual void notifySwitch(const NotifySwitchArgs* args);
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
void flush();
private:
sp mInnerListener;// mInnerListner即是InputDispatcher
Vector mArgsQueue; // 后面flush函数中将会用到
};
在InputReader的构造函数中,传递进来的mInnerListener即为InputDispatcher;
/** \frameworks\native\services\inputflinger\InputListener.cpp **/
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
// 调用NotifyArgs。notify函数
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
// 这里仅是一个封装函数,最终调用InputListenerInterface的notifyKey函数
void NotifyKeyArgs::notify(const sp& listener) const {
listener->notifyKey(this);
}
前面最终调用InputListenerInterface(即InputDispatcher)的notifyKey回调函数;
总结前面的流程即InputReaderThread通过EventHub不断读取获取event信息,获得事件后,调用InputDispather的notifyKey函数来通知InputDispathcer进行处理。注意这里调用InputDispatcher的notifyKey函数依然是在InputReaderThread线程中进行的,此时InputDispathcerThread仍然是epoll_wait阻塞状态中;
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
if (!validateKeyEvent(args->action)) { // 判断event是否合法
return;
}
......
// 初始化KeyEvent
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action,
flags, keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
// 唤醒InputDispatcherThread线程
if (needWake) {
mLooper->wake();
}
}
该部分对传递过来的按键事件进行检查、验证,之后处理特殊按键,将原始按键信息封装成KeyEntry,再调用enqueueInboundEventLocked函数把KeyEntry添加到InboundQueue队列中,最后调用Looper对象的wake往管道中写入字符唤醒InputDispatcherThread线程(类似于Handler机制中的唤醒);
先来看enqueueInboundEventLocked添加事件到InboundQueue队列中:
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
// @value Queue mInboundQueue;
bool needWake = mInboundQueue.isEmpty();
// 将entry入队列
mInboundQueue.enqueueAtTail(entry);
switch (entry->type) { // 如前面所述,InputEvent分为KeyEvent和MotionEvent进行分别处理
case EventEntry::TYPE_KEY: ......
case EventEntry::TYPE_MOTION: .....
}
return needWake;
}
将entry添加到InboundQueue队列尾部;然后判断是否需要唤醒,即needWake是否为true;当mInboundQueue不为空,则明显InputDispathcerThread仍处于运行状态来分发事件,因而不用进行唤醒;而当mInboundQueue为空时,测试InputDispatcherThread进行休眠状态,使用wake对其来唤醒;
InputDispatcherThread之前调用Looper的poolOnce函数阻塞休眠,这里调用wake将其唤醒;因为InputDispatcherThread的threadLoop返回值为true,表示该Thread是循环执行的,故继续调用其dispatchOnce函数;
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// 在没有等待的commands事运行一个dispatch loop,这个loop之后可能enqueue commands
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
// 如果有等待的commands的话,就运行所有的commands
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
来到dispatchOnceInnerLocked:
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) { // 当前mInboundQueue已经存在元素
......
} else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
......
}
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != NULL);
.......
// 根据mPendingEvent的Type的不同分别进行处理
switch (mPendingEvent->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
......
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
break;
}
// KeyEvent采用dispatchKeyLocked进行处理
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast(mPendingEvent);
......
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
// MotionEvent采用dispatchMotionLocked进行处理
case EventEntry::TYPE_MOTION: {
......
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
default:
ALOG_ASSERT(false);
break;
}
if (done) {
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
可以看到是事件处理机制中常用的处理模式,类似于Handler机制,这里先dequeueAtHead使得InBoundQueue事件队列中的事件出队列(FIFO);然后根据事件的类似进行不同的处理;如TYPE_KEY类型事件采用dispatchKeyLocked;TYPE_MOTION类型事件采用dispatchMotionLocked处理
下面以KeyEvent为例进行分析,下面忽略对event的具体处理细节,具体来看事件是如何传递的;
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
......
/** 确定事件的接收方(Target) **/
Vector inputTargets;
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
setInjectionResultLocked(entry, injectionResult);
addMonitoringTargetsLocked(inputTargets);
/** 将消息dispatch给Target **/
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
前面对event的处理细节忽略,重点来看系统是如何查找event对应的接收方(Target)的,这里的InputTarget指定一个输入事件如何被分发到一个特定窗口。该结构体包含了很多特征变量:x,y坐标,输入事件通道InputChannel等;
这里通过findFocusedWindowTargetsLocked来确定InputTarget的,然后调用dispatchEventLocked来将Event分发给具体的Target;
接下来分析函数findFocusedWindowTargetsLocked;
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime) {
int32_t injectionResult;
String8 reason;
// mFocusedWindowHandle表示当前焦点窗口的句柄
// @value sp mFocusedWindowHandle;
/** 当获得焦点的窗口为null时,会丢弃这一事件 **/
if (mFocusedWindowHandle == NULL) {
if (mFocusedApplicationHandle != NULL) {
// 如果没有焦点窗口,但焦点窗口所在的应用程序进程存在,说明该应程序还在启动过程中,故等待nextWakeupTime后再重试
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle, NULL, nextWakeupTime,
"Waiting because no window has focus but there is a "
"focused application that may eventually add a window "
"when it finishes starting up.");
goto Unresponsive;
}
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
/** 如果执行到这里说明当前有焦点窗口 **/
// 先判断权限
if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
goto Failed;
}
// 如果当前焦点窗口正在处理上一个事件,采取和最上面一样的作法,等待一段时间后重试
reason = checkWindowReadyForMoreInputLocked(currentTime,
mFocusedWindowHandle, entry, "focused");
if (!reason.isEmpty()) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
goto Unresponsive;
}
// 成功找到匹配的窗口,通过addWindowTargetLocked添加到inputTargets变量中
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
addWindowTargetLocked(mFocusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
inputTargets);
Failed:
Unresponsive:
nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
updateDispatchStatisticsLocked(currentTime, entry,
injectionResult, timeSpentWaitingForApplication);
return injectionResult;
}
上面查找焦点窗口的逻辑很清晰, 当mFocusedWindowHandle为null时,如果mFocusedApplicationHandle不为null,表示当前没有焦点窗口,但焦点窗口所在的应用程序进程存在,说明该应程序还在启动过程中,故等待nextWakeupTime后再重试;如果mFocusedApplicationHandle为null,则丢弃该事件,因为没有能够接收该事件的窗口;
如果mFocusedWindowHandle不为null,先判断当前窗口是否locked,如果是表示正在处理其他输入事件,这时采用和上面相同的策略,等待一段时间后,然后重试。
当找到匹配的目标窗口之后,赋值给InputTarget;先来看InputTarget的定义:
/** \frameworks\native\services\inputflinger\InputDispatcher.h **/
/*
* An input target specifies how an input event is to be dispatched to a particular window
* including the window's input channel, control flags, a timeout, and an X / Y offset to
* be added to input event coordinates to compensate for the absolute position of the
* window area.
*/
struct InputTarget {
enum { // 该枚举类列举个关于目标窗口的各种属性值描述
/* This flag indicates that the event is being delivered to a foreground application. */
FLAG_FOREGROUND = 1 << 0, // 说明目标窗口是前台应用
......
}
/** InputDispatcher与WMS建立关联通信的地方 */
sp inputChannel;
};
这里引出了重要的类InputChannel,InputDispatcher与WMS之间的通信,正是通过InputChannel来实现的。
继续前面的dispatchKeyLocked函数,接下来会调用dispatchEventLocked来传递消息;
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector& inputTargets) {
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
// 根据inputChannel(其中的fd)来获取对应的Connection
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
sp connection = mConnectionsByFd.valueAt(connectionIndex);
// 继续向下调用
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
}
}
}
这里根据InputChannel的fd值来获取对应的Connection对象,InputChannel以及Connection的相关知识可以西安看第三章;Connection是用来管理InputChannel的变量;然后接着调用 prepareDispatchCycleLocked;
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
// Split a motion event if needed.
if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);
MotionEntry* originalMotionEntry = static_cast(eventEntry);
if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
MotionEntry* splitMotionEntry = splitMotionEvent(
originalMotionEntry, inputTarget->pointerIds);
if (!splitMotionEntry) {
return; // split event was dropped
}
enqueueDispatchEntriesLocked(currentTime, connection,
splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
}
}
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
最后接着调用 enqueueDispatchEntriesLocked函数:
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
// 将dispatch entries入队列
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
// 开始分发事件
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
enqueueDispatchEntryLocked创建DispatchEntry(按键事件对象),并且把该对象作为一个发送数据包加入到outboundQueue队列中;
startDispatchCycleLocked取出outboundQueue队列头元素,赋给dispatchEntry,再取出事件对象KeyEntry,根据事件类型确定case语句分支,如果是按键事件,就调用connection的InputPublisher的publishKeyEvent函数发送到inputchannel中,如果publishKeyEvent返回0,表示按键事件发送成功;
InputDispathcer#enqueueDispatchEntryLocked:
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::enqueueDispatchEntryLocked(
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
int32_t inputTargetFlags = inputTarget->flags;
// 如果inputTargetFlags和dispatchMode不匹配
if (!(inputTargetFlags & dispatchMode)) {
return;
}
inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
// 创建DispatchEntry
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor);
......
// Enqueue the dispatch entry.
// 添加到outboundQueue中
connection->outboundQueue.enqueueAtTail(dispatchEntry);
}
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp& connection) {
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
// 取出outboundQueue的首部元素
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
// 根据EventEntry的Type类型进行处理
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast(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: {
MotionEntry* motionEntry = static_cast(eventEntry);
....
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset,
motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
break;
}
}
.....
// Re-enqueue the event on the wait queue.
// 事件处理完,将该Entry移除队列
connection->outboundQueue.dequeue(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
connection->waitQueue.enqueueAtTail(dispatchEntry);
traceWaitQueueLengthLocked(connection);
}
}
典型的事件处理函数,从outBoundQueue中取出EventEntry,然后根据其Type,是TypeEvent,还是MotionEvent分别进行处理;可以看到KeyEvent使用publishKeyEvent来处理;而MotionEvent采用publishMotionEvent来处理;
/** \frameworks\native\libs\input\InputTransport.cpp **/
status_t InputPublisher::publishMotionEvent(
uint32_t seq,
int32_t deviceId,
......
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
.....
// 一系列的赋值操作
InputMessage msg;
msg.header.type = InputMessage::TYPE_MOTION;
msg.body.motion.seq = seq;
msg.body.motion.deviceId = deviceId;
......
return mChannel->sendMessage(&msg);
}
InputPublisher的publishMotionEvent中创建一个InputMessage,然后根据传递进来的EventEntry中的值进行赋值,然后调用InputChannel的sendMessage进行事件发送;这里的InputChannel即是下面将会提到的在ViewRootImpl中创建的Server端的InputChannel;
/** \frameworks\native\libs\input\InputTransport.cpp **/
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
// mFd对应socket fd;则例相当于往服务器socket中发送消息
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
// 发送失败
if (nWrite < 0) {
.....
return -error;
}
// 发送成功
return OK;
}
InputChannel的sendMessage操作即是使用服务器socket send一个Message;下面将会提到socket服务端没有往inputchannel中写入数据时,客户端暂时处于阻塞状态,一旦服务端有了数据后,客户端也被唤醒了。
这里先来了解下这个重要类InputChannel是如何被初始化的;
/** \frameworks\native\include\input\InputTransport.h **/
/*
* An input channel consists of a local unix domain socket used to send and receive
* input messages across processes. Each channel has a descriptive name for debugging purposes.
*
* Each endpoint has its own InputChannel object that specifies its file descriptor.
*
* The input channel is closed when all references to it are released.
*/
// 上面提到InputChannel是使用unix domain socket(UDS)进行通信的,而非Binder
class InputChannel : public RefBase {
protected:
virtual~InputChannel();
public:
InputChannel(const String8& name, int fd); // fd类似设备描述符
// 用于打开一个InputChannel对(Pair),用以实现双向通信
static status_t openInputChannelPair(const String8& name,
sp& outServerChannel, sp& outClientChannel);
inline String8 getName() const { returnmName; }
inlineint getFd() const { returnmFd; }
// 发送接收信息
status_t sendMessage(const InputMessage* msg);
status_t receiveMessage(InputMessage* msg);
/* Returns a new object that has a duplicate of this channel's fd. */
sp dup() const;
private:
String8 mName;
int mFd; // 重点要弄清该变量代表的含义
};
InputChannel是可以双向通信的,它通过openInputChannelPair来打开一个InputChannel对,然后sendMessage或者receiveMessage来发送接收消息;
InputChannel是通过UDS来实现通信的,Android系统中最为常用的进程间通信时Binder通信,其次便是UDS进行单机内的进程间通信,也称IPC Socket。
来看InputChannel的初始化:
了解Window的创建过程后,之后有一个重要的对象ViewRootImpl,这里从其setView开始探索:
/** \frameworks\base\core\java\android\view\ViewRootImpl.java **/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
.....
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
// 在Session addToDisplay时,传入mInputChannel
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
}
.....
}
}
其实Java层的InputChannel只是对native层的封装,如下所示:
/** \frameworks\base\core\java\android\view\InputChannel.java **/
public final class InputChannel implements Parcelable {
@SuppressWarnings("unused")
private long mPtr; // used by native code
private static native InputChannel[] nativeOpenInputChannelPair(String name);
private native void nativeDispose(boolean finalized);
private native void nativeTransferTo(InputChannel other);
private native void nativeReadFromParcel(Parcel parcel);
private native void nativeWriteToParcel(Parcel parcel);
private native void nativeDup(InputChannel target);
private native String nativeGetName();
}
WindowSession的具体细节参见《View机制深入学习(一)》,addToDisplay会继续调用WindowManagerService的addWindow函数:
/** \frameworks\base\core\java\android\view\WindowManagerService.java **/
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
.....
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
// 打开InputChannel对
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
// WindowState设置inputChannel变量
win.setInputChannel(inputChannels[0]);
// 设置outputChannel
inputChannels[1].transferTo(outInputChannel);
// InputManager注册InputChannel
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
....
}
可以看到在这里通过openInputChannelPair打开InputChannel,前面提到openInputChannelPair就是调用native端InputChannel的openInputChannelPair函数;
从这里面还可以看到,创建的InputChannel对,一个用来设置给WindowState,即供Window使用;一个设置给InputManagerService,其实是设置给native端的InputDispatcher,用以分发相应的事件。
/** \frameworks\base\core\java\android\view\InputChannel.java **/
public static InputChannel[] openInputChannelPair(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
return nativeOpenInputChannelPair(name);
}
private static native InputChannel[] nativeOpenInputChannelPair(String name);
下面来看native端的InputChannel;
/** \frameworks\native\libs\input\InputTransport.cpp **/
status_t InputChannel::openInputChannelPair(const String8& name,
sp& outServerChannel, sp& outClientChannel) {
// 建立UDS
int sockets[2];
// 创建一个饱含2个元素的socket数组,socketpair创建一对socket对象,SOCK_SEQPACKET表示创建连续可靠的数据包连接,如果创建成功,返回0,如果返回-1,出错。
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -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));
// 创建Server与Client端实例
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;
}
上面创建了一对InputChannel:分别为服务端管道对象outServerChannel和客户端管道对象outClientChannel;inputChannels[0]作为服务端管道提供给InputDispatcher使用,用来发送按键事件;inputChannels[1]作为客户端管道提供给应用程序主线程使用,用来接收、消费按键事件。
创建好InputChannel之后,继续来看addWindow中的InputManagerService注册InputChannel的过程;前面提到,创建的inputChannels[0]即outServerChannel是供IMS中的InputDispatcher使用的,因此这里需要进行注册;
直接来到本地端的nativeRegisterInputChannel,
/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
// 将Java端存储的ptr指针地址转化为NativeInputManager对象
NativeInputManager* im = reinterpret_cast(ptr);
// 根据传输进来的inputChannelObj获取InputChannel对象
sp inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
......
// 根据传递进来的inputWindowHandleObj来获取InputWindowHandle对象
sp inputWindowHandle = android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
// 调用NativeInputManager的registerInputChannel进行注册
status_t status = im->registerInputChannel(env, inputChannel, inputWindowHandle, monitor);
......
}
上面的逻辑很清晰,通过java层传递进来的inputChannelObj,inputWindowHandleObj来获取相对应的InputChannel以及InputWindowHandle对象。
然后将获得的实例传入到NativeInputManager中的registerInputChannel进行注册;
/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}
可以看到这里最终是调用InputManager中的InputDispatcher的registerInputChannel进行注册,这也验证了前面所叙述的服务器端的InputChannel是供以InputDispatcher来使用的。
/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
return BAD_VALUE;
}
// 创建一个Connection来管理对应的InputChannel以及WindowHandler
sp connection = new Connection(inputChannel, inputWindowHandle, monitor);
// 获取InputChannel对应的socket Fd;
int fd = inputChannel->getFd();
// 类似于key,value形式,将connection与inputChannel的fd建立起关联
mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
// 将InputChannel的fd添加到Looper中epoll的兴趣事件列表中
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
// 因为connection已经发生了变化,则唤醒Looper
mLooper->wake();
return OK;
}
这里通过InputChannel以及InputWindowHandle来创建相对应的Connection;Connetction是用来管理InputChannel的,Connection存储在 mConnectionsByFd的,它通过key-value形式进行存储,Connection的关键字使用InputChannel创建时的socket的fd来标识。
然后将InputChannel的fd添加到Looper的epoll兴趣列表中,注意这里的Looper对应的是InputDispatcherThread中的Looper;当server端的InputChannel有事件传递时,这时Looper会被唤醒,执行handleReceiveCallback回调;
服务器端InputChannel使用InputManagerService的registerInputChannel来实现,而客户端的InputChannel则通过
inputChannels[1].transferTo(outInputChannel);
来实现;
直接来到对应的native层的transferTo:
/* @path: \frameworks\base\core\jni\android_view_InputChannel.cpp */
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;
}
// 创建InputChannel
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, obj);
android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}
注意函数中出现的几个变量对应的含义:
obj:本地方法所在对象的引用,对应inputChannels[1]客户端对象的引用
otherObj:在ViewRootImpl中创建的InputChannel对象
具体不再细述,就是将本地端的InputChannel[1]赋值给Java端的outInputChannel对象;
在前面第二章末已经提出,使用InputPublisher来将Message传递给InputChannel,这里是发送事件;而相对应的,会有一个是用来接收事件的,其类名为InputConsumer;