当前位置: 首页 > wzjs >正文

幼儿园网站模板怎么做的百度视频

幼儿园网站模板怎么做的,百度视频,给个网站做导航违法吗,电脑路由器做网站服务器吗概述 在Android Input框架中,EventHub主要作用就是读取输入设备上报的event事件, 并将收集的事件提交给InputReader进行处理。本文主要描述了EventHub如何管理系统中的输入设备以及系统上报输入事件的处理流程。本文并没有细节展开描述每一个EventHub类的…

概述

        在Android Input框架中,EventHub主要作用就是读取输入设备上报的event事件, 并将收集的事件提交给InputReader进行处理。本文主要描述了EventHub如何管理系统中的输入设备以及系统上报输入事件的处理流程。本文并没有细节展开描述每一个EventHub类的实现方法和输入事件处理的代码细节,感兴趣的同学可以去分析一下Linux系统中input事件的获取和Linux input事件的组成等。

本文涉及的源码路径

frameworks/native/services/inputflinger/EventHub.cpp

frameworks/native/services/inputflinger/EventHub.h

frameworks/native/services/inputflinger/InputReader.cpp

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

EventHub数据结构

        在讲解EventHub的功能之前,我们先分析一下EventHub的数据结构组成。EventHub数据结构定义有如下两个类进行管理:

1、EventHubInterface

        虚拟基类定义,主要功能就是接口定义,里面都是纯虚函数, InputReader模块会直接调用这个虚拟类定义的函数接口获取输入设备的事件(通过C++的多态,实际调用EvenHub这个子类实现),部分核心函数定义如下所示:

class EventHubInterface : public virtual RefBase {
protected:EventHubInterface() { }virtual ~EventHubInterface() { }public:......virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;virtual int32_t getDeviceControllerNumber(int32_t deviceId) const = 0;virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;......virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;......virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,int32_t* outValue) const = 0;......
};

2、EventHub

        EventHubInterface子类的实现,管理Android系统输入设备,主要成员如下所示:

class EventHub : public EventHubInterface
{
public:EventHub();virtual uint32_t getDeviceClasses(int32_t deviceId) const;virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const;virtual int32_t getDeviceControllerNumber(int32_t deviceId) const;virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;......protected:virtual ~EventHub();
private:struct Device {Device* next;int fd; // may be -1 if device is virtualconst int32_t id;const String8 path;const InputDeviceIdentifier identifier;uint32_t classes;uint8_t keyBitmask[(KEY_MAX + 1) / 8];uint8_t absBitmask[(ABS_MAX + 1) / 8];uint8_t relBitmask[(REL_MAX + 1) / 8];......};......// Input设备管理容器KeyedVector<int32_t, Device*> mDevices;Device *mOpeningDevices;Device *mClosingDevices;......
};

EventHub类的功能:

        1、实现EventHubInterface的接口;

        2、管理系统的输入设备,并将系统中扫描到的输入设备根据设备id保存在mDevices容器中;

EventHub初始化

        1、EventHub对象的创建

                EventHub对象在InputManagerService服务的JNI方法中创建,如下所示:

NativeInputManager::NativeInputManager(jobject contextObj,jobject serviceObj, const sp<Looper>& looper) :mLooper(looper), mInteractive(true) {JNIEnv* env = jniEnv();/* 创建EventHub()用来获取事件获取*/sp<EventHub> eventHub = new EventHub();mInputManager = new InputManager(eventHub, this, this);
}

继续跟踪InputManager的初始化如下所示:

InputManager::InputManager(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {......mReader = new InputReader(eventHub, readerPolicy, mDispatcher);initialize();
}

        在InputManager对象的初始化中,eventHub作为InputReader的输入参数并最终在初始化InputReader的时候,赋值给InputReader的mEventHub。这个地方非常重要,因为事件获取的起点在InputReader中,InputReader会调用EventHubInterface的接口(子类实现就是EventHub),读取Android系统输入设备的事件后面进行详细讲解。

2、EventHub类的初始化

        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) {....../* 创建epoll 监控描述符 */mEpollFd = epoll_create(EPOLL_SIZE_HINT);/* 创建inotify ,监控/dev/input目录下文件的创建和删除 */mINotifyFd = inotify_init();int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);/* mINotifyFd文件描述符加入epoll监控 */struct epoll_event eventItem;memset(&eventItem, 0, sizeof(eventItem));eventItem.events = EPOLLIN;eventItem.data.u32 = EPOLL_ID_INOTIFY;result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);/* 创建管道 */int wakeFds[2];result = pipe(wakeFds);mWakeReadPipeFd = wakeFds[0];mWakeWritePipeFd = wakeFds[1];....../* 读管道描述符加入epoll监控 */eventItem.data.u32 = EPOLL_ID_WAKE;result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);......
}

EventHub对象的初始化,非常简单,主要完成如下的功能:

        a、创建epoll监控文件描述符, 监控EventHub中输入设备事件;

        b、使用Linux inotify机制,创建监控/dev/input/目录下的文件的创建和删除事件,并加入到epoll进行监控;

        c、创建管道,并且将读管道加入到epoll进行监控(这点地方为什么要创建管道呢,大家思考一下)

EventHub事件

        EventHub获取事件的起点位于InputReader线程,核心代码如下所示:

void InputReader::loopOnce() {......size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);......
}

直接调用EventHub的getEvents接口,获取系统的输入事件,getEvents的参数列表如下:

@timeoutMillis:epoll监控超时时间,如果在timeoutMilli还没有等到输入事件,epoll不在等待,进入超时逻辑处理

@buffer: 输出参数,将获取的系统输入事件,都保存在buffer中;

@bufferSize: 最大可保存输入事件缓存大小;

@return: 返回获取到的事件个数

        由于getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize)接口的实现里包含的逻辑比较多,我们进行分段进行分析

设备管理

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {....../* 死循环 */for (;;) {// Reopen input devices if needed.// 判断是否需要重现打开设备if (mNeedToReopenDevices) {....../* 关闭已经打开的设备,并且将待关闭的设备,挂入mClosingDevices设备链表 */closeAllDevicesLocked();mNeedToScanDevices = true;// 函数调用直接返回,InputReader线程再次调用该接口时,进入设备扫描逻辑break; // return to the caller before we actually rescan}......// 关闭挂入该链表的输入设备while (mClosingDevices) {Device* device = mClosingDevices;......mClosingDevices = device->next;/* 构造一个设备删除的事件 */event->when = now;event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;event->type = DEVICE_REMOVED;/* 指向下一个保存事件的位置  */event += 1;/* 删除管理设备的内存 */delete device;mNeedToSendFinishedDeviceScan = true;/* 如果没有缓存空间,保存删除设备事件了,直接调用返回 */if (--capacity == 0) {break;}}/*** 是否需要扫描设备,扫描到的每一个输入设备,都会加入EventHub 设备管理容器*/if (mNeedToScanDevices) {mNeedToScanDevices = false;scanDevicesLocked();mNeedToSendFinishedDeviceScan = true;}/*** 根据EventHub扫描的输入设备,并将每一个发现的设备构造一个event ADD事件保存在buffer中*/while (mOpeningDevices != NULL) {Device* device = mOpeningDevices;mOpeningDevices = device->next;event->when = now;event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;event->type = DEVICE_ADDED;event += 1;mNeedToSendFinishedDeviceScan = true;if (--capacity == 0) {break;}}/* 构造结束扫描事件 */if (mNeedToSendFinishedDeviceScan) {mNeedToSendFinishedDeviceScan = false;event->when = now;event->type = FINISHED_DEVICE_SCAN;event += 1;if (--capacity == 0) {break;}}

设备的管理代码片段,主要完成如下功能:

        1、扫描/dev/input/目录,将发现的每一个输入设备加入到EventHub进行管理;

        2、在获取事件的过程中可能有新的设备加入,并将这种情况,构造event事件保存在getEvents接口提供的输出buffer中;

事件获取

事件获取的代码片段,如下所示:

  /* 等待获取输入事件 */int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock/* 等待超时,直接返回 */if (pollResult == 0) {// Timed out.mPendingEventCount = 0;break;}/* 等待过程中,被异常打断 */if (pollResult < 0) {// An error occurred.mPendingEventCount = 0;// Sleep after errors to avoid locking up the system.// Hopefully the error is transient.// 等待被中断,稍微sleep一会儿,继续等待事件if (errno != EINTR) {ALOGW("poll failed (errno=%d)\n", errno);usleep(100000);}} else {// Some events occurred.// 有input事件上报,u获取上报的事件个数,保存在mPendingEventCount中mPendingEventCount = size_t(pollResult);}

主要完成如下功能:

        1、epoll进行监听,如果监听超时直接结束死循环函数调用返回;

        2、监听过程中被系统打断,如果这种情况,休眠一下继续监听;

        3、监听到输入事件,并获取事件个数保存在mPendingEventCount;

事件保存处理

        事件保存处理的代码比较多,下面只列出核心处理代码

// 处理获取到的事件数while (mPendingEventIndex < mPendingEventCount) {// 遍历每一个系统获取的事件const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];// /dev/input目录发生变化事件,一般是新设备的增加或者旧设备删除if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {if (eventItem.events & EPOLLIN) {mPendingINotify = true;} else {ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);}continue;}// 对于写入管道的事件,只消耗不处理if (eventItem.data.u32 == EPOLL_ID_WAKE) {if (eventItem.events & EPOLLIN) {ALOGV("awoken after wake()");awoken = true;char buffer[16];ssize_t nRead;do {nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));} else {ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",eventItem.events);}continue;}......// 找到上报事件的设备,并读取该设备上报的事件Device* device = mDevices.valueAt(deviceIndex);if (eventItem.events & EPOLLIN) {int32_t readSize = read(device->fd, readBuffer,sizeof(struct input_event) * capacity);if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {......} else if (readSize < 0) {......} else if ((readSize % sizeof(struct input_event)) != 0) {......} 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];... ... event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL+ nsecs_t(iev.time.tv_usec) * 1000LL;.....event->deviceId = deviceId;event->type = iev.type;event->code = iev.code;event->value = iev.value;event += 1;capacity -= 1;}// 没有缓存,进行保存了,直接结束死循环if (capacity == 0) {mPendingEventIndex -= 1;break;}}} else if (eventItem.events & EPOLLHUP) {......} else {ALOGW("Received unexpected epoll event 0x%08x for device %s.",eventItem.events, device->identifier.name.string());}}

对于事件保存处理代码片段,主要完成如下的功能:

        1、处理设备增加和删除事件;

        2、处理写入管道的事件;

        3、处理设备上报的事件,并将该事件保存在getEvents接口提供的输出buffer中;

事件处理收尾

当所有上报的事件处理完成后执行如下的代码片段跳出事件获取循环,代码片段如下所示:

 ...// 所有事件都处理完了,跳出死循环if (event != buffer || awoken) {break;}......// All done, return the number of events we read.// 返回保存到buffer中的事件数return event - buffer;}

        事件处理的收尾比较简单,所有的事件处理完成后返回获取到的事件和事件数,结束本轮的事件监听。

总结

        1、本文主要描述了EventHub输入设备的管理和事件获取流程描述,并没有细节上去描述;

        2、对于输入设备上报的事件,主要有getEvents接口处理,该接口处理的逻辑比较多,读者在分析代码的时候不要顺序去阅读这个函数实现;

        3、对于输入设备的管理并没有做详细的描述,处理核心的逻辑就是系统扫描到的输入设备创建Struct Device进行管理,并且将每一个输入设备根据它支持的事件类型进行分类。这个在后续讲解的InputReader会提及为什么要将输入设备分类。

http://www.dtcms.com/wzjs/101590.html

相关文章:

  • 做网站前端镇江市网站
  • 深圳制作网站全球搜索网站排名
  • 企业网站在哪里建惠州网络营销公司
  • 数据库网站建设多少钱b2b电子商务平台
  • 高端网站建设设计公司排名武汉网站建设
  • 成都华阳有没有做网站的网站交易网
  • 杭州外贸公司沧州seo包年优化软件排名
  • 服装设计画图软件app绍兴seo
  • 360建筑网注册规划师搜索引擎优化叫什么
  • 涪陵网站建设怎么做百度搜索排名
  • 一个域名可以绑定几个网站竞价广告是怎么推广的
  • 手机网站设计理念企业网站设计规范
  • 微网站制作网站优化推广排名
  • 膳食管理东莞网站建设技术支持2022百度指数排名
  • 上海网站建设公司哪家好东莞做网站推广的公司
  • 做销售在那个网站找杭州seo网站哪家好
  • 赣州网站推广企业查询系统官网
  • 湖南省长沙建设工程造价站网站关键词优化排名怎么做
  • 怎么把自己的网站推广武汉seo优化分析
  • 深圳宝安做网站的公司百度服务电话
  • 潍坊市安丘网站建设河北网站建设推广
  • 门户网站的基本特征a信息与服务怎样做搜索引擎推广
  • 怎样做动漫照片下载网站深圳百度网站排名优化
  • 婚纱摄影网站建设方案全网最低价24小时自助下单平台
  • 有网站如何做app营销软文范文
  • 免费高清logo优化网站服务
  • 深圳网站建设创造者亚马逊排名seo
  • 经营类网页游戏大全网络营销推广优化
  • 网站方案怎么写珠海网站建设
  • 温州企业网站设计爱战网关键词挖掘