fix: android crash on app pause (#21768)

* revert service locks

* rename backgroundWorkerFgServiceProvider

* refactor: parallel background worker init (#21769)

* refactor: parallel background worker init

* fix: hashing not running from the background engine (#21773)

* init and dispose workmanager from background engine

* log message contend

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
shenlong 2025-09-10 22:45:42 +05:30 committed by GitHub
parent 2c7b980eed
commit e239b8d2fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 44 additions and 343 deletions

View file

@ -5,7 +5,6 @@ import 'package:background_downloader/background_downloader.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/constants.dart';
import 'package:immich_mobile/domain/utils/isolate_lock_manager.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart';
import 'package:immich_mobile/platform/background_worker_api.g.dart';
@ -24,6 +23,7 @@ import 'package:immich_mobile/utils/bootstrap.dart';
import 'package:immich_mobile/utils/http_ssl_options.dart';
import 'package:isar/isar.dart';
import 'package:logging/logging.dart';
import 'package:worker_manager/worker_manager.dart';
class BackgroundWorkerFgService {
final BackgroundWorkerFgHostApi _foregroundHostApi;
@ -42,8 +42,7 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
final Drift _drift;
final DriftLogger _driftLogger;
final BackgroundWorkerBgHostApi _backgroundHostApi;
final Logger _logger = Logger('BackgroundUploadBgService');
late final IsolateLockManager _lockManager;
final Logger _logger = Logger('BackgroundWorkerBgService');
bool _isCleanedUp = false;
@ -59,7 +58,6 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
driftProvider.overrideWith(driftOverride(drift)),
],
);
_lockManager = IsolateLockManager(onCloseRequest: _cleanup);
BackgroundWorkerFlutterApi.setUp(this);
}
@ -67,41 +65,30 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
Future<void> init() async {
try {
await loadTranslations();
HttpSSLOptions.apply(applyNative: false);
await _ref.read(authServiceProvider).setOpenApiServiceEndpoint();
// Initialize the file downloader
await FileDownloader().configure(
globalConfig: [
// maxConcurrent: 6, maxConcurrentByHost(server):6, maxConcurrentByGroup: 3
(Config.holdingQueue, (6, 6, 3)),
// On Android, if files are larger than 256MB, run in foreground service
(Config.runInForegroundIfFileLargerThan, 256),
],
);
await FileDownloader().trackTasksInGroup(kDownloadGroupLivePhoto, markDownloadedComplete: false);
await FileDownloader().trackTasks();
await Future.wait([
loadTranslations(),
workerManager.init(dynamicSpawning: true),
_ref.read(authServiceProvider).setOpenApiServiceEndpoint(),
// Initialize the file downloader
FileDownloader().configure(
globalConfig: [
// maxConcurrent: 6, maxConcurrentByHost(server):6, maxConcurrentByGroup: 3
(Config.holdingQueue, (6, 6, 3)),
// On Android, if files are larger than 256MB, run in foreground service
(Config.runInForegroundIfFileLargerThan, 256),
],
),
FileDownloader().trackTasksInGroup(kDownloadGroupLivePhoto, markDownloadedComplete: false),
FileDownloader().trackTasks(),
_ref.read(fileMediaRepositoryProvider).enableBackgroundAccess(),
]);
configureFileDownloaderNotifications();
await _ref.read(fileMediaRepositoryProvider).enableBackgroundAccess();
// Notify the host that the background upload service has been initialized and is ready to use
debugPrint("Acquiring background worker lock");
if (await _lockManager.acquireLock().timeout(
const Duration(seconds: 5),
onTimeout: () {
_lockManager.cancel();
return false;
},
)) {
_logger.info("Acquired background worker lock");
await _backgroundHostApi.onInitialized();
return;
}
_logger.warning("Failed to acquire background worker lock");
await _cleanup();
await _backgroundHostApi.close();
// Notify the host that the background worker service has been initialized and is ready to use
_backgroundHostApi.onInitialized();
} catch (error, stack) {
_logger.severe("Failed to initialize background worker", error, stack);
_backgroundHostApi.close();
@ -170,6 +157,7 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
_isCleanedUp = true;
_logger.info("Cleaning up background worker");
final cleanupFutures = [
workerManager.dispose(),
_drift.close(),
_driftLogger.close(),
_ref.read(backgroundSyncProvider).cancel(),
@ -180,8 +168,6 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
cleanupFutures.add(_isar.close());
}
_ref.dispose();
_lockManager.releaseLock();
await Future.wait(cleanupFutures);
_logger.info("Background worker resources cleaned up");
} catch (error, stack) {
@ -191,22 +177,29 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
Future<void> _handleBackup({bool processBulk = true}) async {
if (!_isBackupEnabled) {
_logger.info("[_handleBackup 1] Backup is disabled. Skipping backup routine");
return;
}
_logger.info("[_handleBackup 2] Enqueuing assets for backup from the background service");
final currentUser = _ref.read(currentUserProvider);
if (currentUser == null) {
_logger.warning("[_handleBackup 3] No current user found. Skipping backup from background");
return;
}
if (processBulk) {
_logger.info("[_handleBackup 4] Resume backup from background");
return _ref.read(driftBackupProvider.notifier).handleBackupResume(currentUser.id);
}
final activeTask = await _ref.read(uploadServiceProvider).getActiveTasks(currentUser.id);
if (activeTask.isNotEmpty) {
_logger.info("[_handleBackup 5] Resuming backup for active tasks from background");
await _ref.read(uploadServiceProvider).resumeBackup();
} else {
_logger.info("[_handleBackup 6] Starting serial backup for new tasks from background");
await _ref.read(uploadServiceProvider).startBackupSerial(currentUser.id);
}
}