1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/browser_about_handler.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/file_util.h"
14 #include "base/i18n/number_formatting.h"
15 #include "base/json/json_writer.h"
16 #include "base/memory/singleton.h"
17 #include "base/metrics/histogram.h"
18 #include "base/metrics/stats_table.h"
19 #include "base/path_service.h"
20 #include "base/string_number_conversions.h"
21 #include "base/string_piece.h"
22 #include "base/string_util.h"
23 #include "base/stringprintf.h"
24 #include "base/threading/thread.h"
25 #include "base/tracked_objects.h"
26 #include "base/utf_string_conversions.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/metrics/histogram_synchronizer.h"
33 #include "chrome/browser/net/predictor_api.h"
34 #include "chrome/browser/platform_util.h"
35 #include "chrome/browser/profiles/profile.h"
36 #include "chrome/browser/profiles/profile_manager.h"
37 #include "chrome/browser/ui/browser_dialogs.h"
38 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
39 #include "chrome/common/about_handler.h"
40 #include "chrome/common/chrome_paths.h"
41 #include "chrome/common/chrome_version_info.h"
42 #include "chrome/common/jstemplate_builder.h"
43 #include "chrome/common/net/gaia/google_service_auth_error.h"
44 #include "chrome/common/render_messages.h"
45 #include "chrome/common/url_constants.h"
46 #include "content/browser/browser_thread.h"
47 #include "content/browser/gpu_process_host.h"
48 #include "content/browser/renderer_host/render_process_host.h"
49 #include "content/browser/renderer_host/render_view_host.h"
50 #include "content/common/gpu_messages.h"
51 #include "googleurl/src/gurl.h"
52 #include "grit/browser_resources.h"
53 #include "grit/chromium_strings.h"
54 #include "grit/generated_resources.h"
55 #include "grit/locale_settings.h"
56 #include "net/base/escape.h"
57 #include "ui/base/l10n/l10n_util.h"
58 #include "ui/base/resource/resource_bundle.h"
59 #include "webkit/glue/webkit_glue.h"
60 #include "webkit/glue/plugins/plugin_list.h"
61 #include "webkit/plugins/npapi/webplugininfo.h"
62
63 #ifdef CHROME_V8
64 #include "v8/include/v8.h"
65 #endif
66
67 #if defined(OS_WIN)
68 #include "chrome/browser/enumerate_modules_model_win.h"
69 #elif defined(OS_CHROMEOS)
70 #include "chrome/browser/chromeos/cros/cros_library.h"
71 #include "chrome/browser/chromeos/cros/network_library.h"
72 #include "chrome/browser/chromeos/cros/syslogs_library.h"
73 #include "chrome/browser/chromeos/login/wizard_controller.h"
74 #include "chrome/browser/chromeos/version_loader.h"
75 #include "content/browser/zygote_host_linux.h"
76 #elif defined(OS_LINUX)
77 #include "content/browser/zygote_host_linux.h"
78 #endif
79
80 #if defined(USE_TCMALLOC)
81 #include "third_party/tcmalloc/chromium/src/google/malloc_extension.h"
82 #endif
83
84 using base::Time;
85 using base::TimeDelta;
86
87 #if defined(USE_TCMALLOC)
88 // static
GetInstance()89 AboutTcmallocOutputs* AboutTcmallocOutputs::GetInstance() {
90 return Singleton<AboutTcmallocOutputs>::get();
91 }
92
AboutTcmallocOutputs()93 AboutTcmallocOutputs::AboutTcmallocOutputs() {}
94
~AboutTcmallocOutputs()95 AboutTcmallocOutputs::~AboutTcmallocOutputs() {}
96
97 // Glue between the callback task and the method in the singleton.
AboutTcmallocRendererCallback(base::ProcessId pid,const std::string & output)98 void AboutTcmallocRendererCallback(base::ProcessId pid,
99 const std::string& output) {
100 AboutTcmallocOutputs::GetInstance()->RendererCallback(pid, output);
101 }
102 #endif
103
104 namespace {
105
106 // The (alphabetized) paths used for the about pages.
107 // Note: Keep these in sync with url_constants.h
108 const char kAppCacheInternalsPath[] = "appcache-internals";
109 const char kBlobInternalsPath[] = "blob-internals";
110 const char kCreditsPath[] = "credits";
111 const char kCachePath[] = "view-http-cache";
112 #if defined(OS_WIN)
113 const char kConflictsPath[] = "conflicts";
114 #endif
115 const char kDnsPath[] = "dns";
116 const char kFlagsPath[] = "flags";
117 const char kGpuPath[] = "gpu-internals";
118 const char kHistogramsPath[] = "histograms";
119 const char kMemoryRedirectPath[] = "memory-redirect";
120 const char kMemoryPath[] = "memory";
121 const char kStatsPath[] = "stats";
122 const char kTasksPath[] = "tasks";
123 const char kTcmallocPath[] = "tcmalloc";
124 const char kTermsPath[] = "terms";
125 const char kVersionPath[] = "version";
126 const char kAboutPath[] = "about";
127 // Not about:* pages, but included to make about:about look nicer
128 const char kNetInternalsPath[] = "net-internals";
129 const char kPluginsPath[] = "plugins";
130 const char kSyncInternalsPath[] = "sync-internals";
131
132 #if defined(OS_LINUX)
133 const char kLinuxProxyConfigPath[] = "linux-proxy-config";
134 const char kSandboxPath[] = "sandbox";
135 #endif
136
137 #if defined(OS_CHROMEOS)
138 const char kNetworkPath[] = "network";
139 const char kOSCreditsPath[] = "os-credits";
140 const char kEULAPathFormat[] = "/usr/share/chromeos-assets/eula/%s/eula.html";
141 #endif
142
143 // Add path here to be included in about:about
144 const char *kAllAboutPaths[] = {
145 kAboutPath,
146 kAppCacheInternalsPath,
147 kBlobInternalsPath,
148 kCachePath,
149 kCreditsPath,
150 #if defined(OS_WIN)
151 kConflictsPath,
152 #endif
153 kDnsPath,
154 kFlagsPath,
155 kGpuPath,
156 kHistogramsPath,
157 kMemoryPath,
158 kNetInternalsPath,
159 kPluginsPath,
160 kStatsPath,
161 kSyncInternalsPath,
162 #ifdef TRACK_ALL_TASK_OBJECTS
163 kTasksPath,
164 #endif // TRACK_ALL_TASK_OBJECTS
165 kTcmallocPath,
166 kTermsPath,
167 kVersionPath,
168 #if defined(OS_LINUX)
169 kSandboxPath,
170 #endif
171 #if defined(OS_CHROMEOS)
172 kNetworkPath,
173 kOSCreditsPath,
174 #endif
175 };
176
177 // When you type about:memory, it actually loads an intermediate URL that
178 // redirects you to the final page. This avoids the problem where typing
179 // "about:memory" on the new tab page or any other page where a process
180 // transition would occur to the about URL will cause some confusion.
181 //
182 // The problem is that during the processing of the memory page, there are two
183 // processes active, the original and the destination one. This can create the
184 // impression that we're using more resources than we actually are. This
185 // redirect solves the problem by eliminating the process transition during the
186 // time that about memory is being computed.
GetAboutMemoryRedirectResponse()187 std::string GetAboutMemoryRedirectResponse() {
188 return "<meta http-equiv=\"refresh\" "
189 "content=\"0;chrome://about/memory\">";
190 }
191
192 class AboutSource : public ChromeURLDataManager::DataSource {
193 public:
194 // Creates our datasource.
195 AboutSource();
196
197 // Called when the network layer has requested a resource underneath
198 // the path we registered.
199 virtual void StartDataRequest(const std::string& path,
200 bool is_incognito,
201 int request_id);
202
GetMimeType(const std::string &) const203 virtual std::string GetMimeType(const std::string&) const {
204 return "text/html";
205 }
206
207 // Send the response data.
208 void FinishDataRequest(const std::string& html, int request_id);
209
210 private:
211 virtual ~AboutSource();
212
213 DISALLOW_COPY_AND_ASSIGN(AboutSource);
214 };
215
216 // Handling about:memory is complicated enough to encapsulate its related
217 // methods into a single class. The user should create it (on the heap) and call
218 // its |StartFetch()| method.
219 class AboutMemoryHandler : public MemoryDetails {
220 public:
AboutMemoryHandler(AboutSource * source,int request_id)221 AboutMemoryHandler(AboutSource* source, int request_id)
222 : source_(source), request_id_(request_id) {}
223
224
225 virtual void OnDetailsAvailable();
226
227 private:
~AboutMemoryHandler()228 ~AboutMemoryHandler() {}
229
230 void BindProcessMetrics(DictionaryValue* data,
231 ProcessMemoryInformation* info);
232 void AppendProcess(ListValue* child_data, ProcessMemoryInformation* info);
233
234 scoped_refptr<AboutSource> source_;
235 int request_id_;
236
237 DISALLOW_COPY_AND_ASSIGN(AboutMemoryHandler);
238 };
239
240 #if defined(OS_CHROMEOS)
241 // ChromeOSAboutVersionHandler is responsible for loading the Chrome OS
242 // version.
243 // ChromeOSAboutVersionHandler handles deleting itself once the version has
244 // been obtained and AboutSource notified.
245 class ChromeOSAboutVersionHandler {
246 public:
247 ChromeOSAboutVersionHandler(AboutSource* source, int request_id);
248
249 // Callback from chromeos::VersionLoader giving the version.
250 void OnVersion(chromeos::VersionLoader::Handle handle,
251 std::string version);
252
253 private:
254 // Where the results are fed to.
255 scoped_refptr<AboutSource> source_;
256
257 // ID identifying the request.
258 int request_id_;
259
260 // Handles asynchronously loading the version.
261 chromeos::VersionLoader loader_;
262
263 // Used to request the version.
264 CancelableRequestConsumer consumer_;
265
266 DISALLOW_COPY_AND_ASSIGN(ChromeOSAboutVersionHandler);
267 };
268
269 class ChromeOSTermsHandler
270 : public base::RefCountedThreadSafe<ChromeOSTermsHandler> {
271 public:
Start(AboutSource * source,int request_id)272 static void Start(AboutSource* source, int request_id) {
273 scoped_refptr<ChromeOSTermsHandler> handler(
274 new ChromeOSTermsHandler(source, request_id));
275 handler->StartOnUIThread();
276 }
277
278 private:
ChromeOSTermsHandler(AboutSource * source,int request_id)279 ChromeOSTermsHandler(AboutSource* source, int request_id)
280 : source_(source),
281 request_id_(request_id),
282 locale_(WizardController::GetInitialLocale()) {
283 }
284
StartOnUIThread()285 void StartOnUIThread() {
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
287 BrowserThread::PostTask(
288 BrowserThread::FILE, FROM_HERE,
289 NewRunnableMethod(this, &ChromeOSTermsHandler::LoadFileOnFileThread));
290 }
291
LoadFileOnFileThread()292 void LoadFileOnFileThread() {
293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
294 std::string path = StringPrintf(kEULAPathFormat, locale_.c_str());
295 if (!file_util::ReadFileToString(FilePath(path), &contents_)) {
296 // No EULA for given language - try en-US as default.
297 path = StringPrintf(kEULAPathFormat, "en-US");
298 if (!file_util::ReadFileToString(FilePath(path), &contents_)) {
299 // File with EULA not found, ResponseOnUIThread will load EULA from
300 // resources if contents_ is empty.
301 contents_.clear();
302 }
303 }
304 BrowserThread::PostTask(
305 BrowserThread::UI, FROM_HERE,
306 NewRunnableMethod(this, &ChromeOSTermsHandler::ResponseOnUIThread));
307 }
308
ResponseOnUIThread()309 void ResponseOnUIThread() {
310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
311 if (contents_.empty()) {
312 contents_ = ResourceBundle::GetSharedInstance().GetRawDataResource(
313 IDR_TERMS_HTML).as_string();
314 }
315 source_->FinishDataRequest(contents_, request_id_);
316 }
317
318 // Where the results are fed to.
319 scoped_refptr<AboutSource> source_;
320
321 // ID identifying the request.
322 int request_id_;
323
324 std::string locale_;
325
326 std::string contents_;
327
328 DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsHandler);
329 };
330
331 #endif
332
333 // Individual about handlers ---------------------------------------------------
334
AboutAbout()335 std::string AboutAbout() {
336 std::string html("<html><head><title>About Pages</title></head>\n"
337 "<body><h2>List of About pages</h2>\n<ul>");
338 std::vector<std::string> paths(AboutPaths());
339 for (std::vector<std::string>::const_iterator i = paths.begin();
340 i != paths.end(); ++i) {
341 html += "<li><a href='chrome://";
342 if ((*i != kAppCacheInternalsPath) &&
343 (*i != kBlobInternalsPath) &&
344 (*i != kCachePath) &&
345 #if defined(OS_WIN)
346 (*i != kConflictsPath) &&
347 #endif
348 (*i != kFlagsPath) &&
349 (*i != kGpuPath) &&
350 (*i != kNetInternalsPath) &&
351 (*i != kPluginsPath)) {
352 html += "about/";
353 }
354 html += *i + "/'>about:" + *i + "</a></li>\n";
355 }
356 const char *debug[] = { "crash", "kill", "hang", "shorthang",
357 "gpucrash", "gpuhang" };
358 html += "</ul>\n<h2>For Debug</h2>\n"
359 "<p>The following pages are for debugging purposes only. Because they "
360 "crash or hang the renderer, they're not linked directly; you can type "
361 "them into the address bar if you need them.</p>\n<ul>";
362 for (size_t i = 0; i < arraysize(debug); i++)
363 html += "<li>about:" + std::string(debug[i]) + "</li>\n";
364 html += "</ul>\n</body></html>";
365 return html;
366 }
367
368 #if defined(OS_CHROMEOS)
369
370 // Html output helper functions
371 // TODO(stevenjb): L10N this.
372
373 // Helper function to wrap Html with <th> tag.
WrapWithTH(std::string text)374 static std::string WrapWithTH(std::string text) {
375 return "<th>" + text + "</th>";
376 }
377
378 // Helper function to wrap Html with <td> tag.
WrapWithTD(std::string text)379 static std::string WrapWithTD(std::string text) {
380 return "<td>" + text + "</td>";
381 }
382
383 // Helper function to create an Html table header for a Network.
ToHtmlTableHeader(const chromeos::Network * network)384 static std::string ToHtmlTableHeader(const chromeos::Network* network) {
385 std::string str =
386 WrapWithTH("Name") +
387 WrapWithTH("Active") +
388 WrapWithTH("State");
389 if (network->type() == chromeos::TYPE_WIFI ||
390 network->type() == chromeos::TYPE_CELLULAR) {
391 str += WrapWithTH("Auto-Connect");
392 str += WrapWithTH("Strength");
393 }
394 if (network->type() == chromeos::TYPE_WIFI) {
395 str += WrapWithTH("Encryption");
396 str += WrapWithTH("Passphrase");
397 str += WrapWithTH("Identity");
398 str += WrapWithTH("Certificate");
399 }
400 if (network->type() == chromeos::TYPE_CELLULAR) {
401 str += WrapWithTH("Technology");
402 str += WrapWithTH("Connectivity");
403 str += WrapWithTH("Activation");
404 str += WrapWithTH("Roaming");
405 }
406 if (network->type() == chromeos::TYPE_VPN) {
407 str += WrapWithTH("Host");
408 str += WrapWithTH("Provider Type");
409 str += WrapWithTH("PSK Passphrase");
410 str += WrapWithTH("Username");
411 str += WrapWithTH("User Passphrase");
412 }
413 str += WrapWithTH("Error");
414 str += WrapWithTH("IP Address");
415 return str;
416 }
417
418 // Helper function to create an Html table row for a Network.
ToHtmlTableRow(const chromeos::Network * network)419 static std::string ToHtmlTableRow(const chromeos::Network* network) {
420 std::string str =
421 WrapWithTD(network->name()) +
422 WrapWithTD(base::IntToString(network->is_active())) +
423 WrapWithTD(network->GetStateString());
424 if (network->type() == chromeos::TYPE_WIFI ||
425 network->type() == chromeos::TYPE_CELLULAR) {
426 const chromeos::WirelessNetwork* wireless =
427 static_cast<const chromeos::WirelessNetwork*>(network);
428 str += WrapWithTD(base::IntToString(wireless->auto_connect()));
429 str += WrapWithTD(base::IntToString(wireless->strength()));
430 }
431 if (network->type() == chromeos::TYPE_WIFI) {
432 const chromeos::WifiNetwork* wifi =
433 static_cast<const chromeos::WifiNetwork*>(network);
434 str += WrapWithTD(wifi->GetEncryptionString());
435 str += WrapWithTD(std::string(wifi->passphrase().length(), '*'));
436 str += WrapWithTD(wifi->identity());
437 str += WrapWithTD(wifi->cert_path());
438 }
439 if (network->type() == chromeos::TYPE_CELLULAR) {
440 const chromeos::CellularNetwork* cell =
441 static_cast<const chromeos::CellularNetwork*>(network);
442 str += WrapWithTH(cell->GetNetworkTechnologyString());
443 str += WrapWithTH(cell->GetConnectivityStateString());
444 str += WrapWithTH(cell->GetActivationStateString());
445 str += WrapWithTH(cell->GetRoamingStateString());
446 }
447 if (network->type() == chromeos::TYPE_VPN) {
448 const chromeos::VirtualNetwork* vpn =
449 static_cast<const chromeos::VirtualNetwork*>(network);
450 str += WrapWithTH(vpn->server_hostname());
451 str += WrapWithTH(vpn->GetProviderTypeString());
452 str += WrapWithTD(std::string(vpn->psk_passphrase().length(), '*'));
453 str += WrapWithTH(vpn->username());
454 str += WrapWithTD(std::string(vpn->user_passphrase().length(), '*'));
455 }
456 str += WrapWithTD(network->failed() ? network->GetErrorString() : "");
457 str += WrapWithTD(network->ip_address());
458 return str;
459 }
460
GetNetworkHtmlInfo(int refresh)461 std::string GetNetworkHtmlInfo(int refresh) {
462 chromeos::NetworkLibrary* cros =
463 chromeos::CrosLibrary::Get()->GetNetworkLibrary();
464 std::string output;
465 output.append("<html><head><title>About Network</title>");
466 if (refresh > 0)
467 output.append("<meta http-equiv=\"refresh\" content=\"" +
468 base::IntToString(refresh) + "\"/>");
469 output.append("</head><body>");
470 if (refresh > 0) {
471 output.append("(Auto-refreshing page every " +
472 base::IntToString(refresh) + "s)");
473 } else {
474 output.append("(To auto-refresh this page: about:network/<secs>)");
475 }
476
477 if (cros->ethernet_enabled()) {
478 output.append("<h3>Ethernet:</h3><table border=1>");
479 const chromeos::EthernetNetwork* ethernet = cros->ethernet_network();
480 if (ethernet) {
481 output.append("<tr>" + ToHtmlTableHeader(ethernet) + "</tr>");
482 output.append("<tr>" + ToHtmlTableRow(ethernet) + "</tr>");
483 }
484 }
485
486 if (cros->wifi_enabled()) {
487 output.append("</table><h3>Wifi Networks:</h3><table border=1>");
488 const chromeos::WifiNetworkVector& wifi_networks = cros->wifi_networks();
489 for (size_t i = 0; i < wifi_networks.size(); ++i) {
490 if (i == 0)
491 output.append("<tr>" + ToHtmlTableHeader(wifi_networks[i]) +
492 "</tr>");
493 output.append("<tr>" + ToHtmlTableRow(wifi_networks[i]) + "</tr>");
494 }
495 }
496
497 if (cros->cellular_enabled()) {
498 output.append("</table><h3>Cellular Networks:</h3><table border=1>");
499 const chromeos::CellularNetworkVector& cellular_networks =
500 cros->cellular_networks();
501 for (size_t i = 0; i < cellular_networks.size(); ++i) {
502 if (i == 0)
503 output.append("<tr>" + ToHtmlTableHeader(cellular_networks[i]) +
504 "</tr>");
505 output.append("<tr>" + ToHtmlTableRow(cellular_networks[i]) + "</tr>");
506 }
507 }
508
509 {
510 output.append("</table><h3>Virtual Networks:</h3><table border=1>");
511 const chromeos::VirtualNetworkVector& virtual_networks =
512 cros->virtual_networks();
513 for (size_t i = 0; i < virtual_networks.size(); ++i) {
514 if (i == 0)
515 output.append("<tr>" + ToHtmlTableHeader(virtual_networks[i]) +
516 "</tr>");
517 output.append("<tr>" + ToHtmlTableRow(virtual_networks[i]) + "</tr>");
518 }
519 }
520
521 {
522 output.append(
523 "</table><h3>Remembered Wi-Fi Networks:</h3><table border=1>");
524 const chromeos::WifiNetworkVector& remembered_wifi_networks =
525 cros->remembered_wifi_networks();
526 for (size_t i = 0; i < remembered_wifi_networks.size(); ++i) {
527 if (i == 0)
528 output.append("<tr>" +
529 ToHtmlTableHeader(remembered_wifi_networks[i]) + "</tr>");
530 output.append("<tr>" + ToHtmlTableRow(remembered_wifi_networks[i]) +
531 "</tr>");
532 }
533 }
534
535 output.append("</table></body></html>");
536 return output;
537 }
538
AboutNetwork(const std::string & query)539 std::string AboutNetwork(const std::string& query) {
540 int refresh;
541 base::StringToInt(query, &refresh);
542 return GetNetworkHtmlInfo(refresh);
543 }
544 #endif
545
546 // AboutDnsHandler bounces the request back to the IO thread to collect
547 // the DNS information.
548 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
549 public:
Start(AboutSource * source,int request_id)550 static void Start(AboutSource* source, int request_id) {
551 scoped_refptr<AboutDnsHandler> handler(
552 new AboutDnsHandler(source, request_id));
553 handler->StartOnUIThread();
554 }
555
556 private:
AboutDnsHandler(AboutSource * source,int request_id)557 AboutDnsHandler(AboutSource* source, int request_id)
558 : source_(source),
559 request_id_(request_id) {
560 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
561 }
562
563 // Calls FinishOnUIThread() on completion.
StartOnUIThread()564 void StartOnUIThread() {
565 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
566 BrowserThread::PostTask(
567 BrowserThread::IO, FROM_HERE,
568 NewRunnableMethod(this, &AboutDnsHandler::StartOnIOThread));
569 }
570
StartOnIOThread()571 void StartOnIOThread() {
572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
573
574 std::string data;
575 chrome_browser_net::PredictorGetHtmlInfo(&data);
576
577 BrowserThread::PostTask(
578 BrowserThread::UI, FROM_HERE,
579 NewRunnableMethod(this, &AboutDnsHandler::FinishOnUIThread, data));
580 }
581
FinishOnUIThread(const std::string & data)582 void FinishOnUIThread(const std::string& data) {
583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
584 source_->FinishDataRequest(data, request_id_);
585 }
586
587 // Where the results are fed to.
588 scoped_refptr<AboutSource> source_;
589
590 // ID identifying the request.
591 int request_id_;
592
593 DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler);
594 };
595
596 #if defined(USE_TCMALLOC)
AboutTcmalloc(const std::string & query)597 std::string AboutTcmalloc(const std::string& query) {
598 std::string data;
599 AboutTcmallocOutputsType* outputs =
600 AboutTcmallocOutputs::GetInstance()->outputs();
601
602 // Display any stats for which we sent off requests the last time.
603 data.append("<html><head><title>About tcmalloc</title></head><body>\n");
604 data.append("<p>Stats as of last page load;");
605 data.append("reload to get stats as of this page load.</p>\n");
606 data.append("<table width=\"100%\">\n");
607 for (AboutTcmallocOutputsType::const_iterator oit = outputs->begin();
608 oit != outputs->end();
609 oit++) {
610 data.append("<tr><td bgcolor=\"yellow\">");
611 data.append(oit->first);
612 data.append("</td></tr>\n");
613 data.append("<tr><td><pre>\n");
614 data.append(oit->second);
615 data.append("</pre></td></tr>\n");
616 }
617 data.append("</table>\n");
618 data.append("</body></html>\n");
619
620 // Reset our collector singleton.
621 outputs->clear();
622
623 // Populate the collector with stats from the local browser process
624 // and send off requests to all the renderer processes.
625 char buffer[1024 * 32];
626 MallocExtension::instance()->GetStats(buffer, sizeof(buffer));
627 std::string browser("Browser");
628 AboutTcmallocOutputs::GetInstance()->SetOutput(browser, buffer);
629 RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
630 while (!it.IsAtEnd()) {
631 it.GetCurrentValue()->Send(new ViewMsg_GetRendererTcmalloc);
632 it.Advance();
633 }
634
635 return data;
636 }
637 #endif
638
AboutHistograms(const std::string & query)639 std::string AboutHistograms(const std::string& query) {
640 TimeDelta wait_time = TimeDelta::FromMilliseconds(10000);
641
642 HistogramSynchronizer* current_synchronizer =
643 HistogramSynchronizer::CurrentSynchronizer();
644 DCHECK(current_synchronizer != NULL);
645 current_synchronizer->FetchRendererHistogramsSynchronously(wait_time);
646
647 std::string data;
648 base::StatisticsRecorder::WriteHTMLGraph(query, &data);
649 return data;
650 }
651
AboutMemory(AboutSource * source,int request_id)652 void AboutMemory(AboutSource* source, int request_id) {
653 // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want the
654 // refcount to be greater than 0.
655 scoped_refptr<AboutMemoryHandler>
656 handler(new AboutMemoryHandler(source, request_id));
657 handler->StartFetch();
658 }
659
660 #ifdef TRACK_ALL_TASK_OBJECTS
AboutObjects(const std::string & query)661 static std::string AboutObjects(const std::string& query) {
662 std::string data;
663 tracked_objects::ThreadData::WriteHTML(query, &data);
664 return data;
665 }
666 #endif // TRACK_ALL_TASK_OBJECTS
667
668 // Handler for filling in the "about:stats" page, as called by the browser's
669 // About handler processing.
670 // |query| is roughly the query string of the about:stats URL.
671 // Returns a string containing the HTML to render for the about:stats page.
672 // Conditional Output:
673 // if |query| is "json", returns a JSON format of all counters.
674 // if |query| is "raw", returns plain text of counter deltas.
675 // otherwise, returns HTML with pretty JS/HTML to display the data.
AboutStats(const std::string & query)676 std::string AboutStats(const std::string& query) {
677 // We keep the DictionaryValue tree live so that we can do delta
678 // stats computations across runs.
679 static DictionaryValue root;
680 static base::TimeTicks last_sample_time = base::TimeTicks::Now();
681
682 base::TimeTicks now = base::TimeTicks::Now();
683 base::TimeDelta time_since_last_sample = now - last_sample_time;
684 last_sample_time = now;
685
686 base::StatsTable* table = base::StatsTable::current();
687 if (!table)
688 return std::string();
689
690 // We maintain two lists - one for counters and one for timers.
691 // Timers actually get stored on both lists.
692 ListValue* counters;
693 if (!root.GetList("counters", &counters)) {
694 counters = new ListValue();
695 root.Set("counters", counters);
696 }
697
698 ListValue* timers;
699 if (!root.GetList("timers", &timers)) {
700 timers = new ListValue();
701 root.Set("timers", timers);
702 }
703
704 // NOTE: Counters start at index 1.
705 for (int index = 1; index <= table->GetMaxCounters(); index++) {
706 // Get the counter's full name
707 std::string full_name = table->GetRowName(index);
708 if (full_name.length() == 0)
709 break;
710 DCHECK_EQ(':', full_name[1]);
711 char counter_type = full_name[0];
712 std::string name = full_name.substr(2);
713
714 // JSON doesn't allow '.' in names.
715 size_t pos;
716 while ((pos = name.find(".")) != std::string::npos)
717 name.replace(pos, 1, ":");
718
719 // Try to see if this name already exists.
720 DictionaryValue* counter = NULL;
721 for (size_t scan_index = 0;
722 scan_index < counters->GetSize(); scan_index++) {
723 DictionaryValue* dictionary;
724 if (counters->GetDictionary(scan_index, &dictionary)) {
725 std::string scan_name;
726 if (dictionary->GetString("name", &scan_name) && scan_name == name) {
727 counter = dictionary;
728 }
729 } else {
730 NOTREACHED(); // Should always be there
731 }
732 }
733
734 if (counter == NULL) {
735 counter = new DictionaryValue();
736 counter->SetString("name", name);
737 counters->Append(counter);
738 }
739
740 switch (counter_type) {
741 case 'c':
742 {
743 int new_value = table->GetRowValue(index);
744 int prior_value = 0;
745 int delta = 0;
746 if (counter->GetInteger("value", &prior_value)) {
747 delta = new_value - prior_value;
748 }
749 counter->SetInteger("value", new_value);
750 counter->SetInteger("delta", delta);
751 }
752 break;
753 case 'm':
754 {
755 // TODO(mbelshe): implement me.
756 }
757 break;
758 case 't':
759 {
760 int time = table->GetRowValue(index);
761 counter->SetInteger("time", time);
762
763 // Store this on the timers list as well.
764 timers->Append(counter);
765 }
766 break;
767 default:
768 NOTREACHED();
769 }
770 }
771
772 std::string data;
773 if (query == "json") {
774 base::JSONWriter::WriteWithOptionalEscape(&root, true, false, &data);
775 } else if (query == "raw") {
776 // Dump the raw counters which have changed in text format.
777 data = "<pre>";
778 data.append(StringPrintf("Counter changes in the last %ldms\n",
779 static_cast<long int>(time_since_last_sample.InMilliseconds())));
780 for (size_t i = 0; i < counters->GetSize(); ++i) {
781 Value* entry = NULL;
782 bool rv = counters->Get(i, &entry);
783 if (!rv)
784 continue; // None of these should fail.
785 DictionaryValue* counter = static_cast<DictionaryValue*>(entry);
786 int delta;
787 rv = counter->GetInteger("delta", &delta);
788 if (!rv)
789 continue;
790 if (delta > 0) {
791 std::string name;
792 rv = counter->GetString("name", &name);
793 if (!rv)
794 continue;
795 int value;
796 rv = counter->GetInteger("value", &value);
797 if (!rv)
798 continue;
799 data.append(name);
800 data.append(":");
801 data.append(base::IntToString(delta));
802 data.append("\n");
803 }
804 }
805 data.append("</pre>");
806 } else {
807 // Get about_stats.html and process a pretty page.
808 static const base::StringPiece stats_html(
809 ResourceBundle::GetSharedInstance().GetRawDataResource(
810 IDR_ABOUT_STATS_HTML));
811
812 // Create jstemplate and return.
813 data = jstemplate_builder::GetTemplateHtml(
814 stats_html, &root, "t" /* template root node id */);
815
816 // Clear the timer list since we stored the data in the timers list as well.
817 for (int index = static_cast<int>(timers->GetSize())-1; index >= 0;
818 index--) {
819 Value* value;
820 timers->Remove(index, &value);
821 // We don't care about the value pointer; it's still tracked
822 // on the counters list.
823 }
824 }
825
826 return data;
827 }
828
829 #if defined(OS_LINUX)
AboutLinuxProxyConfig()830 std::string AboutLinuxProxyConfig() {
831 std::string data;
832 data.append("<!DOCTYPE HTML>\n");
833 data.append("<html><head><meta charset=\"utf-8\"><title>");
834 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE));
835 data.append("</title>");
836 data.append("<style>body { max-width: 70ex; padding: 2ex 5ex; }</style>");
837 data.append("</head><body>\n");
838 FilePath binary = CommandLine::ForCurrentProcess()->GetProgram();
839 data.append(l10n_util::GetStringFUTF8(
840 IDS_ABOUT_LINUX_PROXY_CONFIG_BODY,
841 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
842 ASCIIToUTF16(binary.BaseName().value())));
843 data.append("</body></html>\n");
844 return data;
845 }
846
AboutSandboxRow(std::string * data,const std::string & prefix,int name_id,bool good)847 void AboutSandboxRow(std::string* data, const std::string& prefix, int name_id,
848 bool good) {
849 data->append("<tr><td>");
850 data->append(prefix);
851 data->append(l10n_util::GetStringUTF8(name_id));
852 if (good) {
853 data->append("</td><td style=\"color: green;\">");
854 data->append(
855 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
856 } else {
857 data->append("</td><td style=\"color: red;\">");
858 data->append(
859 l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
860 }
861 data->append("</td></tr>");
862 }
863
AboutSandbox()864 std::string AboutSandbox() {
865 std::string data;
866 data.append("<!DOCTYPE HTML>\n");
867 data.append("<html><head><meta charset=\"utf-8\"><title>");
868 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
869 data.append("</title>");
870 data.append("</head><body>\n");
871 data.append("<h1>");
872 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
873 data.append("</h1>");
874
875 const int status = ZygoteHost::GetInstance()->sandbox_status();
876
877 data.append("<table>");
878
879 AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SUID_SANDBOX,
880 status & ZygoteHost::kSandboxSUID);
881 if (status & ZygoteHost::kSandboxPIDNS) {
882 AboutSandboxRow(&data, " ", IDS_ABOUT_SANDBOX_PID_NAMESPACES,
883 status & ZygoteHost::kSandboxPIDNS);
884 AboutSandboxRow(&data, " ", IDS_ABOUT_SANDBOX_NET_NAMESPACES,
885 status & ZygoteHost::kSandboxNetNS);
886 }
887 AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SECCOMP_SANDBOX,
888 status & ZygoteHost::kSandboxSeccomp);
889
890 data.append("</table>");
891
892 bool good = ((status & ZygoteHost::kSandboxSUID) &&
893 (status & ZygoteHost::kSandboxPIDNS)) ||
894 (status & ZygoteHost::kSandboxSeccomp);
895 if (good) {
896 data.append("<p style=\"color: green\">");
897 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK));
898 } else {
899 data.append("<p style=\"color: red\">");
900 data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD));
901 }
902 data.append("</p>");
903
904 data.append("</body></html>\n");
905 return data;
906 }
907 #endif
908
AboutVersion(DictionaryValue * localized_strings)909 std::string AboutVersion(DictionaryValue* localized_strings) {
910 localized_strings->SetString("title",
911 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_TITLE));
912 chrome::VersionInfo version_info;
913
914 std::string webkit_version = webkit_glue::GetWebKitVersion();
915 #ifdef CHROME_V8
916 std::string js_version(v8::V8::GetVersion());
917 std::string js_engine = "V8";
918 #else
919 std::string js_version = webkit_version;
920 std::string js_engine = "JavaScriptCore";
921 #endif
922
923 localized_strings->SetString("name",
924 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
925 localized_strings->SetString("version", version_info.Version());
926 // Bug 79458: Need to evaluate the use of getting the version string on
927 // this thread.
928 base::ThreadRestrictions::ScopedAllowIO allow_io;
929 localized_strings->SetString("version_modifier",
930 platform_util::GetVersionStringModifier());
931 localized_strings->SetString("js_engine", js_engine);
932 localized_strings->SetString("js_version", js_version);
933
934 // Obtain the version of the first enabled Flash plugin.
935 std::vector<webkit::npapi::WebPluginInfo> info_array;
936 webkit::npapi::PluginList::Singleton()->GetPluginInfoArray(
937 GURL(), "application/x-shockwave-flash", false, &info_array, NULL);
938 string16 flash_version =
939 l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN);
940 for (size_t i = 0; i < info_array.size(); ++i) {
941 if (webkit::npapi::IsPluginEnabled(info_array[i])) {
942 flash_version = info_array[i].version;
943 break;
944 }
945 }
946 localized_strings->SetString("flash_plugin", "Flash");
947 localized_strings->SetString("flash_version", flash_version);
948 localized_strings->SetString("webkit_version", webkit_version);
949 localized_strings->SetString("company",
950 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COMPANY_NAME));
951 localized_strings->SetString("copyright",
952 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COPYRIGHT));
953 localized_strings->SetString("cl", version_info.LastChange());
954 localized_strings->SetString("official",
955 l10n_util::GetStringUTF16(
956 version_info.IsOfficialBuild() ?
957 IDS_ABOUT_VERSION_OFFICIAL
958 : IDS_ABOUT_VERSION_UNOFFICIAL));
959 localized_strings->SetString("user_agent_name",
960 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_USER_AGENT));
961 localized_strings->SetString("useragent", webkit_glue::GetUserAgent(GURL()));
962 localized_strings->SetString("command_line_name",
963 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COMMAND_LINE));
964
965 #if defined(OS_WIN)
966 localized_strings->SetString("command_line",
967 WideToUTF16(CommandLine::ForCurrentProcess()->command_line_string()));
968 #elif defined(OS_POSIX)
969 std::string command_line = "";
970 typedef std::vector<std::string> ArgvList;
971 const ArgvList& argv = CommandLine::ForCurrentProcess()->argv();
972 for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end(); iter++)
973 command_line += " " + *iter;
974 // TODO(viettrungluu): |command_line| could really have any encoding, whereas
975 // below we assumes it's UTF-8.
976 localized_strings->SetString("command_line", command_line);
977 #endif
978
979 base::StringPiece version_html(
980 ResourceBundle::GetSharedInstance().GetRawDataResource(
981 IDR_ABOUT_VERSION_HTML));
982
983 return jstemplate_builder::GetTemplatesHtml(
984 version_html, localized_strings, "t" /* template root node id */);
985 }
986
VersionNumberToString(uint32 value)987 std::string VersionNumberToString(uint32 value) {
988 int hi = (value >> 8) & 0xff;
989 int low = value & 0xff;
990 return base::IntToString(hi) + "." + base::IntToString(low);
991 }
992
993 // AboutSource -----------------------------------------------------------------
994
AboutSource()995 AboutSource::AboutSource()
996 : DataSource(chrome::kAboutScheme, MessageLoop::current()) {
997 }
998
~AboutSource()999 AboutSource::~AboutSource() {
1000 }
1001
StartDataRequest(const std::string & path_raw,bool is_incognito,int request_id)1002 void AboutSource::StartDataRequest(const std::string& path_raw,
1003 bool is_incognito, int request_id) {
1004 std::string path = path_raw;
1005 std::string info;
1006 if (path.find("/") != std::string::npos) {
1007 size_t pos = path.find("/");
1008 info = path.substr(pos + 1, path.length() - (pos + 1));
1009 path = path.substr(0, pos);
1010 }
1011 path = StringToLowerASCII(path);
1012
1013 std::string response;
1014 if (path == kDnsPath) {
1015 AboutDnsHandler::Start(this, request_id);
1016 return;
1017 } else if (path == kHistogramsPath) {
1018 response = AboutHistograms(info);
1019 } else if (path == kMemoryPath) {
1020 AboutMemory(this, request_id);
1021 return;
1022 } else if (path == kMemoryRedirectPath) {
1023 response = GetAboutMemoryRedirectResponse();
1024 #ifdef TRACK_ALL_TASK_OBJECTS
1025 } else if (path == kTasksPath) {
1026 response = AboutObjects(info);
1027 #endif
1028 } else if (path == kStatsPath) {
1029 response = AboutStats(info);
1030 #if defined(USE_TCMALLOC)
1031 } else if (path == kTcmallocPath) {
1032 response = AboutTcmalloc(info);
1033 #endif
1034 } else if (path == kVersionPath || path.empty()) {
1035 #if defined(OS_CHROMEOS)
1036 new ChromeOSAboutVersionHandler(this, request_id);
1037 return;
1038 #else
1039 DictionaryValue value;
1040 response = AboutVersion(&value);
1041 #endif
1042 } else if (path == kCreditsPath) {
1043 response = ResourceBundle::GetSharedInstance().GetRawDataResource(
1044 IDR_CREDITS_HTML).as_string();
1045 } else if (path == kAboutPath) {
1046 response = AboutAbout();
1047 #if defined(OS_CHROMEOS)
1048 } else if (path == kOSCreditsPath) {
1049 response = ResourceBundle::GetSharedInstance().GetRawDataResource(
1050 IDR_OS_CREDITS_HTML).as_string();
1051 } else if (path == kNetworkPath) {
1052 response = AboutNetwork(info);
1053 #endif
1054 } else if (path == kTermsPath) {
1055 #if defined(OS_CHROMEOS)
1056 ChromeOSTermsHandler::Start(this, request_id);
1057 return;
1058 #else
1059 response = ResourceBundle::GetSharedInstance().GetRawDataResource(
1060 IDR_TERMS_HTML).as_string();
1061 #endif
1062 #if defined(OS_LINUX)
1063 } else if (path == kLinuxProxyConfigPath) {
1064 response = AboutLinuxProxyConfig();
1065 } else if (path == kSandboxPath) {
1066 response = AboutSandbox();
1067 #endif
1068 }
1069
1070 FinishDataRequest(response, request_id);
1071 }
1072
FinishDataRequest(const std::string & response,int request_id)1073 void AboutSource::FinishDataRequest(const std::string& response,
1074 int request_id) {
1075 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
1076 html_bytes->data.resize(response.size());
1077 std::copy(response.begin(), response.end(), html_bytes->data.begin());
1078 SendResponse(request_id, html_bytes);
1079 }
1080
1081 // AboutMemoryHandler ----------------------------------------------------------
1082
1083 // Helper for AboutMemory to bind results from a ProcessMetrics object
1084 // to a DictionaryValue. Fills ws_usage and comm_usage so that the objects
1085 // can be used in caller's scope (e.g for appending to a net total).
BindProcessMetrics(DictionaryValue * data,ProcessMemoryInformation * info)1086 void AboutMemoryHandler::BindProcessMetrics(DictionaryValue* data,
1087 ProcessMemoryInformation* info) {
1088 DCHECK(data && info);
1089
1090 // Bind metrics to dictionary.
1091 data->SetInteger("ws_priv", static_cast<int>(info->working_set.priv));
1092 data->SetInteger("ws_shareable",
1093 static_cast<int>(info->working_set.shareable));
1094 data->SetInteger("ws_shared", static_cast<int>(info->working_set.shared));
1095 data->SetInteger("comm_priv", static_cast<int>(info->committed.priv));
1096 data->SetInteger("comm_map", static_cast<int>(info->committed.mapped));
1097 data->SetInteger("comm_image", static_cast<int>(info->committed.image));
1098 data->SetInteger("pid", info->pid);
1099 data->SetString("version", info->version);
1100 data->SetInteger("processes", info->num_processes);
1101 }
1102
1103 // Helper for AboutMemory to append memory usage information for all
1104 // sub-processes (i.e. renderers, plugins) used by Chrome.
AppendProcess(ListValue * child_data,ProcessMemoryInformation * info)1105 void AboutMemoryHandler::AppendProcess(ListValue* child_data,
1106 ProcessMemoryInformation* info) {
1107 DCHECK(child_data && info);
1108
1109 // Append a new DictionaryValue for this renderer to our list.
1110 DictionaryValue* child = new DictionaryValue();
1111 child_data->Append(child);
1112 BindProcessMetrics(child, info);
1113
1114 std::string child_label(
1115 ChildProcessInfo::GetFullTypeNameInEnglish(info->type,
1116 info->renderer_type));
1117 if (info->is_diagnostics)
1118 child_label.append(" (diagnostics)");
1119 child->SetString("child_name", child_label);
1120 ListValue* titles = new ListValue();
1121 child->Set("titles", titles);
1122 for (size_t i = 0; i < info->titles.size(); ++i)
1123 titles->Append(new StringValue(info->titles[i]));
1124 }
1125
1126
OnDetailsAvailable()1127 void AboutMemoryHandler::OnDetailsAvailable() {
1128 // the root of the JSON hierarchy for about:memory jstemplate
1129 DictionaryValue root;
1130 ListValue* browsers = new ListValue();
1131 root.Set("browsers", browsers);
1132
1133 const std::vector<ProcessData>& browser_processes = processes();
1134
1135 // Aggregate per-process data into browser summary data.
1136 std::wstring log_string;
1137 for (size_t index = 0; index < browser_processes.size(); index++) {
1138 if (browser_processes[index].processes.empty())
1139 continue;
1140
1141 // Sum the information for the processes within this browser.
1142 ProcessMemoryInformation aggregate;
1143 ProcessMemoryInformationList::const_iterator iterator;
1144 iterator = browser_processes[index].processes.begin();
1145 aggregate.pid = iterator->pid;
1146 aggregate.version = iterator->version;
1147 while (iterator != browser_processes[index].processes.end()) {
1148 if (!iterator->is_diagnostics ||
1149 browser_processes[index].processes.size() == 1) {
1150 aggregate.working_set.priv += iterator->working_set.priv;
1151 aggregate.working_set.shared += iterator->working_set.shared;
1152 aggregate.working_set.shareable += iterator->working_set.shareable;
1153 aggregate.committed.priv += iterator->committed.priv;
1154 aggregate.committed.mapped += iterator->committed.mapped;
1155 aggregate.committed.image += iterator->committed.image;
1156 aggregate.num_processes++;
1157 }
1158 ++iterator;
1159 }
1160 DictionaryValue* browser_data = new DictionaryValue();
1161 browsers->Append(browser_data);
1162 browser_data->SetString("name", browser_processes[index].name);
1163
1164 BindProcessMetrics(browser_data, &aggregate);
1165
1166 // We log memory info as we record it.
1167 if (log_string.length() > 0)
1168 log_string.append(L", ");
1169 log_string.append(UTF16ToWide(browser_processes[index].name));
1170 log_string.append(L", ");
1171 log_string.append(UTF8ToWide(
1172 base::Int64ToString(aggregate.working_set.priv)));
1173 log_string.append(L", ");
1174 log_string.append(UTF8ToWide(
1175 base::Int64ToString(aggregate.working_set.shared)));
1176 log_string.append(L", ");
1177 log_string.append(UTF8ToWide(
1178 base::Int64ToString(aggregate.working_set.shareable)));
1179 }
1180 if (log_string.length() > 0)
1181 VLOG(1) << "memory: " << log_string;
1182
1183 // Set the browser & renderer detailed process data.
1184 DictionaryValue* browser_data = new DictionaryValue();
1185 root.Set("browzr_data", browser_data);
1186 ListValue* child_data = new ListValue();
1187 root.Set("child_data", child_data);
1188
1189 ProcessData process = browser_processes[0]; // Chrome is the first browser.
1190 root.SetString("current_browser_name", process.name);
1191
1192 for (size_t index = 0; index < process.processes.size(); index++) {
1193 if (process.processes[index].type == ChildProcessInfo::BROWSER_PROCESS)
1194 BindProcessMetrics(browser_data, &process.processes[index]);
1195 else
1196 AppendProcess(child_data, &process.processes[index]);
1197 }
1198
1199 root.SetBoolean("show_other_browsers",
1200 browser_defaults::kShowOtherBrowsersInAboutMemory);
1201
1202 // Get about_memory.html
1203 static const base::StringPiece memory_html(
1204 ResourceBundle::GetSharedInstance().GetRawDataResource(
1205 IDR_ABOUT_MEMORY_HTML));
1206
1207 // Create jstemplate and return.
1208 std::string template_html = jstemplate_builder::GetTemplateHtml(
1209 memory_html, &root, "t" /* template root node id */);
1210
1211 source_->FinishDataRequest(template_html, request_id_);
1212 }
1213
1214 #if defined(OS_CHROMEOS)
1215 // ChromeOSAboutVersionHandler -----------------------------------------------
1216
ChromeOSAboutVersionHandler(AboutSource * source,int request_id)1217 ChromeOSAboutVersionHandler::ChromeOSAboutVersionHandler(AboutSource* source,
1218 int request_id)
1219 : source_(source),
1220 request_id_(request_id) {
1221 loader_.EnablePlatformVersions(true);
1222 loader_.GetVersion(&consumer_,
1223 NewCallback(this, &ChromeOSAboutVersionHandler::OnVersion),
1224 chromeos::VersionLoader::VERSION_FULL);
1225 }
1226
OnVersion(chromeos::VersionLoader::Handle handle,std::string version)1227 void ChromeOSAboutVersionHandler::OnVersion(
1228 chromeos::VersionLoader::Handle handle,
1229 std::string version) {
1230 DictionaryValue localized_strings;
1231 localized_strings.SetString("os_name",
1232 l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME));
1233 localized_strings.SetString("os_version", version);
1234 localized_strings.SetBoolean("is_chrome_os", true);
1235 source_->FinishDataRequest(AboutVersion(&localized_strings), request_id_);
1236
1237 // CancelableRequestProvider isn't happy when it's deleted and servicing a
1238 // task, so we delay the deletion.
1239 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
1240 }
1241
1242 #endif
1243
1244 // Returns true if |url|'s spec starts with |about_specifier|, and is
1245 // terminated by the start of a path.
StartsWithAboutSpecifier(const GURL & url,const char * about_specifier)1246 bool StartsWithAboutSpecifier(const GURL& url, const char* about_specifier) {
1247 return StartsWithASCII(url.spec(), about_specifier, true) &&
1248 (url.spec().size() == strlen(about_specifier) ||
1249 url.spec()[strlen(about_specifier)] == '/');
1250 }
1251
1252 // Transforms a URL of the form "about:foo/XXX" to <url_prefix> + "XXX".
RemapAboutURL(const std::string & url_prefix,const GURL & url)1253 GURL RemapAboutURL(const std::string& url_prefix, const GURL& url) {
1254 std::string path;
1255 size_t split = url.spec().find('/');
1256 if (split != std::string::npos)
1257 path = url.spec().substr(split + 1);
1258 return GURL(url_prefix + path);
1259 }
1260
1261 } // namespace
1262
1263 // -----------------------------------------------------------------------------
1264
WillHandleBrowserAboutURL(GURL * url,Profile * profile)1265 bool WillHandleBrowserAboutURL(GURL* url, Profile* profile) {
1266 // We only handle about: schemes.
1267 if (!url->SchemeIs(chrome::kAboutScheme))
1268 return false;
1269
1270 // about:blank is special. Frames are allowed to access about:blank,
1271 // but they are not allowed to access other types of about pages.
1272 // Just ignore the about:blank and let the TAB_CONTENTS_WEB handle it.
1273 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutBlankURL))
1274 return false;
1275
1276 // Rewrite about:cache/* URLs to chrome://view-http-cache/*
1277 if (StartsWithAboutSpecifier(*url, chrome::kAboutCacheURL)) {
1278 *url = RemapAboutURL(chrome::kNetworkViewCacheURL, *url);
1279 return true;
1280 }
1281
1282 #if defined(OS_WIN)
1283 // Rewrite about:conflicts/* URLs to chrome://conflicts/*
1284 if (StartsWithAboutSpecifier(*url, chrome::kAboutConflicts)) {
1285 *url = GURL(chrome::kChromeUIConflictsURL);
1286 return true;
1287 }
1288 #endif
1289
1290 // Rewrite about:flags to chrome://flags/.
1291 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutFlagsURL)) {
1292 *url = GURL(chrome::kChromeUIFlagsURL);
1293 return true;
1294 }
1295
1296 // Rewrite about:net-internals/* URLs to chrome://net-internals/*
1297 if (StartsWithAboutSpecifier(*url, chrome::kAboutNetInternalsURL)) {
1298 *url = RemapAboutURL(chrome::kNetworkViewInternalsURL, *url);
1299 return true;
1300 }
1301
1302 // Rewrite about:gpu/* URLs to chrome://gpu-internals/*
1303 if (StartsWithAboutSpecifier(*url, chrome::kAboutGpuURL)) {
1304 *url = RemapAboutURL(chrome::kGpuInternalsURL, *url);
1305 return true;
1306 }
1307
1308 // Rewrite about:appcache-internals/* URLs to chrome://appcache/*
1309 if (StartsWithAboutSpecifier(*url, chrome::kAboutAppCacheInternalsURL)) {
1310 *url = RemapAboutURL(chrome::kAppCacheViewInternalsURL, *url);
1311 return true;
1312 }
1313
1314 // Rewrite about:sync-internals/* URLs (and about:sync, too, for
1315 // legacy reasons) to chrome://sync-internals/*
1316 if (StartsWithAboutSpecifier(*url, chrome::kAboutSyncInternalsURL) ||
1317 StartsWithAboutSpecifier(*url, chrome::kAboutSyncURL)) {
1318 *url = RemapAboutURL(chrome::kSyncViewInternalsURL, *url);
1319 return true;
1320 }
1321
1322 // Rewrite about:plugins to chrome://plugins/.
1323 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutPluginsURL)) {
1324 *url = GURL(chrome::kChromeUIPluginsURL);
1325 return true;
1326 }
1327
1328 // Handle URL to crash the browser process.
1329 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutBrowserCrash)) {
1330 // Induce an intentional crash in the browser process.
1331 int* bad_pointer = NULL;
1332 *bad_pointer = 42;
1333 return true;
1334 }
1335
1336 // Handle URLs to wreck the gpu process.
1337 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutGpuCrashURL)) {
1338 GpuProcessHost::SendOnIO(
1339 0, content::CAUSE_FOR_GPU_LAUNCH_ABOUT_GPUCRASH, new GpuMsg_Crash());
1340 }
1341 if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutGpuHangURL)) {
1342 GpuProcessHost::SendOnIO(
1343 0, content::CAUSE_FOR_GPU_LAUNCH_ABOUT_GPUHANG, new GpuMsg_Hang());
1344 }
1345
1346 // There are a few about: URLs that we hand over to the renderer. If the
1347 // renderer wants them, don't do any rewriting.
1348 if (chrome_about_handler::WillHandle(*url))
1349 return false;
1350
1351 // Anything else requires our special handler; make sure it's initialized.
1352 InitializeAboutDataSource(profile);
1353
1354 // Special case about:memory to go through a redirect before ending up on
1355 // the final page. See GetAboutMemoryRedirectResponse above for why.
1356 if (LowerCaseEqualsASCII(url->path(), kMemoryPath)) {
1357 *url = GURL("chrome://about/memory-redirect");
1358 return true;
1359 }
1360
1361 // Rewrite the about URL to use chrome:. WebKit treats all about URLS the
1362 // same (blank page), so if we want to display content, we need another
1363 // scheme.
1364 std::string about_url = "chrome://about/";
1365 about_url.append(url->path());
1366 *url = GURL(about_url);
1367 return true;
1368 }
1369
InitializeAboutDataSource(Profile * profile)1370 void InitializeAboutDataSource(Profile* profile) {
1371 profile->GetChromeURLDataManager()->AddDataSource(new AboutSource());
1372 }
1373
1374 // This function gets called with the fixed-up chrome: URLs, so we have to
1375 // compare against those instead of "about:blah".
HandleNonNavigationAboutURL(const GURL & url)1376 bool HandleNonNavigationAboutURL(const GURL& url) {
1377 // about:ipc is currently buggy, so we disable it for official builds.
1378 #if !defined(OFFICIAL_BUILD)
1379
1380 #if (defined(OS_MACOSX) || defined(OS_WIN)) && defined(IPC_MESSAGE_LOG_ENABLED)
1381 if (LowerCaseEqualsASCII(url.spec(), chrome::kChromeUIIPCURL)) {
1382 // Run the dialog. This will re-use the existing one if it's already up.
1383 browser::ShowAboutIPCDialog();
1384 return true;
1385 }
1386 #endif
1387
1388 #endif // OFFICIAL_BUILD
1389
1390 return false;
1391 }
1392
AboutPaths()1393 std::vector<std::string> AboutPaths() {
1394 std::vector<std::string> paths;
1395 paths.reserve(arraysize(kAllAboutPaths));
1396 for (size_t i = 0; i < arraysize(kAllAboutPaths); i++)
1397 paths.push_back(kAllAboutPaths[i]);
1398 return paths;
1399 }
1400