Androiod Input event

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









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值