From 4880c31110bcec1366698307ae3bca62a06adf27 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Tue, 15 Sep 2026 12:10:49 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B7=A8=E7=AB=AF:=20fix(=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E9=97=B8):=20app=20state=20=E4=BA=A4=E5=8F=89=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=EF=BC=88=E7=9F=9B=E7=9B=BE=E2=87=92=E6=8B=BF=E4=B8=8D?= =?UTF-8?q?=E5=87=86=EF=BC=89+=20=E6=AD=A3=E4=BE=8B=E6=8D=A2=E6=88=90**?= =?UTF-8?q?=E7=9C=9F=E6=9C=BA=E5=AE=9E=E9=87=87**=E6=A0=B7=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pi 邮件 `6f902e1e` 指出两件,都对: 1. **我那条正例是自相矛盾的**:我用脚本把 `state #FOREGROUND` 对调,却漏了同一块的 `app state #X` ⇒ 造出 `state FG` + `app state BG` 这种**真机上不会出现**的 dump。于是"闸能放行"这条正例 建在**非法输入**上 —— 它绿,但它没证明任何真机会发生的事。 现在:正例改用 12:08 **真机实采**的 `fixtures/aa-dump-l-ours-foreground.txt`(两个 mission 都在、 `state`/`app state` 一致、FG 是我们); 2. 顺手把"矛盾怎么办"钉成规则:同一块里 `state` 与 `app state` 打架 ⇒ **`unverified`**, **不许"挑一个信"**(那是把互相打脸的证据当成证据)。`app state` 缺失时不因此判未验 (否则老格式 dump 会一律未验 —— 那是"更安静的失效")。 判据 8 条全绿;登记同步为 8。 --- .../test/harmony-deviceprobe.test.mjs | 27 ++++++++++--------- client/electron/test/run-all.mjs | 2 +- .../entry/src/main/ets/model/DeviceProbe.ts | 25 ++++++++++++++--- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/client/electron/test/harmony-deviceprobe.test.mjs b/client/electron/test/harmony-deviceprobe.test.mjs index dbc9841..955e7e9 100644 --- a/client/electron/test/harmony-deviceprobe.test.mjs +++ b/client/electron/test/harmony-deviceprobe.test.mjs @@ -35,18 +35,21 @@ test('★ 真机样本:两个 mission 并存,前台是**对方**(这份样 assert.ok(C.unverifiedReason(C.VERDICT_OTHER).includes('未验')); }); -test('★ 同一份样本把状态对调 ⇒ 前台变成我们(判据只认状态,不认顺序/名字)', () => { - // 把两份 mission 的 state 对调:构造"我们在前台"的合法 dump - const oursFront = real - .replace('lockedState #0 mission affinity #[]\n AbilityRecord ID #31', 'lockedState #0 mission affinity #[]\n AbilityRecord ID #31') - .split('\n') - .map((l) => l.includes('#FOREGROUND') ? l.replace('#FOREGROUND', '#BACKGROUND') : l) - .map((l) => l.includes('#BACKGROUND') && l.trim().startsWith('state') && l.includes('start time [84231]') ? l.replace('#BACKGROUND', '#FOREGROUND') : l) - .join('\n'); - // 上面那步只保证"没有 FOREGROUND 了"或"换了另一个" —— 无论哪种,闸都必须给出**可判**的结论而不是假绿 - assert.equal(C.foregroundVerdict(oursFront, OURS), C.VERDICT_OURS, - '★ 正例必须严格成立:状态对调后前台是我们 ⇒ 必须是 ours。否则这道闸的失效方式是"永远说未验"(更安静的失效)'); - assert.equal(C.mayAssertOn(oursFront, OURS), true, 'ours ⇒ 允许断言(可用窗口不会也被判未验)'); +test('★ 真样本②(12:08 实采):**我们真的在前台** ⇒ ours + 允许断言(严格正例)', () => { + // 此前这条正例是**对调状态合成**的,而且合成得自相矛盾(state FG 却 app state BG)—— + // pi 抓到这点:那种样本不是合法 dump,正例等于建在非法输入上。现在换成**真机实采**的。 + const oursReal = prose(join(HERE, 'fixtures', 'aa-dump-l-ours-foreground.txt')); + assert.equal(C.parseMissions(oursReal).length, 2, '真样本里两个 mission 都在(对方 + 我们)'); + assert.equal(C.foregroundVerdict(oursReal, OURS), C.VERDICT_OURS); + assert.equal(C.mayAssertOn(oursReal, OURS), true, '★ 没有这条,"闸能放行"这个性质就没人验(失效方式是永远未验)'); + assert.equal(C.foregroundBundle(oursReal), OURS); +}); + +test('★ 自相矛盾的 dump(state FG 但 app state BG)⇒ unverified,不许挑一个信', () => { + const contradictory = prose(join(HERE, 'fixtures', 'aa-dump-l-ours-foreground.txt')) + .split('\n').map((l) => l.includes('app state #FOREGROUND') && l.trim().startsWith('app state') ? l.replace('#FOREGROUND', '#BACKGROUND') : l).join('\n'); + assert.equal(C.foregroundVerdict(contradictory, OURS), C.VERDICT_UNVERIFIED, + '同一块里 state 与 app state 打架 ⇒ 这份 dump 自己就不自洽 ⇒ 拿不准,而不是"挑一个信"'); }); test('★ 空 dump / 截断 / 格式变了 ⇒ unverified(缺证据 ≠ 没有那个现象)', () => { diff --git a/client/electron/test/run-all.mjs b/client/electron/test/run-all.mjs index 904b2db..401f68d 100644 --- a/client/electron/test/run-all.mjs +++ b/client/electron/test/run-all.mjs @@ -79,7 +79,7 @@ const SUITE = [ ['test/build-stamp.test.mjs', [], 7], ['test/packaging.test.mjs', [], 5], ['test/align-refs.test.mjs', [], 3], - ['test/harmony-deviceprobe.test.mjs', ['--experimental-strip-types', '--no-warnings'], 7], + ['test/harmony-deviceprobe.test.mjs', ['--experimental-strip-types', '--no-warnings'], 8], ['test/harmony-push.test.mjs', ['--experimental-strip-types', '--no-warnings'], 13], ['test/harmony-calendar.test.mjs', ['--experimental-strip-types', '--no-warnings'], 10], ['test/debt-visibility.test.mjs', [], 1], diff --git a/client/harmony/entry/src/main/ets/model/DeviceProbe.ts b/client/harmony/entry/src/main/ets/model/DeviceProbe.ts index e6ce91f..fa449d7 100644 --- a/client/harmony/entry/src/main/ets/model/DeviceProbe.ts +++ b/client/harmony/entry/src/main/ets/model/DeviceProbe.ts @@ -21,12 +21,16 @@ export const VERDICT_UNVERIFIED: string = 'unverified'; export interface MissionInfo { bundle: string; state: string; + /** 同一块里的 `app state #X` —— 真机 dump 两个都在。**两者矛盾 ⇒ 拿不准**(pi 邮件 `6f902e1e`) */ + appState: string; } /** `bundle name [com.x]` —— 方括号形状是**真机实测**的(样本 fixtures/aa-dump-l-real.txt) */ const RE_BUNDLE = new RegExp('^\\s*(?:bundle|app)\\s+name\\s+\\[([^\\]]+)\\]'); /** 只认行首的 `state`;`app state #FOREGROUND` 是同一块里的另一行,不算错 */ const RE_STATE = new RegExp('^\\s*state\\s+#(\\w+)'); +/** `app state #FOREGROUND` —— 与 `state` 交叉验证:**矛盾就是拿不准**,不是"挑一个信" */ +const RE_APPSTATE = new RegExp('^\\s*app\\s+state\\s+#(\\w+)'); /** * 解析所有 mission 块。取不到就返回**空数组**(空 dump / 截断 / 格式变了)—— 不猜、不兜底。 @@ -42,14 +46,16 @@ export function parseMissions(dump: string): MissionInfo[] { const lines: string[] = dump.split('\n'); let bundle: string = ''; let state: string = ''; + let appState: string = ''; for (const raw of lines) { const line: string = raw.replace('\r', ''); if (line.indexOf('Mission ID') >= 0) { if (bundle.length > 0) { - out.push({ bundle: bundle, state: state }); + out.push({ bundle: bundle, state: state, appState: appState }); } bundle = ''; state = ''; + appState = ''; continue; } const mb = RE_BUNDLE.exec(line); @@ -60,10 +66,15 @@ export function parseMissions(dump: string): MissionInfo[] { const ms = RE_STATE.exec(line); if (ms !== null && state.length === 0) { state = ms[1]; + continue; + } + const ma = RE_APPSTATE.exec(line); + if (ma !== null && appState.length === 0) { + appState = ma[1]; } } if (bundle.length > 0) { - out.push({ bundle: bundle, state: state }); + out.push({ bundle: bundle, state: state, appState: appState }); } return out; } @@ -76,9 +87,15 @@ export function parseMissions(dump: string): MissionInfo[] { export function foregroundBundle(dump: string): string { const missions: MissionInfo[] = parseMissions(dump); for (const m of missions) { - if (m.state === 'FOREGROUND') { - return m.bundle; + if (m.state !== 'FOREGROUND') { + continue; } + // 真机 dump 里 `state` 与 `app state` 是一致的;**两者矛盾 ⇒ 这份 dump 自相矛盾 ⇒ 拿不准** + // (不许"挑一个信":那是把互相打脸的证据当成证据。pi 邮件 `6f902e1e` 抓到我的对调样本正是这种形状) + if (m.appState.length > 0 && m.appState !== 'FOREGROUND') { + return ''; + } + return m.bundle; } return ''; }