Android Input底层机制

前序

一般情况下很多同学对于点击事件的认识都只存在于从 Activity 开始的,然后从 Window 中进行分发,或者有些人有过自定义View的经验可能会涉及事件拦截处理等,会用到 onTouchEvent 和 dispatchTouchEvetn 这几个方法,会处理屏幕滑动,Down事件,Up事件等,但仅停留于对于 View 层的了解。

自定义View的事件处理其实在整个Android输入系统中只能算是最上层的,但这些事件是怎么产生的,上层View是怎么获得到这些事件的呢?喜欢研究底层实现原理的我,今天就给大家讲讲。

输入系统

事件产生的底层主要是输入子系统,Android 中的输入设备有很多,例如屏幕,鼠标,键盘等都是输入设备,对于应用开发者,接触最多的也就是屏幕了。当输入设备可用时,Linux会在 /dev/input 中创建对应的设备节点。用户操作输入设备就会产生各种事件,这些事件的原始信息就会被 Linux内核中的输入子系统采集,原始信息由 Kernel space 的驱动层一直传递到设备结点。

Android提供了一些api可以让开发者在设备节点(dev/input/)中读取内核写入的事件。

InputManagerService

IMS 的工作就是监听 /dev/input 下所有设备的节点,当有数据时就会进行加工处理,并交给中间层的 WMS 派发给合适的 Window。后面简称为IMS。

WindowManagerService

Android的WMS主要是负责窗口管理,窗口的启动、添加、删除,管理窗口大小、层级等,WMS与IMS息息相关。IMS将底层封装好的事件通过Socket pair传递给WMS,WMS通过绑定好的InputChannel找到对应的窗口进行app层的事件分发,这时候就到我们熟悉的Activity的事件分发流程了。

下面借张图,整体流程画的非常详细:

今天我们主要讲底层硬件驱动产生的事件的获取及分发流程,至于硬件驱动层就不展开介绍了。而这里面最重要的就是IMS相关的流程,下面开始补足知识盲区。

IMS的初始化

IMS的构造

和WMS一样,IMS 也是在 SystemServer 中创建的 ,也是 startOtherServers 方法中。

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
        ...
        inputManager = new InputManagerService(context);
        wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
        ...
        inputManager.start();
    }

主要做了三件事:

  • 调用了IMS的构造方法 

  • 将IMS作为参数传递给WMS 

  • 调用了IMS的启动方法start

IMS 构造函数

public InputManagerService(Context context) {
        this.mContext = context;
        //注释1
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
        mStaticAssociations = loadStaticInputPortAssociations();
        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        //注释2
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    }

我们重点关注1创建了一个在android.display 线程的InputManagerHandler,所以后面这个handler处理的消息都是执行在android.display 线程中,android.display 线程是系统共享的单例前台线程,可以用做一些低延时显示的相关操作,WMS 的创建也是在 android.display 中创建的。

注释2 的话,调用了nativeInit 方法,进入native侧创建了 NativeInputManager ,并将该对象指针返回给了 java层,方便后续调用处理。

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
                        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == nullptr) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

接下来看下NativeInputManager的创建


                
  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值