xref: /aosp_15_r20/external/cronet/base/ios/scoped_critical_action.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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