this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
…
}
主要是调用 nativeInit 方法传入一个消息队列,nativeInit 方法是为了去初始化一些 native 对象。最终是为了 new 一个 native 层的 InputManager 。 调用链如(想要了解详情的同学可以在相应的源码类里查看):
new InputManagerService() // InputManagerService.java
-> nativeInit(…, queue) // com_android_server_input_InputManagerService.cpp
-> new NativeInputManager(…, looper) // com_android_server_input_InputManagerService.cpp
-> new InputManager(eventHub, …) //InputManager.cpp
重点就在这个 InputManager 里
InputManager::InputManager(…) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
我们可以看到,在 InputManager 里准备好了 mReader、mDispatcher,以及相关的两个线程,那么接下来当然就是把线程跑起来,好去读事件和分发事件。
启动事件读取和分发线程的调用链如下:
SystemServer.startOtherServices()
-> inputManagerService.start()
-> nativeStart() // com_android_server_input_InputManagerService.cpp
-> InputManager.start() // InputManager.cpp
最后的这个 start 方法很简单,就是把两个线程跑起来
status_t InputManager::start() {
status_t result = mDispatcherThread->run(“InputDispatcher”, PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run(“InputReader”, PRIORITY_URGENT_DISPLAY);
}
至此,事件处理工作所需要的对象和线程都已经准备好了。前面那些代码看完记不住就算了,记住这句话:SystemServer 启动 IMS 时,会创建一个 native 的 InputManager 对象,这个 InputManager 会通过 mReader 不断读事件,再通过 mDispatcher 不断分发事件。
接下来我们看下,事件是怎么读取和分发的。
事件的读取
InputReaderThread 等待按键消息到来,该 Thread 在 threadLoop 中无尽的调用 InputReader 的 loopOnce 方法。
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
在 loopOnce 方法中会通过 EventHub 来获取事件,并放入 buffer 中:
void InputReader::loopOnce() {
// EventHub 从驱动读取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
…
if (count) {
// 获取的事件是 RawEvent,需要处理成 KeyEvent、MotionEvent 等各种类型等
processEventsLocked(mEventBuffer, count);
}
// 将队列中事件刷给监听器,监听器实际上就是 InputDispatcher 事件分发器。
mQueuedListener->flush();
}
InputDispatcher 收到事件后调用,如果是 KeyEvent 会调用 notifyKey,如果是 MotionEvent 则会调用 notifyMotion
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action,
flags, keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
// 通过 NatvieInputManager 在 Event 入队前做一些处理
mPolicy->interceptKeyBeforeQueueing(&event, /byref/ policyFlags);
…
KeyEntry* newEntry = new KeyEntry(args->eventTime, args->source,
args->action, flags, keyCode,…)
// 事件放入队尾
needWake = enqueueInboundEventLocked(newEntry);
}
以上,便是 InputReader 获取到设备事件通知 InputDispatcher 并存放到事件队列中的流程。
事件的分发
下面将介绍 InputDispatcher 如何从事件队列中读取事件并分发出去。
首先在 InputDispatcherThread 的 threadLoop 中无尽的调用 dispatchOnce 方法
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
该方法两个功能:
- 调用 dispatchOnceInnerLocked 分发事件;
- 调用 runCommandsLockedInterruptible 来处理 CommandQueue 中的命令,出队并处理,直到队列为空。
void InputDispatcher::dispatchOnce() {
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
…
}
在 dispatchOnceInnerLocked 中会处理多种类型的事件,这里关注按键类型的(其他如触摸,设备重置等事件流程稍有区别)。一通调用后到 PhoneWindowManager , 终于回到 java 了,
InputDispatcher::dispatchOnceInnerLocked
-> dispatchKeyLocked
-> doInterceptKeyBeforeDispatchingLockedInterruptible
-> NativeInputManager.interceptKeyBeforeDispatching
-> PhoneWindowManager.interceptKeyBeforeDispatching
…
// 以下 NativeInputManager.doInterceptKeyBeforeDispatchingLockedInterruptible 的部分代码
nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
&event, entry->policyFlags);
if (delay < 0) {
// Home 事件将被拦截
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
}
// 未被拦截的继续处理分发,本篇暂不分析
PhoneWindowManager
话不多说,继续看代码,离胜利不远了!源码的注释写得很清楚,我这边就不翻译了。真的不是因为懒,是想让你们提高点英语阅读水平 。(-> <-)
public long interceptKeyBeforeDispatching(KeyEvent event, …) {
// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
// timeout.
if (keyCode == KeyEvent.KEYCODE_HOME) {
// If we have released the home key, and didn’t do anything else
// while it was pressed, then it is time to go home!
if (!down) {
cancelPreloadRecentApps();
mHomePressed = false;
…
// Delay handling home if a double-tap is possible.
if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
mHomeDoubleTapPending = true;
mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
ViewConfiguration.getDoubleTapTimeout());
return -1;
}
handleShortPressOnHome(); //短按
//-1 调用处的事件结果就会赋值 INTERCEPT_KEY_RESULT_SKIP
return -1;
}
…
// Remember that home is pressed and handle special actions.
if (repeatCount == 0) {
mHomePressed = true;
if (mHomeDoubleTapPending) {
handleDoubleTapOnHome();//双击
} else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
preloadRecentApps();//最近 app
}
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
if (!keyguardOn) {
handleLongPressOnHome(event.getDeviceId());//长按
}
}
return -1;
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。





既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。
选定你想去的几家公司后,先去一些小的公司练练,学习下面试技巧,总结下,也算是熟悉下面试氛围,平时和同事或者产品PK时可以讲得头头是道,思路清晰至极,到了现场真的不一样,怎么描述你所做的一切,这绝对是个学术性问题!
面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。
金九银十面试季,跳槽季,整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-RQ037xRG-1711952628486)]
本文详细阐述了Android系统启动时如何创建NativeInputManager对象,涉及InputReader、InputDispatcher的初始化、线程创建以及事件的读取、分发过程。重点在于InputManager如何管理按键和触摸事件,以及其在系统服务中的关键作用。
797

被折叠的 条评论
为什么被折叠?



