本篇为鸡生蛋系列第二篇文章
主要讲一下inputmanager相关的,即驱动把数据上报到用户空间后,用户空间到应用这么个流程,
在上一遍讲内核的input子系统时候,我们采取的反向分析,即由驱动出发,最后到input core,input子系统架构这么个由点到面的分析方法,
那分析inputmanager是否可采用这种方法如何呢?实际上,对于Android上层(Native framework/framework, c++/java)的分析,我一般
采用的是由上而下的分析,即从其初始化(main,构造,onFirstRef())开始, 通常在其初始化时候,会重一些很重要的上下层的连接,如果由下往上看,会麻烦点,
然后再结合实例,看看他的数据流向是如何的,或者一些重要的API, 例如对于Audio来说,可以结合播放音乐流程来分析整个系统架构。
简单说来,input到应用的流程为
EventHub监控并读取/dev/input下数据 --> 给InputReader 加工处理 --> 到InputDispacher --> 找到focused窗口并通过input channel发出去
相关代码目录:
Android 9.0 http://androidxref.com/9.0.0_r3/
frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
frameworks/native/services/inputflinger/
1.1 初始化frameworks/base/services/java/com/android/server/SystemServer.java
startOtherServices() {
inputManager = new InputManagerService(context);
....
wm = WindowManagerService.main(context, inputManager,
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
....
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
......
}
IMS(InputManagerService)的初始化,是从SystemServer开始的,通过搜索代码(如上),我们可以看到构造了一个实例,
并做为参数传给了WMS, 由此我们也猜想,会和WMS有紧密的关系,然后
IMS设置了setWindowManagerCallbacks()并通过start()函数启动了,
SystemServer里有关IMS的就这么几个地方,我们再看下构造和start()具体的流程,与WMS的关联不分析。frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Pointer to native input manager service object.
private final long mPtr;
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
// config_useDevInputEventForAudioJack配置为true, 耳机事件可通过input上报
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
......
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
......
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
....
}
InputManagerService构造和start()主要也是调到JNI的 nativeInit() nativeStart().frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
....
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast(im);
}
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
......
status_t result = im->getInputManager()->start();
......
}
nativeInit()又构造了一个 NativeInputManager(),该类可认为是上层JAVA和下层EventHub InputManager的桥梁,
nativeStart()通过 NativeInputManager最终调到 InputManager 的 start()方法NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp& looper) :
mLooper(looper), mInteractive(true) {
......
sp eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
NativeInputManager()的构造又new了 EventHub 和 InputManager , 其中
eventHub做为参数传给了 InputManager()frameworks/native/services/inputflinger/EventHub.cpp
EventHub::EventHub(void) :
......{
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mEpollFd = epoll_create(EPOLL_SIZE_HINT); // epoll机制
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
mINotifyFd = inotify_init(); // inotify机制
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); // 利用inotify监控 DEVICE_PATH(/dev/input)创建和删除
......
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); // 将inotify的fd添加到Epoll监控中
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
int wakeFds[2];
result = pipe(wakeFds); //读写pipe, InputReader有事件时唤醒
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
......
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
......
}
EventHub相当于一个集线器,把底层的USB, TOUCH,鼠标等事件统一收集上来,再给上层。
其构造函数当中利用inotify机制监控"/dev/input" 目录下设备的创建和删除,这样当有设备变更时就可以收到通知了,
构造函数也创建了所需要的mEpollFd,这个作为IO多路复用的机制,不清楚的可以查下如何使用,
构造里将mINotifyFd添加到了epoll里,在后续input设备创建的时候,也会把input设备的fd添加进去,这样当有数据或者设备变化时,
EventHub就可获取这些事件,进一步处理。
构造还创建了两个pipe,作为wakeup的读端和写端,当InputReader.cpp有事件(配置变更,monitor, 超时请求等)唤醒EventHub处理。InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher); // eventHub又传给了 InputReader,最终他们俩是紧密联系在一起的
initialize(); // eventHub又传给了
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
InputManager(),创建了InputDispatcher和InputReader实例并与对应的InputDispatcherThread InputReaderThread 线程关联
具体的我们不往下跟了,有兴趣的可以再看看,
至此,初始化流程告一段落。
InputManagerService.java的 start方法,最终到InputManager::start(),status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
......
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
......
}
start() 方法目的就是让这两个线程跑起来,这样就可以不断的获取,处理消息了。
1.2 小结startOtherServices()/SystemServer.java
+ new InputManagerService(context) --> nativeInit(...) --> new NativeInputManager(...)
+ + new EventHub() --> inotify监控/dev/input + epoll + wake pipe
+ + new InputManager(eventHub,...)
+ + new InputDispatcher()
+ + new InputReader(eventHub,...)
+ + initialize()
+ + new InputReaderThread(mReader)
+ + new InputDispatcherThread(mDispatcher)
+
+ ^
+ +
+ inputManager.start() --> nativeStart(mPtr) --> im->getInputManager()->start() --> mDispatcherThread->run() mReaderThread->run()
2. 读取数据bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
上一小节讲到IMS通过start()函数,最终让InputReaderThread InputDispatcherThread两个线程跑起来了,
线程跑起来后,他们因为返回值为true, 所以他们会不断的loop, 即不断的读取,分发,读取,分发……
看上面几行代码,觉得整个过程很简单清晰,然而当我们继续跟下去看细节的时候,你能 哇~~哇~~哇~~
这一节我们看看 mReader->loopOnce(), 下一节继续看Dispatcher过程void InputReader::loopOnce() {
......
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
......
if (count) {
processEventsLocked(mEventBuffer, co