CnOps 智能运维与可观测社区
首页开源项目实践文章视频课程常见问答开发者工具STAROps 专题
导航菜单
首页开源项目实践文章视频课程常见问答开发者工具STAROps 专题

CnOps 智能运维与可观测社区

愿景

CnOps 智能运维与可观测社区是一个以"智能运维与可观测"为核心的开放、包容、分享的技术社区,旨在聚集运维专家、开发者和爱好者,共同探讨、学习和分享可观测最佳实践与最新技术,与众多技术社区合作互动,共同探讨交叉领域的技术挑战,推动可观测领域的创新与进步。

内容社区

  • 实践文章
  • 视频课程
  • 开源项目
  • 常见问答
  • 开发者工具

友情链接

  • Prometheus
  • Grafana Lab
  • OpenTelemetry
  • LoongCollector

关注我们

阿里云云原生公众号阿里云云原生
阿里云可观测公众号阿里云可观测

Copyright © 2026 CnOps 社区. All rights reserved.

首页实践文章当 AI Agent 接管手机:移动端如何进行观测

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

#移动端如何进行观测#监控#api#自动化#网络#Agent

agenticOps | 2026-05-23

背景介绍

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

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

  • 转换率虚高:AI 自动下单会对转换率数据造成干扰,导致业务决策误判
  • 用户路径分析失效:AI 操作的路径高度优化且重复,会污染用户行为路径的分析
  • 推荐算法偏差:基于 AI 操作数据训练的推荐模型,会偏离真实用户偏好

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

技术拆解

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

flowchart TB
subgraph Layer1["用户入口层"]
A[用户语音/文字指令]
end

subgraph Layer2["屏幕捕获层"]
A --> B[获取屏幕信息]
style B fill:#ffcccc
end

subgraph Layer3["云端通信层"]
B -->|上传屏幕信息| C[云端推理服务器]
C -->|返回指令| D[手机操作指令]
style C fill:#99ccff
style D fill:#cce5ff
end

subgraph Layer4["操作执行层"]
D --> E[执行操作指令]
end

style Layer1 fill:#f9f9f9,stroke:#333,stroke-width:2px
style Layer2 fill:#fff5f5,stroke:#ff6666,stroke-width:2px
style Layer3 fill:#f5f9ff,stroke:#6699ff,stroke-width:2px
style Layer4 fill:#f5fff5,stroke:#66ff66,stroke-width:2px

主要分为以下几个层次:

  • 用户入口层:用户通过文字/语音等方式下达操作指令
  • 屏幕捕获层:获取原始屏幕信息
  • 云端通信层:云端推理服务器
  • 操作执行层:点击、滑动、长按、输入等

从移动端监控角度去识别“非人”操作,需要重点关注“操作执行层”。以 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 # 点击坐标(500, 1000)
adb shell input swipe 100 200 300 400 # 从(100, 200)滑动到(300, 400)
adb 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 一致

如何检测“非人”操作

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

识别 AccessibilityService 输入事件

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

  • 支持检测是否存在正在运行的无障碍服务
  • 支持读取无障碍服务的Id
  • 支持检测屏幕内容是否被读取
  • 支持检测是否具备操作应用的能力
// 检测是否存在正在运行的无障碍服务
public boolean hasAccessibilityServiceRunning() {
AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
return am != null && am.isEnabled();
}

// 检测无障碍服务的Id
public 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_ENABLED, 0
) > 0;
}

检测 USB 连接状态:

private static boolean isUsbConnected(Context context) {
Intent intent = context.registerReceiver(
null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED)
);

if (intent == null) return 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 = {5555, 5554, 5556, 5557, 5558, 5559, 5560};

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_count
GROUP BY 
"user.name", "context.accessibility_service_id"
ORDER BY 
operation_count DESC
LIMIT 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_devices
FROM log
GROUP 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_count
FROM log
GROUP BY "user.name", "device.id", adb_status
ORDER BY event_count DESC
LIMIT 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"), 2) as inject_ratio
FROM log
GROUP BY "user.name", "device.id"
HAVING injected_event_count > 50
ORDER BY inject_ratio DESC
LIMIT 100

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

结语

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

文章大纲

推荐文章

超过 2000+ 位开发者正在阅读

给 OpenClaw 加上企业级 Memory

给 OpenClaw 加上企业级 Memory

4646 阅读

阿里云 STAROps 全域智能运维平台发布!

阿里云 STAROps 全域智能运维平台发布!

3453 阅读

阿里云正式发布 RCA Benchmark

阿里云正式发布 RCA Benchmark

2716 阅读

推荐视频

UModel 最佳实践 Vol.1 UModel 数据建模全景解读

UModel 最佳实践 Vol.1 UModel 数据建模全景解读

3854 观看50:35
云监控2.0全景:可观测范式升级与智能运维蓝图

云监控2.0全景:可观测范式升级与智能运维蓝图

2532 观看41:06

推荐工具

精选可观测领域开发者工具

云监

云监控 2.0 沙箱体验

7483 使用

免费

免费网络拨测工具

2746 使用