我在实际开发中,遇到一个问题,在电容屏驱动中没有发送input_sync 给上层,导致电容屏有的数据缓存在inputreader 中,会导致系统一系列奇怪问题发生,

至于为什么驱动不发送input_sync ,是因为项目某个功能的框架没有搭好导致的,总之这次不能从驱动中解决这个问题,这次为了弥补这个过失,

就需要在特定的情况下强制把电容屏在inputreader 的缓存清除,好了,这次binder 又要闪亮登场了!

1. 熟悉Inputreader 源码获取清除缓存接口

说实话,没有具体跟踪调试过这部分源码,直接从0开始生硬的看代码确实费力,我尽量简洁地说这块源码,以及我是如何找到清除缓存的接口的。

a. 首先把 frameworks\native\services\inputflinger 这部分代码添加到sourceinsight 中。

b. 只需要大致明白,EventHub.cpp 是直接获取驱动报上来的原始数据,然后InputReader.cpp 对这份数据进行处理保存在一段缓存队列中,InputDispatcher.cpp

从队列中取数据,再发送给上层窗口等等。

所以,只需要阅读InputReader.cpp 代码即可,因为要清空的缓存就在其中。

怎么办,这个cpp 有7千多行代码,不同android 版本说不定有8千多行呢?

别慌!粗略的看一下,发现有个类叫做 MultiTouchInputMapper ,电容屏不就是多点触控么,直接添加相关调试log, 可以清楚这块调用流程。总之,MultiTouchInputMapper

里面有个重要的实现叫做 void MultiTouchInputMapper::reset(nsecs_t when) ,就是它会清空缓存。

c. 熟悉代码后发现 MultiTouchInputMapper 与 InputMapper 有密切的关系,如果实在觉得看代码嫌烦,直接搜出所有的reset ,可以发现void InputDevice::reset(nsecs_t when) 最终会掉进

MultiTouchInputMapper 里面,感觉这就是唯一的通路了,虽然会误伤到SingleTouchInputMapper ,但是对项目没有影响就无所谓了,毕竟SingleTouchInputMapper 中也没有什么数据好清空,如果对我的设计思想有异议请大胆说出来吧!

误伤SingleTouchInputMapper 的InputDevice::reset 代码如下,如果不想误伤可以把下面实现进行修改,或者只调用MultiTouchInputMapper 的reset 接口也行,我这么做主要是害怕只清空一部分不能解决问题,所以后续调试决定统一清空。

void InputDevice::reset(nsecs_t when) {
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->reset(when);
} mContext->updateGlobalMetaState(); notifyReset(when);
}

  

d. 下一步就是搜寻InputDevice 这个类了,可以很快找到调用的方式。

首先声明获取device: InputDevice* device = mDevices.valueAt(deviceIndex);

然后清空数据:device->reset(when);

e. 添加处理代码

void InputReader::clearCTPData(nsecs_t when, int32_t deviceId) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
} InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
} device->reset(when);
}

  

发现里面有个参数比较陌生,deviceId, 调试过input 设备的朋友应该清楚,在adb shell 下输入getevent 就会冒出好多挂载的input 设备信息,其中就包括了deviceId,当然要用代码获取也是可以的,这部分下一节讨论。

2. 添加binder 服务

由上面添加的clearCTPData 这个接口可知,这个处理是在InputReader 类里面新加的一个方法。调用它就需要有一个指针指向当前的InputReader ,好的,有了这个想法就开始写代码吧。

首先在InputReader.cpp 中InputReader::InputReader 的构造函数中添加咱们的binder 指针,binder 调用ontransct的类服务也需要重写一下,就命名为MyInputreaderService 吧。

分三步走,

第一部:

把clearCTPData的代码添加到InputReader.cpp 和 InputReader.h 中,代码刚才有贴过,声明直接放在class InputReader 里面即可。

第二部 :

InputReader.cpp 中在构造函数里面添加binder 的服务,代码如下:

InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener); { // acquire lock
AutoMutex _l(mLock); sp<IBinder> sendBinder = new ByInputreaderService(this); defaultServiceManager()->addService(String16("my.inputreader"), sendBinder); refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}

  

第三部:

完成ByInputreaderService 的功能,我主要借鉴getevent的源码做了一个简单的获取deviceID的功能,同时用InputReader 构造函数中传入的this 来搞事情(调用clearCTPData)

class ByInputreaderService : public BBinder {
public:
InputReader *parent;
int mCTPDeviceId;
nsecs_t mWhen; ByInputreaderService(InputReader *p) : parent(p)
{
mCTPDeviceId = 1;
getCtpFd();
} ~ByInputreaderService()
{ } int scan_input_device(int fd)
{
char name[80];
name[sizeof(name) - 1] = '\0'; if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
ALOGI("could not get device name for %s\n", strerror(errno));
name[0] = '\0';
} ALOGI("getCtpFd device name is %s\n", name);
if(strcmp("cyttsp5_mt", name) == 0)
{
ALOGI("getCtpFd cyttsp5_mt !!!\n");
return 0;
} return -1;
} int getCtpFd(void)
{
int fd = 0;
int device_type = 0;
char devname[50];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir("/dev/input");
if(dir == NULL)
return -1; strcpy(devname, "/dev/input");
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir)))
{
if(de->d_name[0] == '.' && (de->d_name[1] == '\0' ||(de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue; strcpy(filename, de->d_name); fd = open(devname, O_RDWR);
if (fd < 0)
{
ALOGI("[getCtpFd] open device failed! path: %s\n",devname);
continue;
}
device_type = scan_input_device(fd);
if(device_type != 0)
{
mCTPDeviceId ++;
close(fd);
ALOGI("[getCtpFd] scan device failed! path: %s -- %d\n",devname, device_type);
continue;
}
else
{
ALOGI("[getCtpFd] scan device success! path: %s -- %d\n",devname, device_type);
break;
}
}
closedir(dir); close(fd);
return fd;
} status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
ALOGI("ByInputreaderService %d \n", code); if(CLEARINPUTDATA == code)
{
mWhen = systemTime(SYSTEM_TIME_MONOTONIC);
parent->clearCTPData(mWhen, mCTPDeviceId);
}
return NO_ERROR;
} };

  

CLEARINPUTDATA 这个宏随便定义,总之客户端要和这个code 值保持一致即可。

如果觉得代码或者实现的方式有什么不妥的地方请多多指教,谢谢。

希望大家多多吐槽,大家一起共同进步!!

Android native进程间通信实例-binder篇之——解决实际问题inputreader内建类清楚缓存的更多相关文章

  1. Android native进程间通信实例-binder篇之——HAL层访问JAVA层的服务

    有一天在群里聊天的时候,有人提出一个问题,怎样才能做到HAL层访问JAVA层的接口?刚好我不会,所以做了一点研究. 之前的文章末尾部分说过了service call 可以用来调试系统的binder服务 ...

  2. Android native进程间通信实例-binder篇之——简单的单工通信

    网上找了很多binder相关文章,大部分都是在跟踪binder实现源代码,然后再把框架代码贴出来,看着实在费力. 这篇文章从实际出发,直接用一个案例下手,后续想了解binder相关原理的话,可以参考& ...

  3. Android native进程间通信实例-binder篇之——用parcel传输数组

     和之前稍微不同,这次要稍微分析一下 Parce.cpp 和 android_os_Parcel.cp p的源码,为的是能够掌握调试技巧,后续传输其它类型数据就能举一反三了!   1. 代码共享 这次 ...

  4. Android native进程间通信实例-binder结合共享内存

    在android源码的驱动目录下,一般会有共享内存的相关实现源码,目录是:kernel\drivers\staging\android\ashmem.c.但是本篇文章不是讲解android共享内存的功 ...

  5. Android native进程间通信实例-socket本地通信篇之——服务端进程异常退出解决办法

    导读: 好难受啊,为什么服务端说挂就挂,明明只是客户端关闭而已,服务端怎么能挂呢? 想想,如果手机上使用一个聊天程序的时候,手机端关闭了聊天程序,那么远端服务器程序总不能说挂就挂吧!所以一定要查明真相 ...

  6. Android native进程间通信实例-socket本地通信篇之——基本通信功能

    导读: 网上看了很多篇有关socket本地通信的示例,很多都是调通服务端和客户端通信功能后就没有下文了,不太实用,真正开发中遇到的问题以及程序稳定性部分没有涉及,代码健壮性不够,本系列(socket本 ...

  7. 【Android】进程间通信IPC——Binder

    Binder是Android中的跨进程通信方式,bindService的时候,服务端返回Binder对象,通过该对象客户端可以从服务端获取数据.在进程间通信IPC——AIDL中创建了ICustomAi ...

  8. Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了A ...

  9. Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6633311 在上一篇文章中,我 们分析了And ...

随机推荐

  1. NIO基础方法一

    1.remaining();返回当前位置与limit之间得元素数. int[] intArray={1,2,3,4}; IntBuffer intBuffer=IntBuffer.wrap(intAr ...

  2. 【Gradle】Gradle插件

    Gradle插件 插件的作用 把插件应用到项目中,插件会扩展项目的功能,帮助在项目构建过程中做很多事情. 1.可以添加任务到项目中,帮助完成测试.编译.打包等. 2.可以添加依赖配置到项目中,可以通过 ...

  3. Spring Boot 2 使用Servlet、Listener和Filter配置

    开发环境:IntelliJ IDEA 2019.2.2Spring Boot版本:2.1.8 新建一个名称为demo的Spring Boot项目. 一.使用Servlet配置 1.修改启动类 Demo ...

  4. Redis主从复制的基本操作

    一,安装: 1.1.将redis压缩包放到 /opt 下. 2.解压 3.进入目录执行  make 4.执行  make  install 5.在 / 下创建redis文件夹mkdir redis 6 ...

  5. 缺少控制文件备份时如何还原数据库 (Doc ID 1438776.1)

    How to restore database when controlfile backup missing (Doc ID 1438776.1) APPLIES TO: Oracle Databa ...

  6. idea延长使用期

    0. 如果你的idea(版本2019.02)是已过期状态则先上网找个激活码激活再进行下面步骤延长使用期至2089年 1. 附件下载地址: 链接:https://pan.baidu.com/s/1L5O ...

  7. JVM-5-GC(Garbage Collection) 垃圾回收机制

    GC(Garbage Collection)  垃圾回收机制   什么是垃圾回收机制 垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能. ...

  8. 201871010109-胡欢欢《面向对象程序设计(java)》第十六周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  9. LVS负载均衡实现双向热备

    一.LVS1服务器配置 安装ipvsadm,keepalived [root@localhost ~]# yum -y install ipvsadm keepalived 配置keepalivedd ...

  10. Python程序中的进程操作-进程池(multiprocess.Pool)

    目录 一.进程池 二.概念介绍--multiprocess.Pool 三.参数用法 四.主要方法 五.其他方法(了解) 六.代码实例--multiprocess.Pool 6.1 同步 6.2 异步 ...