Home | History | Annotate | Download | only in browser
      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
     89 AboutTcmallocOutputs* AboutTcmallocOutputs::GetInstance() {
     90   return Singleton<AboutTcmallocOutputs>::get();
     91 }
     92 
     93 AboutTcmallocOutputs::AboutTcmallocOutputs() {}
     94 
     95 AboutTcmallocOutputs::~AboutTcmallocOutputs() {}
     96 
     97 // Glue between the callback task and the method in the singleton.
     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.
    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 
    203   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:
    221   AboutMemoryHandler(AboutSource* source, int request_id)
    222     : source_(source), request_id_(request_id) {}
    223 
    224 
    225   virtual void OnDetailsAvailable();
    226 
    227  private:
    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:
    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:
    279   ChromeOSTermsHandler(AboutSource* source, int request_id)
    280     : source_(source),
    281       request_id_(request_id),
    282       locale_(WizardController::GetInitialLocale()) {
    283   }
    284 
    285   void StartOnUIThread() {
    286     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    287     BrowserThread::PostTask(
    288         BrowserThread::FILE, FROM_HERE,
    289         NewRunnableMethod(this, &ChromeOSTermsHandler::LoadFileOnFileThread));
    290   }
    291 
    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 
    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 
    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.
    374 static std::string WrapWithTH(std::string text) {
    375   return "<th>" + text + "</th>";
    376 }
    377 
    378 // Helper function to wrap Html with <td> tag.
    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.
    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.
    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 
    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 
    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:
    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:
    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.
    564   void StartOnUIThread() {
    565     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    566     BrowserThread::PostTask(
    567         BrowserThread::IO, FROM_HERE,
    568         NewRunnableMethod(this, &AboutDnsHandler::StartOnIOThread));
    569   }
    570 
    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 
    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)
    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 
    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 
    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
    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.
    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)
    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 
    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 
    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 
    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 
    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 
    995 AboutSource::AboutSource()
    996     : DataSource(chrome::kAboutScheme, MessageLoop::current()) {
    997 }
    998 
    999 AboutSource::~AboutSource() {
   1000 }
   1001 
   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 
   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).
   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.
   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 
   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 
   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 
   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.
   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".
   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 
   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 
   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".
   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 
   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