Android13 adb input 调试命令使用和源码解析

目录

一、概述

二、常用命令

2.1 输入文本

2.2 模拟按键

2.3 模拟点击

2.4 模拟滑动

2.5 模拟长按

2.6 模拟滚动

三、进阶用法

3.1 组合按键的用法

3.2 长按power键

3.3 输入中文

3.4 代码模拟发送按键

1. 方法1:

2. 方法2:

3. 方法3:

四、注意事项

五、源码解析

六、总结


好了 本篇作为Android 系统调试系列第一篇内容 , 我一直以为和认为Android系统工程师水平,基本可以用 调试水平 调试问题技巧来判断高低。

调试工具手法技巧作为Android程序员的瑞士军刀 必须先磨好刀 。

一、概述

adb shell input是一个命令,用于在Android设备上模拟用户输入。它可以用于自动化测试、调试和其他需要模拟用户输入的场景。通过adb shell input命令,可以模拟按键、滑动、触摸等操作。例如,adb shell input tap x y可以模拟在屏幕上点击坐标为(x,y)的位置。

adb shell input命令的格式如下:

adb shell input [<source>] [-d DISPLAY_ID] <command> [<arg>...]

其中,<source>是要模拟的事件的来源,可以是以下之一:

  • keyboard: 键盘
  • touchscreen: 触摸屏
  • trackball: 轨迹球

如果不指定来源,默认使用以下规则:

  • text: 触摸屏
  • keyevent: 键盘
  • tap: 触摸屏
  • swipe: 触摸屏
  • press: 轨迹球
  • roll: 轨迹球

-d DISPLAY_ID是指定要模拟事件的显示器ID,如果不指定,默认使用以下规则:

  • keyevent: 无效显示器(INVALID_DISPLAY)
  • 其他事件: 默认显示器(DEFAULT_DISPLAY)

<command>是要模拟的事件类型,可以是以下之一:

  • text: 输入文本
  • keyevent: 模拟按键
  • tap: 模拟点击
  • swipe: 模拟滑动
  • press: 模拟长按
  • roll: 模拟滚动

<arg>是根据不同的事件类型指定的参数,例如坐标、按键码、文本内容等。

二、常用命令

2.1 输入文本

要在设备上输入文本,可以使用以下命令:

adb shell input text <string>

其中,<string>是要输入的文本内容。注意,文本中不能包含空格或特殊字符,否则会导致错误或不完整的输入。如果需要输入空格或特殊字符,可以使用转义符\或者使用按键事件代替。

例如,要在设备上输入"Hello World!",可以使用以下命令:

adb shell input text Hello\ World\!

或者

adb shell input keyevent 36 # H
adb shell input keyevent 33 # e
adb shell input keyevent 46 # l
adb shell input keyevent 46 # l
adb shell input keyevent 48 # o
adb shell input keyevent 62 # SPACE
adb shell input keyevent 55 # W
adb shell input keyevent 48 # o
adb shell input keyevent 46 # r
adb shell input keyevent 37 # l
adb shell input keyevent 32 # d
adb shell input keyevent 56 # !

2.2 模拟按键

要在设备上模拟按键,可以使用以下命令:

adb shell input keyevent [--longpress|--doubletap] <keycode>

其中,--longpress--doubletap是可选的修饰符,分别表示长按和双击。<keycode>是要模拟的按键的代码,可以是数字或字符串。例如,要在设备上模拟返回键,可以使用以下命令:

adb shell input keyevent KEYCODE_BACK


或者

adb shell input keyevent 4

 

要查看所有可用的按键代码,请参考 KeyEvent 文档
(仅限于Google官方的镜像 如果自己系统源码中自定义keycode 查不到的 要看自己的系统代码)。

2.3 模拟点击

要在设备上模拟点击某个坐标点,可以使用以下命令:

adb shell input tap <x> <y>

其中,<x><y>是要点击的屏幕坐标。例如,要在设备上点击(100,200)这个点,可以使用以下命令:

adb shell input tap 100 200

2.4 模拟滑动

要在设备上模拟从一个坐标点滑动到另一个坐标点,可以使用以下命令:

adb shell input swipe <x1> <y1> <x2> <y2> [<duration>]

其中,<x1><y1>是滑动的起始坐标,<x2><y2>是滑动的结束坐标,<duration>是滑动的持续时间,单位是毫秒,可选参数。例如,要在设备上从(100,200)滑动到(300,400),并持续2秒,可以使用以下命令:

adb shell input swipe 100 200 300 400 2000

2.5 模拟长按

要在设备上模拟长按某个坐标点,可以使用以下命令:

adb shell input press <x> <y>

其中,<x><y>是要长按的屏幕坐标。例如,要在设备上长按(100,200)这个点,可以使用以下命令:

adb shell input press 100 200

2.6 模拟滚动

要在设备上模拟滚动屏幕,可以使用以下命令:

adb shell input roll <dx> <dy>

其中,<dx><dy>是水平和垂直方向的滚动距离。例如,要在设备上向右滚动50个像素,向下滚动100个像素,可以使用以下命令:

adb shell input roll 50 100

三、进阶用法

3.1 组合按键的用法

要在设备上模拟组合按键,例如Ctrl+C、Alt+Tab等,可以使用以下命令:

adb shell input keyevent --longpress <keycode1> <keycode2> [<keycode3> ...]

或者

adb shell input keycombination [-t duration(ms)] <keycode1> <keycode2> [<keycode3> ...]

其中,--longpress-t duration(ms)是可选的修饰符,分别表示长按和指定按键间隔时间。<keycode1>是要模拟的第一个按键的代码,<keycode2>是要模拟的第二个按键的代码,以此类推。注意,在使用keycombination命令时,按键顺序很重要。例如,要在设备上模拟Ctrl+C,可以使用以下命令:

adb shell input keyevent --longpress KEYCODE_CTRL_LEFT KEYCODE_C

或者

adb shell input keycombination -t 100 KEYCODE_CTRL_LEFT KEYCODE_C

要查看所有可用的按键代码,请参考 KeyEvent 文档。

3.2 长按power键

要在设备上模拟长按power键,可以使用以下命令:

adb shell input keyevent --longpress KEYCODE_POWER

或者

adb shell input keyevent --longpress 26

这样可以弹出关机菜单或者其他功能,根据不同设备的设置而定。

如果想要直接关机或者重启,可以使用以下命令:

adb shell reboot -p # 关机
adb shell reboot # 重启

3.3 输入中文

要在设备上输入中文,不能直接使用以下命令:

adb shell input text <string>

因为这个命令只支持ASCII字符集,不支持中文或其他非ASCII字符。如果强行输入中文,会导致乱码或者错误。

要输入中文,有两种方法:

  • 方法一:使用am broadcast命令发送一个广播,携带要输入的中文内容作为extra数据,然后在设备上安装一个接收该广播的应用,并在接收到广播后调用InputMethodManagershowSoftInput()方法来弹出软键盘,并使用InstrumentationsendStringSync()方法来输入中文。这种方法需要编写一个应用,并且需要root权限。
  • 方法二:使用adb push命令将要输入的中文内容保存到一个文件中,并推送到设备上的某个目录下,然后使用cat命令读取该文件的内容,并通过管道符|将其传递给input text命令。这种方法不需要编写应用,也不需要root权限。

例如,要在设备上输入"你好",可以使用以下命令:

echo "你好" > hello.txt # 在电脑上创建一个文件并写入你好(windows直接写进去就完事)
adb push hello.txt /sdcard/ # 将文件推送到设备上的sdcard目录下
adb shell cat /sdcard/hello.txt | tr -d '\n' | xargs -0 adb shell input text # 读取文件内容并传递给input text命令

3.4 代码模拟发送按键

1. 方法1:

使用Instrumentation类的sendKeySync()方法,这个方法会创建一个KeyEvent对象,并通过Instrumentation类的injectInputEvent()方法将其注入到系统中。这个方法需要具有INJECT_EVENTS权限,否则会抛出安全异常。这个方法适用于普通的按键事件,例如:

Instrumentation inst = new Instrumentation();
inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A));
inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A));
2. 方法2:

使用InputManager类的injectInputEvent()方法,这个方法会直接将一个KeyEvent对象注入到系统中,不经过Instrumentation类的处理。这个方法也需要具有INJECT_EVENTS权限,否则会抛出安全异常。这个方法适用于更复杂的按键事件,例如组合键、长按、双击等,需要自己创建多个KeyEvent对象,并设置相应的属性和时间间隔,并调用相应的方法进行注入。例如:

InputManager im = InputManager.getInstance();
// 模拟发送Ctrl+C组合键
final long now = SystemClock.uptimeMillis();
// 按下Ctrl
im.injectInputEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CTRL_LEFT,
        0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD),
        InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
// 按下C
im.injectInputEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_C,
        0, KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON,
        KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD),
        InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
// 抬起C
im.injectInputEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_C,
        0, KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON,
        KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD),
        InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
// 抬起Ctrl
im.injectInputEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_CTRL_LEFT,
        0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD),
        InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
3. 方法3:

随便搞个ShellUtils工具类 , 网上代码非常多 这种方法要系统root的。

ShellUtils.execCommand("input keyevent 224",true);

系统应用或具有系统签名的应用(app)以及app的UID和GID组对于能否模拟发送输入事件具有影响。通常,只有属于system或shell组的app才能将输入事件注入到系统中。可以使用Process类的myUid()和myGid()方法获取app的UID和GID,并使用Process类的getGidForName()方法获取system或shell组的GID。如果app的UID是0(即root用户)或者GID是system或shell组的GID,那么就可以进行输入事件的注入;否则不可以。

四、注意事项

在使用adb shell input命令时,有一些注意事项需要了解:

  • adb shell input命令只能模拟基本的输入事件,不能模拟复杂的手势或多点触控等操作。
  • adb shell input命令只能模拟用户在设备上的操作,不能模拟设备的物理状态,例如旋转、摇晃、倾斜等。
  • adb shell input命令只能模拟用户在当前屏幕上的操作,不能模拟用户在其他应用或界面上的操作。
  • adb shell input命令只能模拟用户在设备上的操作,不能模拟用户在外接设备上的操作,例如键盘、鼠标、手柄等。
  • adb shell input命令只能模拟用户在设备上的操作,不能模拟用户对设备的语音或人脸等输入。

如果需要模拟更高级或更复杂的输入事件,可以考虑使用其他工具或方法,例如:

  • 使用uiautomatormonkeyrunner等自动化测试框架来编写和执行测试脚本。
  • 使用“Android投屏工具”ARDC等工具来远程控制设备,并在电脑上进行操作。

五、源码解析

adb shell input命令在Android 13中已经不再是一个单独的可执行文件,而是作为一个ShellCommand的子类,被集成到了InputManagerService中。这样做的好处是可以减少进程间通信的开销,提高输入事件的处理效率。源码改到了frameworks/base/services/core/java/com/android/server/input/InputShellCommand.java中,在这个文件中定义了一个InputShellCommand类,继承了ShellCommand类,并实现了各种事件类型的处理方法。例如:

  • onCommand(String cmd):这个函数是ShellCommand类的抽象方法,用于根据输入的命令和参数来执行相应的操作。这个函数首先解析输入源和显示ID(如果有的话),然后根据命令的类型,调用不同的runXXX方法来执行具体的操作。
  • onHelp():这个函数是ShellCommand类的抽象方法,用于打印帮助信息。这个函数向输出流输出adb shell input命令的用法和参数说明。
    --------只关注重点函数 下面的
  • runXXX(int inputSource, int displayId):这些函数用于执行不同类型的命令,例如text、keyevent、tap、swipe等。它们会获取相应的参数,并调用sendXXX方法发送相应的输入事件。
  • sendXXX(int inputSource, ...):这些函数用于发送不同类型的输入事件,例如文本、按键、点击、滑动等。它们会根据参数创建KeyEvent或MotionEvent对象,并设置其属性,并调用injectKeyEvent或injectMotionEvent方法将其注入到系统中。
  • injectKeyEvent(KeyEvent event):这个函数用于同步注入一个键盘事件到系统中,它会使用InputManager类的getInstance()和injectInputEvent()方法来实现。
  • injectKeyEventAsync(KeyEvent event):这个函数用于异步注入一个键盘事件到系统中,它也会使用InputManager类的getInstance()和injectInputEvent()方法来实现,但是使用了INJECT_INPUT_EVENT_MODE_ASYNC模式,以便让系统的拦截器能够处理该事件。
  • injectMotionEvent(int inputSource, int action, long downTime, long when,
    float x, float y, float pressure, int displayId):这个函数用于注入一个动作事件到系统中,它会使用MotionEvent类的obtain()方法来创建一个MotionEvent对象,并设置其输入设备ID、输入源和显示ID等属性,并使用InputManager类的getInstance()和injectInputEvent()方法来实现。

所有的事件处理方法最终都会调用InputManagerService的内部方法来将输入事件注入到系统中。InputManagerService的源码位于frameworks/base/services/core/java/com/android/server/input/InputManagerService.java中,在这个文件中定义了一个InputManagerService类,实现了各种输入事件的管理和分发逻辑。(太复杂了 有空 再分析这块内容)

通过以上源码分析,可以了解到Android 13系统是如何接收、分发和处理adb shell input命令模拟的输入事件的。这些源码也可以帮助大家更好地理解adb shell input命令的原理和限制。

六、总结

本章重点Android adb input 调试命令的使用和源码分析。可以利用这些命令来模拟用户在设备上的各种操作,从而进行测试、调试或其他目的。同时,也可以通过阅读源码来深入了解Android 13系统的输入事件管理机制。希望这篇文章对大家有所帮助,如果还有其他问题,请随时向我提问 如果有错误请指正哈 !。

Guess you like

Origin blog.csdn.net/SHH_1064994894/article/details/131725982