之前的四篇博文记录的都是linux中的input体系相关的东西,最底层以我调试的usb触摸屏的设备驱动为例,贴出链接:

Linux/Android——usb触摸屏驱动 - usbtouchscreen (一)

Linux/Android——输入子系统input_event传递 (二)

Linux/Android——input子系统核心 (三)

Linux/Android——input_handler之evdev (四)

在第二篇有记录input体系整体脉络,博文顺序也差不多是从下往上,这些都没有涉及到android这边的内容,这篇记录一下kernel与android的framework层的关联.


撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42291149#t6


在kernel启动完全之后,input以及evdev都已初始化完,先看在kernel中打开input核心设备的接口input_open_file,

也是android这边frameworks首先会调用到的地方,至于怎么调用到的,后面分析

input_open_file:

在第三篇input核心中,有介绍到注册input这个设备的时候,fops中就有这个input_open_file,现在来看看:

[objc] view plain copy print ?
  1. staticintinput_open_file(structinode*inode,structfile*file)
  2. {
  3. structinput_handler*handler;
  4. conststructfile_operations*old_fops,*new_fops=NULL;
  5. interr;
  6. err=mutex_lock_interruptible(&input_mutex);
  7. if(err)
  8. returnerr;
  9. /*Noload-on-demandhere?*/
  10. handler=input_table[iminor(inode)>>5];//根据索引节点求次设备号除以32,找对应的绑定的事件处理器handler,这里如果得到的次设备号是64~96之间即为evdev的handler,这个input_table数组的维护在上篇有介绍
  11. if(handler)
  12. new_fops=fops_get(handler->fops);//获取handler的fops
  13. mutex_unlock(&input_mutex);
  14. /*
  15. *That's_really_odd.UsuallyNULL->openmeans"nothingspecial",
  16. *not"nodevice".Oh,well...
  17. */
  18. if(!new_fops||!new_fops->open){
  19. fops_put(new_fops);
  20. err=-ENODEV;
  21. gotoout;
  22. }
  23. old_fops=file->f_op;
  24. file->f_op=new_fops;//如果事件处理器有file_operarions就赋值给现在的file->f_op,替换了原来的
  25. err=new_fops->open(inode,file);//这里调用的是事件处理器file方法中的open方法,
  26. if(err){
  27. fops_put(file->f_op);
  28. file->f_op=fops_get(old_fops);
  29. }
  30. fops_put(old_fops);
  31. out:
  32. returnerr;
  33. }

这里如果是打开evdev的,调用到的是evdev_handler中的evdev_fops的open方法!


evdev_fops:

前文有介绍evdev_handler的功能与注册,这里看下这个handler注册的方法:

[objc] view plain copy print ?
  1. staticconststructfile_operationsevdev_fops={
  2. .owner=THIS_MODULE,
  3. .read=evdev_read,
  4. .write=evdev_write,
  5. .poll=evdev_poll,
  6. .open=evdev_open,
  7. .release=evdev_release,
  8. .unlocked_ioctl=evdev_ioctl,
  9. #ifdefCONFIG_COMPAT
  10. .compat_ioctl=evdev_ioctl_compat,
  11. #endif
  12. .fasync=evdev_fasync,
  13. .flush=evdev_flush,
  14. .llseek=no_llseek,
  15. };

都是字面意思,前文也提到匹配connect的时候,在evdev_connect中注册生成了 /sys/class/input/event%d ,

这个字符设备文件就是连接kernel与framework的桥梁了!

可以看到这里有个evdev_open方法,这个方法就是打开设备文件的


evdev_open:

[objc] view plain copy print ?
  1. staticintevdev_open(structinode*inode,structfile*file)
  2. {
  3. structevdev*evdev;
  4. structevdev_client*client;
  5. inti=iminor(inode)-EVDEV_MINOR_BASE;//通过节点算出minor序号,这个在connect生成event%d时有+操作,所以减去BASE
  6. unsignedintbufsize;
  7. interror;
  8. if(i>=EVDEV_MINORS)
  9. return-ENODEV;
  10. error=mutex_lock_interruptible(&evdev_table_mutex);
  11. if(error)
  12. returnerror;
  13. evdev=evdev_table[i];//这个数组就是以minor为索引,存每次匹配上的evdev
  14. ...
  15. bufsize=evdev_compute_buffer_size(evdev->handle.dev);//往下都是分配初始化一个evdev_client变量
  16. client=kzalloc(sizeof(structevdev_client)+
  17. bufsize*sizeof(structinput_event),
  18. GFP_KERNEL);
  19. if(!client){
  20. error=-ENOMEM;
  21. gotoerr_put_evdev;
  22. }
  23. client->bufsize=bufsize;
  24. spin_lock_init(&client->buffer_lock);
  25. snprintf(client->name,sizeof(client->name),"%s-%d",
  26. dev_name(&evdev->dev),task_tgid_vnr(current));
  27. client->evdev=evdev;
  28. evdev_attach_client(evdev,client);//将这个client加入到evdev的client_list链表中
  29. error=evdev_open_device(evdev);//这里深入打开,传入的是设备匹配成功时在evdev_handler中创建的evdev
  30. ...
  31. }

继续看 [objc] view plain copy print ?
  1. staticintevdev_open_device(structevdev*evdev)
  2. {
  3. intretval;
  4. retval=mutex_lock_interruptible(&evdev->mutex);
  5. if(retval)
  6. returnretval;
  7. if(!evdev->exist)
  8. retval=-ENODEV;
  9. elseif(!evdev->open++){//判断是否打开了,初始分配kzalloc,所以open为0,没有打开的话,这里继续调用打开,open计数为1
  10. retval=input_open_device(&evdev->handle);
  11. if(retval)
  12. evdev->open--;
  13. }
  14. mutex_unlock(&evdev->mutex);
  15. returnretval;
  16. }

可以看到这里绕了一圈,由最开始的input_open_file,最后又回到input核心中去了。调用到input.c中的接口,传入的是设备当初匹配成功的组合handle


input_open_device:

[objc] view plain copy print ?
  1. intinput_open_device(structinput_handle*handle)
  2. {
  3. structinput_dev*dev=handle->dev;//取对应的input_dev
  4. intretval;
  5. retval=mutex_lock_interruptible(&dev->mutex);
  6. if(retval)
  7. returnretval;
  8. if(dev->going_away){
  9. retval=-ENODEV;
  10. gotoout;
  11. }
  12. handle->open++;//handle数++,上面是evdev的open++不一样
  13. if(!dev->users++&&dev->open)//这个dev没有被其它进程占用,并且设备有open方法
  14. retval=dev->open(dev);//调用input_dev设备的open方法,这个是在设备驱动注册这个input_dev时初始化的
  15. if(retval){//失败处理情况
  16. dev->users--;
  17. if(!--handle->open){
  18. /*
  19. *Makesurewearenotdeliveringanymoreevents
  20. *throughthishandle
  21. */
  22. synchronize_rcu();
  23. }
  24. }
  25. out:
  26. mutex_unlock(&dev->mutex);
  27. returnretval;
  28. }

这里最终是调用设备驱动注册input_dev时的open方法,现在返回看看我这边注册usbtouchscreen时的input_dev 的open方法: [objc] view plain copy print ?
  1. input_dev->open=usbtouch_open;

这个再往下就是设备驱动干的事了。。这里就不分析usbtouch_open 做了什么了,无非是一些初始化操作之类的

到这里打开设备这一步就完成了!


evdev_read:

这个是evdev设备的读取函数,注册在fops里:

[objc] view plain copy print ?
  1. staticssize_tevdev_read(structfile*file,char__user*buffer,size_tcount,loff_t*ppos)
  2. {
  3. structevdev_client*client=file->private_data;//这个客户端结构在打开的时候分配并保存在file->private_data中
  4. structevdev*evdev=client->evdev;
  5. structinput_eventevent;
  6. intretval;
  7. if(count<input_event_size())
  8. return-EINVAL;
  9. //这条语句提示,用户进程每次读取设备的字节数,不要少于input_event结构的大小
  10. if(client->head==client->tail&&evdev->exist&&(file->f_flags&O_NONBLOCK))
  11. return-EAGAIN;
  12. //head等于tail说明目前还没有事件传回来,如果设置了非阻塞操作,则会立刻返回
  13. retval=wait_event_interruptible(evdev->wait,client->head!=client->tail||!evdev->exist);
  14. //没有事件就会睡在evdev的等待队列上了,等待条件是有事件到来或者设备不存在了(设备关闭的时候,清这个标志)
  15. if(retval)
  16. returnretval;
  17. //如果能执行上面这条语句说明有事件传来或者,设备被关闭了,或者内核发过来终止信号
  18. if(!evdev->exist)
  19. return-ENODEV;
  20. while(retval+input_event_size()<=count&&evdev_fetch_next_event(client,&event))
  21. {
  22. //evdev_fetch_next_event这个函数遍历client里面的input_eventbuffer数组
  23. if(input_event_to_user(buffer+retval,&event))
  24. //将事件复制到用户空间
  25. return-EFAULT;
  26. retval+=input_event_size();
  27. }
  28. returnretval;//返回复制的数据字节数
  29. }

接下来看android的frameworks层 怎么去打开这个input 设备文件的.

framework层相关的处理机制,后续的博文会详细分析,这里只是简单的记录一下与kernel中这些接口的交互,好对android input的运作体系有个整体的概念 !


InputReader:

这个的源码在/frameworks/base/services/input/InputReader.cpp 这个在第二篇,总的脉络图上有,属于input service中一部分,看名字就知道这是一个读取input事件的.

等待输入事件到来的自然会是个loop结构设计.

[objc] view plain copy print ?
  1. boolInputReaderThread::threadLoop(){
  2. mReader->loopOnce();
  3. returntrue;
  4. }

然后看一下这个loopOnce: [objc] view plain copy print ?
  1. voidInputReader::loopOnce(){
  2. int32_toldGeneration;
  3. int32_ttimeoutMillis;
  4. ...
  5. size_tcount=mEventHub->getEvents(timeoutMillis,mEventBuffer,EVENT_BUFFER_SIZE);//这里就是关键了,通过另外一个中间者EventHub获取的input事件
  6. ...
  7. }


EventHub:

源码位于/frameworks/base/services/input/EventHub.cpp

这个里面其它的先不管,这里先介绍下跟本篇有关系的

[objc] view plain copy print ?
  1. size_tEventHub::getEvents(inttimeoutMillis,RawEvent*buffer,size_tbufferSize){
  2. ...
  3. for(;;){
  4. ...
  5. scanDevicesLocked();//这个往里走就是通过EventHub::openDeviceLocked打开*DEVICE_PATH="/dev/input"这个设备,最终用的open,实际到kernel层就是input设备注册的open
  6. ...
  7. int32_treadSize=read(device->fd,readBuffer,//这里的device->fd就是/dev/input/event%d这个设备文件,就是从这里读取出event的buffer
  8. sizeof(structinput_event)*capacity);
  9. ...
  10. }
  11. ..
  12. }


这里的read实际上的操作就是上面介绍的 evdev_read 函数!


至此,kernel层的设备以及事件与android这边的frameworks的input服务处理之间就联系起来了,这里frameworks这边稍微提一下,后续分析细节!


更多相关文章

  1. 如何实现对Android设备进行文本的模拟输入
  2. ADB 工具
  3. Android图形合成和显示系统---基于高通MSM8k MDP4平台
  4. android WebView总结
  5. Android事件处理分析+Android事件处理 +Android输入事件流程
  6. Android之系统给我们提供的常见的Activity
  7. android 笔记 --- 获取Android系统的唯一识别码
  8. Android内核和驱动篇-Android内核介绍
  9. android WebView总结

随机推荐

  1. 基于WiEngine游戏引擎--战斗场景之技能
  2. Android视图SurfaceView的实现原理分析
  3. 【Android】8.4 让主题自适应不同的Andro
  4. Android性能测试工具:Emmagee
  5. 再谈Android的许可证(续)
  6. Android程序安装后图标不显示
  7. Android中分页滑动实现总结
  8. Android(安卓)启动性能优化 - kernel篇
  9. 加快Android离线文档的访问速度
  10. android离开一个页面时关闭子线程