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
- // 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());
- <span style="white-space:pre;"> </span>mUseDevInputEventForAudioJack =
- context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
- Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
- + mUseDevInputEventForAudioJack);
- <span style="white-space:pre;"> </span>//这里对mPtr 进行初始化,调用的还是native的方法,把这个service跟 Systemcontext 传给native对应的方法
- mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
- <span style="white-space:pre;"> </span> LocalServices.addService(InputManagerInternal.class, new LocalService());
- }
代码路径:/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自己 作为参数传过来了
- an style="white-space:pre;"> </span>NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
- messageQueue->getLooper());
- im->incStrong(0);
- return reinterpret_cast<jlong>(im);
代码路径: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;
- }
- <span style="white-space:pre;"> </span>mInteractive = true;
- <span style="white-space:pre;"> </span>//这个是从底层读取input 信息的提供者
- sp<EventHub> eventHub = new EventHub();
- mInputManager = new InputManager(eventHub, this, this);
- }
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.");
- }
- }
代码路径: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;
- }
- void InputManager::initialize() {
- mReaderThread = new InputReaderThread(mReader);
- mDispatcherThread = new InputDispatcherThread(mDispatcher);
- }
代码路径: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;
- 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();
- }
代码路径: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();
- }
- /*
- * 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;
- };
- 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) {
- 代码路径: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的值,<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>
- 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);
- }
- 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;
- }
- Code In InputDispatcher
- int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
- const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
- int32_t injectionResult;
- String8 reason;
- 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;
mFocusedWindowHandler 谁复制的呢?经过查询在InputDispatcher 里面就如下的方法
- void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
- Code 省略
- // newFocusedWindowHandler
- sp<InputWindowHandle> newFocusedWindowHandle;
- //mFocusedWindowHandler 是被赋值为newFocusedWindowHandle
- mFocusedWindowHandle = newFocusedWindowHandle;
- Code 省略
看下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);
- }
- 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 省略
- sp<InputDispatcherInterface> InputManager::getDispatcher() {
- //获得InputDispatcheer.cpp 对象
- return mDispatcher;
代码路径: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 省略
代码路径: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");
- }
看下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);
- }
- 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);
- 代码省略
代码路径: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;
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事件分发机制
- 手势与触摸的事件分发机制
- Jupyter Notebook 修改默认启动目录
- for of
- window.location.href 带参数跳转 如何获取值(解决)
- 科大讯飞语音开发包上手体验(2)
- 数论函数&狄利克雷卷积
- InputManagerService之事件的初始化与分发
- Writeup of Mountainclimbing(reverse) in BugKu
- local_irq_disable,irq_disable与disable_irq的区别
- 点击事件冲突
- R语言处理日期值的数值和字符串之间的相互转换
- vue2.0单页面spa在微信中title设置
- Java 8-----默认方法(Default Methods)
- CSS
- angular实现添加,删除,查询,排序