@onekeyfe/hd-core 1.2.0-alpha.50 → 1.2.0-alpha.51
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 +0 -78
- package/__tests__/DeviceEventRegistration.test.ts +0 -6
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +3 -111
- package/__tests__/connectSettings.test.ts +47 -5
- package/__tests__/device-initialize-timeout.test.ts +56 -0
- package/__tests__/device-lifecycle-events.test.ts +3 -105
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +175 -0
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
- package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
- package/__tests__/firmware-update/firmware-preparation-error.test.ts +27 -0
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +200 -0
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +593 -0
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +213 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +59 -31
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +58 -0
- package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
- package/__tests__/get-device-state.test.ts +12 -132
- package/__tests__/homescreen.test.ts +1 -41
- package/__tests__/logBlockEvent.test.ts +1 -1
- package/__tests__/method-protocol-support.test.ts +0 -19
- package/__tests__/open-wallet-session.test.ts +33 -446
- package/__tests__/protocol-v2-unlock-policy.test.ts +35 -196
- package/__tests__/protocol-v2.test.ts +1032 -1056
- package/__tests__/protocolV2UiInteraction.test.ts +0 -63
- package/__tests__/public-pro2-api-boundary.test.ts +0 -1
- package/__tests__/search-devices.test.ts +3 -12
- package/dist/api/BaseMethod.d.ts +1 -3
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +11 -0
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +7 -3
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +25 -9
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +25 -0
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
- package/dist/api/firmware/FirmwarePreparationError.d.ts +3 -0
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +9 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +25 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +30 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/api/firmware/getBinary.d.ts +7 -0
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/progressThrottle.d.ts +3 -0
- package/dist/api/firmware/progressThrottle.d.ts.map +1 -0
- package/dist/api/firmware/updateBootloader.d.ts +2 -0
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +9 -1
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +0 -2
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +0 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/deviceEventRegistration.d.ts +0 -2
- package/dist/core/deviceEventRegistration.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +2 -4
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +6 -29
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +4 -4
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/events/device.d.ts +0 -4
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-promise.d.ts +2 -4
- package/dist/events/ui-promise.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +2 -31
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/events/ui-response.d.ts +2 -10
- package/dist/events/ui-response.d.ts.map +1 -1
- package/dist/index.d.ts +230 -203
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3445 -2419
- package/dist/inject.d.ts +1 -6
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/lockedError.d.ts +2 -0
- package/dist/protocols/protocol-v2/lockedError.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts +4 -7
- package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts +3 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts +10 -0
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts +1 -4
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +4 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +4 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +70 -2
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts +28 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/types/api/index.d.ts +10 -7
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +0 -3
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/params.d.ts +0 -1
- package/dist/types/params.d.ts.map +1 -1
- package/dist/types/settings.d.ts +13 -22
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +0 -2
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/homescreen.d.ts +0 -4
- package/dist/utils/homescreen.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.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 +0 -10
- package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +10 -8
- package/src/api/CheckAllFirmwareRelease.ts +53 -41
- package/src/api/FirmwareUpdate.ts +15 -7
- package/src/api/FirmwareUpdateV2.ts +313 -126
- package/src/api/FirmwareUpdateV3.ts +265 -63
- package/src/api/FirmwareUpdateV4.ts +937 -430
- package/src/api/GetPassphraseState.ts +1 -7
- package/src/api/OpenWalletSession.ts +17 -54
- package/src/api/SearchDevices.ts +1 -3
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +11 -32
- package/src/api/device/DeviceUnlock.ts +1 -1
- package/src/api/device/DeviceUpdateBootloader.ts +122 -6
- package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
- package/src/api/firmware/FirmwareHostBinding.ts +100 -0
- package/src/api/firmware/FirmwarePreparationError.ts +12 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +83 -16
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +745 -0
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +392 -0
- package/src/api/firmware/progressThrottle.ts +44 -0
- package/src/api/firmware/updateBootloader.ts +19 -4
- package/src/api/firmware/uploadFirmware.ts +144 -39
- package/src/api/helpers/protocolV2FileWrite.ts +4 -11
- package/src/api/index.ts +0 -2
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -3
- package/src/core/deviceEventRegistration.ts +0 -4
- package/src/core/index.ts +83 -167
- package/src/data/messages/messages-protocol-v2.json +0 -25
- package/src/data-manager/DataManager.ts +38 -67
- package/src/data-manager/connectSettings.ts +11 -0
- package/src/device/Device.ts +42 -257
- package/src/device/DevicePool.ts +2 -7
- package/src/events/device.ts +0 -4
- package/src/events/logBlockEvent.ts +0 -1
- package/src/events/ui-promise.ts +2 -4
- package/src/events/ui-request.ts +2 -36
- package/src/events/ui-response.ts +2 -12
- package/src/index.ts +5 -0
- package/src/inject.ts +24 -60
- package/src/lowLevelInject.ts +8 -7
- package/src/protocols/protocol-v2/features.ts +2 -9
- package/src/protocols/protocol-v2/lockedError.ts +10 -0
- package/src/protocols/protocol-v2/uiInteraction.ts +6 -46
- package/src/protocols/protocol-v2/unlockPolicy.ts +105 -1
- package/src/protocols/protocol-v2/unlockRetry.ts +109 -0
- package/src/protocols/protocol-v2/walletSession.ts +30 -169
- package/src/topLevelInject.ts +8 -7
- package/src/types/api/checkAllFirmwareRelease.ts +4 -1
- package/src/types/api/deviceUpdateBootloader.ts +6 -0
- package/src/types/api/export.ts +18 -0
- package/src/types/api/firmwareUpdate.ts +76 -3
- package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
- package/src/types/api/firmwareUpdatePlan.ts +38 -0
- package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
- package/src/types/api/index.ts +14 -13
- package/src/types/api/protocolV2.ts +0 -13
- package/src/types/params.ts +1 -7
- package/src/types/settings.ts +13 -42
- package/src/utils/deviceFeaturesUtils.ts +0 -4
- package/src/utils/homescreen.ts +6 -32
- package/src/utils/index.ts +1 -6
- package/src/utils/pro2Wallpaper.ts +8 -35
- package/__tests__/deviceUploadNft.test.ts +0 -293
- package/__tests__/pro2Nft.test.ts +0 -108
- package/__tests__/protocol-binding.test.ts +0 -89
- package/__tests__/protocol-v2-resources.test.ts +0 -284
- package/__tests__/protocol-v2-ui-lifecycle.test.ts +0 -91
- package/__tests__/uiProgressThrottle.test.ts +0 -74
- package/__tests__/uiPromiseRegistry.test.ts +0 -86
- package/dist/api/DetectDeviceConnectProtocol.d.ts +0 -7
- package/dist/api/DetectDeviceConnectProtocol.d.ts.map +0 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +0 -31
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +0 -1
- package/dist/core/uiPromiseRegistry.d.ts +0 -4
- package/dist/core/uiPromiseRegistry.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/resources.d.ts +0 -30
- package/dist/protocols/protocol-v2/resources.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +0 -22
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +0 -1
- package/dist/types/api/detectDeviceConnectProtocol.d.ts +0 -4
- package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +0 -1
- package/dist/utils/pro2Nft.d.ts +0 -31
- package/dist/utils/pro2Nft.d.ts.map +0 -1
- package/dist/utils/uiProgressThrottle.d.ts +0 -3
- package/dist/utils/uiProgressThrottle.d.ts.map +0 -1
- package/src/api/DetectDeviceConnectProtocol.ts +0 -18
- package/src/api/protocol-v2/DeviceUploadNft.ts +0 -189
- package/src/core/uiPromiseRegistry.ts +0 -41
- package/src/protocols/protocol-v2/resources.ts +0 -359
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +0 -124
- package/src/types/api/detectDeviceConnectProtocol.ts +0 -7
- package/src/utils/pro2Nft.ts +0 -142
- package/src/utils/uiProgressThrottle.ts +0 -63
|
@@ -10,6 +10,7 @@ import { UI_REQUEST } from '../constants/ui-request';
|
|
|
10
10
|
import { BaseMethod } from './BaseMethod';
|
|
11
11
|
import { validateParams } from './helpers/paramsValidator';
|
|
12
12
|
import { getBinary } from './firmware/getBinary';
|
|
13
|
+
import { BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS } from './firmware/FirmwareUpdateBaseMethod';
|
|
13
14
|
import { uploadFirmware } from './firmware/uploadFirmware';
|
|
14
15
|
import { createUiMessage } from '../events';
|
|
15
16
|
import { DeviceModelToTypes, type KnownDevice } from '../types';
|
|
@@ -78,6 +79,10 @@ export default class FirmwareUpdate extends BaseMethod<Params> {
|
|
|
78
79
|
this.checkPromise = createDeferred();
|
|
79
80
|
const env = DataManager.getSettings('env');
|
|
80
81
|
const isBleReconnect = connectId && DataManager.isBleConnect(env);
|
|
82
|
+
// Tracks the in-flight BLE probe so interval ticks never overlap: a superseded
|
|
83
|
+
// Initialize left pending on the V1 transport is exactly what later times out
|
|
84
|
+
// and used to tear down the connection mid-firmware-upload.
|
|
85
|
+
let bleProbeInFlight = false;
|
|
81
86
|
|
|
82
87
|
Log.log('FirmwareUpdate [checkDeviceToBootloader] isBleReconnect: ', isBleReconnect);
|
|
83
88
|
|
|
@@ -85,14 +90,18 @@ export default class FirmwareUpdate extends BaseMethod<Params> {
|
|
|
85
90
|
const intervalTimer: ReturnType<typeof setInterval> | undefined = setInterval(
|
|
86
91
|
async () => {
|
|
87
92
|
if (isBleReconnect) {
|
|
93
|
+
if (bleProbeInFlight) return;
|
|
94
|
+
bleProbeInFlight = true;
|
|
88
95
|
try {
|
|
89
96
|
await this.device.deviceConnector?.acquire(
|
|
90
97
|
this.device.originalDescriptor.id,
|
|
91
98
|
null,
|
|
92
|
-
true
|
|
93
|
-
this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
|
|
99
|
+
true
|
|
94
100
|
);
|
|
95
|
-
|
|
101
|
+
// Bound each probe so a request the rebooting device never received
|
|
102
|
+
// frees the slot for the next tick instead of hanging into the
|
|
103
|
+
// 30s reboot budget.
|
|
104
|
+
await this.device.initialize({ timeoutMs: BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS });
|
|
96
105
|
if (this.device.isBootloader()) {
|
|
97
106
|
clearInterval(intervalTimer);
|
|
98
107
|
this.checkPromise?.resolve(true);
|
|
@@ -100,14 +109,13 @@ export default class FirmwareUpdate extends BaseMethod<Params> {
|
|
|
100
109
|
} catch (e) {
|
|
101
110
|
// ignore error because of device is not connected
|
|
102
111
|
Log.log('catch Bluetooth error when device is restarting: ', e);
|
|
112
|
+
} finally {
|
|
113
|
+
bleProbeInFlight = false;
|
|
103
114
|
}
|
|
104
115
|
} else {
|
|
105
116
|
const deviceDiff = await this.device.deviceConnector?.enumerate();
|
|
106
117
|
const devicesDescriptor = deviceDiff?.descriptors ?? [];
|
|
107
|
-
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId
|
|
108
|
-
connectProtocol:
|
|
109
|
-
this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
|
|
110
|
-
});
|
|
118
|
+
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId);
|
|
111
119
|
|
|
112
120
|
if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
|
|
113
121
|
// should update current device from cache
|
|
@@ -14,18 +14,45 @@ import { BaseMethod } from './BaseMethod';
|
|
|
14
14
|
import { validateParams } from './helpers/paramsValidator';
|
|
15
15
|
import { DevicePool } from '../device/DevicePool';
|
|
16
16
|
import { getBinary, getInfo, getSysResourceBinary } from './firmware/getBinary';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { normalizeFirmwarePreparationError } from './firmware/FirmwarePreparationError';
|
|
18
|
+
import {
|
|
19
|
+
updateResources,
|
|
20
|
+
updateResourcesFromSources,
|
|
21
|
+
uploadFirmwareFromSource,
|
|
22
|
+
} from './firmware/uploadFirmware';
|
|
23
|
+
import { BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS } from './firmware/FirmwareUpdateBaseMethod';
|
|
24
|
+
import { LoggerNames, getDeviceUUID, getLogger, wait } from '../utils';
|
|
19
25
|
import { FirmwareUpdateTipMessage, createUiMessage } from '../events/ui-request';
|
|
20
26
|
import { DeviceModelToTypes } from '../types';
|
|
21
27
|
import { DataManager } from '../data-manager';
|
|
22
28
|
import { DEVICE } from '../events';
|
|
29
|
+
import { type FirmwareByteSource, openFirmwareByteSource } from './firmware/FirmwareArtifactSource';
|
|
30
|
+
import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
|
|
31
|
+
import {
|
|
32
|
+
assertFirmwareUpdatePreparedPlanBinding,
|
|
33
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
34
|
+
getFirmwareUpdateResourceName,
|
|
35
|
+
} from './firmware/FirmwareUpdatePreparedPlan';
|
|
23
36
|
|
|
24
37
|
import type { Features, KnownDevice } from '../types';
|
|
25
38
|
import type { FirmwareBinary } from './firmware/getBinary';
|
|
39
|
+
import type {
|
|
40
|
+
FirmwareArtifactReader,
|
|
41
|
+
FirmwareArtifactReference,
|
|
42
|
+
} from '../types/api/firmwareUpdate';
|
|
43
|
+
import type { FirmwareUpdatePreparedPlan } from '../types/api/firmwareUpdatePreparedPlan';
|
|
26
44
|
|
|
27
45
|
type Params = {
|
|
28
46
|
binary?: ArrayBuffer;
|
|
47
|
+
artifact?: FirmwareArtifactReference;
|
|
48
|
+
resourceArtifact?: FirmwareArtifactReference;
|
|
49
|
+
resourceEntries?: Array<{
|
|
50
|
+
entryName: string;
|
|
51
|
+
artifact: FirmwareArtifactReference;
|
|
52
|
+
}>;
|
|
53
|
+
artifactReader?: FirmwareArtifactReader;
|
|
54
|
+
preparedPlan?: FirmwareUpdatePreparedPlan;
|
|
55
|
+
platform?: FirmwareUpdatePreparedPlan['platform'];
|
|
29
56
|
version?: number[];
|
|
30
57
|
updateType: 'firmware' | 'ble';
|
|
31
58
|
forcedUpdateRes?: boolean;
|
|
@@ -106,6 +133,13 @@ const normalizeFirmwareBinary = (binary: unknown): FirmwareBinary | undefined =>
|
|
|
106
133
|
return normalized.buffer;
|
|
107
134
|
};
|
|
108
135
|
|
|
136
|
+
const toArrayBuffer = (binary: FirmwareBinary): ArrayBuffer => {
|
|
137
|
+
if (binary instanceof ArrayBuffer) {
|
|
138
|
+
return binary;
|
|
139
|
+
}
|
|
140
|
+
return new Uint8Array(binary.buffer, binary.byteOffset, binary.byteLength).slice().buffer;
|
|
141
|
+
};
|
|
142
|
+
|
|
109
143
|
export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
110
144
|
checkPromise: Deferred<any> | null = null;
|
|
111
145
|
|
|
@@ -152,6 +186,38 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
152
186
|
binary: payload.binary,
|
|
153
187
|
};
|
|
154
188
|
}
|
|
189
|
+
|
|
190
|
+
if ('artifact' in payload) {
|
|
191
|
+
const hostBinding = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration);
|
|
192
|
+
const target = payload.isUpdateBootloader ? 'bootloader' : payload.updateType;
|
|
193
|
+
const resourceBindings = [
|
|
194
|
+
...(payload.resourceArtifact
|
|
195
|
+
? [{ target: 'resource' as const, artifact: payload.resourceArtifact }]
|
|
196
|
+
: []),
|
|
197
|
+
...(payload.resourceEntries ?? []).map(
|
|
198
|
+
(entry: { entryName: string; artifact: FirmwareArtifactReference }) => ({
|
|
199
|
+
target: 'resource' as const,
|
|
200
|
+
entryName: entry.entryName,
|
|
201
|
+
artifact: entry.artifact,
|
|
202
|
+
})
|
|
203
|
+
),
|
|
204
|
+
];
|
|
205
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
206
|
+
preparedPlan: payload.preparedPlan,
|
|
207
|
+
executor: 'v2',
|
|
208
|
+
platform: payload.platform,
|
|
209
|
+
scopeTargets: [target, ...(target === 'firmware' ? (['resource'] as const) : [])],
|
|
210
|
+
bindings: [{ target, artifact: payload.artifact }, ...resourceBindings],
|
|
211
|
+
});
|
|
212
|
+
this.params = {
|
|
213
|
+
...this.params,
|
|
214
|
+
preparedPlan: payload.preparedPlan,
|
|
215
|
+
artifact: payload.artifact,
|
|
216
|
+
resourceArtifact: payload.resourceArtifact,
|
|
217
|
+
resourceEntries: payload.resourceEntries,
|
|
218
|
+
artifactReader: hostBinding.artifactReader,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
155
221
|
}
|
|
156
222
|
|
|
157
223
|
postTipMessage = (message: string) => {
|
|
@@ -187,6 +253,10 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
187
253
|
this.checkPromise = createDeferred();
|
|
188
254
|
const env = DataManager.getSettings('env');
|
|
189
255
|
const isBleReconnect = connectId && DataManager.isBleConnect(env);
|
|
256
|
+
// Tracks the in-flight BLE probe so interval ticks never overlap: a superseded
|
|
257
|
+
// Initialize left pending on the V1 transport is exactly what later times out
|
|
258
|
+
// and used to tear down the connection mid-firmware-upload.
|
|
259
|
+
let bleProbeInFlight = false;
|
|
190
260
|
|
|
191
261
|
Log.log('FirmwareUpdateV2 [checkDeviceToBootloader] isBleReconnect: ', isBleReconnect);
|
|
192
262
|
|
|
@@ -234,14 +304,18 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
234
304
|
}
|
|
235
305
|
|
|
236
306
|
if (isBleReconnect) {
|
|
307
|
+
if (bleProbeInFlight) return;
|
|
308
|
+
bleProbeInFlight = true;
|
|
237
309
|
try {
|
|
238
310
|
await this.device.deviceConnector?.acquire(
|
|
239
311
|
this.device.originalDescriptor.id,
|
|
240
312
|
null,
|
|
241
|
-
true
|
|
242
|
-
this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
|
|
313
|
+
true
|
|
243
314
|
);
|
|
244
|
-
|
|
315
|
+
// Bound each probe so a request the rebooting device never received
|
|
316
|
+
// frees the slot for the next tick instead of hanging into the
|
|
317
|
+
// 30s reboot budget.
|
|
318
|
+
await this.device.initialize({ timeoutMs: BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS });
|
|
245
319
|
if (this.device.isBootloader()) {
|
|
246
320
|
clearInterval(intervalTimer);
|
|
247
321
|
this.checkPromise?.resolve(true);
|
|
@@ -249,6 +323,8 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
249
323
|
} catch (e) {
|
|
250
324
|
// ignore error because of device is not connected
|
|
251
325
|
Log.log('catch Bluetooth error when device is restarting: ', e);
|
|
326
|
+
} finally {
|
|
327
|
+
bleProbeInFlight = false;
|
|
252
328
|
}
|
|
253
329
|
} else {
|
|
254
330
|
await this._checkDeviceInBootloaderMode(connectId, intervalTimer, timeoutTimer);
|
|
@@ -273,9 +349,7 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
273
349
|
) {
|
|
274
350
|
const deviceDiff = await this.device.deviceConnector?.enumerate();
|
|
275
351
|
const devicesDescriptor = deviceDiff?.descriptors ?? [];
|
|
276
|
-
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId
|
|
277
|
-
connectProtocol: this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
|
|
278
|
-
});
|
|
352
|
+
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId);
|
|
279
353
|
|
|
280
354
|
if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
|
|
281
355
|
// should update current device from cache
|
|
@@ -344,151 +418,264 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
344
418
|
const { features, commands } = device;
|
|
345
419
|
const deviceType = device.getCurrentDeviceType();
|
|
346
420
|
|
|
421
|
+
// Protocol V2 (Pro2) uses DeviceFirmwareUpdate and must not enter this legacy flow.
|
|
422
|
+
if (device.isProtocolV2()) {
|
|
423
|
+
throw ERRORS.TypedError(
|
|
424
|
+
HardwareErrorCode.RuntimeError,
|
|
425
|
+
'Protocol V2 firmware update must use firmwareUpdateV4'
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
if (params.preparedPlan) {
|
|
429
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
430
|
+
preparedPlan: params.preparedPlan,
|
|
431
|
+
deviceIdentity: getDeviceUUID(features) || undefined,
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
347
435
|
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
348
436
|
const firmwareType = params.firmwareType ?? deviceFirmwareType;
|
|
349
437
|
|
|
350
438
|
this.checkVersionForCopyTouchResource(features, firmwareType);
|
|
351
439
|
|
|
352
|
-
let
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if (params.binary !== undefined) {
|
|
360
|
-
preparedBinary = normalizeFirmwareBinary(params.binary);
|
|
361
|
-
if (!preparedBinary) {
|
|
362
|
-
throw new Error('firmware binary is empty or invalid');
|
|
440
|
+
let preparedSource: FirmwareByteSource | undefined;
|
|
441
|
+
try {
|
|
442
|
+
const acquireFirmwareSource = async (): Promise<FirmwareByteSource> => {
|
|
443
|
+
try {
|
|
444
|
+
if (preparedSource) {
|
|
445
|
+
return preparedSource;
|
|
363
446
|
}
|
|
364
|
-
return preparedBinary;
|
|
365
|
-
}
|
|
366
447
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
requestOptions: FIRMWARE_DOWNLOAD_REQUEST_OPTIONS,
|
|
382
|
-
});
|
|
383
|
-
preparedBinary = normalizeFirmwareBinary(firmware.binary);
|
|
384
|
-
if (!preparedBinary) {
|
|
385
|
-
throw new Error('downloaded firmware binary is empty or invalid');
|
|
386
|
-
}
|
|
387
|
-
this.postTipMessage('DownloadFirmwareSuccess');
|
|
388
|
-
return preparedBinary;
|
|
389
|
-
} catch (err) {
|
|
390
|
-
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
|
|
391
|
-
}
|
|
392
|
-
};
|
|
448
|
+
if (params.binary !== undefined) {
|
|
449
|
+
const binary = normalizeFirmwareBinary(params.binary);
|
|
450
|
+
if (!binary) {
|
|
451
|
+
throw new Error('firmware binary is empty or invalid');
|
|
452
|
+
}
|
|
453
|
+
const source = await openFirmwareByteSource({
|
|
454
|
+
binary: toArrayBuffer(binary),
|
|
455
|
+
});
|
|
456
|
+
if (!source) {
|
|
457
|
+
throw new Error('firmware binary is empty or invalid');
|
|
458
|
+
}
|
|
459
|
+
preparedSource = source;
|
|
460
|
+
return source;
|
|
461
|
+
}
|
|
393
462
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
463
|
+
if (params.artifact) {
|
|
464
|
+
const source = await openFirmwareByteSource({
|
|
465
|
+
artifact: params.artifact,
|
|
466
|
+
reader: params.artifactReader,
|
|
467
|
+
});
|
|
468
|
+
if (!source) {
|
|
469
|
+
throw new Error('firmware artifact is not prepared');
|
|
470
|
+
}
|
|
471
|
+
preparedSource = source;
|
|
472
|
+
return source;
|
|
473
|
+
}
|
|
400
474
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
features,
|
|
406
|
-
forcedUpdateRes: params.forcedUpdateRes,
|
|
407
|
-
firmwareType,
|
|
408
|
-
});
|
|
409
|
-
if (resourceUrl) {
|
|
410
|
-
this.postTipMessage('DownloadLatestUiResource');
|
|
411
|
-
const resource = await getSysResourceBinary(resourceUrl);
|
|
412
|
-
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
413
|
-
if (resource) {
|
|
414
|
-
await updateResources(
|
|
415
|
-
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
416
|
-
this.postMessage,
|
|
417
|
-
device,
|
|
418
|
-
resource.binary
|
|
475
|
+
if (!device.features) {
|
|
476
|
+
throw ERRORS.TypedError(
|
|
477
|
+
HardwareErrorCode.RuntimeError,
|
|
478
|
+
'no features found for this device'
|
|
419
479
|
);
|
|
420
480
|
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// check if the device commands has been disposed
|
|
425
|
-
this.device?.commands?.checkDisposed();
|
|
426
481
|
|
|
427
|
-
|
|
428
|
-
|
|
482
|
+
if (
|
|
483
|
+
params.artifactReader ||
|
|
484
|
+
DataManager.getSettings('firmwareManifestMode') === 'external-only'
|
|
485
|
+
) {
|
|
486
|
+
throw ERRORS.TypedError(
|
|
487
|
+
HardwareErrorCode.RuntimeError,
|
|
488
|
+
'Firmware must be prepared by the external firmware host',
|
|
489
|
+
{
|
|
490
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
491
|
+
artifactName: 'firmware',
|
|
492
|
+
}
|
|
493
|
+
);
|
|
494
|
+
}
|
|
429
495
|
|
|
430
|
-
|
|
431
|
-
|
|
496
|
+
this.postTipMessage('DownloadFirmware');
|
|
497
|
+
const firmware = await getBinary({
|
|
498
|
+
features: device.features,
|
|
499
|
+
version: params.version,
|
|
500
|
+
updateType: params.updateType,
|
|
501
|
+
isUpdateBootloader: params.isUpdateBootloader,
|
|
502
|
+
firmwareType,
|
|
503
|
+
requestOptions: FIRMWARE_DOWNLOAD_REQUEST_OPTIONS,
|
|
504
|
+
});
|
|
505
|
+
const binary = normalizeFirmwareBinary(firmware.binary);
|
|
506
|
+
if (!binary) {
|
|
507
|
+
throw new Error('downloaded firmware binary is empty or invalid');
|
|
508
|
+
}
|
|
509
|
+
const source = await openFirmwareByteSource({
|
|
510
|
+
binary: toArrayBuffer(binary),
|
|
511
|
+
});
|
|
512
|
+
if (!source) {
|
|
513
|
+
throw new Error('downloaded firmware binary is empty or invalid');
|
|
514
|
+
}
|
|
515
|
+
preparedSource = source;
|
|
516
|
+
this.postTipMessage('DownloadFirmwareSuccess');
|
|
517
|
+
return source;
|
|
518
|
+
} catch (err) {
|
|
519
|
+
throw normalizeFirmwarePreparationError(err);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
432
522
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
if (bootRes.type === 'CallMethodError') {
|
|
439
|
-
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure);
|
|
523
|
+
if (!device.isBootloader() && features) {
|
|
524
|
+
const serialNo = device.getCurrentSerialNo();
|
|
525
|
+
// should go to bootloader mode manually
|
|
526
|
+
if (this.isEnteredManuallyBoot()) {
|
|
527
|
+
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateManuallyEnterBoot);
|
|
440
528
|
}
|
|
441
|
-
this.postTipMessage('GoToBootloaderSuccess');
|
|
442
|
-
this.checkDeviceToBootloader(this.payload.connectId);
|
|
443
529
|
|
|
444
|
-
//
|
|
445
|
-
|
|
446
|
-
|
|
530
|
+
// All network-backed input must be ready before the first device mutation.
|
|
531
|
+
await acquireFirmwareSource();
|
|
532
|
+
|
|
533
|
+
// check & upgrade firmware resource
|
|
534
|
+
if (this.isSupportResourceUpdate(params.updateType)) {
|
|
535
|
+
this.postTipMessage('CheckLatestUiResource');
|
|
536
|
+
const resourceUrl = DataManager.getSysResourcesLatestRelease({
|
|
537
|
+
features,
|
|
538
|
+
forcedUpdateRes: params.forcedUpdateRes,
|
|
539
|
+
firmwareType,
|
|
540
|
+
});
|
|
541
|
+
if (resourceUrl) {
|
|
542
|
+
this.postTipMessage('DownloadLatestUiResource');
|
|
543
|
+
if (params.resourceEntries?.length) {
|
|
544
|
+
const sources: Array<{
|
|
545
|
+
entryName: string;
|
|
546
|
+
source: FirmwareByteSource;
|
|
547
|
+
}> = [];
|
|
548
|
+
try {
|
|
549
|
+
for (const entry of params.resourceEntries) {
|
|
550
|
+
const resourceName = getFirmwareUpdateResourceName(entry.entryName);
|
|
551
|
+
const source = await openFirmwareByteSource({
|
|
552
|
+
artifact: entry.artifact,
|
|
553
|
+
reader: params.artifactReader,
|
|
554
|
+
});
|
|
555
|
+
if (!source) {
|
|
556
|
+
throw new Error('Firmware resource entry is not prepared');
|
|
557
|
+
}
|
|
558
|
+
sources.push({ entryName: resourceName, source });
|
|
559
|
+
}
|
|
560
|
+
await updateResourcesFromSources(
|
|
561
|
+
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
562
|
+
this.postMessage,
|
|
563
|
+
device,
|
|
564
|
+
sources.map(entry => ({
|
|
565
|
+
entryName: entry.entryName,
|
|
566
|
+
source: entry.source,
|
|
567
|
+
}))
|
|
568
|
+
);
|
|
569
|
+
} finally {
|
|
570
|
+
await Promise.all(
|
|
571
|
+
sources.map(entry => entry.source.close().catch(() => undefined))
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
575
|
+
} else {
|
|
576
|
+
let resourceBinary: ArrayBuffer | Buffer;
|
|
577
|
+
if (params.resourceArtifact) {
|
|
578
|
+
throw ERRORS.TypedError(
|
|
579
|
+
HardwareErrorCode.RuntimeError,
|
|
580
|
+
'Firmware resource archive must be materialized into prepared entries',
|
|
581
|
+
{
|
|
582
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
583
|
+
artifactName: 'resource',
|
|
584
|
+
}
|
|
585
|
+
);
|
|
586
|
+
} else {
|
|
587
|
+
if (
|
|
588
|
+
params.artifactReader ||
|
|
589
|
+
DataManager.getSettings('firmwareManifestMode') === 'external-only'
|
|
590
|
+
) {
|
|
591
|
+
throw ERRORS.TypedError(
|
|
592
|
+
HardwareErrorCode.RuntimeError,
|
|
593
|
+
'Firmware resource must be prepared by the external firmware host',
|
|
594
|
+
{
|
|
595
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
596
|
+
artifactName: 'resource',
|
|
597
|
+
}
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
resourceBinary = (await getSysResourceBinary(resourceUrl)).binary;
|
|
601
|
+
}
|
|
602
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
603
|
+
await updateResources(
|
|
604
|
+
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
605
|
+
this.postMessage,
|
|
606
|
+
device,
|
|
607
|
+
resourceBinary
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
447
611
|
}
|
|
448
|
-
delete DevicePool.devicesCache[''];
|
|
449
|
-
await this.checkPromise?.promise;
|
|
450
|
-
this.checkPromise = null;
|
|
451
612
|
|
|
452
|
-
//
|
|
613
|
+
// The request may outlive the current transport command instance.
|
|
453
614
|
this.device?.commands?.checkDisposed();
|
|
454
615
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
616
|
+
// auto go to bootloader mode
|
|
617
|
+
try {
|
|
618
|
+
this.postTipMessage('AutoRebootToBootloader');
|
|
619
|
+
const bootRes = await commands.typedCall('DeviceBackToBoot', 'Success');
|
|
620
|
+
// @ts-expect-error
|
|
621
|
+
if (bootRes.type === 'CallMethodError') {
|
|
622
|
+
throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure);
|
|
623
|
+
}
|
|
624
|
+
this.postTipMessage('GoToBootloaderSuccess');
|
|
625
|
+
this.checkDeviceToBootloader(this.payload.connectId);
|
|
626
|
+
|
|
627
|
+
// force clean classic device cache so that the device can initialize again
|
|
628
|
+
if (DeviceModelToTypes.model_classic.includes(deviceType)) {
|
|
629
|
+
DevicePool.clearDeviceCache(serialNo);
|
|
630
|
+
}
|
|
631
|
+
delete DevicePool.devicesCache[''];
|
|
632
|
+
await this.checkPromise?.promise;
|
|
633
|
+
this.checkPromise = null;
|
|
634
|
+
|
|
635
|
+
// check if the device commands has been disposed
|
|
636
|
+
this.device?.commands?.checkDisposed();
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Touch 1 with bootloader v2.5.0 issue: BLE chip need more time for looking up name, here change the delay time to 3000ms after rebooting.
|
|
640
|
+
*/
|
|
641
|
+
const isTouch = DeviceModelToTypes.model_touch.includes(deviceType);
|
|
642
|
+
await wait(isTouch ? 3000 : 1500);
|
|
643
|
+
} catch (e) {
|
|
644
|
+
if (e instanceof HardwareError) {
|
|
645
|
+
return Promise.reject(e);
|
|
646
|
+
}
|
|
647
|
+
console.log('auto go to bootloader mode failed: ', e);
|
|
648
|
+
return Promise.reject(
|
|
649
|
+
ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure)
|
|
650
|
+
);
|
|
463
651
|
}
|
|
464
|
-
console.log('auto go to bootloader mode failed: ', e);
|
|
465
|
-
return Promise.reject(
|
|
466
|
-
ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure)
|
|
467
|
-
);
|
|
468
652
|
}
|
|
469
|
-
}
|
|
470
653
|
|
|
471
|
-
|
|
472
|
-
|
|
654
|
+
// Devices already in bootloader mode still acquire through the same helper.
|
|
655
|
+
const source = await acquireFirmwareSource();
|
|
473
656
|
|
|
474
|
-
|
|
475
|
-
|
|
657
|
+
// check if the device commands has been disposed
|
|
658
|
+
this.device?.commands?.checkDisposed();
|
|
476
659
|
|
|
477
|
-
|
|
660
|
+
await this.device.acquire();
|
|
478
661
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
662
|
+
const response = await uploadFirmwareFromSource(
|
|
663
|
+
params.updateType,
|
|
664
|
+
this.device.getCommands().typedCall.bind(this.device.getCommands()),
|
|
665
|
+
this.postMessage,
|
|
666
|
+
device,
|
|
667
|
+
source,
|
|
668
|
+
true,
|
|
669
|
+
params.isUpdateBootloader
|
|
670
|
+
);
|
|
487
671
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
672
|
+
if (this.connectId) {
|
|
673
|
+
DevicePool.clearDeviceCache(this.connectId);
|
|
674
|
+
}
|
|
491
675
|
|
|
492
|
-
|
|
676
|
+
return response;
|
|
677
|
+
} finally {
|
|
678
|
+
await preparedSource?.close().catch(() => undefined);
|
|
679
|
+
}
|
|
493
680
|
}
|
|
494
681
|
}
|