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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: Android13 adb input 调试命令使用和源码解析

好了 本篇作为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系统的输入事件管理机制。希望这篇文章对大家有所帮助,如果还有其他问题,请随时向我提问 如果有错误请指正哈 !。

相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
17天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
21天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
50 12
|
1月前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
1月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
53 3
|
2月前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
63 5
|
2月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
147 5
|
7月前
|
Shell Android开发
Android系统 adb shell push/pull 禁止特定文件
Android系统 adb shell push/pull 禁止特定文件
603 1
|
7月前
|
Android开发 Python
Python封装ADB获取Android设备wifi地址的方法
Python封装ADB获取Android设备wifi地址的方法
166 0
|
开发工具 Android开发
Mac 安卓(Android) 配置adb路径
Mac 安卓(Android) 配置adb路径
875 0

推荐镜像

更多
下一篇
DataWorks