async-adbc v2.0 重构方案
文档版本: 1.0
创建日期: 2026-05-01
状态: 待审核
1. 概述
本文档描述 async-adbc 项目从 v1.x 到 v2.0 的重构计划,包括当前代码结构分析、存在的问题、重构目标和实施方案。
2. 当前结构分析
2.1 目录结构
async_adbc/
├── __init__.py # 导出 ADBClient, Device, Status
├── adbclient.py # ADBClient 类 (继承 HostService)
├── device.py # Device 类 (继承 LocalService) + Status 枚举
├── exceptions.py # 异常导出 (但定义分散在各模块)
├── plugin.py # Plugin 基类
├── protocol.py # Connection, Response, 协议常量
├── service/
│ ├── __init__.py # Service 抽象基类
│ ├── host.py # HostService + 数据模型 + 异常
│ └── local.py # LocalService
└── plugins/ # 各功能插件
├── __init__.py
├── pm.py # PMPlugin + InstallError 等
├── prop.py
├── cpu.py # CPUPlugin + 数据模型
├── gpu.py
├── mem.py # MemPlugin + 数据模型
├── fps.py # FpsPlugin + SurfaceNotFoundError + FpsStat
├── battery.py
├── temp.py
├── traffic.py
├── forward.py
├── am.py
├── logcat.py
├── minicap.py
├── wm.py
├── input.py
└── utils.py
2.2 依赖关系图
循环依赖风险:
- service/host.py 导入 device.py 中的 Device 和 Status
- device.py 导入 service/host.py 中的 ADBClient (类型注解用)
3. 存在的问题
3.1 代码组织问题
| 问题 | 严重程度 | 说明 |
|---|---|---|
| 职责混杂 | 🔴 高 | service/host.py 包含服务实现、数据模型、异常定义 |
| 硬编码插件 | 🔴 高 | Device.__init__ 中手动实例化所有插件,无法扩展 |
| 异常分散 | 🟡 中 | 异常定义在各插件模块中,通过 exceptions.py 聚合导出 |
| 模型分散 | 🟡 中 | Pydantic 模型分散在各插件和 service 模块中 |
| 单文件过大 | 🟡 中 | protocol.py 包含多个类和常量,可拆分 |
3.2 插件系统问题
- 缺少自动注册机制
- 新增插件需要手动修改
Device.__init__和plugins/__init__.py -
不符合开闭原则 (OCP)
-
插件发现不灵活
- 无法动态启用/禁用插件
- 无法自定义插件加载顺序
3.3 类型注解问题
- 大量使用
typing.TYPE_CHECKING和cast() - 模块间循环依赖导致类型注解复杂
device.py中ADBClient类型注解需要 forward reference
3.4 可维护性问题
| 问题 | 说明 |
|---|---|
| 协议模块过大 | protocol.py 500+ 行,包含常量、Connection、Response |
| 测试耦合 | 测试依赖实际设备连接,难以单元测试 |
| 配置硬编码 | DEFAULT_HOST, DEFAULT_PORT 等常量散落在代码中 |
3.5 命名问题
adbclient.py→ 建议重命名为client.pyrow→raw(拼写错误,见于shell_row应为shell_raw)
4. 重构目标
4.1 核心目标
- 清晰的职责分离 - 每个模块只负责一个功能
- 可扩展的插件系统 - 支持自动发现和注册插件
- 更好的可测试性 - 降低模块间耦合
- 类型安全 - 减少 TYPE_CHECKING 和 cast 使用
4.2 非目标
- 不改变对外 API (保持向后兼容)
- 不重写协议实现
- 不重构测试代码 (除非必要)
5. 目标架构
5.1 新目录结构
async_adbc/
├── __init__.py
├── client.py # ADBClient (重命名)
├── device.py # Device (使用插件注册表)
├── exceptions.py # 所有异常统一定义
├── plugin.py # Plugin基类 + 注册表
├── config.py # 配置常量
│
├── protocol/
│ ├── __init__.py
│ ├── consts.py # 协议常量 (OKAY, FAIL, DATA 等)
│ ├── connection.py # Connection 类
│ └── response.py # Response 类
│
├── service/
│ ├── __init__.py
│ ├── base.py # Service 抽象基类
│ ├── host.py # HostService (纯服务实现)
│ └── local.py # LocalService
│
├── plugins/
│ ├── __init__.py # 使用注册表自动发现
│ ├── _registry.py # 插件注册表 (内部)
│ ├── base.py # 插件基类别名
│ ├── pm.py
│ ├── prop.py
│ ├── cpu.py
│ ├── gpu.py
│ ├── mem.py
│ ├── fps.py
│ ├── battery.py
│ ├── temp.py
│ ├── traffic.py
│ ├── forward.py
│ ├── am.py
│ ├── logcat.py
│ ├── minicap.py
│ ├── wm.py
│ ├── input.py
│ └── utils.py
│
└── models.py # 所有 Pydantic 模型统一定义
5.2 模块职责说明
| 模块 | 职责 |
|---|---|
config.py |
存放全局常量 (DEFAULT_HOST, DEFAULT_PORT 等) |
exceptions.py |
所有异常类的唯一定义位置 |
models.py |
所有 Pydantic 数据模型 (ForwardRule, FpsStat, CPUInfo 等) |
plugin.py |
Plugin 基类 + 装饰器 + 注册表 |
protocol/ |
拆分后的协议实现 |
plugins/_registry.py |
插件注册表实现 (内部模块) |
5.3 依赖流向
config.py ──┐
│
exceptions.py ─┐
├──> models.py
plugin.py ─────┤
├──> protocol/
service/ ──────┤
├──> plugin.py (注册表)
client.py ─────┤
└──> service/
device.py ─────┘
6. 详细实施方案
6.1 阶段一: 整理数据模型和异常
目标: 将分散的模型和异常集中管理
6.1.1 创建 models.py
从以下位置迁移模型:
- service/host.py: DeviceStatusNotification, ForwardRule, ReverseRule
- plugins/fps.py: FpsStat
- plugins/cpu.py: CPUInfo, CPUUsage, CPUFreq, CPUStat, ProcessCPUStat
- plugins/mem.py: MemInfo, MemStat
6.1.2 重构 exceptions.py
从以下位置迁移异常:
- service/host.py: DeviceNotFoundError
- plugins/pm.py: InstallError, UninstallError, ClearError
- plugins/fps.py: SurfaceNotFoundError
6.2 阶段二: 拆分 protocol.py
目标: 将大文件拆分为职责单一的小文件
6.2.1 创建 protocol/consts.py
6.2.2 创建 protocol/connection.py
Connection类encode_length(),decode_length(),pack()函数create_connection()函数
6.2.3 创建 protocol/response.py
Response类
6.2.4 兼容处理
保留 protocol.py 作为导出模块,避免破坏现有导入:
# async_adbc/protocol.py (兼容层)
from .protocol.consts import * # noqa
from .protocol.connection import Connection, create_connection # noqa
from .protocol.response import Response # noqa
6.3 阶段三: 实现插件注册表
目标: 实现自动插件发现和注册机制
6.3.1 设计插件元数据
# plugin.py
from dataclasses import dataclass
from typing import Type
@dataclass
class PluginMetadata:
name: str # 插件名称,如 "pm", "fps"
attr_name: str # Device 属性名,如 "pm" → device.pm
plugin_class: Type['Plugin']
enabled: bool = True
6.3.2 实现注册表
# plugins/_registry.py
from typing import Dict, List, Type
from async_adbc.plugin import Plugin, PluginMetadata
class PluginRegistry:
def __init__(self):
self._plugins: Dict[str, PluginMetadata] = {}
def register(self, name: str, attr_name: str, plugin_class: Type[Plugin]):
self._plugins[name] = PluginMetadata(
name=name,
attr_name=attr_name,
plugin_class=plugin_class
)
def get_all(self) -> List[PluginMetadata]:
return [p for p in self._plugins.values() if p.enabled]
# 全局注册表实例
_registry = PluginRegistry()
6.3.3 注册装饰器
# plugin.py
from typing import Type
from .plugins._registry import _registry
def register_plugin(name: str, attr_name: str):
def decorator(cls: Type[Plugin]):
_registry.register(name, attr_name, cls)
return cls
return decorator
6.3.4 改造插件
# plugins/pm.py
from async_adbc.plugin import Plugin, register_plugin
@register_plugin("pm", "pm")
class PMPlugin(Plugin):
# ... 现有实现
6.4 阶段四: 重构 Device 类
目标: 使用注册表动态加载插件
6.4.1 新的 Device.init
# device.py
from .plugins._registry import _registry
class Device(LocalService):
def __init__(self, adbc: "ADBClient", serialno: str) -> None:
self.adbc = adbc
self.serialno = serialno
# 动态加载插件
self._load_plugins()
def _load_plugins(self):
for metadata in _registry.get_all():
plugin = metadata.plugin_class(self)
setattr(self, metadata.attr_name, plugin)
6.4.2 延迟加载 (可选优化)
考虑实现插件的延迟加载,减少初始化开销:
def _load_plugins(self):
self._plugin_cache = {}
for metadata in _registry.get_all():
self._plugin_cache[metadata.attr_name] = metadata
def __getattr__(self, name):
if name in self._plugin_cache:
metadata = self._plugin_cache[name]
plugin = metadata.plugin_class(self)
setattr(self, name, plugin)
return plugin
raise AttributeError(f"'Device' object has no attribute '{name}'")
6.5 阶段五: 创建 config.py
# config.py
DEFAULT_HOST = "127.0.0.1"
DEFAULT_PORT = 5037
TEMP_PATH = "/data/local/tmp"
DEFAULT_CHMOD = 0o644
DATA_MAX_LENGTH = 65536
修改使用这些常量的模块从 config.py 导入。
6.6 阶段六: 清理 service 模块
6.6.1 service/base.py
将 service/__init__.py 中的 Service 抽象基类移到 service/base.py
6.6.2 service/host.py
- 移除
DeviceNotFoundError(已移到 exceptions.py) - 移除数据模型类 (已移到 models.py)
- 保留纯服务实现
6.6.3 兼容处理
6.7 阶段七: 重命名 adbclient.py
重命名为 client.py,保持兼容:
7. 迁移指南
7.1 对插件开发者
旧方式:
# 1. 创建插件类
class MyPlugin(Plugin): ...
# 2. 在 plugins/__init__.py 导出
from .myplugin import MyPlugin
# 3. 在 device.py 手动添加
self.myplugin = MyPlugin(self)
新方式:
from async_adbc.plugin import Plugin, register_plugin
@register_plugin("myplugin", "myplugin")
class MyPlugin(Plugin): ...
7.2 对库用户
对外 API 保持不变:
# 仍然可以正常使用
from async_adbc import ADBClient, Device
adbc = ADBClient()
device = await adbc.device()
await device.pm.list_packages() # 不变
await device.fps.stat(...) # 不变
8. 测试策略
8.1 保持测试通过
- 重构过程中确保现有测试持续通过
- 使用 git bisect 定位引入问题的提交
8.2 新增测试
- 为插件注册表添加单元测试
- 为新的模块组织结构添加导入测试
8.3 兼容性测试
- 测试旧的导入路径仍然工作
- 测试第三方插件的注册和使用
9. 风险评估
| 风险 | 概率 | 影响 | 缓解措施 |
|---|---|---|---|
| 引入 bug | 🟡 中 | 🔴 高 | 每阶段完成后运行完整测试 |
| 性能下降 | 🟢 低 | 🟡 中 | 插件延迟加载作为可选优化 |
| 第三方插件破坏 | 🟡 中 | 🔴 高 | 提供兼容层,保持 Plugin 基类 API 稳定 |
| 文档过期 | 🟡 中 | 🟡 中 | 同步更新 README 和 API 文档 |
10. 时间规划
| 阶段 | 预计工作量 | 依赖 |
|---|---|---|
| 阶段一: 整理模型和异常 | 0.5 天 | - |
| 阶段二: 拆分 protocol | 0.5 天 | - |
| 阶段三: 实现插件注册表 | 1 天 | - |
| 阶段四: 重构 Device | 0.5 天 | 阶段三 |
| 阶段五: 创建 config.py | 0.5 天 | - |
| 阶段六: 清理 service 模块 | 0.5 天 | 阶段一 |
| 阶段七: 重命名文件 | 0.5 天 | 阶段六 |
| 总计 | 4 天 | - |
11. 回滚计划
如果重构出现问题:
- 分阶段回滚: 每个阶段完成后创建可回滚的 checkpoint
- 完整回滚: 使用 git reset 到重构开始前的 commit
- 增量回滚: 针对特定问题使用 git revert
12. 后续优化方向 (v2.1+)
本次重构不包含但值得考虑的方向:
- 异步上下文管理器: 让 Connection/Response 支持
async with - 连接池: 复用连接,减少连接开销
- 配置文件支持: 从配置文件加载参数
- 更细粒度的插件: 支持按功能模块禁用不需要的插件
- Mock 支持: 提供测试用的 mock device
- 类型注解完善: 为插件添加泛型支持
附录
A. 参考资料
B. 术语表
| 术语 | 说明 |
|---|---|
| HOST SERVICE | ADB Server 提供的服务 (ADBClient 封装) |
| LOCAL SERVICE | Android 设备 adbd 守护进程提供的服务 (Device 封装) |
| Plugin | Device 的功能扩展插件 |