InputManagerService之事件的初始化与分发

来源:互联网 发布:原生js 触发事件 编辑:程序博客网 时间:2024/05/18 00:37

该篇文章接总章,来详细谈论说明InputManagerService 体系,从初始化到事件获取跟分发。咱们在进行前,先明确哪几个问题需要知道,然后看看在这篇文章中是否解决了这些问题。对于InputManagerService,大家第一个想知道是他起什么作用,这个在总章里面有详细说明,简而言之就是获得事件跟分发处理事件。那他如何或者跟其他模块配合获取事件?并且把这个事件进行分发?如何准确定位对应的处理事件的模块?咱们下面开始讨论这些问题,在这个文章出来的时候,android 已经到N了 ,也就是7.0。但是由于我的笔记(初稿) 在M的时候已经完成了,也就是去年。所以这篇文章还是基于M (6.0)来写。

        InputManagerService的初始化:

        跟其他模块一样,作为系统的核心服务初始化在SystemServer。基本系统的核心服务都是在这里初始化,这个可以研究下系统的启动流程,在启动的最后就是需要启动所有的核心服务。

       代码路径:    frameworks/base/services/java/com/android/server/SystemServer.java   

       在run 方法里面,M 是在startOtherService()里面初始化InputManagerService

      

         上面主要是新建IMS(InputManagerService 下面都用这个替换) 对象, 然后把WindowManagerService的InputMonitor作为参数传给IMS,重点关注下InputMonitor,这个跟事件的分发有关。然后在这里调用start方法启动IMS,这里的start 实际是调用 native 的start 方法。

         看下InputManagerServices的start方法:

         代码路径:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

       

上面主要调用了com_android_service_input_InputManagerService.cpp 里面的nativeStart方法,Java层的start方法主要做了两个工作:一个工作就是调用nativeStart方法。另外一个就是point 跟 toucher 相关参数设置跟监听,对应这Input事件的主要两类:Key 跟 toucher。在nativeStart里面的mPtr对应啥呢?首先Java层 跟 native层通信调用,主要通过JNI。这里主要是mPtr指针强制类型转换为NativeInputManager对象,看下源码:

Java层代码:

代码路径:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

[java] view plain copy
print?
  1.     // Pointer to native input manager service object.  
  2.     private final long mPtr;  
  3. public InputManagerService(Context context) {  
  4.         this.mContext = context;  
  5.         this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());  
  6. <span style="white-space:pre;"> </span>mUseDevInputEventForAudioJack =  
  7.                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);  
  8.         Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="  
  9.                 + mUseDevInputEventForAudioJack);  
  10. <span style="white-space:pre;"> </span>//这里对mPtr 进行初始化,调用的还是native的方法,把这个service跟 Systemcontext 传给native对应的方法  
  11.         mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());  
  12. <span style="white-space:pre;"> </span> LocalServices.addService(InputManagerInternal.classnew LocalService());  
  13.     }  
Native层代码:

  代码路径:/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

[cpp] view plain copy
print?
  1. static jlong nativeInit(JNIEnv* env, jclass /* clazz */,  
  2.     jobject serviceObj, jobject contextObj, jobject messageQueueObj) {  
  3. sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);  
  4. if (messageQueue == NULL) {  
  5.     jniThrowRuntimeException(env, "MessageQueue is not initialized.");  
  6.     return 0;  
  7. }   //这里把JAVA层的  Systemcontext 以及IMS自己 作为参数传过来了  
  8. an style="white-space:pre;">    </span>NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,  
  9.         messageQueue->getLooper());  
  10. im->incStrong(0);  
  11. return reinterpret_cast<jlong>(im);  
这个为什么要把IMS 传给NativeInputManager呢?看下NativeInputManager的构造函数

代码路径:frameworks/base/services/core/jni/com_android_server_input_inputmanagerservice.cpp

[cpp] view plain copy
print?
  1. NativeInputManager::NativeInputManager(jobject contextObj,  
  2.         jobject serviceObj, const sp<Looper>& looper) :  
  3.         mLooper(looper), mInteractive(true) {  
  4.     JNIEnv* env = jniEnv();  
  5.   
  6.     mContextObj = env->NewGlobalRef(contextObj);  
  7.     mServiceObj = env->NewGlobalRef(serviceObj);  
  8.    {  
  9.         AutoMutex _l(mLock);  
  10.         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;  
  11.         mLocked.pointerSpeed = 0;  
  12.         mLocked.pointerGesturesEnabled = true;  
  13.         mLocked.showTouches = false;  
  14.     }  
  15. <span style="white-space:pre;"> </span>mInteractive = true;  
  16. <span style="white-space:pre;"> </span>//这个是从底层读取input 信息的提供者  
  17.      sp<EventHub> eventHub = new EventHub();  
  18.     mInputManager = new InputManager(eventHub, thisthis);  
  19. }  
这里有一个重要的对象就是EventHub,如总章所说这个对象是事件获取的重要的对象。在这里也对Native层的InputManager进行了初始化。前面解决了mPtr 是啥,nativeStart又干了啥?

InputManagerService的读取跟分发启动:

[cpp] view plain copy
print?
  1. static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {  
  2.     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);  
  3.     //这里就是上面获得InputManager对象调用start()方法返回的结果  
  4.     status_t result = im->getInputManager()->start();  
  5.     if (result) {  
  6.         jniThrowRuntimeException(env, "Input manager could not be started.");  
  7.     }  
  8. }  
查看下InputManager的start方法到底干了什么?frameworks/native/services/inputFlinger/InputManager.cpp

代码路径:frameworks/native/services/inputFlinger/InputManager.cpp

[cpp] view plain copy
print?
  1. status_t InputManager::start() {  
  2.     status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);  
  3.     if (result) {  
  4.         ALOGE("Could not start InputDispatcher thread due to error %d.", result);  
  5.         return result;  
  6.     }  
  7.   
  8.     result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);  
  9.     if (result) {  
  10.         ALOGE("Could not start InputReader thread due to error %d.", result);  
  11.   
  12.         mDispatcherThread->requestExit();  
  13.         return result;  
  14.     }  
  15.   
  16.     return OK;  
  17. }  
嘿嘿,这里就真正的Input 事件 消息读取分发的工作启动了,从上面的代码就可以知道这里开启了两个线程,这两个线程初始化在InputManager的initialize方法里面。

[cpp] view plain copy
print?
  1. void InputManager::initialize() {  
  2.     mReaderThread = new InputReaderThread(mReader);  
  3.     mDispatcherThread = new InputDispatcherThread(mDispatcher);  
  4. }  
这两个线程主要一个是读取事件,一个是分发事件。读取事件从哪里读呢?从EventHub里面读,源码说了~

代码路径:frameworks/native/services/inputflinger/InputReader.h

[cpp] view plain copy
print?
  1. /* Reads raw events from the event hub and processes them, endlessly. */   这里说明了  
  2. class InputReaderThread : public Thread {  
  3. public:  
  4.     InputReaderThread(const sp<InputReaderInterface>& reader);  
  5.     virtual ~InputReaderThread();  
  6.   
  7. private:  
  8.     sp<InputReaderInterface> mReader;  
  9.   
  10.     virtual bool threadLoop();  
  11. };  
那这个线程如何读取数据呢?
代码路径:frameworks/native/services/inputflinger/InputReader.cpp

[cpp] view plain copy
print?
  1. // --- InputReaderThread ---  
  2. InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :  
  3.          Thread(/*canCallJava*/ true), mReader(reader) {  
  4. }  
  5. InputReaderThread::~InputReaderThread() {  
  6. }  
  7. bool InputReaderThread::threadLoop() {  
[cpp] view plain copy
print?
  1. //调用loopOnce 方法      
  2. mReader->loopOnce();  
  3.   return true;  
InputReader 实际不直接访问设备点,而是通过EventHub 来完成这一工作,EventHub 通过读取/dev/input下的数据。loopOnce如何读取事件了,前面已经反复强调读取数据的工作主要是EventHub,那loopOnce里面EventHub就要一定要出现了。

[cpp] view plain copy
print?
  1. void InputReader::loopOnce() {  
  2.     int32_t oldGeneration;  
  3.     int32_t timeoutMillis;  
  4.     bool inputDevicesChanged = false;  
  5.     Vector<InputDeviceInfo> inputDevices;  
  6. //这里主要是 环境有关的,比如时间,比如设备的状态等等  
  7.     { // acquire lock  
  8.        AutoMutex _l(mLock);  
  9.   
  10.         oldGeneration = mGeneration;  
  11.         timeoutMillis = -1;  
  12.   
  13.         uint32_t changes = mConfigurationChangesToRefresh;  
  14.          if (changes) {  
  15.             mConfigurationChangesToRefresh = 0;  
  16.             timeoutMillis = 0;  
  17.             //主要刷新环境  
  18.             refreshConfigurationLocked(changes);  
  19.         } else if (mNextTimeout != LLONG_MAX) {  
  20.             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  
  21.             timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);  
  22.         }  
  23.     } // release lock  
  24.    //获得input 数据  
  25.     size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);  
  26.     //这里主要处理消息设备  
  27.     { // acquire lock  
  28.         AutoMutex _l(mLock);  
  29.         mReaderIsAliveCondition.broadcast();  
  30.   
  31.         if (count) {  
  32.             //这里主要是 添加事情的设备  
  33.             processEventsLocked(mEventBuffer, count);  
  34.         }  
  35.         if (mNextTimeout != LLONG_MAX) {  
  36.             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  
  37.             if (now >= mNextTimeout) {  
  38. #if DEBUG_RAW_EVENTS  
  39.                 ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);  
  40. #endif  
  41.                 mNextTimeout = LLONG_MAX;  
  42.                 timeoutExpiredLocked(now);  
  43.             }  
  44.         }  
  45.     if (oldGeneration != mGeneration) {  
  46.             inputDevicesChanged = true;  
  47.             getInputDevicesLocked(inputDevices);  
  48.         }  
  49.     } // release lock  
  50.  // Send out a message that the describes the changed input devices.  
  51.     if (inputDevicesChanged) {  
  52.         mPolicy->notifyInputDevicesChanged(inputDevices);  
  53.     }  
  54.     // Flush queued events out to the listener.  
  55.     // This must happen outside of the lock because the listener could potentially call  
  56.     // back into the InputReader's methods, such as getScanCodeState, or become blocked  
  57.     // on another thread similarly waiting to acquire the InputReader lock thereby  
  58.     // resulting in a deadlock.  This situation is actually quite plausible because the  
  59.     // listener is actually the input dispatcher, which calls into the window manager,  
  60.     // which occasionally calls into the input reader.  
[cpp] view plain copy
print?
  1.     //获得数据后,刷新数据,mQueueListener,根据构造函数以及注释可以知道是InputDispatcher的一个封装  
  2.     //查看InputReader的构造函数, InputDispatcher 转成了这个  
  3.     //这里主要是刷新消息栈,进行事件的分发了  
  4.     //QueuedInputListener  定义在 InputListener.cpp里面  
  5.    mQueuedListener->flush();  
  6. }  
看下loopOnce方法EventHub果然出现了,在这个几十行代码里面读取事件EventHub,flush 分发事件都有了,基本上就走完了Input事件的读取跟分发。现在准备进入事件分发的解读,事件的读取由于涉及到kernel层代码的解读,作为子章进行分析说明,本篇不做过多解读。这里从mQueuedListener->flush(); 开始说明。

代码路径:frameworks/native/services/inputflinger/InputListener.cpp

[cpp] view plain copy
print?
  1. void QueuedInputListener::flush() {  
  2.     size_t count = mArgsQueue.size();  
  3.     for (size_t i = 0; i < count; i++) {  
  4.         NotifyArgs* args = mArgsQueue[i];  
  5.         args->notify(mInnerListener);  
  6.         delete args;  
  7.     }  
  8.     mArgsQueue.clear();  
  9. }  
代码路径:frameworks/native/services/inputflinger/inputListener.h

[cpp] view plain copy
print?
  1. /* 
  2.  * An implementation of the listener interface that queues up and defers dispatch 
  3.  * of decoded events until flushed. 
  4.  */  
  5. class QueuedInputListener : public InputListenerInterface {  
  6. protected:  
  7.     virtual ~QueuedInputListener();  
  8. public:  
  9.     QueuedInputListener(const sp<InputListenerInterface>& innerListener);  
  10.     virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);  
  11.     virtual void notifyKey(const NotifyKeyArgs* args);  
  12.     virtual void notifyMotion(const NotifyMotionArgs* args);  
  13.     virtual void notifySwitch(const NotifySwitchArgs* args);  
  14.     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);  
  15.     void flush();  
  16. private:  
  17.     sp<InputListenerInterface> mInnerListener;  
  18.     Vector<NotifyArgs*> mArgsQueue;  
  19. };  
  20. /* 
  21.  * The interface used by the InputReader to notify the InputListener about input events. 
  22.  */  
  23. class InputListenerInterface : public virtual RefBase {  
  24. protected:  
  25.     InputListenerInterface() { }  
  26.     virtual ~InputListenerInterface() { }  
  27. public:  
  28.     virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;  
  29.     virtual void notifyKey(const NotifyKeyArgs* args) = 0;  
  30.     virtual void notifyMotion(const NotifyMotionArgs* args) = 0;  
  31.     virtual void notifySwitch(const NotifySwitchArgs* args) = 0;  
  32.     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;  
  33. };  
由上可知继承inputListenerInterface的子类,会根据情况处理相应的事件。在这里有一个问题InputDispatcher 如何被强转的?其实是InputReader在初始化的时候InputDispatcher作为参数传了过去,然后强转了。上代码说明下:

[cpp] view plain copy
print?
  1. InputManager::InputManager(  
  2.         const sp<EventHubInterface>& eventHub,  
  3.         const sp<InputReaderPolicyInterface>& readerPolicy,  
  4.         const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {  
  5.     mDispatcher = new InputDispatcher(dispatcherPolicy);  
  6.     mReader = new InputReader(eventHub, readerPolicy, mDispatcher);  
  7.     initialize();  
  8. }  
  9.   
  10. // --- InputReader ---  
  11. InputReader::InputReader(const sp<EventHubInterface>& eventHub,  
  12.         const sp<InputReaderPolicyInterface>& policy,  
  13.        //结合上面的代码 以及 这句代码可以知道inputdispatcher被强转了,为什么可以强转?  
  14.        //因为inputListenerInterface这个接口继承Refbase,Refbase是android里面的所有对象的父类  
  15.        //详情参考binder里面的介绍  
  16.         const sp<InputListenerInterface>& listener) :  
  17.         mContext(this), mEventHub(eventHub), mPolicy(policy),  
  18.         mGlobalMetaState(0), mGeneration(1),  
  19.         mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),  
  20.         mConfigurationChangesToRefresh(0) {  
把InputDispatcher强转说清楚,咱们就开始详细了解下事情的分发过程,咱们从notifykey这方法说起

[cpp] view plain copy
print?
  1.      代码路径:frameworks/native/services/inputflinger/InputDispatcher.cpp  
  2.   void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {  
  3.       Code 省略,前面主要检查这个事件有没有问题,把事件里面的信息属性都抽出来,重点看下面的代码  
  4.       bool needWake;  
  5.       { // acquire lock  
  6.         mLock.lock();  
  7.   
  8.   
  9.         if (shouldSendKeyToInputFilterLocked(args)) {  
  10.             mLock.unlock();  
  11.   
  12.   
  13.             policyFlags |= POLICY_FLAG_FILTERED;  
  14.             if (!mPolicy->filterInputEvent(&event, policyFlags)) {  
  15.                 return// event was consumed by the filter  
  16.             }  
  17.   
  18.   
  19.             mLock.lock();  
  20.         }  
  21.   
  22.   
  23.         int32_t repeatCount = 0;  
  24.         KeyEntry* newEntry = new KeyEntry(args->eventTime,  
  25.                 args->deviceId, args->source, policyFlags,  
  26.                 args->action, flags, keyCode, args->scanCode,  
  27.                 metaState, repeatCount, args->downTime);  
  28.   
  29.   
  30.         needWake = enqueueInboundEventLocked(newEntry);  
  31.         mLock.unlock();  
  32.     } // release lock  
[cpp] view plain copy
print?
  1. if (needWake) {  
[cpp] view plain copy
print?
  1.         //事件分发主要在这里,但是要分发要看needWake的值,<span style="color:rgb(72,72,76);font-size:13px;line-height:1.38462;white-space:pre-wrap;background-color:rgb(247,247,249);">enqueueInboundEventLocked 返回true,事件就开始分发了</span>  
  2.         mLooper->wake();  
  3.     }  
  4.   }  

       这里looper 什么怎么进行分发呢?还是看源码

[cpp] view plain copy
print?
  1. // --- InputDispatcherThread ---    这个主要在InputDispatcher.cpp里面  
  2.  InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :  
  3.            Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {  
  4.   }  
  5.    InputDispatcherThread::~InputDispatcherThread() {  
  6.    }  
  7.   . bool InputDispatcherThread::threadLoop() {  
  8.        //开始调用dispatchOnce方法  
  9.        mDispatcher->dispatchOnce();  
  10.        return true;  
  11.  . }  
  12.   . } // namespace android  
[cpp] view plain copy
print?
  1. void InputDispatcher::dispatchOnce() {  
  2.     nsecs_t nextWakeupTime = LONG_LONG_MAX;  
  3.     { // acquire lock  
  4.         AutoMutex _l(mLock);  
  5.         mDispatcherIsAliveCondition.broadcast();  
  6.         // Run a dispatch loop if there are no pending commands.  
  7.         // The dispatch loop might enqueue commands to run afterwards.  
  8.         if (!haveCommandsLocked()) {  
  9.             //调用下面的方法  
  10.             dispatchOnceInnerLocked(&nextWakeupTime);  
  11.         }  
         到这里就开始说明分发事件了,TouchEvent的消息分发结构来分析Input 在Framework的使用

[cpp] view plain copy
print?
  1. Code In InputDispatcher.cpp 里面  
  2. void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {  
  3. Code  省略  
  4. case EventEntry::TYPE_MOTION: {  
  5.         MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);  
  6.         if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {  
  7.             dropReason = DROP_REASON_APP_SWITCH;  
  8.         }  
  9.         if (dropReason == DROP_REASON_NOT_DROPPED  
  10.                 && isStaleEventLocked(currentTime, typedEntry)) {  
  11.             dropReason = DROP_REASON_STALE;  
  12.         }  
  13.         if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {  
  14.             dropReason = DROP_REASON_BLOCKED;  
  15.         }  
  16.         //跳转到下面个函数,去处理motion相关操作  
  17.         done = dispatchMotionLocked(currentTime, typedEntry,  
  18.                 &dropReason, nextWakeupTime);  
  19.         break;  
  20.     }  
 
[cpp] view plain copy
print?
  1. bool InputDispatcher::dispatchMotionLocked(  
  2.         nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {  
  3.     //进行motion事件,进行处理  
  4.     // Preprocessing.  
  5.     if (! entry->dispatchInProgress) {  
  6.         entry->dispatchInProgress = true;  
  7.         //这个函数把motion的相关值打出来  
  8.         logOutboundMotionDetailsLocked("dispatchMotion - ", entry);  
  9.     }  
  10.  // Clean up if dropping the event.  
  11. 把旧有的数据清楚掉  
  12.     if (*dropReason != DROP_REASON_NOT_DROPPED) {  
  13.      //这个方法就是设置插入结果,根据不同InjectionRest弹出不同LOG  
  14.         setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY  
  15.                 ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);  
  16.         return true;  
  17.     }  
  18.  //判断时间的类型  
  19.  bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;  
  20.    //获得事件的接受者或者实际响应者  
  21.     // Identify targets.  
  22.     Vector<InputTarget> inputTargets;  
  23.     bool conflictingPointerActions = false;  
  24.     int32_t injectionResult;  
  25.     if (isPointerEvent) {  
  26.         // Pointer event.  (eg. touchscreen)  
  27.         // 获得对应的window 是 touch 事件,这里是重点  
  28.        injectionResult = findTouchedWindowTargetsLocked(currentTime,  
  29.                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);  
  30.     } else {  
  31.        // Non touch event.  (eg. trackball)  
  32.         // 是轨迹事件  
  33.         injectionResult = findFocusedWindowTargetsLocked(currentTime,  
  34.                 entry, inputTargets, nextWakeupTime);  
  35.     }  
  36.     // 是否延迟处理  
  37.     if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {  
  38.         return false;  
  39.     }  
  40. // 设置延迟处理  
  41. setInjectionResultLocked(entry, injectionResult);  
  42.     if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {  
  43.         if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {  
  44.             CancelationOptions::Mode mode(isPointerEvent ?  
  45.                     CancelationOptions::CANCEL_POINTER_EVENTS :  
  46.                     CancelationOptions::CANCEL_NON_POINTER_EVENTS);  
  47.             CancelationOptions options(mode, "input event injection failed");  
  48.             synthesizeCancelationEventsForMonitorsLocked(options);  
  49.         }  
  50.         return true;  
  51.     }  
  52.     //支持 发送二次输入显示器的显示事件  
  53.     // TODO: support sending secondary display events to input monitors  
  54.     if (isMainDisplay(entry->displayId)) {  
  55.         addMonitoringTargetsLocked(inputTargets);  
  56.     }  
  57. // Dispatch the motion.  
  58.     if (conflictingPointerActions) {  
  59.         CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,  
  60.                 "conflicting pointer actions");  
  61.         synthesizeCancelationEventsForAllConnectionsLocked(options);  
  62.     }  
  63.     dispatchEventLocked(currentTime, entry, inputTargets);  
  64.     return true;  
  65. }  
          这里大概就是touch事件的处理流程, findTouchedWindowTargetsLocked 是找到对应的事件响应者的重要方法,下面开始详细说明
         
[cpp] view plain copy
print?
  1. Code In InputDispatcher  
  2. int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,  
  3.         const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {  
  4.     int32_t injectionResult;  
  5.     String8 reason;  
[cpp] view plain copy
print?
  1.   
//这里判断是否有焦点的窗口跟焦点的应用
// If there is no currently focused window and no focused application // then drop the event. if (mFocusedWindowHandle == NULL) { if (mFocusedApplicationHandle != NULL) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, NULL, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application that may eventually add a window " "when it finishes starting up."); goto Unresponsive; }
[cpp] view plain copy
print?
  1.            ALOGI("Dropping event because there is no focused window or focused application.");  
  2.         injectionResult = INPUT_EVENT_INJECTION_FAILED;  
  3.         goto Failed;  
  4.     }  
[cpp] view plain copy
print?
  1.     // Check permissions.   检查权限  
  2.     if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {  
  3.         injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;  
  4.         goto Failed;  
  5.     }  
[cpp] view plain copy
print?
  1. // Check whether the window is ready for more input.  
[cpp] view plain copy
print?
  1.     // 检查窗口的状态,比如是否pause 等等  
  2.     reason = checkWindowReadyForMoreInputLocked(currentTime,  
  3.             mFocusedWindowHandle, entry, "focused");  
  4.     if (!reason.isEmpty()) {  
  5.         injectionResult = handleTargetsNotReadyLocked(currentTime, entry,  
  6.                 mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());  
  7.         goto Unresponsive;  
  8.     }  
[cpp] view plain copy
print?
  1. // Success!  Output targets.  
[cpp] view plain copy
print?
  1.     // 这里主要是Input 跟 目标窗口相关信息复制跟绑定,重点关注里面的InputChannel,这个跟窗口年消息通信有关  
  2.     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;  
  3.     addWindowTargetLocked(mFocusedWindowHandle,  
  4.             InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),  
  5.             inputTargets);  
[cpp] view plain copy
print?
  1.      // Done.  
  2. Failed:  
  3. Unresponsive:  
  4.     nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);  
  5.     updateDispatchStatisticsLocked(currentTime, entry,  
  6.             injectionResult, timeSpentWaitingForApplication);  
  7. #if DEBUG_FOCUS  
[cpp] view plain copy
print?
  1.      ALOGD("findFocusedWindow finished: injectionResult=%d, "  
  2.             "timeSpentWaitingForApplication=%0.1fms",  
  3.             injectionResult, timeSpentWaitingForApplication / 1000000.0);  
  4. #endif  
  5.     return injectionResult;  
  6.   
  7.      
               上面重点要关注的就是mFocusedWindowHandle  跟  mFocusedApplicationHandle 。他们是谁复制的呢?如何复制的呢?起什么作用了。明白了他们两个就可以明白了Input 跟对应的window的通信。下面就主要从这两个对象进行研究展开。findFocusedWindowTargetsLocked 的方法里面其他就是检查窗口状态等相关信息。

             mFocusedWindowHandler 谁复制的呢?经过查询在InputDispatcher 里面就如下的方法     

[cpp] view plain copy
print?
  1. void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {  
  2. Code 省略  
  3. // newFocusedWindowHandler  
  4. sp<InputWindowHandle> newFocusedWindowHandle;  
  5. //mFocusedWindowHandler 是被赋值为newFocusedWindowHandle  
  6. mFocusedWindowHandle = newFocusedWindowHandle;  
  7. Code 省略  
            这里就是InputDispatcher 设置对应的消息输出窗口的地方,但是到底这个方法到底谁在用?什么地方用?由于咱们讨论的是IMS 整个体系,InputDispatcher跟InputReader 是IMS 的左膀右臂。InputReader是负责的读取的数据然后应该是给IMS 去处理,InputDispatcher 是分发的,应该也是由IMS 去具体处理。咱们去IMS看看是否有设置窗口的调用

            看下InputManagerService.java

           代码路径:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

            public void setInputWindows(InputWindowHandle[] windowHandles) {

[cpp] view plain copy
print?
  1. //这里调用com_android_server_input_InputManagerService.cpp  
  2.       nativeSetInputWindows(mPtr, windowHandles);  
  3. }  
            代码路径:frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

[cpp] view plain copy
print?
  1. void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {  
  2.  Vector<sp<InputWindowHandle> > windowHandles;  
  3.  if (windowHandleObjArray) {  
  4.      jsize length = env->GetArrayLength(windowHandleObjArray);  
  5.     for (jsize i = 0; i < length; i++) {  
  6.          jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);  
  7.          if (! windowHandleObj) {  
  8.              break// found null element indicating end of used portion of the array  
  9.          }  
  10.          sp<InputWindowHandle> windowHandle =  
  11.                  android_server_InputWindowHandle_getHandle(env, windowHandleObj);  
  12.          if (windowHandle != NULL) {  
  13.              windowHandles.push(windowHandle);  
  14.          }  
  15.          env->DeleteLocalRef(windowHandleObj);  
  16.      }  
  17.  }  
  18.  //这里会调用InputManager.cpp里面的方法  
  19.  mInputManager->getDispatcher()->setInputWindows(windowHandles);  
  20.  CODE 省略  
             代码路径:frameworks/native/services/inputflinger/inputManager.cpp

[cpp] view plain copy
print?
  1. sp<InputDispatcherInterface> InputManager::getDispatcher() {  
  2. //获得InputDispatcheer.cpp 对象     
  3. return mDispatcher;  
            从上面可以知道IMS 到 InputDispather 如何层层调用setInputWindow的流程,但是这个方法还是在IMS 体系里面调用,外面别人如何调用呢?既然从IMS 体系找不到,就从外面找,window 的管理者WMS。

            代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

            看下WMS 的 addWindow方法            

[cpp] view plain copy
print?
  1.  Code In WindowManagerService.java  
  2.  public int addWindow(Session session, IWindow client, int seq,  
  3.             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,  
  4.             Rect outContentInsets, Rect outStableInsets, Rect outOutsets,  
  5.             InputChannel outInputChannel) {  
  6.  Code 省略  
  7. if (focusChanged) {  
  8. //调用InputMonitor的方法设置接收窗口  
  9.               mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);  
  10.           }  
  11.           mInputMonitor.updateInputWindowsLw(false /*force*/);  
  12. Code 省略  
          来看下InputMonitor 在干啥

          代码路径:frameworks/base/services/core/java/com/android/server/wm/inputMonitor.java

[cpp] view plain copy
print?
  1. /* Called when the current input focus changes. 
  2.  * Layer assignment is assumed to be complete by the time this is called. 
  3.  */  
  4.  public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {  
  5.      if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {  
  6.          Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);  
  7.      }  
  8.       if (newWindow != mInputFocus) {  
  9.           if (newWindow != null && newWindow.canReceiveKeys()) {  
  10.               // Displaying a window implicitly causes dispatching to be unpaused.  
  11.               // This is to protect against bugs if someone pauses dispatching but  
  12.               // forgets to resume.  
  13.               newWindow.mToken.paused = false;  
  14.           }  
  15.           mInputFocus = newWindow;  
  16.           setUpdateInputWindowsNeededLw();  
  17.           if (updateInputWindows) {  
  18.           //更新当前焦点窗口  
  19.               updateInputWindowsLw(false /*force*/);  
  20.           }  
  21.       }  
  22.   }  
[cpp] view plain copy
print?
  1. /* Updates the cached window information provided to the input dispatcher. */  
  2.     public void updateInputWindowsLw(boolean force) {  
  3.         if (!force && !mUpdateInputWindowsNeeded) {  
  4.             return;  
  5.         }  
  6. Code  省略  
  7. //在这个方法里面会调用InputManagerService的setInputWindow方法传入  
  8. //inputWindowHandlers  
  9.  // Send windows to native code.  
  10.         mService.mInputManager.setInputWindows(mInputWindowHandles);  
  11.  // Clear the list in preparation for the next round.  
  12.         clearInputWindowHandlesLw();  
  13.         if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");  
  14.     }  
           到这里就实现了WMS 通过InputMonitor 跟IMS 再 InputDispather的沟通,也就是Window 跟 Input事件的沟通了。说完他们之间的关系,就说最后一部分他们的通信渠道了。先说结论对应的window 跟  IMS 通信实际是用InputChannel。InputChannel是一个pipe,底层实际是通过socket进行通信。

         看下inputChannel的源码:

        代码路径:frameworks\base\core\java\android\view\InputChannel.java

[cpp] view plain copy
print?
  1. Creates a new input channel pair.  One channel should be provided to the input  
  2.  * dispatcher and the other to the application's input queue.  
  3.  * @param name The descriptive (non-unique) name of the channel pair.  
  4.  * @return A pair of input channels.  The first channel is designated as the  
  5.  * server channel and should be used to publish input events.  The second channel  
  6.  * is designated as the client channel and should be used to consume input events.  
  7.  public static InputChannel[] openInputChannelPair(String name) {  
  8.     if (name == null) {  
  9.         throw new IllegalArgumentException("name must not be null");  
  10.     }  
  11.   
  12.     if (DEBUG) {  
  13.         Slog.d(TAG, "Opening input channel pair '" + name + "'");  
  14.     }  
[cpp] view plain copy
print?
  1.    //这里还要走底层的代码  
  2.     return nativeOpenInputChannelPair(name);  
  3. }  
        代码路径:frameworks\base\core\jni\android_view_InputChannel.cpp
[cpp] view plain copy
print?
  1. static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,  
  2.      jclass clazz, jstring nameObj) {  
  3.  const char* nameChars = env->GetStringUTFChars(nameObj, NULL);  
  4.  String8 name(nameChars);  
  5.  env->ReleaseStringUTFChars(nameObj, nameChars);  
  6.  //这里主要是建立了一堆通信的inputchannel  
  7.  sp<InputChannel> serverChannel;  
  8.  sp<InputChannel> clientChannel;  
  9.  status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);  
[cpp] view plain copy
print?
  1. 代码省略  
       上面代码说明了为了通信,建立了一对inputChannel,那如何跟socket关联了?看下面的代码

     代码路径:frameworks\native\libs\input\InputTransport.cpp

[cpp] view plain copy
print?
  1. status_t InputChannel::openInputChannelPair(const String8& name,  
  2.         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {  
  3.     int sockets[2];  
  4.     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {  
  5.         status_t result = -errno;  
  6.         ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",  
  7.                 name.string(), errno);  
  8.         outServerChannel.clear();  
  9.         outClientChannel.clear();  
  10.         return result;  
  11.     }  
  12.  int bufferSize = SOCKET_BUFFER_SIZE;  
  13.     setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  14.     setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  15.     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  16.     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  17. String8 serverChannelName = name;  
  18.     serverChannelName.append(" (server)");  
  19.     outServerChannel = new InputChannel(serverChannelName, sockets[0]);  
  20.   
  21.     String8 clientChannelName = name;  
  22.     clientChannelName.append(" (client)");  
  23.     outClientChannel = new InputChannel(clientChannelName, sockets[1]);  
  24.     return OK;  
这个其实说明了inputChannel的open方法其实就是建立了socket通信

IMS体系建立了inputChannel,那WMS也相应的做了InputChannel的相关操作

代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

[java] view plain copy
print?
  1. public int addWindow(Session session, IWindow client, int seq,  
  2.             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,  
  3.             Rect outContentInsets, Rect outStableInsets, Rect outOutsets,  
  4.             InputChannel outInputChannel) {  
  5.         int[] appOp = new int[1];  
  6.         int res = mPolicy.checkAddPermission(attrs, appOp);  
  7.         if (res != WindowManagerGlobal.ADD_OKAY) {  
  8. CODE 省略  
  9. if (outInputChannel != null && (attrs.inputFeatures  
  10.                     & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  11.                 /** M: [ALPS00044207] @{ */  
  12.                 try {  
  13.                    //设置当前通道的名字  
  14.                     String name = win.makeInputChannelName();  
  15.                    //打开一对通道  
  16.                     InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);  
  17.                     win.setInputChannel(inputChannels[0]);  
  18.                     inputChannels[1].transferTo(outInputChannel);  
  19.                     mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);  
  20.                 } catch (IllegalArgumentException e) {  
  21.                     Slog.w(TAG, "handle Input channel erorr", e);  
  22.                     return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;  
  23.                 }  
  24.                 /** @} */  
  25.             }  

到了这里基本IMS 关于消息的处理至少在framework层讲得差不多了。做个总结吧,也把开头的问题回答下,其实文中已经说得很清楚了。

重点的几个问题概述下:

InputManager初始化跟其他的核心service一样都是在systemServer里面进行(这里估计有问题),初始化后,会调用start方法。其实调用的是native层inputmanager的start方法,这里初始化了两个线程。native层的inputmanager的构造函数里面会对InputReader/ InputDispatcher进行初始化,Eventhub(读取dev/input里面的事件)和InputDispatcher作为参数传给了InputReader

Work
一:消息处理,inputReader通过EventHub获得数据后,会通知QueuedInputListener调用flush方法,由上面的详细笔记可以知道QueuedInputListener继承InputListenerInterface,InputListenerInterface 是继承Refbase,InputDispatcher作为参数传给了QueuedInputListener。
二:QueuedInputListener.flush方法会调用子类的notify方法,至于notify是key,还是其他,具体情况具体处理。
Inputdispatcher跟WMS的交互,主要在findfocuswindow函数里面实现,关键在setWindow方法传递windowHandler。
setWindow方法都是通过成员变量调方法,进行windowHandler传递。WMS里面有inputmonitor作为成员变量在里面,在InputMonitor里面会调用native InputManagerService的setInputWindow方法,在这个方法里面会通过InputManager调用inputDispatcher方法里面的setInputWindow方法,完成windowHandler的传递。
三:可以知道windowHandler上面有inputChannel,inputChannel是android里面的pipe 管道通信。实现了应用程序跟InputDispatcher的通信
注:mQueuedListener->flush();如何跟InputDispatcher联系上?
在InputRead.cpp的构造函数里面,inputDispatcher作为参数传给了QueuedInputListener里。
QueuedInputListener定义在InputListener.h 里面,InputDispatcher作为参数,到了QueuedInputListener的构造函数里,传给mInnerListener()这个方法里面

问题:那他如何或者跟其他模块配合获取事件?并且把这个事件进行分发?如何准确定位对应的处理事件的模块?

1.其实通过调用,里面有对应的对象调用相对的方法,进行配合使用。

2.分发其实找到对应的window ,然后会建立对应的一对inputchannel进行通信。

Ok,写完了,其实去年就写完了,一直没时间整理发博客。今天大概全部整理了下发出来了。希望能跟各位多多交流。吐槽一句CSDN的博客真不好编辑代码的。


原创粉丝点击