Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / ui / webui / about_ui.cc
blob248d5f4bb34269c80c91ed7d60aa5ec14fef5eba
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.
5 #include "chrome/browser/ui/webui/about_ui.h"
7 #include <algorithm>
8 #include <string>
9 #include <utility>
10 #include <vector>
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/files/file_util.h"
17 #include "base/format_macros.h"
18 #include "base/i18n/number_formatting.h"
19 #include "base/json/json_writer.h"
20 #include "base/memory/singleton.h"
21 #include "base/metrics/statistics_recorder.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_piece.h"
24 #include "base/strings/string_split.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/stringprintf.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/threading/thread.h"
29 #include "base/values.h"
30 #include "chrome/browser/about_flags.h"
31 #include "chrome/browser/browser_process.h"
32 #include "chrome/browser/defaults.h"
33 #include "chrome/browser/memory/oom_priority_manager.h"
34 #include "chrome/browser/memory/tab_stats.h"
35 #include "chrome/browser/memory_details.h"
36 #include "chrome/browser/net/predictor.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/profiles/profile_manager.h"
39 #include "chrome/browser/ui/browser_dialogs.h"
40 #include "chrome/common/chrome_paths.h"
41 #include "chrome/common/url_constants.h"
42 #include "chrome/grit/chromium_strings.h"
43 #include "chrome/grit/generated_resources.h"
44 #include "chrome/grit/locale_settings.h"
45 #include "content/public/browser/browser_thread.h"
46 #include "content/public/browser/render_process_host.h"
47 #include "content/public/browser/render_view_host.h"
48 #include "content/public/browser/url_data_source.h"
49 #include "content/public/browser/web_contents.h"
50 #include "content/public/common/content_client.h"
51 #include "content/public/common/process_type.h"
52 #include "google_apis/gaia/google_service_auth_error.h"
53 #include "grit/browser_resources.h"
54 #include "net/base/escape.h"
55 #include "net/base/filename_util.h"
56 #include "net/base/load_flags.h"
57 #include "net/http/http_response_headers.h"
58 #include "net/url_request/url_fetcher.h"
59 #include "net/url_request/url_request_status.h"
60 #include "ui/base/l10n/l10n_util.h"
61 #include "ui/base/resource/resource_bundle.h"
62 #include "ui/base/webui/jstemplate_builder.h"
63 #include "ui/base/webui/web_ui_util.h"
64 #include "url/gurl.h"
66 #if defined(ENABLE_THEMES)
67 #include "chrome/browser/ui/webui/theme_source.h"
68 #endif
70 #if defined(OS_LINUX) || defined(OS_OPENBSD)
71 #include "content/public/browser/zygote_host_linux.h"
72 #include "content/public/common/sandbox_linux.h"
73 #endif
75 #if defined(OS_WIN)
76 #include "chrome/browser/enumerate_modules_model_win.h"
77 #endif
79 #if defined(OS_CHROMEOS)
80 #include "chrome/browser/browser_process_platform_part_chromeos.h"
81 #include "chrome/browser/chromeos/customization/customization_document.h"
82 #endif
84 using base::Time;
85 using base::TimeDelta;
86 using content::BrowserThread;
87 using content::WebContents;
89 namespace {
91 const char kCreditsJsPath[] = "credits.js";
92 const char kMemoryJsPath[] = "memory.js";
93 const char kMemoryCssPath[] = "about_memory.css";
94 const char kStatsJsPath[] = "stats.js";
95 const char kStringsJsPath[] = "strings.js";
97 // When you type about:memory, it actually loads this intermediate URL that
98 // redirects you to the final page. This avoids the problem where typing
99 // "about:memory" on the new tab page or any other page where a process
100 // transition would occur to the about URL will cause some confusion.
102 // The problem is that during the processing of the memory page, there are two
103 // processes active, the original and the destination one. This can create the
104 // impression that we're using more resources than we actually are. This
105 // redirect solves the problem by eliminating the process transition during the
106 // time that about memory is being computed.
107 std::string GetAboutMemoryRedirectResponse(Profile* profile) {
108 return base::StringPrintf("<meta http-equiv='refresh' content='0;%s'>",
109 chrome::kChromeUIMemoryRedirectURL);
112 // Handling about:memory is complicated enough to encapsulate its related
113 // methods into a single class. The user should create it (on the heap) and call
114 // its |StartFetch()| method.
115 class AboutMemoryHandler : public MemoryDetails {
116 public:
117 explicit AboutMemoryHandler(
118 const content::URLDataSource::GotDataCallback& callback)
119 : callback_(callback) {
122 void OnDetailsAvailable() override;
124 private:
125 ~AboutMemoryHandler() override {}
127 void BindProcessMetrics(base::DictionaryValue* data,
128 ProcessMemoryInformation* info);
129 void AppendProcess(base::ListValue* child_data,
130 ProcessMemoryInformation* info);
132 content::URLDataSource::GotDataCallback callback_;
134 DISALLOW_COPY_AND_ASSIGN(AboutMemoryHandler);
137 #if defined(OS_CHROMEOS)
139 const char kKeyboardUtilsPath[] = "keyboard_utils.js";
141 // chrome://terms falls back to offline page after kOnlineTermsTimeoutSec.
142 const int kOnlineTermsTimeoutSec = 7;
144 // Helper class that fetches the online Chrome OS terms. Empty string is
145 // returned once fetching failed or exceeded |kOnlineTermsTimeoutSec|.
146 class ChromeOSOnlineTermsHandler : public net::URLFetcherDelegate {
147 public:
148 typedef base::Callback<void (ChromeOSOnlineTermsHandler*)> FetchCallback;
150 explicit ChromeOSOnlineTermsHandler(const FetchCallback& callback,
151 const std::string& locale)
152 : fetch_callback_(callback) {
153 std::string eula_URL = base::StringPrintf(chrome::kOnlineEulaURLPath,
154 locale.c_str());
155 eula_fetcher_ =
156 net::URLFetcher::Create(0 /* ID used for testing */, GURL(eula_URL),
157 net::URLFetcher::GET, this);
158 eula_fetcher_->SetRequestContext(
159 g_browser_process->system_request_context());
160 eula_fetcher_->AddExtraRequestHeader("Accept: text/html");
161 eula_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
162 net::LOAD_DO_NOT_SAVE_COOKIES |
163 net::LOAD_DISABLE_CACHE);
164 eula_fetcher_->Start();
165 // Abort the download attempt if it takes longer than one minute.
166 download_timer_.Start(FROM_HERE,
167 base::TimeDelta::FromSeconds(kOnlineTermsTimeoutSec),
168 this,
169 &ChromeOSOnlineTermsHandler::OnDownloadTimeout);
172 void GetResponseResult(std::string* response_string) {
173 std::string mime_type;
174 if (!eula_fetcher_ ||
175 !eula_fetcher_->GetStatus().is_success() ||
176 eula_fetcher_->GetResponseCode() != 200 ||
177 !eula_fetcher_->GetResponseHeaders()->GetMimeType(&mime_type) ||
178 mime_type != "text/html" ||
179 !eula_fetcher_->GetResponseAsString(response_string)) {
180 response_string->clear();
184 private:
185 // Prevents allocation on the stack. ChromeOSOnlineTermsHandler should be
186 // created by 'operator new'. |this| takes care of destruction.
187 ~ChromeOSOnlineTermsHandler() override {}
189 // net::URLFetcherDelegate:
190 void OnURLFetchComplete(const net::URLFetcher* source) override {
191 if (source != eula_fetcher_.get()) {
192 NOTREACHED() << "Callback from foreign URL fetcher";
193 return;
195 fetch_callback_.Run(this);
196 delete this;
199 void OnDownloadTimeout() {
200 eula_fetcher_.reset();
201 fetch_callback_.Run(this);
202 delete this;
205 // Timer that enforces a timeout on the attempt to download the
206 // ChromeOS Terms.
207 base::OneShotTimer<ChromeOSOnlineTermsHandler> download_timer_;
209 // |fetch_callback_| called when fetching succeeded or failed.
210 FetchCallback fetch_callback_;
212 // Helper to fetch online eula.
213 scoped_ptr<net::URLFetcher> eula_fetcher_;
215 DISALLOW_COPY_AND_ASSIGN(ChromeOSOnlineTermsHandler);
218 class ChromeOSTermsHandler
219 : public base::RefCountedThreadSafe<ChromeOSTermsHandler> {
220 public:
221 static void Start(const std::string& path,
222 const content::URLDataSource::GotDataCallback& callback) {
223 scoped_refptr<ChromeOSTermsHandler> handler(
224 new ChromeOSTermsHandler(path, callback));
225 handler->StartOnUIThread();
228 private:
229 friend class base::RefCountedThreadSafe<ChromeOSTermsHandler>;
231 ChromeOSTermsHandler(const std::string& path,
232 const content::URLDataSource::GotDataCallback& callback)
233 : path_(path),
234 callback_(callback),
235 // Previously we were using "initial locale" http://crbug.com/145142
236 locale_(g_browser_process->GetApplicationLocale()) {
239 virtual ~ChromeOSTermsHandler() {}
241 void StartOnUIThread() {
242 DCHECK_CURRENTLY_ON(BrowserThread::UI);
243 if (path_ == chrome::kOemEulaURLPath) {
244 // Load local OEM EULA from the disk.
245 BrowserThread::PostTask(
246 BrowserThread::FILE, FROM_HERE,
247 base::Bind(&ChromeOSTermsHandler::LoadOemEulaFileOnFileThread, this));
248 } else {
249 // Try to load online version of ChromeOS terms first.
250 // ChromeOSOnlineTermsHandler object destroys itself.
251 new ChromeOSOnlineTermsHandler(
252 base::Bind(&ChromeOSTermsHandler::OnOnlineEULAFetched, this),
253 locale_);
257 void OnOnlineEULAFetched(ChromeOSOnlineTermsHandler* loader) {
258 DCHECK_CURRENTLY_ON(BrowserThread::UI);
259 loader->GetResponseResult(&contents_);
260 if (contents_.empty()) {
261 // Load local ChromeOS terms from the file.
262 BrowserThread::PostTask(
263 BrowserThread::FILE, FROM_HERE,
264 base::Bind(&ChromeOSTermsHandler::LoadEulaFileOnFileThread, this));
265 } else {
266 ResponseOnUIThread();
270 void LoadOemEulaFileOnFileThread() {
271 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
272 const chromeos::StartupCustomizationDocument* customization =
273 chromeos::StartupCustomizationDocument::GetInstance();
274 if (customization->IsReady()) {
275 base::FilePath oem_eula_file_path;
276 if (net::FileURLToFilePath(GURL(customization->GetEULAPage(locale_)),
277 &oem_eula_file_path)) {
278 if (!base::ReadFileToString(oem_eula_file_path, &contents_)) {
279 contents_.clear();
283 BrowserThread::PostTask(
284 BrowserThread::UI, FROM_HERE,
285 base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
288 void LoadEulaFileOnFileThread() {
289 std::string file_path =
290 base::StringPrintf(chrome::kEULAPathFormat, locale_.c_str());
291 if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
292 // No EULA for given language - try en-US as default.
293 file_path = base::StringPrintf(chrome::kEULAPathFormat, "en-US");
294 if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
295 // File with EULA not found, ResponseOnUIThread will load EULA from
296 // resources if contents_ is empty.
297 contents_.clear();
300 BrowserThread::PostTask(
301 BrowserThread::UI, FROM_HERE,
302 base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
305 void ResponseOnUIThread() {
306 DCHECK_CURRENTLY_ON(BrowserThread::UI);
307 // If we fail to load Chrome OS EULA from disk, load it from resources.
308 // Do nothing if OEM EULA load failed.
309 if (contents_.empty() && path_ != chrome::kOemEulaURLPath)
310 contents_ = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
311 callback_.Run(base::RefCountedString::TakeString(&contents_));
314 // Path in the URL.
315 const std::string path_;
317 // Callback to run with the response.
318 content::URLDataSource::GotDataCallback callback_;
320 // Locale of the EULA.
321 const std::string locale_;
323 // EULA contents that was loaded from file.
324 std::string contents_;
326 DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsHandler);
329 class ChromeOSCreditsHandler
330 : public base::RefCountedThreadSafe<ChromeOSCreditsHandler> {
331 public:
332 static void Start(const std::string& path,
333 const content::URLDataSource::GotDataCallback& callback) {
334 scoped_refptr<ChromeOSCreditsHandler> handler(
335 new ChromeOSCreditsHandler(path, callback));
336 handler->StartOnUIThread();
339 private:
340 friend class base::RefCountedThreadSafe<ChromeOSCreditsHandler>;
342 ChromeOSCreditsHandler(
343 const std::string& path,
344 const content::URLDataSource::GotDataCallback& callback)
345 : path_(path), callback_(callback) {}
347 virtual ~ChromeOSCreditsHandler() {}
349 void StartOnUIThread() {
350 DCHECK_CURRENTLY_ON(BrowserThread::UI);
351 if (path_ == kKeyboardUtilsPath) {
352 contents_ = ResourceBundle::GetSharedInstance()
353 .GetRawDataResource(IDR_KEYBOARD_UTILS_JS)
354 .as_string();
355 ResponseOnUIThread();
356 return;
358 // Load local Chrome OS credits from the disk.
359 BrowserThread::PostBlockingPoolTaskAndReply(
360 FROM_HERE,
361 base::Bind(&ChromeOSCreditsHandler::LoadCreditsFileOnBlockingPool,
362 this),
363 base::Bind(&ChromeOSCreditsHandler::ResponseOnUIThread, this));
366 void LoadCreditsFileOnBlockingPool() {
367 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
368 base::FilePath credits_file_path(chrome::kChromeOSCreditsPath);
369 if (!base::ReadFileToString(credits_file_path, &contents_)) {
370 // File with credits not found, ResponseOnUIThread will load credits
371 // from resources if contents_ is empty.
372 contents_.clear();
376 void ResponseOnUIThread() {
377 DCHECK_CURRENTLY_ON(BrowserThread::UI);
378 // If we fail to load Chrome OS credits from disk, load it from resources.
379 if (contents_.empty() && path_ != kKeyboardUtilsPath) {
380 contents_ = ResourceBundle::GetSharedInstance()
381 .GetRawDataResource(IDR_OS_CREDITS_HTML)
382 .as_string();
384 callback_.Run(base::RefCountedString::TakeString(&contents_));
387 // Path in the URL.
388 const std::string path_;
390 // Callback to run with the response.
391 content::URLDataSource::GotDataCallback callback_;
393 // Chrome OS credits contents that was loaded from file.
394 std::string contents_;
396 DISALLOW_COPY_AND_ASSIGN(ChromeOSCreditsHandler);
398 #endif
400 } // namespace
402 // Individual about handlers ---------------------------------------------------
404 namespace about_ui {
406 void AppendHeader(std::string* output, int refresh,
407 const std::string& unescaped_title) {
408 output->append("<!DOCTYPE HTML>\n<html>\n<head>\n");
409 if (!unescaped_title.empty()) {
410 output->append("<title>");
411 output->append(net::EscapeForHTML(unescaped_title));
412 output->append("</title>\n");
414 output->append("<meta charset='utf-8'>\n");
415 if (refresh > 0) {
416 output->append("<meta http-equiv='refresh' content='");
417 output->append(base::IntToString(refresh));
418 output->append("'/>\n");
422 void AppendBody(std::string *output) {
423 output->append("</head>\n<body>\n");
426 void AppendFooter(std::string *output) {
427 output->append("</body>\n</html>\n");
430 } // namespace about_ui
432 using about_ui::AppendHeader;
433 using about_ui::AppendBody;
434 using about_ui::AppendFooter;
436 namespace {
438 std::string ChromeURLs() {
439 std::string html;
440 AppendHeader(&html, 0, "Chrome URLs");
441 AppendBody(&html);
442 html += "<h2>List of Chrome URLs</h2>\n<ul>\n";
443 std::vector<std::string> hosts(
444 chrome::kChromeHostURLs,
445 chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs);
446 std::sort(hosts.begin(), hosts.end());
447 for (std::vector<std::string>::const_iterator i = hosts.begin();
448 i != hosts.end(); ++i)
449 html += "<li><a href='chrome://" + *i + "/'>chrome://" + *i + "</a></li>\n";
450 html += "</ul>\n<h2>For Debug</h2>\n"
451 "<p>The following pages are for debugging purposes only. Because they "
452 "crash or hang the renderer, they're not linked directly; you can type "
453 "them into the address bar if you need them.</p>\n<ul>";
454 for (int i = 0; i < chrome::kNumberOfChromeDebugURLs; i++)
455 html += "<li>" + std::string(chrome::kChromeDebugURLs[i]) + "</li>\n";
456 html += "</ul>\n";
457 AppendFooter(&html);
458 return html;
461 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
463 const char kAboutDiscardsRunCommand[] = "run";
465 // Html output helper functions
467 // Helper function to wrap HTML with a tag.
468 std::string WrapWithTag(const std::string& tag, const std::string& text) {
469 return "<" + tag + ">" + text + "</" + tag + ">";
472 // Helper function to wrap Html with <td> tag.
473 std::string WrapWithTD(const std::string& text) {
474 return "<td>" + text + "</td>";
477 // Helper function to wrap Html with <tr> tag.
478 std::string WrapWithTR(const std::string& text) {
479 return "<tr>" + text + "</tr>";
482 std::string AddStringRow(const std::string& name, const std::string& value) {
483 std::string row;
484 row.append(WrapWithTD(name));
485 row.append(WrapWithTD(value));
486 return WrapWithTR(row);
489 void AddContentSecurityPolicy(std::string* output) {
490 output->append("<meta http-equiv='Content-Security-Policy' "
491 "content='default-src 'none';'>");
494 // TODO(stevenjb): L10N AboutDiscards.
496 std::string BuildAboutDiscardsRunPage() {
497 std::string output;
498 AppendHeader(&output, 0, "About discards");
499 output.append(base::StringPrintf("<meta http-equiv='refresh' content='2;%s'>",
500 chrome::kChromeUIDiscardsURL));
501 AddContentSecurityPolicy(&output);
502 output.append(WrapWithTag("p", "Discarding a tab..."));
503 AppendFooter(&output);
504 return output;
507 std::vector<std::string> GetHtmlTabDescriptorsForDiscardPage() {
508 memory::OomPriorityManager* oom = g_browser_process->GetOomPriorityManager();
509 memory::TabStatsList stats = oom->GetTabStats();
510 std::vector<std::string> titles;
511 titles.reserve(stats.size());
512 for (memory::TabStatsList::iterator it = stats.begin(); it != stats.end();
513 ++it) {
514 std::string str;
515 str.reserve(4096);
516 str += "<b>";
517 str += it->is_app ? "[App] " : "";
518 str += it->is_internal_page ? "[Internal] " : "";
519 str += it->is_playing_audio ? "[Audio] " : "";
520 str += it->is_pinned ? "[Pinned] " : "";
521 str += it->is_discarded ? "[Discarded] " : "";
522 str += "</b>";
523 str += net::EscapeForHTML(base::UTF16ToUTF8(it->title));
524 #if defined(OS_CHROMEOS)
525 str += base::StringPrintf(" (%d) ", it->oom_score);
526 #endif
527 if (!it->is_discarded) {
528 str += base::StringPrintf(" <a href='%s%s/%" PRId64 "'>Discard</a>",
529 chrome::kChromeUIDiscardsURL,
530 kAboutDiscardsRunCommand, it->tab_contents_id);
532 str += base::StringPrintf("&nbsp;&nbsp;(%d discards this session)",
533 it->discard_count);
534 titles.push_back(str);
536 return titles;
539 std::string AboutDiscards(const std::string& path) {
540 std::string output;
541 int64 web_content_id;
542 memory::OomPriorityManager* oom = g_browser_process->GetOomPriorityManager();
544 std::vector<std::string> path_split = base::SplitString(
545 path, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
546 if (path_split.size() == 2 && path_split[0] == kAboutDiscardsRunCommand &&
547 base::StringToInt64(path_split[1], &web_content_id)) {
548 oom->DiscardTabById(web_content_id);
549 return BuildAboutDiscardsRunPage();
550 } else if (path_split.size() == 1 &&
551 path_split[0] == kAboutDiscardsRunCommand) {
552 oom->DiscardTab();
553 return BuildAboutDiscardsRunPage();
556 AppendHeader(&output, 0, "About discards");
557 AddContentSecurityPolicy(&output);
558 AppendBody(&output);
559 output.append("<h3>Discarded Tabs</h3>");
560 output.append(
561 "<p>Tabs sorted from most interesting to least interesting. The least "
562 "interesting tab may be discarded if we run out of physical memory.</p>");
564 std::vector<std::string> titles = GetHtmlTabDescriptorsForDiscardPage();
565 if (!titles.empty()) {
566 output.append("<ul>");
567 std::vector<std::string>::iterator it = titles.begin();
568 for ( ; it != titles.end(); ++it) {
569 output.append(WrapWithTag("li", *it));
571 output.append("</ul>");
572 } else {
573 output.append("<p>None found. Wait 10 seconds, then refresh.</p>");
575 output.append(
576 base::StringPrintf("%d discards this session. ", oom->discard_count()));
577 output.append(base::StringPrintf("<a href='%s%s'>Discard tab now</a>",
578 chrome::kChromeUIDiscardsURL,
579 kAboutDiscardsRunCommand));
581 base::SystemMemoryInfoKB meminfo;
582 base::GetSystemMemoryInfo(&meminfo);
583 output.append("<h3>System memory information in MB</h3>");
584 output.append("<table>");
585 // Start with summary statistics.
586 output.append(AddStringRow(
587 "Total", base::IntToString(meminfo.total / 1024)));
588 output.append(AddStringRow(
589 "Free", base::IntToString(meminfo.free / 1024)));
590 #if defined(OS_CHROMEOS)
591 int mem_allocated_kb = meminfo.active_anon + meminfo.inactive_anon;
592 #if defined(ARCH_CPU_ARM_FAMILY)
593 // ARM counts allocated graphics memory separately from anonymous.
594 if (meminfo.gem_size != -1)
595 mem_allocated_kb += meminfo.gem_size / 1024;
596 #endif
597 output.append(AddStringRow(
598 "Allocated", base::IntToString(mem_allocated_kb / 1024)));
599 // Add some space, then detailed numbers.
600 output.append(AddStringRow("&nbsp;", "&nbsp;"));
601 output.append(AddStringRow(
602 "Buffered", base::IntToString(meminfo.buffers / 1024)));
603 output.append(AddStringRow(
604 "Cached", base::IntToString(meminfo.cached / 1024)));
605 output.append(AddStringRow(
606 "Active Anon", base::IntToString(meminfo.active_anon / 1024)));
607 output.append(AddStringRow(
608 "Inactive Anon", base::IntToString(meminfo.inactive_anon / 1024)));
609 output.append(AddStringRow(
610 "Shared", base::IntToString(meminfo.shmem / 1024)));
611 output.append(AddStringRow(
612 "Graphics", base::IntToString(meminfo.gem_size / 1024 / 1024)));
613 #endif // OS_CHROMEOS
614 output.append("</table>");
615 AppendFooter(&output);
616 return output;
619 #endif // OS_WIN || OS_CHROMEOS
621 // AboutDnsHandler bounces the request back to the IO thread to collect
622 // the DNS information.
623 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
624 public:
625 static void Start(Profile* profile,
626 const content::URLDataSource::GotDataCallback& callback) {
627 scoped_refptr<AboutDnsHandler> handler(
628 new AboutDnsHandler(profile, callback));
629 handler->StartOnUIThread();
632 private:
633 friend class base::RefCountedThreadSafe<AboutDnsHandler>;
635 AboutDnsHandler(Profile* profile,
636 const content::URLDataSource::GotDataCallback& callback)
637 : profile_(profile),
638 callback_(callback) {
639 DCHECK_CURRENTLY_ON(BrowserThread::UI);
642 virtual ~AboutDnsHandler() {}
644 // Calls FinishOnUIThread() on completion.
645 void StartOnUIThread() {
646 DCHECK_CURRENTLY_ON(BrowserThread::UI);
647 chrome_browser_net::Predictor* predictor = profile_->GetNetworkPredictor();
648 BrowserThread::PostTask(
649 BrowserThread::IO, FROM_HERE,
650 base::Bind(&AboutDnsHandler::StartOnIOThread, this, predictor));
653 void StartOnIOThread(chrome_browser_net::Predictor* predictor) {
654 DCHECK_CURRENTLY_ON(BrowserThread::IO);
656 std::string data;
657 AppendHeader(&data, 0, "About DNS");
658 AppendBody(&data);
659 chrome_browser_net::Predictor::PredictorGetHtmlInfo(predictor, &data);
660 AppendFooter(&data);
662 BrowserThread::PostTask(
663 BrowserThread::UI, FROM_HERE,
664 base::Bind(&AboutDnsHandler::FinishOnUIThread, this, data));
667 void FinishOnUIThread(const std::string& data) {
668 DCHECK_CURRENTLY_ON(BrowserThread::UI);
669 std::string data_copy(data);
670 callback_.Run(base::RefCountedString::TakeString(&data_copy));
673 Profile* profile_;
675 // Callback to run with the response.
676 content::URLDataSource::GotDataCallback callback_;
678 DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler);
681 void FinishMemoryDataRequest(
682 const std::string& path,
683 const content::URLDataSource::GotDataCallback& callback) {
684 if (path == kStringsJsPath) {
685 // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want
686 // the refcount to be greater than 0.
687 scoped_refptr<AboutMemoryHandler> handler(new AboutMemoryHandler(callback));
688 handler->StartFetch(MemoryDetails::FROM_ALL_BROWSERS);
689 } else {
690 int id = IDR_ABOUT_MEMORY_HTML;
691 if (path == kMemoryJsPath) {
692 id = IDR_ABOUT_MEMORY_JS;
693 } else if (path == kMemoryCssPath) {
694 id = IDR_ABOUT_MEMORY_CSS;
697 std::string result =
698 ResourceBundle::GetSharedInstance().GetRawDataResource(id).as_string();
699 callback.Run(base::RefCountedString::TakeString(&result));
703 #if defined(OS_LINUX) || defined(OS_OPENBSD)
704 std::string AboutLinuxProxyConfig() {
705 std::string data;
706 AppendHeader(&data, 0,
707 l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE));
708 data.append("<style>body { max-width: 70ex; padding: 2ex 5ex; }</style>");
709 AppendBody(&data);
710 base::FilePath binary = base::CommandLine::ForCurrentProcess()->GetProgram();
711 data.append(l10n_util::GetStringFUTF8(
712 IDS_ABOUT_LINUX_PROXY_CONFIG_BODY,
713 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
714 base::ASCIIToUTF16(binary.BaseName().value())));
715 AppendFooter(&data);
716 return data;
719 void AboutSandboxRow(std::string* data, int name_id, bool good) {
720 data->append("<tr><td>");
721 data->append(l10n_util::GetStringUTF8(name_id));
722 if (good) {
723 data->append("</td><td style='color: green;'>");
724 data->append(
725 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
726 } else {
727 data->append("</td><td style='color: red;'>");
728 data->append(
729 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
731 data->append("</td></tr>");
734 std::string AboutSandbox() {
735 std::string data;
736 AppendHeader(&data, 0, l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
737 AppendBody(&data);
738 data.append("<h1>");
739 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
740 data.append("</h1>");
742 // Get expected sandboxing status of renderers.
743 const int status = content::ZygoteHost::GetInstance()->GetSandboxStatus();
745 data.append("<table>");
747 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SUID_SANDBOX,
748 status & content::kSandboxLinuxSUID);
749 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_NAMESPACE_SANDBOX,
750 status & content::kSandboxLinuxUserNS);
751 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_PID_NAMESPACES,
752 status & content::kSandboxLinuxPIDNS);
753 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_NET_NAMESPACES,
754 status & content::kSandboxLinuxNetNS);
755 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX,
756 status & content::kSandboxLinuxSeccompBPF);
757 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX_TSYNC,
758 status & content::kSandboxLinuxSeccompTSYNC);
759 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_YAMA_LSM,
760 status & content::kSandboxLinuxYama);
762 data.append("</table>");
764 // Require either the setuid or namespace sandbox for our first-layer sandbox.
765 bool good_layer1 = (status & content::kSandboxLinuxSUID ||
766 status & content::kSandboxLinuxUserNS) &&
767 status & content::kSandboxLinuxPIDNS &&
768 status & content::kSandboxLinuxNetNS;
769 // A second-layer sandbox is also required to be adequately sandboxed.
770 bool good_layer2 = status & content::kSandboxLinuxSeccompBPF;
771 bool good = good_layer1 && good_layer2;
773 if (good) {
774 data.append("<p style='color: green'>");
775 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK));
776 } else {
777 data.append("<p style='color: red'>");
778 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD));
780 data.append("</p>");
782 AppendFooter(&data);
783 return data;
785 #endif
787 // AboutMemoryHandler ----------------------------------------------------------
789 // Helper for AboutMemory to bind results from a ProcessMetrics object
790 // to a DictionaryValue. Fills ws_usage and comm_usage so that the objects
791 // can be used in caller's scope (e.g for appending to a net total).
792 void AboutMemoryHandler::BindProcessMetrics(base::DictionaryValue* data,
793 ProcessMemoryInformation* info) {
794 DCHECK(data && info);
796 // Bind metrics to dictionary.
797 data->SetInteger("ws_priv", static_cast<int>(info->working_set.priv));
798 data->SetInteger("ws_shareable",
799 static_cast<int>(info->working_set.shareable));
800 data->SetInteger("ws_shared", static_cast<int>(info->working_set.shared));
801 data->SetInteger("comm_priv", static_cast<int>(info->committed.priv));
802 data->SetInteger("comm_map", static_cast<int>(info->committed.mapped));
803 data->SetInteger("comm_image", static_cast<int>(info->committed.image));
804 data->SetInteger("pid", info->pid);
805 data->SetString("version", info->version);
806 data->SetInteger("processes", info->num_processes);
809 // Helper for AboutMemory to append memory usage information for all
810 // sub-processes (i.e. renderers, plugins) used by Chrome.
811 void AboutMemoryHandler::AppendProcess(base::ListValue* child_data,
812 ProcessMemoryInformation* info) {
813 DCHECK(child_data && info);
815 // Append a new DictionaryValue for this renderer to our list.
816 base::DictionaryValue* child = new base::DictionaryValue();
817 child_data->Append(child);
818 BindProcessMetrics(child, info);
820 std::string child_label(
821 ProcessMemoryInformation::GetFullTypeNameInEnglish(info->process_type,
822 info->renderer_type));
823 if (info->is_diagnostics)
824 child_label.append(" (diagnostics)");
825 child->SetString("child_name", child_label);
826 base::ListValue* titles = new base::ListValue();
827 child->Set("titles", titles);
828 for (size_t i = 0; i < info->titles.size(); ++i)
829 titles->Append(new base::StringValue(info->titles[i]));
832 void AboutMemoryHandler::OnDetailsAvailable() {
833 // the root of the JSON hierarchy for about:memory jstemplate
834 scoped_ptr<base::DictionaryValue> root(new base::DictionaryValue);
835 base::ListValue* browsers = new base::ListValue();
836 root->Set("browsers", browsers);
838 const std::vector<ProcessData>& browser_processes = processes();
840 // Aggregate per-process data into browser summary data.
841 base::string16 log_string;
842 for (size_t index = 0; index < browser_processes.size(); index++) {
843 if (browser_processes[index].processes.empty())
844 continue;
846 // Sum the information for the processes within this browser.
847 ProcessMemoryInformation aggregate;
848 ProcessMemoryInformationList::const_iterator iterator;
849 iterator = browser_processes[index].processes.begin();
850 aggregate.pid = iterator->pid;
851 aggregate.version = iterator->version;
852 while (iterator != browser_processes[index].processes.end()) {
853 if (!iterator->is_diagnostics ||
854 browser_processes[index].processes.size() == 1) {
855 aggregate.working_set.priv += iterator->working_set.priv;
856 aggregate.working_set.shared += iterator->working_set.shared;
857 aggregate.working_set.shareable += iterator->working_set.shareable;
858 aggregate.committed.priv += iterator->committed.priv;
859 aggregate.committed.mapped += iterator->committed.mapped;
860 aggregate.committed.image += iterator->committed.image;
861 aggregate.num_processes++;
863 ++iterator;
865 base::DictionaryValue* browser_data = new base::DictionaryValue();
866 browsers->Append(browser_data);
867 browser_data->SetString("name", browser_processes[index].name);
869 BindProcessMetrics(browser_data, &aggregate);
871 // We log memory info as we record it.
872 if (!log_string.empty())
873 log_string += base::ASCIIToUTF16(", ");
874 log_string += browser_processes[index].name + base::ASCIIToUTF16(", ") +
875 base::SizeTToString16(aggregate.working_set.priv) +
876 base::ASCIIToUTF16(", ") +
877 base::SizeTToString16(aggregate.working_set.shared) +
878 base::ASCIIToUTF16(", ") +
879 base::SizeTToString16(aggregate.working_set.shareable);
881 if (!log_string.empty())
882 VLOG(1) << "memory: " << log_string;
884 // Set the browser & renderer detailed process data.
885 base::DictionaryValue* browser_data = new base::DictionaryValue();
886 root->Set("browzr_data", browser_data);
887 base::ListValue* child_data = new base::ListValue();
888 root->Set("child_data", child_data);
890 ProcessData process = browser_processes[0]; // Chrome is the first browser.
891 root->SetString("current_browser_name", process.name);
893 for (size_t index = 0; index < process.processes.size(); index++) {
894 if (process.processes[index].process_type == content::PROCESS_TYPE_BROWSER)
895 BindProcessMetrics(browser_data, &process.processes[index]);
896 else
897 AppendProcess(child_data, &process.processes[index]);
900 root->SetBoolean("show_other_browsers",
901 browser_defaults::kShowOtherBrowsersInAboutMemory);
903 base::DictionaryValue load_time_data;
904 load_time_data.SetString(
905 "summary_desc",
906 l10n_util::GetStringUTF16(IDS_MEMORY_USAGE_SUMMARY_DESC));
907 const std::string& app_locale = g_browser_process->GetApplicationLocale();
908 webui::SetLoadTimeDataDefaults(app_locale, &load_time_data);
909 load_time_data.Set("jstemplateData", root.release());
911 std::string data;
912 webui::AppendJsonJS(&load_time_data, &data);
913 callback_.Run(base::RefCountedString::TakeString(&data));
916 } // namespace
918 // AboutUIHTMLSource ----------------------------------------------------------
920 AboutUIHTMLSource::AboutUIHTMLSource(const std::string& source_name,
921 Profile* profile)
922 : source_name_(source_name),
923 profile_(profile) {}
925 AboutUIHTMLSource::~AboutUIHTMLSource() {}
927 std::string AboutUIHTMLSource::GetSource() const {
928 return source_name_;
931 void AboutUIHTMLSource::StartDataRequest(
932 const std::string& path,
933 int render_process_id,
934 int render_frame_id,
935 const content::URLDataSource::GotDataCallback& callback) {
936 std::string response;
937 // Add your data source here, in alphabetical order.
938 if (source_name_ == chrome::kChromeUIChromeURLsHost) {
939 response = ChromeURLs();
940 } else if (source_name_ == chrome::kChromeUICreditsHost) {
941 int idr = IDR_CREDITS_HTML;
942 if (path == kCreditsJsPath)
943 idr = IDR_CREDITS_JS;
944 #if defined(OS_CHROMEOS)
945 else if (path == kKeyboardUtilsPath)
946 idr = IDR_KEYBOARD_UTILS_JS;
947 #endif
949 response = ResourceBundle::GetSharedInstance().GetRawDataResource(
950 idr).as_string();
951 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
952 } else if (source_name_ == chrome::kChromeUIDiscardsHost) {
953 response = AboutDiscards(path);
954 #endif
955 } else if (source_name_ == chrome::kChromeUIDNSHost) {
956 AboutDnsHandler::Start(profile(), callback);
957 return;
958 #if defined(OS_LINUX) || defined(OS_OPENBSD)
959 } else if (source_name_ == chrome::kChromeUILinuxProxyConfigHost) {
960 response = AboutLinuxProxyConfig();
961 #endif
962 } else if (source_name_ == chrome::kChromeUIMemoryHost) {
963 response = GetAboutMemoryRedirectResponse(profile());
964 } else if (source_name_ == chrome::kChromeUIMemoryRedirectHost) {
965 FinishMemoryDataRequest(path, callback);
966 return;
967 #if defined(OS_CHROMEOS)
968 } else if (source_name_ == chrome::kChromeUIOSCreditsHost) {
969 ChromeOSCreditsHandler::Start(path, callback);
970 return;
971 #endif
972 #if defined(OS_LINUX) || defined(OS_OPENBSD)
973 } else if (source_name_ == chrome::kChromeUISandboxHost) {
974 response = AboutSandbox();
975 #endif
976 #if !defined(OS_ANDROID)
977 } else if (source_name_ == chrome::kChromeUITermsHost) {
978 #if defined(OS_CHROMEOS)
979 ChromeOSTermsHandler::Start(path, callback);
980 return;
981 #else
982 response = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
983 #endif
984 #endif
987 FinishDataRequest(response, callback);
990 void AboutUIHTMLSource::FinishDataRequest(
991 const std::string& html,
992 const content::URLDataSource::GotDataCallback& callback) {
993 std::string html_copy(html);
994 callback.Run(base::RefCountedString::TakeString(&html_copy));
997 std::string AboutUIHTMLSource::GetMimeType(const std::string& path) const {
998 if (path == kCreditsJsPath ||
999 #if defined(OS_CHROMEOS)
1000 path == kKeyboardUtilsPath ||
1001 #endif
1002 path == kStatsJsPath ||
1003 path == kStringsJsPath ||
1004 path == kMemoryJsPath) {
1005 return "application/javascript";
1007 return "text/html";
1010 bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() const {
1011 #if defined(OS_CHROMEOS)
1012 if (source_name_ == chrome::kChromeUIOSCreditsHost)
1013 return false;
1014 #endif
1015 return content::URLDataSource::ShouldAddContentSecurityPolicy();
1018 bool AboutUIHTMLSource::ShouldDenyXFrameOptions() const {
1019 #if defined(OS_CHROMEOS)
1020 if (source_name_ == chrome::kChromeUITermsHost) {
1021 // chrome://terms page is embedded in iframe to chrome://oobe.
1022 return false;
1024 #endif
1025 return content::URLDataSource::ShouldDenyXFrameOptions();
1028 AboutUI::AboutUI(content::WebUI* web_ui, const std::string& name)
1029 : WebUIController(web_ui) {
1030 Profile* profile = Profile::FromWebUI(web_ui);
1032 #if defined(ENABLE_THEMES)
1033 // Set up the chrome://theme/ source.
1034 ThemeSource* theme = new ThemeSource(profile);
1035 content::URLDataSource::Add(profile, theme);
1036 #endif
1038 content::URLDataSource::Add(profile, new AboutUIHTMLSource(name, profile));