Switch back to serial BG installs (#984)

This commit is contained in:
Imran Remtulla
2023-10-11 20:42:33 -04:00
parent 036823cbb6
commit 488049821e

View File

@@ -1369,12 +1369,6 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
(<List<MapEntry<String, int>>>[])) (<List<MapEntry<String, int>>>[]))
]; ];
bool installMode = toCheck.isEmpty &&
toInstall.isNotEmpty; // Task is either in update mode or install mode
logs.add(
'BG ${installMode ? 'install' : 'update'} task $taskId: Started (${installMode ? toInstall.length : toCheck.length}).');
var netResult = await (Connectivity().checkConnectivity()); var netResult = await (Connectivity().checkConnectivity());
if (netResult == ConnectivityResult.none) { if (netResult == ConnectivityResult.none) {
@@ -1399,110 +1393,103 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
return; return;
} }
if (!installMode) { var networkRestricted = false;
// If in update mode, we check for updates. if (appsProvider.settingsProvider.bgUpdatesOnWiFiOnly) {
// We divide the results into 4 groups: networkRestricted = (netResult != ConnectivityResult.wifi) &&
// - toNotify - Apps with updates that the user will be notified about (can't be silently installed) (netResult != ConnectivityResult.ethernet);
// - toRetry - Apps with update check errors that will be retried in a while }
// - toThrow - Apps with update check errors that the user will be notified about (no retry)
// - toInstall - Apps with updates that will be installed silently
// After grouping the updates, we take care of toNotify and toThrow first
// Then if toRetry is not empty, we schedule another update task to run in a while (toInstall is retained)
// If toRetry is empty, we take care of toInstall
// Init. vars. bool installMode =
List<App> updates = []; toCheck.isEmpty; // Task is either in update mode or install mode
List<App> toNotify = [];
List<MapEntry<String, int>> toRetry = []; // In install mode, grab all available silent updates unless explicitly told otherwise
var retryAfterXSeconds = 0; if (installMode && toInstall.isEmpty && !networkRestricted) {
MultiAppMultiError toThrow = MultiAppMultiError(); var temp = appsProvider.findExistingUpdates(installedOnly: true);
var networkRestricted = false; for (var i = 0; i < temp.length; i++) {
if (appsProvider.settingsProvider.bgUpdatesOnWiFiOnly) { if (await appsProvider
var netResult = await (Connectivity().checkConnectivity()); .canInstallSilently(appsProvider.apps[temp[i]]!.app)) {
networkRestricted = (netResult != ConnectivityResult.wifi) && toInstall.add(MapEntry(temp[i], 0));
(netResult != ConnectivityResult.ethernet); }
} }
MultiAppMultiError? errors; }
CheckingUpdatesNotification notif =
CheckingUpdatesNotification(plural('apps', toCheck.length));
logs.add(
'BG ${installMode ? 'install' : 'update'} task $taskId: Started (${installMode ? toInstall.length : toCheck.length}).');
if (!installMode) {
// If in update mode...
var didCompleteChecking = false;
CheckingUpdatesNotification? notif;
// Loop through all updates and check each
List<App> toNotify = [];
try { try {
// Check for updates for (int i = 0; i < toCheck.length; i++) {
notificationsProvider.notify(notif, cancelExisting: true); var appId = toCheck[i].key;
updates = await appsProvider.checkUpdates( var attemptCount = toCheck[i].value + 1;
specificIds: toCheck.map((e) => e.key).toList()); AppInMemory? app = appsProvider.apps[appId];
} catch (e) { if (app?.app.installedVersion != null) {
// If there were errors, group them into toRetry and toThrow try {
if (e is Map) { notificationsProvider.notify(
updates = e['updates']; notif = CheckingUpdatesNotification(app?.name ?? appId),
errors = e['errors']; cancelExisting: true);
errors!.rawErrors.forEach((key, err) { App? newApp = await appsProvider.checkUpdate(appId);
logs.add( if (newApp != null) {
'BG update task $taskId: Got error on checking for $key \'${err.toString()}\'.'); if (networkRestricted ||
var toCheckApp = toCheck.where((element) => element.key == key).first; !(await appsProvider.canInstallSilently(app!.app))) {
if (toCheckApp.value < maxAttempts) { toNotify.add(newApp);
toRetry.add(MapEntry(toCheckApp.key, toCheckApp.value + 1)); }
var minRetryIntervalForThisApp = err is RateLimitError }
? (err.remainingMinutes * 60) if (i == (toCheck.length - 1)) {
: e is ClientException didCompleteChecking = true;
? (15 * 60) }
: pow(toCheckApp.value + 1, 2).toInt(); } catch (e) {
if (minRetryIntervalForThisApp > retryAfterXSeconds) { // If you got an error, move the offender to the back of the line (increment their fail count) and schedule another task to continue checking shortly
retryAfterXSeconds = minRetryIntervalForThisApp; logs.add(
'BG update task $taskId: Got error on checking for $appId \'${e.toString()}\'.');
if (attemptCount < maxAttempts) {
var remainingSeconds = e is RateLimitError
? (i == 0 ? (e.remainingMinutes * 60) : (5 * 60))
: e is ClientException
? (15 * 60)
: pow(attemptCount, 2).toInt();
logs.add(
'BG update task $taskId: Will continue in $remainingSeconds seconds (with $appId moved to the end of the line).');
var remainingToCheck = moveStrToEndMapEntryWithCount(
toCheck.sublist(i), MapEntry(appId, attemptCount));
AndroidAlarmManager.oneShot(Duration(seconds: remainingSeconds),
taskId + 1, bgUpdateCheck,
params: {
'toCheck': remainingToCheck
.map(
(entry) => {'key': entry.key, 'value': entry.value})
.toList(),
'toInstall': toInstall
.map(
(entry) => {'key': entry.key, 'value': entry.value})
.toList(),
});
break;
} else {
// If the offender has reached its fail limit, notify the user and remove it from the list (task can continue)
toCheck.removeAt(i);
i--;
notificationsProvider
.notify(ErrorCheckingUpdatesNotification(e.toString()));
}
} finally {
if (notif != null) {
notificationsProvider.cancel(notif.id);
} }
} else {
toThrow.add(key, err, appName: errors?.appIdNames[key]);
} }
}); }
} else {
// We don't expect to ever get here in any situation so no need to catch
logs.add('Fatal error in BG update task: ${e.toString()}');
rethrow;
} }
} finally { } finally {
notificationsProvider.cancel(notif.id); if (toNotify.isNotEmpty) {
} notificationsProvider.notify(UpdateNotification(toNotify));
// Group the updates into toNotify and toInstall
for (var i = 0; i < updates.length; i++) {
if (networkRestricted ||
!(await appsProvider.canInstallSilently(updates[i]))) {
toNotify.add(updates[i]);
} else {
toInstall.add(MapEntry(updates[i].id, 0));
} }
} }
// If you're done checking and found some silently installable updates, schedule another task which will run in install mode
// Send the update notification if (didCompleteChecking) {
if (toNotify.isNotEmpty) {
notificationsProvider.notify(UpdateNotification(toNotify));
}
// Send the error notifications
if (toThrow.rawErrors.isNotEmpty) {
for (var element in toThrow.idsByErrorString.entries) {
notificationsProvider.notify(ErrorCheckingUpdatesNotification(
errors!.errorsAppsString(element.key, element.value),
id: Random().nextInt(10000)));
}
}
// if there are update checks to retry, schedule a retry task
if (toRetry.isNotEmpty) {
logs.add(
'BG update task $taskId: Will retry in $retryAfterXSeconds seconds.');
AndroidAlarmManager.oneShot(
Duration(seconds: retryAfterXSeconds), taskId + 1, bgUpdateCheck,
params: {
'toCheck': toRetry
.map((entry) => {'key': entry.key, 'value': entry.value})
.toList(),
'toInstall': toInstall
.map((entry) => {'key': entry.key, 'value': entry.value})
.toList(),
});
} else if (toInstall.isNotEmpty) {
// If there are no more update checks, schedule an install task
logs.add( logs.add(
'BG update task $taskId: Done. Scheduling install task to run immediately.'); 'BG update task $taskId: Done. Scheduling install task to run immediately.');
AndroidAlarmManager.oneShot( AndroidAlarmManager.oneShot(
@@ -1513,14 +1500,11 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
.map((entry) => {'key': entry.key, 'value': entry.value}) .map((entry) => {'key': entry.key, 'value': entry.value})
.toList() .toList()
}); });
} else { } else if (didCompleteChecking) {
logs.add('BG install task $taskId: Done.'); logs.add('BG update task $taskId: Done.');
} }
} } else {
// If in install mode...
if (installMode) {
// If in install mode, we install silent updates.
var didCompleteInstalling = false; var didCompleteInstalling = false;
var tempObtArr = toInstall.where((element) => element.key == obtainiumId); var tempObtArr = toInstall.where((element) => element.key == obtainiumId);
if (tempObtArr.isNotEmpty) { if (tempObtArr.isNotEmpty) {