OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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/page_cycler/page_cycler.h" | |
Aaron Boodman
2012/05/16 23:37:00
Not reviewing this because I think I already revie
clintstaley
2012/05/31 01:54:30
Right. Just a Git collision here.
| |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_path.h" | |
9 #include "base/file_util.h" | |
10 #include "base/message_loop.h" | |
11 #include "base/process_util.h" | |
12 #include "base/string_split.h" | |
13 #include "base/string_number_conversions.h" | |
14 #include "base/utf_string_conversions.h" | |
15 #include "chrome/app/chrome_command_ids.h" | |
16 #include "chrome/common/chrome_notification_types.h" | |
17 #include "chrome/test/base/chrome_process_util.h" | |
18 #include "chrome/test/perf/perf_test.h" | |
19 #include "content/public/browser/browser_thread.h" | |
20 #include "content/public/browser/notification_source.h" | |
21 #include "content/public/browser/notification_service.h" | |
22 #include "content/public/browser/notification_details.h" | |
23 #include "content/public/browser/notification_types.h" | |
24 #include "content/public/browser/web_contents.h" | |
25 #include "content/public/common/url_constants.h" | |
26 | |
27 using content::NavigationController; | |
28 using content::OpenURLParams; | |
29 using content::Referrer; | |
30 using content::WebContents; | |
31 | |
32 PageCycler::PageCycler(Browser* browser, | |
33 FilePath urls_file, | |
34 FilePath errors_file) | |
35 : content::WebContentsObserver(browser->GetSelectedWebContents()), | |
36 browser_(browser), | |
37 urls_file_(urls_file), | |
38 errors_file_(errors_file), | |
39 url_index_(0), | |
40 total_iterations_(0), | |
41 current_iteration_(0), | |
42 aborted_(false) { | |
43 BrowserList::AddObserver(this); | |
44 AddRef(); // Balanced in Finish()/Abort() (only one should be called). | |
45 } | |
46 | |
47 PageCycler::~PageCycler() { | |
48 } | |
49 | |
50 bool PageCycler::IsLoadCallbackValid(const GURL& validated_url, | |
51 bool is_main_frame) { | |
52 // If |url_index_| is equal to zero, that means that this was called before | |
53 // LoadNextURL() - this can happen at startup, loading the new tab page; or | |
54 // if the user specified a bad url as the final url in the list. In these | |
55 // cases, do not report success or failure, and load the next page. | |
56 if (!url_index_) { | |
57 LoadNextURL(); | |
58 return false; | |
59 } | |
60 return (is_main_frame && | |
61 validated_url.spec() != content::kUnreachableWebDataURL); | |
62 } | |
63 | |
64 void PageCycler::DidFinishLoad(int64 frame_id, | |
65 const GURL& validated_url, | |
66 bool is_main_frame) { | |
67 if (IsLoadCallbackValid(validated_url, is_main_frame)) | |
68 LoadSucceeded(); | |
69 } | |
70 | |
71 void PageCycler::DidFailProvisionalLoad(int64 frame_id, | |
72 bool is_main_frame, | |
73 const GURL& validated_url, | |
74 int error_code, | |
75 const string16& error_description) { | |
76 if (IsLoadCallbackValid(validated_url, is_main_frame)) | |
77 LoadFailed(validated_url, error_description); | |
78 } | |
79 | |
80 void PageCycler::Run(const int& total_iterations) { | |
81 total_iterations_ = total_iterations; | |
82 content::BrowserThread::PostBlockingPoolTask( | |
83 FROM_HERE, | |
84 base::Bind(&PageCycler::ReadURLsOnBackgroundThread, this)); | |
85 } | |
86 | |
87 void PageCycler::ReadURLsOnBackgroundThread() { | |
88 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
89 std::string file_contents; | |
90 std::vector<std::string> url_strings; | |
91 | |
92 CHECK(file_util::PathExists(urls_file_)) << urls_file_.value(); | |
93 file_util::ReadFileToString(urls_file_, &file_contents); | |
94 base::SplitStringAlongWhitespace(file_contents, &url_strings); | |
95 | |
96 if (!url_strings.size()) { | |
97 #if defined(OS_POSIX) | |
98 error_.append(ASCIIToUTF16("Page Cycler: No URLs in given file: " + | |
99 urls_file_.value())); | |
100 #elif defined(OS_WIN) | |
101 error_.append(ASCIIToUTF16("Page Cycler: No URLs in given file: ")) | |
102 .append(urls_file_.value()); | |
103 #endif // OS_WIN | |
104 } | |
105 | |
106 for (std::vector<std::string>::const_iterator iter = url_strings.begin(); | |
107 iter != url_strings.end(); ++iter) { | |
108 GURL gurl(*iter); | |
109 if (!gurl.is_valid()) | |
110 error_.append(ASCIIToUTF16("Omitting invalid URL: " + *iter + ".\n")); | |
111 // Since we don't count kUnreachableWebData as a valid load, we don't want | |
112 // the user to specify this as one of the pages to visit. | |
113 else if (*iter == content::kUnreachableWebDataURL) { | |
114 error_.append(ASCIIToUTF16( | |
115 "Chrome error pages are not allowed as urls. Omitting url: " + | |
116 *iter + ".\n")); | |
117 } else { | |
118 urls_.push_back(gurl); | |
119 } | |
120 } | |
121 | |
122 content::BrowserThread::PostTask(content::BrowserThread::UI, | |
123 FROM_HERE, | |
124 base::Bind(&PageCycler::BeginCycle, this)); | |
125 } | |
126 | |
127 void PageCycler::BeginCycle() { | |
128 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
129 | |
130 // Upon launch, Chrome will automatically load the newtab page. This can | |
131 // result in the browser being in a state of loading when PageCycler is ready | |
132 // to start. Instead of interrupting the load, we wait for it to finish, and | |
133 // will call LoadNextURL() from DidFinishLoad() or DidFailProvisionalLoad(). | |
134 if (browser_->GetSelectedWebContents()->IsLoading()) | |
135 return; | |
136 | |
137 LoadNextURL(); | |
138 } | |
139 | |
140 void PageCycler::LoadNextURL() { | |
141 CHECK(browser_); | |
142 if (url_index_ >= urls_.size()) { | |
143 if (current_iteration_ < total_iterations_ - 1) { | |
144 ++current_iteration_; | |
145 url_index_ = 0; | |
146 } else { | |
147 PrepareResults(); | |
148 return; | |
149 } | |
150 } | |
151 if (url_index_ || current_iteration_) { | |
152 timings_string_.append(", "); | |
153 urls_string_.append(", "); | |
154 } | |
155 urls_string_.append(urls_[url_index_].spec()); | |
156 initial_time_ = base::TimeTicks::HighResNow(); | |
157 OpenURLParams params(urls_[url_index_], | |
158 Referrer(), | |
159 CURRENT_TAB, | |
160 content::PAGE_TRANSITION_TYPED, | |
161 false); | |
162 ++url_index_; | |
163 browser_->OpenURL(params); | |
164 } | |
165 | |
166 void PageCycler::LoadSucceeded() { | |
167 base::TimeDelta time_elapsed = | |
168 (base::TimeTicks::HighResNow() - initial_time_) / 1000.0; | |
169 timings_string_.append(base::Int64ToString(time_elapsed.ToInternalValue())); | |
170 LoadNextURL(); | |
171 } | |
172 | |
173 void PageCycler::LoadFailed(const GURL& url, | |
174 const string16& error_description) { | |
175 error_.append(ASCIIToUTF16("Failed to load the page at: " + | |
176 url.spec() + ": ")).append(error_description). | |
177 append(ASCIIToUTF16("\n")); | |
178 base::TimeDelta time_elapsed = | |
179 (base::TimeTicks::HighResNow() - initial_time_) / 1000.0; | |
180 timings_string_.append(base::Int64ToString(time_elapsed.ToInternalValue()) + | |
181 (" (failed)")); | |
182 LoadNextURL(); | |
183 } | |
184 | |
185 void PageCycler::PrepareResults() { | |
186 std::string output; | |
187 if (!stats_file_.empty()) { | |
188 #if defined(OS_POSIX) | |
189 base::ProcessId pid = base::GetParentProcessId(base::GetCurrentProcId()); | |
190 #elif defined(OS_WIN) | |
191 base::ProcessId pid = base::GetCurrentProcID(); | |
192 #endif // OS_WIN | |
193 ChromeProcessList chrome_processes(GetRunningChromeProcesses(pid)); | |
194 output += perf_test::MemoryUsageInfoToString("", chrome_processes, pid); | |
195 output += perf_test::IOPerfInfoToString("", chrome_processes, pid); | |
196 output += perf_test::SystemCommitChargeToString("", | |
197 base::GetSystemCommitCharge(), false); | |
198 output.append("Pages: [" + urls_string_ + "]\n"); | |
199 output.append("*RESULT times: t_ref= [" + timings_string_ + "] ms\n"); | |
200 } | |
201 content::BrowserThread::PostBlockingPoolTask( | |
202 FROM_HERE, | |
203 base::Bind(&PageCycler::WriteResultsOnBackgroundThread, this, output)); | |
204 } | |
205 | |
206 void PageCycler::WriteResultsOnBackgroundThread(std::string output) { | |
207 CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
208 if (!output.empty()) { | |
209 CHECK(!stats_file_.empty()); | |
210 file_util::WriteFile(stats_file_, output.c_str(), output.size()); | |
211 } | |
212 CHECK(!errors_file_.empty()); | |
213 if (!error_.empty()) { | |
214 file_util::WriteFile(errors_file_, UTF16ToUTF8(error_).c_str(), | |
215 error_.size()); | |
216 } else if (file_util::PathExists(errors_file_)) { | |
217 // If there is an old error file, delete it to avoid confusion. | |
218 file_util::Delete(errors_file_, false); | |
219 } | |
220 if (aborted_) { | |
221 content::BrowserThread::PostTask(content::BrowserThread::UI, | |
222 FROM_HERE, | |
223 base::Bind(&PageCycler::Abort, this)); | |
224 } else { | |
225 content::BrowserThread::PostTask(content::BrowserThread::UI, | |
226 FROM_HERE, | |
227 base::Bind(&PageCycler::Finish, this)); | |
228 } | |
229 } | |
230 | |
231 void PageCycler::Finish() { | |
232 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
233 BrowserList::RemoveObserver(this); | |
234 browser_->OnWindowClosing(); | |
235 browser_->ExecuteCommand(IDC_EXIT); | |
236 Release(); // Balanced in Init() (only one of Finish/Abort should be called). | |
237 } | |
238 | |
239 void PageCycler::Abort() { | |
240 browser_ = NULL; | |
241 BrowserList::RemoveObserver(this); | |
242 Release(); // Balanced in Init() (only one of Finish/Abort should be called). | |
243 } | |
244 | |
245 void PageCycler::OnBrowserAdded(const Browser* browser) {} | |
246 | |
247 void PageCycler::OnBrowserRemoved(const Browser* browser) { | |
248 if (browser == browser_) { | |
249 aborted_ = true; | |
250 error_.append(ASCIIToUTF16( | |
251 "Browser was closed before the run was completed.")); | |
252 DLOG(WARNING) << | |
253 "Page Cycler: browser was closed before the run was completed."; | |
254 MessageLoop::current()->PostTask( | |
255 FROM_HERE, base::Bind(&PageCycler::PrepareResults, this)); | |
256 } | |
257 } | |
OLD | NEW |