Developer Device Platform (DDP) 实战指南:远程 Android 设备租用、ADB 隧道与会话全生命周期管理
2026/9/13 5:11:09 网站建设 项目流程

Developer Device Platform (DDP) 实战指南:远程 Android 设备租用、ADB 隧道与会话全生命周期管理

【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills

本文基于当前仓库中 developer-device-platform-basics 技能 编写,系统讲解 Developer Device Platform(DDP)的认证配置、设备查询、会话租用、ADB 端口转发与会话过期时间管理等完整链路。读完后,你可以独立完成:通过gcloud与 REST API 租用一台远程 Android 设备、建立本地 ADB 隧道连接该设备,并对会话状态、过期时间与资源释放进行全生命周期管理。

DDP 是什么,以及本技能的定位

Developer Device Platform(DDP)是 Google 全托管的全球性基础设施,提供对多种物理和虚拟设备的访问能力。需要特别注意两点边界:

  • DDP 目前处于Preview(预览)阶段,行为与接口可能随版本演进;
  • 本技能仅覆盖Android 远程设备场景:租用远程设备、建立连接隧道、查询会话状态、延长/取消租约。不适用于 iOS 设备或本地设备/硬件问题

技能元数据(见 SKILL.md 头部 frontmatter)将其归类为CloudInfrastructureAndServices,并明确要求:所有 devicerun 与 devicestreaming API 操作(租用、状态查询、停止/取消、更新、列出会话)都必须使用各 reference 文档中给出的精确 curl 命令。仓库内每个操作都有对应的参考文件:

操作参考文件
查询设备详情describe_device.md
租用设备reserve_device.md
查询会话状态session_status.md
启动 ADB 转发器start_adb_forwarder.md
取消会话cancel_session.md
更新会话过期时间update_session_expiration.md
列出活跃会话list_sessions.md
查看设备屏幕view_device.md

环境准备与认证配置

在发送任何 API 请求前,必须先正确初始化环境。SKILL.md 将其列为 CRITICAL 步骤,完整流程如下。

首先确认gcloud可执行文件是否存在;若缺失,需先按官方 Google Cloud CLI 安装指南安装。然后执行:

1. 配置 Google Cloud 认证与应用默认凭证(ADC)

gcloud auth login --no-browser gcloud auth application-default login --no-browser

2. 启用所需 API(若尚未启用):

gcloud services enable devicerun.googleapis.com devicestreaming.googleapis.com testing.googleapis.com --quiet

注意:Preview 阶段下,Device Streaming API 依赖 Cloud Testing API,因此必须一并启用testing.googleapis.com

3. 安装 gcloud beta 组件device-run命令位于 beta 命名空间):

gcloud components install beta

4. 设置环境变量(后续所有 curl 命令都依赖这两个变量):

export PROJECT_ID=$(gcloud config get project) export ACCESS_TOKEN=$(gcloud auth application-default print-access-token 2>/dev/null)

5. Python 虚拟环境:ADB 转发器脚本的 Python 环境准备见下文启动 ADB 转发器 一节。

查询可用设备与设备详情

开始会话前,需要确定两个关键参数:modelCode(设备型号)与osVersion(系统版本)。

1. 列出可用机型

gcloud beta device-run devices list

输出中的ID列即为CATALOG_ID参数取值(例如shiba-36),后续用它来描述特定设备。

2. 查询设备详情(获取supportedProducts、分辨率、可用性等):

curl \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ "https://devicerun.googleapis.com/v1alpha/projects/${PROJECT_ID}/locations/global/devices/${CATALOG_ID}"

该请求来自 describe_device.md,要点是:host 为devicerun.googleapis.com,版本路径为v1alpha,设备资源位于projects/{PROJECT_ID}/locations/global/devices/{CATALOG_ID}

租用设备会话:完整流程

当需要租用(reserve)或连接一台设备时,SKILL.md 定义了一个严格的 8 步流程,其中包含两条强制性的业务规则。

检查设备可用性

先用上一节的查询方式获得CATALOG_ID,再按 describe_device.md 的 curl 命令检查其可用性。关键判定条件:

  • 设备的supportedProducts必须包含deviceStreaming才可被租用;
  • 若用户未指定具体设备,使用默认值CATALOG_ID=shiba-34(即 SDK 34 上的 Pixel 8);
  • 若用户未指定OS_VERSION,应让用户从设备列表中选择版本,优先选择可用性最高的版本"available": "AVAILABILITY_HIGH");
  • 若某个OS_VERSION不支持deviceStreaming,不要租用,应提示用户改用其他版本。

提取参数并租用设备

从设备详情中提取:

  • model_id:设备详情中的modelCode(必填);
  • version_id:设备详情中的osVersion(必填)。

规则(必须遵守):显式用户确认。租用设备会产生计费并创建云资源。操作前必须向用户明确警告当前 Google Cloud 项目(如${PROJECT_ID})将产生的费用,并停下来等待用户明确批准后才能执行租用命令。

批准通过后,发送租用请求(命令来自 reserve_device.md):

curl -s -X POST \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "androidDevice": { "androidModelId": "{model_id}", "androidVersionId": "{version_id}" } }' \ "https://devicestreaming.googleapis.com/v1/projects/${PROJECT_ID}/deviceSessions"

注意此处 host 与查询设备时不同:租用走的是devicestreaming.googleapis.com且路径为v1(无locations/global段)。从响应中解析出session_name(格式如projects/${PROJECT_ID}/deviceSessions/session-xxxxxx);若租用失败则向用户报告错误。

轮询等待会话变为 ACTIVE

会话创建后处于异步供给(provisioning)状态,需要轮询其状态直至"state""ACTIVE"(curl 命令见 session_status.md):

curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" \ "https://devicestreaming.googleapis.com/v1/{session_name}"

轮询纪律有明确数值约束:

  • 每 5 秒轮询一次,避免触发 API 限流;
  • 若 2 分钟内未变为 ACTIVE(正常通常 1 分钟内完成),报告失败并取消该会话;
  • 变为 ACTIVE 后,从会话 JSON 中提取expireTime,并转换为用户本地时区的可读格式(例如 "June 9, 2026 at 2:44 PM PDT")展示。

启动 ADB 转发器:把本地 adb 接到远程设备

会话 ACTIVE 之后,需要启动 ADB 转发器脚本,把本地 ADB 流量转发到远程设备。该脚本随仓库提供:scripts/demo_adb_forwarder.py,依赖清单为 scripts/requirements.txt。

Python 环境准备

按 start_adb_forwarder.md 的说明,当前工作目录必须是脚本所在目录(因为后续命令使用相对路径),然后:

python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt

每次执行转发器脚本前都必须先激活该虚拟环境。requirements.txt 声明的三个依赖及其版本下限为:google-cloud-devicestreaming>=0.5.0google-auth>=2.50.0absl-py>=2.0.0

运行转发器并解析端口

先计算会话剩余寿命(expireTime与当前时间之差,单位秒),使转发器的存活期与会话对齐,然后在本地虚拟环境中以后台方式运行:

python3 demo_adb_forwarder.py --device_session {session_name} --ttl {remaining_seconds}

务必记录返回的Command ID(后台进程 ID),后续停止会话时需要用它终止进程。

脚本的参数定义(见 demo_adb_forwarder.py):

参数必填默认值说明
--device_session会话完整资源名,格式必须为projects/<project>/deviceSessions/<session-id>
--access_token无(回退 ADC)OAuth2 access token
--ttl900 秒转发器存活时长(秒),必须为正整数

然后监控后台输出,等待日志行ADB forwarding listening on localhost:{port}出现并提取{port};若 2 分钟内未出现(正常通常 1 分钟内),应终止转发器后台进程、取消会话并报告失败。

源码剖析:转发器如何工作

从源码看(demo_adb_forwarder.py),该脚本本质上是一个本地 TCP 服务与 gRPC 双向流之间的 ADB 协议桥,理解它能帮助你在排障时定位问题:

  1. ADB 协议编解码。脚本头部定义了 ADB 协议四种命令魔数:CNXNOPENOKAYCLSEWRTE(L24-L29)。每个 ADB 包是 24 字节小端头(<6I:cmd, arg0, arg1, 载荷长度, 保留位, magic)加可选载荷,其中magic = cmd ^ 0xFFFFFFFF(send_packet),客户端回传方向则按struct.unpack("<6I", header)反向解析(L182-L184)。

  2. 本地监听端口AdbForwarder.start()通过asyncio.start_server(..., "127.0.0.1", 0)在回环地址上绑定随机空闲端口0表示由系统分配),随后从 socket 取出实际端口号(L100-L105)——这就是日志中localhost:{port}端口的来源。

  3. gRPC 双向流。转发器调用DirectAccessServiceAsyncClient.adb_connect()建立到devicestreaming.googleapis.com的双向流,并携带两个 gRPC metadata:x-omnilab-session-name(完整会话资源名)与x-goog-user-project(项目 ID)(L121-L139)。首条消息以stream_id=1000打开shell:echo 'Establishing a connection'服务,用于先行探测链路。

  4. 请求/响应双向桥接。本地 ADB 客户端发来的OPEN请求被转换为AdbMessage.open_投入requests_queue(容量 128)经 gRPC 上送;设备侧返回的stream_status/stream_data再按对应stream_id映射回本地 writer,转成OKAY/WRTE/CLSE包回传(client_connected 与 receive_grpc_messages)。值得注意的是,reverse:开头的反向端口转发请求会被显式拒绝并回发 FAIL 包(reject_reverse)——即转发链路只支持客户端到设备方向,不支持设备反向端口映射。

  5. TTL 自毁与清理main()中 gRPC 超时设为TTL + 10秒缓冲(_TIMEOUT_BUFFER_SECONDS = 10),asyncio.wait_for在 TTL 到期后触发stop()(L340-L363)。stop()会依次执行adb disconnect localhost:{port}、关闭监听 server、关闭 gRPC 传输(L292-L315),保证到期后不残留连接。

  6. 自动接入。转发器启动成功后还会自动执行adb connect localhost:{port}(L149-L157),使设备直接进入本地adb devices列表。

会话就绪后的交付信息

端口就绪后,先运行以下命令获取设备型号:

adb -s localhost:{port} shell getprop ro.product.model

然后直接向用户输出一条就绪信息(SKILL.md 明确要求在聊天中打印,不要创建任何 artifact 文件),格式为:

Device Model: {device_model} OS Version: {version_id} ADB Address: localhost:{port} Session Expiration: {expire_time_human_readable_local}

最后一步同样关键:把{session_name}{command_id}保存到会话上下文中,供后续清理使用。

查看远程设备屏幕(可选)

编码代理可以直接用adb操作远程设备;若用户希望可视化查看屏幕并手动操控,view_device.md 推荐开源工具 scrcpy(安装前必须先征得用户同意),用法示例:

scrcpy -s localhost:{port} --force-adb-forward

修改会话过期时间

当用户要求延长活跃会话时,同样适用"显式用户确认"规则:延长会话会产生额外费用,必须先警告${PROJECT_ID}项目将新增计费并等待批准。随后:

1. 提取参数

  • session_name:活跃会话名;
  • ttl:新的剩余时长(如3600s);若用户以其他形式给出时长,需换算为该格式。

2. 通过 API 修改会话(命令来自 update_session_expiration.md):

curl -s -X PATCH \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "ttl": "3600s" }' \ "https://devicestreaming.googleapis.com/v1/{session_name}?updateMask=ttl"

3. 重启连接转发器。由于旧转发器携带的是旧 TTL,必须:

  • 运行adb disconnect localhost:{port}确保旧转发连接已关闭;
  • 停止对应{command_id}的旧转发器进程;
  • 按"租用设备会话"第 5 步重新启动转发器——重新计算新的--ttl秒数并记录新的 Command ID。

4. 向用户确认会话时长已更新、转发器已按新 TTL 重启。

停止会话与辅助查询

停止 / 释放设备

当用户要求停止、清理或释放设备时:

  1. 定位会话:从上下文中取出{session_name}{command_id};若已丢失,先列出活跃会话(见下文辅助命令)找到会话名;

  2. 通过 API 取消会话(命令来自 cancel_session.md,空 body 的 POST 到:cancel端点):

    curl -s -X POST \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{}" \ "https://devicestreaming.googleapis.com/v1/{session_name}:cancel"
  3. 终止连接转发器:用环境提供的进程管理能力终止匹配{command_id}的后台进程;

  4. 确认:告知用户会话已取消、资源已释放。

辅助:列出活跃会话

上下文丢失时,可用 list_sessions.md 中的命令列出项目内会话并过滤ACTIVE状态:

curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" \ "https://devicestreaming.googleapis.com/v1/projects/${PROJECT_ID}/deviceSessions" \ | python3 -c " import sys, json data = json.load(sys.stdin) sessions = data.get('deviceSessions', []) active = [s for s in sessions if s.get('state') == 'ACTIVE'] print(json.dumps(active, indent=2)) "

关键要点速查

要点说明依据
Preview 阶段DDP 处于预览状态,接口路径含v1alpha(devicerun)与v1(devicestreaming)之分SKILL.md
必需 APIdevicerun+devicestreaming+testing(Preview 期依赖)三个服务SKILL.md
可租用条件supportedProductsdeviceStreamingSKILL.md
默认设备CATALOG_ID=shiba-34(Pixel 8, SDK 34)SKILL.md
计费确认租用/延长前必须显式警告费用并等待用户批准SKILL.md
轮询节奏状态轮询间隔 5 秒;2 分钟超时(会话供给与转发器上线均适用)SKILL.md、start_adb_forwarder.md
转发器本地127.0.0.1随机端口 <-> gRPCadb_connect双向流;TTL 默认 900 秒,到点自动adb disconnect清理demo_adb_forwarder.py
上下文保存必须记录session_namecommand_id以便后续清理SKILL.md

按以上流程操作,即可以可复现的方式完成一次完整的 DDP 远程 Android 设备使用闭环:认证配置 → 选机 → 租用 → 隧道连接 → 使用 → 续期/释放。

【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询