In daily tests, we often need to simulate user clicks and other operations to achieve various input functions of simulated users. Here, we summarize several click methods, as well as their respective advantages and disadvantages. At present, there are roughly four ways to achieve cross-process clicks
- Adb shell command input, we will see it supports the following event types:
private BufferedInputStream stdin = null;
private BufferedOutputStream stdout = null;
private BufferedInputStream erroeOut = null;
private static Process mProcess = null;
public Shell(String su) throws IOException, InterruptedException {
mProcess = Runtime.getRuntime().exec(su);
this.stdin = new BufferedInputStream(mProcess.getInputStream());
this.stdout = new BufferedOutputStream(mProcess.getOutputStream());
this.erroeOut = new BufferedInputStream(mProcess.getErrorStream());
this.read();
}
public void write(String value) throws IOException {
this.stdout.write((value + "\n").getBytes());
this.stdout.flush();
}Copy the code
Above is a simple partition of executing shell commands, now we just pass in the corresponding command, for example, we click the point (100,200) on the screen
Shell shell = new Shell("su");
shell.write( "input tap 100 200" );Copy the code
Adb shell Input is relatively simple to use, but it is slow to execute.
- 2: monkey
You know Monkey used for pressure test, in fact, when we run the Monkey will start “com.android.com mands. Monkey” such a process, all sorts of Monkey click slide operation is implemented in the process, so if we can send events to the process, So now that we have the ability to click across processes, let’s see how we can do that.
Start “com.android.com mands. Monkey” process, can be use the monkey – port 3131, monkey process starts, how can communication can, in fact, we can through the way of the socket to establish a connection, You can communicate with the Monkey process by connecting the 127.0.0.1 address and port 3131, so let’s do that
First check if the Monkey process is running, then kill it and start it again.
Now we can create a socket that connects to port 3131, which is the monkey process we just started.
After connecting to the Monkey process, we can send click events. The Monkey click events have two parts: Down and Up. The format is as follows:
touch down x y touch up x yCopy the code
It can not only send click events, but also send keycode and other events. Monkey execution efficiency is much faster, but sometimes its stability is not good enough, and it and UiAutomator can not be used at the same time, the two conflict
- Three: Instrumentation:
If we can send a click event in our own app in the following way,long downTime = SystemClock.uptimeMillis(); MotionEvent tapDownEvent = MotionEvent.obtain(downTime, downTime,MotionEvent.ACTION_DOWN, x, y, 0); MotionEvent tapUpEvent = MotionEvent.obtain(downTime+100,downTime+100, MotionEvent.ACTION_UP, x, y, 0); mInstrumentation.sendPointerSync(tapDownEvent); mInstrumentation.sendPointerSync(tapUpEvent); tapDownEvent.recycle(); tapUpEvent.recycle();Copy the code
However, if you want a cross-process click, it will report this error,Permission denied, home event from….
This error is caused by sending click events from one application to another, and the two applications have different UUIds.
Therefore, there are two ways to achieve cross-process capability. One is to hook the process of the application under test and click in the application under test through process communication. Another way is to hook the UID of the test application
Native InjectInputEvent in hook, change the UID value to 0, so it can pass the permission verification of hasInjectPermission inside.findAndHookMethod("com.android.server.input.InputManagerService", lpparam.classLoader, "nativeInjectInputEvent", int.class, lpparam.classLoader.loadClass("android.view.InputEvent"), int.class, int.class, int.class, int.class, int.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log("lzf called nativeInjectInputEvent:" + param.args[3]); XposedBridge.log("uid is :" + TargetUid + "" + param.args[3]); if ((Integer) param.args[3] == TargetUid) { XposedBridge.log("here:" + param.args[3]); param.args[3] = 0; }}});Copy the code
TargetUid is the UID of the application we want to inject,
More detailed reasons are availablewww.hizher.com/pageContent… - Iv. Sendevent Mode:
Android provides these two handy tools to handle input events
Getevent: Displays the input information of the device
Sendevent: Injects input events
Get input information from the device using getevent:
This is the information on the N5 device (different devices may have different information). You can see that there are 6 event devices in the N5 phone. /dev/inpu/event1 is the device that sends the touch
/dev/input/event1: EV_ABS ABS_MT_TRACKING_ID 00000005 /dev/input/event1: EV_ABS ABS_MT_POSITION_X 0000018b /dev/input/event1: EV_ABS ABS_MT_POSITION_Y 00000529 /dev/input/event1: EV_ABS ABS_MT_PRESSURE 00000030 /dev/input/event1: EV_SYN SYN_REPORT 00000000 /dev/input/event1: EV_ABS ABS_MT_POSITION_X 0000018a /dev/input/event1: EV_ABS ABS_MT_POSITION_Y 00000528 /dev/input/event1: EV_SYN SYN_REPORT 00000000 /dev/input/event1: EV_ABS ABS_MT_POSITION_X 00000189 /dev/input/event1: EV_ABS ABS_MT_POSITION_Y 00000527 /dev/input/event1: EV_ABS ABS_MT_PRESSURE 0000002e /dev/input/event1: EV_ABS ABS_MT_TOUCH_MAJOR 00000003 /dev/input/event1: EV_SYN SYN_REPORT 00000000 /dev/input/event1: EV_ABS ABS_MT_TRACKING_ID ffffffff /dev/input/event1: EV_SYN SYN_REPORT 00000000Copy the code
Take a look at the description of each item above:
ABS_MT_TRACKING_ID: ID for reporting touch tracking, is a non-negative, arbitrary integer used to distinguish multiple simultaneous operations. For example, when multiple fingers touch the device, each finger is bound to a separate tracking ID while the finger is on the screen, and the tracking ID may be reused when the finger is off the screen (optional)
ABS_MT_POSITION_X: X-axis coordinates of touch events (mandatory)
ABS_MT_POSITION_Y: Y coordinates of touch events (mandatory)
ABS_MT_PRESSURE: Touch event pressure or signal strength (optional)
SYN_REPORT: Semaphore sent when the touch event is up
More references:Multi-touch devices use the following Linux input events
Each Sendevent command requires four parameters
device_name (string)
event_type (decimal int)
event_code (decimal int)
value (decimal int)
The coordinates above are hexadecimal converted to decimal after the click event is sentsendevent /dev/input/event1 3 53 395 sendevent /dev/input/event1 3 54 1321 sendevent /dev/input/event1 0 0 0Copy the code
In this mode, the event types of each device are different and need to be matched with different models.