framework 学习笔记20. input输入事件番外3(native层IMS的启动)

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 = 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(im);
}



//(3)native 层 NativeInputManager的构造函数:com_android_server_input_InputManagerService.cpp 中
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp& looper) :
        mLooper(looper), mInteractive(true) {
    // ...

    sp 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& eventHub,
        const sp& readerPolicy,
        const sp& 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(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(user);
    sp strong(self->mHoldSelf);
    wp 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& 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& 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(native层IMS的启动))