先看结论与判断条件

  • 每个事件只绑定一个明确候选身份,多个版本要拆成关联子记录。
  • 影响范围写用户路径、版本、设备、渠道和时间窗,不用“全部不可用”等模糊词。
  • 原始崩溃、ANR、退出原因和业务回执分别保存,截图和转述不能替代附件。
  • 临时处置必须有批准、到期、风险和回退条件。
  • 升级节点写触发条件、接收角色、所需证据与下一决策,不只写通知时间。
  • 结案要求业务恢复、技术结论、剩余限制和回执全部闭合。

用候选身份建立唯一事件主键

先把事件编号、候选、版本、签名、渠道和发布时间写成可复核对象,而不是凭页面印象判断。APK/IPA 摘要、versionCode/build、证书摘要、轨道和安装来源应与最终候选摘要、版本、环境和操作时间绑定,记录值来自系统回执、测试日志或受控导出。只有这些输入同源,所有证据是否确实属于同一个发布候选才有解释力;文件名相似、人员记忆或聊天截图都不能代替对象身份。

从设备与发布台账双向核对候选,不按聊天中的版本名选包。执行前冻结会改变结果的开关、账号属性、时间窗和网络条件,执行中只改变一个变量,执行后保存输入、观察值与判定。每个通过项都要有正向路径和拒绝或失败路径;只记录“成功”会漏掉错误默认值、未授权访问、取消恢复和边界状态。

事件只记录版本名而没有候选摘要时先标记 blocked,并把剩余未知写进报告。一个主事件可以关联多个候选,但每个证据必须明确归属。这项限制不能靠扩大权限、修改生产导出面或补写未经验证的数字绕过。若后续证据改变,只重开对应记录,不重复执行已经有稳定回执的无关步骤。

用候选身份建立唯一事件主键检查表
检查对象输入证据判定动作失败处置
事件编号、候选、版本、签名、渠道和发布时间身份APK/IPA 摘要、versionCode/build、证书摘要、轨道和安装来源所有证据是否确实属于同一个发布候选事件只记录版本名而没有候选摘要则阻塞
同源基线候选摘要与时间窗锁定比较对象来源不明则阻塞
执行记录从设备与发布台账双向核对候选,不按聊天中的版本名选包保存系统回执只有口头结论则补证
适用边界一个主事件可以关联多个候选,但每个证据必须明确归属限制结论范围不得扩大为全局结论

把影响范围写成可核查集合

受影响用户路径、设备、系统、版本、地区和时间窗要从状态变化而不是最终页面开始核对。把影响计数口径、首末时间、设备分布、可复现路径和未确认范围按发生顺序保留,并为每一步写明触发者、前置条件、候选版本和回执来源。这样可以判断影响是真实扩大、样本偏差还是口径未知发生在读取、计算、传输、系统调度还是业务处理阶段,避免把多个故障压成一句“加固后不可用”。

为确认、推定和未知分别计数并注明数据来源。清单至少包含对象标识、预期、观察、证据引用、责任人和复核状态。自动校验适合发现缺字段、重复记录与不一致结果,最终业务含义仍由熟悉应用的人判断。若依赖第三方平台,还要区分客户端实际状态、平台控制面显示和异步回执的时间差。

验收不能只看操作完成或命令退出码。影响描述没有时间窗、设备或统计来源说明链路仍缺少可归因证据;统计数据不可得时标记未知,不虚构用户数和比例。结论应分成已确认事实、工程判断和适用限制,尤其不能把一次测试通过扩大成所有版本、设备、渠道或客户场景都通过。

把影响范围写成可核查集合检查表
检查对象输入证据判定动作失败处置
受影响用户路径、设备、系统、版本、地区和时间窗身份影响计数口径、首末时间、设备分布、可复现路径和未确认范围影响是真实扩大、样本偏差还是口径未知影响描述没有时间窗、设备或统计来源则阻塞
同源基线候选摘要与时间窗锁定比较对象来源不明则阻塞
执行记录为确认、推定和未知分别计数并注明数据来源保存系统回执只有口头结论则补证
适用边界统计数据不可得时标记未知,不虚构用户数和比例限制结论范围不得扩大为全局结论

保存首次异常与原始诊断证据

处理首次发生时间、操作、原始日志、trace、截图和事件 ID时,先固定应用身份、候选摘要、平台版本和可变条件。原始附件摘要、采集工具、设备、进程、线程和时间必须来自同一轮执行,不能把不同设备或不同发布时间的结果拼在一起。证据链闭合后再讨论现场材料是否足以复现或至少定位首次分叉,否则重试成功也只能说明环境变了,不能支持技术结论。

先复制只读原始材料并计算摘要,再开始清理或重试。基线与最终候选使用相同设备、数据准备、账号权限和触发脚本,差异只保留必要变量。遇到失败先保存现场,再按最小范围补测;重装、清数据、切账号或换网络都会重置条件,必须作为新用例登记,不能覆盖原记录。

出现重试覆盖了首次异常且没有原始附件,应回到上一份同源输入,比较首次分叉点并保留两侧回执。材料可能含用户数据,应在授权环境脱敏和限权。临时绕行可以用于恢复业务,但必须记录批准、到期和回退条件,不能让临时措施替代根因验证或变成长期未审计配置。

保存首次异常与原始诊断证据检查表
检查对象输入证据判定动作失败处置
首次发生时间、操作、原始日志、trace、截图和事件 ID身份原始附件摘要、采集工具、设备、进程、线程和时间现场材料是否足以复现或至少定位首次分叉重试覆盖了首次异常且没有原始附件则阻塞
同源基线候选摘要与时间窗锁定比较对象来源不明则阻塞
执行记录先复制只读原始材料并计算摘要,再开始清理或重试保存系统回执只有口头结论则补证
适用边界材料可能含用户数据,应在授权环境脱敏和限权限制结论范围不得扩大为全局结论

区分崩溃、ANR、进程退出和业务失败

先把异常类型、线程、退出原因、错误码和业务状态写成可复核对象,而不是凭页面印象判断。ApplicationExitInfo、ANR trace、崩溃堆栈、系统状态和业务回执应与最终候选摘要、版本、环境和操作时间绑定,记录值来自系统回执、测试日志或受控导出。只有这些输入同源,故障应进入哪条诊断路径而不是混成单一错误才有解释力;文件名相似、人员记忆或聊天截图都不能代替对象身份。

按异常类型路由到堆栈、线程、退出或业务状态分析。执行前冻结会改变结果的开关、账号属性、时间窗和网络条件,执行中只改变一个变量,执行后保存输入、观察值与判定。每个通过项都要有正向路径和拒绝或失败路径;只记录“成功”会漏掉错误默认值、未授权访问、取消恢复和边界状态。

ANR、崩溃和业务错误使用同一根因结论时先标记 blocked,并把剩余未知写进报告。ApplicationExitInfo 与 vitals 是旁证,不能替代完整上下文。这项限制不能靠扩大权限、修改生产导出面或补写未经验证的数字绕过。若后续证据改变,只重开对应记录,不重复执行已经有稳定回执的无关步骤。

记录临时处置的批准与回退条件

开关、回退、降级、暂停发布和受限访问要从状态变化而不是最终页面开始核对。把动作、执行人、批准人、开始时间、到期、监控和撤回回执按发生顺序保留,并为每一步写明触发者、前置条件、候选版本和回执来源。这样可以判断临时措施是否可接受且能够按条件撤销发生在读取、计算、传输、系统调度还是业务处理阶段,避免把多个故障压成一句“加固后不可用”。

每个临时动作建立批准、到期、观测指标和撤回步骤。清单至少包含对象标识、预期、观察、证据引用、责任人和复核状态。自动校验适合发现缺字段、重复记录与不一致结果,最终业务含义仍由熟悉应用的人判断。若依赖第三方平台,还要区分客户端实际状态、平台控制面显示和异步回执的时间差。

验收不能只看操作完成或命令退出码。临时关闭功能没有批准、到期或回退说明链路仍缺少可归因证据;应急处置用于控制影响,不等于根因修复。结论应分成已确认事实、工程判断和适用限制,尤其不能把一次测试通过扩大成所有版本、设备、渠道或客户场景都通过。

记录临时处置的批准与回退条件检查表
检查对象输入证据判定动作失败处置
开关、回退、降级、暂停发布和受限访问身份动作、执行人、批准人、开始时间、到期、监控和撤回回执临时措施是否可接受且能够按条件撤销临时关闭功能没有批准、到期或回退则阻塞
同源基线候选摘要与时间窗锁定比较对象来源不明则阻塞
执行记录每个临时动作建立批准、到期、观测指标和撤回步骤保存系统回执只有口头结论则补证
适用边界应急处置用于控制影响,不等于根因修复限制结论范围不得扩大为全局结论

把客户、供应商和业务角色写清

处理客户技术 owner、供应商负责人、业务批准人和发布 owner时,先固定应用身份、候选摘要、平台版本和可变条件。角色、组织、联系方式、权限边界、当前任务和交接状态必须来自同一轮执行,不能把不同设备或不同发布时间的结果拼在一起。证据链闭合后再讨论当前决定由谁负责、谁批准、谁只提供证据,否则重试成功也只能说明环境变了,不能支持技术结论。

使用角色而非个人记忆分派任务,变更时保留交接回执。基线与最终候选使用相同设备、数据准备、账号权限和触发脚本,差异只保留必要变量。遇到失败先保存现场,再按最小范围补测;重装、清数据、切账号或换网络都会重置条件,必须作为新用例登记,不能覆盖原记录。

出现责任写成双方跟进或群内确认,应回到上一份同源输入,比较首次分叉点并保留两侧回执。响应时长由合同与事件等级另行定义,文章不作承诺。临时绕行可以用于恢复业务,但必须记录批准、到期和回退条件,不能让临时措施替代根因验证或变成长期未审计配置。

让每次升级都有触发条件和交付物

先把升级级别、触发阈值、接收人、输入证据和截止决策写成可复核对象,而不是凭页面印象判断。条件、事件时间、通知时间、接收确认、交付物和下一检查点应与最终候选摘要、版本、环境和操作时间绑定,记录值来自系统回执、测试日志或受控导出。只有这些输入同源,何时升级给哪个角色以及必须附带什么才有解释力;文件名相似、人员记忆或聊天截图都不能代替对象身份。

达到明确条件才升级,并要求接收人确认材料完整性。执行前冻结会改变结果的开关、账号属性、时间窗和网络条件,执行中只改变一个变量,执行后保存输入、观察值与判定。每个通过项都要有正向路径和拒绝或失败路径;只记录“成功”会漏掉错误默认值、未授权访问、取消恢复和边界状态。

升级只记录已通知而没有接收与下一决定时先标记 blocked,并把剩余未知写进报告。升级机制不能扩大供应商对生产系统的默认权限。这项限制不能靠扩大权限、修改生产导出面或补写未经验证的数字绕过。若后续证据改变,只重开对应记录,不重复执行已经有稳定回执的无关步骤。

让每次升级都有触发条件和交付物检查表
检查对象输入证据判定动作失败处置
升级级别、触发阈值、接收人、输入证据和截止决策身份条件、事件时间、通知时间、接收确认、交付物和下一检查点何时升级给哪个角色以及必须附带什么升级只记录已通知而没有接收与下一决定则阻塞
同源基线候选摘要与时间窗锁定比较对象来源不明则阻塞
执行记录达到明确条件才升级,并要求接收人确认材料完整性保存系统回执只有口头结论则补证
适用边界升级机制不能扩大供应商对生产系统的默认权限限制结论范围不得扩大为全局结论

用代码拒绝只有聊天时间线的记录

脱敏升级记录中的候选、影响、决定和回执要从状态变化而不是最终页面开始核对。把recordId、候选摘要、预期阶段、观察阶段、结果和证据引用按发生顺序保留,并为每一步写明触发者、前置条件、候选版本和回执来源。这样可以判断记录是否具备执行闭环而不只是消息列表发生在读取、计算、传输、系统调度还是业务处理阶段,避免把多个故障压成一句“加固后不可用”。

把公开字段写成 JSON,让校验器拒绝阶段错配和空证据。清单至少包含对象标识、预期、观察、证据引用、责任人和复核状态。自动校验适合发现缺字段、重复记录与不一致结果,最终业务含义仍由熟悉应用的人判断。若依赖第三方平台,还要区分客户端实际状态、平台控制面显示和异步回执的时间差。

验收不能只看操作完成或命令退出码。预期阶段与观察阶段不一致却标记通过说明链路仍缺少可归因证据;代码只审计公开记录,不连接工单系统或读取私密附件。结论应分成已确认事实、工程判断和适用限制,尤其不能把一次测试通过扩大成所有版本、设备、渠道或客户场景都通过。

检查支持事件升级记录是否闭环
import hashlib
import json
import sys
from pathlib import Path

REQUIRED = set([
  'recordId',
  'candidateSha256',
  'impactScope',
  'technicalOwner',
  'expectedStage',
  'observedStage',
  'result',
  'evidenceRef'
])
ALLOWED_RESULTS = set([
  'pass',
  'blocked',
  'mismatch'
])
FORBIDDEN = {'token', 'password', 'privateKey', 'secret', 'customerData'}

def stop(message):
    raise SystemExit(message)

def digest(path):
    hasher = hashlib.sha256()
    with path.open('rb') as stream:
        for chunk in iter(lambda: stream.read(1024 * 1024), b''):
            hasher.update(chunk)
    return hasher.hexdigest()

def text(record, field, index):
    value = str(record[field]).strip()
    if not value:
        stop(f'record {index} has empty {field}')
    return value

def validate(record, index):
    if not isinstance(record, dict):
        stop(f'record {index} is not an object')
    if FORBIDDEN.intersection(record):
        stop(f'record {index} contains forbidden fields')
    missing = sorted(REQUIRED - record.keys())
    if missing:
        raise SystemExit(f'record {index} lacks fields: {missing}')
    for field in REQUIRED:
        if field != 'impactScope':
            text(record, field, index)
    result = text(record, 'result', index)
    if result not in ALLOWED_RESULTS:
        stop(f'record {index} has an unsupported result')
    expected = text(record, 'expectedStage', index)
    observed = text(record, 'observedStage', index)
    evidence = text(record, 'evidenceRef', index)
    if expected != observed and result == 'pass':
        stop(f'record {index} passes despite a mismatch')
    if expected != observed and not evidence:
        stop(f'record {index} has a mismatch without evidence')
    return text(record, 'recordId', index)

if len(sys.argv) != 2:
    stop('usage: python validate_incident_record.py public-checks.json')
source = Path(sys.argv[1]).expanduser().resolve()
if not source.is_file():
    stop('public check file is missing')
raw = source.read_bytes()
data = json.loads(raw.decode('utf-8'))
records = data.get('incidents') if isinstance(data, dict) else None
if not isinstance(records, list) or not records:
    raise SystemExit('incidents must be a non-empty list')
identifiers = [validate(record, index) for index, record in enumerate(records)]
if len(identifiers) != len(set(identifiers)):
    raise SystemExit('record identifiers are duplicated')
summary = {
    'inputSha256': hashlib.sha256(raw).hexdigest(),
    'records': len(records),
    'results': {state: sum(1 for item in records if item['result'] == state) for state in sorted(ALLOWED_RESULTS)},
    'status': 'pass',
}
print(json.dumps(summary, ensure_ascii=False, sort_keys=True))

按恢复、根因和剩余限制结案

处理业务恢复、技术结论、验证范围、遗留项和责任人时,先固定应用身份、候选摘要、平台版本和可变条件。恢复时间、回归结果、根因状态、限制、复发监控和签署必须来自同一轮执行,不能把不同设备或不同发布时间的结果拼在一起。证据链闭合后再讨论事件可关闭、继续观察还是保持 blocked,否则重试成功也只能说明环境变了,不能支持技术结论。

由技术、业务和发布 owner 分别确认各自结案条件。基线与最终候选使用相同设备、数据准备、账号权限和触发脚本,差异只保留必要变量。遇到失败先保存现场,再按最小范围补测;重装、清数据、切账号或换网络都会重置条件,必须作为新用例登记,不能覆盖原记录。

出现业务恢复后立即关闭且没有技术限制记录,应回到上一份同源输入,比较首次分叉点并保留两侧回执。结案仅覆盖列明候选、影响范围、验证和剩余限制。临时绕行可以用于恢复业务,但必须记录批准、到期和回退条件,不能让临时措施替代根因验证或变成长期未审计配置。

事实依据与适用边界

以下内容区分官方事实、本文工程判断和不能外推的范围,避免把设计建议写成未经验证的产品结论。

本文判断事实或工程依据适用限制
安全发布应保留来源、构建、验证和变更证据,并把供应链风险纳入开发流程。NIST SP 800-218 SSDF:安全发布应保留来源、构建、验证和变更证据,并把供应链风险纳入开发流程。SSDF 是组织级实践框架,不定义某个 App 加固产品的具体功能。
ApplicationExitInfo 可提供进程退出原因、ANR trace,并在新版本返回 Native tombstone。Android ApplicationExitInfo:ApplicationExitInfo 可提供进程退出原因、ANR trace,并在新版本返回 Native tombstone。退出记录仍需与同一版本、时间窗和用户路径关联。
Android vitals 提供崩溃、ANR、启动和设备分布等线上质量信号。Android vitals:Android vitals 提供崩溃、ANR、启动和设备分布等线上质量信号。Play 样本受安装来源、用户同意和统计口径限制。
ANR 需要按主线程阻塞、锁竞争、Binder、I/O 与组件超时分层定位。Diagnose Android ANRs:ANR 需要按主线程阻塞、锁竞争、Binder、I/O 与组件超时分层定位。trace 中的表象堆栈不一定是最初阻塞源。
构建证明应绑定产物主体、构建者、构建类型、外部参数与依赖材料。SLSA Provenance v1.1:构建证明应绑定产物主体、构建者、构建类型、外部参数与依赖材料。provenance 只能证明记录的构建过程,不能单独证明运行时安全性。
供应链证明应把产物摘要与有类型的声明负载绑定,避免报告与候选包错配。in-toto Attestation Statement v1:供应链证明应把产物摘要与有类型的声明负载绑定,避免报告与候选包错配。声明格式不保证声明内容真实,仍需可信签名者和门禁核验。
支持升级记录必须把候选身份、当前决定、责任角色和下一升级条件放在同一闭环。工程判断:缺少任一环节都会让接收方无法判断证据归属、下一动作或结案条件。具体角色名称和升级级别由合同与组织结构定义。
聊天时间线不能代替原始诊断附件和系统回执。工程判断:聊天内容可被编辑、截断和脱离上下文,难以证明候选与系统状态。聊天可作为事件索引,但必须链接受控附件与实际系统状态。

工程常见问题

支持群里的完整聊天记录可以直接作为升级记录吗?

不够。聊天可做索引,但还要有候选摘要、影响口径、原始附件、当前决定、责任角色、升级条件和系统回执。

业务已经恢复,事件能立即结案吗?

不能只凭恢复。还要记录临时措施、技术结论、回归范围、剩余限制、复发监控和相关 owner 的确认。

影响用户数拿不到怎么办?

标记未知,记录能确认的版本、设备、路径、时间窗和数据源,不用估算值充当事实。

ANR 和崩溃可以放在同一根因记录吗?

可属于同一主事件,但原始证据和诊断路径要分开,只有证据支持共同根因时才合并结论。

临时关闭某功能需要记录什么?

记录动作、范围、批准人、风险、开始时间、到期、监控、撤回条件和最终回执。

提交御盾升级支持要准备什么?

准备候选摘要、版本签名渠道、影响范围、首次异常、原始崩溃或 ANR 材料、退出原因、临时处置、责任角色和下一决策。

想用自己的 App 验证?

提交候选包、目标系统和关键业务路径,申请御盾 PoC 与兼容性评估。

继续阅读: 御盾 VMP 接入前准备清单