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