免费POC, 零成本试错
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


我要投稿

当 AI Agent 接管手机:移动端如何进行观测

发布日期:2026-02-11 18:59:44 浏览次数: 1511
作者:阿里云云原生

微信搜一搜,关注“阿里云云原生”

推荐语

AI Agent接管手机操作带来便利的同时,也带来了数据污染的挑战,本文深入解析如何识别非人操作的技术路径。

核心内容:
1. AI Agent操作手机对数据分析的三大影响
2. Android平台识别非人操作的三种技术路径
3. AccessibilityService服务实现自动化的三个阶段

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家
图片

背景介绍




Cloud Native

最近,基于 AI Agent 的各种手机助手在社交媒体上爆火,它能够通过 AI 自动操作手机完成下单、比价、搜索等复杂任务。用户只需说一句“帮我找最便宜的 iPhone”,AI 就能自动打开购物 App、搜索商品、对比价格并完成下单。这种“AI 接管手机”的场景,让很多人看到了未来人机交互的新形态。

然而,当 AI 开始大规模操作手机时,传统的用户行为分析将会面临严重的数据污染问题,如:

  • 转换率虚高:AI 自动下单会对转换率数据造成干扰,导致业务决策误判

  • 用户路径分析失效:AI 操作的路径高度优化且重复,会污染用户行为路径的分析

  • 推荐算法偏差:基于 AI 操作数据训练的推荐模型,会偏离真实用户偏好

如何识别“非人”操作?我们先拆解下 AI 或脚本是如何操作手机的。

技术拆解




Cloud Native

我们先看下 AI Agent 操作手机的原理。

主要分为以下几个层次:

  • 用户入口层:用户通过文字/语音等方式下达操作指令

  • 屏幕捕获层:获取原始屏幕信息

  • 云端通信层:云端推理服务器

  • 操作执行层:点击、滑动、长按、输入等

从移动端监控角度去识别“非人”操作,需要重点关注“操作执行层”。以 Android 平台为例,在“操作执行层”常见的有三种技术路径可以实现“非人”操作:

  • 通过 AccessibilityService(无障碍服务)输入事件

  • 通过 INJECT_EVENTS 注入事件

  • 通过 adb shell input 注入事件

除此之外,定制 ROM、外接硬件等也可以实现“非人”操作,这部分暂时不在本文的讨论范围。

通过 AccessibilityService 输入事件

AccessibilityService 是 Android 提供的无障碍服务框架,原本用于辅助残障人士使用手机,但也可以用于自动化操作。是各种辅助功能应用、游戏辅助工具实现自动化操作的主要技术路径。

AccessibilityService 的工作机制可以分为三个阶段:

  • 阶段一:事件监听

  • 阶段二:屏幕读取

  • 阶段三:自动化操作

阶段一:事件监听

当应用界面发生变化时(如新页面打开、按钮状态改变),系统会通过 AccessibilityEvent 通知已注册的无障碍服务。服务可以监听多种事件类型,包括窗口状态变化、内容变化、视图滚动等。

阶段二:屏幕读取

无障碍服务可以获取当前活动窗口的视图层次结构(View Hierarchy),通过 AccessibilityNodeInfo 对象访问屏幕上的所有 UI 元素,包括:

  • 文本内容(按钮文字、输入框内容等)

  • 视图属性(位置、大小、可点击性等)

  • 视图层次关系(父子节点、兄弟节点等)

  • 这使得 AI Agent 能够“看到”屏幕上的内容,理解当前界面状态

阶段三:自动化操作

基于读取的屏幕内容,无障碍服务可以执行两种类型的操作:

  • 节点操作:直接对 UI 节点执行操作(点击、长按、输入文本等)

  • 手势操作:通过 GestureDescription API 执行复杂的触摸手势(滑动、拖拽、多点触控等)

通过无障碍服务输入事件,有以下特点:

  • 需要用户授权:用户需要在系统设置中手动开启无障碍服务

  • 屏幕内容读取:可以完整读取屏幕上的文本、视图层次结构等信息

  • 操作能力灵活:支持点击、滑动、长按、输入文本等复杂操作

通过 INJECT_EVENTS 注入事件

INJECT_EVENTS 是 Android 系统级权限,允许应用直接向输入系统注入触摸事件,模拟用户操作。这个是 Android 系统层面提供的底层事件注入机制。

INJECT_EVENTS 的工作机制也可以分为三个阶段:

  • 阶段一:事件构造

  • 阶段二:权限验证

  • 阶段三:系统注入

阶段一:事件构造

应用通过 Instrumentation 或反射调用系统 API,构造 MotionEvent 对象。这个对象包含了触摸的坐标、动作类型(ACTION_DOWN、ACTION_UP 等)等基本信息。

阶段二:权限验证

Android 系统会检查调用者是否具有 INJECT_EVENTS 权限。这个权限是系统级权限,普通应用无法获取,只有以下情况下才能使用:

  • 系统应用(具有系统签名)

  • Root 权限的应用

阶段三:系统注入

通过权限验证后,事件会被直接注入到 Android 的输入子系统(Input System)。输入子系统负责处理所有输入事件(触摸、按键等),注入的事件会被当作真实的硬件输入事件处理,分发给当前焦点窗口。

通过 INJECT_EVENTS 注入事件有以下特点:

  • 底层注入:事件直接注入到系统,发生在更底层

  • 无需用户授权:不需要用户手动授权(但需要系统签名或 root 权限)

  • 更难检测:注入发生在系统底层,更难被应用层检测

通过 adb shell input 注入事件

adb shell input 是 Android Debug Bridge(ADB)提供的命令行工具,用于通过 USB 连接或网络连接向设备注入输入事件。这是开发调试和自动化测试中常用的方式。与 INJECT_EVENTS 在本质上是一样的,在调用主体和权限获取方面存在差异。

通过 adb shell input 注入事件的工作机制主要分为四个阶段:

  • 阶段一:命令发送

  • 阶段二:ADB 协议传输

  • 阶段三:守护进程处理

  • 阶段四:系统注入

阶段一:命令发送

在 pc 端或远程设备上(如 USB 设备等),可以通过 ADB 客户端发送 input 命令,如下:

adb shell input tap 500 1000                 # 点击坐标(5001000adb shell input swipe 100 200 300 400        # 从(100200)滑动到(300400adb shell input text "hello"                 # 输入文本 "hello"

阶段二:ADB 协议传输

ADB 客户端通过 USB 或 TCP/IP 网络,将命令发送到 Android 设备端的 ADB 守护进程(adbd)。ADB 协议负责命令的序列化、传输和反序列化。

阶段三:守护进程处理

设备端的 adbd 守护进程接收到命令后,解析命令参数,构造相应的 MotionEvent 或 KeyEvent 对象。adbd 进程以系统权限(通常是 shell 或 root)运行,具有系统级权限。

阶段四:系统注入

adbd 调用系统 API(InputManager.injectInputEvent()),将事件注入到输入子系统。这个过程与应用内 INJECT_EVENTS 的最终注入路径相同。

与 INJECT_EVENTS 对比,adb shell input 方式注入事件有以下特点:

  • 需要经过 ADB 协议传输

  • 权限获取方式:只要建立了 ADB 连接就能获取到权限,不需要修改应用

  • 事件注入的底层实现与 INJECT_EVENTS 一致

如何检测“非人”操作




Cloud Native

不少外挂和脚本,包含可以操作手机的 AI Agent 等都在使用上述方案。但特殊人群(如视障用户)也在使用无障碍服务。简单的通过特征值对事件进行分析,可能会造成误判。下文将主要探讨当操作事件发生时,如何通过采集事件的特征以及外部环境的特征,辅助分析“非人”操作事件。

识别 AccessibilityService 输入事件

通过 AccessibilityService 操作手机,需要先在手机系统设置中开启对应的障碍服务。Android 系统提供了可以判断是否有无障碍服务在运行的相关 API,如下:

  • 支持检测是否存在正在运行的无障碍服务

  • 支持读取无障碍服务的 ID

  • 支持检测屏幕内容是否被读取

  • 支持检测是否具备操作应用的能力

// 检测是否存在正在运行的无障碍服务public boolean hasAccessibilityServiceRunning() {      AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);      return am != null && am.isEnabled();}// 检测无障碍服务的Idpublic void checkServiceId() {    List<AccessibilityServiceInfo> enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);    for (AccessibilityServiceInfo service : enabledServices) {        // 获取服务 ID (通常是 "包名/类名")        String id = service.getId();    }}// 检测是否具备操作应用的能力public boolean hasFullControlAgent() {    List<AccessibilityServiceInfo> enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);    for (AccessibilityServiceInfo service : enabledServices) {        int capabilities = service.getCapabilities();        // 1. 检查是否有可以读取屏幕        boolean canRetrieve = (capabilities & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;        // 2. 检查是否可以操作应用        boolean canPerform = (capabilities & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0;        // 具备操作应用的能力        if (canRetrieve && canPerform) {            return true;        }    }    return false;}

除此之外,还可以通过检查 MotionEvent 的 flags 来判断事件是否通过无障碍服务产生:

// 检测事件是否由无障碍服务产生(有API版本要求)public boolean isAccessibilityEvent(MotionEvent event) {    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {        int flags = event.getFlags();        // 使用位运算检查是否包含 0x800        return (flags & FLAG_IS_ACCESSIBILITY_EVENT) != 0;    }    return false;}

通过以上方式,应用虽然可以检测到当前是否存在正在运行的无障碍服务,但也可能对正常的无障碍服务造成误伤。

识别 INJECT_EVENTS 注入事件

INJECT_EVENTS 注入的事件一般有以下特征:

  • 事件属性可能缺少压力值、触摸面积等属性

  • 标志位可能是 FLAG_IS_GENERATED_GESTURE

  • 事件来源可能是 SOURCE_UNKNOWN

检测逻辑如下:

public boolean isEventInjected(MotionEvent event) {    if (event == null) {        return false;    }    // 方法1:检查事件属性    // 注入的事件可能缺少压力值、触摸面积等属性    boolean hasPressure = event.getPressure() > 0;    boolean hasSize = event.getSize() > 0;    boolean hasToolType = event.getToolType(0) != MotionEvent.TOOL_TYPE_UNKNOWN;    // 如果事件缺少这些基本属性,可能是注入的(可能会误判)    if (!hasPressure && !hasSize && !hasToolType) {        return true;    }    // 方法2:检查事件标志位    int flags = event.getFlags();    // FLAG_IS_GENERATED_GESTURE 表示是程序生成的手势    if ((flags & 0x08000000) != 0) {        return true;    }    // 方法3:检查事件来源    int source = event.getSource();    if (source == InputDevice.SOURCE_UNKNOWN) {        return true;    }    return false;}

通过 INJECT_EVENTS 注入的事件,目前并没有非常可靠的单一方法,因为注入的事件发生在更底层,可以绕过应用层的检测机制。对于这类事件的注入,往往需要多维度综合检测的方式进行识别(也适用其他类型的注入事件检测)。即便如此,也可以尝试对事件特征进行检测,用于提升识别“非人”操作的成功率。

识别 adb shell input 注入事件

通过 adb shell input 注入的事件,本质上与通过 INJECT_EVENTS 注入的事件是一样的。但由于需要连接 ADB,相对 INJECT_EVENTS 的注入,可以通过检测 ADB 连接状态等进行识别。

检测 ADB 是否开启:

public static boolean isAdbEnabled(Context context) {    return Settings.Global.getInt(        context.getContentResolver(),        Settings.Global.ADB_ENABLED0    ) > 0;}

检测 USB 连接状态:

private static boolean isUsbConnected(Context context) {    Intent intent = context.registerReceiver(        null,        new IntentFilter(Intent.ACTION_BATTERY_CHANGED)    );    if (intent == nullreturn false;    int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);    // 判断是否通过 USB 供电    return plugged == BatteryManager.BATTERY_PLUGGED_USB;}

检测 ADB 端口是否打开:(无线调试和模拟器场景)

  private static boolean isAdbPortOpen() {      // 常见的 ADB 端口,5555 是默认,部分模拟器可能是 5554-5585      int[] ports = {5555555455565557555855595560};      for (int port : ports) {          try (Socket socket = new Socket()) {              socket.connect(new InetSocketAddress("127.0.0.1", port), 50);              Log.w(TAG, "isAdbPortOpen, opened. port: " + port);          } catch (Exception e) {              // ignored              e.printStackTrace();              Log.w(TAG, "isAdbPortOpen, closed. port: " + port);          }      }      return false;  }

检测调试器状态:

public static boolean isDebuggerAttached() {    return android.os.Debug.isDebuggerConnected();}

检测 USB ADB 状态:

private static boolean isUsbAdbActive() {    try {        Class<?> systemPropertiesClass = Class.forName("android.os.SystemProperties");        Method getMethod = systemPropertiesClass.getMethod("get"String.class);        String usbState = (String) getMethod.invoke(null"sys.usb.state");        // 判断是否包含 adb        // 常见的返回值:        // "mtp,adb" -> 开启了 MTP 传输且 ADB 已连接        // "adb"     -> 仅充电模式且 ADB 已连接        // "mtp"     -> 仅 MTP,未开启 ADB        if (usbState != null && usbState.contains("adb")) {            return true;        }        // 双重校验:有些厂商可能用 persist.sys.usb.config        String usbConfig = (String) getMethod.invoke(null"persist.sys.usb.config");        if (usbConfig != null && usbConfig.contains("adb")) {            return true;        }    } catch (Exception e) {        // 反射失败或权限不足(部分高版本 Android 可能限制读取)        e.printStackTrace();    }    return false;}

通过以上方式,可以采集到操作时的 ADB 相关环境信息。在分析操作事件发生时,结合 ADB 相关的状态信息,可以协助判断当前应用“非人”操作的可能性。

通过 RUM + 自定义 Query 识别异常操作

以上三种方式检测的结果字段将会通过 RUM SDK 上报到用户体验监控产品,通过对结果字段的查询分析可以快速识别可疑的非人操作。以下是几个分析场景。

场景一:识别开启无障碍服务的用户

通过分析无障碍服务的开启状态和服务 ID,快速定位可能存在非人操作的用户。

-- 查询最近1小时内开启无障碍服务的用户及其操作次数* and context.accessibility_enabled: true | SELECT   "user.name",  "context.accessibility_service_id",  COUNT(*as operation_count,  COUNT(DISTINCT "session.id") as session_countGROUP BY   "user.name", "context.accessibility_service_id"ORDER BY   operation_count DESCLIMIT 100

分析说明:如果某个用户的操作次数异常高,且开启了非系统的无障碍服务,需要重点关注。

场景二:识别具备全控能力的无障碍服务

重点分析具备读取屏幕和操作应用双重能力的无障碍服务。

-- 查询具备全控能力的无障碍服务及影响的用户数* and context.can_retrieve_window: true and context.can_perform_gestures: true | SELECT  "context.accessibility_service_id", COUNT(DISTINCT "user.name") as affected_users, COUNT(DISTINCT "device.id") as affected_devicesFROM logGROUP BY "context.accessibility_service_id"ORDER BY affected_users DESC

分析说明:同时具备屏幕读取和手势操作能力的服务,更有可能被用于自动化操作。

场景三:识别 ADB 连接环境下的操作

分析在 ADB 连接状态下的用户操作,可能存在脚本或自动化工具。

-- 查询 ADB 开启状态下的用户操作特征* and context.adb_enabled: true or context.usb_adb_active:true or context.adb_port_open: true | SELECT  "user.name", "device.id", CASE  WHEN "context.adb_enabled" = true THEN 'ADB已开启' WHEN "context.usb_adb_active" = true THEN 'USB-ADB已连接' WHEN "context.adb_port_open" = true THEN 'ADB端口已打开' END as adb_status, COUNT(*as event_countFROM logGROUP BY "user.name", "device.id", adb_statusORDER BY event_count DESCLIMIT 100

分析说明:ADB 连接状态下的操作,可能是自动化脚本。

场景四:识别注入事件特征

通过事件标志位和属性缺失情况,识别可能通过 INJECT_EVENTS 注入的事件。

-- 查询具有注入特征的事件* and event_type: "action" and ( context.is_generated_gesture: true or context.event_source = 'SOURCE_UNKNOWN' or (context.has_pressure: false and context.has_size: false and context.has_tool_type: false)| SELECT  "user.name", "device.id", COUNT(*as injected_event_count, COUNT(DISTINCT session_id) as session_count, ROUND(COUNT(** 100.0 / SUM(COUNT(*)) OVER (PARTITION BY "user.name"), 2as inject_ratioFROM logGROUP BY "user.name", "device.id"HAVING injected_event_count > 50ORDER BY inject_ratio DESCLIMIT 100

分析说明:如果某个用户的注入事件占比过高(如超过 50%),很可能存在非人操作。

结语




Cloud Native

以上内容对 AI Agent 或脚本操作手机的技术原理进行了分析,同时也介绍了三种技术路径下如何提取事件的特征信息。AutoGLM、豆包手机等 AI Agent 的兴起,标志着移动端交互即将进入新的阶段。AI 能够自动完成复杂的交互操作,这既是技术的进步,也为如何识别“非人”操作带来新的挑战。移动端监控要做到准确的“非人”识别,需要通过多个维度进行检测和识别。包括但不限于:应用运行环境检测能力的增强,无障碍服务包名特征的检测,设备特征的检测,行为特征的检测,屏幕轨迹特征的检测等。当前,阿里云可观测用户体验监控 SDK 已经采集相关属性,基于这些属性可以自定义分析当前是否可能存在非人操作(功能灰度中,可以加入钉钉交流群联系笔者,群号:67370002064)。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询