1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_IOS_SCOPED_CRITICAL_ACTION_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_IOS_SCOPED_CRITICAL_ACTION_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <map> 9*6777b538SAndroid Build Coastguard Worker #include <string> 10*6777b538SAndroid Build Coastguard Worker #include <string_view> 11*6777b538SAndroid Build Coastguard Worker #include <utility> 12*6777b538SAndroid Build Coastguard Worker 13*6777b538SAndroid Build Coastguard Worker #include "base/memory/ref_counted.h" 14*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h" 15*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h" 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker namespace base { 18*6777b538SAndroid Build Coastguard Worker namespace ios { 19*6777b538SAndroid Build Coastguard Worker 20*6777b538SAndroid Build Coastguard Worker // This class attempts to allow the application to continue to run for a period 21*6777b538SAndroid Build Coastguard Worker // of time after it transitions to the background. The construction of an 22*6777b538SAndroid Build Coastguard Worker // instance of this class marks the beginning of a task that needs background 23*6777b538SAndroid Build Coastguard Worker // running time when the application is moved to the background and the 24*6777b538SAndroid Build Coastguard Worker // destruction marks the end of such a task. 25*6777b538SAndroid Build Coastguard Worker // 26*6777b538SAndroid Build Coastguard Worker // Note there is no guarantee that the task will continue to finish when the 27*6777b538SAndroid Build Coastguard Worker // application is moved to the background. 28*6777b538SAndroid Build Coastguard Worker // 29*6777b538SAndroid Build Coastguard Worker // This class should be used at times where leaving a task unfinished might be 30*6777b538SAndroid Build Coastguard Worker // detrimental to user experience. For example, it should be used to ensure that 31*6777b538SAndroid Build Coastguard Worker // the application has enough time to save important data or at least attempt to 32*6777b538SAndroid Build Coastguard Worker // save such data. 33*6777b538SAndroid Build Coastguard Worker class ScopedCriticalAction { 34*6777b538SAndroid Build Coastguard Worker public: 35*6777b538SAndroid Build Coastguard Worker ScopedCriticalAction(std::string_view task_name); 36*6777b538SAndroid Build Coastguard Worker 37*6777b538SAndroid Build Coastguard Worker ScopedCriticalAction(const ScopedCriticalAction&) = delete; 38*6777b538SAndroid Build Coastguard Worker ScopedCriticalAction& operator=(const ScopedCriticalAction&) = delete; 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard Worker ~ScopedCriticalAction(); 41*6777b538SAndroid Build Coastguard Worker 42*6777b538SAndroid Build Coastguard Worker // Exposed for unit-testing. 43*6777b538SAndroid Build Coastguard Worker static void ClearNumActiveBackgroundTasksForTest(); 44*6777b538SAndroid Build Coastguard Worker static int GetNumActiveBackgroundTasksForTest(); 45*6777b538SAndroid Build Coastguard Worker 46*6777b538SAndroid Build Coastguard Worker private: 47*6777b538SAndroid Build Coastguard Worker // Core logic; ScopedCriticalAction should not be reference counted so 48*6777b538SAndroid Build Coastguard Worker // that it follows the normal pattern of stack-allocating ScopedFoo objects, 49*6777b538SAndroid Build Coastguard Worker // but the expiration handler needs to have a reference counted object to 50*6777b538SAndroid Build Coastguard Worker // refer to. All functions are thread safe. 51*6777b538SAndroid Build Coastguard Worker class Core : public base::RefCountedThreadSafe<Core> { 52*6777b538SAndroid Build Coastguard Worker public: 53*6777b538SAndroid Build Coastguard Worker Core(); 54*6777b538SAndroid Build Coastguard Worker 55*6777b538SAndroid Build Coastguard Worker Core(const Core&) = delete; 56*6777b538SAndroid Build Coastguard Worker Core& operator=(const Core&) = delete; 57*6777b538SAndroid Build Coastguard Worker 58*6777b538SAndroid Build Coastguard Worker // Informs the OS that the background task has started. This is a 59*6777b538SAndroid Build Coastguard Worker // static method to ensure that the instance has a non-zero refcount. 60*6777b538SAndroid Build Coastguard Worker // |task_name| is used by the OS to log any leaked background tasks. 61*6777b538SAndroid Build Coastguard Worker // Invoking this function more than once is allowed: all except the 62*6777b538SAndroid Build Coastguard Worker // first successful call will be a no-op. 63*6777b538SAndroid Build Coastguard Worker static void StartBackgroundTask(scoped_refptr<Core> core, 64*6777b538SAndroid Build Coastguard Worker std::string_view task_name); 65*6777b538SAndroid Build Coastguard Worker // Informs the OS that the background task has completed. This is a 66*6777b538SAndroid Build Coastguard Worker // static method to ensure that the instance has a non-zero refcount. 67*6777b538SAndroid Build Coastguard Worker // Invoking this function more than once is allowed: all except the 68*6777b538SAndroid Build Coastguard Worker // first call will be a no-op. 69*6777b538SAndroid Build Coastguard Worker static void EndBackgroundTask(scoped_refptr<Core> core); 70*6777b538SAndroid Build Coastguard Worker 71*6777b538SAndroid Build Coastguard Worker private: 72*6777b538SAndroid Build Coastguard Worker friend base::RefCountedThreadSafe<Core>; 73*6777b538SAndroid Build Coastguard Worker ~Core(); 74*6777b538SAndroid Build Coastguard Worker 75*6777b538SAndroid Build Coastguard Worker // |UIBackgroundTaskIdentifier| returned by 76*6777b538SAndroid Build Coastguard Worker // |beginBackgroundTaskWithName:expirationHandler:| when marking the 77*6777b538SAndroid Build Coastguard Worker // beginning of a long-running background task. It is defined as a uint64_t 78*6777b538SAndroid Build Coastguard Worker // instead of a |UIBackgroundTaskIdentifier| so this class can be used in 79*6777b538SAndroid Build Coastguard Worker // .cc files. 80*6777b538SAndroid Build Coastguard Worker uint64_t background_task_id_ GUARDED_BY(background_task_id_lock_); 81*6777b538SAndroid Build Coastguard Worker Lock background_task_id_lock_; 82*6777b538SAndroid Build Coastguard Worker }; 83*6777b538SAndroid Build Coastguard Worker 84*6777b538SAndroid Build Coastguard Worker // This class is thread safe. 85*6777b538SAndroid Build Coastguard Worker class ActiveBackgroundTaskCache { 86*6777b538SAndroid Build Coastguard Worker public: 87*6777b538SAndroid Build Coastguard Worker // This struct should be considered internal to this class and opaque to 88*6777b538SAndroid Build Coastguard Worker // callers. 89*6777b538SAndroid Build Coastguard Worker struct InternalEntry { 90*6777b538SAndroid Build Coastguard Worker InternalEntry(); 91*6777b538SAndroid Build Coastguard Worker InternalEntry(const InternalEntry&) = delete; 92*6777b538SAndroid Build Coastguard Worker InternalEntry(InternalEntry&&); 93*6777b538SAndroid Build Coastguard Worker ~InternalEntry(); 94*6777b538SAndroid Build Coastguard Worker 95*6777b538SAndroid Build Coastguard Worker InternalEntry& operator=(const InternalEntry&) = delete; 96*6777b538SAndroid Build Coastguard Worker InternalEntry& operator=(InternalEntry&&); 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Worker // The instance of the core that drives the background task. 99*6777b538SAndroid Build Coastguard Worker scoped_refptr<Core> core; 100*6777b538SAndroid Build Coastguard Worker // Refcounting for the number of ScopedCriticalAction instances that 101*6777b538SAndroid Build Coastguard Worker // require the existence of this background task. 102*6777b538SAndroid Build Coastguard Worker int num_active_handles = 0; 103*6777b538SAndroid Build Coastguard Worker }; 104*6777b538SAndroid Build Coastguard Worker 105*6777b538SAndroid Build Coastguard Worker using NameAndTime = std::pair<std::string, base::TimeTicks>; 106*6777b538SAndroid Build Coastguard Worker using InternalEntriesMap = std::map<NameAndTime, InternalEntry>; 107*6777b538SAndroid Build Coastguard Worker // A handle should be treated as an opaque token by the caller. 108*6777b538SAndroid Build Coastguard Worker using Handle = InternalEntriesMap::iterator; 109*6777b538SAndroid Build Coastguard Worker 110*6777b538SAndroid Build Coastguard Worker // Returns a leaky singleton instance. 111*6777b538SAndroid Build Coastguard Worker static ActiveBackgroundTaskCache* GetInstance(); 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard Worker ActiveBackgroundTaskCache(); 114*6777b538SAndroid Build Coastguard Worker ~ActiveBackgroundTaskCache(); 115*6777b538SAndroid Build Coastguard Worker 116*6777b538SAndroid Build Coastguard Worker // Starts a new background task if none existed with the same name. If a 117*6777b538SAndroid Build Coastguard Worker // task already exists with the same name, its lifetime is effectively 118*6777b538SAndroid Build Coastguard Worker // extended. Callers must invoke ReleaseHandle() once they no longer need to 119*6777b538SAndroid Build Coastguard Worker // prevent background suspension. 120*6777b538SAndroid Build Coastguard Worker Handle EnsureBackgroundTaskExistsWithName(std::string_view task_name); 121*6777b538SAndroid Build Coastguard Worker 122*6777b538SAndroid Build Coastguard Worker // Indicates that a previous caller to EnsureBackgroundTaskExistsWithName() 123*6777b538SAndroid Build Coastguard Worker // no longer needs to prevent background suspension. 124*6777b538SAndroid Build Coastguard Worker void ReleaseHandle(Handle handle); 125*6777b538SAndroid Build Coastguard Worker 126*6777b538SAndroid Build Coastguard Worker private: 127*6777b538SAndroid Build Coastguard Worker InternalEntriesMap entries_map_ GUARDED_BY(entries_map_lock_); 128*6777b538SAndroid Build Coastguard Worker Lock entries_map_lock_; 129*6777b538SAndroid Build Coastguard Worker }; 130*6777b538SAndroid Build Coastguard Worker 131*6777b538SAndroid Build Coastguard Worker const ActiveBackgroundTaskCache::Handle task_handle_; 132*6777b538SAndroid Build Coastguard Worker }; 133*6777b538SAndroid Build Coastguard Worker 134*6777b538SAndroid Build Coastguard Worker } // namespace ios 135*6777b538SAndroid Build Coastguard Worker } // namespace base 136*6777b538SAndroid Build Coastguard Worker 137*6777b538SAndroid Build Coastguard Worker #endif // BASE_IOS_SCOPED_CRITICAL_ACTION_H_ 138