欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android Q Input (1) -- InputManagerService启动

程序员文章站 2022-07-09 19:38:25
Table of Contents启动流程简化流程图涉及类1.1 SystemServer startOtherServices2.1 InputManagerService初始化2.1.1com_android_server_input_InputManagerService nativeInit2.1.2 InputManager2.1.3EventHub2.2 启动InputManager service2.2.1inputManager.sta......

Table of Contents

启动流程简化

流程图

涉及类

1.1 SystemServer startOtherServices

2.1 InputManagerService初始化

2.1.1 com_android_server_input_InputManagerService  nativeInit

2.1.2 InputManager 

 2.1.3 EventHub

2.2   启动InputManager service

2.2.1 inputManager.start()

2.2.2 nativeStart

2.2.2 InputMansger.start

2.2.2 InputDispatcherThread InputReaderThread线程threadLoop


启动流程简化

  1. systemserver.startOtherServies
  2. 初始化InputmanagerService
  3. 初始化InputDispathcer InputClassifier InputReader EventHub InputDispatherThead InputReaderThread
  4. start InputManagerService
  5.  启动InputDispatherThead InputReaderThread 

流程图

Android Q Input (1) -- InputManagerService启动

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

相关标签: Input android