###序言android
最近在看Android触摸屏事件相关的源码,为了对整个事件体系的了解,因此对事件相关,从事件的产生,写入设备文件到咱们的应用层如何获取到事件,整个传递机制源码进行了分析,如下为对于相关代码的梳理过程当中的一些代码剖析记录。但愿可以对你们有所帮助,同时也但愿对于理解不当之处可以给予指正。bash
针对事件的分析,这里以触摸屏事件为例子,这也是咱们最经常使用的一个事件处理,这里首先抛出咱们应用层相关使用代码的例子,而后在来看事件管理的服务的启动到如何读取事件,事件的整个分发流程机制,如何一步步的走到咱们的应用层中,其中对于涉及到WMS,View,跨进程一些知识,这里没有具体深刻,接下来将针对每个知识点,进行相关的代码分析。session
###应用层
咱们平时的开发中,对于应用层的处理,主要在于为View设置触摸监听器,而后从其中的回调函数中获得咱们所须要的相关的触摸的数据。咱们能够对View进行设置相应的触摸监听器。app
@Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
return true;
}复制代码
从这里,咱们能够获取到触摸事件的相关信息。那么问题来了,这个事件是从哪里传递来的呢?也就是说这个回调函数是被谁调用的呢?事件是如何传递到该View的。同时也涉及到了一个在应用层,事件的传递问题,当一个事件到达,是如何在View的父子层级中进行传递的。socket
###Framework层ide
对于Android Framework层的一些service,都是在SystemServer进程中建立的。和大多数的Service同样,InputManager它也是在SystemServer中建立。在SystemServer的startOtherService中,进行了一些Service的建立。(对于SystemServer启动相关在后续也会进行介绍们这里先着于InputManagerService相关。)函数
InputManager inputManager = new InputManagerService(context);
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();复制代码
首先建立了一个InputManagerService的实例,而后将该服务加入到ServiceManger中,同时为其设置了窗口的输入监听器,而后调用该服务的start方法。这里咱们从其构造函数开始,而后再看一下它start方法的实现。oop
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
....
LocalServices.addService(InputManagerInternal.class, new LocalService());
}复制代码
首先建立了一个InputManagerHandler,同时传入了DisplayThread的looper,这里的InputManagerHandle为InputManager的一个内部类,其中进行了一些消息的处理,调用native方法,nativeInit。其native实如今framework/services/core/jni下的com_android_server_input_InputManagerService.cpp源码分析
其nativeInit的实现以下ui
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}复制代码
获取传递的消息队列,而后根据其建立本地的NativeInputManager。
对于NativeInputManger实例的建立。其构造函数以下所示。
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
...
mInteractive = true;
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}复制代码
建立了一个EventHub,同时利用EventHub来建立了一个InputManger实例。InputManger在framework/services/inputflinger下,
InputManger的构造函数代码以下:
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}复制代码
经过构造函数,咱们能够看到,这里建立了一个InputDispatcher根据传入的分发策略,而后建立了InputReader,传递了读的策略和Dispatcher仍是有EventHub。接下来调用了initialize方法。
void InputManager::initialize()
{
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}复制代码
将上面建立的读和分发事件的核心类传入咱们所建立的线程之中。到此,在咱们的SystemServer中,对于InputManager的建立已经完成,接下来调用了InputManager的start方法,顾名思义,是对于这个InputManger服务的开始。代码中的相关实现。
核心调用
nativeStart(mPtr);复制代码
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
}复制代码
nativeStart函数中调用了InputManager的start方法。该方法执行以下
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
}复制代码
至此,咱们能够看到start方法所作的事情是启动了在以前建立InputManger的时候,建立的DispatcherThread和ReaderThread.
上述建立启动流程图。
InputManager是系统事件处理的核心,它使用了两个线程,一个是InputReaderThread,读和处理未加工的输入事件而后发送事件到由DispatcherThread管理的队列中。InputDispatcherThread等待着在队列上新来的事件,而后将它们分发给应用程序。而对于上层的类只是对这的一个包装。因此要对输入服务有个细致的了解,对于InputManager类的剖析相当重要。
至此,咱们能够看到InputManager开启两个线程,同时建立了Dispatcher核心类和InputReader核心类。
####EventHub
在NativeInputManager的构造函数中,建立了EventHub,同时将其做为参数传递给InputManager,在InputManager构造函数中,建立InputRead的时候,传递了EventHub,EventHub的做用是未来源不一样的各类信息,转化成为一种类型的信息,而后将这些信息提交到上层,给上层作处理。也就是说在输入设备中,各类类型的输入信息,经过EventHub进行一个处理以后,将信息转化为同一种类型的信息传递到上层。
在对源码分析以前,这里先讲一下epoll,当咱们的应用程序要对多个输入流进行监控的时候,处理多个输入流来的数据,咱们能够采起的一个方式是,对于这每个流进行遍历,检测到有数据,读出。
while true {
for i in stream[]; {
if i has data
read until unavailable
}
}复制代码
若是有数据,则读取直到其中没有数据为止。该种方式也称为忙轮询,可是当输入流一直没有数据的时候,就是在空消耗CPU,所以产生了select,poll,epoll。select和poll类似,其实现为,当没有数据的时候阻塞,一旦有了数据,经过轮询的方式读取数据。
while true {
select(streams[])
for i in streams[] {
if i has data
read until unavailable
}
}复制代码
可是当咱们的流比较多的时候,对于轮询检测每个输入流,也是比较消耗的,所以,epoll产生了,当没有数据的时候,岂会阻塞,可是当有数据的时候,epoll可以把哪个流发生了怎样的事件发送给咱们,这样咱们对返回的流进行操做就是有意义的了。
先从EventHub的构造函数看起。
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);
mINotifyFd = inotify_init();
//监视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的句柄加入到epoll监测
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
//建立匿名管道
int wakeFds[2];
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 kerel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}复制代码
构造函数首先建立了epoll句柄,而后建立了inotify句柄,而后建立了一个匿名管道,并将匿名管道设置为非阻塞,inotify是Linux下的一个监控目录和文件变化的机制,这里监控了/dev/input目录,当这个目录发生变化,就代表有输入设备加入或者移除。至此,EventHub只是进行了一些监控操做的处理。而对于EventHub相关事件处理部分的调用则是在建立ReaderThread的时候。
ReaderThread是继承自Android的Thread实现。下面是一个建立Android中Native 线程的方式。
namespace android {
class MyThread: public Thread {
public:
MyThread();
//virtual ~MyThread();
//若是返回true,循环调用此函数,返回false下一次不会再调用此函数
virtual bool threadLoop();
};
}复制代码
ReaderThread的threadLoop实现以下,因为返回的结果为true,因此这里InputReader的loopOnce会被循环调用。
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}复制代码
下面是loopOnce实现的简略版,只是抽离了其中对于事件的处理。
void InputReader::loopOnce() {
.....
//从EventHub中获取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
//若是读到数据,处理事件数据
if (count) {
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
//将排队的事件队列发送给监听者,实际上这个监听者就是Input dispatcher
mQueuedListener->flush();
}复制代码
其中比较关键的几个地方为getEvents()
和processEventsLocked()
接下来让对这个几个重要的方法进行一一的分析。
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
RawEvent* event = buffer;
size_t capacity = bufferSize;
for(;;) {
....
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
.....
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// 设备被移除,关闭设备
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
//没法得到事件
if (errno != EAGAIN && errno != EINTR) {
ALOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
//得到事件的大小非事件类型整数倍
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
//计算读入了多少事件
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
if (iev.type == EV_MSC) {
if (iev.code == MSC_ANDROID_TIME_SEC) {
device->timestampOverrideSec = iev.value;
continue;
} else if (iev.code == MSC_ANDROID_TIME_USEC) {
device->timestampOverrideUsec = iev.value;
continue;
}
}
//事件时间相关计算,时间的错误可能会致使ANR和一些bug。这里采起一系列的防范
.........
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
//每到咱们计算完一个事件,capacity就会减1,若是为0。则表示 结果缓冲区已经满了,
//须要重置开始读取时间的索引值,来读取下一个事件迭代
mPendingEventIndex -= 1;
break;
}
}
//代表读到事件了,跳出循环
if (event != buffer || awoken) {
break;
}
mPendingEventIndex = 0;
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
if (pollResult == 0) {
mPendingEventCount = 0;
break;
}
//判断是否有事件发生
if (pollResult < 0) {
mPendingEventCount = 0;
} else {
//产生的事件的数目
mPendingEventCount = size_t(pollResult);
}
}
//产生的事件数目
return event - buffer;
}复制代码
方法开始部分会进行一些新增设备和移除设备的相关操做,来更新内部的状态。这里咱们聚焦于事件部分。来看一下,触摸屏事件是如何被读出的。这里传入了一个参数RawEvent* ,RawEvent的指针,经过这个指针做为起始地址,记录了咱们的事件,对于事件处理相关,是在一个循环体中,获取时间,检测事件对应的先关设备类型,而后读取事件,为事件进行赋值,若是有事件被读到,直接跳出循环,若是没有则会继续等待直到事件的到来。同时更新mPendingEventCout和mPendingEventIndex,经过这两个变量来控制事件的读取,同时读取的过程当中和开始也会进行一些设备增长或者移除的相关事件的处理。事件的来源则是经过epoll_wait获得。而这个epoll也就是咱们开始的时候对一些目录的输入监听。而事件的写入则是由相关的设备驱动写入,这里对驱动相关再也不展开分析。
InputReaderThread函数不断地调用looperOnce函数,不断的从中读取事件,那么下一个问题来了,读取到事件要放置到哪里,又在哪里被消耗掉了呢?也就是事件接下来的流向问题。让咱们回到looperOnce以前。
在调用了getEvent以后,又调用了函数processEventsLocked
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; } }复制代码
首先对于事件类型进行了判断,将事件中添加,移除设备的事件,和设备自身产生的事件进行了区分,这里咱们只关心对于设备自身产生的事件。也就是processEventsForDeviceLocked
函数中所进行的操做。
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}复制代码
根据事件得到相应的设备类型,而后将事件交给相应的设备处理。
InputDevice的process方法
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
....
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
....
}复制代码
这里的事件又交给了InputMapper来处理
InputMapper对应了不少的子类,这里根据事件的类型进行相应的派发,处理。
事件到了这里以后,如何传递到应用层,这里mapper->process进行了那些处理。这里来看一下对于触摸屏事件的处理函数。
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
}复制代码
经过这里的函数处理,咱们继续追踪函数的数据流向。对于相关的事件处理,这里最终执行的是将
void TouchInputMapper::sync(nsecs_t when) {
.....
processRawTouches(false /*timeout*/);
}复制代码
在相关的函数调用以后,最终调用了dispatchTouches
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
....
dispatchMotion();
....
}复制代码
对于相关事件的分发最终调用到了dispatchMotion(),对事件数据进行组装以后,调用了
void TouchInputMapper::dispatchMotion() {
....
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
}复制代码
getListener函数
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}复制代码
notifyMotion函数实现
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}复制代码
这里能够看到,咱们将触摸相关的事件进行包装以后,将其加入到一个ArgsQueue队列,到此,咱们已经将数据加入到参数队列中,到此事件从设备文件获取到写入流程已经完成,这里让咱们再回到loopOnce方法中,最后调用了QueuedInputListener
的flush
方法,
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}复制代码
NotifyArgs的notify函数实现
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}复制代码
对于这个listener的建立来自于InputReader构建的时候。
mQueuedListener = new QueuedInputListener(listener);复制代码
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);复制代码
而这里的Listener则是InputDispatcher
,InputDispatcher 的notifyMotion实现源码。
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
.....
MotionEvent event;
event.initialize(args->deviceId, args->source, args->action, args->actionButton,
args->flags, args->edgeFlags, args->metaState, args->buttonState,
0, 0, args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
....
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, args->actionButton, args->flags,
args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
needWake = enqueueInboundEventLocked(newEntry);
....
if (needWake) {
mLooper->wake();
}
}复制代码
在该函数中,所作的事情是对于所传递的参数,构造MotionEntry,而后将其加入到enqueueInboundEventLocked之中。而后唤醒其中的looper。
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
...
//进行一些事件和窗口相关的判断处理
}复制代码
Dispatcher开启的线程中,每次循环的操做如何?
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}复制代码
Dispatcher下dispatchOnce的实现
void InputDispatcher::dispatchOnce() {
...
dispatchOnceInnerLocked(&nextWakeupTime);
...
}复制代码
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
....
mPendingEvent = mInboundQueue.dequeueAtHead();
....
switch (mPendingEvent->type) {
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
dropReason = DROP_REASON_APP_SWITCH;
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
....
}
}复制代码
从mInboudQueue中,获取到事件,而后对事件类型进行判断,判断以后调用了dispatchMotionLocked函数,来继续进行事件的传递。
dispatchEventLocked,
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
....
pokeUserActivityLocked(eventEntry);
.....
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
}
}
}复制代码
得到目标输入,根据InputChannel获取相应的链接,而后调用prepareDispatchCycleLocked(),进行事件的派发。enqueueDispatchEntriesLocked,在该方法中又调用了startDispatchCycleLocked方法。其实现为
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
EventEntry* eventEntry = dispatchEntry->eventEntry;
....
switch (eventEntry->type) {
....
case EventEntry::TYPE_MOTION: {
status = connection->inputPublisher.publishMotionEvent( ....);
break;
}
....
}
...
}复制代码
至此调用了connection 的inputPublisher的publishMotionEvent方法将事件分发消耗。
InputPublisher定义在InputTransport.cpp中,
status_t InputPublisher::publishMotionEvent(...) {
....
InputMessage msg;
msg.header.type = InputMessage::TYPE_MOTION;
msg.body.motion.seq = seq;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
msg.body.motion.buttonState = buttonState;
msg.body.motion.xOffset = xOffset;
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.downTime = downTime;
msg.body.motion.eventTime = eventTime;
msg.body.motion.pointerCount = pointerCount;
for (uint32_t i = 0; i < pointerCount; i++) {
msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
return mChannel->sendMessage(&msg);
}复制代码
该方法所执行的操做是利用传入的触摸信息,构建点击消息,而后经过InputChannel将消息发送出去。这里引出了InputChannel,在此,咱们通InputPublisher的建立反推出InputChannel是什么时候被引入的,什么时候被建立的。从而进一步分析其做用。在分析以前先让咱们来对上述的分析过程作一个总结。
ReaderThread开启后会从EventHub中轮询获取时间,获取到事件以后,对手将进行一系列的处理,最终将通过一系列处理封装的事件信息经过InputChannel发送出去。
到此,对于输入事件,咱们已经分析到了InputChannel,对于其上的具体分析转化,将是接下来分析的核心。
从上面分析能够看到事件传递部分最后是经过InputChannel所发送出去的,那么InputChannel是在什么时候被建立的呢?什么时候被InputManager所使用的呢?
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}复制代码
nativeRegisterInputManger
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);
}
}复制代码
NativeInputManager的registerInputChannel
还会调用到InputDispatcher的registerInputChannel,会经过InputChannel建立相应的Connection,同时将InputChannel加入到相应的监控之中。在上面对代码的分析之中,获取InputChannel,就是经过这个Connection来获取的。
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);
int fd = inputChannel->getFd();
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;
}复制代码
那么这个InputChannel是在什么时候建立的呢?同时,对于InputReaderThread和InputDispatcherThread是运行在SystemServer进程中的,而咱们的应用进程是和其不在同一个进程中的。这之间必定也是有进程间的通讯机制在里面。
InputChannel的建立是在 ViewRootImpl
中setView
方法中。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
....
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
....
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
....
}复制代码
这里对于ViewRootImpl和WindowSession相关暂且不介绍,对于这方面的知识,须要很大的篇幅来介绍,这里先只是讲到是在这里建立的,对于其相关的内容将在后续的文章中介绍。这里首先是建立了一个InputChannel,而后将其调用了WindowSession
的addToDisplay
方法将其做为参数传递。
public InputChannel() {
}复制代码
在InputChannel中的方法都为调用了相应的native方法。这里调用的addToDisplay将会把InputChannel添加到WindowManagerService中。会调用WMS的addWindow
方法。
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);
}
....
}复制代码
对于InputChannel的相关处理交给了WindowState的openInputChannel方法。
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
mInputWindowHandle.inputChannel = inputChannels[0];
if (outInputChannel != null) {
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}复制代码
首先调用了InputChannel的openInputChannelPair
方法,该方法调用了InputChannel的native方法nativeOpenInputChannelPair
,建立了两个InputChannel
,对其中一个经过InputManager
进行了InputChannel的注册。对于InputChannel
的相关Native的实现是在InputTransport中,nativeOpenInputChannelPair
的源码以下。
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
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;
}复制代码
这里建立了两个Socket,这两个Socket设置具有读写双端,而后根据建立的socket,建立出两个InputChannel,一个Server,一个Client。这样在SystemServer进程和应用进程间的InputChannel的通讯就能够经过这边,因为两个channel不在同一个进程中,这里进程通讯则是经过其中的socket来进行。在sendMessage
和receiveMessage
中,经过对Socket的写,读操做来实现消息的传递。
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);
if (nWrite < 0) {
int error = errno;
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
return DEAD_OBJECT;
}
return -error;
}
if (size_t(nWrite) != msgLength) {
return DEAD_OBJECT;
}
return OK;
}复制代码
接收消息,经过读socket的方式来读取消息。
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {
int error = errno;
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
return DEAD_OBJECT;
}
return -error;
}
if (nRead == 0) { // check for EOF
return DEAD_OBJECT;
}
if (!msg->isValid(nRead)) {
return BAD_VALUE;
}
return OK;
}复制代码
接收端的消息由谁来触发呢?是如何触发开始接受消息,消息如何在传到InputChannel以后,进行的进一步的数据传递呢?这是接下来所要去分析的,这里先对上面InputChannel进行一个总结。
以前的setView
中,咱们建立了InputChannel以后,开启了对于InputChannel中输入事件的监听。
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}复制代码
WindowInputEventReceiver的构造函数以下,其继承自InputEventReceiver。
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
....
}复制代码
InputEventReceiver的构造函数源码以下
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
....
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
}复制代码
这里调用了native方法来作初始化,相关的native方法的实如今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);
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
.....
}复制代码
根据传入的InputChannel
和MessageQueue
,建立一个NativeInputEventReceiver,而后调用其initialize
方法。
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}复制代码
在initialize()
方法中,只调用了一个函数setFdEvents
,
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);
}
}
}复制代码
从InputConsumer中获取到channel的fd,而后调用Looper的addFd
方法。
int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
ALooper_callbackFunc callback, void* data) {
return ALooper_to_Looper(looper)->addFd(fd, ident, events, callback, data);
}复制代码
Looper的addFd的实现以下
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback;
request.data = data;
if (mNextRequestSeq == -1) mNextRequestSeq = 0;
struct epoll_event eventItem;
request.initEventItem(&eventItem);
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
if (epollResult < 0) {
return -1;
}
mRequests.add(fd, request);
}
}复制代码
该方法所执行的操做就是对传递的fd添加epoll监控,Looper会循环调用pollOnce
方法,而pollOnce
方法的核心实现就是pollInner
。其代码大体实现内容为等待消息的到来,当有消息到来后,根据消息类型作一些判断处理,而后调用其相关的callback。咱们当前是对于开启的socket的一个监听,当有数据到来,咱们便会执行相应的回调。这里对于InputChannel的回调是在调用了NativeInputEventReceiver的handleEvent
方法。
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;
}复制代码
对于Event的处理,这里调用consumeEvents来对事件进行处理。
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
...
for(;;) {
...
InputEvent* inputEvent;
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
...
}
...
}复制代码
InputConsumer是在InputTransport中作的声明。
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
while (!*outEvent) {
....
status_t result = mChannel->receiveMessage(&mMsg);
....
}
}复制代码
调用consume方法会持续的调用InputChannel的receiveMessage方法来从socket中读取数据。到这里,咱们已经将写入socket的事件读出来了。
####ViewRootImpl
事件在从socket读出以后,通过传递,最终会调用到ViewRootImpl的enqueueInputEvent
方法。
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(event);
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}复制代码
enqueueInputEvent方法从InputEventReceiver中获取到InputEvent,而后将其加入到当前的事件队列之中,最后调用doProcessInputEvents
来进行处理。
void doProcessInputEvents() {
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
mPendingInputEventCount -= 1;
long eventTime = q.mEvent.getEventTimeNano();
long oldestEventTime = eventTime;
if (q.mEvent instanceof MotionEvent) {
MotionEvent me = (MotionEvent)q.mEvent;
if (me.getHistorySize() > 0) {
oldestEventTime = me.getHistoricalEventTimeNano(0);
}
}
mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
deliverInputEvent(q);
}
// We are done processing all input events that we can process right now
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}复制代码
遍历全部的消息,若是事件类型为触摸屏事件,对其进行相应的时间修改,最后对于每个处理完成的事件调用deliverInputEvent
,
private void deliverInputEvent(QueuedInputEvent q) {
q.mEvent.getSequenceNumber());
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}复制代码
在事件分发环节,首先进行事件的一个判断,经过shouldSkipIme来判断是否传递给输入法,而后决定使用何种InputStage进行消息的继续传递,这里实现了多种InputStage,对于每个类型的InputStage都实现了一个方法process
方法来针对不一样类型的事件作处理,若是是触摸屏类的消息,最终会将事件的处理转交到View的身上。对于InputStage涉及的篇幅较多,这里也再也不展开,当消息到达ViewRootImpl中后,接下来就是在View间的派发。
###View的事件派发
对于View层的事件派发,咱们最多见的就是dispatchTouchEvent
,onTouch
,onInterceptTouchEvent
,onClick
,onTouchEvent
等。对于View树上事件的派发,就是在对树的遍历传递中,主要起做用的就是这几个函数。这里咱们先从View的相关事件函数开始分析,因为ViewGroup具备子View的缘由,其相关的事件派发逻辑和View有所区别,这里咱们先进行View的事件分析。
public boolean dispatchTouchEvent(MotionEvent event) {
....
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
....
return result;
}复制代码
对于在View上的事件派发,核心操做是两点,一个是调用监听器的onTouch方法,而后判断事件是否被消耗,若是没有被消耗,则会调用onTouchEvent方法。在onTouchEvent中根据消息类型进行一些处理。
根据事件类型来更新内部的一些状态。这里比较复杂的仍是在ViewGroup中的事件分发逻辑,这里在分发的过程当中,须要判断是否对事件进行拦截,若是不拦截,是否自身可处理,若是须要考虑到其中的子View。这里对其中的关键代码进行逐步分析。
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
intercepted = true;
}复制代码
判断是否进行拦截,调用自身的onInterceptTouchEvent
,开发者能够重载这个方法进行本身的一些操做。返回true表示拦截事件。若是要对事件进行拦截,则再也不进行子View的遍历。不然将会进行子View的遍历,事件传递,在子View的事件传递结束以后,若是子View将事件消耗了则会将其加入到mFirstTouchTarget,若是遍历完成没有任何被添加
if (mFirstTouchTarget == null) {
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
}复制代码
接下来进行的是对于事件在子View中的派发,这里咱们也只是针对其中的核心代码进行分析。
final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
....
dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign);
....
}复制代码
在对子View进行遍历的处理的时候,若是子View的事件被消耗,那么咱们就会将其TouchTarget赋值给mFirstTouchTarget
,当检测到mFirstTouchTarget为空时会再调用Viewgroup自身的dispatchTransformedTouchEvent方法,这个时候就会调用其onTouchEvent,而后继续View中的事件传递流程。
if (mFirstTouchTarget == null) {
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
}复制代码
对于dispatchTransformedTouchEvent
函数
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
....
}复制代码
这里事件的派发也是在调用了每个子View的dispatchTouchEvent方法,根据返回结果来判断是否被消耗,一旦事件被消耗则会中止传递。
至此对于从硬件设备产生数据,到数据被逐层传递到应用程序中的整个流程就梳理完了。事件相关的建立,传递流程以下所示。
####参考资料
我读过的最好的epoll讲解--转自”知乎“