android power key 按下到 通知PowerManager亮灭屏的流程

按键和输入有关,就涉及到InputManagerService。

有三个文件:inputManager.java,InputManagerService.java,inputManager.cpp.

InputManager.java在framwork/base/core/java/android/hardware/input/

InputManagerService.java在framwork/base/core/java/com/android/server/input

inputManager.cpp在framworks\native\services\inputflinger\

InputManager.java是客户端,通过binder向InputManagerService.java请求服务。InputManagerService.java是一个binder服务。InputManagerService.java封装cpp层的inputManager.cpp,并向其提供会回调。

SystemServer.java 在startOtherSerivce中,初始化InputManagerService,并调用器start函数。InputManagerService的构造函数中调用nativeInit().

android power key 按下到 通知PowerManager亮灭屏的流程_第1张图片

android power key 按下到 通知PowerManager亮灭屏的流程_第2张图片

nativeInit是什么函数呢?它有对应的native c++函数。

查找规律如下:

InputManagerService的完整包名如下:

com.android.service.input.InputManagerService.java。

将所有 .  修改为 _ ,java改为cpp。  即com_android_service_input_InputManagerService.cpp。 此文件在framwork/base/service/core/jni目录中。

InputManagerService.java的nativeInit(),对应的就是com_android_service_input_InputManagerService.cpp中的nativeInit().在此函数中初始化了NativeInputManager。NativeInputManager构造函数中初始化了InputManager.

android power key 按下到 通知PowerManager亮灭屏的流程_第3张图片

android power key 按下到 通知PowerManager亮灭屏的流程_第4张图片

在NativeInputManager的构造过程中,会创建一个EventHub实例,并且把这个EventHub作为参数来创建InputManager对象。EventHub类是真正执行监控键盘事件操作的地方。android是基于linux kernel的,linux的事件获取需要读/dev/input下的设备文件节点。就是EventHub读取/dev/input节点。

从EventHub.cpp和InputManager.cpp开始,目录变成framworks\native\services\inputflinger\:

android power key 按下到 通知PowerManager亮灭屏的流程_第5张图片

其中有两个InputDispatcher,InputReader成员。其参数 dispatcherPolicy和readerPolicy其实都是NativeInputManager。

InputDispatcher类是负责把输入消息分发给当前激活的Activity窗口的,而InputReader类则是通过EventHub类来实现读取输入事件的。键盘的输入消息也是InputDispatcher负责处理。

Eventhub类:

android power key 按下到 通知PowerManager亮灭屏的流程_第6张图片

Android所有的input设备都会在/dev/input目录下生成对应的设备节点,一旦有任何输入事件产生,便会将事件写到这些节点下,同时对于外部输入设备(鼠标键盘等)的插拔还会引起这些节点的创建和删除。通Inotify和epoll实现对输入设备和输入事件的监控。上面代码中Inotify检测文件系统IN_DELETE,IN_CREATE,即创建和删除,在这里就监测是输入设备打开或者删除的事件。epoll监测多个文件(有无数据供读出、有无空间供写入)。两个如何关联?通过Inotify,输入设备插拔,将写入mInotifyFd文件。通过epoll,mEpollFd监控mInotifyFd的EPOLLIN,即读事件。所以只需要用epoll_wait查询mEpollFd,只要输入设备插拔都会退出epollWait阻塞,进行具体的工作。

mEpollFd还监控了读管道mWakeReadPipeFD。对应的写管道eventHub.wake()函数写入mWakeReadPipeFD。eventHub在nativeInputManger中作为参数传给inputManager,最终传给inputReader。inputRead会调用eventHub.wake(),触发eventHub的getevents()中的epoll_wait退出阻塞。

inotify详见:inotify_add_watch(2) - Linux manual page  等。

epoll 详见epoll_ctl(2) - Linux manual page 等。

mInotifyFd和mWakeReadPipeFD有数据都会通知mEpollFd。如何区分哪个文件有数据呢?eventHub中通过给epoll_ctl()的第三个参数eventItem的data参数指定不同的值来区分。

目前只是检测了输入设备的插拔,如何获取设备的各种输入呢?

围绕mEpollFd搜索代码,原来在registerDeviceForEpollLocked。顺便说下,最近看代码framwork层的WMS,PMS以及这个input模块,发现有很多函数都以Locked,原来以为是有逻辑上的含义,后面领悟到,原来是提示调用的人需要加锁调用。

android power key 按下到 通知PowerManager亮灭屏的流程_第7张图片

registerDeviceForEpollLocked中添加mEpollFd对输入设备的读监听。当设备插入,或使能设备,会触发这个函数。

以设备插入为例,讲如何触发registerDeviceForEpollLocked()的。就涉及到EventHub中一个重要的函数getEvents().后面会讲getEvents()是如何进入的。getEvents()通过epoll_wait监听和处理设备插拔(mInotifyFd),inputreader唤醒(mWakeReadPipeFD),输入设备的输入事件(device->fd)。

一开始是不能监听设备的输入事件的,要先检测到设备的插入。

先看getEvents的最上层逻辑(删除了其他细节),首先是一个无线for循环。通过epoll_wait获得通知,通知放入mPendingEventItems中。

android power key 按下到 通知PowerManager亮灭屏的流程_第8张图片

在最上层的for循环里,有一个while循环处理mPendingEventItems。当有设备插入,将mpendingINotify设置为true。

android power key 按下到 通知PowerManager亮灭屏的流程_第9张图片

将所有的pendingEvent处理完后,通过readNotifyLocked() 从mINotifyFd中读取数据,循环处理inotify_event,将dev/input/和event->name拼合为devname(准确说是设备文件名,而不是设备名),作为入参调用openDeviceLocked().

android power key 按下到 通知PowerManager亮灭屏的流程_第10张图片

android power key 按下到 通知PowerManager亮灭屏的流程_第11张图片

openDeviceLocked通过ioctl(devicepath:dev/input/eventX为入参)获取输入设备的各种信息,对devcie变量初始化和赋值。

然后通过registerDeviceForEpolledLocked()监控dev/input/eventX状态,将device添加到mDevices向量里。

android power key 按下到 通知PowerManager亮灭屏的流程_第12张图片

android power key 按下到 通知PowerManager亮灭屏的流程_第13张图片

监听设备输入文件后,再回来看getEvents函数。函数从设备输入文件读取数据,一个一个读出input_event,转换成RawEvent赋给入参buffer。

android power key 按下到 通知PowerManager亮灭屏的流程_第14张图片

从上面可以看出eventHub维护设备列表,读取输入事件。但是eventHub并不处理输入事件,而是通过getEvents返回给入参buffer。

接下来就要看谁调用的getEvents?是InputReader的loopOnce()调用。接着InputReader经过如下路径。

loopOnce()-> processEventLocked()-> processEventsForDeviceLocked()

然后进入InputDevice类的process()处理。

InputDevice如何被添加到mDevices向量中?当eventtype为Device_ADDED时loopOnce()-> processEventLocked()->addDeviceLocked()中的mDevices.add().

InputDevice类的process()函数调用inputMapper类的process函数处理。

inputMapper又是如何来的?loopOnce()-> processEventLocked()->addDeviceLocked()->createDeviceLocked()调用device->addMapper().

当设备是按键时,createDeviceLocked()调用device->addMapper()时会添加一个keyboardInputMapper。

那么现在进入keyboardMapper的process函数。keyboardMapper,InputDevice都在InputReader.cpp文件定义。

android power key 按下到 通知PowerManager亮灭屏的流程_第15张图片

最终通过process  -> processKey() ->  getListener()->notifyKey(). 

android power key 按下到 通知PowerManager亮灭屏的流程_第16张图片

此Listener是什么呢?回忆一下:

 android power key 按下到 通知PowerManager亮灭屏的流程_第17张图片

android power key 按下到 通知PowerManager亮灭屏的流程_第18张图片

所以这个Listener就是InputDispatcher。

终于到了InputDispatcher分发阶段了!

android power key 按下到 通知PowerManager亮灭屏的流程_第19张图片

对于power按键,最核心的就是mpolicy->interceptKeyBeforQueueing.  mPolicy是什么?请返回看本篇最开始的NativeInputManager()->InputManager()->InputDispatcher() 这依次的初始化流程,NativeInputManager将自己传递给了InputDispatcher的mPolicy参数。

NativeInputManager其实是C++和java层的桥接。从C++层调用NativeInputManager的函数,其实目的就是为了跳到java层InputManagerManager.java中的函数。它通过jni的CallIntMethod调用NativeInputManager的同名函数。具体参见我的另一篇博客通过android inputManagerService 看JNI 函数注册 - CSDN博客

android power key 按下到 通知PowerManager亮灭屏的流程_第20张图片

在inputDispatcher中有三个队列如下,其输入事件处理流程还是比较复杂的。不过power key 触发亮灭屏的操作在interceptKeyBeforQueueing中就处理完了。所以围绕这三个队列的流程就后面有时间再学习。快点结束这篇吧,还有一篇关于PROXIMITY_SCREEN_OFF_WAKE_LOCK的博客,因为半路跳到inputManager而停下来了。这两篇结束后,想学学ims和sip,python也可以啊!

 

回到interceptKeyBeforQueueing:

这个mWindowsManagerCallbacks是什么呢?又要从开天辟地不久之后的startOtherServices说起.inputManager初始化后,通过setWindowManagerCallbacks设置mWindowsManagerCallbacks。入参是InputMonitor.

android power key 按下到 通知PowerManager亮灭屏的流程_第21张图片

进入InputMonitor.interceptKeyBoforeQueueing()函数。调用的是mService.mPolicy.interceptKeyBeforeQueueing:

android power key 按下到 通知PowerManager亮灭屏的流程_第22张图片

看下面几张图,最终是进入PhoneWindowManager().interceptKeyBeforeQueueing():

 

android power key 按下到 通知PowerManager亮灭屏的流程_第23张图片

下面看PhoneWindowManager().interceptKeyBeforeQueueing(),根据Power键时按下还是松开,分别调用interceptPowerKeyDown,interceptPowerKeyUP

android power key 按下到 通知PowerManager亮灭屏的流程_第24张图片

result &=~ACTION_PASS_TO_USER.  默认不传到user。

当时按下power键时先进行初步处理,判断是否截屏,来电静音等等。

android power key 按下到 通知PowerManager亮灭屏的流程_第25张图片

如果前面都没有处理,即若没有消化掉power键,则继续处理,主要工作是在亮屏时按POWER键发送延时事件,触发长按处理。如果超时前抬起power键,这些事件会被撤销。

android power key 按下到 通知PowerManager亮灭屏的流程_第26张图片

超时后,长按事件将得到处理,分别进入powerLongPress(),和powerVeryLongPress():

 android power key 按下到 通知PowerManager亮灭屏的流程_第27张图片

这两个短按和长按关机键的处理函数,默认流程会提示关机。并且将handler设置为true。 

android power key 按下到 通知PowerManager亮灭屏的流程_第28张图片

接下来看当power键抬起,maxcount默认为1.所以不会走maxcount判断语句。默认走powerPress(),处理一次power按下。

android power key 按下到 通知PowerManager亮灭屏的流程_第29张图片

powerPress中,不支持多次按键,count一定是1.默认走SHORT_PRESS_POWER_GO_TO_SLEEP.

即走goToSlee().

android power key 按下到 通知PowerManager亮灭屏的流程_第30张图片

调用PowerManager goToSleep 休眠。具体怎么休眠,灭屏,就要看PowerManager了。

1.亮屏 down 

          发delay事件

           长按 : 弹出关闭重启对话框   delay事件到期触发

           短按 :不做处理,会在up时清除delay事件。

   亮屏 up 

        长按 :不做处理(因为power long press和powerVeryLongPress已经处理了power键,并将handle设置为true了。)

        短按 调用goToSleep休眠系统

2. 灭屏 down

            调用wakeup 唤醒系统:wakeUPFromPowerKey,设置handle为true

     灭屏 up

            不做处理:因为灭屏down时设置handle为true了。

 

你可能感兴趣的:(android移动网络通讯)