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> 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 的启动完成;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容