virtio-input

本文详细介绍了Virtio-input框架如何在基于KVM的Android虚拟机中处理输入事件,如触控屏和键盘事件。通过Virtio-input,这些事件经由VirtQueue传递给内核Input子系统,然后由InputFlinger服务进行处理和分发。此外,文章还探讨了Android的Native运行方式以及InputFlinger的工作流程。
摘要由CSDN通过智能技术生成

说明

本文以Crosvm + KVM运行Android虚拟机为例分析Virtio-input框架,该方案谷歌做的比较成熟,支持Android中响应触控屏事件(鼠标,触控都认为是触控),键盘事件等

概述

在这里插入图片描述

    Android有两种运行形态,一种是运行于Hypervisor之上的虚拟机,另一种是直接运行于硬件的Native Android。
input driver:这两种场景在input驱动层面实现不同,Android虚拟机依赖Virtio-input框架将输入Event上报给Input子系统,Native Android依赖USB驱动和Hid驱动将输入Event上报给Input子系统。
framework inputflinger:不感知这两种场景,处理裸机一致,主要监听读取/dev/input/eventX事件,通过InputDispatcher上报给WindowMnager,分发到对应的winfow和display。

InputFlinger

  • Inputflinger流程. InputManger线程启动后,启动InputDispatcher线程和InputReader线程
  • InputReader. 由EventHub,TouchInputMapper,QueuedInputListener等组成,
    • EventHub打开所有/dev/input/eventX设备并epoll监听,加载idc配置文件,一旦有事件到来就组装为rawEvent放入mEventBuffer
    • InputReader将rawEvent组装为NotifyMotionArgs,携带了更多信息,如displayId等
    • QueuedInputListener将NotifyMotionArgs组装后填充到mInboundQueue
  • InputDispatcher.从mInboundQueue取出Event,根据事件类型进行分发,如触控MOTION事件
#由IMS java调用start()
InputManager::start()
 mDispatcher->start() #启动dispatcher线程,分发Event
  InputDispatcher::dispatchOnce() #分发线程主体
   dispatchOnceInnerLocked #从mInboundQueue取Event根据TYPE分发
    EventEntry::Type::MOTION
      InputDispatcher::dispatchMotionLocked #分发触控事件
        dispatchEventLocked

InputReader->start() #启动inputReader线程,读取Event
 InputReader::start() 
  InputReader::loopOnce
   EventHub::getEvents() #从EventHub读取事件,EVENT_BUFFER_SIZE 256
    EventHub::readNotifyLocked() //检查event事件
     EventHub::scanDirLocked()     //检查新目录事件
      EventHub::openDeviceLocked() //打开eventX设备,加入epoll
      #构造identifier和EventHub::device
      loadConfigurationLocked #根据identifier名称打开idc文件
      #rk3588可以在此处为每个event指定idc
    epoll_wait //有事件后构造event
  InputReader::processEventsLocked() #rawEvent放入mEventBuffer
   InputDevice::process #将rawEvent处理为NotifyMotionArgs
    MultiTouchInputMapper::process
     TouchInputMapper::processRawTouches
      TouchInputMapper::cookAndDispatch
       TouchInputMapper::dispatchTouches
        #组装NotifyMotionArgs
        #要能获取2个deviceId和displayId
        TouchInputMapper::dispatchMotion 
         QueuedInputListener::notifyMotion
  QueuedInputListener::flush() #发送到InputDispatcher线程
   InputClassifier::notifyMotion(NotifyMotionArgs const*)
    InputDispatcher::notifyMotion #填充Event 
     enqueueInboundEventLocked #入mInboundQueue,由Dispatcher去取

virtio-input框架

Virtio-Input框架

  • Virtio-Input框架输入事件上报流程:webrtc -> crosvm virtio-input device --> VirtQueue --> virtio_input.ko -> kernel Input subsystem ->/dev/input/event0 ->Android InputReader

协议

  • 配置协议. virtio_input协议简单,前端向后端请求配置,后端填充。配置一般由触发的virtio-pci的read/write操作.前后端支持的配置协议
VIRTIO_INPUT_CFG_UNSET = 0x00,
VIRTIO_INPUT_CFG_ID_NAME = 0x01,
VIRTIO_INPUT_CFG_ID_SERIAL = 0x02,
VIRTIO_INPUT_CFG_ID_DEVIDS = 0x03,
VIRTIO_INPUT_CFG_PROP_BITS = 0x10, //PROP表示支持的properties
VIRTIO_INPUT_CFG_EV_BITS = 0x11,   //EV表示是什么设备
VIRTIO_INPUT_CFG_ABS_INFO = 0x12, //绝对值,用于表示坐标

数据传输. virtio_input有event和status两个VirtQueue,eventQueue用于传输event事件,形式为[type,code,value],statusQueue用于传输状态,如crosvm从eventQueue读取了多少字节。没有向Virtio-Gpu那种协议CMD。

前端(front-end)分析

Virtio-input.ko.前端为Android中的Virtio-input.ko,

#代码位于common目录,因为Android沿用开源virtio-input前端驱动,基本没有改动,因此不在common-modules目录
common/drivers/virtio/virtio_input.c
#kernel.log日志,input设备实际由crosvm创建
input: Crosvm Virtio Multitouch Touchscreen 0 as /devices/pci0000:00/0000:00:0c.0/virtio11/input/input0
input: Crosvm Virtio Multitouch Touchscreen 1 as /devices/pci0000:00/0000:00:0d.0/virtio12/input/input1
  • 触控调试
#/dev/input/下的设备均是crosvm virtio创建的
#android /dev/input/下的设备均是virtio-input创建
#鼠标点击app键(触控操作也是一样),检测input输入
getevent -l

在这里插入图片描述

  • 代码分析
#前端发送. 向vq发送type,code,value
virtinput_send_status()
#前端接收
virtinput_recv_events()
  #从vq接受type,code,value,向input子系统上报事件
  #如getevent看到的[EV_ABS ABS_MT_POSITION_Y 0000023d]
  input_event() 

后端(back-end)分析

  • Crosvm后端.对mouse,keyboard,single_touch_screen,multi_touch_screen输入设备支持,如trout使能了keyboard,switch,multi_touch_screen,以下对multi_touch_screen进行分析

  • 配置构造

VirtioInputConfig #用于向前端返回配置
  #构造配置内存,根据VIRTIO_INPUT_CFG协议设置cfg,用于拷贝给guest
  build_config_memory
    VIRTIO_INPUT_CFG_ID_DEVIDS
    //设置DEVID,格式(bustype,vendor,product,version)
    VIRTIO_INPUT_CFG_ID_DEVIDS
      //设置abs,格式(min,max,fuzz,flat)
      cfg.set_device_ids(&self.device_ids);
    VIRTIO_INPUT_CFG_
  #由VirtioDevice.write_config调用,在virtio-pci对bar操作配置空间时调用
  read/write //会对cfg进行拷贝 
  • 工作队列
Worker工作队列,给run线程处理事件,支持以下方法
  #从事件源取数据,写到VQ
  fill_event_virtqueue
  #将event发到guest
  send_events
  #将event从guest发到source
  read_event_virtqueue
  #处理statusQ事件,从VQ读状态到source
  process_status_queue 
  • 主线程
Run线程
  For wait_event //等待事件发生并处理,支持以下五种事件
    EventQAvailable //
      send_events
    StatusQAvailable //StatusQ可用,取出发给source
      process_status_queue
    InputEventsAvailable //事件源有event,转发到guest
      send_events
    InterruptResample //中断可以重采样
    Kill 
  • crosvm设备与android设备绑定
#crosvm multi_touch设备和Android input设备绑定
input : Crosvm Virtio Multitouch Touchscreen 0 as /devices/pci0000:00/0000:00:0c.0/virtio11/input/input0
#根据配置文件将crosvm event和Android输入事件event0绑定,
EventHub: New device: id=2, fd=186, path='/dev/input/event0', name='Crosvm Virtio Multitouch Touchscreen 0', classes=TOUCH | TOUCH_MT, configuration='/vendor/usr/idc/Crosvm_Virtio_Multitouch_Touchscreen_0.idc', keyLayout='', keyCharacterMap='', builtinKeyboard=false, 
#crosvm Touchscreen和displayID绑定
InputReader: Device reconfigured: id=3, name='Crosvm Virtio Multitouch Touchscreen 1', size 800x600, orientation 0, mode 1, display id 2 

Aosp处理

参考:https://www.androidperformance.com/2019/11/04/Android-Systrace-Input/#/%E7%B3%BB%E5%88%97%E6%96%87%E7%AB%A0%E7%9B%AE%E5%BD%95

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值