InputManagerService源码分析二:初始化
前言
android系统服务很多实现都是在C端实现的,Input也不例外。Input系统java层主要类是InputManagerService, C层实现类为NativeInputManager。
其中NativeInputManager中有两个类:InputReader和InputDispatcher。InputReader故名思议,主要负责input事件的监听,也负责input设备的监听(添加、删除)。InputDispatcher主要负责输入事件的分发。
一、InputManagerService
InputManagerService是在系统进程system_process进程中创建的,SystemServer类是system_process启动后,从C++层调用创建的。InputManagerService是在SystemServer.java中startOtherServices()内创建的,代码如下所示(本章事例代码为Android 10,为了便于理解,本章节展示的均为精简后的代码)。
startOtherServices(){
...
InputManagerService inputManager = null;
WindowManagerService wm = null;
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
...
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
...
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
}
从上图可以看出InputManagerService与WindowManagerService有不少联系,android事件分发主要是基于window的,window是WindowManagerService管理的,这就很容易理解了。这里暂不做赘述,后续章节会从功能、流程上介绍两者之间关系。
InputManagerServie构造方法如下所示:
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());
}
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
可以看出nativeInit()方法是一个native方法。我们接着看下native层的实现。
二、NativeInputManager
native层nativeinit()方法代码如下:
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == nullptr) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
从代码可以看出C++层创建了一个NativeInputManager实例。NativeInputManager类声明如下,我们截取部分代码。
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface {
void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId);
void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj);
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<IBinder>& token,
const std::string& reason);
virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
}
可以猜测NativeInputManager的部分功能包括:焦点变更Input层处理、ANR识别、按键前处理等。接下来我们分析下NativeInputManager。
NativeInputManager初始化代码如下所示,可以看出在NativeInputManager内部创建了一个InputManager实例,并把它添加到ServiceManager中,可以看出InputManager是一个C层的BinderService。接下来我们看一下InputManager的创建。
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mServiceObj = env->NewGlobalRef(serviceObj);
...
mInputManager = new InputManager(this, this);
defaultServiceManager()->addService(String16("inputflinger"),
mInputManager, false);
}
2.1 InputManager
InputManager的头文件和Cpp文件的目录frameworks\native\services\inputflinger。
InputManager类申明如下:
frameworks\native\services\inputflinger\InputManager.cpp
class InputManager : public InputManagerInterface, public BnInputFlinger {
protected:
virtual ~InputManager();
public:
InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy);
virtual status_t start();
virtual status_t stop();
virtual sp<InputReaderInterface> getReader();
virtual sp<InputClassifierInterface> getClassifier();
virtual sp<InputDispatcherInterface> getDispatcher();
virtual void setInputWindows(const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener);
virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
virtual void registerInputChannel(const sp<InputChannel>& channel);
virtual void unregisterInputChannel(const sp<InputChannel>& channel);
private:
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
sp<InputClassifierInterface> mClassifier;
sp<InputDispatcherInterface> mDispatcher;
sp<InputDispatcherThread> mDispatcher;
void initialize();
};
我们可以看出
1)InputManager继承了BnInputFlinger ,可以看出他的确是一个Binder服务。后续章节我们会结合Surface系统,通过一个简单的程序,可以更加清晰的理解这两个系统。
2)InputManager内部成员变量属性 InputReaderInterface 、InputReaderThread、InputDispatcherInterface、InputDispatcherThread。他们 是Input系统的工作类和工作线程。下面我会详细的介绍这几个类。为了便于理解本章暂不介绍mClassifier。
2.1.1 InputReader、InputDispatcher创建
从InputManager的构造函数,可以看出它内部创建了InputReader、InputDispatcher。创建InputReader构造方法中有一个形参EventHub,它负责监听外部设备的挂载、删除和输入设备输入监听。
frameworks\native\services\inputflinger\InputManager.cpp
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
initialize();
}
frameworks\native\services\inputflinger\InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
return new InputReader(new EventHub(), policy, listener);
}
2.1.2 InputReaderThread、InputReaderThread线程创建
InputManager工作线程mReaderThread、mDispatcherThread是在InputManager构造方法中创建,如下代码所示。
frameworks\native\services\inputflinger\InputManager.cpp
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputReaderThread(mDispatcher);
}
InputReaderThread实现代码如下:
frameworks\native\services\inputflinger\include\InputReaderBase.h
class InputReaderThread : public Thread {
public:
explicit InputReaderThread(const sp<InputReaderInterface>& reader);
virtual ~InputReaderThread();
private:
sp<InputReaderInterface> mReader;
virtual bool threadLoop();
};
frameworks\native\services\inputflinger\InputReaderBase.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
InputDispatcherThread实现代码如下:
frameworks\native\services\inputflinger\InputDispatcher.h
class InputDispatcherThread : public Thread {
public:
explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);
~InputDispatcherThread();
private:
virtual bool threadLoop();
sp<InputDispatcherInterface> mDispatcher;
}
frameworks\native\services\inputflinger\InputDispatcher.cpp
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
InputReaderThread 和InputDispatcherThread都继承自android自定义Thread,threadLoop中返回true,代表着他们方法结束了会继续执行,即轮询。
2.1.3 InputReaderThread、InputReaderThread线程启动
上一节介绍了Input C层工作线程的创建,下面介绍工作线程的启动。
Setp 1: SystemServer中调用inputManager.start():
Setp 2: InputManagerService中调用native方法nativeStart()进入native层:
frameworks\base\services\java\com\android\server\SystemServer.java
startOtherServices(){
...
inputManager.start();
...
}
frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
....
}
Setp 3: C层获取InputManager实例,调用start()方法:
Setp 4: InputManager中开启read和dispatcher线程,进入循环。
frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
frameworks\native\services\inputflinger\InputManager.cpp
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
2.1.4 InputManagerService初始化时序图
2.2 EventHub
上一节介绍InputReader构造方法的时候,提及了EventHub。这一节我们介绍EventHub。EventHub,可以翻译成事件中心。之所以把EventHub单独成一小节介绍,主要是EventHub在Input系统中起着至关重要的作用。它的主要职责就是:
1)输入设备的添加、删除。
2)输入设备的监听。
2.2.1 EventHub若干方法
Eventhub的头文件和cpp文件在目录frameworks\native\services\inputflinger\下。EventHub.h部分代码如下:
class EventHub : public EventHubInterface
{
public:
EventHub();
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
virtual void monitor();
protected:
virtual ~EventHub();
private:
struct Device {
Device* next;
int fd; // may be -1 if device is closed
const int32_t id;
const std::string path;
const InputDeviceIdentifier identifier;
uint32_t classes;
Device(int fd, int32_t id, const std::string& path,
const InputDeviceIdentifier& identifier);
~Device();
void close();
status_t enable();
status_t disable();
};
status_t openDeviceLocked(const char* devicePath);
void addDeviceLocked(Device* device);
void configureFd(Device* device);
status_t registerFdForEpoll(int fd);
status_t unregisterFdFromEpoll(int fd);
status_t scanDirLocked(const char *dirname);
void scanDevicesLocked();
status_t readNotifyLocked();
// Protect all internal state.
mutable Mutex mLock;;
int mEpollFd;
int mINotifyFd;
int mWakeReadPipeFd;
int mWakeWritePipeFd;
int mInputWd;
};
这里简要介绍几个方法,后面会详细介绍各个方法:
1)getEvents(): 主要是做事件识别;
2)processEventsLocked():主要是做事件处理;
2 ) scanDirLocked():检索/dev/input目录下的挂载输入设备,系统初始化的时候读取后,将输入设备封装成Device,存储在EventHub中;
3) readNotifyLocked():设备添加、删除后的处理方法,接受到iNotify事件后调用的方法。主要是做新挂载、删除设备的监听与删除;
4)processEventsForDeviceLocked():输入设备操作数据处理类,下一章事件分发的时候我们再来分析这个类。
2.2.2 EventHub初始化
这一节我们阅读EventHub的构造方法,代码如下:
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(nullptr), mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
mINotifyFd = inotify_init();
mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
DEVICE_PATH, strerror(errno));
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.fd = mINotifyFd;
//添加文件创建、删除监听
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
...
}
上面的代码主要是实现了挂载设备的监听、和Looper的唤醒,使用了Linux epoll和iNotify机制。对这两种机制不了解的,可以看下我之前的博客InputManagerService源码分析一
2.3 InputReader
InputManager开启工作线程后,InputReaderThread进入轮询,从上节可以知道InputReaderThread会调用InputReader的loopOnce方法。
2.3.1 loopOnce方法
InputReader的loopOnce()方法代码如下。
void InputReader::loopOnce() {
...
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
...
{ // acquire lock
AutoMutex _l(mLock);
if (count) {
processEventsLocked(mEventBuffer, count);
}
} // release lock
...
}
其中有两个关键方法
1)getEvents() :读取事件、封装事件 。
2)processEventsLocked():处理事件。
2.3.2 事件处理
这一章我们分析Input系统的事件读取处理流程。事件读取的部分代码如下所示。
frameworks\native\services\inputflinger\EventHub.cpp
size_t EventHub::getEvents(int timeoutMills,RawEvent* buffer,size_t bufferSize)
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
//流程一:设备检索,开始
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
while (mOpeningDevices != nullptr) {
Device* device = mOpeningDevices;
ALOGV("Reporting device opened: id=%d, name=%s\n",
device->id, device->path.c_str());
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;
}
}
//流程一:设备检索结束
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//流程二,输入设备添加删除
if (eventItem.data.fd == mINotifyFd) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
Device* device = getDeviceByFdLocked(eventItem.data.fd);
if (!device) {
ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.",
eventItem.events, eventItem.data.fd);
ALOG_ASSERT(!DEBUG);
continue;
}
// This must be an input event
//流程三:输入设备输入事件
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
" bufferSize: %zu capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
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];
event->when = processEventTimestamp(iev);
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1;
break;
}
}
} else if (eventItem.events & EPOLLHUP) {
ALOGI("Removing device %s due to epoll hang-up event.",
device->identifier.name.c_str());
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.",
eventItem.events, device->identifier.name.c_str());
}
}
// readNotify() will modify the list of devices so this must be done after
// processing all other events to ensure that we read all remaining events
// before closing the devices.
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
// Report added or removed devices immediately.
if (deviceChanged) {
continue;
}
// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) {
break;
}
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
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.
if (errno != EINTR) {
ALOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
// Some events occurred.
mPendingEventCount = size_t(pollResult);
}
}
// All done, return the number of events we read.
return event - buffer;
}
代码中我们标注了三种事件流程:流程一:设备检索流程; 流程二:设备添加、删除流程; 流程三:输入设备输入事件。接下来我们介绍下这三种不同的事件处理了流程。
2.3.2.1 设备检索
我们首先看下流程一的第一部分代码:
frameworks\native\services\inputflinger\EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
...
for (;;) {
...
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
}
从代码中可以看出mNeedToScanDevices为true时,会进入设备检索流程。mNeedToScanDevices在构造方法中设置为ture;所以线程启动后必然会调用检索设备流程。
frameworks\native\services\inputflinger\EventHub.cpp
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(nullptr), mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false)
**step 1:**遍历/dev/input下的挂载文件:
frameworks\native\services\inputflinger\EventHub.cpp
//scanDevicesLocked方法最终调用scanDirLocked方法检索input目录
status_t EventHub::scanDirLocked(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == nullptr)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) {
if(de->d_name[0] == '.' &&
(de->d_name[1] == '\0' ||
(de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
openDeviceLocked(devname);
}
closedir(dir);
return 0;
}
step 2: 读取、分析挂载设备信息,将数据封成Device,存储在EventHub中。因为这个过程涉及代码量比较大,我们这边截取部分关键代码,帮助我们分析这个流程。
1)读取设备信息封装成identifier,封装成Device对象:
frameworks\native\services\inputflinger\EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
//获取检索到的挂载设备句柄
int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
...
InputDeviceIdentifier identifier;
...
// Get device name.
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name = buffer;
}
...
if(ioctl(fd, EVIOCGID, &inputId)) {
ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;
Device* device = new Device(fd, deviceId, devicePath, identifier);
...
}
2)通过ioctl(fd, EVIOCGBIT(0, EV_MAX), buf),获取设备支持哪些事件(EV_KEY、EV_REL和EV_ABS等):
frameworks\native\services\inputflinger\EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
...
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);
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
}
3)设备掩码分析,判断设备支持哪些类型:
根据absBitmask判断设备是否支持屏幕输入。Device的成员变量classes 比较重要,后续介绍processEventsLocked方法的时候会介绍。其他设备的判断这里暂不做介绍。
frameworks\native\services\inputflinger\EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
...
if (test_bit(ABS_MT_POSITION_X, device->absBitmask)
&& test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
// Some joysticks such as the PS3 controller report axes that conflict
// with the ABS_MT range. Try to confirm that the device really is
// a touch screen.
if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
}
// Is this an old style single-touch driver?
}
...
}
4)挂载设备监听:
registerFdForEpoll方法内通过epoll_ctl方法将文件fd添加到mEpollFd监听。
frameworks\native\services\inputflinger\EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
...
if (registerDeviceForEpollLocked(device) != OK) {
delete device;
return -1;
}
...
}
//registerDeviceForEpollLocked方法最终调用了registerFdForEpoll方法
status_t EventHub::registerFdForEpoll(int fd) {
// TODO(b/121395353) - consider adding EPOLLRDHUP
struct epoll_event eventItem = {};
eventItem.events = EPOLLIN | EPOLLWAKEUP;
eventItem.data.fd = fd;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
ALOGE("Could not add fd to epoll instance: %s", strerror(errno));
return -errno;
}
return OK;
}
5 )将封装的Device实例,保存到EventHub中,并将device赋值给mOpeningDevice。这样做的目的是为了将数据封装成RawEvent(Setp 3),为了后续的事件处理。
frameworks\native\services\inputflinger\EventHub.cpp
void EventHub::addDeviceLocked(Device* device) {
mDevices.add(device->id, device);
device->next = mOpeningDevices;
mOpeningDevices = device;
}
step 3: 将封装后Device数据转换成RawEvent数据,代码如下:
frameworks\native\services\inputflinger\EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
while (mOpeningDevices != nullptr) {
Device* device = mOpeningDevices;
ALOGV("Reporting device opened: id=%d, name=%s\n",
device->id, device->path.c_str());
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;
}
}
...
}
留意下event的成员变量type,后续step 5会以type为依据执行不同的操作。
step 5: 事件分析(判断、处理):
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;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
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;
}
}
Step 6: 封装输入设备处理实体InputDevice,将其存储在InputReader中。
本章暂不分析removeDeviceLocked,他的处理逻辑可以参照设备添加逻辑。这里用到了classes这个类型,这里可以看出根据不同的类型,创建了各种映射对象。下一章事件分发我们会详细的介绍各个Mapper的实现。
frameworks\native\services\inputflinger\InputReader.cpp
//addDeviceLocked内部的主要方法为createDeviceLocked
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, uint32_t classes) {
InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
controllerNumber, identifier, classes);
...
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
device->addMapper(new SwitchInputMapper(device));
}
...
// Keyboard-like devices.
uint32_t keyboardSource = 0;
...
if (keyboardSource != 0) {
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
}
...
// 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));
}
return device;
}
设备检索流程图如下所示:
2.3.2.2 设备添加、删除
有了上一节分析设备检索的基础,分析设备删除就会显得比较简单。添加与删除与检索不同之处在于:输入源不同。检索的数据源是通过遍历目录获取的,添加与删除的数据源是通过epoll获取到的。
我们可以分 三步分析它:代码中可以标注了它们的位置
Step 1:事件读取;
Step 2:事件识别;
Step 3:事件处理。
frameworks\native\services\inputflinger\EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
...
for (;;) {
...
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//Step 2 添加、删除事件识别
if (eventItem.data.fd == mINotifyFd) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
...
//Step 3 添加、删除事件处理
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
...
//Step 1 添加、删除事件读取
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
}
...
}
status_t EventHub::readNotifyLocked() {
int res;
char event_buf[512];
int event_size;
int event_pos = 0;
struct inotify_event *event;
ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);
//读取inotify fd中数据
res = read(mINotifyFd, event_buf, sizeof(event_buf));
...
while(res >= (int)sizeof(*event)) {
event = (struct inotify_event *)(event_buf + event_pos);
if(event->len) {
if (event->wd == mInputWd) {
//挂载、删除设备名称拼接
std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
if(event->mask & IN_CREATE) {
//添加设备处理:解析、监听
openDeviceLocked(filename.c_str());
} else {
ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
//删除设备事件处理
closeDeviceByPathLocked(filename.c_str());
}
}
...
}
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
}
return 0;
}
readNotifyLocked会根据事件类型对设备进行两种操作:
1)事件类型为创建:调用openDeviceLocked进行设备的解析与监听(详见2.3.2.1 Step1);
2)事件类型为非创建:做设备删除操作(删除EventHub中对应的Device对象,移除设备文件监听,这里暂不分析)。
后续流程可以参考2.3.2.1。添加、删除事件处理流程图如下所示。
2.3.2.3 设备输入数据
设备输入事件的分析我们在下一章,InputManagerService事件分发中介绍。
2.4 InputDispatcher
事件分发在下一章,InputManagerService事件分发中介绍。
总结
InputManagerService的初始化工作到这里就介绍完毕了,下一节我们介绍InputManagerService事件的分发。