美文网首页
framework 学习笔记20. input输入事件番外3(n

framework 学习笔记20. input输入事件番外3(n

作者: 加个标志位 | 来源:发表于2021-02-22 20:45 被阅读0次

    1. SystemServer 中启动 IMS

    上一章节中,介绍了输入事件的整体架构设计和 java 层 InputManagerService 的启动,接下来将从源码中详细跟踪 IMS 的启动;首先从 SystemServer.java 中 startOtherServices() 方法开始:

      private void startOtherServices() {
          // 创建 IMS
          inputManager = new InputManagerService(context); // 见1.2
          // 创建 WMS
          wm = WindowManagerService.main(context, inputManager,
                  mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                  !mFirstBoot, mOnlyCore);
          ServiceManager.addService(Context.WINDOW_SERVICE, wm);
          ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
    
          mActivityManagerService.setWindowManager(wm);
          // wm.getInputMonitor() 获取到的是InputMonitor 
          inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); // IMS 和 WMS 相互关联 见 1.1
          inputManager.start();  // 见1.2
      }
    

    1.1 InputMonitor:通信桥梁的建立 (InputMonitor 是 IMS 和 WMS 之间的纽带,在是在 WMS 中初始化的);

      final InputMonitor mInputMonitor = new InputMonitor(this);
      public InputMonitor getInputMonitor() {
          return mInputMonitor;
      }
    

    关于 InputMonitor 是 IMS 和 WMS 之间的纽带,其具体的交互是通过 InputDispatcher 完成的,在源码中具体表现为两个方面:InputDispatcher -> InputMonitor -> WMS 和 WMS -> InputMonitor -> InputDispatcher;

    // InputDispatcher -> InputMonitor -> WMS:实现了 IMS 中的 WindowManagerCallbalck 接口
        public interface WindowManagerCallbacks {
            public void notifyConfigurationChanged();  // 配置变更
            public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); // LID 开关
            public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
            // 连接 InputDispatcher 与应用的 socket 连接;
            public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
            // ANR 
            public long notifyANR(InputApplicationHandle inputApplicationHandle,
                    InputWindowHandle inputWindowHandle, String reason);
            // 以下三个回调接口是 WMS 处理事件时优先
            public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
            public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
            public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                    KeyEvent event, int policyFlags);
            // 事件在整个处理流程均未处理时,与 WMS 协商解决
            public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
                    KeyEvent event, int policyFlags);
            public int getPointerLayer();
        }
    // 当IMS接收到相应输入事件后,会通过mWindowManagerCallbacks 来调用mInputMonitor对象方法:
    // return  mWindowManagerCallbacks.notifyConfigurationChanged();
    // return mWindowManagerCallbacks.notifyANR();
    // ...
    
    
    
    // WMS -> InputMonitor -> InputDispatcher:通过 InputMonitor 向 WMS 提供访问一系列访问 InputDistacher 的接口;
    // 比如 InputDispatcher 中的当前窗口焦点,就是WMS 通过 InputMonitor 中的 updateInputWindowsLw() 通知的;
    

    在这里先预留两个问题:InputDispatcher 时如何通知应用程序窗口有事件产生,又是如何与目标窗口(InputTaget)之间进行通信的?

    1.2 InputManagerService 的初始化和 start() 方法:IMS 从 java 层到 native 层的启动;
    (1)InputManagerService.java 的构造函数:从 InputManagerService.java 构造函数开始,初始化 input 输入事件关键类;

    //(1)InputManagerService.java中:构造函数
    public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
    
        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        // native方法,com_android_server_input_InputManagerService.cpp中
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
    
    
    
    //(2)nativeInit():native方法,com_android_server_input_InputManagerService.cpp
    static jlong nativeInit(JNIEnv* env, jclass clazz,
            jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
        // MessageQueue的指针
        sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
        if (messageQueue == NULL) {
            jniThrowRuntimeException(env, "MessageQueue is not initialized.");
            return 0;
        }
        // native 层的 NativeInputManager 对象,并返回该对象的指针,赋值给 Java 层的 mPtr;
        NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
                messageQueue->getLooper());
        im->incStrong(0);
        // reinterpret_cast() 用在任意指针(或引用)类型之间的转换
        return reinterpret_cast<jlong>(im);
    }
    
    
    
    //(3)native 层 NativeInputManager的构造函数:com_android_server_input_InputManagerService.cpp 中
    NativeInputManager::NativeInputManager(jobject contextObj,
            jobject serviceObj, const sp<Looper>& looper) :
            mLooper(looper), mInteractive(true) {
        // ...
    
        sp<EventHub> eventHub = new EventHub();
        // 这就是 input 输入事件番外2 中提到的 mInputManager(输入事件的几个关键类都在其中)
        mInputManager = new InputManager(eventHub, this, this);  
    }
    
    
    
    //(4)native 层 InputManager 的构造函数:frameworks/native/services/inputflinger/InputManager.cpp
    InputManager::InputManager(
            const sp<EventHubInterface>& eventHub,
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
        mDispatcher = new InputDispatcher(dispatcherPolicy);
        mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
        initialize();  // 执行下方的 initialize() 方法
    }
    
    void InputManager::initialize() {
        mReaderThread = new InputReaderThread(mReader);
        mDispatcherThread = new InputDispatcherThread(mDispatcher);
    }
    

    (2)InputManagerService.java 的 start() 方法:
    (a)input 输入事件从 java 层 的启动到 native 方法 nativeStart(mPtr) 的执行;
    (b)nativeStart(mPtr) 方法启动处理线程:处理线程启动后,就代表 IMS 在 native 层成功启动;

    //(a)InputManagerService.java 的 start() 方法:从 java 层启动 IMS 
    public void start() {
        Slog.i(TAG, "Starting input manager");
        // 在 InputManagerService 的对象 inputManager 初始化过程中执行的 nativeInit() 已经对 mPtr 赋值;
        nativeStart(mPtr);  // 关键方法
    
        // 将inputmanagerservice添加到 Wathcdog中,Watchdog检测service是否正常工作
        Watchdog.getInstance().addMonitor(this);
        // 监听Settings.System.POINTER_SPEED、Settings.System.SHOW_TOUCHES 的变化,并通知native层
        registerPointerSpeedSettingObserver();
        registerShowTouchesSettingObserver();
    
        // 接收 ACTION_USER_SWITCHED,这是关于多用户切换的操作
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updatePointerSpeedFromSettings();
                updateShowTouchesFromSettings();
            }
        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
    
        updatePointerSpeedFromSettings();
        updateShowTouchesFromSettings();
    }
    
    
    
    //(b)nativeStart(mPtr):com_android_server_input_InputManagerService.cpp 中
    static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
        // 将传入的 mPtr 强转为 NativeInputManager 对象;reinterpret_cast() 方法上面有介绍过
        NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    
        // 执行的是 InputManager 的 start() 方法;
        // 1.2 的代码块 c 中:在初始化 NativeInputManager 时(构造函数中),也对成员变量 mInputManager 进行了初始化
        status_t result = im->getInputManager()->start();  
        if (result) {
            jniThrowRuntimeException(env, "Input manager could not be started.");
        }
    }
    
    status_t InputManager::start() {
        // 执行 mDispatcherThread 和 mReaderThread 的 run() 方法,启动处理线程;  详见 2 中的分析;
        status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
        if (result) {
            ALOGE("Could not start InputDispatcher thread due to error %d.", result);
            return result;
        }
        // 先启动分发线程,再启动读取线程;这里是为了保证当事件开始读取时,一定会被分发;
        result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
        if (result) {
            ALOGE("Could not start InputReader thread due to error %d.", result);
            mDispatcherThread->requestExit();
            return result;
        }
    
        return OK;
    }
    

    至此,IMS 在 native 层的启动过程基本完成,接下来分析线程启动后,做了哪些事情、事件的读取与分发又是如何完成的 (涉及到后续章节,待更新);

    2. 处理线程的分析

    Thread 类是 Android 为线程操作而做的一个封装,其内部封装了 pthread 线程工具,提供了与 Java 层Thread 类相似的 API;Thread 类提供了一个名为 threadLoop() 的纯虚函数,当线程开始运行后,将会在内建的线程循环中不断地调用 threadLoop(),直到此函数返回 false,则退出线程循环,从而结束线程。

    2.1 线程类简介:
    (1)Thread 类的构造函数:

    Thread::Thread(bool canCallJava)  //注意这里需要传入的参数 canCallJava
        :   mCanCallJava(canCallJava),
            mThread(thread_id_t(-1)),
            mLock("Thread::mLock"),
            mStatus(NO_ERROR),
            mExitPending(false), mRunning(false)
    #ifdef HAVE_ANDROID_OS
            , mTid(-1)
    #endif
    {
    }
    

    (2)Thread 类的 run() 方法:

    status_t Thread::run(const char* name, int32_t priority, size_t stack)
    {
        Mutex::Autolock _l(mLock);
    
        if (mRunning) {
            // thread already started
            return INVALID_OPERATION;
        }
    
        // reset status and exitPending to their default value, so we can
        // try again after an error happened (either below, or in readyToRun())
        mStatus = NO_ERROR;
        mExitPending = false;
        mThread = thread_id_t(-1);
        
        // hold a strong reference on ourself
        mHoldSelf = this;
        mRunning = true;
    
        bool res;
       //如果mCanCallJava为真,则调用createThreadEtc函数,线程函数是_threadLoop。
       //_threadLoop是Thread.cpp中定义的一个函数。
        if (mCanCallJava) {
            res = createThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        } else {
            res = androidCreateRawThreadEtc(_threadLoop,
                    this, name, priority, stack, &mThread);
        }
        
        if (res == false) {
            mStatus = UNKNOWN_ERROR;   // something happened!
            mRunning = false;
            mThread = thread_id_t(-1);
            mHoldSelf.clear();  // "this" may have gone away after this.
    
            return UNKNOWN_ERROR;
        }
    

    (3)_threadLoop(void* user) 方法:循环调用 threadLoop();

    int Thread::_threadLoop(void* user)
    {
        Thread* const self = static_cast<Thread*>(user);
        sp<Thread> strong(self->mHoldSelf);
        wp<Thread> weak(strong);
        self->mHoldSelf.clear();
    
        // ...
        bool first = true;
    
        do {    // 循环调用 threadLoop()
            bool result;
            if (first) {
                first = false;
                self->mStatus = self->readyToRun();
                result = (self->mStatus == NO_ERROR);
    
                if (result && !self->exitPending()) {
                    result = self->threadLoop();
                }
            } else {
                result = self->threadLoop();
            }
    
            {
            Mutex::Autolock _l(self->mLock);
            if (result == false || self->mExitPending) {  // threadLoop() 返回为 false 时,结束线程
                self->mExitPending = true;
                self->mRunning = false;
                self->mThread = thread_id_t(-1);
                // note that interested observers blocked in requestExitAndWait are
                // awoken by broadcast, but blocked on mLock until break exits scope
                self->mThreadExitedCondition.broadcast();
                break;
            }
            }
            strong.clear();  // 释放引用
            // And immediately, re-acquire a strong reference for the next loop
            strong = weak.promote();
    
        } while(strong != 0);
    
        return 0;
    }
    

    这里对线程只是做了简单的介绍,如果想进一步了解,可以参考 framework 线程类
    2.2 事件读取线程 InputReaderThread 和分发线程 InputDispatcherThread:
    (1)InputDispatcherThread:
    构造函数:这里只是构建出 InputDispatcherThread 的实例;

    InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
            Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
    }
    

    循环执行任务:通过上面可知,nativeStart(mPtr) -> InputManager::start() 中执行了分发线程的 run() 方法,而 run() 方法中循环执行 threadLoop() 方法,接下来看看这个方法:

    bool InputDispatcherThread::threadLoop() {
        mDispatcher->dispatchOnce();  // 这里也很简单,也就是循环执行 mDispatcher 的 dispatchOnce() 方法;
        return true;  // return true 表示一直循环执行
    }
    

    (2)InputReaderThread:与 InputDispatcherThread 一致,比较简单;

    // 构造函数
    InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
            Thread(/*canCallJava*/ true), mReader(reader) {
    }
    
    // 循环执行任务
    bool InputReaderThread::threadLoop() {
        mReader->loopOnce();  // 循环执行 mReader的 loopOnce() 方法;
        return true;
    }
    

    小结:

    • SystemServer.java 中 startOtherServices():创建 java 层的 IMS(inputManager),同时创建 WMS(wm),并通过inputManager.setWindowManagerCallbacks(wm.getInputMonitor()) 进行相互关联;最后执行 inputManager.start() 启动 IMS;
      (1)InputManagerService.java 中的构造函数:调用 mPtr = nativeInit(...),创建 native 层的 NativeInputManager,并保存其返回的指针于 mPtr 中;
      (2)InputManagerService.java 的 start() 方法:调用 nativeStart(mPtr),IMS 在 native 层启动;

    • nativeInit() 方法:创建 NativeInputManager 对象并返回其指针,同时创建 InputManager 的对象和输入事件所需几个关键类的对象(EventHub, InputDispatcher, InputDispatcherThread, InputReader, InputReaderThread) ;

    • nativeStart(mPtr) 方法:执行了事件分发线程(mDispatcherThread) 和 事件读取线程(mReaderThread)的 run() 方法,至此 native 层 IMS 的启动完成;

    相关文章

      网友评论

          本文标题:framework 学习笔记20. input输入事件番外3(n

          本文链接:https://www.haomeiwen.com/subject/cxyzzktx.html