Q1:android的输入事件从哪里来?
A1:从Input子系统中来,由EventHub来负责从Input系统中读取所有的事件
linux内核提供了一个Input子系统来实现的,Input子系统会在/dev/input/路径下创建我们硬件输入设备的节点
可以从/proc/bus/input/devices中读出eventXX相关的硬件设备
frameworks/native/services/inputflinger/
EventHub.cpp
1. 看构造方法:监听输入设备节点的删除和添加
static const char *DEVICE_PATH = "/dev/input";
EventHub::EventHub(void) {
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
// 利用inotify机制监听/dev/input目录下的IN_DELETE和IN_CREATE事件:监听输入设备节点的删除和添加
mINotifyFd = inotify_init();
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;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
// 通过管道实现唤醒方法:参考EventHub::wake()
int wakeFds[2];
result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
eventItem.data.u32 = EPOLL_ID_WAKE;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
}
2. 监听设备节点不是目的,获取这些设备的输入事件才是目的
当有EPOLL_ID_INOTIFY事件发生后,会触发EventHub::readNotifyLocked(),去call openDeviceLocked(devname)来添加设备
status_t EventHub::openDeviceLocked(const char *devicePath) {
// 又会去监听这个设备的所有EPOLLIN事件:就能够读取这个设备(devicePath,可能是dev/input/event0)的输入事件啦
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;
eventItem.data.u32 = deviceId;
epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem);
addDeviceLocked(device);
return 0;
}
// mDevices中保存里所有的输入设备
void EventHub::addDeviceLocked(Device* device) {
mDevices.add(device->id, device);
device->next = mOpeningDevices;
mOpeningDevices = device;
}
Q2:如果EventHub启动的不是足够早,会不会出现有些输入设备已经挂载好,因此不会通过inotify机制通知到EventHub
A2:可能,但是这种潜在的问题已被处理。
在构造方法中,mNeedToScanDevices(true),初始化为true
在第一次调用getEvents方法时,会走这条case,因此会主动去把当前所有已经挂载的输入设备都加载进来
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
}
void EventHub::scanDevicesLocked() {
status_t res = scanDirLocked(DEVICE_PATH);
}
Q3:哪一行代码是读入输入事件
A3:当然要找epoll_wait
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
}
Q3:EventHub运行在哪个进程的哪个线程,何时启动
A3:system_server进程,InputReaderThread这个线程,system_server创建InputManagerService的实例并调用它的start()方法后它就开始运行啦
1. systemserver启动InputManagerService
//创建InputManagerService的实例
inputManager = new InputManagerService(context);
//创建WindowManagerService的实例,并直接把inputManager传递给WMS
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
//设置WMS的InputMonitor作为IMS的callback,这意味着IMS会把得到的输入事件交给WMS去处理
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
//启动IMS
inputManager.start();
2. InputManagerService的创建和启动
//它需要创建一个HandlerThread去处理一些消息:比如 MSG_DELIVER_INPUT_DEVICES_CHANGED
//它像个Java层的傀儡,实际工作都在native层实现,需要call nativeInit,在native创建一个实例,并保存到mPtr中
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
}
//需要把HandlerThread中的Looper给到native,在native创建一个NativeInputManager,它才是核心,相当于native中的IMS
com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper());
return reinterpret_cast<jlong>(im);
}
//它需要一个context,因为在native需要通过call java的代码去获得些系统资源:PointerIcon
//它需要IMS的实例,因为它需要回调
//它需要mLooper,不清楚怎么使用的?
//最终要的是,它创建了EventHub的实例,它会去监听/dev/input目录下的IN_DELETE和IN_CREATE事件
//EventHub的getEvents是获取所有输入事件的唯一方法,注意,EventHub保存在InputManager中
//size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize)
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);
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
//InputManager是个重要的类,但也非常简单,它组合了EventHub和NativeInputManager
//且NativeInputManager有两重身份:ReaderPolicy+DispatcherPolicy
//这里启动了两个线程:InputReaderThread+InputDispatcherThread
nputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
//InputManagerService的启动其实也就是把这两个线程执行起来
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
return OK;
}
3. InputReaderThread
作为一个Thread,run方法被call后,就会去执行它的threadLoop方法,它的mReader就是InputReader
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
void InputReader::loopOnce() {
//读取一定数量的events,并交给相应的设备去处理
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
if (count) {
processEventsLocked(mEventBuffer, count);
}
//processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
//InputDevice* device = mDevices.valueAt(deviceIndex);
//device->process(rawEvents, count);
//设备有变化时,要通知NativeInputManager
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
//交给mDispatcher处理
mQueuedListener->flush();
}