Android事件输入和传递系统
事件的产生和传递
- 按键事件
- 触摸事件
- 鼠标事件
- 轨迹球事件
InputEvent 输入事件的基类,派生两个类型的子类KeyEvent和TouchEvent。
整个事件处理流程如下:
事件采集(由Linux驱动支持) -> 前期处理(提取有用信息) -> WindowManagerService分发 -> 应用程序处理
这里主要搞清楚两个问题:
1、输入事件是怎么监听到的?
2、监听到事件是怎么分发到应用程序中的?
InputManagerService也是在system进程启动的。
//frameworks.base.services.java.com.android.server.SystemServer.java
private void startOtherServices() {
InputManagerService inputManager = null;
inputManager = new InputManagerService(context);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
}
//java.com.android.server.input.InputManagerService.java
public void start() {
Slog.i(TAG, "Starting input manager");
//mPtr指针是NativeInputManager实例,在其构造函数中初始化了InputManager。
//mPtr是在nativeInit函数中初始化的
nativeStart(mPtr);
...
}
//构造函数
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
//初始化NativeInputManager,同时初始化了InputManager
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
//frameworks.base.services.core.jni.com_android_server_input_InputManagerService.cpp
//NativeInputManager构造函数,初始化InputManager
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
}
mInteractive = true;
//EventHub用于监听输入事件
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
//启动InputManager,调用其start函数
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
事件采集
Native层的InputManager在创建后,会启动两个线程InputRenderThread和InputDispatcherThread。前者负责从驱动节点读取Event,后者负责分发这些事件。
//frameworks.base.services.inputflinger.InputManager.cpp
//构造函数
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
//InputDispatcher负责事件分发
mDispatcher = new InputDispatcher(dispatcherPolicy);
//InputReader负责事件采集,并发采集到事件经过处理后交给mDispatcher分发出去
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void InputManager::initialize() {
//构建两个线程
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
//启动两个线程,Android中Thread的实现就是pthread_create函数,
//线程创建后最终会调用threadLoop()函数
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
mDispatcherThread->requestExit();
return result;
}
return OK;
}
//frameworks.base.services.inputflinger.InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
void InputReader::loopOnce() {
//可以看到其核心是通过EventHub监听事件输入的,那么EventHub是怎么做到的呢?
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
if (count) {
//处理事件
processEventsLocked(mEventBuffer, count);
}
//将事件分发给监听者,也就是InputDispatcher
mQueuedListener->flush();
}
1.遍历/dev/input目录,为输入事件文件添加监听。
//事件输入目录,该目录下的每个文件都对应一个输入设备,文件名称样式为event0、event1...等等
static const char *DEVICE_PATH = "/dev/input";
status_t EventHub::scanDirLocked(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == NULL)
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;
}
//遍历出所有文件,并添加监听
status_t EventHub::openDeviceLocked(const char *devicePath) {
int fd = open(devicePath, O_RDWR | O_CLOEXEC);
...
//省略通过ioctl获取输入设备的名称、版本、标识、物理位置等信息。
...
//根据设备文件属性构造Device实例
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
//然后判断是什么类型的输入设备(多点触控板、单点触控板、蓝牙书写笔、游戏摇杆等)
//如果是键盘,还要加载键盘布局
// 使用epoll监听文件输入事件
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
if (mUsingEpollWakeup) {
eventItem.events |= EPOLLWAKEUP;
}
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
delete device;
return -1;
}
//添加到Device队列头部
addDeviceLocked(device);
}
那么,是什么时候触发的输入设备扫描呢?就是前面提到的getEvents函数中。
//读取输入事件,其中第二个参数RawEvent是一个输出参数,用来存储原始的事件数据
//返回值size_t代表读取到的事件个数
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
//
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer;
size_t capacity = bufferSize;
for (;;) {
//扫描输入设备
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
//监听设备文件发出输入事件
//mPendingEventItems是一个长度为16的epoll_event数组
//pollResult代表发生的事件个数
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//赋值给mPendingEventCount,代表有等待处理的事件
mPendingEventCount = size_t(pollResult);
//循环处理epoll事件
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//如果是输入事件,则从设备文件中读取事件数据
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
//将input_event转换成RawEvent
struct input_event& iev = readBuffer[i];
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
}
}
}
}
//RawEvent修改前后的差值就是事件个数
return event - buffer;
}
事件分发
InputReader获取到输入事件后,就会交给InputDispatcher去分发给合适的应用程序。
//构造函数
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
//InputDispatcher负责事件分发
mDispatcher = new InputDispatcher(dispatcherPolicy);
//InputReader负责事件采集,并发采集到事件经过处理后交给mDispatcher分发出去
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputDispatcher在创建之初就与InputReader建立了联系。当InputReader通过EventHub拿到事件后,返回到loopOnce()函数后,继续执行mQueuedListener->flush(),mQueuedListener是InputListenerInterface接口类型子接口,内部添加了一个flush()函数,InputDispatcher类就继承了InputListenerInterface接口。
在分给应用程序之前,会对原始输入事件进