android uiautomator 点击分析
来源:互联网 发布:淘宝上的东西是正品吗 编辑:程序博客网 时间:2024/06/06 06:44
之前调研过自动化测试框架,最近有一点时间,查查里面的实现原理。
当时是选了uiautomator.这个只是对UIAutomator 的简单封装,以d.click(x,y)为例,分析下uiautomator做了什么。
python封装部分相对简单,就是封装了一个app,然后jsonrpc调用,实际上走的是
boolean click(int x, int y)
Perform a click at arbitrary coordinates specified by the user
https://developer.android.com/reference/android/support/test/uiautomator/UiDevice.html?hl=zh-cn#click(int, int)
一堆封装之后,源码里面是注入到InputServer
./frameworks/base/core/java/android/app/UiAutomationConnection.java
@Overridepublic boolean injectInputEvent(InputEvent event, boolean sync) { synchronized (mLock) { throwIfCalledByNotTrustedUidLocked(); throwIfShutdownLocked(); throwIfNotConnectedLocked(); } final int mode = (sync) ? InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH : InputManager.INJECT_INPUT_EVENT_MODE_ASYNC; final long identity = Binder.clearCallingIdentity(); try { return InputManager.getInstance().injectInputEvent(event, mode); } finally { Binder.restoreCallingIdentity(identity); }}
这个和输入法输入文字部分的东西好像。举个栗子:
adb input text “hi yeshen”
./frameworks/base/cmds/input/src/com/android/commands/input/Input.java
/** * Convert the characters of string text into key event's and send to * device. * * @param text is a string of characters you want to input to the device. */private void sendText(int source, String text) { StringBuffer buff = new StringBuffer(text); boolean escapeFlag = false; for (int i=0; i<buff.length(); i++) { if (escapeFlag) { escapeFlag = false; if (buff.charAt(i) == 's') { buff.setCharAt(i, ' '); buff.deleteCharAt(--i); } } if (buff.charAt(i) == '%') { escapeFlag = true; } } char[] chars = buff.toString().toCharArray(); KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); KeyEvent[] events = kcm.getEvents(chars); for(int i = 0; i < events.length; i++) { KeyEvent e = events[i]; if (source != e.getSource()) { e.setSource(source); } injectKeyEvent(e); }}
private void injectKeyEvent(KeyEvent event) { Log.i(TAG, "injectKeyEvent: " + event); InputManager.getInstance().injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);}
好了,现在大部分自动化测试框架都会依赖Android UIAutomator,所以都是走的 InputManager.getInstance().injectInputEvent
注释写着
Injects an input event into the event system on behalf of an application.
binder 调用到
./frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
然后进入native层
./frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId,int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,uint32_t policyFlags) { ... bool needWake = false; for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) { EventEntry* nextEntry = entry->next; needWake |= enqueueInboundEventLocked(entry); entry = nextEntry; } ...}
入队之后找到最顶层的window进行事件分发
./frameworks/native/services/inputflinger/InputDispatcher.cpp
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { ... case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && mInputTargetWaitApplicationHandle != NULL) { int32_t displayId = motionEntry->displayId; int32_t x = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (touchedWindowHandle != NULL && touchedWindowHandle->inputApplicationHandle != mInputTargetWaitApplicationHandle) { // User touched a different application than the one we are waiting on. // Flag the event, and start pruning the input queue. mNextUnblockedEvent = motionEntry; needWake = true; } } break; } ...}
整个流程下来,就是作为一个第三方应用,走完了全部的鉴权等操作之后,在InputManagerServer统一处理,入队后分发点击事件给最顶层的窗口。
1,入队后,caller的信息没传过去,所以被自动测试的应用
是没有办法直接感知它是被系统的其他应用控制,还是由硬件直接输入控制的。
2,因为是注入到InputManagerServer中,所以如果有多个自动测试应用
对内控制都没有影响。最多就是InputManagerServer中会携带多个自动测试应用
的信息。
但是被控制还是有许多特征的,举个栗子
ps | grep uiautomator
pm list instrumentation
pm list packages | grep atx
- android uiautomator 点击分析
- android自动化测试Uiautomator源码分析之一
- android自动化测试Uiautomator API分析之一
- android uiautomator
- Android uiautomator
- android自动测试方法分析(monkeyrunner,robotium,uiautomator)
- android自动测试方法分析(monkeyrunner,robotium,uiautomator)
- android自动化测试Uiautomator源码分析之二
- android自动化测试Uiautomator源码分析之三
- android自动化测试Uiautomator源码分析之四
- android自动化测试Uiautomator源码分析之五
- android自动化测试Uiautomator API分析之二
- android UiAutomator写一个等待元素出现并点击的方法
- android UiAutomator了解源码解决控件bonds[0,0]无法点击
- android UiAutomator用递函数归处理网络延迟和点击无效的情况
- Android uiautomator 学习笔记
- Android Uiautomator创建过程
- Android UIAutomator Test
- 安卓调用系统拍照功能:1、启动拍照返回图片,2、启动拍照,图片存储在指定路径下
- 进程间通讯——共享内存
- PullToRefreshScrollView的使用
- vsftpd 配置
- Banner的使用
- android uiautomator 点击分析
- Windows 2012 下Redmine安装和环境搭建
- 泰国旅游记
- linux 服务器网络测试
- HTML基础(二)
- Angular 表单判断密码
- 基于Qt的收银点餐系统之小票打印(二)
- Uva 10129 (dfs判断连通 +欧拉回路)
- 数据库学习---2