Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / webui / about_ui.cc
blobec8cd831bc096bf38306fd4eefb5808949df8d7a
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_ =
154 net::URLFetcher::Create(0 /* ID used for testing */, GURL(eula_URL),
155 net::URLFetcher::GET, this);
156 eula_fetcher_->SetRequestContext(
157 g_browser_process->system_request_context());
158 eula_fetcher_->AddExtraRequestHeader("Accept: text/html");
159 eula_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
160 net::LOAD_DO_NOT_SAVE_COOKIES |
161 net::LOAD_DISABLE_CACHE);
162 eula_fetcher_->Start();
163 // Abort the download attempt if it takes longer than one minute.
164 download_timer_.Start(FROM_HERE,
165 base::TimeDelta::FromSeconds(kOnlineTermsTimeoutSec),
166 this,
167 &ChromeOSOnlineTermsHandler::OnDownloadTimeout);
170 void GetResponseResult(std::string* response_string) {
171 std::string mime_type;
172 if (!eula_fetcher_ ||
173 !eula_fetcher_->GetStatus().is_success() ||
174 eula_fetcher_->GetResponseCode() != 200 ||
175 !eula_fetcher_->GetResponseHeaders()->GetMimeType(&mime_type) ||
176 mime_type != "text/html" ||
177 !eula_fetcher_->GetResponseAsString(response_string)) {
178 response_string->clear();
182 private:
183 // Prevents allocation on the stack. ChromeOSOnlineTermsHandler should be
184 // created by 'operator new'. |this| takes care of destruction.
185 ~ChromeOSOnlineTermsHandler() override {}
187 // net::URLFetcherDelegate:
188 void OnURLFetchComplete(const net::URLFetcher* source) override {
189 if (source != eula_fetcher_.get()) {
190 NOTREACHED() << "Callback from foreign URL fetcher";
191 return;
193 fetch_callback_.Run(this);
194 delete this;
197 void OnDownloadTimeout() {
198 eula_fetcher_.reset();
199 fetch_callback_.Run(this);
200 delete this;
203 // Timer that enforces a timeout on the attempt to download the
204 // ChromeOS Terms.
205 base::OneShotTimer<ChromeOSOnlineTermsHandler> download_timer_;
207 // |fetch_callback_| called when fetching succeeded or failed.
208 FetchCallback fetch_callback_;
210 // Helper to fetch online eula.
211 scoped_ptr<net::URLFetcher> eula_fetcher_;
213 DISALLOW_COPY_AND_ASSIGN(ChromeOSOnlineTermsHandler);
216 class ChromeOSTermsHandler
217 : public base::RefCountedThreadSafe<ChromeOSTermsHandler> {
218 public:
219 static void Start(const std::string& path,
220 const content::URLDataSource::GotDataCallback& callback) {
221 scoped_refptr<ChromeOSTermsHandler> handler(
222 new ChromeOSTermsHandler(path, callback));
223 handler->StartOnUIThread();
226 private:
227 friend class base::RefCountedThreadSafe<ChromeOSTermsHandler>;
229 ChromeOSTermsHandler(const std::string& path,
230 const content::URLDataSource::GotDataCallback& callback)
231 : path_(path),
232 callback_(callback),
233 // Previously we were using "initial locale" http://crbug.com/145142
234 locale_(g_browser_process->GetApplicationLocale()) {
237 virtual ~ChromeOSTermsHandler() {}
239 void StartOnUIThread() {
240 DCHECK_CURRENTLY_ON(BrowserThread::UI);
241 if (path_ == chrome::kOemEulaURLPath) {
242 // Load local OEM EULA from the disk.
243 BrowserThread::PostTask(
244 BrowserThread::FILE, FROM_HERE,
245 base::Bind(&ChromeOSTermsHandler::LoadOemEulaFileOnFileThread, this));
246 } else {
247 // Try to load online version of ChromeOS terms first.
248 // ChromeOSOnlineTermsHandler object destroys itself.
249 new ChromeOSOnlineTermsHandler(
250 base::Bind(&ChromeOSTermsHandler::OnOnlineEULAFetched, this),
251 locale_);
255 void OnOnlineEULAFetched(ChromeOSOnlineTermsHandler* loader) {
256 DCHECK_CURRENTLY_ON(BrowserThread::UI);
257 loader->GetResponseResult(&contents_);
258 if (contents_.empty()) {
259 // Load local ChromeOS terms from the file.
260 BrowserThread::PostTask(
261 BrowserThread::FILE, FROM_HERE,
262 base::Bind(&ChromeOSTermsHandler::LoadEulaFileOnFileThread, this));
263 } else {
264 ResponseOnUIThread();
268 void LoadOemEulaFileOnFileThread() {
269 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
270 const chromeos::StartupCustomizationDocument* customization =
271 chromeos::StartupCustomizationDocument::GetInstance();
272 if (customization->IsReady()) {
273 base::FilePath oem_eula_file_path;
274 if (net::FileURLToFilePath(GURL(customization->GetEULAPage(locale_)),
275 &oem_eula_file_path)) {
276 if (!base::ReadFileToString(oem_eula_file_path, &contents_)) {
277 contents_.clear();
281 BrowserThread::PostTask(
282 BrowserThread::UI, FROM_HERE,
283 base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
286 void LoadEulaFileOnFileThread() {
287 std::string file_path =
288 base::StringPrintf(chrome::kEULAPathFormat, locale_.c_str());
289 if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
290 // No EULA for given language - try en-US as default.
291 file_path = base::StringPrintf(chrome::kEULAPathFormat, "en-US");
292 if (!base::ReadFileToString(base::FilePath(file_path), &contents_)) {
293 // File with EULA not found, ResponseOnUIThread will load EULA from
294 // resources if contents_ is empty.
295 contents_.clear();
298 BrowserThread::PostTask(
299 BrowserThread::UI, FROM_HERE,
300 base::Bind(&ChromeOSTermsHandler::ResponseOnUIThread, this));
303 void ResponseOnUIThread() {
304 DCHECK_CURRENTLY_ON(BrowserThread::UI);
305 // If we fail to load Chrome OS EULA from disk, load it from resources.
306 // Do nothing if OEM EULA load failed.
307 if (contents_.empty() && path_ != chrome::kOemEulaURLPath)
308 contents_ = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
309 callback_.Run(base::RefCountedString::TakeString(&contents_));
312 // Path in the URL.
313 const std::string path_;
315 // Callback to run with the response.
316 content::URLDataSource::GotDataCallback callback_;
318 // Locale of the EULA.
319 const std::string locale_;
321 // EULA contents that was loaded from file.
322 std::string contents_;
324 DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsHandler);
327 class ChromeOSCreditsHandler
328 : public base::RefCountedThreadSafe<ChromeOSCreditsHandler> {
329 public:
330 static void Start(const std::string& path,
331 const content::URLDataSource::GotDataCallback& callback) {
332 scoped_refptr<ChromeOSCreditsHandler> handler(
333 new ChromeOSCreditsHandler(path, callback));
334 handler->StartOnUIThread();
337 private:
338 friend class base::RefCountedThreadSafe<ChromeOSCreditsHandler>;
340 ChromeOSCreditsHandler(
341 const std::string& path,
342 const content::URLDataSource::GotDataCallback& callback)
343 : path_(path), callback_(callback) {}
345 virtual ~ChromeOSCreditsHandler() {}
347 void StartOnUIThread() {
348 DCHECK_CURRENTLY_ON(BrowserThread::UI);
349 if (path_ == kKeyboardUtilsPath) {
350 contents_ = ResourceBundle::GetSharedInstance()
351 .GetRawDataResource(IDR_KEYBOARD_UTILS_JS)
352 .as_string();
353 ResponseOnUIThread();
354 return;
356 // Load local Chrome OS credits from the disk.
357 BrowserThread::PostBlockingPoolTaskAndReply(
358 FROM_HERE,
359 base::Bind(&ChromeOSCreditsHandler::LoadCreditsFileOnBlockingPool,
360 this),
361 base::Bind(&ChromeOSCreditsHandler::ResponseOnUIThread, this));
364 void LoadCreditsFileOnBlockingPool() {
365 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
366 base::FilePath credits_file_path(chrome::kChromeOSCreditsPath);
367 if (!base::ReadFileToString(credits_file_path, &contents_)) {
368 // File with credits not found, ResponseOnUIThread will load credits
369 // from resources if contents_ is empty.
370 contents_.clear();
374 void ResponseOnUIThread() {
375 DCHECK_CURRENTLY_ON(BrowserThread::UI);
376 // If we fail to load Chrome OS credits from disk, load it from resources.
377 if (contents_.empty() && path_ != kKeyboardUtilsPath) {
378 contents_ = ResourceBundle::GetSharedInstance()
379 .GetRawDataResource(IDR_OS_CREDITS_HTML)
380 .as_string();
382 callback_.Run(base::RefCountedString::TakeString(&contents_));
385 // Path in the URL.
386 const std::string path_;
388 // Callback to run with the response.
389 content::URLDataSource::GotDataCallback callback_;
391 // Chrome OS credits contents that was loaded from file.
392 std::string contents_;
394 DISALLOW_COPY_AND_ASSIGN(ChromeOSCreditsHandler);
396 #endif
398 } // namespace
400 // Individual about handlers ---------------------------------------------------
402 namespace about_ui {
404 void AppendHeader(std::string* output, int refresh,
405 const std::string& unescaped_title) {
406 output->append("<!DOCTYPE HTML>\n<html>\n<head>\n");
407 if (!unescaped_title.empty()) {
408 output->append("<title>");
409 output->append(net::EscapeForHTML(unescaped_title));
410 output->append("</title>\n");
412 output->append("<meta charset='utf-8'>\n");
413 if (refresh > 0) {
414 output->append("<meta http-equiv='refresh' content='");
415 output->append(base::IntToString(refresh));
416 output->append("'/>\n");
420 void AppendBody(std::string *output) {
421 output->append("</head>\n<body>\n");
424 void AppendFooter(std::string *output) {
425 output->append("</body>\n</html>\n");
428 } // namespace about_ui
430 using about_ui::AppendHeader;
431 using about_ui::AppendBody;
432 using about_ui::AppendFooter;
434 namespace {
436 std::string ChromeURLs() {
437 std::string html;
438 AppendHeader(&html, 0, "Chrome URLs");
439 AppendBody(&html);
440 html += "<h2>List of Chrome URLs</h2>\n<ul>\n";
441 std::vector<std::string> hosts(
442 chrome::kChromeHostURLs,
443 chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs);
444 std::sort(hosts.begin(), hosts.end());
445 for (std::vector<std::string>::const_iterator i = hosts.begin();
446 i != hosts.end(); ++i)
447 html += "<li><a href='chrome://" + *i + "/'>chrome://" + *i + "</a></li>\n";
448 html += "</ul>\n<h2>For Debug</h2>\n"
449 "<p>The following pages are for debugging purposes only. Because they "
450 "crash or hang the renderer, they're not linked directly; you can type "
451 "them into the address bar if you need them.</p>\n<ul>";
452 for (int i = 0; i < chrome::kNumberOfChromeDebugURLs; i++)
453 html += "<li>" + std::string(chrome::kChromeDebugURLs[i]) + "</li>\n";
454 html += "</ul>\n";
455 AppendFooter(&html);
456 return html;
459 #if defined(OS_CHROMEOS)
461 // Html output helper functions
463 // Helper function to wrap HTML with a tag.
464 std::string WrapWithTag(const std::string& tag, const std::string& text) {
465 return "<" + tag + ">" + text + "</" + tag + ">";
468 // Helper function to wrap Html with <td> tag.
469 std::string WrapWithTD(const std::string& text) {
470 return "<td>" + text + "</td>";
473 // Helper function to wrap Html with <tr> tag.
474 std::string WrapWithTR(const std::string& text) {
475 return "<tr>" + text + "</tr>";
478 std::string AddStringRow(const std::string& name, const std::string& value) {
479 std::string row;
480 row.append(WrapWithTD(name));
481 row.append(WrapWithTD(value));
482 return WrapWithTR(row);
485 void AddContentSecurityPolicy(std::string* output) {
486 output->append("<meta http-equiv='Content-Security-Policy' "
487 "content='default-src 'none';'>");
490 // TODO(stevenjb): L10N AboutDiscards.
492 std::string AboutDiscardsRun() {
493 std::string output;
494 AppendHeader(&output, 0, "About discards");
495 output.append(
496 base::StringPrintf("<meta http-equiv='refresh' content='2;%s'>",
497 chrome::kChromeUIDiscardsURL));
498 AddContentSecurityPolicy(&output);
499 output.append(WrapWithTag("p", "Discarding a tab..."));
500 g_browser_process->platform_part()->
501 oom_priority_manager()->LogMemoryAndDiscardTab();
502 AppendFooter(&output);
503 return output;
506 std::string AboutDiscards(const std::string& path) {
507 std::string output;
508 const char kRunCommand[] = "run";
509 if (path == kRunCommand)
510 return AboutDiscardsRun();
511 AppendHeader(&output, 0, "About discards");
512 AddContentSecurityPolicy(&output);
513 AppendBody(&output);
514 output.append("<h3>About discards</h3>");
515 output.append(
516 "<p>Tabs sorted from most interesting to least interesting. The least "
517 "interesting tab may be discarded if we run out of physical memory.</p>");
519 chromeos::OomPriorityManager* oom =
520 g_browser_process->platform_part()->oom_priority_manager();
521 std::vector<base::string16> titles = oom->GetTabTitles();
522 if (!titles.empty()) {
523 output.append("<ul>");
524 std::vector<base::string16>::iterator it = titles.begin();
525 for ( ; it != titles.end(); ++it) {
526 std::string title = base::UTF16ToUTF8(*it);
527 title = net::EscapeForHTML(title);
528 output.append(WrapWithTag("li", title));
530 output.append("</ul>");
531 } else {
532 output.append("<p>None found. Wait 10 seconds, then refresh.</p>");
534 output.append(base::StringPrintf("%d discards this session. ",
535 oom->discard_count()));
536 output.append(base::StringPrintf("<a href='%s%s'>Discard tab now</a>",
537 chrome::kChromeUIDiscardsURL,
538 kRunCommand));
540 base::SystemMemoryInfoKB meminfo;
541 base::GetSystemMemoryInfo(&meminfo);
542 output.append("<h3>System memory information in MB</h3>");
543 output.append("<table>");
544 // Start with summary statistics.
545 output.append(AddStringRow(
546 "Total", base::IntToString(meminfo.total / 1024)));
547 output.append(AddStringRow(
548 "Free", base::IntToString(meminfo.free / 1024)));
549 int mem_allocated_kb = meminfo.active_anon + meminfo.inactive_anon;
550 #if defined(ARCH_CPU_ARM_FAMILY)
551 // ARM counts allocated graphics memory separately from anonymous.
552 if (meminfo.gem_size != -1)
553 mem_allocated_kb += meminfo.gem_size / 1024;
554 #endif
555 output.append(AddStringRow(
556 "Allocated", base::IntToString(mem_allocated_kb / 1024)));
557 // Add some space, then detailed numbers.
558 output.append(AddStringRow("&nbsp;", "&nbsp;"));
559 output.append(AddStringRow(
560 "Buffered", base::IntToString(meminfo.buffers / 1024)));
561 output.append(AddStringRow(
562 "Cached", base::IntToString(meminfo.cached / 1024)));
563 output.append(AddStringRow(
564 "Active Anon", base::IntToString(meminfo.active_anon / 1024)));
565 output.append(AddStringRow(
566 "Inactive Anon", base::IntToString(meminfo.inactive_anon / 1024)));
567 output.append(AddStringRow(
568 "Shared", base::IntToString(meminfo.shmem / 1024)));
569 output.append(AddStringRow(
570 "Graphics", base::IntToString(meminfo.gem_size / 1024 / 1024)));
571 output.append("</table>");
573 AppendFooter(&output);
574 return output;
577 #endif // OS_CHROMEOS
579 // AboutDnsHandler bounces the request back to the IO thread to collect
580 // the DNS information.
581 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
582 public:
583 static void Start(Profile* profile,
584 const content::URLDataSource::GotDataCallback& callback) {
585 scoped_refptr<AboutDnsHandler> handler(
586 new AboutDnsHandler(profile, callback));
587 handler->StartOnUIThread();
590 private:
591 friend class base::RefCountedThreadSafe<AboutDnsHandler>;
593 AboutDnsHandler(Profile* profile,
594 const content::URLDataSource::GotDataCallback& callback)
595 : profile_(profile),
596 callback_(callback) {
597 DCHECK_CURRENTLY_ON(BrowserThread::UI);
600 virtual ~AboutDnsHandler() {}
602 // Calls FinishOnUIThread() on completion.
603 void StartOnUIThread() {
604 DCHECK_CURRENTLY_ON(BrowserThread::UI);
605 chrome_browser_net::Predictor* predictor = profile_->GetNetworkPredictor();
606 BrowserThread::PostTask(
607 BrowserThread::IO, FROM_HERE,
608 base::Bind(&AboutDnsHandler::StartOnIOThread, this, predictor));
611 void StartOnIOThread(chrome_browser_net::Predictor* predictor) {
612 DCHECK_CURRENTLY_ON(BrowserThread::IO);
614 std::string data;
615 AppendHeader(&data, 0, "About DNS");
616 AppendBody(&data);
617 chrome_browser_net::Predictor::PredictorGetHtmlInfo(predictor, &data);
618 AppendFooter(&data);
620 BrowserThread::PostTask(
621 BrowserThread::UI, FROM_HERE,
622 base::Bind(&AboutDnsHandler::FinishOnUIThread, this, data));
625 void FinishOnUIThread(const std::string& data) {
626 DCHECK_CURRENTLY_ON(BrowserThread::UI);
627 std::string data_copy(data);
628 callback_.Run(base::RefCountedString::TakeString(&data_copy));
631 Profile* profile_;
633 // Callback to run with the response.
634 content::URLDataSource::GotDataCallback callback_;
636 DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler);
639 void FinishMemoryDataRequest(
640 const std::string& path,
641 const content::URLDataSource::GotDataCallback& callback) {
642 if (path == kStringsJsPath) {
643 // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want
644 // the refcount to be greater than 0.
645 scoped_refptr<AboutMemoryHandler> handler(new AboutMemoryHandler(callback));
646 handler->StartFetch(MemoryDetails::FROM_ALL_BROWSERS);
647 } else {
648 int id = IDR_ABOUT_MEMORY_HTML;
649 if (path == kMemoryJsPath) {
650 id = IDR_ABOUT_MEMORY_JS;
651 } else if (path == kMemoryCssPath) {
652 id = IDR_ABOUT_MEMORY_CSS;
655 std::string result =
656 ResourceBundle::GetSharedInstance().GetRawDataResource(id).as_string();
657 callback.Run(base::RefCountedString::TakeString(&result));
661 #if defined(OS_LINUX) || defined(OS_OPENBSD)
662 std::string AboutLinuxProxyConfig() {
663 std::string data;
664 AppendHeader(&data, 0,
665 l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE));
666 data.append("<style>body { max-width: 70ex; padding: 2ex 5ex; }</style>");
667 AppendBody(&data);
668 base::FilePath binary = base::CommandLine::ForCurrentProcess()->GetProgram();
669 data.append(l10n_util::GetStringFUTF8(
670 IDS_ABOUT_LINUX_PROXY_CONFIG_BODY,
671 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
672 base::ASCIIToUTF16(binary.BaseName().value())));
673 AppendFooter(&data);
674 return data;
677 void AboutSandboxRow(std::string* data, int name_id, bool good) {
678 data->append("<tr><td>");
679 data->append(l10n_util::GetStringUTF8(name_id));
680 if (good) {
681 data->append("</td><td style='color: green;'>");
682 data->append(
683 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
684 } else {
685 data->append("</td><td style='color: red;'>");
686 data->append(
687 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
689 data->append("</td></tr>");
692 std::string AboutSandbox() {
693 std::string data;
694 AppendHeader(&data, 0, l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
695 AppendBody(&data);
696 data.append("<h1>");
697 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
698 data.append("</h1>");
700 // Get expected sandboxing status of renderers.
701 const int status = content::ZygoteHost::GetInstance()->GetSandboxStatus();
703 data.append("<table>");
705 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SUID_SANDBOX,
706 status & content::kSandboxLinuxSUID);
707 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_NAMESPACE_SANDBOX,
708 status & content::kSandboxLinuxUserNS);
709 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_PID_NAMESPACES,
710 status & content::kSandboxLinuxPIDNS);
711 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_NET_NAMESPACES,
712 status & content::kSandboxLinuxNetNS);
713 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX,
714 status & content::kSandboxLinuxSeccompBPF);
715 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_SECCOMP_BPF_SANDBOX_TSYNC,
716 status & content::kSandboxLinuxSeccompTSYNC);
717 AboutSandboxRow(&data, IDS_ABOUT_SANDBOX_YAMA_LSM,
718 status & content::kSandboxLinuxYama);
720 data.append("</table>");
722 // Require either the setuid or namespace sandbox for our first-layer sandbox.
723 bool good_layer1 = (status & content::kSandboxLinuxSUID ||
724 status & content::kSandboxLinuxUserNS) &&
725 status & content::kSandboxLinuxPIDNS &&
726 status & content::kSandboxLinuxNetNS;
727 // A second-layer sandbox is also required to be adequately sandboxed.
728 bool good_layer2 = status & content::kSandboxLinuxSeccompBPF;
729 bool good = good_layer1 && good_layer2;
731 if (good) {
732 data.append("<p style='color: green'>");
733 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK));
734 } else {
735 data.append("<p style='color: red'>");
736 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD));
738 data.append("</p>");
740 AppendFooter(&data);
741 return data;
743 #endif
745 // AboutMemoryHandler ----------------------------------------------------------
747 // Helper for AboutMemory to bind results from a ProcessMetrics object
748 // to a DictionaryValue. Fills ws_usage and comm_usage so that the objects
749 // can be used in caller's scope (e.g for appending to a net total).
750 void AboutMemoryHandler::BindProcessMetrics(base::DictionaryValue* data,
751 ProcessMemoryInformation* info) {
752 DCHECK(data && info);
754 // Bind metrics to dictionary.
755 data->SetInteger("ws_priv", static_cast<int>(info->working_set.priv));
756 data->SetInteger("ws_shareable",
757 static_cast<int>(info->working_set.shareable));
758 data->SetInteger("ws_shared", static_cast<int>(info->working_set.shared));
759 data->SetInteger("comm_priv", static_cast<int>(info->committed.priv));
760 data->SetInteger("comm_map", static_cast<int>(info->committed.mapped));
761 data->SetInteger("comm_image", static_cast<int>(info->committed.image));
762 data->SetInteger("pid", info->pid);
763 data->SetString("version", info->version);
764 data->SetInteger("processes", info->num_processes);
767 // Helper for AboutMemory to append memory usage information for all
768 // sub-processes (i.e. renderers, plugins) used by Chrome.
769 void AboutMemoryHandler::AppendProcess(base::ListValue* child_data,
770 ProcessMemoryInformation* info) {
771 DCHECK(child_data && info);
773 // Append a new DictionaryValue for this renderer to our list.
774 base::DictionaryValue* child = new base::DictionaryValue();
775 child_data->Append(child);
776 BindProcessMetrics(child, info);
778 std::string child_label(
779 ProcessMemoryInformation::GetFullTypeNameInEnglish(info->process_type,
780 info->renderer_type));
781 if (info->is_diagnostics)
782 child_label.append(" (diagnostics)");
783 child->SetString("child_name", child_label);
784 base::ListValue* titles = new base::ListValue();
785 child->Set("titles", titles);
786 for (size_t i = 0; i < info->titles.size(); ++i)
787 titles->Append(new base::StringValue(info->titles[i]));
790 void AboutMemoryHandler::OnDetailsAvailable() {
791 // the root of the JSON hierarchy for about:memory jstemplate
792 scoped_ptr<base::DictionaryValue> root(new base::DictionaryValue);
793 base::ListValue* browsers = new base::ListValue();
794 root->Set("browsers", browsers);
796 const std::vector<ProcessData>& browser_processes = processes();
798 // Aggregate per-process data into browser summary data.
799 base::string16 log_string;
800 for (size_t index = 0; index < browser_processes.size(); index++) {
801 if (browser_processes[index].processes.empty())
802 continue;
804 // Sum the information for the processes within this browser.
805 ProcessMemoryInformation aggregate;
806 ProcessMemoryInformationList::const_iterator iterator;
807 iterator = browser_processes[index].processes.begin();
808 aggregate.pid = iterator->pid;
809 aggregate.version = iterator->version;
810 while (iterator != browser_processes[index].processes.end()) {
811 if (!iterator->is_diagnostics ||
812 browser_processes[index].processes.size() == 1) {
813 aggregate.working_set.priv += iterator->working_set.priv;
814 aggregate.working_set.shared += iterator->working_set.shared;
815 aggregate.working_set.shareable += iterator->working_set.shareable;
816 aggregate.committed.priv += iterator->committed.priv;
817 aggregate.committed.mapped += iterator->committed.mapped;
818 aggregate.committed.image += iterator->committed.image;
819 aggregate.num_processes++;
821 ++iterator;
823 base::DictionaryValue* browser_data = new base::DictionaryValue();
824 browsers->Append(browser_data);
825 browser_data->SetString("name", browser_processes[index].name);
827 BindProcessMetrics(browser_data, &aggregate);
829 // We log memory info as we record it.
830 if (!log_string.empty())
831 log_string += base::ASCIIToUTF16(", ");
832 log_string += browser_processes[index].name + base::ASCIIToUTF16(", ") +
833 base::Int64ToString16(aggregate.working_set.priv) +
834 base::ASCIIToUTF16(", ") +
835 base::Int64ToString16(aggregate.working_set.shared) +
836 base::ASCIIToUTF16(", ") +
837 base::Int64ToString16(aggregate.working_set.shareable);
839 if (!log_string.empty())
840 VLOG(1) << "memory: " << log_string;
842 // Set the browser & renderer detailed process data.
843 base::DictionaryValue* browser_data = new base::DictionaryValue();
844 root->Set("browzr_data", browser_data);
845 base::ListValue* child_data = new base::ListValue();
846 root->Set("child_data", child_data);
848 ProcessData process = browser_processes[0]; // Chrome is the first browser.
849 root->SetString("current_browser_name", process.name);
851 for (size_t index = 0; index < process.processes.size(); index++) {
852 if (process.processes[index].process_type == content::PROCESS_TYPE_BROWSER)
853 BindProcessMetrics(browser_data, &process.processes[index]);
854 else
855 AppendProcess(child_data, &process.processes[index]);
858 root->SetBoolean("show_other_browsers",
859 browser_defaults::kShowOtherBrowsersInAboutMemory);
861 base::DictionaryValue load_time_data;
862 load_time_data.SetString(
863 "summary_desc",
864 l10n_util::GetStringUTF16(IDS_MEMORY_USAGE_SUMMARY_DESC));
865 const std::string& app_locale = g_browser_process->GetApplicationLocale();
866 webui::SetLoadTimeDataDefaults(app_locale, &load_time_data);
867 load_time_data.Set("jstemplateData", root.release());
869 std::string data;
870 webui::AppendJsonJS(&load_time_data, &data);
871 callback_.Run(base::RefCountedString::TakeString(&data));
874 } // namespace
876 // AboutUIHTMLSource ----------------------------------------------------------
878 AboutUIHTMLSource::AboutUIHTMLSource(const std::string& source_name,
879 Profile* profile)
880 : source_name_(source_name),
881 profile_(profile) {}
883 AboutUIHTMLSource::~AboutUIHTMLSource() {}
885 std::string AboutUIHTMLSource::GetSource() const {
886 return source_name_;
889 void AboutUIHTMLSource::StartDataRequest(
890 const std::string& path,
891 int render_process_id,
892 int render_frame_id,
893 const content::URLDataSource::GotDataCallback& callback) {
894 std::string response;
895 // Add your data source here, in alphabetical order.
896 if (source_name_ == chrome::kChromeUIChromeURLsHost) {
897 response = ChromeURLs();
898 } else if (source_name_ == chrome::kChromeUICreditsHost) {
899 int idr = IDR_CREDITS_HTML;
900 if (path == kCreditsJsPath)
901 idr = IDR_CREDITS_JS;
902 #if defined(OS_CHROMEOS)
903 else if (path == kKeyboardUtilsPath)
904 idr = IDR_KEYBOARD_UTILS_JS;
905 #endif
907 response = ResourceBundle::GetSharedInstance().GetRawDataResource(
908 idr).as_string();
909 #if defined(OS_CHROMEOS)
910 } else if (source_name_ == chrome::kChromeUIDiscardsHost) {
911 response = AboutDiscards(path);
912 #endif
913 } else if (source_name_ == chrome::kChromeUIDNSHost) {
914 AboutDnsHandler::Start(profile(), callback);
915 return;
916 #if defined(OS_LINUX) || defined(OS_OPENBSD)
917 } else if (source_name_ == chrome::kChromeUILinuxProxyConfigHost) {
918 response = AboutLinuxProxyConfig();
919 #endif
920 } else if (source_name_ == chrome::kChromeUIMemoryHost) {
921 response = GetAboutMemoryRedirectResponse(profile());
922 } else if (source_name_ == chrome::kChromeUIMemoryRedirectHost) {
923 FinishMemoryDataRequest(path, callback);
924 return;
925 #if defined(OS_CHROMEOS)
926 } else if (source_name_ == chrome::kChromeUIOSCreditsHost) {
927 ChromeOSCreditsHandler::Start(path, callback);
928 return;
929 #endif
930 #if defined(OS_LINUX) || defined(OS_OPENBSD)
931 } else if (source_name_ == chrome::kChromeUISandboxHost) {
932 response = AboutSandbox();
933 #endif
934 #if !defined(OS_ANDROID)
935 } else if (source_name_ == chrome::kChromeUITermsHost) {
936 #if defined(OS_CHROMEOS)
937 ChromeOSTermsHandler::Start(path, callback);
938 return;
939 #else
940 response = l10n_util::GetStringUTF8(IDS_TERMS_HTML);
941 #endif
942 #endif
945 FinishDataRequest(response, callback);
948 void AboutUIHTMLSource::FinishDataRequest(
949 const std::string& html,
950 const content::URLDataSource::GotDataCallback& callback) {
951 std::string html_copy(html);
952 callback.Run(base::RefCountedString::TakeString(&html_copy));
955 std::string AboutUIHTMLSource::GetMimeType(const std::string& path) const {
956 if (path == kCreditsJsPath ||
957 #if defined(OS_CHROMEOS)
958 path == kKeyboardUtilsPath ||
959 #endif
960 path == kStatsJsPath ||
961 path == kStringsJsPath ||
962 path == kMemoryJsPath) {
963 return "application/javascript";
965 return "text/html";
968 bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() const {
969 #if defined(OS_CHROMEOS)
970 if (source_name_ == chrome::kChromeUIOSCreditsHost)
971 return false;
972 #endif
973 return content::URLDataSource::ShouldAddContentSecurityPolicy();
976 bool AboutUIHTMLSource::ShouldDenyXFrameOptions() const {
977 #if defined(OS_CHROMEOS)
978 if (source_name_ == chrome::kChromeUITermsHost) {
979 // chrome://terms page is embedded in iframe to chrome://oobe.
980 return false;
982 #endif
983 return content::URLDataSource::ShouldDenyXFrameOptions();
986 AboutUI::AboutUI(content::WebUI* web_ui, const std::string& name)
987 : WebUIController(web_ui) {
988 Profile* profile = Profile::FromWebUI(web_ui);
990 #if defined(ENABLE_THEMES)
991 // Set up the chrome://theme/ source.
992 ThemeSource* theme = new ThemeSource(profile);
993 content::URLDataSource::Add(profile, theme);
994 #endif
996 content::URLDataSource::Add(profile, new AboutUIHTMLSource(name, profile));