InputManagerService之事件的初始化与分发

来源:互联网 发布:php h5 微信支付接口 编辑:程序博客网 时间:2024/04/30 12:00

该篇文章接总章,来详细谈论说明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

    // Pointer to native input manager service object.    private final long 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);//这里对mPtr 进行初始化,调用的还是native的方法,把这个service跟 Systemcontext 传给native对应的方法        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); LocalServices.addService(InputManagerInternal.class, new LocalService());    }
Native层代码:

  代码路径:/frameworks/base/services/core/jni/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);    if (messageQueue == NULL) {        jniThrowRuntimeException(env, "MessageQueue is not initialized.");        return 0;    }   //这里把JAVA层的  Systemcontext 以及IMS自己 作为参数传过来了 NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,            messageQueue->getLooper());    im->incStrong(0);    return reinterpret_cast<jlong>(im);   }
这个为什么要把IMS 传给NativeInputManager呢?看下NativeInputManager的构造函数

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

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;//这个是从底层读取input 信息的提供者     sp<EventHub> eventHub = new EventHub();    mInputManager = new InputManager(eventHub, this, this);}
这里有一个重要的对象就是EventHub,如总章所说这个对象是事件获取的重要的对象。在这里也对Native层的InputManager进行了初始化。前面解决了mPtr 是啥,nativeStart又干了啥?

InputManagerService的读取跟分发启动:

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.");    }}
查看下InputManager的start方法到底干了什么?frameworks/native/services/inputFlinger/InputManager.cpp

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

status_t InputManager::start() {    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);    if (result) {        ALOGE("Could not start InputDispatcher thread due to error %d.", result);        return result;    }    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);    if (result) {        ALOGE("Could not start InputReader thread due to error %d.", result);        mDispatcherThread->requestExit();        return result;    }    return OK;}
嘿嘿,这里就真正的Input 事件 消息读取分发的工作启动了,从上面的代码就可以知道这里开启了两个线程,这两个线程初始化在InputManager的initialize方法里面。

void InputManager::initialize() {    mReaderThread = new InputReaderThread(mReader);    mDispatcherThread = new InputDispatcherThread(mDispatcher);}
这两个线程主要一个是读取事件,一个是分发事件。读取事件从哪里读呢?从EventHub里面读,源码说了~

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

/* Reads raw events from the event hub and processes them, endlessly. */   这里说明了class InputReaderThread : public Thread {public:    InputReaderThread(const sp<InputReaderInterface>& reader);    virtual ~InputReaderThread();private:    sp<InputReaderInterface> mReader;    virtual bool threadLoop();};
那这个线程如何读取数据呢?
代码路径:frameworks/native/services/inputflinger/InputReader.cpp

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

void InputReader::loopOnce() {    int32_t oldGeneration;    int32_t timeoutMillis;    bool inputDevicesChanged = false;    Vector<InputDeviceInfo> inputDevices;//这里主要是 环境有关的,比如时间,比如设备的状态等等    { // acquire lock       AutoMutex _l(mLock);        oldGeneration = mGeneration;        timeoutMillis = -1;        uint32_t changes = mConfigurationChangesToRefresh;         if (changes) {            mConfigurationChangesToRefresh = 0;            timeoutMillis = 0;            //主要刷新环境            refreshConfigurationLocked(changes);        } else if (mNextTimeout != LLONG_MAX) {            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);        }    } // release lock   //获得input 数据    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);    //这里主要处理消息设备    { // acquire lock        AutoMutex _l(mLock);        mReaderIsAliveCondition.broadcast();        if (count) {            //这里主要是 添加事情的设备            processEventsLocked(mEventBuffer, count);        }        if (mNextTimeout != LLONG_MAX) {            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);            if (now >= mNextTimeout) {#if DEBUG_RAW_EVENTS                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);#endif                mNextTimeout = LLONG_MAX;                timeoutExpiredLocked(now);            }        } if (oldGeneration != mGeneration) {            inputDevicesChanged = true;            getInputDevicesLocked(inputDevices);        }    } // release lock // Send out a message that the describes the changed input devices.    if (inputDevicesChanged) {        mPolicy->notifyInputDevicesChanged(inputDevices);    }    // Flush queued events out to the listener.    // This must happen outside of the lock because the listener could potentially call    // back into the InputReader's methods, such as getScanCodeState, or become blocked    // on another thread similarly waiting to acquire the InputReader lock thereby    // resulting in a deadlock.  This situation is actually quite plausible because the    // listener is actually the input dispatcher, which calls into the window manager,    // which occasionally calls into the input reader.
    //获得数据后,刷新数据,mQueueListener,根据构造函数以及注释可以知道是InputDispatcher的一个封装    //查看InputReader的构造函数, InputDispatcher 转成了这个    //这里主要是刷新消息栈,进行事件的分发了    //QueuedInputListener  定义在 InputListener.cpp里面   mQueuedListener->flush();}
看下loopOnce方法EventHub果然出现了,在这个几十行代码里面读取事件EventHub,flush 分发事件都有了,基本上就走完了Input事件的读取跟分发。现在准备进入事件分发的解读,事件的读取由于涉及到kernel层代码的解读,作为子章进行分析说明,本篇不做过多解读。这里从mQueuedListener->flush(); 开始说明。

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

   void QueuedInputListener::flush() {       size_t count = mArgsQueue.size();       for (size_t i = 0; i < count; i++) {           NotifyArgs* args = mArgsQueue[i];           args->notify(mInnerListener);           delete args;       }       mArgsQueue.clear();   }
代码路径:frameworks/native/services/inputflinger/inputListener.h

   /*    * An implementation of the listener interface that queues up and defers dispatch    * of decoded events until flushed.    */   class QueuedInputListener : public InputListenerInterface {   protected:       virtual ~QueuedInputListener();   public:       QueuedInputListener(const sp<InputListenerInterface>& innerListener);       virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);       virtual void notifyKey(const NotifyKeyArgs* args);       virtual void notifyMotion(const NotifyMotionArgs* args);       virtual void notifySwitch(const NotifySwitchArgs* args);       virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);       void flush();   private:       sp<InputListenerInterface> mInnerListener;       Vector<NotifyArgs*> mArgsQueue;   };   /*    * The interface used by the InputReader to notify the InputListener about input events.    */   class InputListenerInterface : public virtual RefBase {   protected:       InputListenerInterface() { }       virtual ~InputListenerInterface() { }   public:       virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;       virtual void notifyKey(const NotifyKeyArgs* args) = 0;       virtual void notifyMotion(const NotifyMotionArgs* args) = 0;       virtual void notifySwitch(const NotifySwitchArgs* args) = 0;       virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;   };
由上可知继承inputListenerInterface的子类,会根据情况处理相应的事件。在这里有一个问题InputDispatcher 如何被强转的?其实是InputReader在初始化的时候InputDispatcher作为参数传了过去,然后强转了。上代码说明下:

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

     代码路径:frameworks/native/services/inputflinger/InputDispatcher.cpp  void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {      Code 省略,前面主要检查这个事件有没有问题,把事件里面的信息属性都抽出来,重点看下面的代码      bool needWake;      { // acquire lock        mLock.lock();        if (shouldSendKeyToInputFilterLocked(args)) {            mLock.unlock();            policyFlags |= POLICY_FLAG_FILTERED;            if (!mPolicy->filterInputEvent(&event, policyFlags)) {                return; // event was consumed by the filter            }            mLock.lock();        }        int32_t repeatCount = 0;        KeyEntry* newEntry = new KeyEntry(args->eventTime,                args->deviceId, args->source, policyFlags,                args->action, flags, keyCode, args->scanCode,                metaState, repeatCount, args->downTime);        needWake = enqueueInboundEventLocked(newEntry);        mLock.unlock();    } // release lock
    if (needWake) {
        //事件分发主要在这里,但是要分发要看needWake的值,enqueueInboundEventLocked 返回true,事件就开始分发了        mLooper->wake();    }  }

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

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

   Code In InputDispatcher.cpp 里面   void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {   Code  省略   case EventEntry::TYPE_MOTION: {           MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);           if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {               dropReason = DROP_REASON_APP_SWITCH;           }           if (dropReason == DROP_REASON_NOT_DROPPED                   && isStaleEventLocked(currentTime, typedEntry)) {               dropReason = DROP_REASON_STALE;           }           if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {               dropReason = DROP_REASON_BLOCKED;           }           //跳转到下面个函数,去处理motion相关操作           done = dispatchMotionLocked(currentTime, typedEntry,                   &dropReason, nextWakeupTime);           break;       }
 
   bool InputDispatcher::dispatchMotionLocked(           nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {       //进行motion事件,进行处理       // Preprocessing.       if (! entry->dispatchInProgress) {           entry->dispatchInProgress = true;           //这个函数把motion的相关值打出来           logOutboundMotionDetailsLocked("dispatchMotion - ", entry);       }    // Clean up if dropping the event.   把旧有的数据清楚掉       if (*dropReason != DROP_REASON_NOT_DROPPED) {        //这个方法就是设置插入结果,根据不同InjectionRest弹出不同LOG           setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY                   ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);           return true;       }    //判断时间的类型    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;      //获得事件的接受者或者实际响应者       // Identify targets.       Vector<InputTarget> inputTargets;       bool conflictingPointerActions = false;       int32_t injectionResult;       if (isPointerEvent) {           // Pointer event.  (eg. touchscreen)           // 获得对应的window 是 touch 事件,这里是重点          injectionResult = findTouchedWindowTargetsLocked(currentTime,                  entry, inputTargets, nextWakeupTime, &conflictingPointerActions);       } else {          // Non touch event.  (eg. trackball)           // 是轨迹事件           injectionResult = findFocusedWindowTargetsLocked(currentTime,                   entry, inputTargets, nextWakeupTime);       }       // 是否延迟处理       if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {           return false;       }   // 设置延迟处理   setInjectionResultLocked(entry, injectionResult);       if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {           if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {               CancelationOptions::Mode mode(isPointerEvent ?                       CancelationOptions::CANCEL_POINTER_EVENTS :                       CancelationOptions::CANCEL_NON_POINTER_EVENTS);               CancelationOptions options(mode, "input event injection failed");               synthesizeCancelationEventsForMonitorsLocked(options);           }           return true;       }       //支持 发送二次输入显示器的显示事件       // TODO: support sending secondary display events to input monitors       if (isMainDisplay(entry->displayId)) {           addMonitoringTargetsLocked(inputTargets);       }   // Dispatch the motion.       if (conflictingPointerActions) {           CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,                   "conflicting pointer actions");           synthesizeCancelationEventsForAllConnectionsLocked(options);       }       dispatchEventLocked(currentTime, entry, inputTargets);       return true;   }
          这里大概就是touch事件的处理流程, findTouchedWindowTargetsLocked 是找到对应的事件响应者的重要方法,下面开始详细说明
         
   Code In InputDispatcher   int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,           const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {       int32_t injectionResult;       String8 reason;
//这里判断是否有焦点的窗口跟焦点的应用
// 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; }
           ALOGI("Dropping event because there is no focused window or focused application.");        injectionResult = INPUT_EVENT_INJECTION_FAILED;        goto Failed;    }
    // Check permissions.   检查权限    if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {        injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;        goto Failed;    }
    // Check whether the window is ready for more input.
    // 检查窗口的状态,比如是否pause 等等    reason = checkWindowReadyForMoreInputLocked(currentTime,            mFocusedWindowHandle, entry, "focused");    if (!reason.isEmpty()) {        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());        goto Unresponsive;    }
    // Success!  Output targets.
    // 这里主要是Input 跟 目标窗口相关信息复制跟绑定,重点关注里面的InputChannel,这个跟窗口年消息通信有关    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;    addWindowTargetLocked(mFocusedWindowHandle,            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),            inputTargets);
     // Done.Failed:Unresponsive:    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);    updateDispatchStatisticsLocked(currentTime, entry,            injectionResult, timeSpentWaitingForApplication);#if DEBUG_FOCUS
     ALOGD("findFocusedWindow finished: injectionResult=%d, "            "timeSpentWaitingForApplication=%0.1fms",            injectionResult, timeSpentWaitingForApplication / 1000000.0);#endif    return injectionResult;   
               上面重点要关注的就是mFocusedWindowHandle  跟  mFocusedApplicationHandle 。他们是谁复制的呢?如何复制的呢?起什么作用了。明白了他们两个就可以明白了Input 跟对应的window的通信。下面就主要从这两个对象进行研究展开。findFocusedWindowTargetsLocked 的方法里面其他就是检查窗口状态等相关信息。

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

      void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {      Code 省略      // newFocusedWindowHandler      sp<InputWindowHandle> newFocusedWindowHandle;      //mFocusedWindowHandler 是被赋值为newFocusedWindowHandle      mFocusedWindowHandle = newFocusedWindowHandle;      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) {

      //这里调用com_android_server_input_InputManagerService.cpp            nativeSetInputWindows(mPtr, windowHandles);      }
            代码路径:frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

      void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {       Vector<sp<InputWindowHandle> > windowHandles;       if (windowHandleObjArray) {           jsize length = env->GetArrayLength(windowHandleObjArray);          for (jsize i = 0; i < length; i++) {               jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);               if (! windowHandleObj) {                   break; // found null element indicating end of used portion of the array               }               sp<InputWindowHandle> windowHandle =                       android_server_InputWindowHandle_getHandle(env, windowHandleObj);               if (windowHandle != NULL) {                   windowHandles.push(windowHandle);               }               env->DeleteLocalRef(windowHandleObj);           }       }       //这里会调用InputManager.cpp里面的方法       mInputManager->getDispatcher()->setInputWindows(windowHandles);       CODE 省略
             代码路径:frameworks/native/services/inputflinger/inputManager.cpp

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

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

            看下WMS 的 addWindow方法            

      Code In WindowManagerService.java      public int addWindow(Session session, IWindow client, int seq,                 WindowManager.LayoutParams attrs, int viewVisibility, int displayId,                 Rect outContentInsets, Rect outStableInsets, Rect outOutsets,                 InputChannel outInputChannel) {      Code 省略     if (focusChanged) {     //调用InputMonitor的方法设置接收窗口                   mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);               }               mInputMonitor.updateInputWindowsLw(false /*force*/);     Code 省略
          来看下InputMonitor 在干啥

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

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

         看下inputChannel的源码:

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

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

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

status_t InputChannel::openInputChannelPair(const String8& name,        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {    int sockets[2];    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {        status_t result = -errno;        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",                name.string(), errno);        outServerChannel.clear();        outClientChannel.clear();        return result;    } int bufferSize = SOCKET_BUFFER_SIZE;    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));String8 serverChannelName = name;    serverChannelName.append(" (server)");    outServerChannel = new InputChannel(serverChannelName, sockets[0]);    String8 clientChannelName = name;    clientChannelName.append(" (client)");    outClientChannel = new InputChannel(clientChannelName, sockets[1]);    return OK;
这个其实说明了inputChannel的open方法其实就是建立了socket通信

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

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

   public int addWindow(Session session, IWindow client, int seq,               WindowManager.LayoutParams attrs, int viewVisibility, int displayId,               Rect outContentInsets, Rect outStableInsets, Rect outOutsets,               InputChannel outInputChannel) {           int[] appOp = new int[1];           int res = mPolicy.checkAddPermission(attrs, appOp);           if (res != WindowManagerGlobal.ADD_OKAY) {   CODE 省略   if (outInputChannel != null && (attrs.inputFeatures                       & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {                   /** M: [ALPS00044207] @{ */                   try {                      //设置当前通道的名字                       String name = win.makeInputChannelName();                      //打开一对通道                       InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);                       win.setInputChannel(inputChannels[0]);                       inputChannels[1].transferTo(outInputChannel);                       mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);                   } catch (IllegalArgumentException e) {                       Slog.w(TAG, "handle Input channel erorr", e);                       return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;                   }                   /** @} */               }

到了这里基本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的博客真不好编辑代码的。


0 0
原创粉丝点击