@onekeyfe/hd-core 1.2.0-alpha.110 → 1.2.0-alpha.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/DeviceCommands.test.ts +2 -2
- package/__tests__/device-lifecycle-events.test.ts +1 -1
- package/__tests__/device-state-mapper.test.ts +4 -4
- package/__tests__/device-utils.test.ts +1 -1
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -54
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +36 -89
- package/__tests__/get-device-state.test.ts +8 -8
- package/__tests__/protocol-v2-resources.test.ts +20 -0
- package/__tests__/protocol-v2.test.ts +219 -240
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +0 -3
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
- package/dist/index.d.ts +5 -20
- package/dist/index.js +139 -226
- package/dist/protocols/protocol-v2/features.d.ts +4 -4
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -1
- package/dist/types/settings.d.ts +4 -19
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV3.ts +16 -23
- package/src/api/FirmwareUpdateV4.ts +85 -178
- package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
- package/src/api/protocol-v2/DeviceInfoGet.ts +3 -3
- package/src/data/messages/messages-protocol-v2.json +31 -14
- package/src/device/DeviceStateMapper.ts +15 -15
- package/src/deviceProfile/buildDeviceFeatures.ts +3 -3
- package/src/protocols/protocol-v2/features.ts +6 -6
- package/src/protocols/protocol-v2/resources.ts +10 -49
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +1 -0
- package/src/types/settings.ts +4 -19
|
@@ -28,7 +28,6 @@ import { DevicePool } from '../device/DevicePool';
|
|
|
28
28
|
import {
|
|
29
29
|
PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
|
|
30
30
|
ProtocolV2FirmwareTargetType,
|
|
31
|
-
isLegacyProtocolV2ProtocolInfo,
|
|
32
31
|
} from '../protocols/protocol-v2';
|
|
33
32
|
import { requestProtocolV2DeviceInfo } from '../protocols/protocol-v2/features';
|
|
34
33
|
import {
|
|
@@ -70,6 +69,7 @@ import type {
|
|
|
70
69
|
Features,
|
|
71
70
|
IFirmwareReleaseInfo,
|
|
72
71
|
IProtocolV2FirmwareComponent,
|
|
72
|
+
IProtocolV2ResourceManifestFile,
|
|
73
73
|
IVersionArray,
|
|
74
74
|
} from '../types';
|
|
75
75
|
import type { FirmwareByteSource } from './firmware/FirmwareArtifactSource';
|
|
@@ -89,7 +89,6 @@ const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
|
|
|
89
89
|
const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 3 * 60 * 1000;
|
|
90
90
|
const PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT = 5 * 1000;
|
|
91
91
|
const PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT = 15 * 1000;
|
|
92
|
-
const PROTOCOL_V2_START_UPDATE_TIMEOUT = 3 * 60 * 1000;
|
|
93
92
|
const PROTOCOL_V2_INSTALL_TIMEOUT = 8 * 60 * 1000;
|
|
94
93
|
const PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT = 30 * 1000;
|
|
95
94
|
const PROTOCOL_V2_TARGET_STATUS_PENDING = 0;
|
|
@@ -113,6 +112,13 @@ const PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES = 1024 * 1024;
|
|
|
113
112
|
const PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT = 512;
|
|
114
113
|
const PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
|
|
115
114
|
|
|
115
|
+
const getProtocolV2LocalResourceArchivePath = (entryName: string) => {
|
|
116
|
+
const match = entryName.match(
|
|
117
|
+
/(?:^|\/)((?:bundles\/|loaders\/(?:bootloader|rom)\/).+\.okpkg)$/iu
|
|
118
|
+
);
|
|
119
|
+
return match?.[1];
|
|
120
|
+
};
|
|
121
|
+
|
|
116
122
|
const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set<FirmwareUpdateV4Target>(['se03', 'se04']);
|
|
117
123
|
|
|
118
124
|
const getProtocolV2ZipEntrySizes = (entry: JSZip.JSZipObject) => {
|
|
@@ -181,14 +187,11 @@ const getProtocolV2DeviceTransferProgress = (
|
|
|
181
187
|
totalBytes: number
|
|
182
188
|
) => {
|
|
183
189
|
if (!Number.isFinite(totalBytes) || totalBytes <= 0) {
|
|
184
|
-
return
|
|
190
|
+
return 0;
|
|
185
191
|
}
|
|
186
192
|
if (bytesBeforeChunk <= 0 && bytesAfterChunk < totalBytes) {
|
|
187
193
|
return 0;
|
|
188
194
|
}
|
|
189
|
-
if (bytesAfterChunk >= totalBytes) {
|
|
190
|
-
return 100;
|
|
191
|
-
}
|
|
192
195
|
return Math.min(Math.max(Math.ceil((bytesAfterChunk / totalBytes) * 100), 1), 99);
|
|
193
196
|
};
|
|
194
197
|
|
|
@@ -199,8 +202,6 @@ type ProtocolV2FirmwareUpdateStatusTarget = {
|
|
|
199
202
|
path?: string;
|
|
200
203
|
};
|
|
201
204
|
|
|
202
|
-
type ProtocolV2FirmwareUpdateStartResponse = TypedResponseMessage<'Success'>;
|
|
203
|
-
|
|
204
205
|
type ProtocolV2TargetBinary = { fileName: string; binary: ArrayBuffer; targetId: number };
|
|
205
206
|
type ProtocolV2InstallItem = ProtocolV2TargetBinary & {
|
|
206
207
|
kind: ProtocolV2RemoteComponentTarget['kind'];
|
|
@@ -377,31 +378,6 @@ const isProtocolV2ReconnectProbeError = (error: unknown) => {
|
|
|
377
378
|
);
|
|
378
379
|
};
|
|
379
380
|
|
|
380
|
-
const PROTOCOL_V2_BLE_INSTALL_INTERRUPTION_ERROR_CODES = new Set<number>([
|
|
381
|
-
HardwareErrorCode.BleConnectedError,
|
|
382
|
-
HardwareErrorCode.BleCharacteristicNotifyError,
|
|
383
|
-
HardwareErrorCode.BleForceCleanRunPromise,
|
|
384
|
-
HardwareErrorCode.BleDeviceDisconnected,
|
|
385
|
-
]);
|
|
386
|
-
|
|
387
|
-
const isProtocolV2BleInstallInterruptionError = (error: unknown) => {
|
|
388
|
-
if (
|
|
389
|
-
error instanceof HardwareError &&
|
|
390
|
-
PROTOCOL_V2_BLE_INSTALL_INTERRUPTION_ERROR_CODES.has(error.errorCode)
|
|
391
|
-
) {
|
|
392
|
-
return true;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
396
|
-
const compactMessage = message.replace(/\s+/gu, '');
|
|
397
|
-
return (
|
|
398
|
-
/react native ble transport (?:released|disconnected)/u.test(message) ||
|
|
399
|
-
(compactMessage.includes('rxerrorerror6') &&
|
|
400
|
-
(compactMessage.includes('multiplatformbleadapter') ||
|
|
401
|
-
compactMessage.includes('multipalformebleadapter')))
|
|
402
|
-
);
|
|
403
|
-
};
|
|
404
|
-
|
|
405
381
|
const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
|
|
406
382
|
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
407
383
|
return (
|
|
@@ -411,15 +387,6 @@ const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
|
|
|
411
387
|
);
|
|
412
388
|
};
|
|
413
389
|
|
|
414
|
-
const isProtocolV2FirmwareUpdateEndpointUnavailable = (error: unknown) => {
|
|
415
|
-
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
416
|
-
return (
|
|
417
|
-
message.includes('handler not registered') ||
|
|
418
|
-
message.includes('message handler not found') ||
|
|
419
|
-
message.includes('unsupported message')
|
|
420
|
-
);
|
|
421
|
-
};
|
|
422
|
-
|
|
423
390
|
const isProtocolV2TerminalInstallStatusError = (error: unknown) =>
|
|
424
391
|
error instanceof HardwareError &&
|
|
425
392
|
(error.errorCode === HardwareErrorCode.FirmwareError ||
|
|
@@ -596,7 +563,7 @@ export const assertProtocolV2ReconnectIdentity = (
|
|
|
596
563
|
*
|
|
597
564
|
* It intentionally does not fall back to FirmwareUpdateV3/V1 behavior:
|
|
598
565
|
* - upload uses FilesystemFileWrite
|
|
599
|
-
* - install uses DeviceFirmwareUpdateRequest
|
|
566
|
+
* - install uses DeviceFirmwareUpdateStage followed by an empty DeviceFirmwareUpdateRequest
|
|
600
567
|
* - completion waits for target status to finish, reboots to normal, then polls DeviceInfo
|
|
601
568
|
*/
|
|
602
569
|
export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
|
|
@@ -614,8 +581,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
614
581
|
|
|
615
582
|
private protocolV2ExecutionInLoader = false;
|
|
616
583
|
|
|
617
|
-
private protocolV2LegacyDirectUpdate = false;
|
|
618
|
-
|
|
619
584
|
private protocolV2BootResourceStagingSafe = false;
|
|
620
585
|
|
|
621
586
|
private protocolV2CompletedTargetVersions = new Map<number, number>();
|
|
@@ -624,8 +589,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
624
589
|
|
|
625
590
|
private protocolV2FinalStatusVerified = false;
|
|
626
591
|
|
|
627
|
-
private protocolV2InstallAckReceived = false;
|
|
628
|
-
|
|
629
592
|
private protocolV2InstallBaselineVersions = new Map<number, string>();
|
|
630
593
|
|
|
631
594
|
private protocolV2LastRuntimeProbeFeatures?: Features;
|
|
@@ -1293,92 +1256,86 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1293
1256
|
);
|
|
1294
1257
|
}
|
|
1295
1258
|
const entries = zipEntries.filter(entry => !entry.dir);
|
|
1296
|
-
if (entries.length === 0
|
|
1259
|
+
if (entries.length === 0) {
|
|
1297
1260
|
throw ERRORS.TypedError(
|
|
1298
1261
|
HardwareErrorCode.RuntimeError,
|
|
1299
1262
|
'Protocol V2 local resource ZIP entry set is invalid',
|
|
1300
1263
|
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1301
1264
|
);
|
|
1302
1265
|
}
|
|
1303
|
-
|
|
1304
|
-
let
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
declaredUncompressedSize += sizes.uncompressedSize;
|
|
1309
|
-
const entryLimit =
|
|
1310
|
-
entry.name === 'manifest.json'
|
|
1311
|
-
? PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
|
|
1312
|
-
: PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES;
|
|
1266
|
+
const manifestEntry = entries.find(entry => entry.name.split('/').pop() === 'manifest.json');
|
|
1267
|
+
let manifestBinary: ArrayBuffer | undefined;
|
|
1268
|
+
let manifestDirectory = '';
|
|
1269
|
+
let selectedFiles: IProtocolV2ResourceManifestFile[];
|
|
1270
|
+
if (manifestEntry) {
|
|
1313
1271
|
if (
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
declaredUncompressedSize >
|
|
1317
|
-
PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES + PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
|
|
1272
|
+
getProtocolV2ZipEntrySizes(manifestEntry).uncompressedSize >
|
|
1273
|
+
PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
|
|
1318
1274
|
) {
|
|
1319
1275
|
throw ERRORS.TypedError(
|
|
1320
1276
|
HardwareErrorCode.RuntimeError,
|
|
1321
|
-
'Protocol V2 local resource
|
|
1277
|
+
'Protocol V2 local resource manifest size is invalid',
|
|
1322
1278
|
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1323
1279
|
);
|
|
1324
1280
|
}
|
|
1281
|
+
manifestBinary = await manifestEntry.async('arraybuffer');
|
|
1282
|
+
if (
|
|
1283
|
+
manifestBinary.byteLength <= 0 ||
|
|
1284
|
+
manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
|
|
1285
|
+
) {
|
|
1286
|
+
throw ERRORS.TypedError(
|
|
1287
|
+
HardwareErrorCode.RuntimeError,
|
|
1288
|
+
'Protocol V2 local resource manifest size is invalid',
|
|
1289
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
let manifestValue: unknown;
|
|
1293
|
+
try {
|
|
1294
|
+
manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
|
|
1295
|
+
} catch (error) {
|
|
1296
|
+
throw ERRORS.TypedError(
|
|
1297
|
+
HardwareErrorCode.RuntimeError,
|
|
1298
|
+
`Protocol V2 local resource manifest is invalid: ${String(error)}`,
|
|
1299
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1300
|
+
);
|
|
1301
|
+
}
|
|
1302
|
+
selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
1303
|
+
manifest: parseProtocolV2ResourceManifest(manifestValue),
|
|
1304
|
+
targetsToUpdate: this.params.targetsToUpdate ?? [],
|
|
1305
|
+
});
|
|
1306
|
+
manifestDirectory = manifestEntry.name.slice(0, -'manifest.json'.length);
|
|
1307
|
+
} else {
|
|
1308
|
+
selectedFiles = entries.flatMap(entry => {
|
|
1309
|
+
const archivePath = getProtocolV2LocalResourceArchivePath(entry.name);
|
|
1310
|
+
if (!archivePath) return [];
|
|
1311
|
+
return [
|
|
1312
|
+
{
|
|
1313
|
+
archive_path: archivePath,
|
|
1314
|
+
original_name: archivePath.split('/').pop() ?? archivePath,
|
|
1315
|
+
device_path: `vol0:/${archivePath}`,
|
|
1316
|
+
size: getProtocolV2ZipEntrySizes(entry).uncompressedSize,
|
|
1317
|
+
sha256: '',
|
|
1318
|
+
},
|
|
1319
|
+
];
|
|
1320
|
+
});
|
|
1325
1321
|
}
|
|
1326
|
-
|
|
1327
|
-
if (!manifestEntry) {
|
|
1328
|
-
throw ERRORS.TypedError(
|
|
1329
|
-
HardwareErrorCode.RuntimeError,
|
|
1330
|
-
'Protocol V2 local resource ZIP has no manifest.json',
|
|
1331
|
-
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1332
|
-
);
|
|
1333
|
-
}
|
|
1334
|
-
const manifestBinary = await manifestEntry.async('arraybuffer');
|
|
1335
|
-
if (
|
|
1336
|
-
manifestBinary.byteLength <= 0 ||
|
|
1337
|
-
manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
|
|
1338
|
-
) {
|
|
1339
|
-
throw ERRORS.TypedError(
|
|
1340
|
-
HardwareErrorCode.RuntimeError,
|
|
1341
|
-
'Protocol V2 local resource manifest size is invalid',
|
|
1342
|
-
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1343
|
-
);
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
let manifestValue: unknown;
|
|
1347
|
-
try {
|
|
1348
|
-
manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
|
|
1349
|
-
} catch (error) {
|
|
1350
|
-
throw ERRORS.TypedError(
|
|
1351
|
-
HardwareErrorCode.RuntimeError,
|
|
1352
|
-
`Protocol V2 local resource manifest is invalid: ${String(error)}`,
|
|
1353
|
-
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1354
|
-
);
|
|
1355
|
-
}
|
|
1356
|
-
const manifest = parseProtocolV2ResourceManifest(manifestValue);
|
|
1357
|
-
const selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
1358
|
-
manifest,
|
|
1359
|
-
targetsToUpdate: this.params.targetsToUpdate ?? [],
|
|
1360
|
-
});
|
|
1361
|
-
const expectedEntryNames = new Set([
|
|
1362
|
-
'manifest.json',
|
|
1363
|
-
...selectedFiles.map(file => file.archive_path),
|
|
1364
|
-
]);
|
|
1365
|
-
if (
|
|
1366
|
-
entries.length !== expectedEntryNames.size ||
|
|
1367
|
-
entries.some(entry => !expectedEntryNames.has(entry.name))
|
|
1368
|
-
) {
|
|
1322
|
+
if (selectedFiles.length === 0 || selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
|
|
1369
1323
|
throw ERRORS.TypedError(
|
|
1370
1324
|
HardwareErrorCode.RuntimeError,
|
|
1371
|
-
'Protocol V2 local resource ZIP
|
|
1325
|
+
'Protocol V2 local resource ZIP has no resource packages',
|
|
1372
1326
|
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1373
1327
|
);
|
|
1374
1328
|
}
|
|
1375
1329
|
|
|
1376
1330
|
let totalSize = 0;
|
|
1377
|
-
const materializedEntries: FirmwareMemoryArtifactEntry[] = [
|
|
1378
|
-
|
|
1379
|
-
];
|
|
1331
|
+
const materializedEntries: FirmwareMemoryArtifactEntry[] = [];
|
|
1332
|
+
const normalizedFiles: IProtocolV2ResourceManifestFile[] = [];
|
|
1380
1333
|
for (const file of selectedFiles) {
|
|
1381
|
-
const entry =
|
|
1334
|
+
const entry = manifestEntry
|
|
1335
|
+
? zip.file(`${manifestDirectory}${file.archive_path}`)
|
|
1336
|
+
: entries.find(
|
|
1337
|
+
candidate => getProtocolV2LocalResourceArchivePath(candidate.name) === file.archive_path
|
|
1338
|
+
);
|
|
1382
1339
|
if (!entry) {
|
|
1383
1340
|
throw ERRORS.TypedError(
|
|
1384
1341
|
HardwareErrorCode.RuntimeError,
|
|
@@ -1397,15 +1354,21 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1397
1354
|
}
|
|
1398
1355
|
const fileBinary = await entry.async('arraybuffer');
|
|
1399
1356
|
const digest = bytesToHex(sha256(new Uint8Array(fileBinary)));
|
|
1400
|
-
if (
|
|
1357
|
+
if (
|
|
1358
|
+
fileBinary.byteLength !== file.size ||
|
|
1359
|
+
(file.sha256 && digest !== file.sha256.toLowerCase())
|
|
1360
|
+
) {
|
|
1401
1361
|
throw ERRORS.TypedError(
|
|
1402
1362
|
HardwareErrorCode.RuntimeError,
|
|
1403
1363
|
`Protocol V2 local resource file does not match manifest: ${file.archive_path}`,
|
|
1404
1364
|
{ firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
|
|
1405
1365
|
);
|
|
1406
1366
|
}
|
|
1367
|
+
normalizedFiles.push({ ...file, sha256: digest });
|
|
1407
1368
|
materializedEntries.push({ entryName: file.archive_path, binary: fileBinary });
|
|
1408
1369
|
}
|
|
1370
|
+
manifestBinary ??= new TextEncoder().encode(JSON.stringify({ files: normalizedFiles })).buffer;
|
|
1371
|
+
materializedEntries.unshift({ entryName: 'manifest.json', binary: manifestBinary });
|
|
1409
1372
|
return { binary, materializedEntries };
|
|
1410
1373
|
}
|
|
1411
1374
|
|
|
@@ -2168,11 +2131,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2168
2131
|
return this.device.features?.mode === 'romloader';
|
|
2169
2132
|
}
|
|
2170
2133
|
|
|
2171
|
-
private isLegacyProtocolV2Runtime() {
|
|
2172
|
-
const protocolInfo = this.device.state?.raw?.protocolV2ProtocolInfo;
|
|
2173
|
-
return protocolInfo ? isLegacyProtocolV2ProtocolInfo(protocolInfo) : false;
|
|
2174
|
-
}
|
|
2175
|
-
|
|
2176
2134
|
private async rebootProtocolV2ToBootloader() {
|
|
2177
2135
|
try {
|
|
2178
2136
|
this.postTipMessage(FirmwareUpdateTipMessage.AutoRebootToBootloader);
|
|
@@ -2192,18 +2150,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2192
2150
|
}
|
|
2193
2151
|
|
|
2194
2152
|
async enterProtocolV2BootloaderMode() {
|
|
2195
|
-
this.protocolV2LegacyDirectUpdate = false;
|
|
2196
2153
|
// romloader is the first update environment and forwards targets to bootloader.
|
|
2197
2154
|
// It rejects DeviceRebootType.Bootloader, so reuse the current connection.
|
|
2198
2155
|
if (this.isProtocolV2RomloaderMode()) {
|
|
2199
2156
|
Log.debug('Protocol V2 device is in romloader mode; start firmware update directly');
|
|
2200
|
-
this.protocolV2LegacyDirectUpdate = this.isLegacyProtocolV2Runtime();
|
|
2201
2157
|
this.protocolV2ExecutionInLoader = true;
|
|
2202
2158
|
return false;
|
|
2203
2159
|
}
|
|
2204
2160
|
if (this.isProtocolV2BootloaderMode()) {
|
|
2205
2161
|
Log.debug('Protocol V2 device is already in bootloader mode, skip reboot');
|
|
2206
|
-
this.protocolV2LegacyDirectUpdate = this.isLegacyProtocolV2Runtime();
|
|
2207
2162
|
this.protocolV2ExecutionInLoader = true;
|
|
2208
2163
|
this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
2209
2164
|
return false;
|
|
@@ -2714,7 +2669,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2714
2669
|
let missingTargetStatusSince: number | undefined;
|
|
2715
2670
|
let missingTargetStatusKey: string | undefined;
|
|
2716
2671
|
let normalModeWithoutInstallEvidenceSince: number | undefined;
|
|
2717
|
-
let installEvidenceObserved =
|
|
2672
|
+
let installEvidenceObserved = false;
|
|
2718
2673
|
const resetMissingTargetStatusGrace = () => {
|
|
2719
2674
|
missingTargetStatusSince = undefined;
|
|
2720
2675
|
missingTargetStatusKey = undefined;
|
|
@@ -2734,7 +2689,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2734
2689
|
try {
|
|
2735
2690
|
const statusResponse = await this.device.getCommands().typedCall(
|
|
2736
2691
|
'DeviceFirmwareUpdateStatusGet',
|
|
2737
|
-
'DeviceFirmwareUpdateStatus',
|
|
2692
|
+
['DeviceFirmwareUpdateStatus', 'Success'],
|
|
2738
2693
|
{
|
|
2739
2694
|
fields: {
|
|
2740
2695
|
status: true,
|
|
@@ -2744,6 +2699,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2744
2699
|
},
|
|
2745
2700
|
{ timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT }
|
|
2746
2701
|
);
|
|
2702
|
+
if (statusResponse.type === 'Success') {
|
|
2703
|
+
this.protocolV2FinalStatusVerified = true;
|
|
2704
|
+
this.postProgressMessage(100, 'installingFirmware');
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2747
2707
|
const statusTargets = (statusResponse.message.records ??
|
|
2748
2708
|
[]) as ProtocolV2FirmwareUpdateStatusTarget[];
|
|
2749
2709
|
if (
|
|
@@ -3148,65 +3108,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
3148
3108
|
}: {
|
|
3149
3109
|
targets: Array<{ target_id: number; path: string }>;
|
|
3150
3110
|
}) {
|
|
3151
|
-
this.protocolV2InstallAckReceived = false;
|
|
3152
3111
|
this.protocolV2LastRuntimeProbeFeatures = undefined;
|
|
3153
|
-
const
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
.typedCall(
|
|
3157
|
-
'DeviceFirmwareUpdateRequest',
|
|
3158
|
-
'Success',
|
|
3159
|
-
{ targets },
|
|
3160
|
-
{ timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT }
|
|
3161
|
-
);
|
|
3162
|
-
let response: ProtocolV2FirmwareUpdateStartResponse | undefined;
|
|
3163
|
-
try {
|
|
3164
|
-
response = await startUpdate();
|
|
3165
|
-
this.protocolV2InstallAckReceived = true;
|
|
3166
|
-
} catch (error) {
|
|
3167
|
-
if (this.isBleReconnect() && isProtocolV2BleInstallInterruptionError(error)) {
|
|
3168
|
-
this.throwIfAborted();
|
|
3169
|
-
// Installation can reboot the device before the Success response reaches
|
|
3170
|
-
// the host. The request has side effects, so do not replay it; reconnect
|
|
3171
|
-
// and let status polling determine whether installation was accepted.
|
|
3172
|
-
Log.log(
|
|
3173
|
-
'[FirmwareUpdateV4] install request interrupted by device reboot; continue status polling: ',
|
|
3174
|
-
error
|
|
3175
|
-
);
|
|
3176
|
-
} else if (
|
|
3177
|
-
this.protocolV2LegacyDirectUpdate &&
|
|
3178
|
-
isProtocolV2FirmwareUpdateEndpointUnavailable(error)
|
|
3179
|
-
) {
|
|
3180
|
-
// Both legacy loaders register this request. A missing handler therefore identifies
|
|
3181
|
-
// a legacy App before dispatch, so it is safe to reboot and retry the unhandled request.
|
|
3182
|
-
this.protocolV2LegacyDirectUpdate = false;
|
|
3183
|
-
Log.debug(
|
|
3184
|
-
'[FirmwareUpdateV4] legacy App does not expose DeviceFirmwareUpdateRequest; rebooting to bootloader'
|
|
3185
|
-
);
|
|
3186
|
-
await this.rebootProtocolV2ToBootloader();
|
|
3187
|
-
try {
|
|
3188
|
-
response = await startUpdate();
|
|
3189
|
-
this.protocolV2InstallAckReceived = true;
|
|
3190
|
-
} catch (retryError) {
|
|
3191
|
-
if (!(this.isBleReconnect() && isProtocolV2BleInstallInterruptionError(retryError))) {
|
|
3192
|
-
throw retryError;
|
|
3193
|
-
}
|
|
3194
|
-
this.throwIfAborted();
|
|
3195
|
-
Log.log(
|
|
3196
|
-
'[FirmwareUpdateV4] install request interrupted after legacy reboot; continue status polling: ',
|
|
3197
|
-
retryError
|
|
3198
|
-
);
|
|
3199
|
-
}
|
|
3200
|
-
} else {
|
|
3201
|
-
throw error;
|
|
3202
|
-
}
|
|
3203
|
-
}
|
|
3204
|
-
this.protocolV2LegacyDirectUpdate = false;
|
|
3205
|
-
// A Success ACK or an install-time disconnect both end confirmation. In the
|
|
3206
|
-
// latter case only status polling may establish the final outcome.
|
|
3112
|
+
const commands = this.device.getCommands();
|
|
3113
|
+
await commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
|
|
3114
|
+
await commands.call('DeviceFirmwareUpdateRequest', {}, { returnAfterWrite: true });
|
|
3207
3115
|
this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdating);
|
|
3208
3116
|
this.postProgressMessage(0, 'installingFirmware');
|
|
3209
|
-
return response;
|
|
3210
3117
|
}
|
|
3211
3118
|
|
|
3212
3119
|
private async protocolV2Reboot(rebootType: DeviceRebootType) {
|
|
@@ -25,7 +25,7 @@ export default class DeviceFactoryInfoSet extends BaseMethod<DeviceFactoryInfoSe
|
|
|
25
25
|
info: {
|
|
26
26
|
version: this.params.version,
|
|
27
27
|
serial_number: this.params.serial_number,
|
|
28
|
-
|
|
28
|
+
factory_burn_in_completed: this.params.burn_in_completed,
|
|
29
29
|
factory_test_completed: this.params.factory_test_completed,
|
|
30
30
|
manufacture_time: this.params.manufacture_time,
|
|
31
31
|
},
|
|
@@ -5,7 +5,7 @@ import { invalidParameter } from '../helpers/filesystemValidation';
|
|
|
5
5
|
|
|
6
6
|
export type DeviceInfoGetTargets = {
|
|
7
7
|
hw?: boolean;
|
|
8
|
-
|
|
8
|
+
main_mcu?: boolean;
|
|
9
9
|
coprocessor?: boolean;
|
|
10
10
|
se1?: boolean;
|
|
11
11
|
se2?: boolean;
|
|
@@ -27,7 +27,7 @@ export type DeviceInfoGetParams = {
|
|
|
27
27
|
|
|
28
28
|
const TARGET_KEYS: (keyof DeviceInfoGetTargets)[] = [
|
|
29
29
|
'hw',
|
|
30
|
-
'
|
|
30
|
+
'main_mcu',
|
|
31
31
|
'coprocessor',
|
|
32
32
|
'se1',
|
|
33
33
|
'se2',
|
|
@@ -39,7 +39,7 @@ const TYPE_KEYS: (keyof DeviceInfoGetTypes)[] = ['version', 'build_id', 'hash',
|
|
|
39
39
|
|
|
40
40
|
const DEFAULT_TARGETS: DeviceInfoGetTargets = {
|
|
41
41
|
hw: true,
|
|
42
|
-
|
|
42
|
+
main_mcu: true,
|
|
43
43
|
coprocessor: true,
|
|
44
44
|
};
|
|
45
45
|
|
|
@@ -462,9 +462,10 @@
|
|
|
462
462
|
"MessageType_FilesystemDirMake": 60809,
|
|
463
463
|
"MessageType_FilesystemDirRemove": 60810,
|
|
464
464
|
"MessageType_FilesystemFormat": 60811,
|
|
465
|
-
"
|
|
466
|
-
"
|
|
467
|
-
"
|
|
465
|
+
"MessageType_DeviceFirmwareUpdateStage": 61000,
|
|
466
|
+
"MessageType_DeviceFirmwareUpdateRequest": 61001,
|
|
467
|
+
"MessageType_DeviceFirmwareUpdateStatusGet": 61002,
|
|
468
|
+
"MessageType_DeviceFirmwareUpdateStatus": 61003,
|
|
468
469
|
"MessageType_DeviceSessionGet": 61200,
|
|
469
470
|
"MessageType_DeviceSession": 61201,
|
|
470
471
|
"MessageType_DeviceSessionAskPin": 61202,
|
|
@@ -10924,7 +10925,7 @@
|
|
|
10924
10925
|
"type": "bytes",
|
|
10925
10926
|
"id": 1
|
|
10926
10927
|
},
|
|
10927
|
-
"
|
|
10928
|
+
"signning_message": {
|
|
10928
10929
|
"type": "bytes",
|
|
10929
10930
|
"id": 2
|
|
10930
10931
|
},
|
|
@@ -11813,14 +11814,14 @@
|
|
|
11813
11814
|
"type": "string",
|
|
11814
11815
|
"id": 2
|
|
11815
11816
|
},
|
|
11816
|
-
"burn_in_completed": {
|
|
11817
|
-
"type": "bool",
|
|
11818
|
-
"id": 3
|
|
11819
|
-
},
|
|
11820
11817
|
"factory_test_completed": {
|
|
11821
11818
|
"type": "bool",
|
|
11822
11819
|
"id": 4
|
|
11823
11820
|
},
|
|
11821
|
+
"factory_burn_in_completed": {
|
|
11822
|
+
"type": "bool",
|
|
11823
|
+
"id": 3
|
|
11824
|
+
},
|
|
11824
11825
|
"manufacture_time": {
|
|
11825
11826
|
"type": "DeviceFactoryInfoManufactureTime",
|
|
11826
11827
|
"id": 5
|
|
@@ -11906,7 +11907,7 @@
|
|
|
11906
11907
|
}
|
|
11907
11908
|
}
|
|
11908
11909
|
},
|
|
11909
|
-
"
|
|
11910
|
+
"DeviceFirmwareUpdateStage": {
|
|
11910
11911
|
"fields": {
|
|
11911
11912
|
"targets": {
|
|
11912
11913
|
"rule": "repeated",
|
|
@@ -11915,6 +11916,9 @@
|
|
|
11915
11916
|
}
|
|
11916
11917
|
}
|
|
11917
11918
|
},
|
|
11919
|
+
"DeviceFirmwareUpdateRequest": {
|
|
11920
|
+
"fields": {}
|
|
11921
|
+
},
|
|
11918
11922
|
"DeviceFirmwareUpdateRecord": {
|
|
11919
11923
|
"fields": {
|
|
11920
11924
|
"target_id": {
|
|
@@ -12096,7 +12100,7 @@
|
|
|
12096
12100
|
"type": "bool",
|
|
12097
12101
|
"id": 100
|
|
12098
12102
|
},
|
|
12099
|
-
"
|
|
12103
|
+
"main_mcu": {
|
|
12100
12104
|
"type": "bool",
|
|
12101
12105
|
"id": 200
|
|
12102
12106
|
},
|
|
@@ -12165,7 +12169,7 @@
|
|
|
12165
12169
|
"type": "DeviceHardwareInfo",
|
|
12166
12170
|
"id": 100
|
|
12167
12171
|
},
|
|
12168
|
-
"
|
|
12172
|
+
"main_mcu": {
|
|
12169
12173
|
"type": "DeviceMainMcuInfo",
|
|
12170
12174
|
"id": 200
|
|
12171
12175
|
},
|
|
@@ -12703,9 +12707,12 @@
|
|
|
12703
12707
|
"id": 1
|
|
12704
12708
|
},
|
|
12705
12709
|
"text": {
|
|
12706
|
-
"rule": "required",
|
|
12707
12710
|
"type": "string",
|
|
12708
12711
|
"id": 2
|
|
12712
|
+
},
|
|
12713
|
+
"text_id": {
|
|
12714
|
+
"type": "uint32",
|
|
12715
|
+
"id": 3
|
|
12709
12716
|
}
|
|
12710
12717
|
}
|
|
12711
12718
|
},
|
|
@@ -12736,7 +12743,6 @@
|
|
|
12736
12743
|
"ViewSignPage": {
|
|
12737
12744
|
"fields": {
|
|
12738
12745
|
"title": {
|
|
12739
|
-
"rule": "required",
|
|
12740
12746
|
"type": "string",
|
|
12741
12747
|
"id": 1
|
|
12742
12748
|
},
|
|
@@ -12770,13 +12776,16 @@
|
|
|
12770
12776
|
"options": {
|
|
12771
12777
|
"default": "LayoutDefault"
|
|
12772
12778
|
}
|
|
12779
|
+
},
|
|
12780
|
+
"title_id": {
|
|
12781
|
+
"type": "uint32",
|
|
12782
|
+
"id": 8
|
|
12773
12783
|
}
|
|
12774
12784
|
}
|
|
12775
12785
|
},
|
|
12776
12786
|
"ViewVerifyPage": {
|
|
12777
12787
|
"fields": {
|
|
12778
12788
|
"title": {
|
|
12779
|
-
"rule": "required",
|
|
12780
12789
|
"type": "string",
|
|
12781
12790
|
"id": 1
|
|
12782
12791
|
},
|
|
@@ -12801,6 +12810,14 @@
|
|
|
12801
12810
|
"value_key": {
|
|
12802
12811
|
"type": "uint32",
|
|
12803
12812
|
"id": 6
|
|
12813
|
+
},
|
|
12814
|
+
"title_id": {
|
|
12815
|
+
"type": "uint32",
|
|
12816
|
+
"id": 7
|
|
12817
|
+
},
|
|
12818
|
+
"chain_id": {
|
|
12819
|
+
"type": "uint32",
|
|
12820
|
+
"id": 8
|
|
12804
12821
|
}
|
|
12805
12822
|
}
|
|
12806
12823
|
},
|
|
@@ -267,11 +267,11 @@ export const mapProtocolV2DeviceInfoToState = (
|
|
|
267
267
|
}
|
|
268
268
|
: { mode },
|
|
269
269
|
versions: definedEntries({
|
|
270
|
-
firmware: imageVersion(info.
|
|
271
|
-
applicationP1: imageVersion(info.
|
|
272
|
-
applicationP2: imageVersion(info.
|
|
273
|
-
bootloader: imageVersion(info.
|
|
274
|
-
board: imageVersion(info.
|
|
270
|
+
firmware: imageVersion(info.main_mcu?.application),
|
|
271
|
+
applicationP1: imageVersion(info.main_mcu?.application),
|
|
272
|
+
applicationP2: imageVersion(info.main_mcu?.application_data),
|
|
273
|
+
bootloader: imageVersion(info.main_mcu?.bootloader),
|
|
274
|
+
board: imageVersion(info.main_mcu?.romloader),
|
|
275
275
|
ble: imageVersion(info.coprocessor?.application),
|
|
276
276
|
se01: imageVersion(info.se1?.application),
|
|
277
277
|
se02: imageVersion(info.se2?.application),
|
|
@@ -283,16 +283,16 @@ export const mapProtocolV2DeviceInfoToState = (
|
|
|
283
283
|
se04Boot: imageVersion(info.se4?.bootloader),
|
|
284
284
|
}),
|
|
285
285
|
verification: definedEntries({
|
|
286
|
-
firmwareBuildId: imageBuildId(info.
|
|
287
|
-
firmwareHash: imageHash(info.
|
|
288
|
-
applicationP1BuildId: imageBuildId(info.
|
|
289
|
-
applicationP1Hash: imageHash(info.
|
|
290
|
-
applicationP2BuildId: imageBuildId(info.
|
|
291
|
-
applicationP2Hash: imageHash(info.
|
|
292
|
-
bootloaderBuildId: imageBuildId(info.
|
|
293
|
-
bootloaderHash: imageHash(info.
|
|
294
|
-
boardBuildId: imageBuildId(info.
|
|
295
|
-
boardHash: imageHash(info.
|
|
286
|
+
firmwareBuildId: imageBuildId(info.main_mcu?.application),
|
|
287
|
+
firmwareHash: imageHash(info.main_mcu?.application),
|
|
288
|
+
applicationP1BuildId: imageBuildId(info.main_mcu?.application),
|
|
289
|
+
applicationP1Hash: imageHash(info.main_mcu?.application),
|
|
290
|
+
applicationP2BuildId: imageBuildId(info.main_mcu?.application_data),
|
|
291
|
+
applicationP2Hash: imageHash(info.main_mcu?.application_data),
|
|
292
|
+
bootloaderBuildId: imageBuildId(info.main_mcu?.bootloader),
|
|
293
|
+
bootloaderHash: imageHash(info.main_mcu?.bootloader),
|
|
294
|
+
boardBuildId: imageBuildId(info.main_mcu?.romloader),
|
|
295
|
+
boardHash: imageHash(info.main_mcu?.romloader),
|
|
296
296
|
bleBuildId: imageBuildId(info.coprocessor?.application),
|
|
297
297
|
bleHash: imageHash(info.coprocessor?.application),
|
|
298
298
|
se01BuildId: imageBuildId(info.se1?.application),
|
|
@@ -216,9 +216,9 @@ export const buildProtocolV2FeaturesPayload = ({
|
|
|
216
216
|
runtimeMode?: ProtocolV2RuntimeMode;
|
|
217
217
|
}): Features => {
|
|
218
218
|
const info = deviceInfo;
|
|
219
|
-
const fwApplication = info?.
|
|
220
|
-
const fwBootloader = info?.
|
|
221
|
-
const fwBoard = info?.
|
|
219
|
+
const fwApplication = info?.main_mcu?.application;
|
|
220
|
+
const fwBootloader = info?.main_mcu?.bootloader;
|
|
221
|
+
const fwBoard = info?.main_mcu?.romloader;
|
|
222
222
|
const bleApplication = info?.coprocessor?.application;
|
|
223
223
|
const status = deviceStatus;
|
|
224
224
|
const incomingSerialNo = info?.hw?.serial_no;
|