当前位置: 首页 > news >正文

Android11 InputManagerService启动流程分析

InputManagerService在systemserver进程中被启动

//frameworks\base\services\java\com\android\server\SystemServer.java
t.traceBegin("StartInputManagerService");
inputManager = new InputManagerService(context);//1
t.traceEnd();
//省略
//注册服务
ServiceManager.addService(Context.INPUT_SERVICE, inputManager, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);//2
//省略
inputManager.start();//3

注释1处创建InputManagerService对象,注释2处注册input服务。注释3处调用inputManager的start方法。先来看一下InputManagerService对象的创建过程

//frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
public InputManagerService(Context context) {//省略mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());//省略
}

继续调用nativeInit方法,这是一个native方法,会通过JNI调用到com_android_server_input_InputManagerService.cpp的nativeInit方法

//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 == nullptr) {jniThrowRuntimeException(env, "MessageQueue is not initialized.");return 0;}NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper());//1im->incStrong(0);return reinterpret_cast<jlong>(im);
}static const JNINativeMethod gInputManagerMethods[] = {/* name, signature, funcPtr */{"nativeInit","(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/""MessageQueue;)J",(void*)nativeInit},//省略

注释1处,继续创建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();mServiceObj = env->NewGlobalRef(serviceObj);//省略mInteractive = true;mInputManager = new InputManager(this, this);//1defaultServiceManager()->addService(String16("inputflinger"),mInputManager, false);//2
}

注释1处创建InputManager对象,注释2处,这里又在native层注册了一个inputflinger服务。

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

注释1处创建InputDispatcher对象,注释2处创建InputClassifier对象,注释3处创建InputReader对象。接下来看一下各个对象的创建过程
InputDispatcher:

//frameworks\native\services\inputflinger\dispatcher\InputDispatcherFactory.cpp
sp<InputDispatcherInterface> createInputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) {return new android::inputdispatcher::InputDispatcher(policy);
}//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy): mPolicy(policy),//1mPendingEvent(nullptr),mLastDropReason(DropReason::NOT_DROPPED),mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),mAppSwitchSawKeyDown(false),mAppSwitchDueTime(LONG_LONG_MAX),mNextUnblockedEvent(nullptr),mDispatchEnabled(false),mDispatchFrozen(false),mInputFilterEnabled(false),// mInTouchMode will be initialized by the WindowManager to the default device config.// To avoid leaking stack in case that call never comes, and for tests,// initialize it here anyways.mInTouchMode(true),mFocusedDisplayId(ADISPLAY_ID_DEFAULT) {mLooper = new Looper(false);mReporter = createInputReporter();mKeyRepeatState.lastKeyEntry = nullptr;policy->getDispatcherConfiguration(&mConfig);
}

注释1处将policy赋给mPolicy,这里的policy就是传进来的NativeInputManager对象。所以,InputDispatcher中的mPolicy指向的是NativeInputManager对象

InputClassifier:

//frameworks\native\services\inputflinger\InputClassifier.cpp
InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener): mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}

mListener指向listener,这里的listener就是我们前面创建的InputDispatcher对象,所以,InputClassifier中的mListener指向的是一个InputDispatcher对象

InputReader:

//frameworks\native\services\inputflinger\reader\InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) {return new InputReader(std::make_unique<EventHub>(), policy, listener);//1
}

注释1处先创建一个EventHub,然后创建一个InputReader对象

//frameworks\native\services\inputflinger\reader\EventHub.cpp
EventHub::EventHub(void): mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),mNextDeviceId(1),mControllerNumbers(),mOpeningDevices(nullptr),mClosingDevices(nullptr),mNeedToSendFinishedDeviceScan(false),mNeedToReopenDevices(false),mNeedToScanDevices(true),mPendingEventCount(0),mPendingEventIndex(0),mPendingINotify(false) {ensureProcessCanBlockSuspend();mEpollFd = epoll_create1(EPOLL_CLOEXEC);//1LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));mINotifyFd = inotify_init();//2mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);//3LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,strerror(errno));//省略struct epoll_event eventItem = {};eventItem.events = EPOLLIN | EPOLLWAKEUP;eventItem.data.fd = mINotifyFd;int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);//4LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);//省略

注释1处创建一个epoll,用于监听是否有数据可供读入。注释2处初始化inotify,并在注释3处将DEVICE_PATH添加到inotify的监测中,DEVICE_PATH为/dev/input。注释4处将这个inotify又添加到epoll的监测中。如果DEVICE_PATH目录下有设备节点增加或删除,inotify就可以监测到,mINotifyFd就有数据可供读入,epoll也就可以监测到了。
接着回到InputReader的创建里面

InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener): mContext(this),mEventHub(eventHub),//1mPolicy(policy),//2mGlobalMetaState(0),mGeneration(1),mNextInputDeviceId(END_RESERVED_ID),mDisableVirtualKeysTimeout(LLONG_MIN),mNextTimeout(LLONG_MAX),mConfigurationChangesToRefresh(0) {mQueuedListener = new QueuedInputListener(listener);//3{ // acquire lockAutoMutex _l(mLock);refreshConfigurationLocked(0);updateGlobalMetaStateLocked();} // release lock
}

注释1处将mEventHub指向上面创建的EventHub对象。注释2处将mPolicy指向传进来的policy,而传进来的policy为NativeInputManager对象,所以,InputReader中的mPolicy也是指向NativeInputManager对象,注释3处根据传进来的InputClassifier对象构造QueuedInputListener

//frameworks\native\services\inputflinger\InputListener.cpp
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :mInnerListener(innerListener) {
}

所以QueuedInputListener对象中的mInnerListener指向的是一个InputClassifier对象

至此,各个对象的创建都已完毕,来看一下各对象简易的类图

在这里插入图片描述

接着回到systemserver中,InputManagerService对象创建后,就会调用该对象的start方法

//frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
public void start() {Slog.i(TAG, "Starting input manager");nativeStart(mPtr);
//省略

继续调用nativeStart,这也是一个Native方法,调用com_android_server_input_InputManagerService.cpp的nativeStart方法

//frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);status_t result = im->getInputManager()->start();//2if (result) {jniThrowRuntimeException(env, "Input manager could not be started.");}
}static const JNINativeMethod gInputManagerMethods[] = {/* name, signature, funcPtr *///省略{"nativeStart", "(J)V", (void*)nativeStart},//省略

注释1处getInputManager返回的是上面创建的InputManager对象,调用InputManager的start方法

//frameworks\native\services\inputflinger\InputManager.cpp
status_t InputManager::start() {status_t result = mDispatcher->start();//1if (result) {ALOGE("Could not start InputDispatcher thread due to error %d.", result);return result;}result = mReader->start();//2if (result) {ALOGE("Could not start InputReader due to error %d.", result);mDispatcher->stop();return result;}return OK;
}

注释1处调用InputDispatcher的start方法,注释2处调用InputReader的start方法

//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
status_t InputDispatcher::start() {if (mThread) {return ALREADY_EXISTS;}mThread = std::make_unique<InputThread>("InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });return OK;
}//frameworks\native\services\inputflinger\reader\InputReader.cpp
status_t InputReader::start() {if (mThread) {return ALREADY_EXISTS;}mThread = std::make_unique<InputThread>("InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });return OK;
}

可以看出,分别启动了InputDispatcher和InputReader线程。InputReader线程启动调用loopOnce读取事件,InputDispatcher线程启动调用dispatchOnce分发事件

总结
在InputManagerService启动过程中,会启动两个线程,InputReader和InputDispatcher线程,用于读取数据和分发数据。其中在InputReader对象的创建过程中,会创建EventHub对象,初始化Epoll和inotify用于监测/dev/input目录
InputDispatcher和InputReader对象的创建流程
在这里插入图片描述
InputDispatcher和InputReader线程的启动流程:

在这里插入图片描述

相关文章:

Android11 InputManagerService启动流程分析

InputManagerService在systemserver进程中被启动 //frameworks\base\services\java\com\android\server\SystemServer.java t.traceBegin("StartInputManagerService"); inputManager new InputManagerService(context);//1 t.traceEnd(); //省略 //注册服务 Servi…...

【计算机网络篇】数据链路层(8)共享式以太网的退避算法和信道利用率

文章目录 &#x1f6f8;共享式以太网的退避算法&#x1f95a;截断二进制指数算法 &#x1f354;共享式以太网的信道利用率 &#x1f6f8;共享式以太网的退避算法 在使用CSMA/CD协议的共享总线以太网中&#xff0c;正在发送帧的站点一边发送帧一边检测碰撞&#xff0c;当检测到…...

wordpress主题 7B2 PRO主题5.4.2免授权直接安装

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 WordPress 资讯、资源、社交、商城、圈子、导航等多功能商用主题&#xff1a;B2 PRO 其设计风格专业且时尚&#xff0c;功能十分强大&#xff0c;包括多栏布局、自定义页面、强大的主…...

Dubbo基本使用

Dubbo基本使用 1.项目介绍2.开发步骤2.1 启动注册中心2.2 初始化项目2.3 添加 Maven 依赖2.3.1 父pom.xml2.3.1 consumer模块和provider模块pom.xml 2.4 定义服务接口2.5 定义服务端的实现2.6 配置服务端 Yaml 配置文件2.7 配置消费端 Yaml 配置文件2.8 基于 Spring 配置服务端…...

JS解密之新js加密实战(二)

前言 上次发了一篇关于新加密的&#xff0c;只解了前边两层&#xff0c;这中间家里各种事情因素影响&#xff0c;没有继续进一步研究&#xff0c;今天百忙之中抽空发布第二篇&#xff0c;关于其中的一小段加密片段&#xff0c;我认为分割成多个小片段是更容易被理解的。逻辑相…...

tsconfig 备忘清单

前言 ❝ Nealyang/blog0 使用 ts 已多年&#xff0c;但是貌似对于 tsconfig 总是记忆不清&#xff0c;每次都是 cv 历史项目&#xff0c;所以写了这篇备忘录&#xff0c;希望能帮助到大家。 本文总结整理自 Matt Pocock 的一篇文章3&#xff0c;加以个人理解&#xff0c;并做了…...

jmeter后置处理器提取到的参数因为换行符导致json解析错误

现象&#xff1a; {"message":"JSON parse error: Illegal unquoted character ((CTRL-CHAR, code 10)): has to be escaped using backslash to be included in string value; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Ill…...

栈与队列的实现

前言 本次博客将要实现一下栈和队列&#xff0c;好吧 他们两个既可以使用动态数组也可以使用链表来实现 本次会有详细的讲解 栈的实现 栈的基础知识 什么是栈呢&#xff1f; 栈的性质是后进先出 来画个图来理解 当然可不可以出一个进一个呢&#xff0c;当然可以了 比如…...

线性集合:ArrayList,LinkedList,Vector/Stack

共同点&#xff1a;都是线性集合 ArrayList ArrayList 底层是基于数组实现的&#xff0c;并且实现了动态扩容&#xff08;当需要添加新元素时&#xff0c;如果 elementData 数组已满&#xff0c;则会自动扩容&#xff0c;新的容量将是原来的 1.5 倍&#xff09;&#xff0c;来…...

llama3 发布!大语言模型新选择 | 开源日报 No.251

meta-llama/llama Stars: 53.0k License: NOASSERTION llama 是用于 Llama 模型推理的代码。 提供了预训练和微调的 Llama 语言模型&#xff0c;参数范围从 7B 到 70B。可以通过下载脚本获取模型权重和 tokenizer。支持在本地快速运行推理&#xff0c;并提供不同规格的模型并…...

SpringBoot 具体是做什么的?

Spring Boot是一个用于构建独立的、生产级别的、基于Spring框架的应用程序的开源框架。它的目标是简化Spring应用程序的开发和部署过程&#xff0c;通过提供一种快速、便捷的方式来创建Spring应用程序&#xff0c;同时保持Spring的灵活性和强大特性。 1. 简化Spring应用程序开…...

Debian常用命令

Debian是一个开源的Unix-like操作系统&#xff0c;提供了大量的软件包供用户安装和使用。在Debian系统中&#xff0c;命令行界面&#xff08;CLI&#xff09;是用户与系统进行交互的重要工具。以下是Debian中一些常用的命令及其详细解释&#xff1a; 文件和目录操作命令&#x…...

常见的前端框架

常用的前端框架有以下几种&#xff1a; 模型 React&#xff1a;由Facebook开发的一款前端框架&#xff0c;采用虚拟DOM的概念&#xff0c;可高效地更新页面。Vue.js&#xff1a;一款轻量级的前端框架&#xff0c;易学易用&#xff0c;支持组件化开发和双向数据绑定。AngularJ…...

初学者如何选择ARM开发硬件?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「ARM的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;如果你没有ARM开发经验&#xff0…...

Mysql 多表查询,内外连接

内连接&#xff1a; 隐式内连接 使用sql语句直接进行多表查询 select 字段列表 from 表1 , 表2 where 条件 … ; 显式内连接 将‘&#xff0c;’改为 inner join 连接两个表的 on select 字段列表 from 表1 [ inner ] join 表2 on 连接条件 … ; select emp.id, emp.name, …...

【C语言】函数

目录 一、函数的概念 二、库函数 2.1 ❥ 标准库 2.2 ❥ 库函数的使用方法 三、自定义函数 四、形参和实参 4.1 ❥ 实参&#xff08;实际参数&#xff09; 4.2 ❥ 形参&#xff08;形式参数&#xff09; 五、return语句 六、函数的调用 6.1 ❥ 传值调用 6.2 ❥ 传址调…...

【LeetCode】每日一题 2024_5_13 腐烂的橘子(经典多源 BFS)

文章目录 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01;题目&#xff1a;找出不同元素数目差数组题目描述代码与解题思路 每天进步一点点 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 好久没写每日一题题解了&#xff0c;今天重新起航 干…...

【Linux系统编程】第十七弹---进程理解

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、进程的基本概念 2、描述进程-PCB 2.1、什么是PCB 2.2、为什么要有PCB 3、task_ struct 3.1、启动进程 3.2、创建进程…...

【网络安全入门】你必须要有的学习工具(附安装包)零基础入门到进阶,看这一篇就够了!

工欲善其事必先利其器 在新入门网络安全的小伙伴而言。这些工具你必须要有所了解。本文我们简单说说这些网络安全工具吧&#xff01; Web安全类 Web类工具主要是通过各种扫描工具&#xff0c;发现web站点存在的各种漏洞如sql注入、xss等。从而获取系统权限&#xff0c;常用的…...

【解决】:git clone项目报错fatal: fetch-pack: invalid index-pack output

象&#xff1a;之前一直使用gitee将个人学习和工作相关记录上传到个人gitee仓库&#xff0c;一直没出现过问题。直到有一天换电脑重新拉取代码发现出了问题&#xff0c;具体如下图&#xff1a; 原因分析&#xff1a; 经过查询发现主要原因是因为git clone的远程仓库的项目过大…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...