diff --git a/Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj b/Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj index 2cba60edc..b3094171c 100644 --- a/Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj +++ b/Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj @@ -175,7 +175,6 @@ - @@ -192,6 +191,7 @@ + @@ -601,7 +601,6 @@ - diff --git a/Covid19Radar/Covid19Radar.Android/MainApplication.cs b/Covid19Radar/Covid19Radar.Android/MainApplication.cs index 016bfe599..ddbbd0e7b 100644 --- a/Covid19Radar/Covid19Radar.Android/MainApplication.cs +++ b/Covid19Radar/Covid19Radar.Android/MainApplication.cs @@ -54,6 +54,9 @@ private Lazy _loggerService private Lazy _exposureConfigurationRepository = new Lazy(() => ContainerLocator.Current.Resolve()); + private Lazy _dataMaintainanceService + = new Lazy(() => ContainerLocator.Current.Resolve()); + public MainApplication(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) { } @@ -95,6 +98,7 @@ private void ScheduleBackgroundTasks() { _loggerService.Value.Exception("Failed to schedule ExposureDetectionBackgroundService", exception); } + try { _eventLogSubmissionBackgroundService.Value.Schedule(); @@ -103,6 +107,15 @@ private void ScheduleBackgroundTasks() { _loggerService.Value.Exception("Failed to schedule EventLogSubmissionBackgroundService", exception); } + + try + { + _dataMaintainanceService.Value.Schedule(); + } + catch (Exception exception) + { + _loggerService.Value.Exception("Failed to schedule DataMaintainanceBackgroundService", exception); + } } private void SetupENClient(ExposureNotificationClient client) @@ -118,7 +131,7 @@ private void RegisterPlatformTypes(IContainer container) // Services container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); - container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); diff --git a/Covid19Radar/Covid19Radar.Android/Services/DataMaintainanceBackgroundService.cs b/Covid19Radar/Covid19Radar.Android/Services/DataMaintainanceBackgroundService.cs new file mode 100644 index 000000000..9be4e2586 --- /dev/null +++ b/Covid19Radar/Covid19Radar.Android/Services/DataMaintainanceBackgroundService.cs @@ -0,0 +1,106 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +using System; +using Android.Content; +using Android.Runtime; +using AndroidX.Work; +using Covid19Radar.Services; +using Covid19Radar.Services.Logs; +using Java.Util.Concurrent; +using Prism.Ioc; +using Xamarin.Essentials; + +namespace Covid19Radar.Droid.Services.Logs +{ + public class DataMaintainanceBackgroundService : AbsDataMaintainanceBackgroundService + { + private const string CURRENT_WORK_NAME = "data_maintainance_worker_20220628"; + + private static readonly long INTERVAL_IN_HOURS = 24; + private static readonly long BACKOFF_DELAY_IN_MINUTES = 60; + + public DataMaintainanceBackgroundService( + ILogFileService logFileService, + ILoggerService loggerService + ) : base(logFileService, loggerService) + { + // do nothing + } + + public override void Schedule() + { + loggerService.StartMethod(); + + WorkManager workManager = WorkManager.GetInstance(Platform.AppContext); + + PeriodicWorkRequest periodicWorkRequest = CreatePeriodicWorkRequest(); + workManager.EnqueueUniquePeriodicWork( + CURRENT_WORK_NAME, + ExistingPeriodicWorkPolicy.Keep, + periodicWorkRequest + ); + + loggerService.EndMethod(); + } + + private PeriodicWorkRequest CreatePeriodicWorkRequest() + { + var workRequestBuilder = new PeriodicWorkRequest.Builder( + typeof(BackgroundWorker), + INTERVAL_IN_HOURS, TimeUnit.Hours + ) + .SetConstraints(new Constraints.Builder() + .SetRequiresBatteryNotLow(true) + .Build()) + .SetBackoffCriteria(BackoffPolicy.Linear, BACKOFF_DELAY_IN_MINUTES, TimeUnit.Minutes); + return workRequestBuilder.Build(); + } + } + + [Preserve] + public class BackgroundWorker : Worker + { + private Lazy _dataMaintainanceBackgroundService + => new Lazy(() => ContainerLocator.Current.Resolve()); + private Lazy _loggerService => new Lazy(() => ContainerLocator.Current.Resolve()); + + public BackgroundWorker(Context context, WorkerParameters workerParameters) + : base(context, workerParameters) + { + // do nothing + } + + public override Result DoWork() + { + var dataMaintainanceBackgroundService = _dataMaintainanceBackgroundService.Value; + var loggerService = _loggerService.Value; + + loggerService.StartMethod(); + + try + { + dataMaintainanceBackgroundService.ExecuteAsync().GetAwaiter().GetResult(); + return Result.InvokeSuccess(); + } + catch (Exception exception) + { + loggerService.Exception("Exception", exception); + return Result.InvokeFailure(); + } + finally + { + loggerService.EndMethod(); + } + } + + public override void OnStopped() + { + base.OnStopped(); + + _loggerService.Value.Warning("OnStopped"); + } + + } +} diff --git a/Covid19Radar/Covid19Radar.Android/Services/EventLogSubmissionBackgroundService.cs b/Covid19Radar/Covid19Radar.Android/Services/EventLogSubmissionBackgroundService.cs index 11daf9f39..c5701b866 100644 --- a/Covid19Radar/Covid19Radar.Android/Services/EventLogSubmissionBackgroundService.cs +++ b/Covid19Radar/Covid19Radar.Android/Services/EventLogSubmissionBackgroundService.cs @@ -17,7 +17,7 @@ namespace Covid19Radar.Droid.Services { public class EventLogSubmissionBackgroundService : AbsEventLogSubmissionBackgroundService { - private const string CURRENT_WORK_NAME = "eventlog_submission_worker_20220112"; + private const string CURRENT_WORK_NAME = "eventlog_submission_worker_20220628"; private const long INTERVAL_IN_HOURS = 24; private const long BACKOFF_DELAY_IN_MINUTES = 60; @@ -40,14 +40,14 @@ public override void Schedule() PeriodicWorkRequest periodicWorkRequest = CreatePeriodicWorkRequest(); workManager.EnqueueUniquePeriodicWork( CURRENT_WORK_NAME, - ExistingPeriodicWorkPolicy.Replace, + ExistingPeriodicWorkPolicy.Keep, periodicWorkRequest ); _loggerService.EndMethod(); } - private static PeriodicWorkRequest CreatePeriodicWorkRequest() + private PeriodicWorkRequest CreatePeriodicWorkRequest() { var workRequestBuilder = new PeriodicWorkRequest.Builder( typeof(BackgroundWorker), diff --git a/Covid19Radar/Covid19Radar.Android/Services/Logs/LogPeriodicDeleteService.cs b/Covid19Radar/Covid19Radar.Android/Services/Logs/LogPeriodicDeleteService.cs deleted file mode 100644 index d88497c70..000000000 --- a/Covid19Radar/Covid19Radar.Android/Services/Logs/LogPeriodicDeleteService.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -using System; -using Android.App; -using Android.Content; -using Covid19Radar.Services.Logs; -using Prism.Ioc; -using Xamarin.Essentials; - -namespace Covid19Radar.Droid.Services.Logs -{ - public class LogPeriodicDeleteService : ILogPeriodicDeleteService - { - private static readonly int requestCode = 1000; - private static readonly long executionIntervalMillis = 60 * 60 * 24 * 1000; // 24hours - - private readonly ILoggerService loggerService; - - public LogPeriodicDeleteService( - ILoggerService loggerService - ) - { - this.loggerService = loggerService; - } - - public void Init() - { - var nextScheduledTime = SetNextSchedule(); - loggerService.Info($"Next scheduled time: {DateTimeOffset.FromUnixTimeMilliseconds(nextScheduledTime).ToOffset(new TimeSpan(9, 0, 0))}"); - } - - public static long SetNextSchedule() - { - var nextScheduledTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + executionIntervalMillis; - - var context = Platform.AppContext; - var intent = new Intent(context, typeof(LogPeriodicDeleteReceiver)); - var pendingIntent = PendingIntent.GetBroadcast(context, requestCode, intent, PendingIntentFlags.CancelCurrent); - - var alermService = context.GetSystemService(Context.AlarmService) as AlarmManager; - if (alermService != null) - { - alermService.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, nextScheduledTime, pendingIntent); - } - - return nextScheduledTime; - } - } - - [BroadcastReceiver] - [IntentFilter(new[] { Intent.ActionBootCompleted })] - public class LogPeriodicDeleteReceiver : BroadcastReceiver - { - private ILoggerService loggerService => ContainerLocator.Current.Resolve(); - private ILogFileService logFileService => ContainerLocator.Current.Resolve(); - - public LogPeriodicDeleteReceiver() - { - // do nothing - } - - public override void OnReceive(Context context, Intent intent) - { - try - { - loggerService.Info($"Action: {intent.Action}"); - logFileService.Rotate(); - loggerService.Info("Periodic deletion of old logs."); - var nextScheduledTime = LogPeriodicDeleteService.SetNextSchedule(); - loggerService.Info($"Next scheduled time: {DateTimeOffset.FromUnixTimeMilliseconds(nextScheduledTime).ToOffset(new TimeSpan(9, 0, 0))}"); - } - catch - { - // do nothing - } - } - } -} diff --git a/Covid19Radar/Covid19Radar.Android/Services/Migration/MigrationProcessService.cs b/Covid19Radar/Covid19Radar.Android/Services/Migration/MigrationProcessService.cs index 9ee3dbbbb..e771af87b 100644 --- a/Covid19Radar/Covid19Radar.Android/Services/Migration/MigrationProcessService.cs +++ b/Covid19Radar/Covid19Radar.Android/Services/Migration/MigrationProcessService.cs @@ -69,14 +69,20 @@ public override Result DoWork() public class MigrationProccessService : IMigrationProcessService { private readonly AbsExposureDetectionBackgroundService _exposureDetectionBackgroundService; + private readonly AbsDataMaintainanceBackgroundService _dataMaintainanceBackgroundService; + private readonly AbsEventLogSubmissionBackgroundService _eventLogSubmissionBackgroundService; private readonly ILoggerService _loggerService; public MigrationProccessService( AbsExposureDetectionBackgroundService exposureDetectionBackgroundService, + AbsDataMaintainanceBackgroundService dataMaintainanceBackgroundService, + AbsEventLogSubmissionBackgroundService eventLogSubmissionBackgroundService, ILoggerService loggerService ) { _exposureDetectionBackgroundService = exposureDetectionBackgroundService; + _dataMaintainanceBackgroundService = dataMaintainanceBackgroundService; + _eventLogSubmissionBackgroundService = eventLogSubmissionBackgroundService; _loggerService = loggerService; } @@ -86,6 +92,8 @@ public async Task SetupAsync() await new WorkManagerMigrator( _exposureDetectionBackgroundService, + _dataMaintainanceBackgroundService, + _eventLogSubmissionBackgroundService, _loggerService ).ExecuteAsync(); diff --git a/Covid19Radar/Covid19Radar.Android/Services/Migration/WorkManagerMigrator.cs b/Covid19Radar/Covid19Radar.Android/Services/Migration/WorkManagerMigrator.cs index c0e02ee8a..c40b7b290 100644 --- a/Covid19Radar/Covid19Radar.Android/Services/Migration/WorkManagerMigrator.cs +++ b/Covid19Radar/Covid19Radar.Android/Services/Migration/WorkManagerMigrator.cs @@ -19,14 +19,21 @@ internal class WorkManagerMigrator }; private readonly AbsExposureDetectionBackgroundService _exposureDetectionBackgroundService; + private readonly AbsDataMaintainanceBackgroundService _dataMaintainanceBackgroundService; + private readonly AbsEventLogSubmissionBackgroundService _eventLogSubmissionBackgroundService; + private readonly ILoggerService _loggerService; public WorkManagerMigrator( AbsExposureDetectionBackgroundService exposureDetectionBackgroundService, + AbsDataMaintainanceBackgroundService dataMaintainanceBackgroundService, + AbsEventLogSubmissionBackgroundService eventLogSubmissionBackgroundService, ILoggerService loggerService ) { _exposureDetectionBackgroundService = exposureDetectionBackgroundService; + _dataMaintainanceBackgroundService = dataMaintainanceBackgroundService; + _eventLogSubmissionBackgroundService = eventLogSubmissionBackgroundService; _loggerService = loggerService; } @@ -38,6 +45,8 @@ internal Task ExecuteAsync() CancelOldWorks(workManager, OldWorkNames, _loggerService); _exposureDetectionBackgroundService.Schedule(); + _dataMaintainanceBackgroundService.Schedule(); + _eventLogSubmissionBackgroundService.Schedule(); _loggerService.EndMethod(); diff --git a/Covid19Radar/Covid19Radar.iOS/AppDelegate.cs b/Covid19Radar/Covid19Radar.iOS/AppDelegate.cs index 6c491c375..87f3fdc79 100644 --- a/Covid19Radar/Covid19Radar.iOS/AppDelegate.cs +++ b/Covid19Radar/Covid19Radar.iOS/AppDelegate.cs @@ -53,6 +53,9 @@ private Lazy _loggerService private Lazy _exposureConfigurationRepository = new Lazy(() => ContainerLocator.Current.Resolve()); + private Lazy _dataMaintainanceBackgroundService + = new Lazy(() => ContainerLocator.Current.Resolve()); + private App? AppInstance { get @@ -112,12 +115,12 @@ public override bool FinishedLaunching(UIApplication app, NSDictionary launchOpt UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum); - ScheduleBackgroundTask(); + ScheduleBackgroundTasks(); return base.FinishedLaunching(app, launchOptions); } - private void ScheduleBackgroundTask() + private void ScheduleBackgroundTasks() { try { @@ -127,6 +130,7 @@ private void ScheduleBackgroundTask() { _loggerService.Value.Exception("Failed to schedule ExposureDetectionBackgroundService", exception); } + try { _eventLogSubmissionBackgroundService.Value.Schedule(); @@ -135,6 +139,15 @@ private void ScheduleBackgroundTask() { _loggerService.Value.Exception("Failed to schedule EventLogSubmissionBackgroundService", exception); } + + try + { + _dataMaintainanceBackgroundService.Value.Schedule(); + } + catch (Exception exception) + { + _loggerService.Value.Exception("Failed to schedule DataMaintainanceBackgroundService", exception); + } } private bool IsUniversalLinks(NSDictionary launchOptions) @@ -256,7 +269,7 @@ private void RegisterPlatformTypes(IContainer container) // Services container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); - container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Reuse.Singleton); diff --git a/Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj b/Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj index 013036399..6cecd9df3 100644 --- a/Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj +++ b/Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj @@ -256,7 +256,6 @@ - @@ -271,6 +270,7 @@ + @@ -548,7 +548,6 @@ - diff --git a/Covid19Radar/Covid19Radar.iOS/Info.plist b/Covid19Radar/Covid19Radar.iOS/Info.plist index 751350d06..a88e10d47 100644 --- a/Covid19Radar/Covid19Radar.iOS/Info.plist +++ b/Covid19Radar/Covid19Radar.iOS/Info.plist @@ -54,8 +54,8 @@ BGTaskSchedulerPermittedIdentifiers APP_PACKAGE_NAME.exposure-notification - APP_PACKAGE_NAME.delete-old-logs APP_PACKAGE_NAME.eventlog-submission + APP_PACKAGE_NAME.data-maintainance UIAppFonts @@ -68,7 +68,6 @@ LaunchScreen UIBackgroundModes - fetch processing UIUserInterfaceStyle diff --git a/Covid19Radar/Covid19Radar.iOS/Services/DataMaintainanceBackgroundService.cs b/Covid19Radar/Covid19Radar.iOS/Services/DataMaintainanceBackgroundService.cs new file mode 100644 index 000000000..61fd5a28f --- /dev/null +++ b/Covid19Radar/Covid19Radar.iOS/Services/DataMaintainanceBackgroundService.cs @@ -0,0 +1,136 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using BackgroundTasks; +using Covid19Radar.Common; +using Covid19Radar.Services; +using Covid19Radar.Services.Logs; +using Foundation; +using Xamarin.Essentials; + +namespace Covid19Radar.iOS.Services.Logs +{ + public class DataMaintainanceBackgroundService : AbsDataMaintainanceBackgroundService + { + #region Constants + + private const int TASK_INTERVAL_IN_DAYS = 1; + + #endregion + + #region Static Fields + + private static readonly string BGTASK_IDENTIFIER = AppInfo.PackageName + ".data-maintainance"; + + #endregion + + #region Instance Fields + + private readonly IDateTimeUtility _dateTimeUtility; + + #endregion + + #region Constructors + + public DataMaintainanceBackgroundService( + ILoggerService loggerService, + ILogFileService logFileService, + IDateTimeUtility dateTimeUtility + ) : base(logFileService, loggerService) + { + _dateTimeUtility = dateTimeUtility; + } + + #endregion + + #region ILogPeriodicDeleteService Methods + + public override void Schedule() + { + loggerService.StartMethod(); + + var result = BGTaskScheduler.Shared.Register(BGTASK_IDENTIFIER, null, task => + { + loggerService.Info("Background task has been started."); + + DateTime nextDateTime = _dateTimeUtility.UtcNow.Date.AddDays(TASK_INTERVAL_IN_DAYS); + ScheduleBgTask(nextDateTime); + + var cancellationTokenSource = new CancellationTokenSource(); + task.ExpirationHandler = cancellationTokenSource.Cancel; + + _ = Task.Run(async () => + { + try + { + await ExecuteAsync(); + task.SetTaskCompleted(true); + } + catch (OperationCanceledException exception) + { + loggerService.Exception($"Background task canceled.", exception); + task.SetTaskCompleted(false); + } + catch (Exception exception) + { + loggerService.Exception($"Exception", exception); + task.SetTaskCompleted(false); + } + finally + { + cancellationTokenSource.Dispose(); + } + }, cancellationTokenSource.Token); + }); + + if (result) + { + loggerService.Debug("BGTaskScheduler.Shared.Register succeeded."); + } + else + { + loggerService.Info("BGTaskScheduler.Shared.Register failed."); + } + + ScheduleBgTask(_dateTimeUtility.UtcNow); + + loggerService.EndMethod(); + } + + #endregion + + #region Other Private Methods + + private void ScheduleBgTask(DateTime nextDateTime) + { + loggerService.StartMethod(); + + try + { + BGProcessingTaskRequest bgTaskRequest = new BGProcessingTaskRequest(BGTASK_IDENTIFIER) + { + EarliestBeginDate = NSDate.FromTimeIntervalSince1970(nextDateTime.ToUnixEpoch()) + }; + + BGTaskScheduler.Shared.Submit(bgTaskRequest, out var error); + if (error != null) + { + NSErrorException exception = new NSErrorException(error); + loggerService.Exception("BGTaskScheduler submit failed.", exception); + throw exception; + } + } + finally + { + loggerService.EndMethod(); + } + } + + #endregion + } + +} diff --git a/Covid19Radar/Covid19Radar.iOS/Services/EventLogSubmissionBackgroundService.cs b/Covid19Radar/Covid19Radar.iOS/Services/EventLogSubmissionBackgroundService.cs index eb6b65720..4d1516b41 100644 --- a/Covid19Radar/Covid19Radar.iOS/Services/EventLogSubmissionBackgroundService.cs +++ b/Covid19Radar/Covid19Radar.iOS/Services/EventLogSubmissionBackgroundService.cs @@ -16,97 +16,103 @@ namespace Covid19Radar.iOS.Services { public class EventLogSubmissionBackgroundService : AbsEventLogSubmissionBackgroundService { - private static readonly string IDENTIFIER = AppInfo.PackageName + ".eventlog-submission"; + private const int TASK_INTERVAL_IN_DAYS = 1; - private const double ONE_DAY_IN_SECONDS = 1 * 24 * 60 * 60; + private static readonly string BGTASK_IDENTIFIER = AppInfo.PackageName + ".eventlog-submission"; private readonly IEventLogService _eventLogService; private readonly ILoggerService _loggerService; + private readonly IDateTimeUtility _dateTimeUtility; public EventLogSubmissionBackgroundService( IEventLogService eventLogService, - ILoggerService loggerService + ILoggerService loggerService, + IDateTimeUtility dateTimeUtility ) : base() { _eventLogService = eventLogService; _loggerService = loggerService; + _dateTimeUtility = dateTimeUtility; } public override void Schedule() { _loggerService.StartMethod(); - _ = BGTaskScheduler.Shared.Register(IDENTIFIER, null, task => + var result = BGTaskScheduler.Shared.Register(BGTASK_IDENTIFIER, null, task => { - HandleSendLogAsync((BGAppRefreshTask)task); - }); - - ScheduleSendEventLog(); - - _loggerService.EndMethod(); - } - - private void HandleSendLogAsync(BGAppRefreshTask task) - { - _loggerService.StartMethod(); + _loggerService.Info("Background task has been started."); - ScheduleSendEventLog(); + DateTime nextDateTime = _dateTimeUtility.UtcNow.Date.AddDays(TASK_INTERVAL_IN_DAYS); + ScheduleBgTask(nextDateTime); - var cancellationTokenSource = new CancellationTokenSource(); - task.ExpirationHandler = cancellationTokenSource.Cancel; + var cancellationTokenSource = new CancellationTokenSource(); + task.ExpirationHandler = cancellationTokenSource.Cancel; - _ = Task.Run(async () => - { - _loggerService.Info("HandleSendLogAsync() Task.Run() start"); - try - { - await _eventLogService.SendAllAsync( - AppConstants.EventLogMaxRequestSizeInBytes, - AppConstants.EventLogMaxRetry); - task.SetTaskCompleted(true); - } - catch (OperationCanceledException exception) - { - _loggerService.Exception($"Background task canceled.", exception); - task.SetTaskCompleted(false); - } - catch (Exception exception) - { - _loggerService.Exception($"Exception", exception); - task.SetTaskCompleted(false); - } - finally + _ = Task.Run(async () => { - cancellationTokenSource.Dispose(); - _loggerService.Info("HandleSendLogAsync() Task.Run() end"); - } + try + { + await _eventLogService.SendAllAsync( + AppConstants.EventLogMaxRequestSizeInBytes, + AppConstants.EventLogMaxRetry); + task.SetTaskCompleted(true); + } + catch (OperationCanceledException exception) + { + _loggerService.Exception($"Background task canceled.", exception); + task.SetTaskCompleted(false); + } + catch (Exception exception) + { + _loggerService.Exception($"Exception", exception); + task.SetTaskCompleted(false); + } + finally + { + cancellationTokenSource.Dispose(); + } + }, cancellationTokenSource.Token); }); + if (result) + { + _loggerService.Debug("BGTaskScheduler.Shared.Register succeeded."); + } + else + { + _loggerService.Info("BGTaskScheduler.Shared.Register failed."); + } + + ScheduleBgTask(_dateTimeUtility.UtcNow); + _loggerService.EndMethod(); } - private void ScheduleSendEventLog() + private void ScheduleBgTask(DateTime nextDateTime) { _loggerService.StartMethod(); - var bgTaskRequest = new BGProcessingTaskRequest(IDENTIFIER) + try { - EarliestBeginDate = NSDate.FromTimeIntervalSinceNow(ONE_DAY_IN_SECONDS), - RequiresNetworkConnectivity = true - }; - - _loggerService.Info($"request.EarliestBeginDate: {bgTaskRequest.EarliestBeginDate}"); + BGProcessingTaskRequest bgTaskRequest = new BGProcessingTaskRequest(BGTASK_IDENTIFIER) + { + RequiresNetworkConnectivity = true, + EarliestBeginDate = NSDate.FromTimeIntervalSince1970(nextDateTime.ToUnixEpoch()) + }; - _ = BGTaskScheduler.Shared.Submit(bgTaskRequest, out var error); - if (error != null) + BGTaskScheduler.Shared.Submit(bgTaskRequest, out var error); + if (error != null) + { + NSErrorException exception = new NSErrorException(error); + _loggerService.Exception("BGTaskScheduler submit failed.", exception); + throw exception; + } + } + finally { - NSErrorException exception = new NSErrorException(error); - _loggerService.Exception("BGTaskScheduler submit failed.", exception); - throw exception; + _loggerService.EndMethod(); } - - _loggerService.EndMethod(); } } } - diff --git a/Covid19Radar/Covid19Radar.iOS/Services/Logs/LogPeriodicDeleteService.cs b/Covid19Radar/Covid19Radar.iOS/Services/Logs/LogPeriodicDeleteService.cs deleted file mode 100644 index 8f3955de2..000000000 --- a/Covid19Radar/Covid19Radar.iOS/Services/Logs/LogPeriodicDeleteService.cs +++ /dev/null @@ -1,159 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -using BackgroundTasks; -using Covid19Radar.Services.Logs; -using Foundation; -using Xamarin.Essentials; - -namespace Covid19Radar.iOS.Services.Logs -{ - public class LogPeriodicDeleteService : ILogPeriodicDeleteService - { - #region Static Fields - - private static readonly string identifier = AppInfo.PackageName + ".delete-old-logs"; - - #endregion - - #region Instance Fields - - private readonly ILoggerService loggerService; - private readonly ILogFileService logFileService; - - #endregion - - #region Constructors - - public LogPeriodicDeleteService( - ILoggerService loggerService, - ILogFileService logFileService - ) - { - this.loggerService = loggerService; - this.logFileService = logFileService; - } - - #endregion - - #region ILogPeriodicDeleteService Methods - - public void Init() - { - loggerService.StartMethod(); - - _ = BGTaskScheduler.Shared.Register(identifier, null, task => - { - HandleAppRefresh((BGAppRefreshTask)task); - }); - - ScheduleAppRefresh(); - - loggerService.EndMethod(); - } - - #endregion - - #region Other Private Methods - - private void HandleAppRefresh(BGAppRefreshTask task) - { - try - { - loggerService.StartMethod(); - - ScheduleAppRefresh(); - - var queue = new NSOperationQueue(); - queue.MaxConcurrentOperationCount = 1; - - task.ExpirationHandler = () => - { - loggerService.Info("Task expired."); - queue.CancelAllOperations(); - }; - - var operation = new DeleteOldLogsOperation(loggerService, logFileService); - operation.CompletionBlock = () => - { - loggerService.Info($"Operation completed. operation.IsCancelled: {operation.IsCancelled}"); - task.SetTaskCompleted(!operation.IsCancelled); - }; - - queue.AddOperation(operation); - - loggerService.EndMethod(); - } - catch - { - // do nothing - } - } - - private void ScheduleAppRefresh() - { - loggerService.StartMethod(); - - var oneDay = 1 * 24 * 60 * 60; - var request = new BGAppRefreshTaskRequest(identifier); - request.EarliestBeginDate = NSDate.FromTimeIntervalSinceNow(oneDay); // Fetch no earlier than 1 day from now - - loggerService.Info($"request.EarliestBeginDate: {request.EarliestBeginDate}"); - - _ = BGTaskScheduler.Shared.Submit(request, out var error); - - if (error != null) - { - loggerService.Error($"Could not schedule app refresh. Error: {error}"); - } - - loggerService.EndMethod(); - } - - #endregion - } - - class DeleteOldLogsOperation : NSOperation - { - #region Instance Fields - - private readonly ILoggerService loggerService; - private readonly ILogFileService logFileService; - - #endregion - - #region Constructors - - public DeleteOldLogsOperation(ILoggerService loggerService, ILogFileService logFileService) - { - this.loggerService = loggerService; - this.logFileService = logFileService; - } - - #endregion - - #region NSOperation Methods - - public override void Main() - { - base.Main(); - - try - { - loggerService.StartMethod(); - - logFileService.Rotate(); - - loggerService.Info("Periodic deletion of old logs."); - loggerService.EndMethod(); - } - catch - { - // do nothing - } - } - - #endregion - } -} diff --git a/Covid19Radar/Covid19Radar/App.xaml.cs b/Covid19Radar/Covid19Radar/App.xaml.cs index 5653063f3..0296db4f3 100644 --- a/Covid19Radar/Covid19Radar/App.xaml.cs +++ b/Covid19Radar/Covid19Radar/App.xaml.cs @@ -229,21 +229,6 @@ private static void RegisterCommonTypes(IContainer container) container.Register(Reuse.Singleton); } - protected override void OnStart() - { - // Initialize periodic log delete service - var logPeriodicDeleteService = Container.Resolve(); - logPeriodicDeleteService.Init(); - - LogFileService.Rotate(); - } - - protected override void OnResume() - { - base.OnResume(); - LogFileService.Rotate(); - } - protected override void OnSleep() { base.OnSleep(); diff --git a/Covid19Radar/Covid19Radar/Services/AbsDataMaintainanceBackgroundService.cs b/Covid19Radar/Covid19Radar/Services/AbsDataMaintainanceBackgroundService.cs new file mode 100644 index 000000000..2198801a4 --- /dev/null +++ b/Covid19Radar/Covid19Radar/Services/AbsDataMaintainanceBackgroundService.cs @@ -0,0 +1,40 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +using System.Threading.Tasks; +using Covid19Radar.Services.Logs; + +namespace Covid19Radar.Services +{ + public abstract class AbsDataMaintainanceBackgroundService : IBackgroundService + { + protected readonly ILoggerService loggerService; + + private readonly ILogFileService _logFileService; + + public AbsDataMaintainanceBackgroundService( + ILogFileService logFileService, + ILoggerService loggerService + ) + { + _logFileService = logFileService; + this.loggerService = loggerService; + } + + public abstract void Schedule(); + + public async Task ExecuteAsync() + { + loggerService.StartMethod(); + + try + { + _logFileService.Rotate(); + } + finally + { + loggerService.EndMethod(); + } + } + } +} diff --git a/Covid19Radar/Covid19Radar/Services/Logs/LogPeriodicDeleteService.cs b/Covid19Radar/Covid19Radar/Services/Logs/LogPeriodicDeleteService.cs deleted file mode 100644 index 0a9711e44..000000000 --- a/Covid19Radar/Covid19Radar/Services/Logs/LogPeriodicDeleteService.cs +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -namespace Covid19Radar.Services.Logs -{ - public interface ILogPeriodicDeleteService - { - void Init(); - } -} diff --git a/Covid19Radar/Covid19Radar/ViewModels/HomePage/SplashPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/HomePage/SplashPageViewModel.cs index cbc5ea5c6..8d9d77f72 100644 --- a/Covid19Radar/Covid19Radar/ViewModels/HomePage/SplashPageViewModel.cs +++ b/Covid19Radar/Covid19Radar/ViewModels/HomePage/SplashPageViewModel.cs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using System.Threading.Tasks; using Covid19Radar.Model; using Covid19Radar.Repository; using Covid19Radar.Services; @@ -19,6 +20,7 @@ public class SplashPageViewModel : ViewModelBase private readonly IUserDataService _userDataService; private readonly IMigrationService _migrationService; private readonly IUserDataRepository _userDataRepository; + private readonly ILogFileService _logFileService; public SplashPageViewModel( INavigationService navigationService, @@ -26,7 +28,8 @@ public SplashPageViewModel( ILoggerService loggerService, IUserDataRepository userDataRepository, IUserDataService userDataService, - IMigrationService migrationService + IMigrationService migrationService, + ILogFileService logFileService ) : base(navigationService) { _termsUpdateService = termsUpdateService; @@ -34,6 +37,7 @@ IMigrationService migrationService _userDataRepository = userDataRepository; _userDataService = userDataService; _migrationService = migrationService; + _logFileService = logFileService; } public override async void OnNavigatedTo(INavigationParameters parameters) @@ -44,6 +48,10 @@ public override async void OnNavigatedTo(INavigationParameters parameters) await _migrationService.MigrateAsync(); + await Task.Run(() => { + _logFileService.Rotate(); + }); + var destination = Destination.HomePage; if (parameters.ContainsKey(SplashPage.DestinationKey)) {