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的博客真不好编辑代码的。
- InputManagerService之事件的初始化与分发
- InputManagerService之事件的初始化与分发
- InputManagerService服务的初始化
- InputManagerService分发输入事件给应用程序(上)
- InputManagerService分发输入事件给应用程序(下)
- InputManagerService分析一:IMS的启动与事件传递
- Android事件机制之ViewPager的分发与拦截
- Android 事件分发机制解析之View的事件分发
- Android之事件分发与消费机制
- Android 应用初始化及窗体事件的分发
- Android 应用初始化及窗体事件(按键)的分发
- Android 应用初始化及窗体事件的分发
- Android 应用初始化及窗体事件的分发
- Android 应用初始化及窗体事件的分发
- Android 应用初始化及窗体事件的分发
- Android 应用初始化及窗体事件(按键)的分发
- View的事件体系之View位置参数与View事件分发机制
- 手势与触摸的事件分发机制
- PostgreSQL log配置
- 如何抢到腾讯云校园1元优惠资格(新版腾讯云)-更新
- h5上传格式设置,frameset使用方法
- 2016东莞市特长生考试 子数整数
- 二叉树的简单实现
- InputManagerService之事件的初始化与分发
- QT之toolbox简单实例
- Oracle(18)pl/sql编程 概念、快速入门及编程规范
- Kindergarten Election ZOJ
- 【原创】C++ 动态数组 vector 详解
- Java 时间转换
- process.waitFor() 返回值含义
- .net中跨数据库遇到的问题 分布式
- 正则表达式