Android Q Input (1) -- InputManagerService启动
Table of Contents
1.1 SystemServer startOtherServices
2.1.1 com_android_server_input_InputManagerService nativeInit
2.2.2 InputDispatcherThread InputReaderThread线程threadLoop
启动流程简化
- systemserver.startOtherServies
- 初始化InputmanagerService
- 初始化InputDispathcer InputClassifier InputReader EventHub InputDispatherThead InputReaderThread
- start InputManagerService
- 启动InputDispatherThead InputReaderThread
流程图
InputManagerService在后文中用IMS代替。IMS是在系统加载后,SystemServer中进行创建、初始化和启动的。在SystemServer中的startOtherService方法中创建了IMS对象,InputManagerService的构造方法中需要传入当前系统的context。在IMS的构造方法中首先通过DisplayThread创建了一个InputManagerHandler对象,用于控制输入设备改变、切换键盘布局、重新加载键盘、重新加载设备以及更新键盘布局的操作。另外调用了native方法nativeInit即就是jni层的com_android_server_input_InputManagerService文件中的nativeInit方法,该方法有三个参数、第一个是IMS服务本身,第二个是系统的Context,第三个是消息队列,该队列是创建的InputManagerHandler中的队列。用于缓冲输入事件。在nativeInit方法中创建了NativeInputManager对象,并将该对象使用集合存储,用于后期事件发送到上层Java层。
在NativeInputManager的构造方法中放入了通过InputManagerHandler创建的消息队列的Looper对象,用于操作消息队列中的消息,保证java层和nativie层的不断交互,并且创建了InputManager对象,将NativeInputManager对象通过形参进行传递,NativeInputManager实现了InputReaderPolicyInterface、InputDispatcherPolicyInterface、PointerControllerPolicyInterface,而InputManager中恰好就需要的是InputReaderPolicyInterface和InputDispatcherPolicyInterface对象的引用,通过这两个对象分别创建了InputReader(利用工厂模式进行创建,Android Q上新增InputClassifier对象,其中InputReader中将InputDispatcher对象和InputClassifier作为传参保存到InputReader对象中,另外创建InputRedaer对象时创建了一个非常重要的对象EventHub,该对象是负责监听和读取驱动写入到/dev/input目录下的事件信息)、 InputDispatcher对象。初始化创建了两个线程InputReaderThread和InputDispatcherThread,InputReaderThread是负责事件读取的线程,InputDispatcherThread是负责事件派发的线程。
在EventHub构造方法中初始化了一些变量的值和注册了epoll机制、Inotify机制。比如打开设备变量mOpeningDevices默认值是空,关闭设备mClosingDevices链表变量默认值是空,是否扫描完成变量mNeedToSendFinishedDeviceScan默认值是false,是否需要重新打开变量mNeedToReopenDevices的值默认是false,是否需要重新扫描设备mNeedToScanDevices变量是true,事件数量变量mPendingEventCount默认是0,下一个事件下标变量mPendingEventIndex是0。其次利用linux中的inotify机制和epoll机制分别通过inotify_init、 epoll_create1方法创建了mEpollFd、mINotifyFd变量,然后将mINotifyFd通过inotify_add_watch方法注册了/dev/input目录的文件删除和创建,利用epoll_ctl对inotify进行控制。
在这里要说明的是在Android P版本上还没有采用工厂模式创建InputReader和InputDispatcher对象,而且在Android Q版本上在EventHub的构造方法中多注册了一个目录/dev,从代码中看是该目录下写入的时间是支持V4L机制的时间,V4L是一种Linux机制
到这里IMS对象就创建完成了。
回到SystemServer中,将刚刚创建的IMS对象使用传参的形式创建了WindowManagerService,目的是在WMS中保存IMS对象,当存在窗口发生变化的时候,及时将窗口信息传递给IMS中。同理将创建好的WMS对象中实现了InputManagerService.WindowManagerCallbacks接口的WindowManagerCallbacks对象设置给IMS,这样就能保证IMS能够直接将其中的事件回调给WMS中。最后一步,IMS调用start方法调用nativie层的方法,最后启动创建的InputReaderThread、InputDispatcherThread两个线程。
参考https://blog.csdn.net/chen364567628/article/details/102811219 https://blog.csdn.net/chen364567628/article/details/103605548
涉及类
frameworks/native/services/inputflinger/
- InputDispatcher.cpp
- InputReader.cpp
- InputManager.cpp
- EventHub.cpp
- InputListener.cpp
frameworks/native/libs/input/
- InputTransport.cpp
- Input.cpp
- InputDevice.cpp
- Keyboard.cpp
- KeyCharacterMap.cpp
- IInputFlinger.cpp
frameworks/base/services/core/
- java/com/android/server/SystemServer.java
- java/com/android/server/input/InputManagerService.java
- jni/com_android_server_input_InputManagerService.cpp
1.1 SystemServer startOtherServices
创建InputManagerServic
frameworks/base/services/java/com/android/server/SystemServer.java
@SystemServer.java
private void startOtherServices() {
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context); //初始化InputManagerService
***
}
2.1 InputManagerService初始化
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
318 public InputManagerService(Context context) {
319 this.mContext = context;
320 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
321
322 mUseDevInputEventForAudioJack =
323 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
324 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
325 + mUseDevInputEventForAudioJack);
326 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
327
328 String doubleTouchGestureEnablePath = context.getResources().getString(
329 R.string.config_doubleTouchGestureEnableFile);
330 mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
331 new File(doubleTouchGestureEnablePath);
332
333 LocalServices.addService(InputManagerInternal.class, new LocalService());
334 }
195 private static native long nativeInit(InputManagerService service,
196 Context context, MessageQueue messageQueue);
2.1.1 com_android_server_input_InputManagerService nativeInit
通过JNI实现java和c层的交互
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
1322static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
1323 jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
1324 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);///java传入的messageQueue, mHandler.getLooper().getQueue()
1325 if (messageQueue == nullptr) {
1326 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
1327 return 0;
1328 }
1329
1330 NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
1331 messageQueue->getLooper());
1332 im->incStrong(0);
1333 return reinterpret_cast<jlong>(im);
1334}
334NativeInputManager::NativeInputManager(jobject contextObj,
335 jobject serviceObj, const sp<Looper>& looper) :
336 mLooper(looper), mInteractive(true) {
337 JNIEnv* env = jniEnv();
338
339 mServiceObj = env->NewGlobalRef(serviceObj);
340
350 mInteractive = true;
351
352 mInputManager = new InputManager(this, this);
353 defaultServiceManager()->addService(String16("inputflinger"),
354 mInputManager, false);
355}
2.1.2 InputManager
构造InputManager,同时创建了InputDispather 和InputReader的引用,并实现对应Thread的创建。用于获取kernel相应事件的获取以及监听
frameworks/native/services/inputflinger/InputManager.cpp
33InputManager::InputManager(
34 const sp<InputReaderPolicyInterface>& readerPolicy,
35 const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
36 mDispatcher = new InputDispatcher(dispatcherPolicy);
37 mClassifier = new InputClassifier(mDispatcher);
38 mReader = createInputReader(readerPolicy, mClassifier);
39 initialize();
40}
frameworks/native/services/inputflinger/InputReaderFactory.cpp
22sp<InputReaderInterface> createInputReader(
23 const sp<InputReaderPolicyInterface>& policy,
24 const sp<InputListenerInterface>& listener) {
25 return new InputReader(new EventHub(), policy, listener);
26}
46void InputManager::initialize() {
47 mReaderThread = new InputReaderThread(mReader);
48 mDispatcherThread = new InputDispatcherThread(mDispatcher);
49}
2.1.3 EventHub
在EventHub的构造函数中,它通过INotify与Epoll机制建立起对设备点增删事件及可读状态的监听。INotify是Linux内核所提供的一种文件系统变化通知机制。它可以为应用程序监控文件系统的变化,如文件的新建、删除、读写等等。它有两个基本对象,inotify对象对应一个队列,应用程序可以向inotify对象添加多个监听,当被监听的事件发生时,可以通过read()函数从inotify对象中将事件信息读取出来;而watch对象则用来描述文件系统的变化事件的监听,它是一个二元组,包括监听目标和事件掩码两个元素,监听目标是文件系统的一个路径,可以是文件也可以是文件夹。Epoll可以使用一次等待监听多个描述符的可读/可写状态。
@frameworks/native/services/inputflinger/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);
mEpollFd = epoll_create(EPOLL_SIZE_HINT); //创建epoll
mINotifyFd = inotify_init(); //int mINotifyFd;
//man inotify_add_watch: add a watch to an initialized inotify instance监听/dev/input目录,create和删除事件,然后通知mINotifyFd
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); //char *DEVICE_PATH = "/dev/input";
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
result = pipe(wakeFds);
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);
// EPOLLWAKEUP was introduced in kernel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
2.2 启动InputManager service
调用start启动inputdispatcher和inputReader线程
frameworks/base/services/java/com/android/server/SystemServer.java
@SystemServer.java
private void startOtherServices() {
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context); //初始化InputManagerService
****
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.INPUT_SERVICE, inputManager); //可以通过IInputManager来binder调用InputManagerService方法
traceBeginAndSlog("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start(); //start inputmanager
}
2.2.1 inputManager.start()
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
344 public void start() {
345 Slog.i(TAG, "Starting input manager");
346 nativeStart(mPtr);
347
348 // Add ourself to the Watchdog monitors.
349 Watchdog.getInstance().addMonitor(this);
350
2.2.2 nativeStart
/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
1336static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
1337 NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1338
1339 status_t result = im->getInputManager()->start();
1340 if (result) {
1341 jniThrowRuntimeException(env, "Input manager could not be started.");
1342 }
1343}
2.2.2 InputMansger.start
启动mReaderThread和DispatcherThread
frameworks/native/services/inputflinger/InputManager.cpp
51status_t InputManager::start() {
52 status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
53 if (result) {
54 ALOGE("Could not start InputDispatcher thread due to error %d.", result);
55 return result;
56 }
57
58 result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
59 if (result) {
60 ALOGE("Could not start InputReader thread due to error %d.", result);
61
62 mDispatcherThread->requestExit();
63 return result;
64 }
65
66 return OK;
67}
2.2.2 InputDispatcherThread InputReaderThread线程threadLoop
//return true就会一直调用threadLoop方法,这里表示线程会一直调用dispatchOnce和loopOnce
frameworks/native/services/inputflinger/InputReaderBase.cpp
38InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
39 Thread(/*canCallJava*/ true), mReader(reader) {
40}
41
42InputReaderThread::~InputReaderThread() {
43}
44
45bool InputReaderThread::threadLoop() {
46 mReader->loopOnce();
47 return true;
48}
frameworks/native/services/inputflinger/InputDispatcher.cpp
5231InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
5232 Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
5233}
5234
5235InputDispatcherThread::~InputDispatcherThread() {
5236}
5237
5238bool InputDispatcherThread::threadLoop() {
5239 mDispatcher->dispatchOnce();
5240 return true;
5241}
本文地址:https://blog.csdn.net/u012805129/article/details/107594566
下一篇: 饿了么蓝骑士皮肤“被盗”,背后的商业伦理
推荐阅读
-
谷歌开发者日历泄露:Android Q Beta1有望在3月13日推送
-
android Q activity启动流程
-
Android Q Input (1) -- InputManagerService启动
-
Android Q Beta 5来了:谷歌禁止在第三方启动器上使用手势导航
-
Android开发艺术探索——1.Activity的生命周期和启动模式
-
谷歌开发者日历泄露:Android Q Beta1有望在3月13日推送
-
Android Q Go Apk热启动白屏/显示LOGO
-
android Q activity启动流程
-
Android Q Beta 5来了:谷歌禁止在第三方启动器上使用手势导航
-
Android Q Input (1) -- InputManagerService启动