一、概述
InputManagerService(下面简称IMS)在输入事件的获取和分发中,起着重要的作用。它是Android系统中的一个关键服务,主要有以下几个功能:
1、输入事件处理:
从各种输入设备(如触摸屏、键盘、鼠标等)接收输入事件。然后对接收到的输入事件进行处理,包括事件的转换、标准化等。
2、输入事件分发:
将处理后的输入事件分发给适当的应用程序或窗口。确保事件能够传递到当前焦点窗口或应用程序。
3、输入设备管理:
管理系统中的输入设备,包括设备的初始化、状态监控和驱动接口。支持动态添加和移除输入设备,同时进行相应的配置和调整。
本文主要分析IMS是如何处理输入事件的,代码基于Android 14。
二、IMS启动流程
首先看下IMS的启动流程,和其他重要的系统服务一样,IMS也是在SystemServer中启动的
frameworks/base/services/java/com/android/server/SystemServer.javaprivate void startOtherServices(@NonNull TimingsTraceAndSlog t) {t.traceBegin("startOtherServices");......InputManagerService inputManager = null;......t.traceBegin("StartInputManagerService");inputManager = new InputManagerService(context);//1.构造方法创建IMS对象t.traceEnd();......wm = WindowManagerService.main(context, inputManager, !mFirstBoot,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);......t.traceBegin("StartInputManager");inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());//2.为Input设置窗口变化的回调inputManager.start();//3.启动IMSt.traceEnd();......if (!isWatch) {t.traceBegin("StartWiredAccessoryManager");try {// Listen for wired headset changesinputManager.setWiredAccessoryCallbacks(new WiredAccessoryManager(context, inputManager));//监听有线配件(如耳机、键盘、鼠标等)的插入、移除和状态变化} catch (Throwable e) {reportWtf("starting WiredAccessoryManager", e);}t.traceEnd();}}
在startOtherServices()方法里启动IMS,启动IMS主要做了以下操作:
1.构造方法创建IMS对象
frameworks/base/services/core/java/com/android/server/input/InputManagerService.javapublic InputManagerService(Context context) {this(new Injector(context, DisplayThread.get().getLooper(), new UEventManager() {}));//IMS运行在"android.display"线程}@VisibleForTestingInputManagerService(Injector injector) {// The static association map is accessed by both java and native code, so it must be// initialized before initializing the native service.mStaticAssociations = loadStaticInputPortAssociations();mContext = injector.getContext();mHandler = new InputManagerHandler(injector.getLooper());mNative = injector.getNativeService(this);// 返回NativeInputManagerService.NativeImpl对象mSettingsObserver = new InputSettingsObserver(mContext, mHandler, this, mNative);//监听input相关的settings值,这些值可以被传到native侧mKeyboardLayoutManager = new KeyboardLayoutManager(mContext, mNative, mDataStore,injector.getLooper());//管理物理键盘的键盘布局mBatteryController = new BatteryController(mContext, mNative, injector.getLooper(),injector.getUEventManager());//管理输入设备的电池状态mKeyboardBacklightController = InputFeatureFlagProvider.isKeyboardBacklightControlEnabled()? new KeyboardBacklightController(mContext, mNative, mDataStore,injector.getLooper(), injector.getUEventManager()): new KeyboardBacklightControllerInterface() {};//管理键盘背光mStickyModifierStateController = new StickyModifierStateController();//用于管理ctrl+、shift+这种具有黏性的组合按键mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());//负责管理按键映射mPointerIconCache = new PointerIconCache(mContext, mNative);//光标图标相关mUseDevInputEventForAudioJack =mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);//是否对音频插孔使用 dev/input/event或uevent 子系统Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="+ mUseDevInputEventForAudioJack);String doubleTouchGestureEnablePath = mContext.getResources().getString(R.string.config_doubleTouchGestureEnableFile);mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :new File(doubleTouchGestureEnablePath);//双击手势相关mVelocityTrackerStrategy = DeviceConfig.getProperty(NAMESPACE_INPUT_NATIVE_BOOT, VELOCITYTRACKER_STRATEGY_PROPERTY);//触摸事件的速度和加速度相关injector.registerLocalService(new LocalService());}
IMS的构造方法主要就是创建mNative对象和一些input相关的管理类对象:键盘、光标、双击手势等。
重点是通过getNativeService(this)方法返回了NativeInputManagerService.NativeImpl对象,方法将IMS当做参数传递下去。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.javastatic class Injector {......NativeInputManagerService getNativeService(InputManagerService service) {return new NativeInputManagerService.NativeImpl(service, mLooper.getQueue());}......}
NativeInputManagerService是一个接口类,NativeImpl则是这个类的实现类,NativeImpl里的函数实现其实调用的都是native侧的函数:
frameworks/base/services/core/java/com/android/server/input/NativeInputManagerService.javainterface NativeInputManagerService {void start();....
}class NativeImpl implements NativeInputManagerService {@Overridepublic native void start();
}
所以,我们在IMS里通过mNative调用的方法最终是在native层实现的。
这些native方法是在native侧的com_android_server_input_InputManagerService.cpp里实现的。
继续看NativeImpl的构造方法:
frameworks/base/services/core/java/com/android/server/input/NativeInputManagerService.java/** The native implementation of InputManagerService methods. */class NativeImpl implements NativeInputManagerService {/** Pointer to native input manager service object, used by native code. */@SuppressWarnings({"unused", "FieldCanBeLocal"})private final long mPtr;NativeImpl(InputManagerService service, MessageQueue messageQueue) {mPtr = init(service, messageQueue);}private native long init(InputManagerService service, MessageQueue messageQueue);@Overridepublic native void start();......
}
NativeInputManagerService.NativeImpl的构造方法里调用init()方法初始化了mPtr这个对象,mPtr指向native层NativeInputManager对象。
init()方法是一个native方法,它的第一个参数service就是上面传下来的IMS,这样native侧就持有了上层IMS的引用了。
上文提到过,init()方法是在com_android_server_input_InputManagerService.cpp里实现的。
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cppstatic const JNINativeMethod gInputManagerMethods[] = {/* name, signature, funcPtr */{"init","(Lcom/android/server/input/InputManagerService;Landroid/os/""MessageQueue;)J",(void*)nativeInit},{"start", "()V", (void*)nativeStart},......
}
java层的init()方法对应native层的nativeInit()方法,strat()方法对应nativeStart()方法(后面分析start方法)。
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cppstatic jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj,jobject messageQueueObj) {sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);//获取messageQueueif (messageQueue == nullptr) {jniThrowRuntimeException(env, "MessageQueue is not initialized.");return 0;}static std::once_flag nativeInitialize;NativeInputManager* im = nullptr;std::call_once(nativeInitialize, [&]() {// Create the NativeInputManager, which should not be destroyed or deallocated for the// lifetime of the process.im = new NativeInputManager(serviceObj, messageQueue->getLooper());//创建NativeInputManager对象});LOG_ALWAYS_FATAL_IF(im == nullptr, "NativeInputManager was already initialized.");return reinterpret_cast<jlong>(im);
}
主要是通过new NativeInputManager来创建NativeInputManager对象,native层创建了NativeInputManager对象,然后返回给上层(上文说的mPtr指向native层NativeInputManager对象)。
看下创建NativeInputManager时做了哪些操作:
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cppNativeInputManager::NativeInputManager(jobject serviceObj, const sp<Looper>& looper): mLooper(looper), mInteractive(true) {JNIEnv* env = jniEnv();mServiceObj = env->NewGlobalRef(serviceObj);//指向InputManagerService对象InputManager* im = new InputManager(this, *this, *this, *this);//创建了InputManager对象mInputManager = im;defaultServiceManager()->addService(String16("inputflinger"), im);//在native层注册inputflinger服务
}
NativeInputManager的构造函数里有一个mServiceObj对象,指向上层的InputManagerService。而InputManagerService的mPtr指向底层的NativeInputManager,所以上层和底层就可以连接到一起。
创建InputManager对象
frameworks/native/services/inputflinger/InputManager.cppInputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy,InputDispatcherPolicyInterface& dispatcherPolicy,PointerChoreographerPolicyInterface& choreographerPolicy,InputFilterPolicyInterface& inputFilterPolicy) {mInputFlingerRust = createInputFlingerRust();mDispatcher = createInputDispatcher(dispatcherPolicy);//创建InputDispatcher对象,用于分发事件mTracingStages.emplace_back(std::make_unique<TracedInputListener>("InputDispatcher", *mDispatcher));if (ENABLE_INPUT_FILTER_RUST) {//启用或禁用Rust编写的输入过滤器mInputFilter = std::make_unique<InputFilter>(*mTracingStages.back(), *mInputFlingerRust,inputFilterPolicy);mTracingStages.emplace_back(std::make_unique<TracedInputListener>("InputFilter", *mInputFilter));InputFilter用于处理和过滤从输入设备(如触摸屏、键盘、鼠标等)传来的输入事件。}if (ENABLE_INPUT_DEVICE_USAGE_METRICS) {//是否对输入设备使用情况进行统计mCollector = std::make_unique<InputDeviceMetricsCollector>(*mTracingStages.back());mTracingStages.emplace_back(std::make_unique<TracedInputListener>("MetricsCollector", *mCollector));}mProcessor = std::make_unique<InputProcessor>(*mTracingStages.back());mTracingStages.emplace_back(std::make_unique<TracedInputListener>("InputProcessor", *mProcessor));if (ENABLE_POINTER_CHOREOGRAPHER) {//用于启用或禁用Pointer Choreographer这一功能mChoreographer =std::make_unique<PointerChoreographer>(*mTracingStages.back(), choreographerPolicy);mTracingStages.emplace_back(std::make_unique<TracedInputListener>("PointerChoreographer", *mChoreographer));//PointerChoreographer用于优化触摸事件处理和动画}mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mTracingStages.back());mTracingStages.emplace_back(std::make_unique<TracedInputListener>("UnwantedInteractionBlocker", *mBlocker));mReader = createInputReader(readerPolicy, *mTracingStages.back());//创建InputReader对象,用于读取事件
}
在InputManager中通过调用createInputDispatcher、createInputReader方法来分别创建InputDispatcher和InputReader对象。
InputDispatcher是Input系统中的一个重要组件,负责处理和分发来自输入设备(如触摸屏、键盘、鼠标等)的输入事件。它是 Android 输入事件处理架构中的核心部分,主要用于确保输入事件能够准确且高效地传递到系统中的相应窗口或应用程序。
InputReader负责从输入设备中读取原始的输入事件数据,并将这些数据传递给InputDispatcher进行进一步处理。它是 Android 输入事件处理体系中的一个关键部分,涉及从硬件层面获取输入事件并将其转换为系统能够理解和处理的格式。
先看下createInputDispatcher
frameworks/native/services/inputflinger/dispatcher/InputDispatcherFactory.cppstd::unique_ptr<InputDispatcherInterface> createInputDispatcher(InputDispatcherPolicyInterface& policy) {return std::make_unique<android::inputdispatcher::InputDispatcher>(policy);
}frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cppInputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,std::unique_ptr<trace::InputTracingBackendInterface> traceBackend): mPolicy(policy),mPendingEvent(nullptr),mLastDropReason(DropReason::NOT_DROPPED),mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),mMinTimeBetweenUserActivityPokes(DEFAULT_USER_ACTIVITY_POKE_INTERVAL),mNextUnblockedEvent(nullptr),mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT),mDispatchEnabled(false),mDispatchFrozen(false),mInputFilterEnabled(false),mMaximumObscuringOpacityForTouch(1.0f),mFocusedDisplayId(ADISPLAY_ID_DEFAULT),mWindowTokenWithPointerCapture(nullptr),mLatencyAggregator(),mLatencyTracker(&mLatencyAggregator) {mLooper = sp<Looper>::make(false);mReporter = createInputReporter();mWindowInfoListener = sp<DispatcherWindowListener>::make(*this);
#if defined(__ANDROID__)SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
#endifmKeyRepeatState.lastKeyEntry = nullptr;if (traceBackend) {mTracer = std::make_unique<trace::impl::InputTracer>(std::move(traceBackend));}mLastUserActivityTimes.fill(0);
}
createInputReader创建InputReader
frameworks/native/services/inputflinger/reader/InputReaderFactory.cppstd::unique_ptr<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy, InputListenerInterface& listener) {return std::make_unique<InputReader>(std::make_unique<EventHub>(), policy, listener);
}frameworks/native/services/inputflinger/reader/InputReader.cpp
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,const sp<InputReaderPolicyInterface>& policy,InputListenerInterface& listener): mContext(this),mEventHub(eventHub),mPolicy(policy),mNextListener(listener),mGlobalMetaState(AMETA_NONE),mLedMetaState(AMETA_NONE),mGeneration(1),mNextInputDeviceId(END_RESERVED_ID),mDisableVirtualKeysTimeout(LLONG_MIN),mNextTimeout(LLONG_MAX),mConfigurationChangesToRefresh(0) {refreshConfigurationLocked(/*changes=*/{});updateGlobalMetaStateLocked();
}
创建InputReader的时候还创建了EventHub,主要负责从底层输入系统中读取事件数据,并将这些事件数据提供给InputDispatcher进行进一步的处理和分发。
EventHub的主要工作流程为:
(1)从底层的输入设备驱动程序或系统中读取原始输入事件数据。这些事件数据可能包括触摸事件、按键事件、鼠标事件等
(2)将读取的原始事件数据解析成Android系统能够理解的事件格式(如 MotionEvent、KeyEvent 等)。
(3)将解析后的事件数据传递给InputDispatcher。
EventHub还可以跟踪输入设备的状态,包括设备的连接和断开。
2.设置窗口回调
wm.getInputManagerCallback获取到的是InputManagerCallback类,这个类实现了InputManagerService.WindowManagerCallbacks接口里的方法,里面定义了窗口管理器需要处理的输入事件相关的回调方法:
frameworks/base/services/core/java/com/android/server/input/InputManagerService.javapublic interface WindowManagerCallbacks extends LidSwitchCallback {void notifyConfigurationChanged();//系统配置发生变化的回调。例如横竖屏的改变、键盘、语言的变化等。void notifyPointerLocationChanged(boolean pointerLocationEnabled);//屏幕上指针变化(显示与否),pointer_location值发生变化void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);//相机镜头盖开关改变状态时void notifyInputChannelBroken(IBinder token);//输入通道的断开或错误情况。输入通道用于传递和管理输入事件,比如触摸、键盘、鼠标等。void notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle);//焦点app没有任何焦点窗口,并且无法响应焦点输入事件,发生anr。void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,@NonNull String reason);//窗口无响应void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid);//通知窗口管理器窗口已响应int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);//在输入事件被排队到消息队列之前拦截和处理键盘事件,意味着它会在事件还没有到达任何具体的窗口或视图之前进行处理。int interceptMotionBeforeQueueingNonInteractive(int displayId, int source, int action,long whenNanos, int policyFlags);//在不可交互状态下拦截触摸事件long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);//在键盘事件被分发到具体的窗口或视图之前进行拦截和处理,意味着事件已经被排队并准备分发到目标窗口或视图,但还未实际到达这些目标。KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags);//拦截未被处理的事件int getPointerLayer();//获取与当前触摸事件相关的指针图层int getPointerDisplayId();//获取触摸事件发生时的显示器/屏 idvoid onPointerDownOutsideFocus(IBinder touchedToken);//在未获得焦点的窗口上发生了ACTION_DOWN指针事件void notifyFocusChanged(IBinder oldToken, IBinder newToken);//焦点窗口发生变化void notifyDropWindow(IBinder token, float x, float y);//通常用于处理窗口的拖放操作,当一个窗口被用户拖动并放置在新的位置时,系统会调用这个方法来更新窗口的位置和状态SurfaceControl getParentSurfaceForPointers(int displayId);//获取触摸事件所涉及的指针的父级表面surface@NullableSurfaceControl createSurfaceForGestureMonitor(String name, int displayId);//主要作用是为手势监控创建一个新的表面Surface,这个表面可以用于捕获和处理手势事件,例如多点触控手势、滑动手势等void notifyPointerDisplayIdChanged(int displayId, float x, float y);//当鼠标指针的显示发生变化时通知WMS}
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback())可以将从窗口管理器获取的回调接口传递给IMS
。这使得input管理器能够通知窗口管理器有关输入事件的变化,例如触摸事件的处理、窗口的焦点变化等。
当用户与屏幕进行交互(如点击、滑动等)时,这些事件会被InputManager捕获,然后通过WindowManagerCallbacks接口传递给WindowManager。WindowManager再根据这些事件更新窗口的状态,如移动窗口、调整窗口大小等。
3.start()方法启动IMS
frameworks/base/services/core/java/com/android/server/input/InputManagerService.javapublic void start() {Slog.i(TAG, "Starting input manager");mNative.start();// Add ourselves to the Watchdog monitors.Watchdog.getInstance().addMonitor(this);//设置watchdog监听}
首先调用mNative.start()方法启动IMS,上文提到过mNative实际上是NativeInputManagerService的实例,start()方法在com_android_server_input_InputManagerService里对应nativeStart()方法:
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cppstatic void nativeStart(JNIEnv* env, jobject nativeImplObj) {NativeInputManager* im = getNativeInputManager(env, nativeImplObj);status_t result = im->getInputManager()->start();if (result) {jniThrowRuntimeException(env, "Input manager could not be started.");}
}
getInputManager() 方法获取到的是InputManager,调用InputManager.cpp里的start()方法
frameworks/native/services/inputflinger/InputManager.cppstatus_t InputManager::start() {status_t result = mDispatcher->start();//调用InputDispatcher的start方法if (result) {ALOGE("Could not start InputDispatcher thread due to error %d.", result);return result;}result = mReader->start();//调用InputReader的start方法if (result) {ALOGE("Could not start InputReader due to error %d.", result);mDispatcher->stop();//如果InputReader启动失败,停止InputDispatcher线程return result;}return OK;
}
InputManager.cpp里的start()方法主要做了两件事情:
(1)启动InputDispatcher线程
(2)启动InputReader线程
至此,IMS的启动流程结束。