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"
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"
63 #if defined(ENABLE_THEMES)
64 #include "chrome/browser/ui/webui/theme_source.h"
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"
73 #include "chrome/browser/enumerate_modules_model_win.h"
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"
83 using base::TimeDelta
;
84 using content::BrowserThread
;
85 using content::WebContents
;
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
{
115 explicit AboutMemoryHandler(
116 const content::URLDataSource::GotDataCallback
& callback
)
117 : callback_(callback
) {
120 void OnDetailsAvailable() override
;
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
{
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
,
153 eula_fetcher_
.reset(net::URLFetcher::Create(0 /* ID used for testing */,
155 net::URLFetcher::GET
,
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
),
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();
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";
194 fetch_callback_
.Run(this);
198 void OnDownloadTimeout() {
199 eula_fetcher_
.reset();
200 fetch_callback_
.Run(this);
204 // Timer that enforces a timeout on the attempt to download the
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
> {
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();
228 friend class base::RefCountedThreadSafe
<ChromeOSTermsHandler
>;
230 ChromeOSTermsHandler(const std::string
& path
,
231 const content::URLDataSource::GotDataCallback
& 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));
248 // Try to load online version of ChromeOS terms first.
249 // ChromeOSOnlineTermsHandler object destroys itself.
250 new ChromeOSOnlineTermsHandler(
251 base::Bind(&ChromeOSTermsHandler::OnOnlineEULAFetched
, this),
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));
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_
)) {
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.
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_
));
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
> {
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();
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
)
354 ResponseOnUIThread();
357 // Load local Chrome OS credits from the disk.
358 BrowserThread::PostBlockingPoolTaskAndReply(
360 base::Bind(&ChromeOSCreditsHandler::LoadCreditsFileOnBlockingPool
,
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.
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
)
383 callback_
.Run(base::RefCountedString::TakeString(&contents_
));
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
);
401 // Individual about handlers ---------------------------------------------------
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");
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
;
437 std::string
ChromeURLs() {
439 AppendHeader(&html
, 0, "Chrome URLs");
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";
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
) {
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() {
495 AppendHeader(&output
, 0, "About discards");
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
);
507 std::string
AboutDiscards(const std::string
& path
) {
509 const char kRunCommand
[] = "run";
510 if (path
== kRunCommand
)
511 return AboutDiscardsRun();
512 AppendHeader(&output
, 0, "About discards");
513 AddContentSecurityPolicy(&output
);
515 output
.append("<h3>About discards</h3>");
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>");
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
,
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;
556 output
.append(AddStringRow(
557 "Allocated", base::IntToString(mem_allocated_kb
/ 1024)));
558 // Add some space, then detailed numbers.
559 output
.append(AddStringRow(" ", " "));
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
);
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
> {
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();
592 friend class base::RefCountedThreadSafe
<AboutDnsHandler
>;
594 AboutDnsHandler(Profile
* profile
,
595 const content::URLDataSource::GotDataCallback
& callback
)
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
);
616 AppendHeader(&data
, 0, "About DNS");
618 chrome_browser_net::Predictor::PredictorGetHtmlInfo(predictor
, &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
));
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
);
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
;
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() {
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>");
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())));
678 void AboutSandboxRow(std::string
* data
, int name_id
, bool good
) {
679 data
->append("<tr><td>");
680 data
->append(l10n_util::GetStringUTF8(name_id
));
682 data
->append("</td><td style='color: green;'>");
684 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL
));
686 data
->append("</td><td style='color: red;'>");
688 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL
));
690 data
->append("</td></tr>");
693 std::string
AboutSandbox() {
695 AppendHeader(&data
, 0, l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE
));
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
;
733 data
.append("<p style='color: green'>");
734 data
.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK
));
736 data
.append("<p style='color: red'>");
737 data
.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD
));
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())
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
++;
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
]);
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(
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());
871 webui::AppendJsonJS(&load_time_data
, &data
);
872 callback_
.Run(base::RefCountedString::TakeString(&data
));
877 // AboutUIHTMLSource ----------------------------------------------------------
879 AboutUIHTMLSource::AboutUIHTMLSource(const std::string
& source_name
,
881 : source_name_(source_name
),
884 AboutUIHTMLSource::~AboutUIHTMLSource() {}
886 std::string
AboutUIHTMLSource::GetSource() const {
890 void AboutUIHTMLSource::StartDataRequest(
891 const std::string
& path
,
892 int render_process_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
;
908 response
= ResourceBundle::GetSharedInstance().GetRawDataResource(
910 #if defined(OS_CHROMEOS)
911 } else if (source_name_
== chrome::kChromeUIDiscardsHost
) {
912 response
= AboutDiscards(path
);
914 } else if (source_name_
== chrome::kChromeUIDNSHost
) {
915 AboutDnsHandler::Start(profile(), callback
);
917 #if defined(OS_LINUX) || defined(OS_OPENBSD)
918 } else if (source_name_
== chrome::kChromeUILinuxProxyConfigHost
) {
919 response
= AboutLinuxProxyConfig();
921 } else if (source_name_
== chrome::kChromeUIMemoryHost
) {
922 response
= GetAboutMemoryRedirectResponse(profile());
923 } else if (source_name_
== chrome::kChromeUIMemoryRedirectHost
) {
924 FinishMemoryDataRequest(path
, callback
);
926 #if defined(OS_CHROMEOS)
927 } else if (source_name_
== chrome::kChromeUIOSCreditsHost
) {
928 ChromeOSCreditsHandler::Start(path
, callback
);
931 #if defined(OS_LINUX) || defined(OS_OPENBSD)
932 } else if (source_name_
== chrome::kChromeUISandboxHost
) {
933 response
= AboutSandbox();
935 #if !defined(OS_ANDROID)
936 } else if (source_name_
== chrome::kChromeUITermsHost
) {
937 #if defined(OS_CHROMEOS)
938 ChromeOSTermsHandler::Start(path
, callback
);
941 response
= l10n_util::GetStringUTF8(IDS_TERMS_HTML
);
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
||
961 path
== kStatsJsPath
||
962 path
== kStringsJsPath
||
963 path
== kMemoryJsPath
) {
964 return "application/javascript";
969 bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() const {
970 #if defined(OS_CHROMEOS)
971 if (source_name_
== chrome::kChromeUIOSCreditsHost
)
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.
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
);
997 content::URLDataSource::Add(profile
, new AboutUIHTMLSource(name
, profile
));