第4章 RePlugin 插件生命周期管理:安装、启动、销毁流程与 Hook 点设计
4.1 本章定位与架构边界
插件生命周期管理是 RePlugin 插件化框架的核心能力层,它定义了插件从“外部资源包”转变为“可运行组件”再到“完全卸载”的完整过程。与 Atlas 基于“bundle 按需挂载”的策略不同,RePlugin 采用“独立 APK + 动态注册”的模型,生命周期的边界更清晰,但控制点也更为集中。
架构边界界定:
- 宿主侧边界:只负责提供 ClassLoader 创建入口和插件管理服务(Loader 进程)。
- 插件侧边界:插件 APK 自身不感知生命周期调度,仅暴露入口组件(Activity/Service/Receiver)。
- 框架侧边界:RePlugin 框架(包括宿主 Loader 与插件 Local 层)承担全部生命周期编排。
4.2 分层模型与组件职责
| 分层 | 组件/模块 | 生命周期职责 |
|---|---|---|
| 宿主层 | PluginManagerClient (宿主进程) |
发起安装/卸载请求;维护插件状态表;提供 Hook 注册接口 |
| Loader 层 | PluginServiceHelper TaskExecutor |
解析插件包;创建 DexClassLoader;分配组件坑位;回调预/后置 Hook |
| 插件层 | 插件内 Application 入口 Activity/Service |
接收生命周期回调;执行自身初始化/销毁逻辑;不参与调度决策 |
| 安全校验层 | SignatureVerifier TrustChainValidator |
安装时校验签名与信任链;启动时校验插件完整性(可选) |
4.3 安装、启动、销毁三阶段流程与 Hook 点设计
RePlugin 将插件生命周期划分为三个主阶段,每个阶段内部包含若干原子步骤,并在关键步骤前后插入 Hook 回调,供宿主或插件进行干预。
4.3.1 安装阶段
- 资源拷贝:将插件 APK 文件从外部存储复制到宿主私有目录(
data/data/<package>/plugins/)。 - 签名校验:验证插件 APK 签名是否与宿主允许的签名列表匹配。
- 组件扫描:解析
AndroidManifest.xml中声明的 Activity、Service、Receiver、ContentProvider,并建立组件注册表。 - 坑位分配:为组件分配宿主预埋的“坑位”(占位 Activity/Service),更新坑位映射表。
- 数据库记录:将插件信息写入
PluginDB,标记为“已安装”状态。
安装阶段 Hook 点:
| Hook 名 | 触发时机 | 可修改内容 |
|---|---|---|
onBeforeInstall | 拷贝开始前 | 插件路径、签名校验规则 |
onAfterVerify | 签名校验完成后 | 是否允许安装(返回 false 则中断) |
onComponentRegistered | 组件注册表写入后 | 组件别名、坑位编号 |
4.3.2 启动阶段
- 插件类加载:创建
DexClassLoader,加载插件 APK 中的 Dex 和资源。 - 初始化插件 Application:反射调用插件内 Application 的
onCreate方法(若插件声明了)。 - 组件实例化:通过坑位映射查找目标组件,创建实例并调用其生命周期方法(如 Activity 的
onCreate)。 - 重定向上下文:替换组件内
Context为插件资源桥接上下文,确保资源与宿主隔离。
启动阶段 Hook 点:
| Hook 名 | 触发时机 | 可修改内容 |
|---|---|---|
onBeforeLoadClass | DexClassLoader 创建前 | 自定义 ClassLoader 结构、类白名单 |
onAfterCreateApp | 插件 Application 初始化后 | 向 Application 注入宿主依赖 |
onComponentPrepared | 组件实例化完成但未回调 onCreate | 组件参数、Intent 数据 |
4.3.3 销毁阶段
- 组件销毁:调用插件内组件的
onDestroy/onStop等方法。 - 释放 ClassLoader:断开
DexClassLoader引用,允许 GC 回收。 - 清理资源表:从组件注册表中移除该插件条目;释放坑位。
- 删除文件:可选择删除插件 APK 文件及数据目录。
- 更新状态:将
PluginDB中状态标记为“已卸载”或删除记录。
销毁阶段 Hook 点:
| Hook 名 | 触发时机 | 可修改内容 |
|---|---|---|
onBeforeUnload | 组件销毁前 | 取消未完成任务、持久化数据 |
onAfterClean | 资源清理完成后 | 执行回调通知宿主其他模块 |
4.4 控制流与监控链路
下图展示了 RePlugin 插件从“开始安装”到“卸载完成”的完整控制流,以及三个阶段的 Hook 锚点分布。
4.5 选型权衡与风险点
风险点一:安装过程无事务回滚
RePlugin 在安装阶段未采用数据库事务 + 文件备份机制。如果在“拷贝 APK”后“签名校验”失败,宿主目录下会残留不完整插件文件。需要宿主自行在 onAfterVerify Hook 中做清理补偿。
风险点二:启动阶段 DexClassLoader 泄露
每次启动都会创建新的 DexClassLoader,若调用方未及时回收引用,将导致 DexClassLoader 和对应 Dex 文件长期驻留内存。建议在 onBeforeUnload Hook 中主动清除所有外部引用。
与 Atlas 的选型权衡:
| 决策维度 | RePlugin | Atlas |
|---|---|---|
| 安装粒度 | 全量安装整个插件 APK | 可按 bundle 增量挂载 |
| 启动开销 | 每次创建独立的 DexClassLoader,CMS 压力较大 | 复用宿主 ClassLoader,启动更快 |
| 卸载彻底性 | 可完全删除插件文件 | bundle 仅卸载类,文件需额外清理 |
| Hook 扩展性 | 8 个预定义钩子 + 自定义扩展 | 支持 bundle 级 AOP 切面 |
4.6 落地步骤与验收标准
落地步骤
- 初始化 Hook 注册中心:在宿主 Application
onCreate中调用PluginManager.addLifecycleHook()注册所有自定义回调。 - 实现签名校验插件:在
onAfterVerify中使用宿主预埋的公钥验证插件签名哈希。 - 配置组件坑位表:在宿主
AndroidManifest.xml中预留足够数量的占位 Activity/Service。 - 异常补偿:在
onBeforeUnload中序列化插件当前状态,并清理临时文件。 - 单元测试覆盖:编写安装 → 启动 → 销毁三阶段的集成测试,验证 Hook 回调执行顺序和参数正确性。
验收标准
- 安装一个 10MB 的插件 APK,从文件复制到组件注册完成,耗时 ≤ 800ms(中端设备)。
- 连续安装/卸载 50 次后,宿主
/data/data/<package>/plugins/目录下无残留文件。 - 销毁后调用
PluginManager.isInstalled()返回false;内存快照中不存在该插件的 DexClassLoader 强引用。 - 每个 Hook 点通过日志输出被正确调用,入参上下文有效。
经验建议:
RePlugin 的“独立 ClassLoader 模型”在插件隔离性上优于 Atlas,但代价是包体积和安装时间。如果你的业务场景中插件数量超过 20 个,应优先考虑“预加载 + 懒卸载”策略,在 onBeforeUnload Hook 中设置引用计数,避免频繁重建 ClassLoader。