NDK 模块生产就绪清单:从能运行到敢上线
mediumAndroidNDKProductionReliabilityChecklist
NDK 模块“能跑起来”和“可以上线”之间差很远。native 崩溃通常是进程级崩溃,播放器这类实时模块还会涉及线程、Surface、codec、内存、时钟和三方库。
这篇给一份发布前清单。它不是形式主义,而是把前面学过的知识变成上线门禁。
兼容性检查
minSdk 与 ANDROID_PLATFORM 一致或经过明确设计
所有目标 ABI 都有对应 .so
没有意外缺失 arm64-v8a
新 NDK API 有运行时探测或降级路径
所有 native 库支持 16KB page size
三方 .so 来源、版本、ABI、许可证已登记
新手最容易漏的是“三方 SDK 里的 .so”。只要它被打进你的 App,就属于你的发布风险。
JNI 检查
JNI 方法集中在少量 bridge 文件
高频操作不跨 JNI 逐帧调用
JNIEnv 不跨线程保存
跨线程保存 Java 对象时使用 GlobalRef
GlobalRef 成对 DeleteGlobalRef
JNI_OnLoad 注册失败有明确日志
RegisterNatives 签名有测试覆盖
JNI 边界要窄。桥越宽,越难排查。
内存与线程检查
C API 资源有 RAII 包装
AMediaExtractor/AMediaCodec/ANativeWindow 释放成对
release 幂等
Surface 销毁后 render 不再使用旧 window
线程退出协议明确
队列有容量上限
seek 会清队列和 flush codec
播放器发布前至少做:
反复进出播放页
快速 seek
横竖屏切换
切后台再回来
弱网或坏包注入
崩溃可观测性
每个发布版本归档 unstripped .so
ndk-stack 可还原模拟 crash
native 日志带 state、serial、thread、source
错误码区分 recoverable 和 fatal
崩溃平台能按 ABI 和版本聚合
没有符号归档,不允许发布 native 模块。这个规则要硬。
性能检查
首帧时间有基线
seek 恢复时间有基线
播放 30 分钟无队列膨胀
simpleperf 有热点报告
优化前后有数据对比
JNI 回调频率可控
日志不在帧循环里刷屏
性能指标建议区分平均值和 P95/P99。播放器用户感知的是卡顿尾部,不是平均值。
媒体链路检查
AMediaExtractor 轨道选择正确
sample ptsUs 大体递增
AMediaCodec 输出 buffer 都 release
format changed 有处理
EOS 同时考虑音频和视频
AVSync 有 drift 指标
音频缺失时有 video-only clock
特别注意 releaseOutputBuffer。output buffer 不释放,codec 队列会被占满,播放会卡死。
三档发布结论
把检查结果分三档。
阻断项:必须修复,否则不能发版
观察项:可灰度,但要加监控
通过项:满足发布标准
阻断项示例:
arm64-v8a 缺库
符号无法归档
16KB page size 检查失败
release 后线程不退出
Surface 销毁后仍发生 render crash
观察项示例:
某低端设备 seek P95 偏高
三方库导出符号较多但暂未冲突
GWP-ASan 线上偶发采样报告待观察
发布后 7 天观察
native crash rate
ANR rate
首帧 P95
seek P95
播放中 Error 状态次数
Buffering 次数
设备/ABI 分布
新增三方库 crash 聚合
发布不是终点。native 模块要看灰度数据,必要时快速回滚。
小白怎样使用这张清单
不要一次性把清单当成巨大压力。可以按发布阶段使用。
开发阶段:关注 JNI、资源释放、线程退出
联调阶段:关注播放器状态机、seek、Surface 生命周期
测试阶段:关注 sanitizer、simpleperf、兼容性
发布阶段:关注 ABI、符号、16KB、三方库审计
灰度阶段:关注 crash rate、P95、回滚条件
每个阶段只回答一个问题:现在最大的未知风险是什么?
最小发布门禁示例
如果团队刚开始做 NDK,可以先设置最小门禁。
arm64-v8a/x86_64 构建通过
content smoke test 通过
播放器打开、播放、暂停、seek、退出通过
release 后线程退出
ndk-stack 能还原模拟 crash
所有 .so 通过 16KB 检查
符号文件归档
随着模块变复杂,再逐步加入 sanitizer 周期任务、simpleperf 基线、三方库升级审计。
回滚条件
native 模块必须提前定义回滚条件。
native crash rate 超过基线 2 倍
某 ABI crash 聚合明显异常
首帧 P95 超过基线 30%
seek fatal error 超过阈值
三方库初始化失败集中出现
回滚不是失败,而是工程系统的一部分。敢上线的前提,是知道什么时候应该退回来。
责任归属
清单最好有负责人。
构建负责人:ABI、符号、16KB
客户端负责人:JNI、生命周期、播放器状态
测试负责人:压力、兼容性、回归
发布负责人:灰度、观测、回滚
责任清楚,问题出现时才不会所有人一起猜。
本章结论
NDK 模块的生产就绪不是“功能能跑”,而是兼容性、JNI、内存、崩溃、性能、媒体链路和发布观测全部可控。清单越具体,线上越不靠运气。