Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(746)

Side by Side Diff: chrome/browser/after_startup_task.cc

Issue 949293002: Implement a poor man's PostAfterStartupTask() function. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
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.h"
6
7 #include "base/lazy_instance.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/process/process_info.h"
11 #include "base/rand_util.h"
12 #include "base/synchronization/cancellation_flag.h"
13 #include "base/task_runner.h"
14 #include "base/tracked_objects.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_iterator.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/render_frame_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_observer.h"
22
23 using content::BrowserThread;
24 using content::WebContents;
25 using content::WebContentsObserver;
26 using StartupCompleteFlag = base::CancellationFlag;
27
28 namespace {
29
30 struct AfterStartupTask {
31 AfterStartupTask(const tracked_objects::Location& from_here,
32 const scoped_refptr<base::TaskRunner>& task_runner,
33 const base::Closure& task)
34 : from_here(from_here), task_runner(task_runner), task(task) {}
35 ~AfterStartupTask() {}
36
37 const tracked_objects::Location from_here;
38 const scoped_refptr<base::TaskRunner> task_runner;
39 const base::Closure task;
40 };
41
42 class StartupObserver;
43 void SetBrowserStartupIsComplete();
44 bool IsBrowserStartupComplete();
45 void QueueTask(scoped_ptr<AfterStartupTask> queued_task);
46 void ScheduleTask(scoped_ptr<AfterStartupTask> queued_task);
47 void RunTask(scoped_ptr<AfterStartupTask> queued_task);
gab 2015/03/30 18:29:37 Fwd-declaring is quite atypical in Chromium, can y
michaeln 2015/04/03 19:51:38 Done
48
49 base::LazyInstance<StartupCompleteFlag>::Leaky g_startup_complete_flag;
50 base::LazyInstance<std::deque<AfterStartupTask*>>::Leaky g_after_startup_tasks;
gab 2015/03/30 18:29:37 Add a comment that this should only be accessed on
michaeln 2015/04/03 19:51:38 Done.
51
52 void SetBrowserStartupIsComplete() {
53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
gab 2015/03/30 18:29:36 Use DCHECK_CURRENTLY_ON.
michaeln 2015/04/03 19:51:38 Done.
54 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX)
55 // CurrentProcessInfo::CreationTime() is not available on all platforms.
56 const base::Time process_creation_time =
57 base::CurrentProcessInfo::CreationTime();
58 if (!process_creation_time.is_null()) {
59 UMA_HISTOGRAM_LONG_TIMES("AfterStartupTasks.RunTime",
60 base::Time::Now() - process_creation_time);
61 }
62 #endif // defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX)
63 UMA_HISTOGRAM_COUNTS_100("AfterStartupTasks.Count",
gab 2015/03/30 18:29:36 I can imagine this growing beyond 100.
michaeln 2015/04/03 19:51:38 Done, how about 10000
64 g_after_startup_tasks.Get().size());
65 g_startup_complete_flag.Get().Set();
66 for (AfterStartupTask* queued_task : g_after_startup_tasks.Get())
67 ScheduleTask(make_scoped_ptr(queued_task));
68 g_after_startup_tasks.Get().clear();
69
70 // poorman's shrink_to_fit()
71 std::deque<AfterStartupTask*>(g_after_startup_tasks.Get()).swap(
72 g_after_startup_tasks.Get());
73 }
74
75 bool IsBrowserStartupComplete() {
76 // Be sure to allocate the flag on the main thread.
77 if (g_startup_complete_flag == nullptr)
78 return false;
79 return g_startup_complete_flag.Get().IsSet();
80 }
81
82 void QueueTask(scoped_ptr<AfterStartupTask> queued_task) {
83 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
84 BrowserThread::PostTask(
85 BrowserThread::UI, FROM_HERE,
86 base::Bind(QueueTask, base::Passed(queued_task.Pass())));
87 return;
88 }
89 if (IsBrowserStartupComplete()) {
gab 2015/03/30 18:29:37 Please add a comment as to why checking this is ne
michaeln 2015/04/03 19:51:38 Done.
90 ScheduleTask(queued_task.Pass());
91 return;
92 }
93 g_after_startup_tasks.Get().push_back(queued_task.release());
94 }
95
96 void ScheduleTask(scoped_ptr<AfterStartupTask> queued_task) {
97 // Spread their execution over a brief time.
98 const int kMinDelay = 0;
99 const int kMaxDelay = 10;
100 scoped_refptr<base::TaskRunner> target_runner = queued_task->task_runner;
101 tracked_objects::Location from_here = queued_task->from_here;
102 target_runner->PostDelayedTask(
103 from_here, base::Bind(&RunTask, base::Passed(queued_task.Pass())),
104 base::TimeDelta::FromSeconds(base::RandInt(kMinDelay, kMaxDelay)));
105 }
106
107 void RunTask(scoped_ptr<AfterStartupTask> queued_task) {
108 // We're careful to delete the caller's |task| on the target runner's thread.
109 DCHECK(queued_task->task_runner->RunsTasksOnCurrentThread());
110 queued_task->task.Run();
111 }
112
113 // Observes the first page load and set the startup complete flag accordingly.
gab 2015/03/30 18:29:36 I would add "visible" to that (i.e., "first visibi
michaeln 2015/04/03 19:51:38 Done, should work well with background mode launch
114 class StartupObserver : public WebContentsObserver {
gab 2015/03/30 18:29:36 I'd feel safer (and it would be self-documenting c
michaeln 2015/04/03 19:51:38 Done, except only put the dcheck in OnStartupCompl
115 public:
116 StartupObserver() : weak_factory_(this) {}
117 ~StartupObserver() override { DCHECK(IsBrowserStartupComplete()); }
118
119 void Start();
120
121 private:
122 void OnStartupComplete() {
123 SetBrowserStartupIsComplete();
124 delete this;
125 }
126
127 void OnFailsafeTimeout() { OnStartupComplete(); }
128
129 // WebContentsObserver overrides
130 void DidFinishLoad(content::RenderFrameHost* render_frame_host,
131 const GURL& validated_url) override {
132 if (!render_frame_host->GetParent())
133 OnStartupComplete();
134 }
135
136 void DidFailLoad(content::RenderFrameHost* render_frame_host,
137 const GURL& validated_url,
138 int error_code,
139 const base::string16& error_description) override {
140 if (!render_frame_host->GetParent())
141 OnStartupComplete();
142 }
143
144 void WebContentsDestroyed() override { OnStartupComplete(); }
145
146 base::WeakPtrFactory<StartupObserver> weak_factory_;
147
148 DISALLOW_COPY_AND_ASSIGN(StartupObserver);
149 };
150
151 void StartupObserver::Start() {
152 // Signal completion quickly when there is no first page to load.
153 const int kShortDelaySecs = 3;
154 base::TimeDelta delay = base::TimeDelta::FromSeconds(kShortDelaySecs);
155
156 #if !defined(OS_ANDROID)
157 WebContents* contents = nullptr;
158 for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) {
159 contents = (*iter)->tab_strip_model()->GetActiveWebContents();
160 if (contents)
161 break;
162 }
163
164 if (contents) {
165 // Give the page time to finish loading.
166 const int kLongerDelayMins = 3;
167 Observe(contents);
168 delay = base::TimeDelta::FromMinutes(kLongerDelayMins);
169 }
170 #endif // !defined(OS_ANDROID)
171
172 BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
173 base::Bind(&StartupObserver::OnFailsafeTimeout,
174 weak_factory_.GetWeakPtr()),
175 delay);
176 }
177
178 } // namespace
179
180 void StartMonitoringStartup() {
181 // The observer is self-deleting.
182 (new StartupObserver)->Start();
gab 2015/03/30 18:29:37 This is a little weird, should we make the constru
michaeln 2015/04/03 19:51:38 You mean a static method with this body :) I origi
183 }
184
185 void PostAfterStartupTask(const tracked_objects::Location& from_here,
186 const scoped_refptr<base::TaskRunner>& task_runner,
187 const base::Closure& task) {
188 if (IsBrowserStartupComplete()) {
189 task_runner->PostTask(from_here, task);
190 return;
191 }
192
193 scoped_ptr<AfterStartupTask> queued_task(
194 new AfterStartupTask(from_here, task_runner, task));
195 QueueTask(queued_task.Pass());
196 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698