xref: /aosp_15_r20/external/cronet/base/critical_closure.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_CRITICAL_CLOSURE_H_
6 #define BASE_CRITICAL_CLOSURE_H_
7 
8 #include <string_view>
9 #include <utility>
10 
11 #include "base/functional/callback.h"
12 #include "base/location.h"
13 #include "build/build_config.h"
14 #include "build/ios_buildflags.h"
15 
16 #if BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_APP_EXTENSION)
17 #include <optional>
18 
19 #include "base/functional/bind.h"
20 #include "base/ios/scoped_critical_action.h"
21 #endif
22 
23 namespace base {
24 
25 namespace internal {
26 
27 #if BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_APP_EXTENSION)
28 // This class wraps a closure so it can continue to run for a period of time
29 // when the application goes to the background by using
30 // |ios::ScopedCriticalAction|.
31 class ImmediateCriticalClosure {
32  public:
33   explicit ImmediateCriticalClosure(std::string_view task_name,
34                                     OnceClosure closure);
35   ImmediateCriticalClosure(const ImmediateCriticalClosure&) = delete;
36   ImmediateCriticalClosure& operator=(const ImmediateCriticalClosure&) = delete;
37   ~ImmediateCriticalClosure();
38   void Run();
39 
40  private:
41   ios::ScopedCriticalAction critical_action_;
42   OnceClosure closure_;
43 };
44 
45 // This class is identical to ImmediateCriticalClosure, but the critical action
46 // is started when the action runs, not when the CriticalAction is created.
47 class PendingCriticalClosure {
48  public:
49   explicit PendingCriticalClosure(std::string_view task_name,
50                                   OnceClosure closure);
51   PendingCriticalClosure(const PendingCriticalClosure&) = delete;
52   PendingCriticalClosure& operator=(const PendingCriticalClosure&) = delete;
53   ~PendingCriticalClosure();
54   void Run();
55 
56  private:
57   std::optional<ios::ScopedCriticalAction> critical_action_;
58   std::string task_name_;
59   OnceClosure closure_;
60 };
61 #endif  // BUILDFLAG(IS_IOS)
62 
63 }  // namespace internal
64 
65 // Returns a closure that will continue to run for a period of time when the
66 // application goes to the background if possible on platforms where
67 // applications don't execute while backgrounded, otherwise the original task is
68 // returned. If |is_immediate| is true, the closure will immediately prevent
69 // background suspension. Otherwise, the closure will wait to request background
70 // permission until it is run.
71 //
72 // Example:
73 //   file_task_runner_->PostTask(
74 //       FROM_HERE,
75 //       MakeCriticalClosure(task_name,
76 //                           base::BindOnce(&WriteToDiskTask, path_, data)));
77 //
78 // Note new closures might be posted in this closure. If the new closures need
79 // background running time, |MakeCriticalClosure| should be applied on them
80 // before posting. |task_name| is used by the platform to identify any tasks
81 // that do not complete in time for suspension.
82 //
83 // This function is used automatically for tasks posted to a sequence runner
84 // using TaskShutdownBehavior::BLOCK_SHUTDOWN.
85 #if BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_APP_EXTENSION)
MakeCriticalClosure(std::string_view task_name,OnceClosure closure,bool is_immediate)86 inline OnceClosure MakeCriticalClosure(std::string_view task_name,
87                                        OnceClosure closure,
88                                        bool is_immediate) {
89   // Wrapping a null closure in a critical closure has unclear semantics and
90   // most likely indicates a bug. CHECK-ing early allows detecting and
91   // investigating these cases more easily.
92   CHECK(!closure.is_null());
93   if (is_immediate) {
94     return base::BindOnce(&internal::ImmediateCriticalClosure::Run,
95                           Owned(new internal::ImmediateCriticalClosure(
96                               task_name, std::move(closure))));
97   } else {
98     return base::BindOnce(&internal::PendingCriticalClosure::Run,
99                           Owned(new internal::PendingCriticalClosure(
100                               task_name, std::move(closure))));
101   }
102 }
103 
MakeCriticalClosure(const Location & posted_from,OnceClosure closure,bool is_immediate)104 inline OnceClosure MakeCriticalClosure(const Location& posted_from,
105                                        OnceClosure closure,
106                                        bool is_immediate) {
107   return MakeCriticalClosure(posted_from.ToString(), std::move(closure),
108                              is_immediate);
109 }
110 
111 #else  // BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_APP_EXTENSION)
112 
MakeCriticalClosure(std::string_view task_name,OnceClosure closure,bool is_immediate)113 inline OnceClosure MakeCriticalClosure(std::string_view task_name,
114                                        OnceClosure closure,
115                                        bool is_immediate) {
116   // No-op for platforms where the application does not need to acquire
117   // background time for closures to finish when it goes into the background.
118   return closure;
119 }
120 
MakeCriticalClosure(const Location & posted_from,OnceClosure closure,bool is_immediate)121 inline OnceClosure MakeCriticalClosure(const Location& posted_from,
122                                        OnceClosure closure,
123                                        bool is_immediate) {
124   return closure;
125 }
126 
127 #endif  // BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_APP_EXTENSION)
128 
129 }  // namespace base
130 
131 #endif  // BASE_CRITICAL_CLOSURE_H_
132