Input子系统架构包括内核层与框架层详解.doc

上传人:文库蛋蛋多 文档编号:2387989 上传时间:2023-02-17 格式:DOC 页数:42 大小:243KB
返回 下载 相关 举报
Input子系统架构包括内核层与框架层详解.doc_第1页
第1页 / 共42页
Input子系统架构包括内核层与框架层详解.doc_第2页
第2页 / 共42页
Input子系统架构包括内核层与框架层详解.doc_第3页
第3页 / 共42页
Input子系统架构包括内核层与框架层详解.doc_第4页
第4页 / 共42页
Input子系统架构包括内核层与框架层详解.doc_第5页
第5页 / 共42页
点击查看更多>>
资源描述

《Input子系统架构包括内核层与框架层详解.doc》由会员分享,可在线阅读,更多相关《Input子系统架构包括内核层与框架层详解.doc(42页珍藏版)》请在三一办公上搜索。

1、第1章 Android Input子系统架构1.1 Input服务的启动在Android的开机过程中,系统中的服务很多都是由SystemServer中启动的。SystemServer的代码中有这么一句话。Framework/base/services/java/com/android/server/SystemServer.javaSlog.i(TAG, Window Manager); wm = WindowManagerService.main(context, power, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,!first

2、Boot);在这里new了一个WindowManagerService的类,我们找到这个类的构造函数。Framework/base/services/java/com/android/server/wm/WindowManagerServer.javaprivate WindowManagerService(Context context, PowerManagerService pm, boolean haveInputMethods, boolean showBootMsgs) mInputManager = new InputManager(context, this);mInputMa

3、nager.start();在WindowManagerService的构造函数中又new了一个InputManager类。InputManager类是整个android的input的上层代码最重要的类,就是通过这个类繁衍出了整个复杂的Android的input子系统。作用就好像Zygote的孕育着Android的各个服务,而InputManager就是负责将整个android的Input子系统。Framework/base/services/java/com/android/server/wm/WindowManagerServer.javapublic InputManager(Conte

4、xt context, WindowManagerService windowManagerService) Looper looper = windowManagerService.mH.getLooper();nativeInit(mContext, mCallbacks, looper.getQueue();在InputManger的构造函数中,调用了nativeInit这个方式,看到native开头或者结尾的函数,一般都是JNI。在InputManager的JNI可以找到这个函数的实现。Framework/base/services/jni/com_android_server_Inp

5、utManager.javastatic JNINativeMethod gInputManagerMethods = nativeInit, (Landroid/content/Context;Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V, (void*) android_server_InputManager_nativeInit ,简单介绍下JNI的代码风格,第一个引号括起来的函数就是我们java代码的函数原型,中间的引号中的就是代表java原型函数的参数。而最后的那个函数就是在对应的函

6、数。一般都是c+代码。Framework/base/services/jni/com_android_server_InputManager.javastatic void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz, jobject contextObj, jobject callbacksObj, jobject messageQueueObj) gNativeInputManager = new NativeInputManager(contextObj, callbacksObj, looper);在

7、JNI的代码中,又构造了一个重要的NativeInputManager类,这是个C+的本地类。已经不在是之前了那个java的InputManager类。接下来看看NativeInputManager的构造函数。Framework/base/services/jni/com_android_server_InputManager.javaNativeInputManager:NativeInputManager(jobject contextObj, jobject callbacksObj, const sp& looper) :mLooper(looper) sp eventHub = ne

8、w EventHub(); mInputManager = new InputManager(eventHub, this, this);这里new了两个类,EventHub和InputManager类。EventHub就是Input子系统的HAL层了,负责将linux的所有的input设备打开并负责轮询读取他们的上报的数据,后面会详细介绍,这里先简单介绍一下。InputManager类主要是负责管理input Event,有InputReader从EventHub读取事件,然后交给InputDispatcher进行分发。Framework/base/services/input/InputM

9、anager.cppInputManager:InputManager( const sp& reader, const sp& dispatcher) : mReader(reader), mDispatcher(dispatcher) initialize();void InputManager:initialize() mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher);在InputManager中的initialize的初始化

10、了两个线程。一个是inputReaderThread,负责从EventHub中读取事件,另外一个是InputDispatcherThread线程,主要负责分发读取的事件去处理。Framework/base/services/java/com/android/server/wm/WindowManagerServer.javaprivate WindowManagerService(Context context, PowerManagerService pm, boolean haveInputMethods, boolean showBootMsgs) mInputManager.start

11、();在开始的时候,new了一个InputManager,然后在继续调用其start方法。Framework/base/services/java/com/android/server/wm/WindowManagerServer.javapublic void start() Slog.i(TAG, Starting input manager); nativeStart(); registerPointerSpeedSettingObserver(); registerShowTouchesSettingObserver(); updatePointerSpeedFromSettings(

12、); updateShowTouchesFromSettings(); NativeStart()跑到JNI的代码中去了,跟上面的方式一样。Framework/base/services/jni/com_android_server_InputManager.javastatic JNINativeMethod gInputManagerMethods = nativeStart, ()V, (void*) android_server_InputManager_nativeStart ,static void android_server_InputManager_nativeStart(J

13、NIEnv* env, jclass clazz) status_t result = gNativeInputManager-getInputManager()-start();在java代码中用了nativeStart(),然后JNI中又调用了NativeInputManager的start方法。在Native的InputManager中找到start的实现。Framework/base/services/input/InputManager.cppstatus_t InputManager:start() status_t result = mDispatcherThread-run(I

14、nputDispatcher, PRIORITY_URGENT_DISPLAY);result = mReaderThread-run(InputReader, PRIORITY_URGENT_DISPLAY);这个方法就是在前面InputManager中的构造函数initialize中的两个线程运行起来。先看InputDispatcher线程运行的情况,然后就是InputReader线程。Framework/base/services/input/InputDispatcher.cppbool InputDispatcherThread:threadLoop() mDispatcher-di

15、spatchOnce(); return true;InputDispatcher线程调用了Dispatcher的dispatchOnce的方法。同样的InputReader线程也会调用Reader的ReaderOnce的方法。Framework/base/services/input/InputDispatcher.cppvoid InputDispatcher:dispatchOnce() dispatchOnceInnerLocked(&nextWakeupTime); int timeoutMillis = toMillisecondTimeoutDelay(currentTime,

16、nextWakeupTime); mLooper-pollOnce(timeoutMillis);dispatchOnceInnerLocked是处理input输入消息,mLooper-pollOnce(timeoutMillis)是等待下次输入消息的事件。先看下消息在dispatchOnceInnerLocked函数中是如何处理的。Framework/base/services/input/InputDispatcher.cppvoid InputDispatcher:dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) case EventEnt

17、ry:TYPE_KEYdone = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);case EventEntry:TYPE_MOTION: done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);这个函数比较长,input事件在android的上层通过两个队列来保存,分别是InboundQueue和outboundQueue。当有input事件产生时候,会判断InboundQueue是否为空

18、,如果事件不为空的话,就从队列中取出这个input事件,然后根据input事件的类型来分发事件给不同的处理函数,比较常见的是KEY和Motion事件。不管是Key事件也好还是Motion事件都会调用dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);这个函数来继续处理。Framework/base/services/input/InputDispatcher.cppvoid InputDispatcher:dispatchEventToCurrentInputTargetsLocked(nsecs_t curr

19、entTime, EventEntry* eventEntry, bool resumeWithAppendedMotionSample) prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget, resumeWithAppendedMotionSample);在这个函数中会继续调用prepareDispatchCycleLocked方法来继续处理。而在prepareDispatchCycleLocked中又会继续调用startDispatchCycleLocked(currentTime, c

20、onnection)来进一步处理。Framework/base/services/input/InputDispatcher.cppvoid InputDispatcher:startDispatchCycleLocked(nsecs_t currentTime, const sp& connection) switch (eventEntry-type) case EventEntry:TYPE_KEY: status = connection-inputPublisher.publishKeyEventcase EventEntry:TYPE_MOTION: status = connec

21、tion-inputPublisher.publishMotionEventstatus = connection-inputPublisher.sendDispatchSignal();这个函数主要是根据input事件的类型来分发给不同的函数去处理,如果是KEY类型的事件就调用inputPublisher类的publishKeyEvent,如果是MOTION类的事件就会调用inputPublisher类的publishMotionEvent方法。并在最后发一个sendDispatchSignal。Framework/base/libs/ui/InputTransport.cppstatus_

22、t InputPublisher:publishInputEvent(int ashmemFd = mChannel-getAshmemFd();int result = ashmem_pin_region(ashmemFd, 0, 0);mSemaphoreInitialized = true; mSharedMessage-consumed = false; mSharedMessage-type = type; mSharedMessage-deviceId = deviceId;mSharedMessage-source = source;利用publisher中的publishInp

23、utEvent将input event写入共享内存。这边产生了事件,另外一边必然会有个地方回去消费这个事件。注意到上面的代码中,最后发送了一个sendDispatchSignal。Framework/base/libs/ui/InputTransport.cppstatus_t InputPublisher:sendDispatchSignal() return mChannel-sendSignal(INPUT_SIGNAL_DISPATCH);这个函数直接调用了inputChannel的sendSignal方法。继续找到inputChannel的sendSignal实现。Framework

24、/base/libs/ui/InputTransport.cppstatus_t InputChannel:sendSignal(char signal) do nWrite = :write(mSendPipeFd, & signal, 1); while (nWrite = -1 & errno = EINTR);而在注册InputChannel的时候就曾经注册了当Looper接收到了信号的一个回调函数。Framework/base/services/input/InputDispatcher.cppstatus_t InputDispatcher:registerInputChannel

25、(const sp& inputChannel, const sp& inputWindowHandle, bool monitor) mLooper-addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);在handleReceiveCallback中,作为回调函数然后调用InputConsumer的consume函数来消费从inputReader中读取过来的InputEvent。Framework/base/core/jni/android_view_InputQueue.cppint NativeInpu

26、tQueue:handleReceiveCallback(int receiveFd, int events, void* data) status = connection-inputConsumer.consume(& connection-inputEventFactory, & inputEvent);回过头来看之前的InputReader线程,在inputManager的start方法被调用了,Input的线程也就开始运行了。Framework/base/services/input/InputReader.cppbool InputReaderThread:threadLoop()

27、 mReader-loopOnce(); return true;在InputReader的loopOnce中会调用EventHub的getevents方法。这个方法会和linux内核的input子系统打交道。Framework/base/services/input/InputReader.cppvoid InputReader:loopOnce() size_t count = mEventHub-getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);if (count) processEventsLocked(mEventBu

28、ffer, count); 这个函数主要通过EventHub的getEvents来获取input事件。Framework/base/services/input/EventHub.cppsize_t EventHub:getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) struct input_event readBufferbufferSize;for (;) if (mNeedToScanDevices) mNeedToScanDevices = false; scanDevicesLocked(); mNee

29、dToSendFinishedDeviceScan = true; 在eventHub初始化的时候mNeedToScanDevices的值是ture的,所以会直接进入到scanDevicesLocked。而在内核里面所有的input device在注册的时候都会在linux的文件系统下的/dev/input 下面,所以按照一般的HAL的思想,如果要去操作这个设备,首先还是要打开这个设备节点的。Framework/base/services/input/EventHub.cppvoid EventHub:scanDevicesLocked() status_t res = scanDirLock

30、ed(DEVICE_PATH); if(res 0) LOGE(scan dir failed for %sn, DEVICE_PATH); status_t EventHub:scanDirLocked(const char *dirname)openDeviceLocked(devname);代码中的while循环会对DEVICE_PATH(/dev/input)下的所有的设备节点调用openDeviceLocked方法。Framework/base/services/input/EventHub.cppstatus_t EventHub:openDeviceLocked(const ch

31、ar *devicePath) int fd = open(devicePath, O_RDWR);InputDeviceIdentifier identifier;if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) next = mOpeningDevices; mOpeningDevices = device;return 0;首先通过open系统调用得到设备节点的文件描述符,然后新构造一个叫InputDeviceIdentifier类。接着通过对刚才得到的设备节点描述下ioctl的命令获取设备的一些简单信息,譬如:设备的名字,设备驱

32、动的版本号,设备的唯一id,和描述符轮询的方式。得到的这些信息保存在InputDeviceIdentifier类里面。最后又构造了一个Device类,其中设备描述符和刚才的构造InputDeviceIdentifier类作为参数重新构造了Device类。然后在构造成功了Device类又会通过ioctl系统调用获取input设备的一些比较重要的参数。比如:设备上报事件的类型是相对事件还是绝对事件,相对事件一般是指像鼠标滑动,绝对事件就好比触摸屏上报的坐标,设备所属的class等一些比较重要的信息。举一些例子:INPUT_DEVICE_CLASS_KEYBOARD(按键类型),INPUT_DEVI

33、CE_CLASS_CURSOR(带游标类型:鼠标和轨迹球等),INPUT_DEVICE_CLASS_TOUCH(触摸类型:单点触摸或多点触摸),INPUT_DEVICE_CLASS_TOUCH_MT(这个类型特指多点触摸)等。如果一个设备的驱动没有指明设备的类型的话,那么他在android中上报的数据时不会被处理的。这个函数的最后是将input设备的文件描述符加入到轮询的集合中去,如果接收到事件就会去处理。Framework/base/services/input/InputReader.cppvoid InputReader:loopOnce() size_t count = mEventH

34、ub-getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);if (count) processEventsLocked(mEventBuffer, count); 回到之前的InputReader的线程中,通过EventHub的getevents方法得到了input事件。函数返回的是获取的事件数目。如果事件不为零或者负数就会调用processEventLocked来处理。Framework/base/services/input/InputReader.cppvoid InputReader:processEventsLocked

35、(const RawEvent* rawEvents, size_t count) processEventsForDeviceLocked(deviceId, rawEvent, batchSize);case EventHubInterface:DEVICE_ADDED: addDeviceLocked(rawEvent-when, rawEvent-deviceId);case EventHubInterface:DEVICE_REMOVED: removeDeviceLocked(rawEvent-when, rawEvent-deviceId);case EventHubInterf

36、ace:FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent-when);在处理input的事件时候,如果不是设备的添加,删除和完成扫描的时候。就会调用processEventsForDeviceLocked来处理。Framework/base/services/input/InputReader.cppvoid InputReader:processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) devic

37、e-process(rawEvents, count);这个函数也很简单直接回调了device的process方法来进行处理,这个device就是在之前的eventHub打开设备时候构造了一个device类。下面来具体看看device的process是如何进行处理的。Framework/base/services/input/InputReader.cppvoid InputDevice:process(const RawEvent* rawEvents, size_t count) for (size_t i = 0; i process(rawEvent); 这里直接调用了mapper的p

38、rocess。那InputMapper是什么时候初始化的呢?前面提到如果设备不是设备的添加或删除的时候就调用processEventsForDeviceLocked来处理。也就是说当设备第一次添加的时候,就会调用addDeviceLocked。InputMapper就是从这个地方注册过来的。具体看下面的代码:Framework/base/services/input/InputReader.cppvoid InputReader:addDeviceLocked(nsecs_t when, int32_t deviceId) InputDevice* device = createDeviceL

39、ocked(deviceId, name, classes);InputDevice* InputReader:createDeviceLocked(int32_t deviceId,const String8& name, uint32_t classes) InputDevice* device = new InputDevice(&mContext, deviceId, name, classes);if (classes & INPUT_DEVICE_CLASS_SWITCH) device-addMapper(new SwitchInputMapper(device);if (cla

40、sses & INPUT_DEVICE_CLASS_CURSOR) device-addMapper(new CursorInputMapper(device);if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) device-addMapper(new MultiTouchInputMapper(device); else if (classes & INPUT_DEVICE_CLASS_TOUCH) device-addMapper(new SingleTouchInputMapper(device);if (classes & INPUT_DEVICE_

41、CLASS_JOYSTICK) device-addMapper(new JoystickInputMapper(device);return device;从上面的代码可以非常明显的看出,InputMapper是根据inputDevice的class来构造的这么一个类。也就是说如果我们的设备是Switch类就为这个设备构造一个SwitchInputMapper类,我们假设我们现在的事件是由触摸屏上报的事件处理流程。在前面处理的过程中我们就会调用MultiTouchInputMapper的process来继续处理。也就是说当处理到mapper-process的时候,代码就会根据具体的设备cla

42、ss类型来处理相应的事件。这么多inputMapper,我们就以MultiTouchInputMapper的流程继续来分析事件的处理流程。Framework/base/services/input/InputReader.cppvoid MultiTouchInputMapper:process(const RawEvent* rawEvent) TouchInputMapper:process(rawEvent); mMultiTouchMotionAccumulator.process(rawEvent);void MultiTouchMotionAccumulator:process(const RawEvent* rawEvent) switch (rawEvent-scanCode) case ABS_MT_POSITION_X: slot-mInUse = true; slot-mAb

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/施工/环境 > 项目建议


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号