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线程的启动流程:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/9220.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

socket实现TCP UDP

1、socket通信建立流程 1.1、创建服务端流程 使用 socket 函数来创建 socket服务。 使用 bind 函数绑定端口。 使用 listen 函数监听端口。 使用 accept 函数接收客户端请求。 1.2、创建客户端流程 使用 socket 函数来创建 socket 服务。 使用 connect 函数连接到 socke…

基于springboot+jsp+Mysql的商务安全邮箱邮件收发

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

【强训笔记】day16

NO.1 代码实现&#xff1a; class StringFormat { public:string formatString(string A, int n, vector<char> arg, int m) {string ret;int j0;for(int i0;i<n;i){if(A[i]%){if(i1<n&&A[i1]s){retarg[j];i;}else {retA[i];}}else {retA[i];}}while(j&l…

设计模式之拦截过滤器模式

想象一下&#xff0c;在你的Java应用里&#xff0c;每个请求就像一场冒险旅程&#xff0c;途中需要经过层层安检和特殊处理。这时候&#xff0c;拦截过滤器模式就化身为你最可靠的特工团队&#xff0c;悄无声息地为每一个请求保驾护航&#xff0c;确保它们安全、高效地到达目的…

小白必看:数据防泄密软件介绍|安在云和Ping32对比?

在当今数字化时代&#xff0c;数据防泄密软件已经成为企业和组织不可或缺的重要工具。随着信息技术的发展&#xff0c;企业面临着越来越多的网络安全威胁&#xff0c;数据泄露事件也屡见不鲜。数据防泄密软件的出现&#xff0c;为企业提供了有效的解决方案。 一、数据防泄密软…

wlan二层旁挂组网实验

实验拓扑图 代码&#xff1a; SW1 <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sysn sw1 [sw1]undo info-center enable Info: Information center is disabled. [sw1]vlan batch 10 20 30 Info: This operation may take a few seconds. …

Linux网络——自定义序列化与反序列化

前言 之前我们学习过socket之tcp通信&#xff0c;知道了使用tcp建立连接的一系列操作&#xff0c;并通过write与read函数能让客户端与服务端进行通信&#xff0c;但是tcp是面向字节流的&#xff0c;有可能我们write时只写入了部分数据&#xff0c;此时另一端就来read了&#x…

rk3588局域网推流

最近无意间看见在网上有使用MediaMtx插件配合ffmpeg在Windows来进行推流&#xff0c;然后在使用其他软件进行拉流显示数据图像的&#xff0c;既然windows都可以使用 &#xff0c;我想linux应该也可以&#xff0c;正好手上也有一块RK3588的开发板&#xff0c;就测试了一下&#…

【每日刷题】Day35

【每日刷题】Day35 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 844. 比较含退格的字符串 - 力扣&#xff08;LeetCode&#xff09; 2. 2487. 从链表中移除节点 - 力…

【启明智显技术分享】“ESP-IDF环境搭建全攻略:告别基于乐鑫方案彩屏开发中的搭建难题”

前言&#xff1a; 【启明智显】专注于HMI&#xff08;人机交互&#xff09;及AIoT&#xff08;人工智能物联网&#xff09;产品和解决方案的提供商&#xff0c;我们深知彩屏显示方案在现代物联网应用中的重要性。为此&#xff0c;我们一直致力于为客户提供彩屏显示方案相关的技…

银行职员向媒体投稿发文章我找到了好方法

作为一名基层银行的媒体联络专员,我的日常工作中有一项至关重要的任务,那就是代表我所在的支行向各大媒体投稿,传播我们的金融服务、产品动态以及社会责任实践。起初,这项看似简单的工作却成了我职业生涯中的一大挑战。传统的邮件投稿方式,不仅耗时费力,而且审核流程严格,稿件从…

springboot3+springsecurity+redis 整合登录认证以及权限校验

1. 架构说明 整体架构如下(提供的对应的模块引入)&#xff0c;围绕着springsecurity中的三大核心展开&#xff1a; ​ 1、Authentication&#xff1a;存储了认证信息&#xff0c;代表当前登录用户 ​ 2、SeucirtyContext&#xff1a;上下文对象&#xff0c;用来获取Authenti…

扩散模型~

推荐&#xff1a;write_own_pipeline.ipynb - Colab (google.com) 基本管道 一直显示NVIDIA有问题&#xff0c;所以就把.to("cuda")去掉了&#xff0c;使用Colab运行的&#xff0c;代码如下&#xff1a; from diffusers import DDPMPipelineddpm DDPMPipeline.fr…

Java实战:验证改进的哥德巴赫猜想

改进的哥德巴赫猜想&#xff08;Improved Goldbach’s Conjecture&#xff09;声称每个大于5的奇数都可以表示为三个素数之和。这个猜想是对原始哥德巴赫猜想的扩展&#xff0c;针对奇数的情况。原始哥德巴赫猜想是指每个大于2的偶数都可以表示为两个素数之和。尽管改进的哥德巴…

Python轻量级Web框架Flask(13)—— Flask个人博客项目

0、前言: ★这部分内容是基于之前Flask学习内容的一个实战项目梳理内容,没有可以直接抄下来跑的代码,是学习了之前Flask基础知识之后,再来看这部分内容,就会对Flask项目开发流程有更清楚的认知,对一些开发细节可以进一步的学习。项目功能,通过Flask制作个人博客。项目架…

自动化运维工具-Ansible

一、Ansible概述 Ansible是一种基于python开发的自动化运维工具&#xff0c;它只需要在服务端安装ansible&#xff0c;无需在每个客户端安装客户端程序&#xff0c;通过ssh的方式来进行客户端服务器的管理&#xff0c;基于模块来实现批量数据配置、批量设备部署以及批量命令执…

飞天使-k8s知识点31-rancher的正确打开方式

文章目录 安装之前优化一下内核参数以及系统内核版本 rancher安装主要是使用以下命令nginx的配置为解决办法 安装之前优化一下内核参数以及系统内核版本 内核版本 4.17 cat > /etc/modules-load.d/iptables.conf <<EOF ip_tables iptable_filter EOF 然后重启服务器…

Python运维之多进程!!

本节的快速导航目录如下喔&#xff01;&#xff01;&#xff01; 一、创建进程的类Process 二、进程并发控制之Semaphore 三、进程同步之Lock 四、进程同步之Event 五、进程优先队列Queue 六、多进程之进程池Pool 七、多进程之数据交换Pipe 一、创建进程的类Process mu…

【 书生·浦语大模型实战营】学习笔记(六):Lagent AgentLego 智能体应用搭建

&#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料&#xff0c;配有全面而有深度的专栏内容&#xff0c;包括不限于 前沿论文解读、…

暗区突围国际服pc端海外版如何快速致富 暗区突围pc端怎么赚钱

暗区突围是一款由腾讯魔方工作室研发的高拟真硬核射击手游&#xff0c;以现代战争为游戏题材&#xff0c;采用了全新的u3d引擎打造&#xff0c;整体游戏画风逼真写实&#xff0c;搭配上优秀的射击玩法&#xff0c;辅以史诗级的背景配乐&#xff0c;致力于带给玩家无与伦比的枪战…