@otakit/capacitor-updater 2.3.2 → 3.0.0
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/README.md +46 -5
- package/android/build.gradle +16 -0
- package/android/src/main/java/com/otakit/updater/BundleCrypto.java +38 -17
- package/android/src/main/java/com/otakit/updater/BundleInfo.java +10 -0
- package/android/src/main/java/com/otakit/updater/BundleStore.java +134 -86
- package/android/src/main/java/com/otakit/updater/CheckFailure.java +53 -0
- package/android/src/main/java/com/otakit/updater/DeltaAssembler.java +46 -41
- package/android/src/main/java/com/otakit/updater/DeviceEventClient.java +125 -26
- package/android/src/main/java/com/otakit/updater/DocumentReadyBridge.java +71 -0
- package/android/src/main/java/com/otakit/updater/DownloadRetry.java +144 -0
- package/android/src/main/java/com/otakit/updater/EventOutbox.java +174 -0
- package/android/src/main/java/com/otakit/updater/FileDownloader.java +80 -0
- package/android/src/main/java/com/otakit/updater/ForegroundDeadline.java +84 -0
- package/android/src/main/java/com/otakit/updater/HashUtils.java +26 -0
- package/android/src/main/java/com/otakit/updater/ManifestClient.java +12 -9
- package/android/src/main/java/com/otakit/updater/ManifestKeyConfig.java +47 -0
- package/android/src/main/java/com/otakit/updater/ManifestVerifier.java +22 -4
- package/android/src/main/java/com/otakit/updater/SDKVersion.java +9 -0
- package/android/src/main/java/com/otakit/updater/UpdateOwner.java +27 -0
- package/android/src/main/java/com/otakit/updater/UpdaterCoordinator.java +154 -59
- package/android/src/main/java/com/otakit/updater/UpdaterPlugin.java +284 -209
- package/android/src/main/java/com/otakit/updater/WebViewActivation.java +26 -0
- package/dist/esm/definitions.d.ts +3 -3
- package/dist/esm/definitions.d.ts.map +1 -1
- package/ios/Sources/UpdaterPlugin/BundleCrypto.swift +35 -3
- package/ios/Sources/UpdaterPlugin/BundleInfo.swift +13 -0
- package/ios/Sources/UpdaterPlugin/BundleStore.swift +103 -77
- package/ios/Sources/UpdaterPlugin/CheckFailure.swift +41 -0
- package/ios/Sources/UpdaterPlugin/DeltaAssembler.swift +29 -17
- package/ios/Sources/UpdaterPlugin/DeviceEventClient.swift +12 -10
- package/ios/Sources/UpdaterPlugin/DocumentReadyBridge.swift +43 -0
- package/ios/Sources/UpdaterPlugin/DownloadRetry.swift +51 -0
- package/ios/Sources/UpdaterPlugin/Downloader.swift +97 -39
- package/ios/Sources/UpdaterPlugin/EventOutbox.swift +183 -0
- package/ios/Sources/UpdaterPlugin/ForegroundDeadline.swift +94 -0
- package/ios/Sources/UpdaterPlugin/HashUtils.swift +16 -0
- package/ios/Sources/UpdaterPlugin/ManifestClient.swift +2 -4
- package/ios/Sources/UpdaterPlugin/ManifestKeyConfig.swift +20 -0
- package/ios/Sources/UpdaterPlugin/ManifestVerifier.swift +7 -1
- package/ios/Sources/UpdaterPlugin/SDKVersion.swift +4 -0
- package/ios/Sources/UpdaterPlugin/UpdateOwner.swift +12 -0
- package/ios/Sources/UpdaterPlugin/UpdaterCoordinator.swift +146 -110
- package/ios/Sources/UpdaterPlugin/UpdaterPlugin.swift +206 -202
- package/ios/Tests/UpdaterPluginTests/BundleCryptoTests.swift +80 -0
- package/ios/Tests/UpdaterPluginTests/BundlePersistenceTests.swift +102 -0
- package/ios/Tests/UpdaterPluginTests/CheckFailureTests.swift +55 -0
- package/ios/Tests/UpdaterPluginTests/DeltaCacheIntegrityTests.swift +69 -0
- package/ios/Tests/UpdaterPluginTests/DocumentReadyBridgeTests.swift +102 -0
- package/ios/Tests/UpdaterPluginTests/DownloadIntegrityTests.swift +40 -0
- package/ios/Tests/UpdaterPluginTests/DownloadRetryTests.swift +189 -0
- package/ios/Tests/UpdaterPluginTests/EventDeliveryTests.swift +56 -0
- package/ios/Tests/UpdaterPluginTests/EventOutboxTests.swift +86 -0
- package/ios/Tests/UpdaterPluginTests/ForegroundDeadlineTests.swift +144 -0
- package/ios/Tests/UpdaterPluginTests/ManifestKeyConfigTests.swift +48 -0
- package/ios/Tests/UpdaterPluginTests/UpdateOwnerTests.swift +34 -0
- package/ios/Tests/UpdaterPluginTests/UpdaterCoordinatorTests.swift +394 -0
- package/package.json +7 -3
|
@@ -10,6 +10,16 @@ import java.util.concurrent.locks.ReentrantLock;
|
|
|
10
10
|
|
|
11
11
|
final class UpdaterCoordinator {
|
|
12
12
|
|
|
13
|
+
static final class Trial {
|
|
14
|
+
|
|
15
|
+
final String bundleId;
|
|
16
|
+
final String activationId = java.util.UUID.randomUUID().toString();
|
|
17
|
+
|
|
18
|
+
Trial(String bundleId) {
|
|
19
|
+
this.bundleId = bundleId;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
interface BundlePredicate {
|
|
14
24
|
boolean test(BundleInfo bundle);
|
|
15
25
|
}
|
|
@@ -42,6 +52,8 @@ final class UpdaterCoordinator {
|
|
|
42
52
|
final String channel;
|
|
43
53
|
final String releaseId;
|
|
44
54
|
final String detail;
|
|
55
|
+
final String attemptId;
|
|
56
|
+
final String phase;
|
|
45
57
|
|
|
46
58
|
DeviceEventPayload(
|
|
47
59
|
String action,
|
|
@@ -50,6 +62,19 @@ final class UpdaterCoordinator {
|
|
|
50
62
|
String channel,
|
|
51
63
|
String releaseId,
|
|
52
64
|
String detail
|
|
65
|
+
) {
|
|
66
|
+
this(action, bundleVersion, runtimeVersion, channel, releaseId, detail, null, null);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
DeviceEventPayload(
|
|
70
|
+
String action,
|
|
71
|
+
String bundleVersion,
|
|
72
|
+
String runtimeVersion,
|
|
73
|
+
String channel,
|
|
74
|
+
String releaseId,
|
|
75
|
+
String detail,
|
|
76
|
+
String attemptId,
|
|
77
|
+
String phase
|
|
53
78
|
) {
|
|
54
79
|
this.action = action;
|
|
55
80
|
this.bundleVersion = bundleVersion;
|
|
@@ -57,6 +82,8 @@ final class UpdaterCoordinator {
|
|
|
57
82
|
this.channel = channel;
|
|
58
83
|
this.releaseId = releaseId;
|
|
59
84
|
this.detail = detail;
|
|
85
|
+
this.attemptId = attemptId;
|
|
86
|
+
this.phase = phase;
|
|
60
87
|
}
|
|
61
88
|
}
|
|
62
89
|
|
|
@@ -86,18 +113,18 @@ final class UpdaterCoordinator {
|
|
|
86
113
|
static final class StartupPreparation {
|
|
87
114
|
|
|
88
115
|
final String activationPath;
|
|
89
|
-
final
|
|
116
|
+
final Trial trial;
|
|
90
117
|
final List<String> cleanupBundleIds;
|
|
91
118
|
final DeviceEventPayload eventPayload;
|
|
92
119
|
|
|
93
120
|
StartupPreparation(
|
|
94
121
|
String activationPath,
|
|
95
|
-
|
|
122
|
+
Trial trial,
|
|
96
123
|
List<String> cleanupBundleIds,
|
|
97
124
|
DeviceEventPayload eventPayload
|
|
98
125
|
) {
|
|
99
126
|
this.activationPath = activationPath;
|
|
100
|
-
this.
|
|
127
|
+
this.trial = trial;
|
|
101
128
|
this.cleanupBundleIds = cleanupBundleIds;
|
|
102
129
|
this.eventPayload = eventPayload;
|
|
103
130
|
}
|
|
@@ -106,12 +133,12 @@ final class UpdaterCoordinator {
|
|
|
106
133
|
static final class ApplyPreparation {
|
|
107
134
|
|
|
108
135
|
final String activationPath;
|
|
109
|
-
final
|
|
136
|
+
final Trial trial;
|
|
110
137
|
final List<String> cleanupBundleIds;
|
|
111
138
|
|
|
112
|
-
ApplyPreparation(String activationPath,
|
|
139
|
+
ApplyPreparation(String activationPath, Trial trial, List<String> cleanupBundleIds) {
|
|
113
140
|
this.activationPath = activationPath;
|
|
114
|
-
this.
|
|
141
|
+
this.trial = trial;
|
|
115
142
|
this.cleanupBundleIds = cleanupBundleIds;
|
|
116
143
|
}
|
|
117
144
|
|
|
@@ -176,6 +203,7 @@ final class UpdaterCoordinator {
|
|
|
176
203
|
private final BundleStore store;
|
|
177
204
|
private final AtomicBoolean operationInProgress = new AtomicBoolean(false);
|
|
178
205
|
private final ReentrantLock stateLock = new ReentrantLock();
|
|
206
|
+
private Trial activeTrial;
|
|
179
207
|
|
|
180
208
|
UpdaterCoordinator(BundleStore store) {
|
|
181
209
|
this.store = store;
|
|
@@ -214,6 +242,7 @@ final class UpdaterCoordinator {
|
|
|
214
242
|
|
|
215
243
|
List<String> pruneIncompatibleBundles(BundlePredicate isCompatibleRuntime) {
|
|
216
244
|
return withStateLock(() -> {
|
|
245
|
+
store.protectedBundleIds();
|
|
217
246
|
Set<String> cleanupBundleIds = new LinkedHashSet<>();
|
|
218
247
|
|
|
219
248
|
for (BundleInfo bundle : store.listDownloadedBundleInfos()) {
|
|
@@ -234,6 +263,8 @@ final class UpdaterCoordinator {
|
|
|
234
263
|
|
|
235
264
|
StartupPreparation normalizeStartupState(BundlePredicate isBundleUsable) {
|
|
236
265
|
return withStateLock(() -> {
|
|
266
|
+
store.protectedBundleIds();
|
|
267
|
+
activeTrial = null;
|
|
237
268
|
Set<String> cleanupBundleIds = new LinkedHashSet<>();
|
|
238
269
|
clearStaleBundlePointersLocked();
|
|
239
270
|
normalizeStagedPointerLocked(isBundleUsable, cleanupBundleIds);
|
|
@@ -251,20 +282,28 @@ final class UpdaterCoordinator {
|
|
|
251
282
|
}
|
|
252
283
|
|
|
253
284
|
BundleInfo normalizedCurrent = store.getCurrentBundle();
|
|
254
|
-
if (
|
|
285
|
+
if (
|
|
286
|
+
!normalizedCurrent.isBuiltin() &&
|
|
287
|
+
(normalizedCurrent.status == BundleStatus.ERROR || !isBundleUsable.test(normalizedCurrent))
|
|
288
|
+
) {
|
|
255
289
|
cleanupBundleIds.add(normalizedCurrent.id);
|
|
256
|
-
normalizedCurrent = restoreFallbackOrBuiltinLocked(
|
|
290
|
+
normalizedCurrent = restoreFallbackOrBuiltinLocked(
|
|
291
|
+
isBundleUsable,
|
|
292
|
+
cleanupBundleIds,
|
|
293
|
+
normalizedCurrent.id,
|
|
294
|
+
null
|
|
295
|
+
);
|
|
257
296
|
}
|
|
258
297
|
|
|
259
|
-
|
|
298
|
+
Trial trial = null;
|
|
260
299
|
if (!normalizedCurrent.isBuiltin() && normalizedCurrent.status == BundleStatus.PENDING) {
|
|
261
300
|
normalizedCurrent = updateStatusLocked(normalizedCurrent, BundleStatus.TRIAL);
|
|
262
|
-
|
|
301
|
+
trial = beginTrialLocked(normalizedCurrent.id);
|
|
263
302
|
}
|
|
264
303
|
|
|
265
304
|
return new StartupPreparation(
|
|
266
305
|
normalizedCurrent.isBuiltin() ? null : normalizedCurrent.path,
|
|
267
|
-
|
|
306
|
+
trial,
|
|
268
307
|
new ArrayList<>(cleanupBundleIds),
|
|
269
308
|
eventPayload
|
|
270
309
|
);
|
|
@@ -318,6 +357,9 @@ final class UpdaterCoordinator {
|
|
|
318
357
|
|
|
319
358
|
List<String> stageDownloadedBundle(BundleInfo bundle) throws Exception {
|
|
320
359
|
return withStateLock(() -> {
|
|
360
|
+
if (bundle.isBuiltin() || store.protectedBundleIds().contains(bundle.id)) {
|
|
361
|
+
throw new IllegalStateException("Cannot overwrite a referenced bundle installation");
|
|
362
|
+
}
|
|
321
363
|
Set<String> cleanupBundleIds = new LinkedHashSet<>();
|
|
322
364
|
String previousStagedId = store.getStagedBundleId();
|
|
323
365
|
store.saveBundle(bundle);
|
|
@@ -343,6 +385,11 @@ final class UpdaterCoordinator {
|
|
|
343
385
|
) {
|
|
344
386
|
return withStateLock(() -> {
|
|
345
387
|
Set<String> cleanupBundleIds = new LinkedHashSet<>();
|
|
388
|
+
BundleInfo previousCurrent = store.getCurrentBundle();
|
|
389
|
+
// A staged update must not replace the only running trial before it is acknowledged.
|
|
390
|
+
if (previousCurrent.status == BundleStatus.TRIAL) {
|
|
391
|
+
return new ApplyPreparation(null, null, new ArrayList<>());
|
|
392
|
+
}
|
|
346
393
|
BundleInfo staged = stagedBundleLocked(
|
|
347
394
|
true,
|
|
348
395
|
isCompatibleRuntime,
|
|
@@ -353,38 +400,42 @@ final class UpdaterCoordinator {
|
|
|
353
400
|
return new ApplyPreparation(null, null, new ArrayList<>(cleanupBundleIds));
|
|
354
401
|
}
|
|
355
402
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
store.setCurrentBundleId(staged.id);
|
|
364
|
-
store.setStagedBundleId(null);
|
|
365
|
-
|
|
366
|
-
String trialBundleId = null;
|
|
403
|
+
String fallbackId = previousCurrent.isBuiltin()
|
|
404
|
+
? null
|
|
405
|
+
: (previousCurrent.status == BundleStatus.SUCCESS
|
|
406
|
+
? previousCurrent.id
|
|
407
|
+
: store.getFallbackBundleId());
|
|
367
408
|
if (staged.status == BundleStatus.PENDING) {
|
|
368
409
|
staged = updateStatusLocked(staged, BundleStatus.TRIAL);
|
|
369
|
-
trialBundleId = staged.id;
|
|
370
|
-
} else if (staged.status == BundleStatus.TRIAL) {
|
|
371
|
-
trialBundleId = staged.id;
|
|
372
410
|
}
|
|
411
|
+
store.setCoreState(staged.id, fallbackId, null, store.getLastFailedBundle());
|
|
412
|
+
Trial trial = staged.status == BundleStatus.TRIAL ? beginTrialLocked(staged.id) : null;
|
|
373
413
|
|
|
374
|
-
return new ApplyPreparation(staged.path,
|
|
414
|
+
return new ApplyPreparation(staged.path, trial, new ArrayList<>(cleanupBundleIds));
|
|
375
415
|
});
|
|
376
416
|
}
|
|
377
417
|
|
|
378
|
-
NotifyReadyPreparation prepareNotifyAppReady() {
|
|
418
|
+
NotifyReadyPreparation prepareNotifyAppReady(String activationId) {
|
|
379
419
|
return withStateLock(() -> {
|
|
380
420
|
BundleInfo current = store.getCurrentBundle();
|
|
381
|
-
if (
|
|
421
|
+
if (
|
|
422
|
+
current.isBuiltin() ||
|
|
423
|
+
activeTrial == null ||
|
|
424
|
+
!activeTrial.activationId.equals(activationId) ||
|
|
425
|
+
!activeTrial.bundleId.equals(current.id) ||
|
|
426
|
+
(current.status != BundleStatus.TRIAL &&
|
|
427
|
+
!(current.status == BundleStatus.SUCCESS &&
|
|
428
|
+
!current.id.equals(store.getFallbackBundleId())))
|
|
429
|
+
) {
|
|
382
430
|
return new NotifyReadyPreparation(null, new ArrayList<>());
|
|
383
431
|
}
|
|
384
432
|
|
|
385
433
|
String oldFallbackId = store.getFallbackBundleId();
|
|
386
|
-
|
|
434
|
+
if (current.status == BundleStatus.TRIAL) {
|
|
435
|
+
updateStatusLocked(current, BundleStatus.SUCCESS);
|
|
436
|
+
}
|
|
387
437
|
store.setFallbackBundleId(current.id);
|
|
438
|
+
activeTrial = null;
|
|
388
439
|
|
|
389
440
|
Set<String> cleanupBundleIds = new LinkedHashSet<>();
|
|
390
441
|
if (oldFallbackId != null && !oldFallbackId.equals(current.id)) {
|
|
@@ -398,15 +449,31 @@ final class UpdaterCoordinator {
|
|
|
398
449
|
current.runtimeVersion,
|
|
399
450
|
current.channel,
|
|
400
451
|
current.releaseId,
|
|
401
|
-
null
|
|
452
|
+
null,
|
|
453
|
+
current.attemptId(),
|
|
454
|
+
"readiness"
|
|
402
455
|
),
|
|
403
456
|
new ArrayList<>(cleanupBundleIds)
|
|
404
457
|
);
|
|
405
458
|
});
|
|
406
459
|
}
|
|
407
460
|
|
|
408
|
-
RollbackPreparation prepareRollback(
|
|
461
|
+
RollbackPreparation prepareRollback(
|
|
462
|
+
Trial expectedTrial,
|
|
463
|
+
String reason,
|
|
464
|
+
BundlePredicate isBundleUsable
|
|
465
|
+
) {
|
|
409
466
|
return withStateLock(() -> {
|
|
467
|
+
BundleInfo current = store.getCurrentBundle();
|
|
468
|
+
if (
|
|
469
|
+
activeTrial == null ||
|
|
470
|
+
expectedTrial == null ||
|
|
471
|
+
!activeTrial.activationId.equals(expectedTrial.activationId) ||
|
|
472
|
+
!current.id.equals(expectedTrial.bundleId) ||
|
|
473
|
+
current.status != BundleStatus.TRIAL
|
|
474
|
+
) {
|
|
475
|
+
return new RollbackPreparation(false, null, null, new ArrayList<>());
|
|
476
|
+
}
|
|
410
477
|
Set<String> cleanupBundleIds = new LinkedHashSet<>();
|
|
411
478
|
LockedRollbackResult rollback = rollbackLocked(reason, isBundleUsable, cleanupBundleIds);
|
|
412
479
|
return new RollbackPreparation(
|
|
@@ -418,11 +485,9 @@ final class UpdaterCoordinator {
|
|
|
418
485
|
});
|
|
419
486
|
}
|
|
420
487
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
return current.id.equals(bundleId) && current.status == BundleStatus.TRIAL;
|
|
425
|
-
});
|
|
488
|
+
private Trial beginTrialLocked(String bundleId) {
|
|
489
|
+
activeTrial = new Trial(bundleId);
|
|
490
|
+
return activeTrial;
|
|
426
491
|
}
|
|
427
492
|
|
|
428
493
|
void cleanupBundles(List<String> bundleIds) {
|
|
@@ -433,9 +498,22 @@ final class UpdaterCoordinator {
|
|
|
433
498
|
}
|
|
434
499
|
}
|
|
435
500
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
501
|
+
withStateLock(() -> {
|
|
502
|
+
Set<String> protectedIds;
|
|
503
|
+
try {
|
|
504
|
+
protectedIds = store.protectedBundleIds();
|
|
505
|
+
} catch (Exception error) {
|
|
506
|
+
// An unreadable state is not evidence that these files are unreferenced.
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
for (String bundleId : uniqueIds) {
|
|
510
|
+
// Cleanup can run after a newer transition has made this bundle live again.
|
|
511
|
+
if (!protectedIds.contains(bundleId)) {
|
|
512
|
+
deleteRecursivelyQuietly(store.bundleDirectory(bundleId));
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return null;
|
|
516
|
+
});
|
|
439
517
|
}
|
|
440
518
|
|
|
441
519
|
private <T> T withStateLock(LockedSupplier<T> work) {
|
|
@@ -482,7 +560,7 @@ final class UpdaterCoordinator {
|
|
|
482
560
|
return;
|
|
483
561
|
}
|
|
484
562
|
|
|
485
|
-
if (!isBundleUsable.test(fallback)) {
|
|
563
|
+
if (fallback.status != BundleStatus.SUCCESS || !isBundleUsable.test(fallback)) {
|
|
486
564
|
store.setFallbackBundleId(null);
|
|
487
565
|
cleanupBundleIds.add(fallback.id);
|
|
488
566
|
}
|
|
@@ -576,11 +654,14 @@ final class UpdaterCoordinator {
|
|
|
576
654
|
return new LockedRollbackResult(false, null, null);
|
|
577
655
|
}
|
|
578
656
|
|
|
579
|
-
BundleInfo failed =
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
657
|
+
BundleInfo failed = current.withStatus(BundleStatus.ERROR);
|
|
658
|
+
BundleInfo fallback = restoreFallbackOrBuiltinLocked(
|
|
659
|
+
isBundleUsable,
|
|
660
|
+
cleanupBundleIds,
|
|
661
|
+
current.id,
|
|
662
|
+
failed
|
|
663
|
+
);
|
|
664
|
+
activeTrial = null;
|
|
584
665
|
cleanupBundleIds.add(current.id);
|
|
585
666
|
|
|
586
667
|
return new LockedRollbackResult(
|
|
@@ -592,40 +673,54 @@ final class UpdaterCoordinator {
|
|
|
592
673
|
current.runtimeVersion,
|
|
593
674
|
current.channel,
|
|
594
675
|
current.releaseId,
|
|
595
|
-
reason
|
|
676
|
+
reason,
|
|
677
|
+
current.attemptId(),
|
|
678
|
+
"rollback"
|
|
596
679
|
)
|
|
597
680
|
);
|
|
598
681
|
}
|
|
599
682
|
|
|
600
683
|
private BundleInfo restoreFallbackOrBuiltinLocked(
|
|
601
684
|
BundlePredicate isBundleUsable,
|
|
602
|
-
Set<String> cleanupBundleIds
|
|
685
|
+
Set<String> cleanupBundleIds,
|
|
686
|
+
String excludedBundleId,
|
|
687
|
+
BundleInfo failedBundle
|
|
603
688
|
) {
|
|
689
|
+
BundleInfo restored = store.builtinBundle();
|
|
604
690
|
String fallbackId = store.getFallbackBundleId();
|
|
605
691
|
if (fallbackId != null) {
|
|
606
692
|
BundleInfo fallback = store.getBundle(fallbackId);
|
|
607
|
-
if (
|
|
608
|
-
|
|
609
|
-
|
|
693
|
+
if (
|
|
694
|
+
fallback != null &&
|
|
695
|
+
!fallback.isBuiltin() &&
|
|
696
|
+
!fallback.id.equals(excludedBundleId) &&
|
|
697
|
+
fallback.status == BundleStatus.SUCCESS &&
|
|
698
|
+
isBundleUsable.test(fallback)
|
|
699
|
+
) {
|
|
700
|
+
restored = fallback;
|
|
610
701
|
}
|
|
611
702
|
}
|
|
612
703
|
|
|
613
|
-
if (fallbackId != null) {
|
|
614
|
-
|
|
615
|
-
if (!"builtin".equals(fallbackId)) {
|
|
616
|
-
cleanupBundleIds.add(fallbackId);
|
|
617
|
-
}
|
|
704
|
+
if (fallbackId != null && !"builtin".equals(fallbackId) && !fallbackId.equals(restored.id)) {
|
|
705
|
+
cleanupBundleIds.add(fallbackId);
|
|
618
706
|
}
|
|
619
|
-
|
|
620
|
-
store.
|
|
621
|
-
|
|
707
|
+
String restoredId = restored.isBuiltin() ? null : restored.id;
|
|
708
|
+
store.setCoreState(
|
|
709
|
+
restoredId,
|
|
710
|
+
restoredId,
|
|
711
|
+
failedBundle == null ? store.getStagedBundleId() : null,
|
|
712
|
+
failedBundle == null ? store.getLastFailedBundle() : failedBundle
|
|
713
|
+
);
|
|
714
|
+
return restored;
|
|
622
715
|
}
|
|
623
716
|
|
|
624
717
|
private BundleInfo updateStatusLocked(BundleInfo bundle, BundleStatus status) {
|
|
625
718
|
BundleInfo updated = bundle.withStatus(status);
|
|
626
719
|
try {
|
|
627
720
|
store.saveBundle(updated);
|
|
628
|
-
} catch (Exception
|
|
721
|
+
} catch (Exception error) {
|
|
722
|
+
throw new IllegalStateException("Could not persist bundle status", error);
|
|
723
|
+
}
|
|
629
724
|
return updated;
|
|
630
725
|
}
|
|
631
726
|
|