[M120][Tizen][Onscreen] Fix build errors for TV profile
[platform/framework/web/chromium-efl.git] / chrome / browser / after_startup_task_utils.cc
1 // Copyright 2015 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 #include "chrome/browser/after_startup_task_utils.h"
6
7 #include "base/containers/circular_deque.h"
8 #include "base/lazy_instance.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/process/process.h"
12 #include "base/synchronization/atomic_flag.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/trace_event/trace_event.h"
15 #include "build/build_config.h"
16 #include "build/chromeos_buildflags.h"
17 #include "components/performance_manager/performance_manager_impl.h"
18 #include "components/performance_manager/public/graph/graph.h"
19 #include "components/performance_manager/public/graph/page_node.h"
20 #include "content/public/browser/browser_task_traits.h"
21 #include "content/public/browser/browser_thread.h"
22
23 #if BUILDFLAG(IS_CHROMEOS_ASH)
24 #include "chrome/browser/ash/login/ui/login_display_host.h"
25 #endif
26
27 #if BUILDFLAG(IS_CHROMEOS_LACROS)
28 #include "chromeos/startup/browser_params_proxy.h"
29 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
30
31 using content::BrowserThread;
32
33 namespace {
34
35 struct AfterStartupTask {
36   AfterStartupTask(const base::Location& from_here,
37                    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
38                    base::OnceClosure task)
39       : from_here(from_here), task_runner(task_runner), task(std::move(task)) {}
40   ~AfterStartupTask() {}
41
42   const base::Location from_here;
43   const scoped_refptr<base::SequencedTaskRunner> task_runner;
44   base::OnceClosure task;
45 };
46
47 // The flag may be read on any thread, but must only be set on the UI thread.
48 base::LazyInstance<base::AtomicFlag>::Leaky g_startup_complete_flag;
49
50 // The queue may only be accessed on the UI thread.
51 base::LazyInstance<base::circular_deque<AfterStartupTask*>>::Leaky
52     g_after_startup_tasks;
53
54 bool IsBrowserStartupComplete() {
55   // Be sure to initialize the LazyInstance on the main thread since the flag
56   // may only be set on it's initializing thread.
57   if (!g_startup_complete_flag.IsCreated())
58     return false;
59   return g_startup_complete_flag.Get().IsSet();
60 }
61
62 void RunTask(std::unique_ptr<AfterStartupTask> queued_task) {
63   // We're careful to delete the caller's |task| on the target runner's thread.
64   DCHECK(queued_task->task_runner->RunsTasksInCurrentSequence());
65   std::move(queued_task->task).Run();
66 }
67
68 void ScheduleTask(std::unique_ptr<AfterStartupTask> queued_task) {
69   scoped_refptr<base::SequencedTaskRunner> target_runner =
70       queued_task->task_runner;
71   base::Location from_here = queued_task->from_here;
72   target_runner->PostTask(from_here,
73                           base::BindOnce(&RunTask, std::move(queued_task)));
74 }
75
76 void QueueTask(std::unique_ptr<AfterStartupTask> queued_task) {
77   DCHECK(queued_task);
78
79   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
80   // for details.
81   CHECK(queued_task->task);
82
83   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
84     // Posted with USER_VISIBLE priority to avoid this becoming an after startup
85     // task itself.
86     content::GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE})
87         ->PostTask(FROM_HERE,
88                    base::BindOnce(QueueTask, std::move(queued_task)));
89     return;
90   }
91
92   // The flag may have been set while the task to invoke this method
93   // on the UI thread was inflight.
94   if (IsBrowserStartupComplete()) {
95     ScheduleTask(std::move(queued_task));
96     return;
97   }
98   g_after_startup_tasks.Get().push_back(queued_task.release());
99 }
100
101 void SetBrowserStartupIsComplete() {
102   DCHECK_CURRENTLY_ON(BrowserThread::UI);
103
104   if (IsBrowserStartupComplete())
105     return;
106
107   TRACE_EVENT0("startup", "SetBrowserStartupIsComplete");
108   g_startup_complete_flag.Get().Set();
109 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || \
110     BUILDFLAG(IS_CHROMEOS)
111   // Process::Current().CreationTime() is not available on all platforms.
112   const base::Time process_creation_time =
113       base::Process::Current().CreationTime();
114   if (!process_creation_time.is_null()) {
115     UMA_HISTOGRAM_LONG_TIMES("Startup.AfterStartupTaskDelayedUntilTime",
116                              base::Time::Now() - process_creation_time);
117   }
118 #endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) ||
119         // BUILDFLAG(IS_CHROMEOS)
120   UMA_HISTOGRAM_COUNTS_10000("Startup.AfterStartupTaskCount",
121                              g_after_startup_tasks.Get().size());
122   for (AfterStartupTask* queued_task : g_after_startup_tasks.Get())
123     ScheduleTask(base::WrapUnique(queued_task));
124   g_after_startup_tasks.Get().clear();
125   g_after_startup_tasks.Get().shrink_to_fit();
126 }
127
128 // Observes the first visible page load and sets the startup complete
129 // flag accordingly. Ownership is passed to the Performance Manager
130 // after creation.
131 class StartupObserver
132     : public performance_manager::GraphOwned,
133       public performance_manager::PageNode::ObserverDefaultImpl {
134  public:
135   StartupObserver(const StartupObserver&) = delete;
136   StartupObserver& operator=(const StartupObserver&) = delete;
137
138   ~StartupObserver() override = default;
139
140   static void Start();
141
142  private:
143   StartupObserver() = default;
144
145   void OnStartupComplete() {
146     if (!performance_manager::PerformanceManagerImpl::IsAvailable()) {
147       // Already shutting down before startup finished. Do not notify.
148       return;
149     }
150
151     // This should only be called once.
152     if (!startup_complete_) {
153       startup_complete_ = true;
154       content::GetUIThreadTaskRunner({})->PostTask(
155           FROM_HERE, base::BindOnce(&SetBrowserStartupIsComplete));
156       // This will result in delete getting called.
157       TakeFromGraph();
158     }
159   }
160
161   // GraphOwned overrides
162   void OnPassedToGraph(performance_manager::Graph* graph) override {
163     graph->AddPageNodeObserver(this);
164   }
165
166   void OnTakenFromGraph(performance_manager::Graph* graph) override {
167     graph->RemovePageNodeObserver(this);
168   }
169
170   // PageNodeObserver overrides
171   void OnLoadingStateChanged(
172       const performance_manager::PageNode* page_node,
173       performance_manager::PageNode::LoadingState previous_state) override {
174     // Only interested in visible PageNodes
175     if (page_node->IsVisible()) {
176       if (page_node->GetLoadingState() ==
177               performance_manager::PageNode::LoadingState::kLoadedIdle ||
178           page_node->GetLoadingState() ==
179               performance_manager::PageNode::LoadingState::kLoadingTimedOut)
180         OnStartupComplete();
181     }
182   }
183
184   void PassToGraph() {
185     // Pass to the performance manager so we can get notified when
186     // loading completes.  Ownership of this object is passed to the
187     // performance manager.
188     DCHECK(performance_manager::PerformanceManagerImpl::IsAvailable());
189     performance_manager::PerformanceManagerImpl::PassToGraph(
190         FROM_HERE, base::WrapUnique(this));
191   }
192
193   void TakeFromGraph() {
194     // Remove this object from the performance manager.  This will
195     // cause the object to be deleted.
196     DCHECK(performance_manager::PerformanceManagerImpl::IsAvailable());
197     performance_manager::PerformanceManager::CallOnGraph(
198         FROM_HERE, base::BindOnce(
199                        [](performance_manager::GraphOwned* observer,
200                           performance_manager::Graph* graph) {
201                          graph->TakeFromGraph(observer);
202                        },
203                        base::Unretained(this)));
204   }
205
206   bool startup_complete_ = false;
207 };
208
209 // static
210 void StartupObserver::Start() {
211   // Create the StartupObserver and pass it to the Performance Manager which
212   // will own it going forward.
213   (new StartupObserver)->PassToGraph();
214 }
215
216 }  // namespace
217
218 void AfterStartupTaskUtils::StartMonitoringStartup() {
219   // For Android, startup completion is signaled via
220   // AfterStartupTaskUtils.java. We do not use the StartupObserver.
221 #if !BUILDFLAG(IS_ANDROID)
222 #if BUILDFLAG(IS_CHROMEOS_LACROS)
223   // For Lacros, there may not be a Browser created at startup.
224   if (chromeos::BrowserParamsProxy::Get()->InitialBrowserAction() ==
225       crosapi::mojom::InitialBrowserAction::kDoNotOpenWindow) {
226     content::GetUIThreadTaskRunner({})->PostTask(
227         FROM_HERE, base::BindOnce(&SetBrowserStartupIsComplete));
228     return;
229   }
230 #endif
231
232 #if BUILDFLAG(IS_CHROMEOS_ASH)
233   // If we are on a login screen which does not expect WebUI to be loaded,
234   // Browser won't be created at startup.
235   if (ash::LoginDisplayHost::default_host() &&
236       !ash::LoginDisplayHost::default_host()->IsWebUIStarted()) {
237     content::GetUIThreadTaskRunner({})->PostTask(
238         FROM_HERE, base::BindOnce(&SetBrowserStartupIsComplete));
239     return;
240   }
241 #endif
242
243   StartupObserver::Start();
244 #endif  // !BUILDFLAG(IS_ANDROID)
245
246   // Add failsafe timeout
247   content::GetUIThreadTaskRunner({})->PostDelayedTask(
248       FROM_HERE, base::BindOnce(&SetBrowserStartupIsComplete),
249       base::Minutes(3));
250 }
251
252 void AfterStartupTaskUtils::PostTask(
253     const base::Location& from_here,
254     const scoped_refptr<base::SequencedTaskRunner>& destination_runner,
255     base::OnceClosure task) {
256   if (IsBrowserStartupComplete()) {
257     destination_runner->PostTask(from_here, std::move(task));
258     return;
259   }
260
261   std::unique_ptr<AfterStartupTask> queued_task(
262       new AfterStartupTask(from_here, destination_runner, std::move(task)));
263   QueueTask(std::move(queued_task));
264 }
265
266 void AfterStartupTaskUtils::SetBrowserStartupIsCompleteForTesting() {
267   ::SetBrowserStartupIsComplete();
268 }
269
270 void AfterStartupTaskUtils::SetBrowserStartupIsComplete() {
271   ::SetBrowserStartupIsComplete();
272 }
273
274 bool AfterStartupTaskUtils::IsBrowserStartupComplete() {
275   return ::IsBrowserStartupComplete();
276 }
277
278 void AfterStartupTaskUtils::UnsafeResetForTesting() {
279   DCHECK(g_after_startup_tasks.Get().empty());
280   if (!IsBrowserStartupComplete())
281     return;
282   g_startup_complete_flag.Get().UnsafeResetForTesting();
283   DCHECK(!IsBrowserStartupComplete());
284 }