Android源码笔记-输入事件(一)

news/2024/6/23 20:28:12

          这一节主要了解一下Android输入事件源码,Android输入系统的工作原理概括来说,就是监控/dev/input/下的所有设备节点,当某个节点有数据可读时,将数据读出并进行一系列的加工,然后在所有的窗口中寻找合适的事件接收者,并派发给它。 整体含有几个关键因素:

Linux内核:接受输入设备的中断,并将原始事件的数据写入设备节点中。

设备节点:作为内核与IMS的桥梁,它将原始事件的数据暴露给用户空间,以便IMS可以从中读取事件。

EventHub:直接访问所有的设备节点。并且正如其名字所描述的,它通过一个名为getEvents()的函数将所有输入系统相关的待处理的底层事件返回给使用者。这些事件包括原始输入事件、设备节点的增删等。

InputReader,是IMS中的关键组件之一。它运行于一个独立的线程中,负责管理输入设备的列表与配置,以及进行输入事件的加工处理。它通过其线程循环不断地通过getEventsO)函数从EventHub 中将事件取出并进行处理。对于设备节点的增删事件,它会更新输入设备列表与配置。对于原始输入事件,InputReader对其进行翻译、组装、封装为包含更多信息、更具可读性的输人事件,然后交给 InputDispatcher 进行派发。

InputReaderPolicy:它为InputReader的事件加工处理提供一些策略配置,例如键盘布局信息等。

InputDispatcher:是IMS中的另一个关键组件。它也运行于一个独立的线程中。InputDispatcher中保管了来自WMS的所有窗口的信息,其收到来自InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口。

InputDispatcherPolicy:它为InputDispatcher的派发过程提供策略控制。例如截取某些特定的输入事件用作特殊用途,或者阻止将某些事件派发给目标窗口。一个典型的例子就是HOME键被InputDispatcherPolicy截取到PhoneWindowManager中进行处理,并阻止窗口收到HOME键按下的事件。

WMS:虽说不是输入系统中的一员,但是它却对InputDispatcher的正常工作起到了至关重要的作用。当新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道。另外,WMS还将所有窗口的信息,包括窗口的可点击区域、焦点窗口等信息,实时地更新到IMS的InputDispatcher 中,使得InputDispatcher 可以正确地将事件派发到指定的窗口。

ViewRootImpl:对某些窗口,如壁纸窗口、SurfaceView的窗口来说,窗口就是输入事件派发的终点。而对其他的如Activity、对话框等使用了Android 控件系统的窗口来说,输入事件的终点是控件(View)。ViewRootImpl将窗口所接收的输人事件沿着控件树将事件派发给感兴趣的控件。

frameworks/base/services/java/com/android/server/SystemServer.javapublic static void main(String[] args) {new SystemServer().run();}private void run() {TimingsTraceAndSlog t = new TimingsTraceAndSlog();try {t.traceBegin("InitBeforeStartServices");// Record the process start information in sys props.SystemProperties.set(SYSPROP_START_COUNT, String.valueOf(mStartCount));SystemProperties.set(SYSPROP_START_ELAPSED, String.valueOf(mRuntimeStartElapsedTime));SystemProperties.set(SYSPROP_START_UPTIME, String.valueOf(mRuntimeStartUptime));EventLog.writeEvent(EventLogTags.SYSTEM_SERVER_START,mStartCount, mRuntimeStartUptime, mRuntimeStartElapsedTime);      // The system server should never make non-oneway callsBinder.setWarnOnBlocking(true);// The system server should always load safe labelsPackageItemInfo.forceSafeLabels();// Default to FULL within the system server.SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;// Deactivate SQLiteCompatibilityWalFlags until settings provider is initializedSQLiteCompatibilityWalFlags.init(null);// Here we go!Slog.i(TAG, "Entered the Android system server!");final long uptimeMillis = SystemClock.elapsedRealtime();EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);if (!mRuntimeRestart) {FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_INIT_START,uptimeMillis);}SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());// Mmmmmm... more memory!VMRuntime.getRuntime().clearGrowthLimit();// Some devices rely on runtime fingerprint generation, so make sure// we've defined it before booting further.Build.ensureFingerprintProperty();// Create the system service manager.mSystemServiceManager = new SystemServiceManager(mSystemContext);mSystemServiceManager.setStartInfo(mRuntimeRestart,mRuntimeStartElapsedTime, mRuntimeStartUptime);LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);// Prepare the thread pool for init tasks that can be parallelizedSystemServerInitThreadPool.start();// Attach JVMTI agent if this is a debuggable build and the system property is set....} finally {t.traceEnd();  // InitBeforeStartServices}// Setup the default WTF handlerRuntimeInit.setDefaultApplicationWtfHandler(SystemServer::handleEarlySystemWtf);// Start services.try {t.traceBegin("StartServices");// 启动引导服务startBootstrapServices(t);// 启动核心服务startCoreServices(t);// 启动其他服务 startOtherServices(t);} catch (Throwable ex) {Slog.e("System", "******************************************");Slog.e("System", "************ Failure starting system services", ex);throw ex;} finally {t.traceEnd(); // StartServices}StrictMode.initVmDefaults(null);...// Diagnostic to ensure that the system is in a base healthy state. Done here as a common// non-zygote process.if (!VMRuntime.hasBootImageSpaces()) {Slog.wtf(TAG, "Runtime is not running with a boot image!");}// Loop forever.Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}private void startOtherServices(@NonNull TimingsTraceAndSlog t) {final Context context = mSystemContext;VibratorService vibrator = null;DynamicSystemService dynamicSystem = null;IStorageManager storageManager = null;NetworkManagementService networkManagement = null;IpSecService ipSecService = null;NetworkStatsService networkStats = null;NetworkPolicyManagerService networkPolicy = null;ConnectivityService connectivity = null;NsdService serviceDiscovery = null;WindowManagerService wm = null;SerialService serial = null;NetworkTimeUpdateService networkTimeUpdater = null;InputManagerService inputManager = null;TelephonyRegistry telephonyRegistry = null;ConsumerIrService consumerIr = null;MmsServiceBroker mmsService = null;HardwarePropertiesManagerService hardwarePropertiesService = null;try {t.traceBegin("StartInputManagerService");inputManager = new InputManagerService(context);wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());inputManager.start();		} catch (Throwable e) {Slog.e("System", "******************************************");Slog.e("System", "************ Failure starting core service");throw e;}		} 
/frameworks/base/services/core/java/com/android/server/input/InputManagerService.javapublic void start() {Slog.i(TAG, "Starting input manager");nativeStart(mPtr);// Add ourself to the Watchdog monitors.Watchdog.getInstance().addMonitor(this);registerPointerSpeedSettingObserver();registerShowTouchesSettingObserver();registerAccessibilityLargePointerSettingObserver();registerLongPressTimeoutObserver();mContext.registerReceiver(new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {updatePointerSpeedFromSettings();updateShowTouchesFromSettings();updateAccessibilityLargePointerFromSettings();updateDeepPressStatusFromSettings("user switched");}}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);updatePointerSpeedFromSettings();updateShowTouchesFromSettings();updateAccessibilityLargePointerFromSettings();updateDeepPressStatusFromSettings("just booted");}
/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cppstatic void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);status_t result = im->getInputManager()->start();if (result) {jniThrowRuntimeException(env, "Input manager could not be started.");}}inline sp<InputManager> getInputManager() const { return mInputManager; }

用reinterpret_cast操作符将jlong类型的ptr强制转换为原类型(NativeInputManager指针类型)。

 /frameworks/native/services/inputflinger/InputManager.cppstatus_t InputManager::start() {status_t result = mDispatcher->start();if (result) {ALOGE("Could not start InputDispatcher thread due to error %d.", result);return result;}result = mReader->start();if (result) {ALOGE("Could not start InputReader due to error %d.", result);mDispatcher->stop();return result;}return OK;
}
/frameworks/native/services/inputflinger/reader/InputReaderFactory.cppnamespace android {sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) {return new InputReader(std::make_unique<EventHub>(), policy, listener);
}} // namespace android/frameworks/native/services/inputflinger/reader/InputReader.cppstatus_t InputReader::start() {if (mThread) {return ALREADY_EXISTS;}mThread = std::make_unique<InputThread>("InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });return OK;
}
/frameworks/native/services/inputflinger/InputThread.cppclass InputThreadImpl : public Thread {
public:explicit InputThreadImpl(std::function<void()> loop): Thread(/* canCallJava */ true), mThreadLoop(loop) {}~InputThreadImpl() {}private:std::function<void()> mThreadLoop;bool threadLoop() override {mThreadLoop();return true;}
};

InputManager的start函数运行了InputDispatcherThread和InputReaderThread线程;

InputDispatcher和InputReader是在哪创建的

/frameworks/native/services/inputflinger/InputManager.cppInputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {mDispatcher = createInputDispatcher(dispatcherPolicy);mClassifier = new InputClassifier(mDispatcher);mReader = createInputReader(readerPolicy, mClassifier);
}

可以看出InputDispatcher和InputReader是有关联的,InputDispatcher会作为一个参数传入到InputReader中;


https://www.xjx100.cn/news/3366599.html

相关文章

Solana 线下活动回顾|多方创新实践,引领 Solana“文艺复兴”新浪潮

Solana 作为在过去一年里实现突破式飞跃的头部公链&#xff0c;究竟是如何与 Web3 行业共振&#xff0c;带来全新的技术发展与生态亮点的呢&#xff1f;在 3 月 24 日刚结束的「TinTin Destination Moon」活动现场&#xff0c;来自 Solana 生态的的专家大咖和 Web3 行业的资深人…

演绎推理【科学推理】

演绎推理是集观察&#xff0c;实验&#xff0c;类比&#xff0c;联想&#xff0c;联想&#xff0c;经验归纳为一体的推理方法。 特点是有一般到特殊&#xff0c;有分析&#xff0c;综合&#xff0c;化归等解题策略。 正推是充分性&#xff0c; 反推是必要性。 小充分 …

谈谈你对 ES6 的理解

es6 是一个新的标准&#xff0c;它包含了许多新的语言特性和库&#xff0c;是 JS 最实质性的一次升级。 比如箭头函数、字符串模板、generators(生成器)、async/await、解构赋值、class等等&#xff0c;还有就是引入 module 模块的概念。 箭头函数可以让 this 指向固定化&…

【算法每日一练]-数论(保姆级教程 篇1 埃氏筛,欧拉筛)

目录 保证给你讲透讲懂 第一种&#xff1a;埃氏筛法 第二种&#xff1a;欧拉筛法 题目&#xff1a;质数率 题目&#xff1a;不喜欢的数 思路&#xff1a; 问题&#xff1a;1~n 中筛选出所有素数&#xff08;质数&#xff09; 有两种经典的时间复杂度较低的筛法&#xff0…

[实验报告]--基于端口安全

[实验报告] 目录 [实验报告] 一、项目背景 二、实验环境 三、项目规划设计 四、项目实施 五、验证项目成果 基于端口安全的 Jan16 公司网络组建 一、项目背景 Jan16 公司开发部为重要部门&#xff0c;所有员工使用指定的计算机工作&#xff0c;为防止员工或访客使 用个…

【c++基础】数池塘(四方向)

说明 农夫约翰的农场可以表示成N*M&#xff08;1≤N、M≤100&#xff09;个方格组成的矩形。由于近日的降雨&#xff0c;在约翰农场上的不同地方形成了池塘。每一个方格或者有积水&#xff08;W&#xff09;或者没有积水&#xff08;.&#xff09;。农夫约翰打算数出他的农场上…

Smart-Config SpringBoot动态变更配置 单机版apollo

Smart-Config&#xff08;单机Apollo&#xff09; 智能配置&#xff1a;单体应用下的动态配置。主要用来解决在单体应用没有配置中心时&#xff0c;想要实现动态变更配置&#xff0c;程序自动处理配置变更&#xff0c;给字段赋值的痛点。可以理解为单机版的Apollo。Apollo是携…

element-ui avatar 组件源码分享

今日简单分享 avatar 组件的源码实现&#xff0c;主要从以下四个方面&#xff1a; 1、avatar 组件页面结构 2、avatar 组件属性 3、avatar 组件事件 4、avatar 组件 slot 一、avatar 组件页面结构 二、avatar 组件属性 2.1 icon 属性&#xff0c;设置头像的图标类型&…