android 4.2 input 流程分析,Android InputManager分析

本篇为鸡生蛋系列第二篇文章

主要讲一下inputmanager相关的,即驱动把数据上报到用户空间后,用户空间到应用这么个流程,

在上一遍讲内核的input子系统时候,我们采取的反向分析,即由驱动出发,最后到input core,input子系统架构这么个由点到面的分析方法,

那分析inputmanager是否可采用这种方法如何呢?实际上,对于Android上层(Native framework/framework, c++/java)的分析,我一般

采用的是由上而下的分析,即从其初始化(main,构造,onFirstRef())开始, 通常在其初始化时候,会重一些很重要的上下层的连接,如果由下往上看,会麻烦点,

然后再结合实例,看看他的数据流向是如何的,或者一些重要的API, 例如对于Audio来说,可以结合播放音乐流程来分析整个系统架构。

简单说来,input到应用的流程为

EventHub监控并读取/dev/input下数据 --> 给InputReader 加工处理 --> 到InputDispacher --> 找到focused窗口并通过input channel发出去

相关代码目录:

Android 9.0 http://androidxref.com/9.0.0_r3/

frameworks/base/services/java/com/android/server/SystemServer.java

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

frameworks/native/services/inputflinger/

1.1 初始化frameworks/base/services/java/com/android/server/SystemServer.java

startOtherServices() {

inputManager = new InputManagerService(context);

....

wm = WindowManagerService.main(context, inputManager,

ServiceManager.addService(Context.INPUT_SERVICE, inputManager,

/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);

....

inputManager.setWindowManagerCallbacks(wm.getInputMonitor());

inputManager.start();

......

}

IMS(InputManagerService)的初始化,是从SystemServer开始的,通过搜索代码(如上),我们可以看到构造了一个实例,

并做为参数传给了WMS, 由此我们也猜想,会和WMS有紧密的关系,然后

IMS设置了setWindowManagerCallbacks()并通过start()函数启动了,

SystemServer里有关IMS的就这么几个地方,我们再看下构造和start()具体的流程,与WMS的关联不分析。frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

// Pointer to native input manager service object.

private final long mPtr;

public InputManagerService(Context context) {

this.mContext = context;

this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

// config_useDevInputEventForAudioJack配置为true, 耳机事件可通过input上报

mUseDevInputEventForAudioJack =

context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);

......

mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

......

LocalServices.addService(InputManagerInternal.class, new LocalService());

}

public void start() {

Slog.i(TAG, "Starting input manager");

nativeStart(mPtr);

....

}

InputManagerService构造和start()主要也是调到JNI的 nativeInit() nativeStart().frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,

jobject serviceObj, jobject contextObj, jobject messageQueueObj) {

....

NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,

messageQueue->getLooper());

im->incStrong(0);

return reinterpret_cast(im);

}

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {

......

status_t result = im->getInputManager()->start();

......

}

nativeInit()又构造了一个 NativeInputManager(),该类可认为是上层JAVA和下层EventHub InputManager的桥梁,

nativeStart()通过 NativeInputManager最终调到 InputManager 的 start()方法NativeInputManager::NativeInputManager(jobject contextObj,

jobject serviceObj, const sp& looper) :

mLooper(looper), mInteractive(true) {

......

sp eventHub = new EventHub();

mInputManager = new InputManager(eventHub, this, this);

}

NativeInputManager()的构造又new了 EventHub 和 InputManager , 其中

eventHub做为参数传给了 InputManager()frameworks/native/services/inputflinger/EventHub.cpp

EventHub::EventHub(void) :

......{

acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

mEpollFd = epoll_create(EPOLL_SIZE_HINT); // epoll机制

LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);

mINotifyFd = inotify_init(); // inotify机制

int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); // 利用inotify监控 DEVICE_PATH(/dev/input)创建和删除

......

eventItem.events = EPOLLIN;

eventItem.data.u32 = EPOLL_ID_INOTIFY;

result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); // 将inotify的fd添加到Epoll监控中

LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);

int wakeFds[2];

result = pipe(wakeFds); //读写pipe, InputReader有事件时唤醒

LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);

mWakeReadPipeFd = wakeFds[0];

mWakeWritePipeFd = wakeFds[1];

......

result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);

......

}

EventHub相当于一个集线器,把底层的USB, TOUCH,鼠标等事件统一收集上来,再给上层。

其构造函数当中利用inotify机制监控"/dev/input" 目录下设备的创建和删除,这样当有设备变更时就可以收到通知了,

构造函数也创建了所需要的mEpollFd,这个作为IO多路复用的机制,不清楚的可以查下如何使用,

构造里将mINotifyFd添加到了epoll里,在后续input设备创建的时候,也会把input设备的fd添加进去,这样当有数据或者设备变化时,

EventHub就可获取这些事件,进一步处理。

构造还创建了两个pipe,作为wakeup的读端和写端,当InputReader.cpp有事件(配置变更,monitor, 超时请求等)唤醒EventHub处理。InputManager::InputManager(

const sp& eventHub,

const sp& readerPolicy,

const sp& dispatcherPolicy) {

mDispatcher = new InputDispatcher(dispatcherPolicy);

mReader = new InputReader(eventHub, readerPolicy, mDispatcher); // eventHub又传给了 InputReader,最终他们俩是紧密联系在一起的

initialize(); // eventHub又传给了

}

void InputManager::initialize() {

mReaderThread = new InputReaderThread(mReader);

mDispatcherThread = new InputDispatcherThread(mDispatcher);

}

InputManager(),创建了InputDispatcher和InputReader实例并与对应的InputDispatcherThread InputReaderThread 线程关联

具体的我们不往下跟了,有兴趣的可以再看看,

至此,初始化流程告一段落。

InputManagerService.java的 start方法,最终到InputManager::start(),status_t InputManager::start() {

status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);

......

result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);

......

}

start() 方法目的就是让这两个线程跑起来,这样就可以不断的获取,处理消息了。

1.2 小结startOtherServices()/SystemServer.java

+ new InputManagerService(context) --> nativeInit(...) --> new NativeInputManager(...)

+ + new EventHub() --> inotify监控/dev/input + epoll + wake pipe

+ + new InputManager(eventHub,...)

+ + new InputDispatcher()

+ + new InputReader(eventHub,...)

+ + initialize()

+ + new InputReaderThread(mReader)

+ + new InputDispatcherThread(mDispatcher)

+

+ ^

+ +

+ inputManager.start() --> nativeStart(mPtr) --> im->getInputManager()->start() --> mDispatcherThread->run() mReaderThread->run()

2. 读取数据bool InputReaderThread::threadLoop() {

mReader->loopOnce();

return true;

}

bool InputDispatcherThread::threadLoop() {

mDispatcher->dispatchOnce();

return true;

}

上一小节讲到IMS通过start()函数,最终让InputReaderThread InputDispatcherThread两个线程跑起来了,

线程跑起来后,他们因为返回值为true, 所以他们会不断的loop, 即不断的读取,分发,读取,分发……

看上面几行代码,觉得整个过程很简单清晰,然而当我们继续跟下去看细节的时候,你能 哇~~哇~~哇~~

这一节我们看看 mReader->loopOnce(), 下一节继续看Dispatcher过程void InputReader::loopOnce() {

......

size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

......

if (count) {

processEventsLocked(mEventBuffer, count);

}

......// 通知dispather分发

mQueuedListener->flush();

}

InputReader的loopOnce()通过

EventHub getEvents()

获得元数据,然后通过

processEventsLocked()

进一步的处理,

然后再通过

mQueuedListener->flush()

通知InputDispatcher有数据了,该处理了

2.1 InputReader::loopOnce()之 EventHub->getEvents()size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {

......

for (;;) {

nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

// Reopen input devices if needed.

......

// Report any devices that had last been added/removed.

while (mClosingDevices) {

......

}

// 扫描设备

if (mNeedToScanDevices) {

mNeedToScanDevices = false;

scanDevicesLocked();

mNeedToSendFinishedDeviceScan = true;

}

......

// Grab the next input event.

bool deviceChanged = false;

while (mPendingEventIndex < mPendingEventCount) {

const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];

......

ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);

......

Device* device = mDevices.valueAt(deviceIndex);

if (eventItem.events & EPOLLIN) { //epoll事件

// 读取数据

int32_t readSize = read(device->fd, readBuffer,

sizeof(struct input_event) * capacity);

......

event->deviceId = deviceId; //

event->type = iev.type;

event->code = iev.code;

event->value = iev.value;

event += 1;

......

// Return now if we have collected any events or if we were explicitly awoken.

if (event != buffer || awoken) {

break;

}

// Poll for events. Mind the wake lock dance!

......

int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

......

return event - buffer;

}

getEvents()会检查是否需要扫描设备,如果需要的话,则会建立设备KeyedVector向量表,

之后若有数据到来则通过read()函数读取数据, 返回RawEvent* buffer给processEventsLocked()进行下一步处理,

若啥事都没有通过epoll_wait()阻塞等待。

本来数据的读取(read())比较简单, 这里只列下设备扫描流程,作为个人笔记,有兴趣的可以看下EventHub::scanDevicesLocked() --> scanDirLocked(DEVICE_PATH) "/dev/input" --> while处理 openDeviceLocked() -->

status_t EventHub::openDeviceLocked(const char *devicePath) {

......

int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);

......//一大堆ioctl的信息获取

if(ioctl(......)) {

......//生成唯一的 deviceId,和device, 做为mdevices的 key, value. 以后的操作会常用到这个deviceId

// Allocate device. (The device object takes ownership of the fd at this point.)

int32_t deviceId = mNextDeviceId++;

Device* device = new Device(fd, deviceId, String8(devicePath), identifier);

......

// Load the configuration file for the device.

// 加载这个设备的 idc(Input Device Configuration)配置文件

loadConfigurationLocked(device);

......//能力获取和分类

// Figure out the kinds of events the device reports.

ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);

ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);

ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);

...... // 设备分类

device->classes |= ......;

......

//加入到epoll当中

if (registerDeviceForEpollLocked(device) != OK) {

......

configureFd(device);

......//加入mDevices并更新 mOpeningDevices 链表

addDeviceLocked(device);

return OK;

}// 对于我们的触屏来说class为

// See if this is a touch pad.

// Is this a new modern multi-touch driver?

if (test_bit(ABS_MT_POSITION_X, device->absBitmask)

&& test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {

......

if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {

device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;

}

......//之后还会加载虚拟key.

// Configure virtual keys.

if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {

// Load the virtual keys for the touch screen, if any.

// We do this now so that we can make sure to load the keymap if necessary.

status_t status = loadVirtualKeyMapLocked(device);

status_t EventHub::loadVirtualKeyMapLocked(Device* device) {

// The virtual key map is supplied by the kernel as a system board property file.

......

path.append("/sys/board_properties/virtualkeys.");

path.append(device->identifier.name);

......

return VirtualKeyMap::load(path, &device->virtualKeyMap);

addDeviceLocked()即添加到

EventHub.h KeyedVector mDevices;

并更新链表mOpeningDevicesvoid EventHub::addDeviceLocked(Device* device) {

mDevices.add(device->id, device);

device->next = mOpeningDevices;

mOpeningDevices = device;

}

另外要注意一点的是,在scanDevicesLocked()时候也会创建虚拟键盘。void EventHub::scanDevicesLocked() {

status_t res = scanDirLocked(DEVICE_PATH);

.......

// 创建虚拟键盘

if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {

createVirtualKeyboardLocked();

}

}

2.2 InputReader::loopOnce()之 processEventsLocked

mEventHub->getEvents(), 反回元数据后,传给 processEventsLocked()进一步处理

元数据的定义如下,主要记录了时间,设备id, type, code, value.struct RawEvent {

nsecs_t when;

int32_t deviceId;

int32_t type;

int32_t code;

int32_t value;

};

其中的deviceId起了个连接作用,用于标识eventhub和iputreader中的设备,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;

......

processEventsForDeviceLocked(deviceId, rawEvent, batchSize);

......

case EventHubInterface::DEVICE_ADDED:

addDeviceLocked(rawEvent->when, rawEvent->deviceId);

case EventHubInterface::DEVICE_REMOVED:

......

case EventHubInterface::FINISHED_DEVICE_SCAN:

......

}

}

processEventsLocked()函数有个

processEventsForDeviceLocked() 对于对数据的处理,

另外还根据type, 处理了对设备添加移除,扫描的处理,

大家就有点奇怪了,咦,eventhub扫描设备的时候,不是有处理添加设备吗?

咋这儿又有添加设备了? 而且看代码,两者都有个mDevices变量EventHub.h KeyedVector mDevices;

InputReader.h KeyedVector mDevices;

上面可看到两者value类型不同,他们之间的key 即deviceID是相同的,

其实我个人认为EventHub中的Device为设备的本身属性,是下层设备的实例化,

而InputReader中的InputDevice为更高层次的抽象,主要用于往上层处理数据,

addDeviceLocked()过程中还会根据input设备的不同属性设置不同的Mapper事件转换器。

我们先看下processEventsForDeviceLocked()过程:void InputReader::processEventsForDeviceLocked(int32_t deviceId,

const RawEvent* rawEvents, size_t count) {

ssize_t deviceIndex = mDevices.indexOfKey(deviceId);

......

InputDevice* device = mDevices.valueAt(deviceIndex);

......

device->process(rawEvents, count);

}

void InputDevice::process(const RawEvent* rawEvents, size_t count) {

// Process all of the events in order for each mapper.

......

// 可能会有多个mapper

size_t numMappers = mMappers.size();

for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {

......

for (size_t i = 0; i < numMappers; i++) {

InputMapper* mapper = mMappers[i];

mapper->process(rawEvent);

}

......

}

processEventsForDeviceLocked() --> device->process() --> mapper->process()

最终数据的处理也是通过mapper来处理的,所以我们还得看下mapper咋添加的

Mapper添加

mapper的添加是根据分类来添加的, 以触屏为例frameworks/native/services/inputflinger/InputReader.cpp

InputReader::processEventsLocked() --> addDeviceLocked() --> createDeviceLocked() -->

// Touchscreens and touchpad devices.

if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {

device->addMapper(new MultiTouchInputMapper(device));

} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {

device->addMapper(new SingleTouchInputMapper(device));

}

所以触屏的最后数据处理函数会调到

MultiTouchInputMapper的process函数不再详细看void MultiTouchInputMapper::process(const RawEvent* rawEvent) {

TouchInputMapper::process(rawEvent);

mMultiTouchMotionAccumulator.process(rawEvent);

}

2.3 InputReader数据如何到InputDispatcher的?

InputReader::loopOnce() 数据处理完后便调用 mQueuedListener->flush() 通知 InputDispatcher 该处理数据了。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();

}

flush()方法即把mArgsQueue Vector一个个取出来,然后再调用notify()方法,

那我们肯定想要知道

1. 数据是咋压入 mArgsQueue的?

2. notify() 后续流程咋把数据给到 InputDispatcher

1.void QueuedInputListener::notifyConfigurationChanged(

const NotifyConfigurationChangedArgs* args) {

mArgsQueue.push(new NotifyConfigurationChangedArgs(*args));

}

void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {

mArgsQueue.push(new NotifyKeyArgs(*args));

}

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {

mArgsQueue.push(new NotifyMotionArgs(*args));

}

void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {

mArgsQueue.push(new NotifySwitchArgs(*args));

}

void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {

mArgsQueue.push(new NotifyDeviceResetArgs(*args));

}

在QueuedInputListener中看到 notifyConfigurationChanged() notifyKey() notifyMotion() notifySwitch() notifyDeviceReset()

当有配置变化或事件时,都会新创建个notify args实例(都继承自NotifyArgs),然后push到mArgsQueue,

以触屏事件为例,push流程为:TouchInputMapper::sync() --> processRawTouches() --> cookAndDispatch() --> dispatchTouches() --> dispatchMotion()

--> NotifyMotionArgs args(...) getListener()->notifyMotion(&args) -->

frameworks/native/services/inputflinger/InputListener.cpp

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {

mArgsQueue.push(new NotifyMotionArgs(*args));

}InputReader::loopOnce() --> QueuedInputListener::flush() --> for args->notify(mInnerListener);

以触屏NotifyMotionArgs为例,其调用到void NotifyMotionArgs::notify(const sp& listener) const {

listener->notifyMotion(this);

}

注意其 listener 为 InputDispatcher (InputDispatcher 继承自 InputDispatcherInterface class InputDispatcher : public InputDispatcherInterface),frameworks/native/services/inputflinger/InputManager.cpp

mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(..., ..., mDispatcher); --> InputReader::InputReader(..., ..., ...listener) --> new QueuedInputListener(listener);

所以最终就调到了

InputDispatcher::notifyMotion()void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {

......// 合法性检查

if (!validateMotionEvent(args->action, args->actionButton,

args->pointerCount, args->pointerProperties)) {

......// 预处理

mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);

......

if (shouldSendMotionToInputFilterLocked(args)) {

mLock.unlock();

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);

policyFlags |= POLICY_FLAG_FILTERED;

// 过滤

if (!mPolicy->filterInputEvent(&event, policyFlags)) {

return; // event was consumed by the filter

}

mLock.lock();

}

// Just enqueue a new motion event.

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);

mLock.unlock();

} // release lock

if (needWake) {

// 唤醒

mLooper->wake();

}

}

notifyMotion()会先检查合法性,然后预处理,如果需要过滤则进行过滤处理,

否则构建 MotionEntry,并入队,随后将looper唤醒。bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {

bool needWake = mInboundQueue.isEmpty();

// 入队

mInboundQueue.enqueueAtTail(entry);

......

}

InputReader这一侧大至就分析完了,数据从InputReader传到InputDispatcher也清楚了,

接下来看看数据分发。

3. 分发数据

在开头也讲到,InputDispatcherThread里不断的loop,调用dispatchOnce()进行数据的分发。frameworks/native/services/inputflinger/InputDispatcher.cpp

void InputDispatcher::dispatchOnce() {

......

// Run a dispatch loop if there are no pending commands.

// The dispatch loop might enqueue commands to run afterwards.

if (!haveCommandsLocked()) {

// 如果命令列队为空, 进行事件分发

dispatchOnceInnerLocked(&nextWakeupTime);

}

//如果looper里没有信息,会阻塞,直到timeoutMillis超时

mLooper->pollOnce(timeoutMillis);

}

dispatchOnce()里如果命令处理完了,才会调用dispatchOnceInnerLocked()进行事件处理。void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {

.....//如果没有event,抓取一个

// Ready to start a new event.

// If we don't already have a pending event, go grab one.

if (! mPendingEvent) {

if (mInboundQueue.isEmpty()) {

......

} else {

// Inbound queue has at least one entry.

mPendingEvent = mInboundQueue.dequeueAtHead(); //

traceInboundQueueLengthLocked();

}

......//一些错误处理,包括anr时间重置,略过

switch (mPendingEvent->type) {

case EventEntry::TYPE_CONFIGURATION_CHANGED: ....

case EventEntry::TYPE_DEVICE_RESET: ....

case EventEntry::TYPE_KEY: .....

......//对我们的touch来说是motion事件

case EventEntry::TYPE_MOTION: {

MotionEntry* typedEntry = static_cast(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;

}

......

}

dispatchOnceInnerLocked从mInboundQueue队列中取出之前的MotionEntry,

然后错误处理,对于触屏事件做dispatchMotionLocked()bool InputDispatcher::dispatchMotionLocked(

nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {

......// 是否为 point event

bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

// Identify targets.

Vector inputTargets;

......

if (isPointerEvent) {

// Pointer event. (eg. touchscreen)

injectionResult = findTouchedWindowTargetsLocked(currentTime,

entry, inputTargets, nextWakeupTime, &conflictingPointerActions);

} else {

// Non touch event. (eg. trackball)

injectionResult = findFocusedWindowTargetsLocked(currentTime,

entry, inputTargets, nextWakeupTime);

}

......

dispatchEventLocked(currentTime, entry, inputTargets);

return true;

}

对于point event,会先用

findTouchedWindowTargetsLocked() 找到目标窗口,否则用

findFocusedWindowTargetsLocked() 找到目标窗口

对我们的触屏来说,包含有该属性

frameworks/native/include/android/input.h

AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER,

找到目标窗口后,再用 dispatchEventLocked() 发给目标窗口dispatchEventLocked() --> prepareDispatchCycleLocked() --> enqueueDispatchEntriesLocked()

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,

EventEntry* eventEntry, const Vector& inputTargets) {

......

for (size_t i = 0; i < inputTargets.size(); i++) {

const InputTarget& inputTarget = inputTargets.itemAt(i);

ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);

if (connectionIndex >= 0) {

sp connection = mConnectionsByFd.valueAt(connectionIndex);

prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);

......

}

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,

......

// Not splitting. Enqueue dispatch entries for the event as is.

enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);

}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.

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()会根据flag mode进行比较,然后加入到connection的outboundQueue里

connection->outboundQueue.enqueueAtTail(dispatchEntry);

然后再调用

startDispatchCycleLocked()最终通过socket把事件发出去void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

const sp& connection) {

......

case EventEntry::TYPE_MOTION: {

......

// Publish the motion event.

status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,

motionEntry->deviceId, motionEntry->source, motionEntry->displayId,

dispatchEntry->resolvedAction, motionEntry->actionButton,

dispatchEntry->resolvedFlags, motionEntry->edgeFlags,

motionEntry->metaState, motionEntry->buttonState,

xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,

motionEntry->downTime, motionEntry->eventTime,

motionEntry->pointerCount, motionEntry->pointerProperties,

usingCoords);

break;

}

......

frameworks/native/libs/input/InputTransport.cpp

status_t InputPublisher::publishMotionEvent(

......

InputMessage msg;

msg.header.type = InputMessage::TYPE_MOTION;

...... // 通过socket发送

return mChannel->sendMessage(&msg);

}

4. 数据接收

数据发送后,又被谁接收到了呢?之后流程又如何呢?

input数据主要有两种,一个应用,一个MonitoringChannel,

这里仅简单的列举下,详细的请看看参考文档

4.1 App 接收

对于应用的接收,需要看input channel是咋建立的,

然后看看findTouchedWindowTargetsLocked(),咋找到目录窗口,该函数很复杂,

但有个比较重要的是查询 mWindowHandles, 该变量在setInputWindows()设置,WindowManagerService.java

mInputMonitor.updateInputWindowsLw(false /*force*/); in addWindow() -+

mInputMonitor.updateInputWindowsLw(true /*force*/); in postWindowRemoveCleanupLocked() +

mInputMonitor.updateInputWindowsLw(true /*force*/); in relayoutWindow() +

mInputMonitor.updateInputWindowsLw(true /*force*/); in relayoutWindow() +--> updateInputWindowsLw() -->

mInputMonitor.updateInputWindowsLw(true /*force*/); in removeWindowToken() +

mInputMonitor.updateInputWindowsLw(true /*force*/); in startPositioningLocked() +

mInputMonitor.updateInputWindowsLw(true /*force*/); in startPositioningLocked() +

mInputMonitor.updateInputWindowsLw(true /*force*/); in finishPositioning() -+

InputMonitor.java updateInputWindowsLw()

+--> mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag)

+--> updateInputWindows()

+--> InputManagerService.java setInputWindows()

+--> nativeSetInputWindows()

+--> im->setInputWindows (NativeInputManager::setInputWindows())

+--> mInputManager->getDispatcher()->setInputWindows()

+-->

void InputDispatcher::setInputWindows(const Vector >& inputWindowHandles) {

......

mWindowHandles = inputWindowHandles;

应用添加窗口设置mWindowHandles如上。在addWindow() relayoutWindow()...过程中都可能设置该变量frameworks/base/core/java/android/view/ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

...... // addToDisplay() 将调用WMS mService.addWindow()

res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,

getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,

mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,

mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);

...... //

mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,

Looper.myLooper());

}

对应用来说在setView() 时会调用mWindowSession.addToDisplay(),很后调用addWindow(), 然后win.openInputChannel(outInputChannel)等建立channel操作

addToDisplay() 之会,会将mInputChannel looper,通过 WindowInputEventReceiver绑在一起,

这样当有数据到来时在looper里面处理。

WindowInputEventReceiver()流程如下WindowInputEventReceiver() --> InputEventReceiver.java InputEventReceiver() --> nativeInit() -->

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,

jobject inputChannelObj, jobject messageQueueObj) {

......

sp receiver = new NativeInputEventReceiver(env,

receiverWeak, inputChannel, messageQueue);

status_t status = receiver->initialize();

......

}

initialize() (NativeInputEventReceiver::initialize())--> setFdEvents(ALOOPER_EVENT_INPUT) -->

// 注意事件类型为 ALOOPER_EVENT_INPUT

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);

system/core/libutils/Looper.cpp

int Looper::addFd(int fd, int ident, int events, const sp& callback, void* data) {

......// 将input channel的fd加入到epoll监控中

int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);

** 当socket接收到数据时,通过handle来处理android_view_InputEventReceiver.cpp

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {

......// ALOOPER_EVENT_INPUT 事件

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;

}

......

}

handleEvent() --> consumeEvents() -->

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,

bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {

......

status_t status = mInputConsumer.consume(&mInputEventFactory, //取数据

......

if (inputEventObj) {

...

env->CallVoidMethod(receiverObj.get(),

gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj, //调用 dispatchInputEvent()

......

}

-->

frameworks/base/core/java/android/view/InputEventReceiver.java dispatchInputEvent() --> onInputEvent() -->

final class WindowInputEventReceiver extends InputEventReceiver {

......

@Override

public void onInputEvent(InputEvent event, int displayId) {

enqueueInputEvent(event, this, 0, true);

}

void enqueueInputEvent(InputEvent event,

InputEventReceiver receiver, int flags, boolean processImmediately) {

......

if (processImmediately) {

doProcessInputEvents(); // --> deliverInputEvent(q);

} else {

scheduleProcessInputEvents();

}

}

ViewRootImpl.java

private void deliverInputEvent(QueuedInputEvent q) {

......

InputStage stage;

if (q.shouldSendToSynthesizer()) {

stage = mSyntheticInputStage;

} else {

// mFirstPostImeInputStage = earlyPostImeStage; new EarlyPostImeInputStage(nativePostImeStage); 注意参数为nativePostImeStage,在 apply(q, onProcess(q)) 返回forward时会用到

stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;

}

......

if (stage != null) {

handleWindowFocusChanged();

stage.deliver(q);

......

}

stage.deliver --> apply(q, onProcess(q)) --> EarlyPostImeInputStage onProcess() --> processPointerEvent() --> (EarlyPostImeInputStage-->NativePostImeInputStage-->ViewPostImeInputStage-->SyntheticInputStage;)

ViewPostImeInputStage mView.dispatchPointerEvent(event)

View.java dispatchPointerEvent() +-->View.java dispatchTouchEvent() --> li.mOnTouchListener.onTouch(this, event) onTouchEvent(event)

+

+--> ViewGroup.java dispatchTouchEvent()

4.2 input monitor笔记

在分发input数据时,会把 mMonitoringChannels 加入到目标中,然后通过socket也发给该目标,

InputDispatcher::dispatchMotionLocked() --> addMonitoringTargetsLocked() --> for mMonitoringChannels

在WMS时构造,会通过monitorInput()创建,

之后别的服务可通过WMS registerPointerEventListener() unregisterPointerEventListener() 以listener方式获取数据frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

private WindowManagerService(......) {

......

if(mInputManager != null) {

final InputChannel inputChannel = mInputManager.monitorInput(TAG_WM);

mPointerEventDispatcher = inputChannel != null

? new PointerEventDispatcher(inputChannel) : null;

@Override

public void registerPointerEventListener(PointerEventListener listener) {

mPointerEventDispatcher.registerInputEventListener(listener);

}

@Override

public void unregisterPointerEventListener(PointerEventListener listener) {

mPointerEventDispatcher.unregisterInputEventListener(listener);

}

monitorInput()流程如下:InputManagerService.java monitorInput()

+--> nativeRegisterInputChannel(......, true);

+--> NativeInputManager::registerInputChannel()

+--> mInputManager->getDispatcher()->registerInputChannel() -->

status_t InputDispatcher::registerInputChannel(const sp& inputChannel,

const sp& inputWindowHandle, bool monitor) {

......

if (monitor) {

mMonitoringChannels.push(inputChannel);

}

......

}

个人笔记

数据的转存

从slot --> RawPointerData --> cookAndDispatch() cookPointerData()进一步处理将值给

mCurrentCookedState.cookedPointerData,主要为

cookedPointerData.pointerCoords cookedPointerData.pointerProperties

dispatchMotion()时参数传入cookedPointerData,进一步将数据封装为

NotifyMotionArgsdispatchMotion(when, policyFlags, mSource,

......

mCurrentCookedStat.cookedPointerData.pointerProperties,

mCurrentCookedStat.cookedPointerData.pointerCoords,

mCurrentCookedStat.cookedPointerData.idToIndex,

......TouchInputMapper::sync()

+-> syncTouch(when, next); --> 数据从slot到outState->rawPointerData.pointers[outCount];

+-> processRawTouches() --> cookAndDispatch() --> dispatchTouches() --> dispatchMotion()

数据处理完后将 NotifyMotionArgs 压入mArgsQueueTouchInputMapper::dispatchMotion() --> getListener()->notifyMotion(&args) -->

frameworks/native/services/inputflinger/InputListener.cpp

void NotifyMotionArgs::notify(const sp& listener) const {

listener->notifyMotion(this);

}

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {

mArgsQueue.push(new NotifyMotionArgs(*args));

}

数据从MultiTouchMotionAccumulator::Slot 转到 RawPointerData::Pointervoid MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {

size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();

......

for (size_t inIndex = 0; inIndex < inCount; inIndex++) {

const MultiTouchMotionAccumulator::Slot* inSlot =

mMultiTouchMotionAccumulator.getSlot(inIndex);

......

RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];

outPointer.x = inSlot->getX();

outPointer.y = inSlot->getY();

......

}

加工数据void TouchInputMapper::processRawTouches(bool timeout) {

....//在处理mRawStatesPending数据时,一个一个取出给mCurrentRawState,然后 cookAndDispatch进一步处理

for(count = 0; count < N; count++) {

const RawState& next = mRawStatesPending[count];

......//给mCurrentRawState

mCurrentRawState.copyFrom(next);

......//cookAndDispatch加工并分发

cookAndDispatch(mCurrentRawState.when);

void TouchInputMapper::cookPointerData() {

uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;

mCurrentCookedState.cookedPointerData.clear();

......//将数据进一步的处理,例如,计算旋转后的值

// Walk through the the active pointers and map device coordinates onto

// surface coordinates and adjust for display orientation.

for (uint32_t i = 0; i < currentPointerCount; i++) {

const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];

......

case DISPLAY_ORIENTATION_90:

x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;

y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;

......//将值给 cookedPointerData.pointerCoords

// Write output coords.

PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];

out.clear();

out.setAxisValue(AMOTION_EVENT_AXIS_X, x);

out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);

out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);

......//将值给 cookedPointerData.pointerProperties

// Write output properties.

PointerProperties& properties =

mCurrentCookedState.cookedPointerData.pointerProperties[i];

uint32_t id = in.id;

properties.clear();

properties.id = id;

properties.toolType = in.toolType;

// Write id index.

mCurrentCookedState.cookedPointerData.idToIndex[id] = i;

......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值