@onekeyfe/hd-core 1.2.0-alpha.19 → 1.2.0-alpha.20
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__/AllNetworkGetAddressBase.tracing.test.ts +75 -0
- package/__tests__/DeviceCommands.test.ts +143 -7
- package/__tests__/RequestQueue.test.ts +106 -0
- package/__tests__/UploadPortfolio.test.ts +46 -0
- package/__tests__/core-dispose.test.ts +34 -0
- package/__tests__/core-error-output.test.ts +39 -0
- package/__tests__/device-lifecycle-events.test.ts +117 -0
- package/__tests__/device-pool-state.test.ts +20 -1
- package/__tests__/device-settings.test.ts +184 -6
- package/__tests__/device-state-events.test.ts +1 -2
- package/__tests__/device-state-mapper.test.ts +33 -26
- package/__tests__/device-state-store.test.ts +1 -34
- package/__tests__/device-utils.test.ts +106 -0
- package/__tests__/device-wallet-session-store.test.ts +65 -29
- package/__tests__/deviceSettings.test.ts +21 -12
- package/__tests__/evmLedgerLegacySafety.test.ts +2 -2
- package/__tests__/evmSignTypedData.test.ts +80 -0
- package/__tests__/filesystemValidation.test.ts +53 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +402 -0
- package/__tests__/get-device-state.test.ts +77 -41
- package/__tests__/logBlockEvent.test.ts +24 -11
- package/__tests__/networkUtils.test.ts +386 -0
- package/__tests__/open-wallet-session-error-response.test.ts +43 -0
- package/__tests__/open-wallet-session.test.ts +559 -0
- package/__tests__/protocol-v2.test.ts +756 -452
- package/__tests__/public-device-state-api.test.ts +113 -13
- package/__tests__/public-pro2-api-boundary.test.ts +91 -0
- package/__tests__/search-devices.test.ts +43 -0
- package/dist/api/BaseMethod.d.ts +3 -0
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
- package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
- package/dist/api/ClearSessionCache.d.ts.map +1 -1
- package/dist/api/DirList.d.ts.map +1 -1
- package/dist/api/FileRead.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +2 -2
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +3 -2
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts +14 -0
- package/dist/api/OpenWalletSession.d.ts.map +1 -0
- package/dist/api/PathInfo.d.ts.map +1 -1
- package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts +3 -0
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
- package/dist/api/device/DeviceFullyUploadResource.d.ts +1 -2
- package/dist/api/device/DeviceFullyUploadResource.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +7 -3
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/helpers/filesystemValidation.d.ts +3 -0
- package/dist/api/helpers/filesystemValidation.d.ts.map +1 -1
- package/dist/api/helpers/paramsValidator.d.ts +1 -0
- package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +7 -11
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceSettingsSet.d.ts.map +1 -1
- package/dist/api/utils.d.ts.map +1 -1
- package/dist/core/RequestQueue.d.ts +17 -1
- package/dist/core/RequestQueue.d.ts.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +6 -5
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +5 -5
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts +1 -0
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts +2 -2
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/device/DeviceStateProjector.d.ts +1 -2
- package/dist/device/DeviceStateProjector.d.ts.map +1 -1
- package/dist/device/DeviceStateStore.d.ts +1 -3
- package/dist/device/DeviceStateStore.d.ts.map +1 -1
- package/dist/device/DeviceWalletSessionStore.d.ts +6 -1
- package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -1
- package/dist/device/cloneDeviceState.d.ts +2 -0
- package/dist/device/cloneDeviceState.d.ts.map +1 -0
- package/dist/deviceProfile/buildDeviceFeatures.d.ts +3 -1
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +608 -75
- package/dist/index.js +2287 -1706
- package/dist/inject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/deviceSession.d.ts +7 -0
- package/dist/protocols/protocol-v2/deviceSession.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/features.d.ts +11 -4
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/index.d.ts +2 -2
- package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts +16 -0
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +8 -3
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -2
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceSettings.d.ts +1 -0
- package/dist/types/api/deviceSettings.d.ts.map +1 -1
- package/dist/types/api/deviceUnlock.d.ts +1 -1
- package/dist/types/api/deviceUnlock.d.ts.map +1 -1
- package/dist/types/api/getFeatures.d.ts.map +1 -1
- package/dist/types/api/getOnekeyFeatures.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +13 -15
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +41 -0
- package/dist/types/api/openWalletSession.d.ts.map +1 -0
- package/dist/types/api/protocolV2.d.ts +6 -11
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts +2 -9
- package/dist/types/device.d.ts.map +1 -1
- package/dist/utils/assets.d.ts +2 -1
- package/dist/utils/assets.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts +13 -0
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -0
- package/dist/utils/deviceFeaturesUtils.d.ts +11 -1
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts +9 -8
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.d.ts +2 -0
- package/dist/utils/deviceSettings.d.ts.map +1 -1
- package/dist/utils/deviceVersionUtils.d.ts +6 -5
- package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/networkUtils.d.ts +9 -1
- package/dist/utils/networkUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +17 -10
- package/src/api/CheckBootloaderRelease.ts +1 -2
- package/src/api/CheckFirmwareRelease.ts +1 -2
- package/src/api/ClearSessionCache.ts +0 -4
- package/src/api/DirList.ts +5 -3
- package/src/api/DirMake.ts +3 -3
- package/src/api/DirRemove.ts +3 -3
- package/src/api/FileDelete.ts +3 -3
- package/src/api/FileRead.ts +9 -6
- package/src/api/FileWrite.ts +3 -3
- package/src/api/FirmwareUpdate.ts +4 -4
- package/src/api/FirmwareUpdateV2.ts +133 -45
- package/src/api/FirmwareUpdateV3.ts +3 -5
- package/src/api/FirmwareUpdateV4.ts +192 -154
- package/src/api/GetPassphraseState.ts +10 -16
- package/src/api/OpenWalletSession.ts +221 -0
- package/src/api/PathInfo.ts +5 -3
- package/src/api/PromptWebDeviceAccess.ts +2 -3
- package/src/api/SearchDevices.ts +6 -2
- package/src/api/UploadPortfolio.ts +12 -3
- package/src/api/alephium/AlephiumSignTransaction.ts +2 -2
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +4 -8
- package/src/api/benfen/BenfenGetAddress.ts +1 -1
- package/src/api/btc/BTCGetPublicKey.ts +1 -1
- package/src/api/device/DeviceChangePin.ts +1 -0
- package/src/api/device/DeviceFullyUploadResource.ts +4 -5
- package/src/api/device/DeviceSettings.ts +93 -0
- package/src/api/device/DeviceUpdateBootloader.ts +1 -2
- package/src/api/device/DeviceWipe.ts +1 -0
- package/src/api/evm/EVMSignTypedData.ts +3 -5
- package/src/api/evm/legacyV1/getAddress.ts +2 -2
- package/src/api/evm/legacyV1/getPublicKey.ts +2 -2
- package/src/api/evm/legacyV1/signMessage.ts +2 -2
- package/src/api/evm/legacyV1/signTypedData.ts +2 -2
- package/src/api/evm/legacyV1/signTypedHash.ts +2 -2
- package/src/api/evm/legacyV1/verifyMessage.ts +2 -2
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +3 -3
- package/src/api/firmware/getBinary.ts +8 -3
- package/src/api/helpers/batchGetPublickeys.ts +2 -2
- package/src/api/helpers/filesystemValidation.ts +61 -0
- package/src/api/helpers/paramsValidator.ts +1 -1
- package/src/api/helpers/protocolV2FileWrite.ts +3 -2
- package/src/api/index.ts +9 -12
- package/src/api/nervos/NervosSignTransaction.ts +2 -2
- package/src/api/nexa/NexaSignTransaction.ts +1 -1
- package/src/api/protocol-v2/DeviceFactoryInfoGet.ts +1 -1
- package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
- package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +4 -4
- package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +6 -5
- package/src/api/protocol-v2/DeviceInfoGet.ts +4 -4
- package/src/api/protocol-v2/DeviceReboot.ts +1 -1
- package/src/api/protocol-v2/DeviceSettingsPageShow.ts +11 -8
- package/src/api/protocol-v2/DeviceSettingsSet.ts +4 -11
- package/src/api/protocol-v2/FilesystemFormat.ts +1 -1
- package/src/api/protocol-v2/FilesystemPermissionFix.ts +1 -1
- package/src/api/protocol-v2/Ping.ts +1 -1
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -1
- package/src/api/utils.ts +1 -3
- package/src/core/RequestQueue.ts +107 -6
- package/src/core/index.ts +91 -46
- package/src/data/messages/messages-protocol-v2.json +25 -79
- package/src/data-manager/DataManager.ts +6 -6
- package/src/device/Device.ts +186 -102
- package/src/device/DeviceCommands.ts +51 -21
- package/src/device/DeviceFeaturesState.ts +4 -4
- package/src/device/DevicePool.ts +17 -3
- package/src/device/DeviceStateMapper.ts +13 -29
- package/src/device/DeviceStateProjector.ts +11 -8
- package/src/device/DeviceStateStore.ts +11 -52
- package/src/device/DeviceWalletSessionStore.ts +31 -4
- package/src/device/cloneDeviceState.ts +39 -0
- package/src/device/deviceIdentity.ts +2 -2
- package/src/deviceProfile/buildDeviceFeatures.ts +29 -88
- package/src/events/logBlockEvent.ts +8 -1
- package/src/inject.ts +14 -24
- package/src/protocols/protocol-v2/deviceSession.ts +24 -0
- package/src/protocols/protocol-v2/features.ts +37 -49
- package/src/protocols/protocol-v2/firmware.ts +1 -1
- package/src/protocols/protocol-v2/index.ts +2 -3
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +61 -0
- package/src/protocols/protocol-v2/uiInteraction.ts +4 -3
- package/src/protocols/protocol-v2/walletSession.ts +57 -146
- package/src/types/api/checkAllFirmwareRelease.ts +1 -2
- package/src/types/api/deviceSettings.ts +1 -0
- package/src/types/api/deviceUnlock.ts +1 -1
- package/src/types/api/firmwareUpdate.ts +5 -5
- package/src/types/api/getDeviceState.ts +1 -1
- package/src/types/api/getFeatures.ts +3 -0
- package/src/types/api/getOnekeyFeatures.ts +3 -0
- package/src/types/api/getPassphraseState.ts +6 -0
- package/src/types/api/index.ts +16 -23
- package/src/types/api/openWalletSession.ts +64 -0
- package/src/types/api/protocolV2.ts +36 -18
- package/src/types/device.ts +20 -14
- package/src/types/params.ts +1 -1
- package/src/types/settings.ts +8 -8
- package/src/utils/assets.ts +4 -1
- package/src/utils/deviceFeaturesCompat.ts +173 -0
- package/src/utils/deviceFeaturesUtils.ts +9 -8
- package/src/utils/deviceInfoUtils.ts +26 -64
- package/src/utils/deviceSettings.ts +18 -11
- package/src/utils/deviceVersionUtils.ts +25 -44
- package/src/utils/findDefectiveBatchDevice.ts +3 -3
- package/src/utils/index.ts +2 -5
- package/src/utils/networkUtils.ts +270 -14
- package/src/utils/pro2Wallpaper.ts +11 -13
- package/src/utils/tracing.ts +2 -2
- package/dist/api/internal.d.ts +0 -4
- package/dist/api/internal.d.ts.map +0 -1
- package/dist/api/protocol-v2/DeviceSessionOpen.d.ts +0 -28
- package/dist/api/protocol-v2/DeviceSessionOpen.d.ts.map +0 -1
- package/src/api/internal.ts +0 -9
- package/src/api/protocol-v2/DeviceSessionOpen.ts +0 -100
|
@@ -22,11 +22,9 @@ import { DevicePool } from '../device/DevicePool';
|
|
|
22
22
|
import {
|
|
23
23
|
PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
|
|
24
24
|
ProtocolV2FirmwareTargetType,
|
|
25
|
-
isProtocolV2LoaderDeviceInfo,
|
|
26
25
|
} from '../protocols/protocol-v2';
|
|
27
26
|
import { requestProtocolV2DeviceInfo } from '../protocols/protocol-v2/features';
|
|
28
27
|
import {
|
|
29
|
-
PROTOCOL_V2_FIRMWARE_UPDATE_RESPONSE_TYPES,
|
|
30
28
|
getProtocolV2UnknownErrorText,
|
|
31
29
|
isProtocolV2DeviceDisconnectedError,
|
|
32
30
|
} from './protocol-v2/helpers';
|
|
@@ -46,6 +44,7 @@ const Log = getLogger(LoggerNames.Method);
|
|
|
46
44
|
|
|
47
45
|
const SESSION_ERROR = 'session not found';
|
|
48
46
|
const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 60 * 1000;
|
|
47
|
+
const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 2 * 60 * 1000;
|
|
49
48
|
const PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT = 5 * 1000;
|
|
50
49
|
const PROTOCOL_V2_START_UPDATE_TIMEOUT = 3 * 60 * 1000;
|
|
51
50
|
const PROTOCOL_V2_INSTALL_TIMEOUT = 5 * 60 * 1000;
|
|
@@ -95,10 +94,7 @@ type ProtocolV2FirmwareUpdateStatusTarget = {
|
|
|
95
94
|
path?: string;
|
|
96
95
|
};
|
|
97
96
|
|
|
98
|
-
type ProtocolV2FirmwareUpdateStartResponse =
|
|
99
|
-
| TypedResponseMessage<'Success'>
|
|
100
|
-
| TypedResponseMessage<'DeviceFirmwareUpdateStatus'>
|
|
101
|
-
| undefined;
|
|
97
|
+
type ProtocolV2FirmwareUpdateStartResponse = TypedResponseMessage<'Success'>;
|
|
102
98
|
|
|
103
99
|
type ProtocolV2TargetBinary = { fileName: string; binary: ArrayBuffer; targetId: number };
|
|
104
100
|
type ProtocolV2InstallItem = ProtocolV2TargetBinary & {
|
|
@@ -115,12 +111,12 @@ type ProtocolV2FileTransferParams = PROTO.FirmwareUpload & {
|
|
|
115
111
|
onTransferredBytes?: (transferredBytes: number) => void;
|
|
116
112
|
};
|
|
117
113
|
|
|
118
|
-
/** RESC bundle okpkg
|
|
114
|
+
/** RESC bundle okpkg written independently to devicePath through FileWrite. */
|
|
119
115
|
type ProtocolV2ResourceBundleBinary = {
|
|
120
116
|
name: string;
|
|
121
117
|
binary: ArrayBuffer;
|
|
122
118
|
devicePath: string;
|
|
123
|
-
/**
|
|
119
|
+
/** Download URL for remote-config mode; omitted in manual mode. */
|
|
124
120
|
url?: string;
|
|
125
121
|
version?: IVersionArray;
|
|
126
122
|
payloadHash?: string;
|
|
@@ -203,8 +199,8 @@ const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map<number, FirmwareUpdateV4T
|
|
|
203
199
|
const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE =
|
|
204
200
|
'FW_MGMT_TARGET_ROMLOADER is not accepted by the current Pro2 bootloader update request. Flash romloader with the loader-specific flow instead of firmwareUpdateV4.';
|
|
205
201
|
|
|
206
|
-
// hd-transport
|
|
207
|
-
//
|
|
202
|
+
// hd-transport historically decodes scalar enums as enum-name strings.
|
|
203
|
+
// Map them back to firmware protocol values before internal comparisons.
|
|
208
204
|
const PROTOCOL_V2_TARGET_ID_BY_DECODED_NAME = new Map<string, number>(
|
|
209
205
|
Object.entries(ProtocolV2FirmwareTargetType).map(([key, value]) => [key, value])
|
|
210
206
|
);
|
|
@@ -230,13 +226,12 @@ const isProtocolV2ReconnectProbeError = (error: unknown) => {
|
|
|
230
226
|
);
|
|
231
227
|
};
|
|
232
228
|
|
|
233
|
-
const
|
|
229
|
+
const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
|
|
234
230
|
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
235
231
|
return (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
message.includes('
|
|
239
|
-
(message.includes('response timeout') && message.includes('devicefirmwareupdaterequest'))
|
|
232
|
+
message.includes('handler not registered') ||
|
|
233
|
+
message.includes('message handler not found') ||
|
|
234
|
+
message.includes('unsupported message')
|
|
240
235
|
);
|
|
241
236
|
};
|
|
242
237
|
|
|
@@ -403,6 +398,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
403
398
|
init() {
|
|
404
399
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
405
400
|
this.requireDeviceMode = [];
|
|
401
|
+
this.unlockPolicy = 'retry-on-locked';
|
|
406
402
|
this.useDevicePassphraseState = false;
|
|
407
403
|
this.skipForceUpdateCheck = true;
|
|
408
404
|
|
|
@@ -495,6 +491,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
495
491
|
let fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
496
492
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
497
493
|
let installItems: ProtocolV2InstallItem[] | undefined;
|
|
494
|
+
let resourceBundles: ProtocolV2ResourceBundleBinary[] | undefined;
|
|
498
495
|
try {
|
|
499
496
|
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
500
497
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
@@ -508,13 +505,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
508
505
|
fwBinaryMap = remoteBinaries.fwBinaryMap;
|
|
509
506
|
installItems = remoteBinaries.installItems;
|
|
510
507
|
}
|
|
508
|
+
resourceBundles = this.prepareProtocolV2ResourceBundles(firmwareType, deviceFeatures);
|
|
509
|
+
if (resourceBundles?.length) {
|
|
510
|
+
resourceBundles = await this.prefetchProtocolV2ResourceBundles(resourceBundles);
|
|
511
|
+
}
|
|
511
512
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
512
513
|
} catch (err) {
|
|
513
514
|
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
|
|
514
515
|
}
|
|
515
516
|
|
|
516
|
-
const resourceBundles = this.prepareProtocolV2ResourceBundles(firmwareType, deviceFeatures);
|
|
517
|
-
|
|
518
517
|
if (!bootloaderBinary && fwBinaryMap.length === 0 && !resourceBundles?.length) {
|
|
519
518
|
throw ERRORS.TypedError(
|
|
520
519
|
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
@@ -742,22 +741,22 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
742
741
|
}
|
|
743
742
|
|
|
744
743
|
// ============================================================
|
|
745
|
-
// RESC bundle
|
|
744
|
+
// Incremental RESC bundle sync through FileRead and FilesystemFileWrite
|
|
746
745
|
// ============================================================
|
|
747
746
|
|
|
748
747
|
/**
|
|
749
|
-
*
|
|
748
|
+
* Prepare the RESC bundle list.
|
|
750
749
|
*
|
|
751
|
-
*
|
|
752
|
-
* -
|
|
753
|
-
* -
|
|
754
|
-
*
|
|
750
|
+
* Two modes, matching FirmwareUpdateV3 binary-versus-version behavior:
|
|
751
|
+
* - resourceBundleFiles supplied: use binaries directly without version checks.
|
|
752
|
+
* - Otherwise load release.resourceBundles from remote config.json; the binaries
|
|
753
|
+
* are prefetched before reboot and synchronization skips matching device headers.
|
|
755
754
|
*/
|
|
756
755
|
private prepareProtocolV2ResourceBundles(
|
|
757
756
|
firmwareType: EFirmwareType,
|
|
758
757
|
features: Features
|
|
759
758
|
): ProtocolV2ResourceBundleBinary[] | undefined {
|
|
760
|
-
//
|
|
759
|
+
// Manual binaries are installed directly without comparison.
|
|
761
760
|
if (this.params.resourceBundleFiles?.length) {
|
|
762
761
|
return this.params.resourceBundleFiles.map(file => ({
|
|
763
762
|
name: file.devicePath.split('/').pop() ?? file.devicePath,
|
|
@@ -770,7 +769,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
770
769
|
return undefined;
|
|
771
770
|
}
|
|
772
771
|
|
|
773
|
-
//
|
|
772
|
+
// Remote-config bundles are downloaded and compared later.
|
|
774
773
|
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
775
774
|
if (!release?.resourceBundles?.length) return undefined;
|
|
776
775
|
|
|
@@ -785,11 +784,32 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
785
784
|
})) as ProtocolV2ResourceBundleBinary[];
|
|
786
785
|
}
|
|
787
786
|
|
|
787
|
+
private async prefetchProtocolV2ResourceBundles(
|
|
788
|
+
bundles: ProtocolV2ResourceBundleBinary[]
|
|
789
|
+
): Promise<ProtocolV2ResourceBundleBinary[]> {
|
|
790
|
+
const prefetched: ProtocolV2ResourceBundleBinary[] = [];
|
|
791
|
+
for (const bundle of bundles) {
|
|
792
|
+
let { binary } = bundle;
|
|
793
|
+
if (binary.byteLength === 0) {
|
|
794
|
+
if (!bundle.url) {
|
|
795
|
+
throw new Error(`Missing Protocol V2 RESC bundle binary: ${bundle.name}`);
|
|
796
|
+
}
|
|
797
|
+
Log.log(`[FirmwareUpdateV4] downloading RESC bundle ${bundle.name} from ${bundle.url}`);
|
|
798
|
+
({ binary } = await getSysResourceBinary(bundle.url));
|
|
799
|
+
}
|
|
800
|
+
if (binary.byteLength === 0) {
|
|
801
|
+
throw new Error(`Protocol V2 RESC bundle is empty: ${bundle.name}`);
|
|
802
|
+
}
|
|
803
|
+
prefetched.push({ ...bundle, binary });
|
|
804
|
+
}
|
|
805
|
+
return prefetched;
|
|
806
|
+
}
|
|
807
|
+
|
|
788
808
|
/**
|
|
789
|
-
*
|
|
809
|
+
* Synchronize RESC bundles to the device.
|
|
790
810
|
*
|
|
791
|
-
*
|
|
792
|
-
*
|
|
811
|
+
* Manual mode writes supplied binaries directly.
|
|
812
|
+
* Remote-config mode uses prefetched binaries and skips matching bundles after FileRead.
|
|
793
813
|
*/
|
|
794
814
|
private async syncProtocolV2ResourceBundles(
|
|
795
815
|
bundles: ProtocolV2ResourceBundleBinary[],
|
|
@@ -798,20 +818,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
798
818
|
const transferStartTime = Date.now();
|
|
799
819
|
const transferTransport = this.getProtocolV2FirmwareTransferTransport();
|
|
800
820
|
|
|
801
|
-
const
|
|
821
|
+
const isRemoteMode = bundles.some(bundle => !!bundle.url);
|
|
802
822
|
let bundlesToSync = bundles;
|
|
803
823
|
|
|
804
|
-
//
|
|
805
|
-
|
|
824
|
+
// Remote binaries were prefetched before bootloader entry. Only device-local
|
|
825
|
+
// header comparison and transfer are allowed in this phase.
|
|
826
|
+
if (isRemoteMode) {
|
|
806
827
|
const filtered: ProtocolV2ResourceBundleBinary[] = [];
|
|
807
828
|
for (const bundle of bundles) {
|
|
808
|
-
//
|
|
809
|
-
if (bundle.binary.byteLength === 0 && bundle.url) {
|
|
810
|
-
Log.log(`[FirmwareUpdateV4] downloading RESC bundle ${bundle.name} from ${bundle.url}`);
|
|
811
|
-
const { binary } = await getSysResourceBinary(bundle.url);
|
|
812
|
-
bundle.binary = binary;
|
|
813
|
-
}
|
|
814
|
-
// 比对设备上已有 header
|
|
829
|
+
// Compare the existing device header.
|
|
815
830
|
const upToDate = await this.isProtocolV2ResourceBundleUpToDate(bundle);
|
|
816
831
|
if (upToDate) {
|
|
817
832
|
Log.log(`[FirmwareUpdateV4] skip RESC bundle ${bundle.name}; already up to date`);
|
|
@@ -827,7 +842,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
827
842
|
return { processedSize: 0, totalSize: firmwareSize };
|
|
828
843
|
}
|
|
829
844
|
|
|
830
|
-
// FileWrite
|
|
845
|
+
// Write directly to the device through FileWrite.
|
|
831
846
|
let totalSize = 0;
|
|
832
847
|
for (const b of bundlesToSync) totalSize += b.binary.byteLength;
|
|
833
848
|
|
|
@@ -855,7 +870,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
855
870
|
}
|
|
856
871
|
|
|
857
872
|
/**
|
|
858
|
-
*
|
|
873
|
+
* Compare the existing okpkg OKPP header in remote-config mode.
|
|
859
874
|
*/
|
|
860
875
|
private async isProtocolV2ResourceBundleUpToDate(
|
|
861
876
|
bundle: ProtocolV2ResourceBundleBinary
|
|
@@ -894,8 +909,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
894
909
|
}
|
|
895
910
|
|
|
896
911
|
async enterProtocolV2BootloaderMode() {
|
|
897
|
-
// romloader
|
|
898
|
-
//
|
|
912
|
+
// romloader is the first update environment and forwards targets to bootloader.
|
|
913
|
+
// It rejects DeviceRebootType.Bootloader, so reuse the current connection.
|
|
899
914
|
if (this.isProtocolV2BootloaderMode() || this.device.features?.mode === 'romloader') {
|
|
900
915
|
Log.debug('Protocol V2 device is already in loader mode, skip reboot to bootloader');
|
|
901
916
|
return false;
|
|
@@ -931,9 +946,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
931
946
|
commands: this.device.getCommands(),
|
|
932
947
|
timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
|
|
933
948
|
});
|
|
934
|
-
//
|
|
935
|
-
//
|
|
936
|
-
const features = this.device.updateProtocolV2Features(deviceInfo, null);
|
|
949
|
+
// This is a reconnect probe after a Bootloader reboot. Bootloader does not
|
|
950
|
+
// support DeviceStatusGet, so the generic runtime-mode probe is invalid here.
|
|
951
|
+
const features = this.device.updateProtocolV2Features(deviceInfo, null, 'bootloader');
|
|
937
952
|
assertProtocolV2ReconnectIdentity(
|
|
938
953
|
this.protocolV2ExpectedDeviceId,
|
|
939
954
|
features.deviceId ?? undefined,
|
|
@@ -959,8 +974,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
959
974
|
}
|
|
960
975
|
|
|
961
976
|
/**
|
|
962
|
-
*
|
|
963
|
-
*
|
|
977
|
+
* Collect explicit target binaries grouped by DeviceFirmwareTargetType.
|
|
978
|
+
* Filenames are display-only staging paths because target_id is explicit.
|
|
964
979
|
*/
|
|
965
980
|
private collectExplicitTargetBinaries() {
|
|
966
981
|
const entries: ProtocolV2TargetBinary[] = [];
|
|
@@ -1030,7 +1045,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1030
1045
|
totalSize = resourceTransfer.totalSize;
|
|
1031
1046
|
}
|
|
1032
1047
|
|
|
1033
|
-
//
|
|
1048
|
+
// Skip staging and installation when the update contains RESC bundles only.
|
|
1034
1049
|
if (orderedInstallItems.length === 0) {
|
|
1035
1050
|
Log.log('[FirmwareUpdateV4] no firmware targets to install (RESC bundles only)');
|
|
1036
1051
|
if (totalSize > 0) {
|
|
@@ -1100,8 +1115,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1100
1115
|
path: item.path,
|
|
1101
1116
|
}));
|
|
1102
1117
|
Log.log(`[FirmwareUpdateV4] DeviceFirmwareUpdateRequest targets=${JSON.stringify(allTargets)}`);
|
|
1103
|
-
|
|
1104
|
-
await this.waitForProtocolV2FirmwareUpdateComplete(allTargets
|
|
1118
|
+
await this.protocolV2StartFirmwareUpdate({ targets: allTargets });
|
|
1119
|
+
await this.waitForProtocolV2FirmwareUpdateComplete(allTargets);
|
|
1105
1120
|
}
|
|
1106
1121
|
|
|
1107
1122
|
private getProtocolV2InstallItemStagingPath(item: ProtocolV2InstallItem) {
|
|
@@ -1121,98 +1136,117 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1121
1136
|
}
|
|
1122
1137
|
}
|
|
1123
1138
|
|
|
1124
|
-
private isProtocolV2NormalModeFeatures(features?: Features | null) {
|
|
1125
|
-
return !!features && !features.bootloaderMode && features.mode !== 'bootloader';
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
private async probeProtocolV2NormalMode() {
|
|
1129
|
-
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
1130
|
-
const deviceInfo = await requestProtocolV2DeviceInfo({
|
|
1131
|
-
commands: this.device.getCommands(),
|
|
1132
|
-
timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
|
|
1133
|
-
});
|
|
1134
|
-
if (isProtocolV2LoaderDeviceInfo(deviceInfo, null)) {
|
|
1135
|
-
this.device.updateProtocolV2Features(deviceInfo, null);
|
|
1136
|
-
return false;
|
|
1137
|
-
}
|
|
1138
|
-
const { message: deviceStatus } = await typedCall(
|
|
1139
|
-
'DeviceStatusGet',
|
|
1140
|
-
'DeviceStatus',
|
|
1141
|
-
{},
|
|
1142
|
-
{ timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT }
|
|
1143
|
-
);
|
|
1144
|
-
const features = this.device.updateProtocolV2Features(deviceInfo, deviceStatus);
|
|
1145
|
-
assertProtocolV2ReconnectIdentity(
|
|
1146
|
-
this.protocolV2ExpectedDeviceId,
|
|
1147
|
-
features.deviceId ?? undefined
|
|
1148
|
-
);
|
|
1149
|
-
if (this.isProtocolV2NormalModeFeatures(features)) {
|
|
1150
|
-
Log.log('Protocol V2 firmware install finished; device is back in normal mode');
|
|
1151
|
-
return true;
|
|
1152
|
-
}
|
|
1153
|
-
return false;
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
1139
|
private assertProtocolV2TargetStatus(
|
|
1157
1140
|
statusTargets: ProtocolV2FirmwareUpdateStatusTarget[],
|
|
1158
1141
|
expectedTargetIds: Set<number>
|
|
1159
1142
|
) {
|
|
1143
|
+
Log.log(
|
|
1144
|
+
`[FirmwareUpdateV4] DeviceFirmwareUpdateStatus records=${JSON.stringify(statusTargets)}`
|
|
1145
|
+
);
|
|
1160
1146
|
const failedTarget = statusTargets.find(
|
|
1161
1147
|
target =>
|
|
1162
1148
|
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
|
|
1163
1149
|
isProtocolV2TargetStatusFailed(target.status)
|
|
1164
1150
|
);
|
|
1165
1151
|
if (failedTarget) {
|
|
1152
|
+
const failedTargetDetails = JSON.stringify({
|
|
1153
|
+
targetId: failedTarget.target_id,
|
|
1154
|
+
status: failedTarget.status,
|
|
1155
|
+
payloadVersion: failedTarget.payload_version,
|
|
1156
|
+
path: failedTarget.path,
|
|
1157
|
+
});
|
|
1158
|
+
Log.error(`[FirmwareUpdateV4] firmware install failed target=${failedTargetDetails}`);
|
|
1166
1159
|
throw ERRORS.TypedError(
|
|
1167
1160
|
HardwareErrorCode.FirmwareError,
|
|
1168
|
-
`Protocol V2 firmware target
|
|
1161
|
+
`Protocol V2 firmware target failed: target=${failedTarget.target_id} status=${
|
|
1162
|
+
failedTarget.status ?? 'unknown'
|
|
1163
|
+
} payloadVersion=${failedTarget.payload_version ?? 'unknown'} path=${
|
|
1164
|
+
failedTarget.path ?? 'unknown'
|
|
1165
|
+
}`
|
|
1169
1166
|
);
|
|
1170
1167
|
}
|
|
1171
1168
|
|
|
1172
|
-
const
|
|
1173
|
-
target
|
|
1174
|
-
|
|
1175
|
-
|
|
1169
|
+
const matchingTargets = statusTargets.filter(target =>
|
|
1170
|
+
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1)
|
|
1171
|
+
);
|
|
1172
|
+
const completedTargets = matchingTargets.filter(target =>
|
|
1173
|
+
isProtocolV2TargetStatusFinished(target.status)
|
|
1176
1174
|
);
|
|
1177
1175
|
if (completedTargets.length === expectedTargetIds.size && expectedTargetIds.size > 0) {
|
|
1176
|
+
this.postProgressMessage(100, 'installingFirmware');
|
|
1178
1177
|
return true;
|
|
1179
1178
|
}
|
|
1180
1179
|
|
|
1181
|
-
|
|
1182
|
-
target =>
|
|
1183
|
-
expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
|
|
1180
|
+
if (expectedTargetIds.size > 0 && matchingTargets.length > 0) {
|
|
1181
|
+
const hasInProgressTarget = matchingTargets.some(target =>
|
|
1184
1182
|
isProtocolV2TargetStatusInProgress(target.status)
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1183
|
+
);
|
|
1184
|
+
const completedProgress = Math.floor(
|
|
1185
|
+
(completedTargets.length / expectedTargetIds.size) * 100
|
|
1186
|
+
);
|
|
1187
|
+
// The protocol exposes no per-target percentage, so report coarse progress by
|
|
1188
|
+
// completed targets and use 1% once work starts to keep the UI responsive.
|
|
1189
|
+
const progress = Math.min(99, Math.max(completedProgress, hasInProgressTarget ? 1 : 0));
|
|
1190
|
+
this.postProgressMessage(progress, 'installingFirmware');
|
|
1188
1191
|
}
|
|
1189
1192
|
|
|
1190
1193
|
return false;
|
|
1191
1194
|
}
|
|
1192
1195
|
|
|
1193
1196
|
private async waitForProtocolV2FirmwareUpdateComplete(
|
|
1194
|
-
targets: Array<{ target_id: number; path: string }
|
|
1195
|
-
startResponse?: ProtocolV2FirmwareUpdateStartResponse
|
|
1197
|
+
targets: Array<{ target_id: number; path: string }>
|
|
1196
1198
|
) {
|
|
1197
1199
|
const expectedTargetIds = new Set(targets.map(target => target.target_id));
|
|
1198
|
-
if (startResponse?.type === 'DeviceFirmwareUpdateStatus') {
|
|
1199
|
-
const statusTargets = (startResponse.message.records ??
|
|
1200
|
-
[]) as ProtocolV2FirmwareUpdateStatusTarget[];
|
|
1201
|
-
// 仅消费安装请求自身返回的状态,用于尽早报告明确失败和安装中进度。
|
|
1202
|
-
// 后续完成判定不再主动轮询 DeviceFirmwareUpdateStatusGet。
|
|
1203
|
-
this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds);
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
1200
|
const startTime = Date.now();
|
|
1207
1201
|
let lastError: unknown;
|
|
1208
1202
|
|
|
1209
1203
|
while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
|
|
1210
1204
|
try {
|
|
1211
1205
|
await this.reconnectProtocolV2Device();
|
|
1212
|
-
|
|
1213
|
-
|
|
1206
|
+
try {
|
|
1207
|
+
const statusResponse = await this.device.getCommands().typedCall(
|
|
1208
|
+
'DeviceFirmwareUpdateStatusGet',
|
|
1209
|
+
'DeviceFirmwareUpdateStatus',
|
|
1210
|
+
{
|
|
1211
|
+
fields: {
|
|
1212
|
+
status: true,
|
|
1213
|
+
payload_version: true,
|
|
1214
|
+
path: true,
|
|
1215
|
+
},
|
|
1216
|
+
},
|
|
1217
|
+
{ timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT }
|
|
1218
|
+
);
|
|
1219
|
+
if (
|
|
1220
|
+
this.assertProtocolV2TargetStatus(
|
|
1221
|
+
(statusResponse.message.records ?? []) as ProtocolV2FirmwareUpdateStatusTarget[],
|
|
1222
|
+
expectedTargetIds
|
|
1223
|
+
)
|
|
1224
|
+
) {
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
lastError = new Error('Protocol V2 firmware targets are still installing');
|
|
1228
|
+
} catch (error) {
|
|
1229
|
+
if (
|
|
1230
|
+
error instanceof HardwareError &&
|
|
1231
|
+
error.errorCode === HardwareErrorCode.FirmwareError
|
|
1232
|
+
) {
|
|
1233
|
+
throw error;
|
|
1234
|
+
}
|
|
1235
|
+
// App firmware does not register DeviceFirmwareUpdateStatusGet. If the
|
|
1236
|
+
// device already rebooted into App, this endpoint error signals that the
|
|
1237
|
+
// install phase ended; the later phase performs the final readiness check.
|
|
1238
|
+
if (isProtocolV2FirmwareStatusEndpointUnavailable(error)) {
|
|
1239
|
+
Log.log(
|
|
1240
|
+
'[FirmwareUpdateV4] firmware status endpoint unavailable after reboot; continue with normal-mode verification'
|
|
1241
|
+
);
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
lastError = error;
|
|
1245
|
+
Log.log(
|
|
1246
|
+
'[FirmwareUpdateV4] DeviceFirmwareUpdateStatusGet unavailable during install: ',
|
|
1247
|
+
error
|
|
1248
|
+
);
|
|
1214
1249
|
}
|
|
1215
|
-
lastError = new Error('Protocol V2 device is reachable but is not in normal mode');
|
|
1216
1250
|
} catch (error) {
|
|
1217
1251
|
lastError = error;
|
|
1218
1252
|
if (error instanceof HardwareError && error.errorCode === HardwareErrorCode.FirmwareError) {
|
|
@@ -1230,22 +1264,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1230
1264
|
}
|
|
1231
1265
|
|
|
1232
1266
|
private async exitProtocolV2BootloaderToNormal() {
|
|
1233
|
-
this.
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
if (await this.probeProtocolV2NormalMode()) {
|
|
1237
|
-
Log.log('Protocol V2 device is already in normal mode, skip normal reboot');
|
|
1238
|
-
return;
|
|
1239
|
-
}
|
|
1240
|
-
} catch (error) {
|
|
1241
|
-
Log.log('Protocol V2 normal-mode probe before reboot failed: ', error);
|
|
1242
|
-
}
|
|
1267
|
+
await this.reconnectProtocolV2Device();
|
|
1268
|
+
// The connection may still be in bootloader. Request a Normal reboot directly;
|
|
1269
|
+
// repeating it after an automatic App reboot is idempotent.
|
|
1243
1270
|
await this.protocolV2Reboot(DeviceRebootType.Normal);
|
|
1244
1271
|
}
|
|
1245
1272
|
|
|
1246
1273
|
private async waitForProtocolV2FinalFeatures() {
|
|
1247
1274
|
const features = await this.waitForProtocolV2ReconnectAndFeatures(
|
|
1248
|
-
|
|
1275
|
+
PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT
|
|
1249
1276
|
);
|
|
1250
1277
|
|
|
1251
1278
|
const bootloaderVersion = getDeviceBootloaderVersion(features).join('.');
|
|
@@ -1274,15 +1301,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1274
1301
|
const deviceInfo = await requestProtocolV2DeviceInfo({
|
|
1275
1302
|
commands: this.device.getCommands(),
|
|
1276
1303
|
timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
|
|
1277
|
-
//
|
|
1304
|
+
// Completion needs target versions only; keep scope aligned with the request.
|
|
1278
1305
|
request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
|
|
1279
1306
|
});
|
|
1280
|
-
const features = this.device.
|
|
1307
|
+
const features = await this.device.probeProtocolV2RuntimeState(
|
|
1308
|
+
deviceInfo,
|
|
1309
|
+
PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
|
|
1310
|
+
);
|
|
1281
1311
|
assertProtocolV2ReconnectIdentity(
|
|
1282
1312
|
this.protocolV2ExpectedDeviceId,
|
|
1283
1313
|
features.deviceId ?? undefined
|
|
1284
1314
|
);
|
|
1285
|
-
if (features.
|
|
1315
|
+
if (features.mode !== 'normal' || features.bootloaderMode) {
|
|
1286
1316
|
throw ERRORS.TypedError(
|
|
1287
1317
|
HardwareErrorCode.DeviceNotFound,
|
|
1288
1318
|
'Protocol V2 device is still in bootloader mode'
|
|
@@ -1290,6 +1320,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1290
1320
|
}
|
|
1291
1321
|
return features;
|
|
1292
1322
|
} catch (error) {
|
|
1323
|
+
// A confirmed deviceId change is a firmware contract violation and cannot be
|
|
1324
|
+
// fixed by polling. A temporarily missing identity may still become ready.
|
|
1325
|
+
if (this.isProtocolV2ReconnectIdentityMismatch(error)) {
|
|
1326
|
+
throw error;
|
|
1327
|
+
}
|
|
1293
1328
|
lastError = error;
|
|
1294
1329
|
Log.log('Protocol V2 normal mode not ready, polling Ping: ', error);
|
|
1295
1330
|
await wait(1000);
|
|
@@ -1324,19 +1359,21 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1324
1359
|
},
|
|
1325
1360
|
true
|
|
1326
1361
|
);
|
|
1327
|
-
await this.
|
|
1362
|
+
await this.ensureProtocolV2DeviceAcquired();
|
|
1328
1363
|
this.device.commands.disposed = false;
|
|
1329
1364
|
this.device.getCommands().mainId = this.device.mainId ?? '';
|
|
1330
1365
|
assertProtocolV2ReconnectIdentity(
|
|
1331
1366
|
this.protocolV2ExpectedDeviceId,
|
|
1332
1367
|
this.device.getCurrentDeviceId(),
|
|
1333
|
-
|
|
1368
|
+
// Cached identity may be absent immediately after acquire. Reject only an
|
|
1369
|
+
// existing mismatch; the final refresh performs strict identity validation.
|
|
1370
|
+
{ allowMissingActual: true }
|
|
1334
1371
|
);
|
|
1335
1372
|
return;
|
|
1336
1373
|
}
|
|
1337
1374
|
|
|
1338
|
-
// App
|
|
1339
|
-
//
|
|
1375
|
+
// App and bootloader serials may differ temporarily. During V4 reconnect, accept
|
|
1376
|
+
// only a uniquely enumerated device instead of repeatedly using the old App path.
|
|
1340
1377
|
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
|
|
1341
1378
|
connectProtocol: PROTOCOL_V2_CONNECT_PROTOCOL,
|
|
1342
1379
|
});
|
|
@@ -1349,16 +1386,36 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1349
1386
|
deviceList[0].getConnectId()
|
|
1350
1387
|
);
|
|
1351
1388
|
this.device.updateFromCache(deviceList[0]);
|
|
1352
|
-
await this.
|
|
1389
|
+
await this.ensureProtocolV2DeviceAcquired();
|
|
1353
1390
|
this.device.commands.disposed = false;
|
|
1354
1391
|
this.device.getCommands().mainId = this.device.mainId ?? '';
|
|
1355
1392
|
assertProtocolV2ReconnectIdentity(
|
|
1356
1393
|
this.protocolV2ExpectedDeviceId,
|
|
1357
1394
|
this.device.getCurrentDeviceId(),
|
|
1358
|
-
|
|
1395
|
+
// Cached identity may be absent immediately after acquire. Reject only an
|
|
1396
|
+
// existing mismatch; the final refresh performs strict identity validation.
|
|
1397
|
+
{ allowMissingActual: true }
|
|
1359
1398
|
);
|
|
1360
1399
|
}
|
|
1361
1400
|
|
|
1401
|
+
/**
|
|
1402
|
+
* After acquiring a USB session, polling reuses its command channel. Reacquire only
|
|
1403
|
+
* after reboot or enumeration changes cause hasDeviceAcquire() to become false.
|
|
1404
|
+
*/
|
|
1405
|
+
private async ensureProtocolV2DeviceAcquired() {
|
|
1406
|
+
const commands = this.device.getCommands();
|
|
1407
|
+
if (this.device.hasDeviceAcquire() && !commands.disposed) {
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, {
|
|
1411
|
+
throwOnRunPromiseError: true,
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
private isProtocolV2ReconnectIdentityMismatch(error: unknown) {
|
|
1416
|
+
return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect identity mismatch');
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1362
1419
|
private async protocolV2CommonUpdateProcess(params: ProtocolV2FileTransferParams) {
|
|
1363
1420
|
let lastError: unknown;
|
|
1364
1421
|
for (let attempt = 1; attempt <= PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT; attempt += 1) {
|
|
@@ -1505,35 +1562,16 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1505
1562
|
targets: Array<{ target_id: number; path: string }>;
|
|
1506
1563
|
}) {
|
|
1507
1564
|
const commands = this.device.getCommands();
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
{
|
|
1517
|
-
intermediateTypes: ['DeviceFirmwareUpdateStatus'],
|
|
1518
|
-
timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT,
|
|
1519
|
-
onIntermediateResponse: (response: { type?: string }) => {
|
|
1520
|
-
if (response.type === 'DeviceFirmwareUpdateStatus') {
|
|
1521
|
-
this.postProgressMessage(99, 'installingFirmware');
|
|
1522
|
-
}
|
|
1523
|
-
},
|
|
1524
|
-
}
|
|
1525
|
-
);
|
|
1526
|
-
} catch (error) {
|
|
1527
|
-
if (isProtocolV2StartUpdateTransientError(error)) {
|
|
1528
|
-
Log.log(
|
|
1529
|
-
'Protocol V2 firmware update request did not return; continue status polling',
|
|
1530
|
-
error
|
|
1531
|
-
);
|
|
1532
|
-
} else {
|
|
1533
|
-
throw error;
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1565
|
+
const response: ProtocolV2FirmwareUpdateStartResponse = await commands.typedCall(
|
|
1566
|
+
'DeviceFirmwareUpdateRequest',
|
|
1567
|
+
'Success',
|
|
1568
|
+
{ targets },
|
|
1569
|
+
{ timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT }
|
|
1570
|
+
);
|
|
1571
|
+
// Success acknowledges that the device accepted installation. End confirmation
|
|
1572
|
+
// and begin status polling only after receiving this ACK.
|
|
1536
1573
|
this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdating);
|
|
1574
|
+
this.postProgressMessage(0, 'installingFirmware');
|
|
1537
1575
|
return response;
|
|
1538
1576
|
}
|
|
1539
1577
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ERRORS, HardwareErrorCode, createDeviceNotSupportMethodError } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import { UI_REQUEST } from '../constants/ui-request';
|
|
4
4
|
import { getPassphraseStateWithRefreshDeviceInfo } from '../utils/deviceFeaturesUtils';
|
|
@@ -11,23 +11,17 @@ export default class GetPassphraseState extends BaseMethod {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
async run() {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
if (this.device.isProtocolV2()) {
|
|
15
|
+
throw createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
|
|
16
|
+
}
|
|
17
|
+
if (!this.device.features) {
|
|
18
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed);
|
|
19
|
+
}
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
-
const deviceType = this.device.getCurrentDeviceType();
|
|
21
|
+
const { passphraseState } = await getPassphraseStateWithRefreshDeviceInfo(this.device);
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
// Protocol V2 的钱包身份由 DeviceSession 返回的 btc_test_address 决定,
|
|
25
|
-
// 不依赖固件 passphrase_enabled 状态。
|
|
26
|
-
return Promise.resolve(passphraseState);
|
|
27
|
-
}
|
|
23
|
+
const passphraseProtection = this.device.getCurrentPassphraseProtection();
|
|
28
24
|
|
|
29
|
-
return Promise.resolve(
|
|
30
|
-
deviceType === EDeviceType.Pro || passphraseProtection === true ? passphraseState : undefined
|
|
31
|
-
);
|
|
25
|
+
return Promise.resolve(passphraseProtection === true ? passphraseState : undefined);
|
|
32
26
|
}
|
|
33
27
|
}
|