• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/&lt;secs&gt;)");
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, "&nbsp;&nbsp;", IDS_ABOUT_SANDBOX_PID_NAMESPACES,
883                     status & ZygoteHost::kSandboxPIDNS);
884     AboutSandboxRow(&data, "&nbsp;&nbsp;", 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