Android Instrumention.sendPointerSync发送Event失败分析
问题场景
Android4.3,进入被测app某个Activity后,测试案例ClickOnScreen出现异常(Click can not be completed!)。
Android4.4正常。
前置说明
测试案例使用的是本人实现的测试框架,它底层调用了Robotium。
分析过程
1. 框架调用了Robotium的ClickOnScreen,源码如下:
(com.jayway.android.robotium.solo.Clicker)

当sendPointerSync(发送点击事件给被测app)10次都失败,便会断言异常:Click can not be completed。
而引发sendPointerSync的异常是:SecurityException。在Android中,出现SecurityException异常是因为权限不足,一般的情况是:被测试App和测试案例的签名不一致,而这在instrumention启动被测试app就出现,不用等到instrument.sendPointerSync,这里是其他的问题引发的。
2. 继续跟进问题。
(1)android.app.Instrumentation

(2)android.hardware.input.InputManager

(3)android.hardware.input.IInputManager

最后是调用Binder.transect进行跨进程调用。
3. 被调用者是系统服务,可追朔到InputManagerService的injectInputEvent。
(1)/frameworks/base/services/java/com/android/server/input/InputManagerService.java

终于发现了我们要找的SecurityException,导致INPUT_EVENT_INJECTION_PERMISSION_DENIED是jni层的nativeInjectInputEvent。
(2)/frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp

(3)/frameworks/base/services/input/InputDispatcher.cpp

终于发现了INPUT_EVENT_INJECTION_PERMISSION_DENIED踪迹,继续查看checkInjectionPermission:

查看系统日志,发现是造成Permission验证失败的原因是:当前windowHandle(被测app)->owneruid与注入者(instrument)->injectoruid不一致。并且windowHandle(被测app)的owneruid竟然是1000(系统账户)!
(4) 系统日志如下:

同时,根据windowHandle->getName().string(),我意外发现“凶手”的Name是:hidden nav(隐藏的nav??….)。
4. 在 被测app源码 和 Android源码中分别查找,最终发在“凶手”匿藏在PhoneWindowManager中……
(1)/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

mHideNavFakeWindow的创建了addFackWindow,mHideNavFakeWindow的owneruid=Process.getmyid()(这里不列代码了), 而PhoneWindowManager是内部服务PhoneWindowService的策略类,属于系统用户。所以mHideNavFakeWindow这个透明的窗口,也是系统用户级别了(mHideNavFakeWindow为了满足某特殊需要,不得不设置为系统用户)…
而执行这个分支,需要满足一个条件:在重渲染ui界面时,被设置了标记:View.SYSTEM_UI_FLAG_HIDE_NAVIGATION。
在被测App源码代码中search,终于发现疑似凶手:view.getRootView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); 而它确实就在出现ClickOnScreen异常的Activity里。最后经调试,确认问题确实如此。
4.3 与 4.4表现不一致的原因
对比PhoneWindowManager 4.3和4.4的代码,发4.4做了改进,如下(右为4.4):

而在被测app的代码中…..

就是 被测试App 在4.4时,会增加一个flag,导致了它撞大运般地在4.4中执行流程发生了改变,避免了mHideNavFakeWindow创建,从而也避免异常的发生。
总结
1. 个人认为这是Android设计上的bug,它的instrument在极端的情况下会失效。
2. 除非测试案例在系统中以系统用户启动,否则在4.3以下系统,该问题无法避免!
3. 只要有mHideNavFakeWindow的存在,原则上所有的操作都会失败,包括drag在内,但Robotium对drag的异常进行了拦截并直接丢弃,所以使用drag表面是成功的,但实际上是失败,这会导致运行中出现无法解释的诡异问题。
Android Instrumention.sendPointerSync发送Event失败分析的更多相关文章
- 转——Android应用开发性能优化完全分析
[工匠若水 http://blog.csdn.net/yanbober 转载请注明出处.] 1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉 ...
- Android 应用开发性能优化完全分析
1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...
- 【转】Android应用开发性能优化完全分析
http://blog.csdn.net/yanbober/article/details/48394201 1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关 ...
- Android应用开发性能优化完全分析
1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...
- Android应用程序发送广播(sendBroadcast)的过程分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6744448 前面我们分析了Android应用程 ...
- Android之 MTP框架和流程分析
概要 本文的目的是介绍Android系统中MTP的一些相关知识.主要的内容包括:第1部分 MTP简介 对Mtp协议进行简单的介绍.第2部分 MTP框架 介绍 ...
- 转:Android应用开发性能优化完全分析
转自:http://blog.csdn.net/yanbober/article/details/48394201 1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜 ...
- Android Debuggerd 简要介绍和源码分析(转载)
转载: http://dylangao.com/2014/05/16/android-debuggerd-%E7%AE%80%E8%A6%81%E4%BB%8B%E7%BB%8D%E5%92%8C%E ...
- android 常见死机问题--log分析
http://blog.csdn.net/fangchongbory/article/details/7645815 android 常见死机问题--log分析============ ...
随机推荐
- getElementsByTagName获得的不是数组的问题!
getElementsByTag() returns a NodeList instead of an Array. You can convert a NodeList to an Array bu ...
- Maven + Eclipse + Tomcat - 开启项目调试之旅(转)
本文的读者需要拥有一些Maven基础知识和实践,如果没有,请直接绕过或者先看一些关于Maven教程,比如Juven翻译的<Maven权威指南>,google一下便知. 开门见山,首先抛出一 ...
- C# 加密
一.RSA加密解密 using System; using System.Collections.Generic; using System.IO; using System.Linq; using ...
- 服务器TIME_WAIT和CLOSE_WAIT详解和解决办法
转载的服务器TIME_WAIT和CLOSE_WAIT详解和解决办法
- 解决 IE 6/7 中console对象兼容性问题
话不多说,直接上代码 (function (){ //创建空console对象,避免JS报错 if(!window.console) window.console = {}; var console ...
- Python 4 —— 函数与模块
函数和模块的使用 一.函数 一个例子说明一切. def hello(): print "hello world" def increment(num): num += 1 retu ...
- 使用git svn clone迁移svn仓库
使用git svn clone迁移svn仓库 clone命令可以指定很多参数,主要用到这些,你也可以使用git svn help查看完整的参数列表. git svn clone https://172 ...
- Windows Phone 8.1 新特性 - 页面导航
本篇介绍一下Windows Phone 8.1 中页面导航的实现方式. 大家对Windows Phone 8 中页面导航的实现一定不陌生,我们使用 NavigationService 来实现.具体写法 ...
- android ontouch事件分发机制
最近开发一个项目中,banner图左右切换和下拉刷新手势有冲突,为此去研究了事件分发,网上资料一大抄,有些讲的不对有些讲的不全,结合了网上一些博文以及源码总结如下 一个完整的触摸事件包含down,m ...
- (多重背包+记录路径)Charlie's Change (poj 1787)
http://poj.org/problem?id=1787 描述 Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie dri ...