android inputmanager中事件的传递流程

2024-03-30 14:48

本文主要是介绍android inputmanager中事件的传递流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

涉及文件路径:

frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
frameworks\base\core\java\android\view\InputChannel.java
frameworks\base\core\jni\android_view_InputChannel.cpp
frameworks\base\core\java\android\hardware\input\InputManager.java
frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
frameworks\native\services\inputflinger\InputManager.h
frameworks\native\services\inputflinger\InputManager.cpp
frameworks\native\services\inputflinger\InputReader.h
frameworks\native\services\inputflinger\InputReader.cpp
frameworks\native\services\inputflinger\InputListener.cpp
frameworks\native\services\inputflinger\InputDispatcher.h
system\core\libutils\include\utils\Looper.h
system\core\libutils\Looper.cpp
frameworks\native\services\inputflinger\InputDispatcher.cpp
frameworks\native\libs\input\InputTransport.cpp
frameworks\native\include\input\InputTransport.h
frameworks\base\core\java\android\view\ViewRootImpl.java
frameworks\native\services\inputflinger\EventHub.h
frameworks\native\include\input\InputDevice.h
frameworks\native\services\inputflinger\EventHub.cpp
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
frameworks\base\services\core\java\com\android\server\wm\Session.java
frameworks\base\core\java\android\view\InputEventReceiver.java
frameworks\base\core\jni\android_view_InputEventReceiver.cpp

概述:

android系统输入管理系统inputmanager主要功能就是监听android输入设备,及时将屏幕点击、按键事件、滚动球、鼠标等输入设备产生的输入事件通过转换成java层可使用的事件,比如motionevent,keyevent等将其从底层设备获取出来传递至android系统或者app,然后由系统或者app来做出相应的处理,比如在一个activity中点击了一个控件,屏幕的点击事件会通过inputmanager系统转化成一次触摸事件,然后将其传递至activity,然后activity继续将其传递至该控件,由该控件来做相应处理。

inputmanager系统主要类关系图如下:
在这里插入图片描述
主要从五个流程上来分析:
1、inputmanager系统的初始化
2、InputReader读取事件的流程
3、InputDispatcher事件分发的流程
4、java层事件监听器的注册流程
5、事件如何从C层传递至Java层

inputmanager系统的初始化

inputmanagerservice服务在systemserver中启动:

            traceBeginAndSlog("StartInputManagerService");inputManager = new InputManagerService(context);traceEnd();............traceBeginAndSlog("StartInputManager");inputManager.setWindowManagerCallbacks(wm.getInputMonitor());inputManager.start();traceEnd();

InputManagerService服务启动后的流程如下图:
在这里插入图片描述
inputmanagerservice初始化方法如下:

    public InputManagerService(Context context) {this.mContext = context;this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());mUseDevInputEventForAudioJack =context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);//调用native方法的初始化,这个是重点mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());......}......public void start() {//开始扫描设备发送事件nativeStart(mPtr);......}

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;}//初始化NativeInputManagerNativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper());im->incStrong(0);return reinterpret_cast<jlong>(im);
}static 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.");}
}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;mLocked.pointerCapture = false;}mInteractive = true;//初始化EventHub和InputManagersp<EventHub> eventHub = new EventHub();mInputManager = new InputManager(eventHub, this, this);
}

EventHub.cpp

EventHub::EventHub(void) :mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),mOpeningDevices(0), mClosingDevices(0),mNeedToSendFinishedDeviceScan(false),mNeedToReopenDevices(false), mNeedToScanDevices(true),mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);//新建epoll对象mEpollFd = epoll_create(EPOLL_SIZE_HINT);//新建notify对象mINotifyFd = inotify_init();//将存储设备点的路径dev/input作为监听对象添加到inotify对象中int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);//将mINotifyFd作为epoll的一个监控对象struct epoll_event eventItem;memset(&eventItem, 0, sizeof(eventItem));eventItem.events = EPOLLIN;eventItem.data.u32 = EPOLL_ID_INOTIFY;//将对mINotifyFd的监听注册到epoll对象中result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);int wakeFds[2];result = pipe(wakeFds);LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);mWakeReadPipeFd = wakeFds[0];mWakeWritePipeFd = wakeFds[1];result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);eventItem.data.u32 = EPOLL_ID_WAKE;result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);int major, minor;getLinuxRelease(&major, &minor);mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}

在EventHub的构造函数中,它通过INotify与Epoll机制建立起对设备点增删事件及可读状态的监听。INotify是Linux内核所提供的一种文件系统变化通知机制。它可以为应用程序监控文件系统的变化,如文件的新建、删除、读写等等。它有两个基本对象,inotify对象对应一个队列,应用程序可以向inotify对象添加多个监听,当被监听的事件发生时,可以通过read()函数从inotify对象中将事件信息读取出来;而watch对象则用来描述文件系统的变化事件的监听,它是一个二元组,包括监听目标和事件掩码两个元素,监听目标是文件系统的一个路径,可以是文件也可以是文件夹。Epoll可以使用一次等待监听多个描述符的可读/可写状态。

InputManager.cpp

InputManager::InputManager(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {mDispatcher = new InputDispatcher(dispatcherPolicy);//reader的初始化中将mDispatcher作为参数传入mReader = new InputReader(eventHub, readerPolicy, mDispatcher);initialize();
}

从类关系图可知,InputDispatcher继承自InputListenerInterface

void InputManager::initialize() {//初始化两个线程mReaderThread = new InputReaderThread(mReader);mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
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;
}
InputReader读取事件的流程

事件读取流程如下图:

这篇关于android inputmanager中事件的传递流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/861775

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目