// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/browser_about_handler.h" #include #include #include #include "base/callback.h" #include "base/command_line.h" #include "base/file_util.h" #include "base/i18n/number_formatting.h" #include "base/json/json_writer.h" #include "base/memory/singleton.h" #include "base/metrics/histogram.h" #include "base/metrics/stats_table.h" #include "base/path_service.h" #include "base/string_number_conversions.h" #include "base/string_piece.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "base/threading/thread.h" #include "base/tracked_objects.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/about_flags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/defaults.h" #include "chrome/browser/memory_details.h" #include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/net/predictor.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/plugin_prefs.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" #include "chrome/common/about_handler.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_version_info.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/net/gaia/google_service_auth_error.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "content/browser/browser_thread.h" #include "content/browser/gpu/gpu_process_host.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/sensors/sensors_provider.h" #include "content/common/gpu/gpu_messages.h" #include "crypto/nss_util.h" #include "googleurl/src/gurl.h" #include "grit/browser_resources.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" #include "net/base/escape.h" #include "net/base/net_util.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "v8/include/v8.h" #include "webkit/glue/user_agent.h" #include "webkit/glue/webkit_glue.h" #include "webkit/plugins/npapi/plugin_list.h" #include "webkit/plugins/webplugininfo.h" #if defined(OS_WIN) #include "chrome/browser/enumerate_modules_model_win.h" #elif defined(OS_CHROMEOS) #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/cryptohome_library.h" #include "chrome/browser/chromeos/cros/network_library.h" #include "chrome/browser/chromeos/customization_document.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/version_loader.h" #include "chrome/browser/oom_priority_manager.h" #include "content/browser/zygote_host_linux.h" #elif defined(OS_LINUX) #include "content/browser/zygote_host_linux.h" #endif #if defined(USE_TCMALLOC) #include "third_party/tcmalloc/chromium/src/google/malloc_extension.h" #endif using base::Time; using base::TimeDelta; #if defined(USE_TCMALLOC) // static AboutTcmallocOutputs* AboutTcmallocOutputs::GetInstance() { return Singleton::get(); } AboutTcmallocOutputs::AboutTcmallocOutputs() {} AboutTcmallocOutputs::~AboutTcmallocOutputs() {} // Glue between the callback task and the method in the singleton. void AboutTcmallocRendererCallback(base::ProcessId pid, const std::string& output) { AboutTcmallocOutputs::GetInstance()->RendererCallback(pid, output); } #endif namespace { // Add paths here to be included in chrome://chrome-urls (about:about). // These paths will also be suggested by BuiltinProvider. const char* const kChromePaths[] = { chrome::kChromeUIAppCacheInternalsHost, chrome::kChromeUIBlobInternalsHost, chrome::kChromeUIBookmarksHost, chrome::kChromeUICacheHost, chrome::kChromeUIChromeURLsHost, chrome::kChromeUICrashesHost, chrome::kChromeUICreditsHost, chrome::kChromeUIDNSHost, chrome::kChromeUIDownloadsHost, chrome::kChromeUIExtensionsHost, chrome::kChromeUIFlagsHost, chrome::kChromeUIFlashHost, chrome::kChromeUIGpuInternalsHost, chrome::kChromeUIHistogramsHost, chrome::kChromeUIHistoryHost, chrome::kChromeUIIPCHost, chrome::kChromeUIMediaInternalsHost, chrome::kChromeUIMemoryHost, chrome::kChromeUINetInternalsHost, chrome::kChromeUINetworkViewCacheHost, chrome::kChromeUINewTabHost, chrome::kChromeUIPluginsHost, chrome::kChromeUIPrintHost, chrome::kChromeUIQuotaInternalsHost, chrome::kChromeUISessionsHost, chrome::kChromeUISettingsHost, chrome::kChromeUIStatsHost, chrome::kChromeUISyncInternalsHost, chrome::kChromeUITCMallocHost, chrome::kChromeUITermsHost, chrome::kChromeUITracingHost, chrome::kChromeUIVersionHost, chrome::kChromeUIWorkersHost, #ifdef TRACK_ALL_TASK_OBJECTS chrome::kChromeUITaskManagerHost, #endif #if defined(OS_WIN) chrome::kChromeUIConflictsHost, #endif #if defined(OS_LINUX) chrome::kChromeUILinuxProxyConfigHost, chrome::kChromeUISandboxHost, #endif #if defined(OS_CHROMEOS) chrome::kChromeUIActiveDownloadsHost, chrome::kChromeUIChooseMobileNetworkHost, chrome::kChromeUICryptohomeHost, chrome::kChromeUIDiscardsHost, chrome::kChromeUIImageBurnerHost, chrome::kChromeUIKeyboardOverlayHost, chrome::kChromeUILoginHost, chrome::kChromeUINetworkHost, chrome::kChromeUIOobeHost, chrome::kChromeUIOSCreditsHost, chrome::kChromeUIProxySettingsHost, chrome::kChromeUISystemInfoHost, #endif }; // AboutSource handles these chrome:// paths. const char* const kAboutSourceNames[] = { chrome::kChromeUIChromeURLsHost, chrome::kChromeUICreditsHost, chrome::kChromeUIDNSHost, chrome::kChromeUIHistogramsHost, chrome::kChromeUIMemoryHost, chrome::kChromeUIMemoryRedirectHost, chrome::kChromeUIStatsHost, chrome::kChromeUITermsHost, chrome::kChromeUIVersionHost, #ifdef TRACK_ALL_TASK_OBJECTS chrome::kChromeUITaskManagerHost, #endif #if defined(USE_TCMALLOC) chrome::kChromeUITCMallocHost, #endif #if defined(OS_LINUX) chrome::kChromeUILinuxProxyConfigHost, chrome::kChromeUISandboxHost, #endif #if defined(OS_CHROMEOS) chrome::kChromeUICryptohomeHost, chrome::kChromeUIDiscardsHost, chrome::kChromeUINetworkHost, chrome::kChromeUIOSCreditsHost, #endif }; const char kCreditsJsPath[] = "credits.js"; const char kMemoryJsPath[] = "memory.js"; const char kStatsJsPath[] = "stats.js"; const char kStringsJsPath[] = "strings.js"; const char kVersionJsPath[] = "version.js"; class AboutSource : public ChromeURLDataManager::DataSource { public: // Construct a data source for the specified |source_name|. AboutSource(const std::string& source_name, Profile* profile); // Called when the network layer has requested a resource underneath // the path we registered. virtual void StartDataRequest(const std::string& path, bool is_incognito, int request_id) OVERRIDE; virtual std::string GetMimeType(const std::string& path) const OVERRIDE; // Send the response data. void FinishDataRequest(const std::string& html, int request_id); Profile* profile() { return profile_; } private: virtual ~AboutSource(); Profile* profile_; DISALLOW_COPY_AND_ASSIGN(AboutSource); }; // When you type about:memory, it actually loads this intermediate URL that // redirects you to the final page. This avoids the problem where typing // "about:memory" on the new tab page or any other page where a process // transition would occur to the about URL will cause some confusion. // // The problem is that during the processing of the memory page, there are two // processes active, the original and the destination one. This can create the // impression that we're using more resources than we actually are. This // redirect solves the problem by eliminating the process transition during the // time that about memory is being computed. std::string GetAboutMemoryRedirectResponse(Profile* profile) { InitializeAboutDataSource(chrome::kChromeUIMemoryRedirectHost, profile); return StringPrintf("", chrome::kChromeUIMemoryRedirectURL); } // Handling about:memory is complicated enough to encapsulate its related // methods into a single class. The user should create it (on the heap) and call // its |StartFetch()| method. class AboutMemoryHandler : public MemoryDetails { public: AboutMemoryHandler(AboutSource* source, int request_id) : source_(source), request_id_(request_id) { } virtual void OnDetailsAvailable() OVERRIDE; private: ~AboutMemoryHandler() {} void BindProcessMetrics(DictionaryValue* data, ProcessMemoryInformation* info); void AppendProcess(ListValue* child_data, ProcessMemoryInformation* info); scoped_refptr source_; int request_id_; DISALLOW_COPY_AND_ASSIGN(AboutMemoryHandler); }; #if defined(OS_CHROMEOS) // ChromeOSAboutVersionHandler is responsible for loading the Chrome OS // version. // ChromeOSAboutVersionHandler handles deleting itself once the version has // been obtained and AboutSource notified. class ChromeOSAboutVersionHandler { public: ChromeOSAboutVersionHandler(AboutSource* source, int request_id); // Callback from chromeos::VersionLoader giving the version. void OnVersion(chromeos::VersionLoader::Handle handle, std::string version); private: // Where the results are fed to. scoped_refptr source_; // ID identifying the request. int request_id_; // Handles asynchronously loading the version. chromeos::VersionLoader loader_; // Used to request the version. CancelableRequestConsumer consumer_; DISALLOW_COPY_AND_ASSIGN(ChromeOSAboutVersionHandler); }; class ChromeOSTermsHandler : public base::RefCountedThreadSafe { public: static void Start(AboutSource* source, const std::string& path, int request_id) { scoped_refptr handler( new ChromeOSTermsHandler(source, path, request_id)); handler->StartOnUIThread(); } private: ChromeOSTermsHandler(AboutSource* source, const std::string& path, int request_id) : source_(source), path_(path), request_id_(request_id), locale_(chromeos::WizardController::GetInitialLocale()) { } void StartOnUIThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod(this, &ChromeOSTermsHandler::LoadFileOnFileThread)); } void LoadFileOnFileThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); if (path_ == chrome::kOemEulaURLPath) { const chromeos::StartupCustomizationDocument* customization = chromeos::StartupCustomizationDocument::GetInstance(); if (customization->IsReady()) { FilePath oem_eula_file_path; if (net::FileURLToFilePath(GURL(customization->GetEULAPage(locale_)), &oem_eula_file_path)) { if (!file_util::ReadFileToString(oem_eula_file_path, &contents_)) { contents_.clear(); } } } } else { std::string file_path = StringPrintf(chrome::kEULAPathFormat, locale_.c_str()); if (!file_util::ReadFileToString(FilePath(file_path), &contents_)) { // No EULA for given language - try en-US as default. file_path = StringPrintf(chrome::kEULAPathFormat, "en-US"); if (!file_util::ReadFileToString(FilePath(file_path), &contents_)) { // File with EULA not found, ResponseOnUIThread will load EULA from // resources if contents_ is empty. contents_.clear(); } } } BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &ChromeOSTermsHandler::ResponseOnUIThread)); } void ResponseOnUIThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // If we fail to load Chrome OS EULA from disk, load it from resources. // Do nothing if OEM EULA load failed. if (contents_.empty() && path_ != chrome::kOemEulaURLPath) { contents_ = ResourceBundle::GetSharedInstance().GetRawDataResource( IDR_TERMS_HTML).as_string(); } source_->FinishDataRequest(contents_, request_id_); } // Where the results are fed to. scoped_refptr source_; // Path in the URL. std::string path_; // ID identifying the request. int request_id_; // Locale of the EULA. std::string locale_; // EULA contents that was loaded from file. std::string contents_; DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsHandler); }; #endif // Individual about handlers --------------------------------------------------- void AppendHeader(std::string* output, int refresh, const std::string& unescaped_title) { output->append("\n\n\n"); if (!unescaped_title.empty()) { output->append(""); output->append(EscapeForHTML(unescaped_title)); output->append("\n"); } output->append("\n"); output->append(ResourceBundle::GetSharedInstance().GetRawDataResource( IDR_CONTENT_SECURITY_POLICY_HTML).as_string()); if (refresh > 0) { output->append("append(base::IntToString(refresh)); output->append("\"/>\n"); } } void AppendBody(std::string *output) { output->append("\n\n"); } void AppendFooter(std::string *output) { output->append("\n\n"); } std::string ChromeURLs() { std::string html; AppendHeader(&html, 0, "Chrome URLs"); AppendBody(&html); html += "

List of Chrome URLs

\n
    \n"; std::vector paths(ChromePaths()); for (std::vector::const_iterator i = paths.begin(); i != paths.end(); ++i) html += "
  • chrome://" + *i + "
  • \n"; html += "
\n

For Debug

\n" "

The following pages are for debugging purposes only. Because they " "crash or hang the renderer, they're not linked directly; you can type " "them into the address bar if you need them.

\n
    "; for (int i = 0; i < chrome::kNumberOfChromeDebugURLs; i++) html += "
  • " + std::string(chrome::kChromeDebugURLs[i]) + "
  • \n"; html += "
\n"; AppendFooter(&html); return html; } #if defined(OS_CHROMEOS) // Html output helper functions // TODO(stevenjb): L10N this. // Helper function to wrap HTML with a tag. std::string WrapWithTag(const std::string& tag, const std::string& text) { return "<" + tag + ">" + text + ""; } // Helper function to wrap Html with tag. std::string WrapWithTH(const std::string& text) { return "" + text + ""; } // Helper function to wrap Html with tag. std::string WrapWithTD(const std::string& text) { return "" + text + ""; } // Helper function to wrap Html with tag. std::string WrapWithTR(const std::string& text) { return "" + text + ""; } void AppendRefresh(std::string *output, int refresh, const std::string& name) { if (refresh > 0) { output->append("(Auto-refreshing page every "); output->append(base::IntToString(refresh)); output->append("s)"); } else { output->append("(To auto-refresh this page: about:"); output->append(name); output->append("/<secs>)"); } } // Helper function to create an Html table header for a Network. std::string ToHtmlTableHeader(const chromeos::Network* network) { std::string str = WrapWithTH("Name") + WrapWithTH("Active") + WrapWithTH("State"); if (network->type() == chromeos::TYPE_WIFI || network->type() == chromeos::TYPE_CELLULAR) { str += WrapWithTH("Auto-Connect"); str += WrapWithTH("Strength"); } if (network->type() == chromeos::TYPE_WIFI) { str += WrapWithTH("Encryption"); str += WrapWithTH("Passphrase"); str += WrapWithTH("Identity"); } if (network->type() == chromeos::TYPE_CELLULAR) { str += WrapWithTH("Technology"); str += WrapWithTH("Connectivity"); str += WrapWithTH("Activation"); str += WrapWithTH("Roaming"); } if (network->type() == chromeos::TYPE_VPN) { str += WrapWithTH("Host"); str += WrapWithTH("Provider Type"); str += WrapWithTH("PSK Passphrase"); str += WrapWithTH("Username"); str += WrapWithTH("User Passphrase"); } str += WrapWithTH("Error"); str += WrapWithTH("IP Address"); return WrapWithTR(str); } // Helper function to create an Html table row for a Network. std::string ToHtmlTableRow(const chromeos::Network* network) { std::string str = WrapWithTD(network->name()) + WrapWithTD(base::IntToString(network->is_active())) + WrapWithTD(network->GetStateString()); if (network->type() == chromeos::TYPE_WIFI || network->type() == chromeos::TYPE_CELLULAR) { const chromeos::WirelessNetwork* wireless = static_cast(network); str += WrapWithTD(base::IntToString(wireless->auto_connect())); str += WrapWithTD(base::IntToString(wireless->strength())); } if (network->type() == chromeos::TYPE_WIFI) { const chromeos::WifiNetwork* wifi = static_cast(network); str += WrapWithTD(wifi->GetEncryptionString()); str += WrapWithTD(std::string(wifi->passphrase().length(), '*')); str += WrapWithTD(wifi->identity()); } if (network->type() == chromeos::TYPE_CELLULAR) { const chromeos::CellularNetwork* cell = static_cast(network); str += WrapWithTH(cell->GetNetworkTechnologyString()); str += WrapWithTH(cell->GetActivationStateString()); str += WrapWithTH(cell->GetRoamingStateString()); } if (network->type() == chromeos::TYPE_VPN) { const chromeos::VirtualNetwork* vpn = static_cast(network); str += WrapWithTH(vpn->server_hostname()); str += WrapWithTH(vpn->GetProviderTypeString()); str += WrapWithTD(std::string(vpn->psk_passphrase().length(), '*')); str += WrapWithTH(vpn->username()); str += WrapWithTD(std::string(vpn->user_passphrase().length(), '*')); } str += WrapWithTD(network->failed() ? network->GetErrorString() : ""); str += WrapWithTD(network->ip_address()); return WrapWithTR(str); } std::string GetNetworkHtmlInfo(int refresh) { chromeos::NetworkLibrary* cros = chromeos::CrosLibrary::Get()->GetNetworkLibrary(); std::string output; AppendHeader(&output, refresh, "About Network"); AppendBody(&output); AppendRefresh(&output, refresh, "network"); if (cros->ethernet_enabled()) { output.append("

Ethernet:

"); const chromeos::EthernetNetwork* ethernet = cros->ethernet_network(); if (ethernet) { output.append(ToHtmlTableHeader(ethernet)); output.append(ToHtmlTableRow(ethernet)); } } if (cros->wifi_enabled()) { output.append("

Wifi Networks:

"); const chromeos::WifiNetworkVector& wifi_networks = cros->wifi_networks(); for (size_t i = 0; i < wifi_networks.size(); ++i) { if (i == 0) output.append(ToHtmlTableHeader(wifi_networks[i])); output.append(ToHtmlTableRow(wifi_networks[i])); } } if (cros->cellular_enabled()) { output.append("

Cellular Networks:

"); const chromeos::CellularNetworkVector& cellular_networks = cros->cellular_networks(); for (size_t i = 0; i < cellular_networks.size(); ++i) { if (i == 0) output.append(ToHtmlTableHeader(cellular_networks[i])); output.append(ToHtmlTableRow(cellular_networks[i])); } } { output.append("

Virtual Networks:

"); const chromeos::VirtualNetworkVector& virtual_networks = cros->virtual_networks(); for (size_t i = 0; i < virtual_networks.size(); ++i) { if (i == 0) output.append(ToHtmlTableHeader(virtual_networks[i])); output.append(ToHtmlTableRow(virtual_networks[i])); } } { output.append( "

Remembered Wi-Fi Networks:

"); const chromeos::WifiNetworkVector& remembered_wifi_networks = cros->remembered_wifi_networks(); for (size_t i = 0; i < remembered_wifi_networks.size(); ++i) { if (i == 0) output.append( ToHtmlTableHeader(remembered_wifi_networks[i])); output.append(ToHtmlTableRow(remembered_wifi_networks[i])); } } output.append("
"); AppendFooter(&output); return output; } std::string AboutNetwork(const std::string& query) { int refresh; base::StringToInt(query, &refresh); return GetNetworkHtmlInfo(refresh); } std::string AddBoolRow(const std::string& name, bool value) { std::string row; row.append(WrapWithTD(name)); row.append(WrapWithTD(value ? "true" : "false")); return WrapWithTR(row); } std::string AddStringRow(const std::string& name, const std::string& value) { std::string row; row.append(WrapWithTD(name)); row.append(WrapWithTD(value)); return WrapWithTR(row); } std::string GetCryptohomeHtmlInfo(int refresh) { chromeos::CryptohomeLibrary* cryptohome = chromeos::CrosLibrary::Get()->GetCryptohomeLibrary(); std::string output; AppendHeader(&output, refresh, "About Cryptohome"); AppendBody(&output); AppendRefresh(&output, refresh, "cryptohome"); output.append("

CryptohomeLibrary:

"); output.append(""); output.append(AddBoolRow("IsMounted", cryptohome->IsMounted())); output.append(AddBoolRow("TpmIsReady", cryptohome->TpmIsReady())); output.append(AddBoolRow("TpmIsEnabled", cryptohome->TpmIsEnabled())); output.append(AddBoolRow("TpmIsOwned", cryptohome->TpmIsOwned())); output.append(AddBoolRow("TpmIsBeingOwned", cryptohome->TpmIsBeingOwned())); output.append(AddBoolRow("Pkcs11IsTpmTokenReady", cryptohome->Pkcs11IsTpmTokenReady())); output.append("
"); std::string token_name, user_pin; crypto::GetTPMTokenInfo(&token_name, &user_pin); output.append("

crypto:

"); output.append(""); output.append(AddBoolRow("IsTPMTokenReady", crypto::IsTPMTokenReady())); output.append(AddStringRow("token_name", token_name)); output.append(AddStringRow("user_pin", std::string(user_pin.length(), '*'))); output.append("
"); AppendFooter(&output); return output; } std::string AboutCryptohome(const std::string& query) { int refresh; base::StringToInt(query, &refresh); return GetCryptohomeHtmlInfo(refresh); } std::string AboutDiscards() { std::string output; AppendHeader(&output, 0, "About discards"); AppendBody(&output); output.append("

About discards

"); output.append( "

Tabs sorted from most interesting to least interesting. The least " "interesting tab may be discarded if we run out of physical memory.

"); std::vector titles = browser::OomPriorityManager::GetInstance()->GetTabTitles(); if (!titles.empty()) { output.append("
    "); std::vector::iterator it = titles.begin(); for ( ; it != titles.end(); ++it) { std::string title = UTF16ToUTF8(*it); output.append(WrapWithTag("li", title)); } output.append("
"); } else { output.append("

None found. Wait 10 seconds, then refresh.

"); } base::SystemMemoryInfoKB meminfo; base::GetSystemMemoryInfo(&meminfo); output.append("

System memory information in MB

"); output.append(""); output.append(AddStringRow( "Total Memory", base::IntToString(meminfo.total / 1024))); output.append(AddStringRow( "Free Memory", base::IntToString(meminfo.free / 1024))); output.append(AddStringRow( "Buffered Memory", base::IntToString(meminfo.buffers / 1024))); output.append(AddStringRow( "Cached Memory", base::IntToString(meminfo.cached / 1024))); output.append(AddStringRow( "Committed Memory", base::IntToString( (meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached) / 1024))); output.append(AddStringRow( "Active Anon Memory", base::IntToString(meminfo.active_anon / 1024))); output.append(AddStringRow( "Inactive Anon Memory", base::IntToString(meminfo.inactive_anon / 1024))); output.append(AddStringRow( "Shared Memory", base::IntToString(meminfo.shmem / 1024))); output.append("
"); AppendFooter(&output); return output; } #endif // OS_CHROMEOS // AboutDnsHandler bounces the request back to the IO thread to collect // the DNS information. class AboutDnsHandler : public base::RefCountedThreadSafe { public: static void Start(AboutSource* source, int request_id) { scoped_refptr handler( new AboutDnsHandler(source, request_id)); handler->StartOnUIThread(); } private: AboutDnsHandler(AboutSource* source, int request_id) : source_(source), request_id_(request_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } // Calls FinishOnUIThread() on completion. void StartOnUIThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); chrome_browser_net::Predictor* predictor = source_->profile()->GetNetworkPredictor(); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(this, &AboutDnsHandler::StartOnIOThread, predictor)); } void StartOnIOThread(chrome_browser_net::Predictor* predictor) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); std::string data; AppendHeader(&data, 0, "About DNS"); AppendBody(&data); chrome_browser_net::Predictor::PredictorGetHtmlInfo(predictor, &data); AppendFooter(&data); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(this, &AboutDnsHandler::FinishOnUIThread, data)); } void FinishOnUIThread(const std::string& data) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); source_->FinishDataRequest(data, request_id_); } // Where the results are fed to. scoped_refptr source_; // ID identifying the request. int request_id_; DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler); }; #if defined(USE_TCMALLOC) std::string AboutTcmalloc() { std::string data; AboutTcmallocOutputsType* outputs = AboutTcmallocOutputs::GetInstance()->outputs(); // Display any stats for which we sent off requests the last time. AppendHeader(&data, 0, "About tcmalloc"); AppendBody(&data); data.append("

Stats as of last page load;"); data.append("reload to get stats as of this page load.

\n"); data.append("\n"); for (AboutTcmallocOutputsType::const_iterator oit = outputs->begin(); oit != outputs->end(); oit++) { data.append("\n"); data.append("\n"); } data.append("
"); data.append(oit->first); data.append("
\n");
    data.append(oit->second);
    data.append("
\n"); AppendFooter(&data); // Reset our collector singleton. outputs->clear(); // Populate the collector with stats from the local browser process // and send off requests to all the renderer processes. char buffer[1024 * 32]; MallocExtension::instance()->GetStats(buffer, sizeof(buffer)); std::string browser("Browser"); AboutTcmallocOutputs::GetInstance()->SetOutput(browser, buffer); RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); while (!it.IsAtEnd()) { it.GetCurrentValue()->Send(new ChromeViewMsg_GetRendererTcmalloc); it.Advance(); } return data; } #endif std::string AboutHistograms(const std::string& query) { TimeDelta wait_time = TimeDelta::FromMilliseconds(10000); HistogramSynchronizer* current_synchronizer = HistogramSynchronizer::CurrentSynchronizer(); DCHECK(current_synchronizer != NULL); current_synchronizer->FetchRendererHistogramsSynchronously(wait_time); std::string unescaped_query; std::string unescaped_title("About Histograms"); if (!query.empty()) { unescaped_query = UnescapeURLComponent(query, UnescapeRule::NORMAL); unescaped_title += " - " + unescaped_query; } std::string data; AppendHeader(&data, 0, unescaped_title); AppendBody(&data); base::StatisticsRecorder::WriteHTMLGraph(unescaped_query, &data); AppendFooter(&data); return data; } void AboutMemory(const std::string& path, AboutSource* source, int request_id) { if (path == kStringsJsPath) { // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want the // refcount to be greater than 0. scoped_refptr handler(new AboutMemoryHandler(source, request_id)); handler->StartFetch(); } else { source->FinishDataRequest( ResourceBundle::GetSharedInstance().GetRawDataResource( path == kMemoryJsPath ? IDR_ABOUT_MEMORY_JS : IDR_ABOUT_MEMORY_HTML).as_string(), request_id); } } #ifdef TRACK_ALL_TASK_OBJECTS static std::string AboutObjects(const std::string& query) { std::string unescaped_title("About Histograms"); if (!query.empty()) { unescaped_title += " - "; unescaped_title += UnescapeURLComponent(query, UnescapeRule::NORMAL); } std::string data; AppendHeader(&data, 0, unescaped_title); AppendBody(&data); tracked_objects::ThreadData::WriteHTML(query, &data); AppendFooter(&data); return data; } #endif // TRACK_ALL_TASK_OBJECTS // Handler for filling in the "about:stats" page, as called by the browser's // About handler processing. // |query| is roughly the query string of the about:stats URL. // Returns a string containing the HTML to render for the about:stats page. // Conditional Output: // if |query| is "json", returns a JSON format of all counters. // if |query| is "raw", returns plain text of counter deltas. // otherwise, returns HTML with pretty JS/HTML to display the data. std::string AboutStats(const std::string& query) { // We keep the DictionaryValue tree live so that we can do delta // stats computations across runs. static DictionaryValue root; static base::TimeTicks last_sample_time = base::TimeTicks::Now(); base::TimeTicks now = base::TimeTicks::Now(); base::TimeDelta time_since_last_sample = now - last_sample_time; last_sample_time = now; base::StatsTable* table = base::StatsTable::current(); if (!table) return std::string(); // We maintain two lists - one for counters and one for timers. // Timers actually get stored on both lists. ListValue* counters; if (!root.GetList("counters", &counters)) { counters = new ListValue(); root.Set("counters", counters); } ListValue* timers; if (!root.GetList("timers", &timers)) { timers = new ListValue(); root.Set("timers", timers); } // NOTE: Counters start at index 1. for (int index = 1; index <= table->GetMaxCounters(); index++) { // Get the counter's full name std::string full_name = table->GetRowName(index); if (full_name.length() == 0) break; DCHECK_EQ(':', full_name[1]); char counter_type = full_name[0]; std::string name = full_name.substr(2); // JSON doesn't allow '.' in names. size_t pos; while ((pos = name.find(".")) != std::string::npos) name.replace(pos, 1, ":"); // Try to see if this name already exists. DictionaryValue* counter = NULL; for (size_t scan_index = 0; scan_index < counters->GetSize(); scan_index++) { DictionaryValue* dictionary; if (counters->GetDictionary(scan_index, &dictionary)) { std::string scan_name; if (dictionary->GetString("name", &scan_name) && scan_name == name) { counter = dictionary; } } else { NOTREACHED(); // Should always be there } } if (counter == NULL) { counter = new DictionaryValue(); counter->SetString("name", name); counters->Append(counter); } switch (counter_type) { case 'c': { int new_value = table->GetRowValue(index); int prior_value = 0; int delta = 0; if (counter->GetInteger("value", &prior_value)) { delta = new_value - prior_value; } counter->SetInteger("value", new_value); counter->SetInteger("delta", delta); } break; case 'm': { // TODO(mbelshe): implement me. } break; case 't': { int time = table->GetRowValue(index); counter->SetInteger("time", time); // Store this on the timers list as well. timers->Append(counter); } break; default: NOTREACHED(); } } std::string data; if (query == "json" || query == kStringsJsPath) { base::JSONWriter::WriteWithOptionalEscape(&root, true, false, &data); if (query == kStringsJsPath) data = "var templateData = " + data + ";"; } else if (query == "raw") { // Dump the raw counters which have changed in text format. data = "
";
    data.append(StringPrintf("Counter changes in the last %ldms\n",
        static_cast(time_since_last_sample.InMilliseconds())));
    for (size_t i = 0; i < counters->GetSize(); ++i) {
      Value* entry = NULL;
      bool rv = counters->Get(i, &entry);
      if (!rv)
        continue;  // None of these should fail.
      DictionaryValue* counter = static_cast(entry);
      int delta;
      rv = counter->GetInteger("delta", &delta);
      if (!rv)
        continue;
      if (delta > 0) {
        std::string name;
        rv = counter->GetString("name", &name);
        if (!rv)
          continue;
        int value;
        rv = counter->GetInteger("value", &value);
        if (!rv)
          continue;
        data.append(name);
        data.append(":");
        data.append(base::IntToString(delta));
        data.append("\n");
      }
    }
    data.append("
"); } else { // Get about_stats.html/js from resource bundle. data = ResourceBundle::GetSharedInstance().GetRawDataResource( (query == kStatsJsPath ? IDR_ABOUT_STATS_JS : IDR_ABOUT_STATS_HTML)). as_string(); if (query != kStatsJsPath) { // Clear the timer list since we stored the data in the timers list // as well. for (int index = static_cast(timers->GetSize())-1; index >= 0; index--) { Value* value; timers->Remove(index, &value); // We don't care about the value pointer; it's still tracked // on the counters list. } } } return data; } #if defined(OS_LINUX) std::string AboutLinuxProxyConfig() { std::string data; AppendHeader(&data, 0, l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE)); data.append(""); AppendBody(&data); FilePath binary = CommandLine::ForCurrentProcess()->GetProgram(); data.append(l10n_util::GetStringFUTF8( IDS_ABOUT_LINUX_PROXY_CONFIG_BODY, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), ASCIIToUTF16(binary.BaseName().value()))); AppendFooter(&data); return data; } void AboutSandboxRow(std::string* data, const std::string& prefix, int name_id, bool good) { data->append(""); data->append(prefix); data->append(l10n_util::GetStringUTF8(name_id)); if (good) { data->append(""); data->append( l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)); } else { data->append(""); data->append( l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL)); } data->append(""); } std::string AboutSandbox() { std::string data; AppendHeader(&data, 0, l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE)); AppendBody(&data); data.append("

"); data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE)); data.append("

"); const int status = ZygoteHost::GetInstance()->sandbox_status(); data.append(""); AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SUID_SANDBOX, status & ZygoteHost::kSandboxSUID); AboutSandboxRow(&data, "  ", IDS_ABOUT_SANDBOX_PID_NAMESPACES, status & ZygoteHost::kSandboxPIDNS); AboutSandboxRow(&data, "  ", IDS_ABOUT_SANDBOX_NET_NAMESPACES, status & ZygoteHost::kSandboxNetNS); AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SECCOMP_SANDBOX, status & ZygoteHost::kSandboxSeccomp); data.append("
"); bool good = ((status & ZygoteHost::kSandboxSUID) && (status & ZygoteHost::kSandboxPIDNS)) || (status & ZygoteHost::kSandboxSeccomp); if (good) { data.append("

"); data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK)); } else { data.append("

"); data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD)); } data.append("

"); AppendFooter(&data); return data; } #endif std::string AboutVersionStaticContent(const std::string& query) { return ResourceBundle::GetSharedInstance().GetRawDataResource( query == kVersionJsPath ? IDR_ABOUT_VERSION_JS : IDR_ABOUT_VERSION_HTML).as_string(); } std::string AboutVersionStrings(DictionaryValue* localized_strings, Profile* profile) { localized_strings->SetString("title", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_TITLE)); chrome::VersionInfo version_info; localized_strings->SetString("name", l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); localized_strings->SetString("version", version_info.Version()); // Bug 79458: Need to evaluate the use of getting the version string on // this thread. base::ThreadRestrictions::ScopedAllowIO allow_io; localized_strings->SetString("version_modifier", chrome::VersionInfo::GetVersionStringModifier()); localized_strings->SetString("os_name", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_OS)); localized_strings->SetString("platform", l10n_util::GetStringUTF16(IDS_PLATFORM_LABEL)); localized_strings->SetString("os_type", version_info.OSType()); localized_strings->SetString("webkit_version", webkit_glue::GetWebKitVersion()); localized_strings->SetString("js_engine", "V8"); localized_strings->SetString("js_version", v8::V8::GetVersion()); // Obtain the version of the first enabled Flash plugin. std::vector info_array; webkit::npapi::PluginList::Singleton()->GetPluginInfoArray( GURL(), "application/x-shockwave-flash", false, NULL, &info_array, NULL); string16 flash_version = l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN); PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile); for (size_t i = 0; i < info_array.size(); ++i) { if (plugin_prefs->IsPluginEnabled(info_array[i])) { flash_version = info_array[i].version; break; } } localized_strings->SetString("flash_plugin", "Flash"); localized_strings->SetString("flash_version", flash_version); localized_strings->SetString("company", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COMPANY_NAME)); localized_strings->SetString("copyright", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COPYRIGHT)); localized_strings->SetString("cl", version_info.LastChange()); localized_strings->SetString("official", l10n_util::GetStringUTF16( version_info.IsOfficialBuild() ? IDS_ABOUT_VERSION_OFFICIAL : IDS_ABOUT_VERSION_UNOFFICIAL)); localized_strings->SetString("user_agent_name", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_USER_AGENT)); localized_strings->SetString("useragent", webkit_glue::GetUserAgent(GURL())); localized_strings->SetString("command_line_name", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COMMAND_LINE)); #if defined(OS_WIN) localized_strings->SetString("command_line", WideToUTF16(CommandLine::ForCurrentProcess()->GetCommandLineString())); #elif defined(OS_POSIX) std::string command_line = ""; typedef std::vector ArgvList; const ArgvList& argv = CommandLine::ForCurrentProcess()->argv(); for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end(); iter++) command_line += " " + *iter; // TODO(viettrungluu): |command_line| could really have any encoding, whereas // below we assumes it's UTF-8. localized_strings->SetString("command_line", command_line); #endif // Allow IO temporarily based on allow_io (defined above) // since the following operation will complete quickly localized_strings->SetString("executable_path_name", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_EXECUTABLE_PATH)); FilePath executable_path = CommandLine::ForCurrentProcess()->GetProgram(); if (file_util::AbsolutePath(&executable_path)) { localized_strings->SetString("executable_path", executable_path.value()); } else { localized_strings->SetString("executable_path", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_PATH_NOTFOUND)); } localized_strings->SetString("profile_path_name", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_PROFILE_PATH)); if (profile) { FilePath profile_path = profile->GetPath(); if (file_util::AbsolutePath(&profile_path)) { localized_strings->SetString("profile_path", profile_path.value()); } else { localized_strings->SetString("profile_path", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_PATH_NOTFOUND)); } } else { localized_strings->SetString("profile_path", l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_PATH_NOTFOUND)); } std::string data; jstemplate_builder::AppendJsonJS(localized_strings, &data); return data; } // AboutMemoryHandler ---------------------------------------------------------- // Helper for AboutMemory to bind results from a ProcessMetrics object // to a DictionaryValue. Fills ws_usage and comm_usage so that the objects // can be used in caller's scope (e.g for appending to a net total). void AboutMemoryHandler::BindProcessMetrics(DictionaryValue* data, ProcessMemoryInformation* info) { DCHECK(data && info); // Bind metrics to dictionary. data->SetInteger("ws_priv", static_cast(info->working_set.priv)); data->SetInteger("ws_shareable", static_cast(info->working_set.shareable)); data->SetInteger("ws_shared", static_cast(info->working_set.shared)); data->SetInteger("comm_priv", static_cast(info->committed.priv)); data->SetInteger("comm_map", static_cast(info->committed.mapped)); data->SetInteger("comm_image", static_cast(info->committed.image)); data->SetInteger("pid", info->pid); data->SetString("version", info->version); data->SetInteger("processes", info->num_processes); } // Helper for AboutMemory to append memory usage information for all // sub-processes (i.e. renderers, plugins) used by Chrome. void AboutMemoryHandler::AppendProcess(ListValue* child_data, ProcessMemoryInformation* info) { DCHECK(child_data && info); // Append a new DictionaryValue for this renderer to our list. DictionaryValue* child = new DictionaryValue(); child_data->Append(child); BindProcessMetrics(child, info); std::string child_label( ChildProcessInfo::GetFullTypeNameInEnglish(info->type, info->renderer_type)); if (info->is_diagnostics) child_label.append(" (diagnostics)"); child->SetString("child_name", child_label); ListValue* titles = new ListValue(); child->Set("titles", titles); for (size_t i = 0; i < info->titles.size(); ++i) titles->Append(new StringValue(info->titles[i])); } void AboutMemoryHandler::OnDetailsAvailable() { // the root of the JSON hierarchy for about:memory jstemplate DictionaryValue root; ListValue* browsers = new ListValue(); root.Set("browsers", browsers); const std::vector& browser_processes = processes(); // Aggregate per-process data into browser summary data. std::wstring log_string; for (size_t index = 0; index < browser_processes.size(); index++) { if (browser_processes[index].processes.empty()) continue; // Sum the information for the processes within this browser. ProcessMemoryInformation aggregate; ProcessMemoryInformationList::const_iterator iterator; iterator = browser_processes[index].processes.begin(); aggregate.pid = iterator->pid; aggregate.version = iterator->version; while (iterator != browser_processes[index].processes.end()) { if (!iterator->is_diagnostics || browser_processes[index].processes.size() == 1) { aggregate.working_set.priv += iterator->working_set.priv; aggregate.working_set.shared += iterator->working_set.shared; aggregate.working_set.shareable += iterator->working_set.shareable; aggregate.committed.priv += iterator->committed.priv; aggregate.committed.mapped += iterator->committed.mapped; aggregate.committed.image += iterator->committed.image; aggregate.num_processes++; } ++iterator; } DictionaryValue* browser_data = new DictionaryValue(); browsers->Append(browser_data); browser_data->SetString("name", browser_processes[index].name); BindProcessMetrics(browser_data, &aggregate); // We log memory info as we record it. if (log_string.length() > 0) log_string.append(L", "); log_string.append(UTF16ToWide(browser_processes[index].name)); log_string.append(L", "); log_string.append(UTF8ToWide( base::Int64ToString(aggregate.working_set.priv))); log_string.append(L", "); log_string.append(UTF8ToWide( base::Int64ToString(aggregate.working_set.shared))); log_string.append(L", "); log_string.append(UTF8ToWide( base::Int64ToString(aggregate.working_set.shareable))); } if (log_string.length() > 0) VLOG(1) << "memory: " << log_string; // Set the browser & renderer detailed process data. DictionaryValue* browser_data = new DictionaryValue(); root.Set("browzr_data", browser_data); ListValue* child_data = new ListValue(); root.Set("child_data", child_data); ProcessData process = browser_processes[0]; // Chrome is the first browser. root.SetString("current_browser_name", process.name); for (size_t index = 0; index < process.processes.size(); index++) { if (process.processes[index].type == ChildProcessInfo::BROWSER_PROCESS) BindProcessMetrics(browser_data, &process.processes[index]); else AppendProcess(child_data, &process.processes[index]); } root.SetBoolean("show_other_browsers", browser_defaults::kShowOtherBrowsersInAboutMemory); std::string data; jstemplate_builder::AppendJsonJS(&root, &data); source_->FinishDataRequest(data, request_id_); } #if defined(OS_CHROMEOS) // ChromeOSAboutVersionHandler ----------------------------------------------- ChromeOSAboutVersionHandler::ChromeOSAboutVersionHandler( AboutSource* source, int request_id) : source_(source), request_id_(request_id) { loader_.EnablePlatformVersions(true); loader_.GetVersion(&consumer_, NewCallback(this, &ChromeOSAboutVersionHandler::OnVersion), chromeos::VersionLoader::VERSION_FULL); } void ChromeOSAboutVersionHandler::OnVersion( chromeos::VersionLoader::Handle handle, std::string version) { DictionaryValue localized_strings; localized_strings.SetString("os_version", version); source_->FinishDataRequest(AboutVersionStrings( &localized_strings, source_->profile()), request_id_); // CancelableRequestProvider isn't happy when it's deleted and servicing a // task, so we delay the deletion. MessageLoop::current()->DeleteSoon(FROM_HERE, this); } #endif } // namespace // AboutSource ----------------------------------------------------------------- AboutSource::AboutSource(const std::string& source_name, Profile* profile) : DataSource(source_name, MessageLoop::current()), profile_(profile) { } AboutSource::~AboutSource() { } void AboutSource::StartDataRequest(const std::string& path, bool is_incognito, int request_id) { std::string response; std::string host = source_name(); // Add your data source here, in alphabetical order. if (host == chrome::kChromeUIChromeURLsHost) { response = ChromeURLs(); } else if (host == chrome::kChromeUICreditsHost) { int idr = (path == kCreditsJsPath) ? IDR_CREDITS_JS : IDR_CREDITS_HTML; response = ResourceBundle::GetSharedInstance().GetRawDataResource( idr).as_string(); #if defined(OS_CHROMEOS) } else if (host == chrome::kChromeUICryptohomeHost) { response = AboutCryptohome(path); } else if (host == chrome::kChromeUIDiscardsHost) { response = AboutDiscards(); #endif } else if (host == chrome::kChromeUIDNSHost) { AboutDnsHandler::Start(this, request_id); return; } else if (host == chrome::kChromeUIHistogramsHost) { response = AboutHistograms(path); #if defined(OS_LINUX) } else if (host == chrome::kChromeUILinuxProxyConfigHost) { response = AboutLinuxProxyConfig(); #endif } else if (host == chrome::kChromeUIMemoryHost) { response = GetAboutMemoryRedirectResponse(profile()); } else if (host == chrome::kChromeUIMemoryRedirectHost) { AboutMemory(path, this, request_id); return; #if defined(OS_CHROMEOS) } else if (host == chrome::kChromeUINetworkHost) { response = AboutNetwork(path); } else if (host == chrome::kChromeUIOSCreditsHost) { response = ResourceBundle::GetSharedInstance().GetRawDataResource( IDR_OS_CREDITS_HTML).as_string(); #endif #if defined(OS_LINUX) } else if (host == chrome::kChromeUISandboxHost) { response = AboutSandbox(); #endif } else if (host == chrome::kChromeUIStatsHost) { response = AboutStats(path); #ifdef TRACK_ALL_TASK_OBJECTS } else if (host == chrome::kChromeUITaskManagerHost) { response = AboutObjects(path); #endif #if defined(USE_TCMALLOC) } else if (host == chrome::kChromeUITCMallocHost) { response = AboutTcmalloc(); #endif } else if (host == chrome::kChromeUITermsHost) { #if defined(OS_CHROMEOS) ChromeOSTermsHandler::Start(this, path, request_id); return; #else response = ResourceBundle::GetSharedInstance().GetRawDataResource( IDR_TERMS_HTML).as_string(); #endif } else if (host == chrome::kChromeUIVersionHost) { if (path == kStringsJsPath) { #if defined(OS_CHROMEOS) new ChromeOSAboutVersionHandler(this, request_id); return; #else DictionaryValue localized_strings; localized_strings.SetString("os_version", ""); response = AboutVersionStrings(&localized_strings, profile_); #endif } else { response = AboutVersionStaticContent(path); } } FinishDataRequest(response, request_id); } void AboutSource::FinishDataRequest(const std::string& html, int request_id) { std::string html_copy(html); SendResponse(request_id, base::RefCountedString::TakeString(&html_copy)); } std::string AboutSource::GetMimeType(const std::string& path) const { if (path == kCreditsJsPath || path == kStatsJsPath || path == kStringsJsPath || path == kVersionJsPath || path == kMemoryJsPath) { return "application/javascript"; } return "text/html"; } // ----------------------------------------------------------------------------- void InitializeAboutDataSource(const std::string& name, content::BrowserContext* browser_context) { Profile* profile = static_cast(browser_context); ChromeURLDataManager* manager = profile->GetChromeURLDataManager(); for (size_t i = 0; i < arraysize(kAboutSourceNames); i++) { if (name == kAboutSourceNames[i]) { manager->AddDataSource(new AboutSource(name, profile)); return; } } } bool WillHandleBrowserAboutURL(GURL* url, content::BrowserContext* browser_context) { // TODO(msw): Eliminate "about:*" constants and literals from code and tests, // then hopefully we can remove this forced fixup. *url = URLFixerUpper::FixupURL(url->possibly_invalid_spec(), std::string()); // Check that about: URLs are fixed up to chrome: by URLFixerUpper::FixupURL. DCHECK((*url == GURL(chrome::kAboutBlankURL)) || !url->SchemeIs(chrome::kAboutScheme)); // Only handle chrome://foo/, URLFixerUpper::FixupURL translates about:foo. // TAB_CONTENTS_WEB handles about:blank, which frames are allowed to access. if (!url->SchemeIs(chrome::kChromeUIScheme)) return false; // Circumvent processing URLs that the renderer process will handle. if (chrome_about_handler::WillHandle(*url)) return false; std::string host(url->host()); std::string path; // Replace about with chrome-urls. if (host == chrome::kChromeUIAboutHost) host = chrome::kChromeUIChromeURLsHost; // Replace cache with view-http-cache. if (host == chrome::kChromeUICacheHost) { host = chrome::kChromeUINetworkViewCacheHost; // Replace gpu with gpu-internals. } else if (host == chrome::kChromeUIGpuHost) { host = chrome::kChromeUIGpuInternalsHost; // Replace sync with sync-internals (for legacy reasons). } else if (host == chrome::kChromeUISyncHost) { host = chrome::kChromeUISyncInternalsHost; // Redirect chrome://extensions to chrome://settings/extensions. } else if (host == chrome::kChromeUIExtensionsHost) { host = chrome::kChromeUISettingsHost; path = chrome::kExtensionsSubPage; } GURL::Replacements replacements; replacements.SetHostStr(host); if (!path.empty()) replacements.SetPathStr(path); *url = url->ReplaceComponents(replacements); // Handle URLs to crash the browser or wreck the gpu process. if (host == chrome::kChromeUIBrowserCrashHost) { // Induce an intentional crash in the browser process. CHECK(false); } else if (host == chrome::kChromeUIGpuCleanHost) { GpuProcessHost::SendOnIO( 0, content::CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH, new GpuMsg_Clean()); } else if (host == chrome::kChromeUIGpuCrashHost) { GpuProcessHost::SendOnIO( 0, content::CAUSE_FOR_GPU_LAUNCH_ABOUT_GPUCRASH, new GpuMsg_Crash()); } else if (host == chrome::kChromeUIGpuHangHost) { GpuProcessHost::SendOnIO( 0, content::CAUSE_FOR_GPU_LAUNCH_ABOUT_GPUHANG, new GpuMsg_Hang()); #if defined(OS_CHROMEOS) } else if (host == chrome::kChromeUIRotateHost) { sensors::ScreenOrientation change; std::string query(url->query()); if (query == "left") { change.upward = sensors::ScreenOrientation::LEFT; } else if (query == "right") { change.upward = sensors::ScreenOrientation::RIGHT; } else if (query == "top") { change.upward = sensors::ScreenOrientation::TOP; } else if (query == "bottom") { change.upward = sensors::ScreenOrientation::BOTTOM; } else { NOTREACHED() << "Unknown orientation"; } sensors::Provider::GetInstance()->ScreenOrientationChanged(change); // Nothing to communicate to the user, so show a blank page. host = chrome::kChromeUIBlankHost; *url = GURL(chrome::kChromeUIBlankHost); #endif } // Initialize any potentially corresponding AboutSource handler. InitializeAboutDataSource(host, browser_context); return true; } bool HandleNonNavigationAboutURL(const GURL& url) { // chrome://ipc/ is currently buggy, so we disable it for official builds. #if !defined(OFFICIAL_BUILD) #if (defined(OS_MACOSX) || defined(OS_WIN)) && defined(IPC_MESSAGE_LOG_ENABLED) if (LowerCaseEqualsASCII(url.spec(), chrome::kChromeUIIPCURL)) { // Run the dialog. This will re-use the existing one if it's already up. browser::ShowAboutIPCDialog(); return true; } #endif #endif // OFFICIAL_BUILD return false; } std::vector ChromePaths() { std::vector paths; paths.reserve(arraysize(kChromePaths)); for (size_t i = 0; i < arraysize(kChromePaths); i++) paths.push_back(kChromePaths[i]); return paths; }