@onekeyfe/hd-core 1.2.0-alpha.74 → 1.2.0-alpha.75

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.
Files changed (120) hide show
  1. package/__tests__/connectSettings.test.ts +5 -45
  2. package/__tests__/devicePoolBootloaderPath.test.ts +64 -0
  3. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
  4. package/__tests__/protocol-v2.test.ts +100 -405
  5. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  6. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  7. package/dist/api/FirmwareUpdateV2.d.ts +0 -10
  8. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  9. package/dist/api/FirmwareUpdateV3.d.ts +3 -7
  10. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  11. package/dist/api/FirmwareUpdateV4.d.ts +5 -25
  12. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  13. package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
  14. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  15. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -8
  16. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  17. package/dist/api/firmware/getBinary.d.ts +0 -7
  18. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  19. package/dist/api/firmware/updateBootloader.d.ts +0 -2
  20. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  21. package/dist/api/firmware/uploadFirmware.d.ts +1 -9
  22. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  23. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  24. package/dist/core/index.d.ts.map +1 -1
  25. package/dist/data-manager/DataManager.d.ts +0 -1
  26. package/dist/data-manager/DataManager.d.ts.map +1 -1
  27. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  28. package/dist/device/Device.d.ts +0 -1
  29. package/dist/device/Device.d.ts.map +1 -1
  30. package/dist/device/DeviceConnector.d.ts +1 -1
  31. package/dist/device/DeviceConnector.d.ts.map +1 -1
  32. package/dist/device/DevicePool.d.ts +1 -0
  33. package/dist/device/DevicePool.d.ts.map +1 -1
  34. package/dist/index.d.ts +2 -180
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1078 -3083
  37. package/dist/inject.d.ts.map +1 -1
  38. package/dist/lowLevelInject.d.ts.map +1 -1
  39. package/dist/topLevelInject.d.ts.map +1 -1
  40. package/dist/types/api/checkAllFirmwareRelease.d.ts +0 -4
  41. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  42. package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
  43. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  44. package/dist/types/api/export.d.ts +1 -4
  45. package/dist/types/api/export.d.ts.map +1 -1
  46. package/dist/types/api/firmwareUpdate.d.ts +0 -68
  47. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  48. package/dist/types/api/index.d.ts +1 -9
  49. package/dist/types/api/index.d.ts.map +1 -1
  50. package/dist/types/settings.d.ts +0 -13
  51. package/dist/types/settings.d.ts.map +1 -1
  52. package/dist/utils/deviceFeaturesCompat.d.ts +0 -1
  53. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  54. package/package.json +4 -4
  55. package/src/api/CheckAllFirmwareRelease.ts +6 -57
  56. package/src/api/FirmwareUpdate.ts +1 -13
  57. package/src/api/FirmwareUpdateV2.ts +121 -296
  58. package/src/api/FirmwareUpdateV3.ts +57 -263
  59. package/src/api/FirmwareUpdateV4.ts +349 -881
  60. package/src/api/device/DeviceUpdateBootloader.ts +6 -125
  61. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +1 -72
  62. package/src/api/firmware/updateBootloader.ts +4 -19
  63. package/src/api/firmware/uploadFirmware.ts +22 -140
  64. package/src/core/index.ts +16 -0
  65. package/src/data-manager/DataManager.ts +54 -62
  66. package/src/data-manager/connectSettings.ts +0 -11
  67. package/src/device/Device.ts +3 -7
  68. package/src/device/DeviceConnector.ts +2 -2
  69. package/src/device/DevicePool.ts +15 -1
  70. package/src/index.ts +0 -5
  71. package/src/inject.ts +2 -22
  72. package/src/lowLevelInject.ts +1 -5
  73. package/src/topLevelInject.ts +1 -5
  74. package/src/types/api/checkAllFirmwareRelease.ts +0 -4
  75. package/src/types/api/deviceUpdateBootloader.ts +0 -6
  76. package/src/types/api/export.ts +0 -18
  77. package/src/types/api/firmwareUpdate.ts +0 -75
  78. package/src/types/api/index.ts +0 -14
  79. package/src/types/settings.ts +0 -13
  80. package/src/utils/deviceFeaturesCompat.ts +0 -6
  81. package/__tests__/device-initialize-timeout.test.ts +0 -56
  82. package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -175
  83. package/__tests__/firmware-update/device-update-bootloader.test.ts +0 -87
  84. package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
  85. package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
  86. package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
  87. package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +0 -200
  88. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
  89. package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +0 -394
  90. package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
  91. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -231
  92. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -64
  93. package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
  94. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
  95. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
  96. package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
  97. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
  98. package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
  99. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
  100. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
  101. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
  102. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
  103. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
  104. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -32
  105. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
  106. package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
  107. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
  108. package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
  109. package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
  110. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
  111. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
  112. package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
  113. package/src/api/firmware/FirmwareHostBinding.ts +0 -100
  114. package/src/api/firmware/FirmwarePreparationError.ts +0 -12
  115. package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
  116. package/src/api/firmware/FirmwareUpdatePlan.ts +0 -772
  117. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -449
  118. package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
  119. package/src/types/api/firmwareUpdatePlan.ts +0 -38
  120. package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
@@ -5,24 +5,15 @@ import { UI_REQUEST } from '../../constants/ui-request';
5
5
  import { FirmwareUpdateTipMessage } from '../../events/ui-request';
6
6
  import { FirmwareUpdateBaseMethod } from '../firmware/FirmwareUpdateBaseMethod';
7
7
  import { getSysResourceBinary } from '../firmware/getBinary';
8
- import { updateBootloader, updateBootloaderFromSource } from '../firmware/uploadFirmware';
8
+ import { updateBootloader } from '../firmware/uploadFirmware';
9
9
  import { DeviceModelToTypes } from '../../types';
10
10
  import { DataManager } from '../../data-manager';
11
- import { checkBootloaderLength, checkBootloaderSourceLength } from '../firmware/updateBootloader';
12
- import { openFirmwareByteSource } from '../firmware/FirmwareArtifactSource';
13
- import { resolveFirmwareUpdateHostBinding } from '../firmware/FirmwareHostBinding';
14
- import {
15
- assertFirmwareUpdatePreparedPlanBinding,
16
- assertFirmwareUpdatePreparedPlanDeviceIdentity,
17
- } from '../firmware/FirmwareUpdatePreparedPlan';
18
- import { getDeviceType, getDeviceUUID } from '../../utils';
19
- import { resolveDeviceBootloaderMode } from '../../utils/deviceFeaturesCompat';
11
+ import { checkBootloaderLength } from '../firmware/updateBootloader';
20
12
 
21
13
  import type { DeviceUpdateBootloaderParams } from '../../types/api/deviceUpdateBootloader';
22
14
  import type { EFirmwareType } from '@onekeyfe/hd-shared';
23
15
  import type { Device } from '../../device/Device';
24
16
  import type { Features } from '../../types';
25
- import type { FirmwareByteSource } from '../firmware/FirmwareArtifactSource';
26
17
 
27
18
  export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any> {
28
19
  init() {
@@ -52,68 +43,17 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
52
43
  return true;
53
44
  }
54
45
 
55
- async updateBootloaderWithEmmcFileWriteFromSource(_device: Device, source: FirmwareByteSource) {
56
- const filePath = '0:boot/bootloader.bin';
57
-
58
- this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
59
- await this.emmcCommonUpdateProcessFromSource({
60
- source,
61
- filePath,
62
- });
63
- this.postTipMessage(FirmwareUpdateTipMessage.ConfirmOnDevice);
64
- await this.reboot(RebootType.Normal);
65
- this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloaderSuccess);
66
- return true;
67
- }
68
-
69
46
  async updateTouchBootloader({
70
47
  device,
71
48
  features,
72
49
  firmwareType,
73
- binary: preparedBinary,
74
- source: preparedSource,
75
50
  }: {
76
51
  device: Device;
77
52
  features?: Features;
78
53
  firmwareType: EFirmwareType;
79
- binary?: ArrayBuffer;
80
- source?: FirmwareByteSource;
81
54
  }) {
82
- if (preparedSource) {
83
- if (!(await checkBootloaderSourceLength(preparedSource))) {
84
- throw ERRORS.TypedError(HardwareErrorCode.CheckDownloadFileError);
85
- }
86
- if (features && device.isBootloader()) {
87
- this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloader);
88
- const result = await this.updateBootloaderWithEmmcFileWriteFromSource(
89
- device,
90
- preparedSource
91
- );
92
- return result;
93
- }
94
- if (features && !device.isBootloader()) {
95
- await updateBootloaderFromSource(
96
- this.device.getCommands().typedCall.bind(this.device.getCommands()),
97
- this.postMessage,
98
- device,
99
- preparedSource
100
- );
101
- return true;
102
- }
103
- }
104
-
105
- let binary = preparedBinary;
55
+ let { binary } = this.payload;
106
56
  if (!binary) {
107
- if (DataManager.getSettings('firmwareManifestMode') === 'external-only') {
108
- throw ERRORS.TypedError(
109
- HardwareErrorCode.RuntimeError,
110
- 'Bootloader must be prepared by the external firmware host',
111
- {
112
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
113
- artifactName: 'bootloader',
114
- }
115
- );
116
- }
117
57
  this.postTipMessage(FirmwareUpdateTipMessage.CheckLatestUiResource);
118
58
  const resourceUrl = features
119
59
  ? DataManager.getBootloaderResource(features, firmwareType)
@@ -128,7 +68,7 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
128
68
  }
129
69
  }
130
70
 
131
- if (!binary || !checkBootloaderLength(binary)) {
71
+ if (!checkBootloaderLength(binary)) {
132
72
  throw ERRORS.TypedError(HardwareErrorCode.CheckDownloadFileError);
133
73
  }
134
74
 
@@ -136,8 +76,7 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
136
76
  if (features && device.isBootloader()) {
137
77
  // Use emmcFileWrite + reboot logic for bootloader mode
138
78
  this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloader);
139
- const result = await this.updateBootloaderWithEmmcFileWrite(device, binary);
140
- return result;
79
+ return this.updateBootloaderWithEmmcFileWrite(device, binary);
141
80
  }
142
81
 
143
82
  if (features && !device.isBootloader()) {
@@ -157,71 +96,13 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
157
96
  const { features } = device;
158
97
 
159
98
  const payload = this.payload as DeviceUpdateBootloaderParams;
160
- const hostBinding = payload.artifact
161
- ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
162
- : undefined;
163
- const executionParams = {
164
- ...payload,
165
- artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
166
- };
167
- if (payload.artifact) {
168
- assertFirmwareUpdatePreparedPlanDeviceIdentity({
169
- preparedPlan: payload.preparedPlan,
170
- deviceIdentity: getDeviceUUID(features) || undefined,
171
- bootloaderMode: resolveDeviceBootloaderMode(features),
172
- deviceModel: String(getDeviceType(features)),
173
- });
174
- assertFirmwareUpdatePreparedPlanBinding({
175
- preparedPlan: payload.preparedPlan,
176
- executor: 'v2',
177
- scopeTargets: ['bootloader'],
178
- bindings: [
179
- {
180
- target: 'bootloader',
181
- artifact: payload.artifact,
182
- },
183
- ],
184
- });
185
- const source = await openFirmwareByteSource({
186
- artifact: payload.artifact,
187
- reader: executionParams.artifactReader,
188
- });
189
- if (!source) {
190
- throw ERRORS.TypedError(
191
- HardwareErrorCode.RuntimeError,
192
- 'Bootloader artifact is not prepared'
193
- );
194
- }
195
- try {
196
- const deviceType = device.getCurrentDeviceType();
197
- const deviceFirmwareType = device.getCurrentFirmwareType();
198
- const firmwareType = payload.firmwareType ?? deviceFirmwareType;
199
- if (DeviceModelToTypes.model_touch.includes(deviceType)) {
200
- return await this.updateTouchBootloader({
201
- device,
202
- features,
203
- firmwareType,
204
- source,
205
- });
206
- }
207
- return true;
208
- } finally {
209
- await source.close().catch(() => undefined);
210
- }
211
- }
212
99
 
213
- const { binary } = payload;
214
100
  const deviceType = device.getCurrentDeviceType();
215
101
  const deviceFirmwareType = device.getCurrentFirmwareType();
216
102
  const firmwareType = payload.firmwareType ?? deviceFirmwareType;
217
103
 
218
104
  if (DeviceModelToTypes.model_touch.includes(deviceType)) {
219
- return this.updateTouchBootloader({
220
- device,
221
- features,
222
- firmwareType,
223
- binary,
224
- });
105
+ return this.updateTouchBootloader({ device, features, firmwareType });
225
106
  }
226
107
 
227
108
  return Promise.resolve(true);
@@ -13,7 +13,6 @@ import { DeviceModelToTypes } from '../../types';
13
13
  import { DataManager } from '../../data-manager';
14
14
  import { BaseMethod } from '../BaseMethod';
15
15
  import { DEVICE } from '../../events';
16
- import { writeFirmwareByteSource } from './FirmwareArtifactSource';
17
16
 
18
17
  import type {
19
18
  FirmwareProgress,
@@ -25,22 +24,11 @@ import type { RebootType } from '@onekeyfe/hd-transport';
25
24
  import type { Deferred } from '@onekeyfe/hd-shared';
26
25
  import type { KnownDevice } from '../../types';
27
26
  import type { TypedResponseMessage } from '../../device/DeviceCommands';
28
- import type { FirmwareByteSource } from './FirmwareArtifactSource';
29
27
 
30
28
  const Log = getLogger(LoggerNames.Method);
31
29
  const SESSION_ERROR = 'session not found';
32
30
  const FIRMWARE_UPDATE_CONFIRM = 'Firmware install confirmed';
33
31
 
34
- /**
35
- * Response timeout for each Initialize probe while polling a rebooting device over BLE.
36
- * Overlap safety comes from the poll's in-flight guard, not from this value. Keep it
37
- * well below the 30s reboot budget so several attempts fit: a probe written into the
38
- * dying pre-reboot connection is never answered, and its timeout tears that stale link
39
- * down so the next tick reconnects fresh. Raise it only if a device model is proven to
40
- * answer bootloader Initialize slower than this on a fresh connection.
41
- */
42
- export const BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS = 5000;
43
-
44
32
  type FirmwareTransferMetrics = Pick<
45
33
  FirmwareProgress['payload'],
46
34
  'transferredBytes' | 'totalBytes' | 'rateBytesPerSecond' | 'elapsedMs'
@@ -155,10 +143,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
155
143
  this.checkPromise = createDeferred();
156
144
  const env = DataManager.getSettings('env');
157
145
  const isBleReconnect = connectId && DataManager.isBleConnect(env);
158
- // Tracks the in-flight BLE probe so interval ticks never overlap: a superseded
159
- // Initialize left pending on the V1 transport is exactly what later times out
160
- // and used to tear down the connection mid-firmware-upload.
161
- let bleProbeInFlight = false;
162
146
 
163
147
  Log.log('FirmwareUpdateBaseMethod [checkDeviceToBootloader] isBleReconnect: ', isBleReconnect);
164
148
 
@@ -214,8 +198,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
214
198
  }
215
199
 
216
200
  if (isBleReconnect) {
217
- if (bleProbeInFlight) return;
218
- bleProbeInFlight = true;
219
201
  try {
220
202
  await this.device.deviceConnector?.acquire(
221
203
  this.device.originalDescriptor.id,
@@ -223,10 +205,7 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
223
205
  true,
224
206
  this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
225
207
  );
226
- // Bound each probe so a request the rebooting device never received
227
- // frees the slot for the next tick instead of hanging into the
228
- // 30s reboot budget.
229
- await this.device.initialize({ timeoutMs: BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS });
208
+ await this.device.initialize();
230
209
  if (this.device.isBootloader()) {
231
210
  clearInterval(intervalTimer);
232
211
  this.checkPromise?.resolve(true);
@@ -234,8 +213,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
234
213
  } catch (e) {
235
214
  // ignore error because of device is not connected
236
215
  Log.log('catch Bluetooth error when device is restarting: ', e);
237
- } finally {
238
- bleProbeInFlight = false;
239
216
  }
240
217
  } else {
241
218
  await this._checkDeviceInBootloaderMode(connectId, intervalTimer, timeoutTimer);
@@ -417,54 +394,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
417
394
  return totalSize !== undefined ? (processedSize ?? 0) + payload.byteLength : 0;
418
395
  }
419
396
 
420
- async emmcCommonUpdateProcessFromSource({
421
- source,
422
- filePath,
423
- processedSize,
424
- totalSize,
425
- }: {
426
- source: FirmwareByteSource;
427
- filePath: string;
428
- processedSize?: number;
429
- totalSize?: number;
430
- }) {
431
- if (!filePath.startsWith('0:')) {
432
- throw new Error('filePath must start with 0:');
433
- }
434
- const env = DataManager.getSettings('env');
435
- const chunkSize = 1024 * (DataManager.isBleConnect(env) ? 16 : 128);
436
-
437
- await writeFirmwareByteSource({
438
- source,
439
- chunkSize,
440
- write: async ({ data, sourceOffset, length, first }) => {
441
- const progress =
442
- totalSize !== undefined && processedSize !== undefined
443
- ? Math.min(Math.ceil(((processedSize + sourceOffset + length) / totalSize) * 100), 99)
444
- : Math.min(Math.ceil(((sourceOffset + length) / source.size) * 100), 99);
445
- const writeRes = await this.emmcFileWriteWithRetry(
446
- filePath,
447
- length,
448
- sourceOffset,
449
- data,
450
- first,
451
- progress
452
- );
453
- if (!writeRes) {
454
- throw ERRORS.TypedError(
455
- HardwareErrorCode.EmmcFileWriteFirmwareError,
456
- 'transfer data error'
457
- );
458
- }
459
- const processedBytes = Number(writeRes.message.processed_byte);
460
- this.postProgressMessage(progress, 'transferData');
461
- return Number.isFinite(processedBytes) ? processedBytes : length;
462
- },
463
- });
464
-
465
- return totalSize !== undefined ? (processedSize ?? 0) + source.size : 0;
466
- }
467
-
468
397
  async emmcFileWriteWithRetry(
469
398
  filePath: string,
470
399
  chunkLength: number,
@@ -8,7 +8,6 @@ import { shouldUpdateBootloaderForClassicAndMini } from './bootloaderHelper';
8
8
 
9
9
  import type { Features } from '../../types';
10
10
  import type { EFirmwareType } from '@onekeyfe/hd-shared';
11
- import type { FirmwareByteSource } from './FirmwareArtifactSource';
12
11
 
13
12
  export function checkNeedUpdateBootForTouch(features: Features, firmwareType: EFirmwareType) {
14
13
  const deviceType = getDeviceType(features);
@@ -63,7 +62,8 @@ export function checkNeedUpdateBootForClassicAndMini({
63
62
  }
64
63
 
65
64
  const INIT_DATA_CHUNK_SIZE = 16 * 1024;
66
- const readBootloaderLength = (chunk: Uint8Array) => {
65
+ export function checkBootloaderLength(data: ArrayBuffer) {
66
+ const chunk = new Uint8Array(data.slice(0, Math.min(INIT_DATA_CHUNK_SIZE, data.byteLength)));
67
67
  const buffer = ByteBuffer.wrap(chunk, undefined, undefined, true);
68
68
  buffer.LE();
69
69
  // byte 'O', 'K', 'T', 'B'
@@ -77,21 +77,6 @@ const readBootloaderLength = (chunk: Uint8Array) => {
77
77
  buffer.readUint32();
78
78
  // codelen
79
79
  const codelen = buffer.readUint32();
80
- return hdrlen + codelen;
81
- };
82
-
83
- export function checkBootloaderLength(data: ArrayBuffer) {
84
- if (data.byteLength < 16) {
85
- return false;
86
- }
87
- const chunk = new Uint8Array(data.slice(0, Math.min(INIT_DATA_CHUNK_SIZE, data.byteLength)));
88
- return readBootloaderLength(chunk) === data.byteLength;
80
+ const bootloaderLength = hdrlen + codelen;
81
+ return bootloaderLength === data.byteLength;
89
82
  }
90
-
91
- export const checkBootloaderSourceLength = async (source: FirmwareByteSource) => {
92
- if (source.size < 16) {
93
- return false;
94
- }
95
- const chunk = new Uint8Array(await source.readAt(0, Math.min(INIT_DATA_CHUNK_SIZE, source.size)));
96
- return readBootloaderLength(chunk) === source.size;
97
- };
@@ -10,7 +10,6 @@ import { bytesToHex } from '../helpers/hexUtils';
10
10
  import { DataManager } from '../../data-manager';
11
11
  import { DevicePool } from '../../device/DevicePool';
12
12
  import { buildProtocolV1FeaturesPayload } from '../../deviceProfile';
13
- import { openFirmwareByteSource, readFirmwareByteSourceFully } from './FirmwareArtifactSource';
14
13
 
15
14
  import type { KnownDevice } from '../../types';
16
15
  import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
@@ -18,7 +17,6 @@ import type { PROTO } from '../../constants';
18
17
  import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
19
18
  import type { Success } from '@onekeyfe/hd-transport';
20
19
  import type { Device } from '../../device/Device';
21
- import type { FirmwareByteSource } from './FirmwareArtifactSource';
22
20
 
23
21
  const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
24
22
  const SESSION_ERROR = 'session not found';
@@ -90,20 +88,17 @@ export const waitBleInstall = async (updateType: string) => {
90
88
  }
91
89
  };
92
90
 
93
- const toArrayBuffer = (payload: ArrayBuffer | Buffer): ArrayBuffer => {
94
- if (payload instanceof ArrayBuffer) {
95
- return payload;
96
- }
97
- return new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength).slice().buffer;
98
- };
99
-
100
- export const uploadFirmwareFromSource = async (
91
+ export const uploadFirmware = async (
101
92
  updateType: 'firmware' | 'ble',
102
93
  typedCall: TypedCall,
103
94
  postMessage: (message: CoreMessage) => void,
104
95
  device: Device,
105
- source: FirmwareByteSource,
106
- rebootOnSuccess?: boolean,
96
+ {
97
+ payload,
98
+ rebootOnSuccess,
99
+ }: PROTO.FirmwareUpload & {
100
+ rebootOnSuccess?: boolean;
101
+ },
107
102
  isUpdateBootloader?: boolean
108
103
  ) => {
109
104
  const deviceType = device.getCurrentDeviceType();
@@ -124,20 +119,20 @@ export const uploadFirmwareFromSource = async (
124
119
  if (supportUpgradeFileHeader) {
125
120
  // Extract and validate firmware header (first 1KB)
126
121
  const HEADER_SIZE = 1024;
127
- if (source.size < HEADER_SIZE) {
122
+ if (payload.byteLength < HEADER_SIZE) {
128
123
  throw ERRORS.TypedError(
129
124
  HardwareErrorCode.RuntimeError,
130
- `firmware payload too small: ${source.size} bytes, expected at least ${HEADER_SIZE} bytes`
125
+ `firmware payload too small: ${payload.byteLength} bytes, expected at least ${HEADER_SIZE} bytes`
131
126
  );
132
127
  }
133
128
 
134
129
  Log.debug('Uploading firmware header:', {
135
130
  size: HEADER_SIZE,
136
- totalSize: source.size,
131
+ totalSize: payload.byteLength,
137
132
  });
138
133
  postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
139
134
 
140
- const header = new Uint8Array(await source.readAt(0, HEADER_SIZE));
135
+ const header = new Uint8Array(payload.slice(0, HEADER_SIZE));
141
136
 
142
137
  try {
143
138
  const headerRes = await typedCall('UpgradeFileHeader', 'Success', {
@@ -174,9 +169,6 @@ export const uploadFirmwareFromSource = async (
174
169
  postProgressMessage(device, 0, 'installingFirmware', postMessage);
175
170
  let updateResponse: TypedResponseMessage<'Success'>;
176
171
  try {
177
- // Classic/Mini bootloaders accept one protobuf payload and do not expose
178
- // a request-range protocol. Other device families remain fully streamed.
179
- const payload = await readFirmwareByteSourceFully(source);
180
172
  updateResponse = await typedCall('FirmwareUpload', 'Success', {
181
173
  payload,
182
174
  });
@@ -208,7 +200,9 @@ export const uploadFirmwareFromSource = async (
208
200
  updateType,
209
201
  postMessage,
210
202
  device,
211
- source,
203
+ {
204
+ payload,
205
+ },
212
206
  rebootOnSuccess
213
207
  );
214
208
  return response.message;
@@ -217,7 +211,7 @@ export const uploadFirmwareFromSource = async (
217
211
 
218
212
  postConfirmationMessage(device);
219
213
  postProgressTip(device, 'ConfirmOnDevice', postMessage);
220
- const length = source.size;
214
+ const length = payload.byteLength;
221
215
 
222
216
  let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
223
217
  postProgressTip(device, 'FirmwareEraseSuccess', postMessage);
@@ -226,7 +220,7 @@ export const uploadFirmwareFromSource = async (
226
220
  const start = response.message.offset!;
227
221
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
228
222
  const end = response.message.offset! + response.message.length!;
229
- const chunk = await source.readAt(start, end - start);
223
+ const chunk = payload.slice(start, end);
230
224
 
231
225
  if (start > 0) {
232
226
  postProgressMessage(
@@ -255,45 +249,11 @@ export const uploadFirmwareFromSource = async (
255
249
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'uploadFirmware: unknown device model');
256
250
  };
257
251
 
258
- export const uploadFirmware = async (
259
- updateType: 'firmware' | 'ble',
260
- typedCall: TypedCall,
261
- postMessage: (message: CoreMessage) => void,
262
- device: Device,
263
- {
264
- payload,
265
- rebootOnSuccess,
266
- }: PROTO.FirmwareUpload & {
267
- rebootOnSuccess?: boolean;
268
- },
269
- isUpdateBootloader?: boolean
270
- ) => {
271
- const source = await openFirmwareByteSource({
272
- binary: toArrayBuffer(payload),
273
- });
274
- if (!source) {
275
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'firmware payload is empty');
276
- }
277
- try {
278
- return await uploadFirmwareFromSource(
279
- updateType,
280
- typedCall,
281
- postMessage,
282
- device,
283
- source,
284
- rebootOnSuccess,
285
- isUpdateBootloader
286
- );
287
- } finally {
288
- await source.close();
289
- }
290
- };
291
-
292
252
  const newTouchUpdateProcess = async (
293
253
  updateType: 'firmware' | 'ble',
294
254
  postMessage: (message: CoreMessage) => void,
295
255
  device: Device,
296
- source: FirmwareByteSource,
256
+ { payload }: PROTO.FirmwareUpload,
297
257
  rebootOnSuccess = true
298
258
  ) => {
299
259
  let typedCall = device.getCommands().typedCall.bind(device.getCommands());
@@ -303,13 +263,13 @@ const newTouchUpdateProcess = async (
303
263
  const env = DataManager.getSettings('env');
304
264
  const perPackageSize = DataManager.isBleConnect(env) ? 16 : 128;
305
265
  const chunkSize = 1024 * perPackageSize;
306
- const totalChunks = Math.ceil(source.size / chunkSize);
266
+ const totalChunks = Math.ceil(payload.byteLength / chunkSize);
307
267
  let offset = 0;
308
268
  for (let i = 0; i < totalChunks; i++) {
309
269
  const chunkStart = i * chunkSize;
310
- const chunkEnd = Math.min(chunkStart + chunkSize, source.size);
270
+ const chunkEnd = Math.min(chunkStart + chunkSize, payload.byteLength);
311
271
  const chunkLength = chunkEnd - chunkStart;
312
- const chunk = await source.readAt(chunkStart, chunkLength);
272
+ const chunk = payload.slice(chunkStart, chunkEnd);
313
273
  const overwrite = i === 0;
314
274
  const progress = Math.round(((i + 1) / totalChunks) * 100);
315
275
  const writeRes = await emmcFileWriteWithRetry(
@@ -543,67 +503,6 @@ export const updateResource = async (
543
503
  return processResourceRequest(typedCall, res, data);
544
504
  };
545
505
 
546
- export const updateResourceFromSource = async (
547
- typedCall: TypedCall,
548
- fileName: string,
549
- source: FirmwareByteSource,
550
- onConfirmAfter?: () => void
551
- ) => {
552
- const initialLength = Math.min(INIT_DATA_CHUNK_SIZE, source.size);
553
- const initialChunk = new Uint8Array(await source.readAt(0, initialLength));
554
- let response = await typedCall('ResourceUpdate', ['ResourceRequest', 'Success'], {
555
- file_name: fileName,
556
- data_length: source.size,
557
- initial_data_chunk: bytesToHex(initialChunk),
558
- hash: bytesToHex(blake2s(initialChunk)),
559
- });
560
- onConfirmAfter?.();
561
-
562
- while (response.type !== 'Success') {
563
- const { offset, data_length: dataLength } = response.message;
564
- if (
565
- !Number.isSafeInteger(offset) ||
566
- offset === undefined ||
567
- offset < 0 ||
568
- !Number.isSafeInteger(dataLength) ||
569
- dataLength === undefined ||
570
- dataLength <= 0 ||
571
- offset + dataLength > source.size
572
- ) {
573
- throw ERRORS.TypedError(
574
- HardwareErrorCode.RuntimeError,
575
- 'Device requested an invalid firmware resource range'
576
- );
577
- }
578
- const chunk = new Uint8Array(await source.readAt(offset, dataLength));
579
- response = await typedCall('ResourceAck', ['ResourceRequest', 'Success'], {
580
- data_chunk: bytesToHex(chunk),
581
- hash: bytesToHex(blake2s(chunk)),
582
- });
583
- }
584
- return response.message;
585
- };
586
-
587
- export const updateResourcesFromSources = async (
588
- typedCall: TypedCall,
589
- postMessage: (message: CoreMessage) => void,
590
- device: Device,
591
- entries: ReadonlyArray<{ entryName: string; source: FirmwareByteSource }>
592
- ) => {
593
- postProgressTip(device, 'UpdateSysResource', postMessage);
594
- for (const [index, entry] of entries.entries()) {
595
- await updateResourceFromSource(typedCall, entry.entryName, entry.source);
596
- postProgressMessage(
597
- device,
598
- Math.floor(((index + 1) / entries.length) * 100),
599
- 'installingFirmware',
600
- postMessage
601
- );
602
- }
603
- postProgressTip(device, 'UpdateSysResourceSuccess', postMessage);
604
- return true;
605
- };
606
-
607
506
  export const updateResources = async (
608
507
  typedCall: TypedCall,
609
508
  postMessage: (message: CoreMessage) => void,
@@ -638,28 +537,11 @@ export const updateBootloader = async (
638
537
  typedCall: TypedCall,
639
538
  postMessage: (message: CoreMessage) => void,
640
539
  device: Device,
641
- data: ArrayBuffer
642
- ) => {
643
- const source = await openFirmwareByteSource({ binary: data });
644
- if (!source) {
645
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'bootloader payload is empty');
646
- }
647
- try {
648
- return await updateBootloaderFromSource(typedCall, postMessage, device, source);
649
- } finally {
650
- await source.close();
651
- }
652
- };
653
-
654
- export const updateBootloaderFromSource = async (
655
- typedCall: TypedCall,
656
- postMessage: (message: CoreMessage) => void,
657
- device: Device,
658
- source: FirmwareByteSource
540
+ source: ArrayBuffer
659
541
  ) => {
660
542
  postProgressTip(device, 'UpdateBootloader', postMessage);
661
543
  postProgressMessage(device, Math.floor(0), 'installingFirmware', postMessage);
662
- await updateResourceFromSource(typedCall, 'bootloader.bin', source, () => {
544
+ await updateResource(typedCall, 'bootloader.bin', source, () => {
663
545
  postProcessingMessage('resource', postMessage);
664
546
  });
665
547
  postProgressMessage(device, Math.floor(100), 'installingFirmware', postMessage);
package/src/core/index.ts CHANGED
@@ -3,6 +3,7 @@ import EventEmitter from 'events';
3
3
  import { DeviceSessionPinType, TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
4
4
  import {
5
5
  ERRORS,
6
+ ERROR_CODES_REQUIRE_DISCONNECT,
6
7
  ERROR_CODES_REQUIRE_RELEASE,
7
8
  HardwareError,
8
9
  HardwareErrorCode,
@@ -933,6 +934,21 @@ async function connectDeviceForBle(method: BaseMethod, device: Device, retryCoun
933
934
  DevicePool.emitter.emit(DEVICE.CONNECT, device);
934
935
  }
935
936
  } catch (err) {
937
+ // Device.run()'s REQUIRE_DISCONNECT handling never sees acquire/initialize
938
+ // failures, so with keep-alive a wedged link would be reused by every retry
939
+ // (field case: Initialize timing out at 25s per attempt, forever). Drop it
940
+ // here so the next retry cold-connects.
941
+ if (
942
+ ERROR_CODES_REQUIRE_DISCONNECT.includes(err.errorCode) &&
943
+ device.mainId &&
944
+ device.deviceConnector
945
+ ) {
946
+ await device.deviceConnector.disconnect(device.mainId).catch(() => undefined);
947
+ // The connector only drops the link; `deviceAcquired` is reset by
948
+ // release()/markTransportDisconnected() alone. Leaving it set makes the
949
+ // next attempt skip acquire and initialize onto the link we just cut.
950
+ device.markTransportDisconnected();
951
+ }
936
952
  if (
937
953
  (err.errorCode === HardwareErrorCode.BleTimeoutError ||
938
954
  err.errorCode === HardwareErrorCode.BleConnectedError ||