ProfilePolicyConnectorFactory: Refactoring from Profile to BrowserContext.
[chromium-blink-merge.git] / chrome / browser / ui / webui / about_ui.cc
blob2e9eb6f49b4c4bc4cc4c366414e4afe97b176194
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/i18n/number_formatting.h"
18 #include "base/json/json_writer.h"
19 #include "base/memory/singleton.h"
20 #include "base/metrics/statistics_recorder.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_piece.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/threading/thread.h"
27 #include "base/values.h"
28 #include "chrome/browser/about_flags.h"
29 #include "chrome/browser/browser_process.h"
30 #include "chrome/browser/defaults.h"
31 #include "chrome/browser/memory_details.h"
32 #include "chrome/browser/net/predictor.h"
33 #include "chrome/browser/profiles/profile.h"
34 #include "chrome/browser/profiles/profile_manager.h"
35 #include "chrome/browser/ui/browser_dialogs.h"
36 #include "chrome/common/chrome_paths.h"
37 #include "chrome/common/render_messages.h"
38 #include "chrome/common/url_constants.h"
39 #include "chrome/grit/chromium_strings.h"
40 #include "chrome/grit/generated_resources.h"
41 #include "chrome/grit/locale_settings.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "content/public/browser/render_process_host.h"
44 #include "content/public/browser/render_view_host.h"
45 #include "content/public/browser/url_data_source.h"
46 #include "content/public/browser/web_contents.h"
47 #include "content/public/common/content_client.h"
48 #include "content/public/common/process_type.h"
49 #include "google_apis/gaia/google_service_auth_error.h"
50 #include "grit/browser_resources.h"
51 #include "net/base/escape.h"
52 #include "net/base/filename_util.h"
53 #include "net/base/load_flags.h"
54 #include "net/http/http_response_headers.h"
55 #include "net/url_request/url_fetcher.h"
56 #include "net/url_request/url_request_status.h"
57 #include "ui/base/l10n/l10n_util.h"
58 #include "ui/base/resource/resource_bundle.h"
59 #include "ui/base/webui/jstemplate_builder.h"
60 #include "ui/base/webui/web_ui_util.h"
61 #include "url/gurl.h"
63 #if defined(ENABLE_THEMES)
64 #include "chrome/browser/ui/webui/theme_source.h"
65 #endif
67 #if defined(OS_LINUX) || defined(OS_OPENBSD)
68 #include "content/public/browser/zygote_host_linux.h"
69 #include "content/public/common/sandbox_linux.h"
70 #endif
72 #if defined(OS_WIN)
73 #include "chrome/browser/enumerate_modules_model_win.h"
74 #endif
76 #if defined(OS_CHROMEOS)
77 #include "chrome/browser/browser_process_platform_part_chromeos.h"
78 #include "chrome/browser/chromeos/customization/customization_document.h"
79 #include "chrome/browser/chromeos/memory/oom_priority_manager.h"
80 #endif
82 using base::Time;
83 using base::TimeDelta;
84 using content::BrowserThread;
85 using content::WebContents;
87 namespace {
89 const char kCreditsJsPath[] = "credits.js";
90 const char kMemoryJsPath[] = "memory.js";
91 const char kMemoryCssPath[] = "about_memory.css";
92 const char kStatsJsPath[] = "stats.js";
93 const char kStringsJsPath[] = "strings.js";
95 // When you type about:memory, it actually loads this intermediate URL that
96 // redirects you to the final page. This avoids the problem where typing
97 // "about:memory" on the new tab page or any other page where a process
98 // transition would occur to the about URL will cause some confusion.
100 // The problem is that during the processing of the memory page, there are two
101 // processes active, the original and the destination one. This can create the
102 // impression that we're using more resources than we actually are. This
103 // redirect solves the problem by eliminating the process transition during the
104 // time that about memory is being computed.
105 std::string GetAboutMemoryRedirectResponse(Profile* profile) {
106 return base::StringPrintf("<meta http-equiv='refresh' content='0;%s'>",
107 chrome::kChromeUIMemoryRedirectURL);
110 // Handling about:memory is complicated enough to encapsulate its related
111 // methods into a single class. The user should create it (on the heap) and call
112 // its |StartFetch()| method.
113 class AboutMemoryHandler : public MemoryDetails {
114 public:
115 explicit AboutMemoryHandler(
116 const content::URLDataSource::GotDataCallback& callback)
117 : callback_(callback) {
120 void OnDetailsAvailable() override;
122 private:
123 ~AboutMemoryHandler() override {}
125 void BindProcessMetrics(base::DictionaryValue* data,
126 ProcessMemoryInformation* info);
127 void AppendProcess(base::ListValue* child_data,
128 ProcessMemoryInformation* info);
130 content::URLDataSource::GotDataCallback callback_;
132 DISALLOW_COPY_AND_ASSIGN(AboutMemoryHandler);
135 #if defined(OS_CHROMEOS)
137 const char kKeyboardUtilsPath[] = "keyboard_utils.js";
139 // chrome://terms falls back to offline page after kOnlineTermsTimeoutSec.
140 const int kOnlineTermsTimeoutSec = 7;
142 // Helper class that fetches the online Chrome OS terms. Empty string is
143 // returned once fetching failed or exceeded |kOnlineTermsTimeoutSec|.
144 class ChromeOSOnlineTermsHandler : public net::URLFetcherDelegate {
145 public:
146 typedef base::Callback<void (ChromeOSOnlineTermsHandler*)> FetchCallback;
148 explicit ChromeOSOnlineTermsHandler(const FetchCallback& callback,
149 const std::string& locale)
150 : fetch_callback_(callback) {
151 std::string eula_URL = base::StringPrintf(chrome::kOnlineEulaURLPath,
152 locale.c_str());
153 eula_fetcher_.reset(net::URLFetcher::Create(0 /* ID used for testing */,
154 GURL(eula_URL),
155 net::URLFetcher::GET,
156 this));
157 eula_fetcher_->SetRequestContext(
158 g_browser_process->system_request_context());
159 eula_fetcher_->AddExtraRequestHeader("Accept: text/html");
160 eula_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
161 net::LOAD_DO_NOT_SAVE_COOKIES |
162 net::LOAD_DISABLE_CACHE);
163 eula_fetcher_->Start();
164 // Abort the download attempt if it takes longer than one minute.
165 download_timer_.Start(FROM_HERE,
166 base::TimeDelta::FromSeconds(kOnlineTermsTimeoutSec),
167 this,
168 &ChromeOSOnlineTermsHandler::OnDownloadTimeout);
171 void GetResponseResult(std::string* response_string) {
172 std::string mime_type;
173 if (!eula_fetcher_ ||
174 !eula_fetcher_->GetStatus().is_success() ||
175 eula_fetcher_->GetResponseCode() != 200 ||
176 !eula_fetcher_->GetResponseHeaders()->GetMimeType(&mime_type) ||
177 mime_type != "text/html" ||
178 !eula_fetcher_->GetResponseAsString(response_string)) {
179 response_string->clear();
183 private:
184 // Prevents allocation on the stack. ChromeOSOnlineTermsHandler should be
185 // created by 'operator new'. |this| takes care of destruction.
186 ~ChromeOSOnlineTermsHandler() override {}
188 // net::URLFetcherDelegate:
189 void OnURLFetchComplete(const net::URLFetcher* source) override {
190 if (source != eula_fetcher_.get()) {
191 NOTREACHED() << "Callback from foreign URL fetcher";
192 return;
194 fetch_callback_.Run(this);
195 delete this;
198 void OnDownloadTimeout() {
199 eula_fetcher_.reset();
200 fetch_callback_.Run(this);
201 delete this;
204 // Timer that enforces a timeout on the attempt to download the
205 // ChromeOS Terms.
206 base::OneShotTimer<ChromeOSOnlineTermsHandler> download_timer_;
208 // |fetch_callback_| called when fetching succeeded or failed.
209 FetchCallback fetch_callback_;
211 // Helper to fetch online eula.
212 scoped_ptr<net::URLFetcher> eula_fetcher_;
214 DISALLOW_COPY_AND_ASSIGN(ChromeOSOnlineTermsHandler);
217 class ChromeOSTermsHandler
218 : public base::RefCountedThreadSafe<ChromeOSTermsHandler> {
219 public:
220 static void Start(const std::string& path,
221 const content::URLDataSource::GotDataCallback& callback) {
222 scoped_refptr<ChromeOSTermsHandler> handler(
223 new ChromeOSTermsHandler(path, callback));
224 handler->StartOnUIThread();
227 private:
228 friend class base::RefCountedThreadSafe<ChromeOSTermsHandler>;
230 ChromeOSTermsHandler(const std::string& path,
231 const content::URLDataSource::GotDataCallback& callback)
232 : path_(path),
233 callback_(callback),
234 // Previously we were using "initial locale" http://crbug.com/145142
235 locale_(g_browser_process->GetApplicationLocale()) {
238 virtual ~ChromeOSTermsHandler() {}
240 void StartOnUIThread() {
241 DCHECK_CURRENTLY_ON(BrowserThread::UI);
242 if (path_ == chrome::kOemEulaURLPath) {
243 // Load local OEM EULA from the disk.
244 BrowserThread::PostTask(
245 BrowserThread::FILE, FROM_HERE,
246 base::Bind(&ChromeOSTermsHandler::LoadOemEulaFileOnFileThread, this));
247 } else {
248 // Try to load online version of ChromeOS terms first.
249 // ChromeOSOnlineTermsHandler object destroys itself.
250 new ChromeOSOnlineTermsHandler(
251 base::Bind(&ChromeOSTermsHandler::OnOnlineEULAFetched, this),
252 locale_);
256 void OnOnlineEULAFetched(ChromeOSOnlineTermsHandler* loader) {
257 DCHECK_CURRENTLY_ON(BrowserThread::UI);
258 loader->GetResponseResult(&contents_);
259 if (contents_.empty()) {
260 // Load local ChromeOS terms from the file.
261 BrowserThread::PostTask(
262 BrowserThread::FILE, FROM_HERE,
263 base::Bind(&ChromeOSTermsHandler::LoadEulaFileOnFileThread, this));
264 } else {
265 ResponseOnUIThread();
269 void LoadOemEulaFileOnFileThread() {
270 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
271 const chromeos::StartupCustomizationDocument* customization =
272 chromeos::StartupCustomizationDocument::GetInstance();
273 if (customization->IsReady()) {
274 base::FilePath oem_eula_file_path;
275 if (net::FileURLToFilePath(GURL(customization->GetEULAPage(locale_)),
276 &oem_eula_file_path)) {
277 if (!base::ReadFileToString(oem_eula_file_path, &contents_)) {
278 contents_.clear();
282 BrowserThread::PostTask(
283 BrowserThread::UI, FROM_HERE,
284 base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
287 void LoadEulaFileOnFileThread() {
288 std::string file_path =
289 base::StringPrintf(chrome::kEULAPathFormat, locale_.c_str());
290 if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
291 // No EULA for given language - try en-US as default.
292 file_path = base::StringPrintf(chrome::kEULAPathFormat, "en-US");
293 if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
294 // File with EULA not found, ResponseOnUIThread will load EULA from
295 // resources if contents_ is empty.
296 contents_.clear();
299 BrowserThread::PostTask(
300 BrowserThread::UI, FROM_HERE,
301 base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
304 void ResponseOnUIThread() {
305 DCHECK_CURRENTLY_ON(BrowserThread::UI);
306 // If we fail to load Chrome OS EULA from disk, load it from resources.
307 // Do nothing if OEM EULA load failed.
308 if (contents_.empty() && path_ != chrome::kOemEulaURLPath)
309 contents_ = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
310 callback_.Run(base::RefCountedString::TakeString(&contents_));
313 // Path in the URL.
314 const std::string path_;
316 // Callback to run with the response.
317 content::URLDataSource::GotDataCallback callback_;
319 // Locale of the EULA.
320 const std::string locale_;
322 // EULA contents that was loaded from file.
323 std::string contents_;
325 DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsHandler);
328 class ChromeOSCreditsHandler
329 : public base::RefCountedThreadSafe<ChromeOSCreditsHandler> {
330 public:
331 static void Start(const std::string& path,
332 const content::URLDataSource::GotDataCallback& callback) {
333 scoped_refptr<ChromeOSCreditsHandler> handler(
334 new ChromeOSCreditsHandler(path, callback));
335 handler->StartOnUIThread();
338 private:
339 friend class base::RefCountedThreadSafe<ChromeOSCreditsHandler>;
341 ChromeOSCreditsHandler(
342 const std::string& path,
343 const content::URLDataSource::GotDataCallback& callback)
344 : path_(path), callback_(callback) {}
346 virtual ~ChromeOSCreditsHandler() {}
348 void StartOnUIThread() {
349 DCHECK_CURRENTLY_ON(BrowserThread::UI);
350 if (path_ == kKeyboardUtilsPath) {
351 contents_ = ResourceBundle::GetSharedInstance()
352 .GetRawDataResource(IDR_KEYBOARD_UTILS_JS)
353 .as_string();
354 ResponseOnUIThread();
355 return;
357 // Load local Chrome OS credits from the disk.
358 BrowserThread::PostBlockingPoolTaskAndReply(
359 FROM_HERE,
360 base::Bind(&ChromeOSCreditsHandler::LoadCreditsFileOnBlockingPool,
361 this),
362 base::Bind(&ChromeOSCreditsHandler::ResponseOnUIThread, this));
365 void LoadCreditsFileOnBlockingPool() {
366 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
367 base::FilePath credits_file_path(chrome::kChromeOSCreditsPath);
368 if (!base::ReadFileToString(credits_file_path, &contents_)) {
369 // File with credits not found, ResponseOnUIThread will load credits
370 // from resources if contents_ is empty.
371 contents_.clear();
375 void ResponseOnUIThread() {
376 DCHECK_CURRENTLY_ON(BrowserThread::UI);
377 // If we fail to load Chrome OS credits from disk, load it from resources.
378 if (contents_.empty() && path_ != kKeyboardUtilsPath) {
379 contents_ = ResourceBundle::GetSharedInstance()
380 .GetRawDataResource(IDR_OS_CREDITS_HTML)
381 .as_string();
383 callback_.Run(base::RefCountedString::TakeString(&contents_));
386 // Path in the URL.
387 const std::string path_;
389 // Callback to run with the response.
390 content::URLDataSource::GotDataCallback callback_;
392 // Chrome OS credits contents that was loaded from file.
393 std::string contents_;
395 DISALLOW_COPY_AND_ASSIGN(ChromeOSCreditsHandler);
397 #endif
399 } // namespace
401 // Individual about handlers ---------------------------------------------------
403 namespace about_ui {
405 void AppendHeader(std::string* output, int refresh,
406 const std::string& unescaped_title) {
407 output->append("<!DOCTYPE HTML>\n<html>\n<head>\n");
408 if (!unescaped_title.empty()) {
409 output->append("<title>");
410 output->append(net::EscapeForHTML(unescaped_title));
411 output->append("</title>\n");
413 output->append("<meta charset='utf-8'>\n");
414 if (refresh > 0) {
415 output->append("<meta http-equiv='refresh' content='");
416 output->append(base::IntToString(refresh));
417 output->append("'/>\n");
421 void AppendBody(std::string *output) {
422 output->append("</head>\n<body>\n");
425 void AppendFooter(std::string *output) {
426 output->append("</body>\n</html>\n");
429 } // namespace about_ui
431 using about_ui::AppendHeader;
432 using about_ui::AppendBody;
433 using about_ui::AppendFooter;
435 namespace {
437 std::string ChromeURLs() {
438 std::string html;
439 AppendHeader(&html, 0, "Chrome URLs");
440 AppendBody(&html);
441 html += "<h2>List of Chrome URLs</h2>\n<ul>\n";
442 std::vector<std::string> hosts(
443 chrome::kChromeHostURLs,
444 chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs);
445 std::sort(hosts.begin(), hosts.end());
446 for (std::vector<std::string>::const_iterator i = hosts.begin();
447 i != hosts.end(); ++i)
448 html += "<li><a href='chrome://" + *i + "/'>chrome://" + *i + "</a></li>\n";
449 html += "</ul>\n<h2>For Debug</h2>\n"
450 "<p>The following pages are for debugging purposes only. Because they "
451 "crash or hang the renderer, they're not linked directly; you can type "
452 "them into the address bar if you need them.</p>\n<ul>";
453 for (int i = 0; i < chrome::kNumberOfChromeDebugURLs; i++)
454 html += "<li>" + std::string(chrome::kChromeDebugURLs[i]) + "</li>\n";
455 html += "</ul>\n";
456 AppendFooter(&html);
457 return html;
460 #if defined(OS_CHROMEOS)
462 // Html output helper functions
464 // Helper function to wrap HTML with a tag.
465 std::string WrapWithTag(const std::string& tag, const std::string& text) {
466 return "<" + tag + ">" + text + "</" + tag + ">";
469 // Helper function to wrap Html with <td> tag.
470 std::string WrapWithTD(const std::string& text) {
471 return "<td>" + text + "</td>";
474 // Helper function to wrap Html with <tr> tag.
475 std::string WrapWithTR(const std::string& text) {
476 return "<tr>" + text + "</tr>";
479 std::string AddStringRow(const std::string& name, const std::string& value) {
480 std::string row;
481 row.append(WrapWithTD(name));
482 row.append(WrapWithTD(value));
483 return WrapWithTR(row);
486 void AddContentSecurityPolicy(std::string* output) {
487 output->append("<meta http-equiv='Content-Security-Policy' "
488 "content='default-src 'none';'>");
491 // TODO(stevenjb): L10N AboutDiscards.
493 std::string AboutDiscardsRun() {
494 std::string output;
495 AppendHeader(&output, 0, "About discards");
496 output.append(
497 base::StringPrintf("<meta http-equiv='refresh' content='2;%s'>",
498 chrome::kChromeUIDiscardsURL));
499 AddContentSecurityPolicy(&output);
500 output.append(WrapWithTag("p", "Discarding a tab..."));
501 g_browser_process->platform_part()->
502 oom_priority_manager()->LogMemoryAndDiscardTab();
503 AppendFooter(&output);
504 return output;
507 std::string AboutDiscards(const std::string& path) {
508 std::string output;
509 const char kRunCommand[] = "run";
510 if (path == kRunCommand)
511 return AboutDiscardsRun();
512 AppendHeader(&output, 0, "About discards");
513 AddContentSecurityPolicy(&output);
514 AppendBody(&output);
515 output.append("<h3>About discards</h3>");
516 output.append(
517 "<p>Tabs sorted from most interesting to least interesting. The least "
518 "interesting tab may be discarded if we run out of physical memory.</p>");
520 chromeos::OomPriorityManager* oom =
521 g_browser_process->platform_part()->oom_priority_manager();
522 std::vector<base::string16> titles = oom->GetTabTitles();
523 if (!titles.empty()) {
524 output.append("<ul>");
525 std::vector<base::string16>::iterator it = titles.begin();
526 for ( ; it != titles.end(); ++it) {
527 std::string title = base::UTF16ToUTF8(*it);
528 title = net::EscapeForHTML(title);
529 output.append(WrapWithTag("li", title));
531 output.append("</ul>");
532 } else {
533 output.append("<p>None found. Wait 10 seconds, then refresh.</p>");
535 output.append(base::StringPrintf("%d discards this session. ",
536 oom->discard_count()));
537 output.append(base::StringPrintf("<a href='%s%s'>Discard tab now</a>",
538 chrome::kChromeUIDiscardsURL,
539 kRunCommand));
541 base::SystemMemoryInfoKB meminfo;
542 base::GetSystemMemoryInfo(&meminfo);
543 output.append("<h3>System memory information in MB</h3>");
544 output.append("<table>");
545 // Start with summary statistics.
546 output.append(AddStringRow(
547 "Total", base::IntToString(meminfo.total / 1024)));
548 output.append(AddStringRow(
549 "Free", base::IntToString(meminfo.free / 1024)));
550 int mem_allocated_kb = meminfo.active_anon + meminfo.inactive_anon;
551 #if defined(ARCH_CPU_ARM_FAMILY)
552 // ARM counts allocated graphics memory separately from anonymous.
553 if (meminfo.gem_size != -1)
554 mem_allocated_kb += meminfo.gem_size / 1024;
555 #endif
556 output.append(AddStringRow(
557 "Allocated", base::IntToString(mem_allocated_kb / 1024)));
558 // Add some space, then detailed numbers.
559 output.append(AddStringRow("&nbsp;", "&nbsp;"));
560 output.append(AddStringRow(
561 "Buffered", base::IntToString(meminfo.buffers / 1024)));
562 output.append(AddStringRow(
563 "Cached", base::IntToString(meminfo.cached / 1024)));
564 output.append(AddStringRow(
565 "Active Anon", base::IntToString(meminfo.active_anon / 1024)));
566 output.append(AddStringRow(
567 "Inactive Anon", base::IntToString(meminfo.inactive_anon / 1024)));
568 output.append(AddStringRow(
569 "Shared", base::IntToString(meminfo.shmem / 1024)));
570 output.append(AddStringRow(
571 "Graphics", base::IntToString(meminfo.gem_size / 1024 / 1024)));
572 output.append("</table>");
574 AppendFooter(&output);
575 return output;
578 #endif // OS_CHROMEOS
580 // AboutDnsHandler bounces the request back to the IO thread to collect
581 // the DNS information.
582 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
583 public:
584 static void Start(Profile* profile,
585 const content::URLDataSource::GotDataCallback& callback) {
586 scoped_refptr<AboutDnsHandler> handler(
587 new AboutDnsHandler(profile, callback));
588 handler->StartOnUIThread();
591 private:
592 friend class base::RefCountedThreadSafe<AboutDnsHandler>;
594 AboutDnsHandler(Profile* profile,
595 const content::URLDataSource::GotDataCallback& callback)
596 : profile_(profile),
597 callback_(callback) {
598 DCHECK_CURRENTLY_ON(BrowserThread::UI);
601 virtual ~AboutDnsHandler() {}
603 // Calls FinishOnUIThread() on completion.
604 void StartOnUIThread() {
605 DCHECK_CURRENTLY_ON(BrowserThread::UI);
606 chrome_browser_net::Predictor* predictor = profile_->GetNetworkPredictor();
607 BrowserThread::PostTask(
608 BrowserThread::IO, FROM_HERE,
609 base::Bind(&AboutDnsHandler::StartOnIOThread, this, predictor));
612 void StartOnIOThread(chrome_browser_net::Predictor* predictor) {
613 DCHECK_CURRENTLY_ON(BrowserThread::IO);
615 std::string data;
616 AppendHeader(&data, 0, "About DNS");
617 AppendBody(&data);
618 chrome_browser_net::Predictor::PredictorGetHtmlInfo(predictor, &data);
619 AppendFooter(&data);
621 BrowserThread::PostTask(
622 BrowserThread::UI, FROM_HERE,
623 base::Bind(&AboutDnsHandler::FinishOnUIThread, this, data));
626 void FinishOnUIThread(const std::string& data) {
627 DCHECK_CURRENTLY_ON(BrowserThread::UI);
628 std::string data_copy(data);
629 callback_.Run(base::RefCountedString::TakeString(&data_copy));
632 Profile* profile_;
634 // Callback to run with the response.
635 content::URLDataSource::GotDataCallback callback_;
637 DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler);
640 void FinishMemoryDataRequest(
641 const std::string& path,
642 const content::URLDataSource::GotDataCallback& callback) {
643 if (path == kStringsJsPath) {
644 // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want
645 // the refcount to be greater than 0.
646 scoped_refptr<AboutMemoryHandler> handler(new AboutMemoryHandler(callback));
647 handler->StartFetch(MemoryDetails::FROM_ALL_BROWSERS);
648 } else {
649 int id = IDR_ABOUT_MEMORY_HTML;
650 if (path == kMemoryJsPath) {
651 id = IDR_ABOUT_MEMORY_JS;
652 } else if (path == kMemoryCssPath) {
653 id = IDR_ABOUT_MEMORY_CSS;
656 std::string result =
657 ResourceBundle::GetSharedInstance().GetRawDataResource(id).as_string();
658 callback.Run(base::RefCountedString::TakeString(&result));
662 #if defined(OS_LINUX) || defined(OS_OPENBSD)
663 std::string AboutLinuxProxyConfig() {
664 std::string data;
665 AppendHeader(&data, 0,
666 l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE));
667 data.append("<style>body { max-width: 70ex; padding: 2ex 5ex; }</style>");
668 AppendBody(&data);
669 base::FilePath binary = base::CommandLine::ForCurrentProcess()->GetProgram();
670 data.append(l10n_util::GetStringFUTF8(
671 IDS_ABOUT_LINUX_PROXY_CONFIG_BODY,
672 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
673 base::ASCIIToUTF16(binary.BaseName().value())));
674 AppendFooter(&data);
675 return data;
678 void AboutSandboxRow(std::string* data, int name_id, bool good) {
679 data->append("<tr><td>");
680 data->append(l10n_util::GetStringUTF8(name_id));
681 if (good) {
682 data->append("</td><td style='color: green;'>");
683 data->append(
684 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
685 } else {
686 data->append("</td><td style='color: red;'>");
687 data->append(
688 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
690 data->append("</td></tr>");
693 std::string AboutSandbox() {
694 std::string data;
695 AppendHeader(&data, 0, l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
696 AppendBody(&data);
697 data.append("<h1>");
698 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
699 data.append("</h1>");
701 // Get expected sandboxing status of renderers.
702 const int status = content::ZygoteHost::GetInstance()->GetSandboxStatus();
704 data.append("<table>");
706 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SUID_SANDBOX,
707 status & content::kSandboxLinuxSUID);
708 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_NAMESPACE_SANDBOX,
709 status & content::kSandboxLinuxUserNS);
710 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_PID_NAMESPACES,
711 status & content::kSandboxLinuxPIDNS);
712 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_NET_NAMESPACES,
713 status & content::kSandboxLinuxNetNS);
714 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX,
715 status & content::kSandboxLinuxSeccompBPF);
716 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX_TSYNC,
717 status & content::kSandboxLinuxSeccompTSYNC);
718 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_YAMA_LSM,
719 status & content::kSandboxLinuxYama);
721 data.append("</table>");
723 // Require either the setuid or namespace sandbox for our first-layer sandbox.
724 bool good_layer1 = (status & content::kSandboxLinuxSUID ||
725 status & content::kSandboxLinuxUserNS) &&
726 status & content::kSandboxLinuxPIDNS &&
727 status & content::kSandboxLinuxNetNS;
728 // A second-layer sandbox is also required to be adequately sandboxed.
729 bool good_layer2 = status & content::kSandboxLinuxSeccompBPF;
730 bool good = good_layer1 && good_layer2;
732 if (good) {
733 data.append("<p style='color: green'>");
734 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK));
735 } else {
736 data.append("<p style='color: red'>");
737 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD));
739 data.append("</p>");
741 AppendFooter(&data);
742 return data;
744 #endif
746 // AboutMemoryHandler ----------------------------------------------------------
748 // Helper for AboutMemory to bind results from a ProcessMetrics object
749 // to a DictionaryValue. Fills ws_usage and comm_usage so that the objects
750 // can be used in caller's scope (e.g for appending to a net total).
751 void AboutMemoryHandler::BindProcessMetrics(base::DictionaryValue* data,
752 ProcessMemoryInformation* info) {
753 DCHECK(data && info);
755 // Bind metrics to dictionary.
756 data->SetInteger("ws_priv", static_cast<int>(info->working_set.priv));
757 data->SetInteger("ws_shareable",
758 static_cast<int>(info->working_set.shareable));
759 data->SetInteger("ws_shared", static_cast<int>(info->working_set.shared));
760 data->SetInteger("comm_priv", static_cast<int>(info->committed.priv));
761 data->SetInteger("comm_map", static_cast<int>(info->committed.mapped));
762 data->SetInteger("comm_image", static_cast<int>(info->committed.image));
763 data->SetInteger("pid", info->pid);
764 data->SetString("version", info->version);
765 data->SetInteger("processes", info->num_processes);
768 // Helper for AboutMemory to append memory usage information for all
769 // sub-processes (i.e. renderers, plugins) used by Chrome.
770 void AboutMemoryHandler::AppendProcess(base::ListValue* child_data,
771 ProcessMemoryInformation* info) {
772 DCHECK(child_data && info);
774 // Append a new DictionaryValue for this renderer to our list.
775 base::DictionaryValue* child = new base::DictionaryValue();
776 child_data->Append(child);
777 BindProcessMetrics(child, info);
779 std::string child_label(
780 ProcessMemoryInformation::GetFullTypeNameInEnglish(info->process_type,
781 info->renderer_type));
782 if (info->is_diagnostics)
783 child_label.append(" (diagnostics)");
784 child->SetString("child_name", child_label);
785 base::ListValue* titles = new base::ListValue();
786 child->Set("titles", titles);
787 for (size_t i = 0; i < info->titles.size(); ++i)
788 titles->Append(new base::StringValue(info->titles[i]));
791 void AboutMemoryHandler::OnDetailsAvailable() {
792 // the root of the JSON hierarchy for about:memory jstemplate
793 scoped_ptr<base::DictionaryValue> root(new base::DictionaryValue);
794 base::ListValue* browsers = new base::ListValue();
795 root->Set("browsers", browsers);
797 const std::vector<ProcessData>& browser_processes = processes();
799 // Aggregate per-process data into browser summary data.
800 base::string16 log_string;
801 for (size_t index = 0; index < browser_processes.size(); index++) {
802 if (browser_processes[index].processes.empty())
803 continue;
805 // Sum the information for the processes within this browser.
806 ProcessMemoryInformation aggregate;
807 ProcessMemoryInformationList::const_iterator iterator;
808 iterator = browser_processes[index].processes.begin();
809 aggregate.pid = iterator->pid;
810 aggregate.version = iterator->version;
811 while (iterator != browser_processes[index].processes.end()) {
812 if (!iterator->is_diagnostics ||
813 browser_processes[index].processes.size() == 1) {
814 aggregate.working_set.priv += iterator->working_set.priv;
815 aggregate.working_set.shared += iterator->working_set.shared;
816 aggregate.working_set.shareable += iterator->working_set.shareable;
817 aggregate.committed.priv += iterator->committed.priv;
818 aggregate.committed.mapped += iterator->committed.mapped;
819 aggregate.committed.image += iterator->committed.image;
820 aggregate.num_processes++;
822 ++iterator;
824 base::DictionaryValue* browser_data = new base::DictionaryValue();
825 browsers->Append(browser_data);
826 browser_data->SetString("name", browser_processes[index].name);
828 BindProcessMetrics(browser_data, &aggregate);
830 // We log memory info as we record it.
831 if (!log_string.empty())
832 log_string += base::ASCIIToUTF16(", ");
833 log_string += browser_processes[index].name + base::ASCIIToUTF16(", ") +
834 base::Int64ToString16(aggregate.working_set.priv) +
835 base::ASCIIToUTF16(", ") +
836 base::Int64ToString16(aggregate.working_set.shared) +
837 base::ASCIIToUTF16(", ") +
838 base::Int64ToString16(aggregate.working_set.shareable);
840 if (!log_string.empty())
841 VLOG(1) << "memory: " << log_string;
843 // Set the browser & renderer detailed process data.
844 base::DictionaryValue* browser_data = new base::DictionaryValue();
845 root->Set("browzr_data", browser_data);
846 base::ListValue* child_data = new base::ListValue();
847 root->Set("child_data", child_data);
849 ProcessData process = browser_processes[0]; // Chrome is the first browser.
850 root->SetString("current_browser_name", process.name);
852 for (size_t index = 0; index < process.processes.size(); index++) {
853 if (process.processes[index].process_type == content::PROCESS_TYPE_BROWSER)
854 BindProcessMetrics(browser_data, &process.processes[index]);
855 else
856 AppendProcess(child_data, &process.processes[index]);
859 root->SetBoolean("show_other_browsers",
860 browser_defaults::kShowOtherBrowsersInAboutMemory);
862 base::DictionaryValue load_time_data;
863 load_time_data.SetString(
864 "summary_desc",
865 l10n_util::GetStringUTF16(IDS_MEMORY_USAGE_SUMMARY_DESC));
866 const std::string& app_locale = g_browser_process->GetApplicationLocale();
867 webui::SetLoadTimeDataDefaults(app_locale, &load_time_data);
868 load_time_data.Set("jstemplateData", root.release());
870 std::string data;
871 webui::AppendJsonJS(&load_time_data, &data);
872 callback_.Run(base::RefCountedString::TakeString(&data));
875 } // namespace
877 // AboutUIHTMLSource ----------------------------------------------------------
879 AboutUIHTMLSource::AboutUIHTMLSource(const std::string& source_name,
880 Profile* profile)
881 : source_name_(source_name),
882 profile_(profile) {}
884 AboutUIHTMLSource::~AboutUIHTMLSource() {}
886 std::string AboutUIHTMLSource::GetSource() const {
887 return source_name_;
890 void AboutUIHTMLSource::StartDataRequest(
891 const std::string& path,
892 int render_process_id,
893 int render_frame_id,
894 const content::URLDataSource::GotDataCallback& callback) {
895 std::string response;
896 // Add your data source here, in alphabetical order.
897 if (source_name_ == chrome::kChromeUIChromeURLsHost) {
898 response = ChromeURLs();
899 } else if (source_name_ == chrome::kChromeUICreditsHost) {
900 int idr = IDR_CREDITS_HTML;
901 if (path == kCreditsJsPath)
902 idr = IDR_CREDITS_JS;
903 #if defined(OS_CHROMEOS)
904 else if (path == kKeyboardUtilsPath)
905 idr = IDR_KEYBOARD_UTILS_JS;
906 #endif
908 response = ResourceBundle::GetSharedInstance().GetRawDataResource(
909 idr).as_string();
910 #if defined(OS_CHROMEOS)
911 } else if (source_name_ == chrome::kChromeUIDiscardsHost) {
912 response = AboutDiscards(path);
913 #endif
914 } else if (source_name_ == chrome::kChromeUIDNSHost) {
915 AboutDnsHandler::Start(profile(), callback);
916 return;
917 #if defined(OS_LINUX) || defined(OS_OPENBSD)
918 } else if (source_name_ == chrome::kChromeUILinuxProxyConfigHost) {
919 response = AboutLinuxProxyConfig();
920 #endif
921 } else if (source_name_ == chrome::kChromeUIMemoryHost) {
922 response = GetAboutMemoryRedirectResponse(profile());
923 } else if (source_name_ == chrome::kChromeUIMemoryRedirectHost) {
924 FinishMemoryDataRequest(path, callback);
925 return;
926 #if defined(OS_CHROMEOS)
927 } else if (source_name_ == chrome::kChromeUIOSCreditsHost) {
928 ChromeOSCreditsHandler::Start(path, callback);
929 return;
930 #endif
931 #if defined(OS_LINUX) || defined(OS_OPENBSD)
932 } else if (source_name_ == chrome::kChromeUISandboxHost) {
933 response = AboutSandbox();
934 #endif
935 #if !defined(OS_ANDROID)
936 } else if (source_name_ == chrome::kChromeUITermsHost) {
937 #if defined(OS_CHROMEOS)
938 ChromeOSTermsHandler::Start(path, callback);
939 return;
940 #else
941 response = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
942 #endif
943 #endif
946 FinishDataRequest(response, callback);
949 void AboutUIHTMLSource::FinishDataRequest(
950 const std::string& html,
951 const content::URLDataSource::GotDataCallback& callback) {
952 std::string html_copy(html);
953 callback.Run(base::RefCountedString::TakeString(&html_copy));
956 std::string AboutUIHTMLSource::GetMimeType(const std::string& path) const {
957 if (path == kCreditsJsPath ||
958 #if defined(OS_CHROMEOS)
959 path == kKeyboardUtilsPath ||
960 #endif
961 path == kStatsJsPath ||
962 path == kStringsJsPath ||
963 path == kMemoryJsPath) {
964 return "application/javascript";
966 return "text/html";
969 bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() const {
970 #if defined(OS_CHROMEOS)
971 if (source_name_ == chrome::kChromeUIOSCreditsHost)
972 return false;
973 #endif
974 return content::URLDataSource::ShouldAddContentSecurityPolicy();
977 bool AboutUIHTMLSource::ShouldDenyXFrameOptions() const {
978 #if defined(OS_CHROMEOS)
979 if (source_name_ == chrome::kChromeUITermsHost) {
980 // chrome://terms page is embedded in iframe to chrome://oobe.
981 return false;
983 #endif
984 return content::URLDataSource::ShouldDenyXFrameOptions();
987 AboutUI::AboutUI(content::WebUI* web_ui, const std::string& name)
988 : WebUIController(web_ui) {
989 Profile* profile = Profile::FromWebUI(web_ui);
991 #if defined(ENABLE_THEMES)
992 // Set up the chrome://theme/ source.
993 ThemeSource* theme = new ThemeSource(profile);
994 content::URLDataSource::Add(profile, theme);
995 #endif
997 content::URLDataSource::Add(profile, new AboutUIHTMLSource(name, profile));