Пример #1
0
        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());
            }
        }
Пример #2
0
        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);
        }
Пример #4
0
        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();
        }
Пример #5
0
        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}");
            }
        }
Пример #6
0
        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();
            }
        }
Пример #7
0
        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();
            }
        }
Пример #8
0
            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}");
                }
            }
Пример #9
0
        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.");
                }
            }
        }