protected override void ScheduleNative(JobInfo jobInfo) { var identifier = this.GetIdentifier( jobInfo.DeviceCharging, jobInfo.RequiredInternetAccess == InternetAccess.Any ); var request = new BGProcessingTaskRequest(identifier); request.RequiresExternalPower = jobInfo.DeviceCharging; request.RequiresNetworkConnectivity = jobInfo.RequiredInternetAccess == InternetAccess.Any; if (!BGTaskScheduler.Shared.Submit(request, out var e)) { throw new ArgumentException(e.LocalizedDescription.ToString()); } }
public void SubmitTaskRequestTest() { TestRuntime.AssertDevice(); TestRuntime.AssertXcodeVersion(11, 0); Assert.True(registered, "Task was not registered."); // get the shared scheduler, create a request and submit it, this will be called asap // and the autoreset event set. var request = new BGProcessingTaskRequest(taskIdentifier); NSError error; BGTaskScheduler.Shared.Submit(request, out error); Assert.IsNull(error, $"Error submiting request {error}"); LaunchBGTask(); autoResetEvent.WaitOne(300); Assert.True(taskWasCalled, "Called task."); }
static Task PlatformScheduleFetch() { // This is a special ID suffix which iOS treats a certain way // we can basically request infinite background tasks // and iOS will throttle it sensibly for us. var id = AppInfo.PackageName + ".exposure-notification"; void scheduleBgTask() { var newBgTask = new BGProcessingTaskRequest(id); newBgTask.RequiresNetworkConnectivity = true; BGTaskScheduler.Shared.Submit(newBgTask, out _); } BGTaskScheduler.Shared.Register(id, null, async t => { if (await PlatformIsEnabled()) { var cancelSrc = new CancellationTokenSource(); t.ExpirationHandler = cancelSrc.Cancel; Exception ex = null; try { await ExposureNotification.UpdateKeysFromServer(); } catch (Exception e) { ex = e; } t.SetTaskCompleted(ex != null); } scheduleBgTask(); }); scheduleBgTask(); return(Task.CompletedTask); }
private void ScheduleSendEventLog() { _loggerService.StartMethod(); var bgTaskRequest = new BGProcessingTaskRequest(IDENTIFIER) { EarliestBeginDate = NSDate.FromTimeIntervalSinceNow(ONE_DAY_IN_SECONDS), RequiresNetworkConnectivity = true }; _loggerService.Info($"request.EarliestBeginDate: {bgTaskRequest.EarliestBeginDate}"); _ = BGTaskScheduler.Shared.Submit(bgTaskRequest, out var error); if (error != null) { NSErrorException exception = new NSErrorException(error); _loggerService.Exception("BGTaskScheduler submit failed.", exception); throw exception; } _loggerService.EndMethod(); }
void ScheduleDatabaseCleaningIfNeeded() { var lastCleanDate = DBManager.SharedInstance.LastCleaned ?? DateTime.MinValue; var now = DateTime.Now; // Clean the database at most once per week. if (now <= lastCleanDate.AddDays(7)) { return; } var request = new BGProcessingTaskRequest(CleaningDbTaskId) { RequiresNetworkConnectivity = false, RequiresExternalPower = true }; BGTaskScheduler.Shared.Submit(request, out NSError error); if (error != null) { Debug.WriteLine($"Could not schedule app refresh: {error}"); } }
private void ScheduleBgTask() { _loggerService.StartMethod(); try { BGProcessingTaskRequest bgTaskRequest = new BGProcessingTaskRequest(BGTASK_IDENTIFIER) { RequiresNetworkConnectivity = true }; 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(); } }
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(); } }
static void scheduleBgTask() { if (ENManager.AuthorizationStatus != ENAuthorizationStatus.Authorized) { return; } var newBgTask = new BGProcessingTaskRequest(backgroundTaskId); newBgTask.RequiresNetworkConnectivity = true; try { BGTaskScheduler.Shared.Submit(newBgTask, out var error); if (error != null) { throw new NSErrorException(error); } } catch (Exception ex) { Console.WriteLine($"[Xamarin.ExposureNotifications] There was an error submitting the background task: {ex}"); } }
static Task PlatformScheduleFetch() { // This is a special ID suffix which iOS treats a certain way // we can basically request infinite background tasks // and iOS will throttle it sensibly for us. var id = AppInfo.PackageName + ".exposure-notification"; var isUpdating = false; BGTaskScheduler.Shared.Register(id, null, task => { // Disallow concurrent exposure detection, because if allowed we might try to detect the same diagnosis keys more than once if (isUpdating) { task.SetTaskCompleted(false); return; } isUpdating = true; var cancelSrc = new CancellationTokenSource(); task.ExpirationHandler = cancelSrc.Cancel; // Run the actual task on a background thread Task.Run(async() => { try { await UpdateKeysFromServer(cancelSrc.Token); task.SetTaskCompleted(true); } catch (OperationCanceledException) { Console.WriteLine($"[Xamarin.ExposureNotifications] Background task took too long to complete."); } catch (Exception ex) { Console.WriteLine($"[Xamarin.ExposureNotifications] There was an error running the background task: {ex}"); task.SetTaskCompleted(false); } isUpdating = false; }); scheduleBgTask(); }); scheduleBgTask(); return(Task.CompletedTask); void scheduleBgTask() { if (ENManager.AuthorizationStatus != ENAuthorizationStatus.Authorized) { return; } var newBgTask = new BGProcessingTaskRequest(id); newBgTask.RequiresNetworkConnectivity = true; try { BGTaskScheduler.Shared.Submit(newBgTask, out var error); if (error != null) { throw new NSErrorException(error); } } catch (Exception ex) { Console.WriteLine($"[Xamarin.ExposureNotifications] There was an error submitting the background task: {ex}"); } } }
public static Task PlatformScheduleFetch() { string logPrefix = $"{nameof(BackgroundServiceHandler)}.{nameof(PlatformScheduleFetch)}: "; // iOS 12.5 if (AppDelegate.ShouldOperateIn12_5Mode) { if (ObjCRuntime.Class.GetHandle("ENManager") == IntPtr.Zero) { LogUtils.LogException(Enums.LogSeverity.ERROR, new NullReferenceException("Pointer to ENManager is null"), logPrefix + "Failed to retrieve ENManager instance [iOS 12.5 mode]"); return(null); } ENManager manager = new ENManager(); manager.SetLaunchActivityHandler(activityFlags => { if (activityFlags.HasFlag(ENActivityFlags.PeriodicRun)) { Task.Run(async() => { CancellationTokenSource cancelSrc = new CancellationTokenSource(); try { await Xamarin.ExposureNotifications.ExposureNotification.UpdateKeysFromServer(cancelSrc.Token); } catch (OperationCanceledException e) { LogUtils.LogException(Enums.LogSeverity.WARNING, e, logPrefix + "Background task took too long to complete [iOS 12.5 mode]"); } catch (NSErrorException nserror) { if (nserror.Domain == "ENErrorDomain") { LogUtils.LogException(Enums.LogSeverity.WARNING, nserror, logPrefix + $"Background task failed due to EN API Error Code={nserror.Code} [iOS 12.5 mode]"); } else { LogUtils.LogException(Enums.LogSeverity.WARNING, nserror, logPrefix + $"Background task failed due to NSError {nserror.Domain} {nserror.Code}. [iOS 12.5 mode]"); } } catch (Exception ex) { LogUtils.LogException(Enums.LogSeverity.WARNING, ex, logPrefix + $"Background task: An error occurred inside the async task [iOS 12.5 mode]"); } }); } }); return(manager.ActivateAsync()); } // iOS 13+ // This is a special ID suffix which iOS treats a certain way // we can basically request infinite background tasks // and iOS will throttle it sensibly for us. string id = CommonServiceLocator.ServiceLocator.Current.GetInstance <IAppInfo>().PackageName + ".exposure-notification"; BGTaskScheduler.Shared.Register(id, null, async task => { try { if (ENManager.AuthorizationStatus != ENAuthorizationStatus.Authorized) // ENManager is not authorised yet { Debug.WriteLine(logPrefix + "ENManager AuthorizationStatus isn't authorized"); scheduleBgTask(0); // reschedule to try in the future return; } bool shouldFetch = await Xamarin.ExposureNotifications.ExposureNotification.IsEnabledAsync(); if (!shouldFetch) { LogUtils.LogMessage(Enums.LogSeverity.WARNING, logPrefix + "Did not pull. EN was not enabled (iOS)"); } System.Diagnostics.Debug.WriteLine($"Background Task is fetching: {shouldFetch}"); if (shouldFetch) { CancellationTokenSource cancelSrc = new CancellationTokenSource(); task.ExpirationHandler = cancelSrc.Cancel; // Run the actual task on a background thread await Task.Run(async() => { try { await Xamarin.ExposureNotifications.ExposureNotification.UpdateKeysFromServer(cancelSrc.Token); task.SetTaskCompleted(true); } catch (OperationCanceledException e) { LogUtils.LogException(Enums.LogSeverity.WARNING, e, logPrefix + "Background task took too long to complete. - BG Task is rescheduled"); task.SetTaskCompleted(false); } catch (NSErrorException nserror) { if (nserror.Domain == "ENErrorDomain") { LogUtils.LogException(Enums.LogSeverity.WARNING, nserror, logPrefix + $"Background task failed due to EN API Error Code={nserror.Code} - BG Task is rescheduled"); task.SetTaskCompleted(false); } else { LogUtils.LogException(Enums.LogSeverity.WARNING, nserror, logPrefix + $"Background task failed due to NSError {nserror.Domain} {nserror.Code}. - BG Task is rescheduled"); task.SetTaskCompleted(false); } } catch (Exception ex) { LogUtils.LogException(Enums.LogSeverity.WARNING, ex, logPrefix + $"Background task: An error occurred inside the async task - BG Task is rescheduled"); task.SetTaskCompleted(false); } }); } } catch (Exception e) { LogUtils.LogException(Enums.LogSeverity.WARNING, e, logPrefix + $"Background task: An error occurred before executing the async task - BG Task is rescheduled"); task.SetTaskCompleted(false); } scheduleBgTask(0); }); scheduleBgTask(0); return(Task.CompletedTask); void scheduleBgTask(int numberOfRetries) { BGProcessingTaskRequest newBgTask = new BGProcessingTaskRequest(id); newBgTask.RequiresNetworkConnectivity = true; try { BGTaskScheduler.Shared.Submit(newBgTask, out var error); if (error != null) { if ((BGTaskSchedulerErrorCode)(int)error.Code == BGTaskSchedulerErrorCode.TooManyPendingTaskRequests && numberOfRetries < 5) { BGTaskScheduler.Shared.Cancel(id); scheduleBgTask(++numberOfRetries); } else { if ((BGTaskSchedulerErrorCode)(int)error.Code == BGTaskSchedulerErrorCode.Unavailable) { //This will happen IF: // - The EN-API permission is not granted/was removed // AND // - The “Background app refresh” setting is turned OFF. } throw new NSErrorException(error); } } } catch (Exception ex) { LogUtils.LogException(Enums.LogSeverity.ERROR, ex, logPrefix + $"Failed to schedule the background task (Tried 5 times). It will try again when the app is restarted."); } } }