summaryrefslogtreecommitdiffstats
path: root/chrome/browser/browser_about_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/browser_about_handler.cc')
-rw-r--r--chrome/browser/browser_about_handler.cc1177
1 files changed, 1177 insertions, 0 deletions
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
new file mode 100644
index 0000000..14e748f
--- /dev/null
+++ b/chrome/browser/browser_about_handler.cc
@@ -0,0 +1,1177 @@
+// Copyright (c) 2010 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 <algorithm>
+#include <string>
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/callback.h"
+#include "base/file_version_info.h"
+#include "base/histogram.h"
+#include "base/i18n/number_formatting.h"
+#include "base/path_service.h"
+#include "base/platform_thread.h"
+#include "base/stats_table.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/thread.h"
+#include "base/tracked_objects.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/browser/google_service_auth_error.h"
+#include "chrome/browser/memory_details.h"
+#include "chrome/browser/metrics/histogram_synchronizer.h"
+#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/sync/profile_sync_service.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/pref_names.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/url_constants.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 "webkit/glue/webkit_glue.h"
+#ifdef CHROME_V8
+#include "v8/include/v8.h"
+#endif
+
+#if defined(OS_WIN)
+#include "chrome/browser/views/about_ipc_dialog.h"
+#elif defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/chromeos/cros/syslogs_library.h"
+#include "chrome/browser/chromeos/version_loader.h"
+#include "chrome/browser/zygote_host_linux.h"
+#elif defined(OS_MACOSX)
+#include "chrome/browser/cocoa/about_ipc_dialog.h"
+#elif defined(OS_LINUX)
+#include "chrome/browser/zygote_host_linux.h"
+#endif
+
+#if defined(USE_TCMALLOC)
+#include "third_party/tcmalloc/chromium/src/google/malloc_extension.h"
+#endif
+
+using sync_api::SyncManager;
+
+using base::Time;
+using base::TimeDelta;
+
+#if defined(USE_TCMALLOC)
+// Glue between the callback task and the method in the singleton.
+void AboutTcmallocRendererCallback(base::ProcessId pid, std::string output) {
+ Singleton<AboutTcmallocOutputs>::get()->RendererCallback(pid, output);
+}
+#endif
+
+namespace {
+
+// The (alphabetized) paths used for the about pages.
+// Note: Keep these in sync with url_constants.h
+const char kAppCacheInternalsPath[] = "appcache-internals";
+const char kCreditsPath[] = "credits";
+const char kCachePath[] = "view-http-cache";
+const char kDnsPath[] = "dns";
+const char kHistogramsPath[] = "histograms";
+const char kMemoryRedirectPath[] = "memory-redirect";
+const char kMemoryPath[] = "memory";
+const char kStatsPath[] = "stats";
+const char kSyncPath[] = "sync";
+const char kTasksPath[] = "tasks";
+const char kTcmallocPath[] = "tcmalloc";
+const char kTermsPath[] = "terms";
+const char kVersionPath[] = "version";
+const char kAboutPath[] = "about";
+// Not about:* pages, but included to make about:about look nicer
+const char kNetInternalsPath[] = "net-internals";
+const char kPluginsPath[] = "plugins";
+
+#if defined(OS_LINUX)
+const char kLinuxProxyConfigPath[] = "linux-proxy-config";
+const char kSandboxPath[] = "sandbox";
+#endif
+
+#if defined(OS_CHROMEOS)
+const char kNetworkPath[] = "network";
+const char kOSCreditsPath[] = "os-credits";
+const char kSysPath[] = "system";
+#endif
+
+// Add path here to be included in about:about
+const char *kAllAboutPaths[] = {
+ kAppCacheInternalsPath,
+ kCachePath,
+ kCreditsPath,
+ kDnsPath,
+ kHistogramsPath,
+ kMemoryPath,
+ kNetInternalsPath,
+ kPluginsPath,
+ kStatsPath,
+ kSyncPath,
+ kTasksPath,
+ kTcmallocPath,
+ kTermsPath,
+ kVersionPath,
+#if defined(OS_LINUX)
+ kLinuxProxyConfigPath,
+ kSandboxPath,
+#endif
+#if defined(OS_CHROMEOS)
+ kNetworkPath,
+ kOSCreditsPath,
+ kSysPath,
+#endif
+ };
+
+// Points to the singleton AboutSource object, if any.
+ChromeURLDataManager::DataSource* about_source = NULL;
+
+// When you type about:memory, it actually loads an 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() {
+ return "<meta http-equiv=\"refresh\" "
+ "content=\"0;chrome://about/memory\">";
+}
+
+class AboutSource : public ChromeURLDataManager::DataSource {
+ public:
+ // Creates our datasource.
+ AboutSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ // Send the response data.
+ void FinishDataRequest(const std::string& html, int request_id);
+
+ private:
+ virtual ~AboutSource();
+
+ DISALLOW_COPY_AND_ASSIGN(AboutSource);
+};
+
+// 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();
+
+ private:
+ ~AboutMemoryHandler() {}
+
+ void BindProcessMetrics(DictionaryValue* data,
+ ProcessMemoryInformation* info);
+ void AppendProcess(ListValue* child_data, ProcessMemoryInformation* info);
+
+ scoped_refptr<AboutSource> 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<AboutSource> 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);
+};
+#endif
+
+// Individual about handlers ---------------------------------------------------
+
+std::string AboutAbout() {
+ std::string html;
+ html.append("<html><head><title>About Pages</title></head><body>\n");
+ html.append("<h2>List of About pages</h2><ul>\n");
+ for (size_t i = 0; i < arraysize(kAllAboutPaths); i++) {
+ if (kAllAboutPaths[i] == kNetInternalsPath ||
+ kAllAboutPaths[i] == kPluginsPath ||
+ kAllAboutPaths[i] == kCachePath ||
+ kAllAboutPaths[i] == kAppCacheInternalsPath)
+ html.append("<li><a href='chrome://");
+ else
+ html.append("<li><a href='chrome://about/");
+ html.append(kAllAboutPaths[i]);
+ html.append("/'>about:");
+ html.append(kAllAboutPaths[i]);
+ html.append("</a>\n");
+ }
+ const char *debug[] = { "crash", "hang", "shorthang" };
+ html.append("</ul><h2>For Debug</h2>");
+ html.append("</ul><p>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.</p><ul>");
+ for (size_t i = 0; i < arraysize(debug); i++) {
+ html.append("<li>");
+ html.append("about:");
+ html.append(debug[i]);
+ html.append("\n");
+ }
+ html.append("</ul></body></html>");
+ return html;
+}
+
+#if defined(OS_CHROMEOS)
+std::string AboutNetwork(const std::string& query) {
+ int refresh;
+ StringToInt(query, &refresh);
+ return chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
+ GetHtmlInfo(refresh);
+}
+#endif
+
+// AboutDnsHandler bounces the request back to the IO thread to collect
+// the DNS information.
+class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
+ public:
+ static void Start(AboutSource* source, int request_id) {
+ scoped_refptr<AboutDnsHandler> handler =
+ new AboutDnsHandler(source, request_id);
+ handler->StartOnUIThread();
+ }
+
+ private:
+ AboutDnsHandler(AboutSource* source, int request_id)
+ : source_(source),
+ request_id_(request_id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ }
+
+ // Calls FinishOnUIThread() on completion.
+ void StartOnUIThread() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &AboutDnsHandler::StartOnIOThread));
+ }
+
+ void StartOnIOThread() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+
+ std::string data;
+ chrome_browser_net::PredictorGetHtmlInfo(&data);
+
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &AboutDnsHandler::FinishOnUIThread, data));
+ }
+
+ void FinishOnUIThread(const std::string& data) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ source_->FinishDataRequest(data, request_id_);
+ }
+
+ // Where the results are fed to.
+ scoped_refptr<AboutSource> source_;
+
+ // ID identifying the request.
+ int request_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler);
+};
+
+#if defined(USE_TCMALLOC)
+std::string AboutTcmalloc(const std::string& query) {
+ std::string data;
+ AboutTcmallocOutputsType* outputs =
+ Singleton<AboutTcmallocOutputs>::get()->outputs();
+
+ // Display any stats for which we sent off requests the last time.
+ data.append("<html><head><title>About tcmalloc</title></head><body>\n");
+ data.append("<p>Stats as of last page load;");
+ data.append("reload to get stats as of this page load.</p>\n");
+ data.append("<table width=\"100%\">\n");
+ for (AboutTcmallocOutputsType::const_iterator oit = outputs->begin();
+ oit != outputs->end();
+ oit++) {
+ data.append("<tr><td bgcolor=\"yellow\">");
+ data.append(oit->first);
+ data.append("</td></tr>\n");
+ data.append("<tr><td><pre>\n");
+ data.append(oit->second);
+ data.append("</pre></td></tr>\n");
+ }
+ data.append("</table>\n");
+ data.append("</body></html>\n");
+
+ // 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");
+ Singleton<AboutTcmallocOutputs>::get()->SetOutput(browser, buffer);
+ RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
+ while (!it.IsAtEnd()) {
+ it.GetCurrentValue()->Send(new ViewMsg_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 data;
+ StatisticsRecorder::WriteHTMLGraph(query, &data);
+ return data;
+}
+
+void AboutMemory(AboutSource* source, int request_id) {
+ // The AboutMemoryHandler cleans itself up, but |StartFetch()| will want the
+ // refcount to be greater than 0.
+ scoped_refptr<AboutMemoryHandler>
+ handler(new AboutMemoryHandler(source, request_id));
+ handler->StartFetch();
+}
+
+#ifdef TRACK_ALL_TASK_OBJECTS
+static std::string AboutObjects(const std::string& query) {
+ std::string data;
+ tracked_objects::ThreadData::WriteHTML(query, &data);
+ return data;
+}
+#endif // TRACK_ALL_TASK_OBJECTS
+
+std::string AboutStats() {
+ // We keep the DictionaryValue tree live so that we can do delta
+ // stats computations across runs.
+ static DictionaryValue root;
+
+ StatsTable* table = 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(L"counters", &counters)) {
+ counters = new ListValue();
+ root.Set(L"counters", counters);
+ }
+
+ ListValue* timers;
+ if (!root.GetList(L"timers", &timers)) {
+ timers = new ListValue();
+ root.Set(L"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::wstring scan_name;
+ if (dictionary->GetString(L"name", &scan_name) &&
+ WideToASCII(scan_name) == name) {
+ counter = dictionary;
+ }
+ } else {
+ NOTREACHED(); // Should always be there
+ }
+ }
+
+ if (counter == NULL) {
+ counter = new DictionaryValue();
+ counter->SetString(L"name", ASCIIToWide(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(L"value", &prior_value)) {
+ delta = new_value - prior_value;
+ }
+ counter->SetInteger(L"value", new_value);
+ counter->SetInteger(L"delta", delta);
+ }
+ break;
+ case 'm':
+ {
+ // TODO(mbelshe): implement me.
+ }
+ break;
+ case 't':
+ {
+ int time = table->GetRowValue(index);
+ counter->SetInteger(L"time", time);
+
+ // Store this on the timers list as well.
+ timers->Append(counter);
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ // Get about_stats.html
+ static const base::StringPiece stats_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_STATS_HTML));
+
+ // Create jstemplate and return.
+ std::string data = jstemplate_builder::GetTemplateHtml(
+ stats_html, &root, "t" /* template root node id */);
+
+ // Clear the timer list since we stored the data in the timers list as well.
+ for (int index = static_cast<int>(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;
+ data.append("<!DOCTYPE HTML>\n");
+ data.append("<html><head><meta charset=\"utf-8\"><title>");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE));
+ data.append("</title>");
+ data.append("<style>body { max-width: 70ex; padding: 2ex 5ex; }</style>");
+ data.append("</head><body>\n");
+ 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())));
+ data.append("</body></html>\n");
+ return data;
+}
+
+void AboutSandboxRow(std::string* data, const std::string& prefix, int name_id,
+ bool good) {
+ data->append("<tr><td>");
+ data->append(prefix);
+ data->append(l10n_util::GetStringUTF8(name_id));
+ if (good) {
+ data->append("</td><td style=\"color: green;\">");
+ data->append(
+ l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
+ } else {
+ data->append("</td><td style=\"color: red;\">");
+ data->append(
+ l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
+ }
+ data->append("</td></tr>");
+}
+
+std::string AboutSandbox() {
+ std::string data;
+ data.append("<!DOCTYPE HTML>\n");
+ data.append("<html><head><meta charset=\"utf-8\"><title>");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
+ data.append("</title>");
+ data.append("</head><body>\n");
+ data.append("<h1>");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
+ data.append("</h1>");
+
+ const int status = Singleton<ZygoteHost>()->sandbox_status();
+
+ data.append("<table>");
+
+ AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SUID_SANDBOX,
+ status & ZygoteHost::kSandboxSUID);
+ if (status & ZygoteHost::kSandboxPIDNS) {
+ AboutSandboxRow(&data, "&nbsp;&nbsp;", IDS_ABOUT_SANDBOX_PID_NAMESPACES,
+ status & ZygoteHost::kSandboxPIDNS);
+ AboutSandboxRow(&data, "&nbsp;&nbsp;", IDS_ABOUT_SANDBOX_NET_NAMESPACES,
+ status & ZygoteHost::kSandboxNetNS);
+ }
+ AboutSandboxRow(&data, "", IDS_ABOUT_SANDBOX_SECCOMP_SANDBOX,
+ status & ZygoteHost::kSandboxSeccomp);
+
+ data.append("</table>");
+
+ bool good = ((status & ZygoteHost::kSandboxSUID) &&
+ (status & ZygoteHost::kSandboxPIDNS)) ||
+ (status & ZygoteHost::kSandboxSeccomp);
+ if (good) {
+ data.append("<p style=\"color: green\">");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_OK));
+ } else {
+ data.append("<p style=\"color: red\">");
+ data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_BAD));
+ }
+ data.append("</p>");
+
+ data.append("</body></html>\n");
+ return data;
+}
+#endif
+
+std::string AboutVersion(DictionaryValue* localized_strings) {
+ localized_strings->SetString(L"title",
+ l10n_util::GetString(IDS_ABOUT_VERSION_TITLE));
+ scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
+ if (version_info == NULL) {
+ DLOG(ERROR) << "Unable to create FileVersionInfo object";
+ return std::string();
+ }
+
+ std::string webkit_version = webkit_glue::GetWebKitVersion();
+#ifdef CHROME_V8
+ std::string js_version(v8::V8::GetVersion());
+ std::string js_engine = "V8";
+#else
+ std::string js_version = webkit_version;
+ std::string js_engine = "JavaScriptCore";
+#endif
+
+ localized_strings->SetString(L"name",
+ l10n_util::GetString(IDS_PRODUCT_NAME));
+ localized_strings->SetString(L"version", version_info->file_version());
+ std::wstring mod = UTF16ToWide(platform_util::GetVersionStringModifier());
+ localized_strings->SetString(L"version_modifier", mod);
+ localized_strings->SetString(L"js_engine", js_engine);
+ localized_strings->SetString(L"js_version", js_version);
+ localized_strings->SetString(L"webkit_version", webkit_version);
+ localized_strings->SetString(L"company",
+ l10n_util::GetString(IDS_ABOUT_VERSION_COMPANY_NAME));
+ localized_strings->SetString(L"copyright",
+ l10n_util::GetString(IDS_ABOUT_VERSION_COPYRIGHT));
+ localized_strings->SetString(L"cl", version_info->last_change());
+ if (version_info->is_official_build()) {
+ localized_strings->SetString(L"official",
+ l10n_util::GetString(IDS_ABOUT_VERSION_OFFICIAL));
+ } else {
+ localized_strings->SetString(L"official",
+ l10n_util::GetString(IDS_ABOUT_VERSION_UNOFFICIAL));
+ }
+ localized_strings->SetString(L"user_agent_name",
+ l10n_util::GetString(IDS_ABOUT_VERSION_USER_AGENT));
+ localized_strings->SetString(L"useragent", webkit_glue::GetUserAgent(GURL()));
+ localized_strings->SetString(L"command_line_name",
+ l10n_util::GetString(IDS_ABOUT_VERSION_COMMAND_LINE));
+
+#if defined(OS_WIN)
+ localized_strings->SetString(L"command_line",
+ CommandLine::ForCurrentProcess()->command_line_string());
+#elif defined(OS_POSIX)
+ std::string command_line = "";
+ typedef std::vector<std::string> ArgvList;
+ const ArgvList& argv = CommandLine::ForCurrentProcess()->argv();
+ for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end(); iter++)
+ command_line += " " + *iter;
+ localized_strings->SetString(L"command_line", command_line);
+#endif
+
+ base::StringPiece version_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_VERSION_HTML));
+
+ return jstemplate_builder::GetTemplatesHtml(
+ version_html, localized_strings, "t" /* template root node id */);
+}
+
+static void AddBoolSyncDetail(ListValue* details, const std::wstring& stat_name,
+ bool stat_value) {
+ DictionaryValue* val = new DictionaryValue;
+ val->SetString(L"stat_name", stat_name);
+ val->SetBoolean(L"stat_value", stat_value);
+ details->Append(val);
+}
+
+static void AddIntSyncDetail(ListValue* details, const std::wstring& stat_name,
+ int64 stat_value) {
+ DictionaryValue* val = new DictionaryValue;
+ val->SetString(L"stat_name", stat_name);
+ val->SetString(L"stat_value", UTF16ToWide(base::FormatNumber(stat_value)));
+ details->Append(val);
+}
+
+static std::wstring MakeSyncAuthErrorText(
+ const GoogleServiceAuthError::State& state) {
+ switch (state) {
+ case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
+ return L"INVALID_GAIA_CREDENTIALS";
+ case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
+ return L"USER_NOT_SIGNED_UP";
+ case GoogleServiceAuthError::CONNECTION_FAILED:
+ return L"CONNECTION_FAILED";
+ default:
+ return std::wstring();
+ }
+}
+
+std::string AboutSync() {
+ FilePath user_data_dir;
+ if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
+ return std::string();
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
+ ProfileSyncService* service = profile->GetProfileSyncService();
+
+ DictionaryValue strings;
+ if (!service || !service->HasSyncSetupCompleted()) {
+ strings.SetString(L"summary", L"SYNC DISABLED");
+ } else {
+ SyncManager::Status full_status(service->QueryDetailedSyncStatus());
+
+ strings.SetString(L"summary",
+ ProfileSyncService::BuildSyncStatusSummaryText(
+ full_status.summary));
+
+ strings.Set(L"authenticated",
+ new FundamentalValue(full_status.authenticated));
+ strings.SetString(L"auth_problem",
+ MakeSyncAuthErrorText(service->GetAuthError().state()));
+
+ strings.SetString(L"time_since_sync", service->GetLastSyncedTimeString());
+
+ ListValue* details = new ListValue();
+ strings.Set(L"details", details);
+ AddBoolSyncDetail(details, L"Server Up", full_status.server_up);
+ AddBoolSyncDetail(details, L"Server Reachable",
+ full_status.server_reachable);
+ AddBoolSyncDetail(details, L"Server Broken", full_status.server_broken);
+ AddBoolSyncDetail(details, L"Notifications Enabled",
+ full_status.notifications_enabled);
+ AddIntSyncDetail(details, L"Notifications Received",
+ full_status.notifications_received);
+ AddIntSyncDetail(details, L"Notifications Sent",
+ full_status.notifications_sent);
+ AddIntSyncDetail(details, L"Unsynced Count", full_status.unsynced_count);
+ AddIntSyncDetail(details, L"Conflicting Count",
+ full_status.conflicting_count);
+ AddBoolSyncDetail(details, L"Syncing", full_status.syncing);
+ AddBoolSyncDetail(details, L"Initial Sync Ended",
+ full_status.initial_sync_ended);
+ AddBoolSyncDetail(details, L"Syncer Stuck", full_status.syncer_stuck);
+ AddIntSyncDetail(details, L"Updates Available",
+ full_status.updates_available);
+ AddIntSyncDetail(details, L"Updates Received",
+ full_status.updates_received);
+ AddBoolSyncDetail(details, L"Disk Full", full_status.disk_full);
+ AddBoolSyncDetail(details, L"Invalid Store", full_status.invalid_store);
+ AddIntSyncDetail(details, L"Max Consecutive Errors",
+ full_status.max_consecutive_errors);
+
+ if (service->unrecoverable_error_detected()) {
+ strings.Set(L"unrecoverable_error_detected", new FundamentalValue(true));
+ strings.SetString(L"unrecoverable_error_message",
+ service->unrecoverable_error_message());
+ tracked_objects::Location loc(service->unrecoverable_error_location());
+ std::string location_str;
+ loc.Write(true, true, &location_str);
+ strings.SetString(L"unrecoverable_error_location", location_str);
+ }
+
+ browser_sync::ModelSafeRoutingInfo routes;
+ service->backend()->GetModelSafeRoutingInfo(&routes);
+ ListValue* routing_info = new ListValue();
+ strings.Set(L"routing_info", routing_info);
+ browser_sync::ModelSafeRoutingInfo::const_iterator it = routes.begin();
+ for (; it != routes.end(); ++it) {
+ DictionaryValue* val = new DictionaryValue;
+ val->SetString(L"model_type", ModelTypeToString(it->first));
+ val->SetString(L"group", ModelSafeGroupToString(it->second));
+ routing_info->Append(val);
+ }
+ }
+
+ static const base::StringPiece sync_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_SYNC_HTML));
+
+ return jstemplate_builder::GetTemplateHtml(
+ sync_html, &strings , "t" /* template root node id */);
+}
+
+#if defined(OS_CHROMEOS)
+std::string AboutSys() {
+ DictionaryValue strings;
+ chromeos::SyslogsLibrary* syslogs_lib =
+ chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
+ scoped_ptr<chromeos::LogDictionaryType> sys_info_;
+ if (syslogs_lib)
+ sys_info_.reset(syslogs_lib->GetSyslogs(new FilePath()));
+ if (sys_info_.get()) {
+ ListValue* details = new ListValue();
+ strings.Set(L"details", details);
+ chromeos::LogDictionaryType::iterator it;
+
+ for (it = sys_info_.get()->begin(); it != sys_info_.get()->end(); ++it) {
+ DictionaryValue* val = new DictionaryValue;
+ val->SetString(L"stat_name", (*it).first);
+ val->SetString(L"stat_value", (*it).second);
+ details->Append(val);
+ }
+ }
+ static const base::StringPiece sys_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_SYS_HTML));
+
+ return jstemplate_builder::GetTemplateHtml(
+ sys_html, &strings , "t" /* template root node id */);
+}
+#endif
+
+// AboutSource -----------------------------------------------------------------
+
+AboutSource::AboutSource()
+ : DataSource(chrome::kAboutScheme, MessageLoop::current()) {
+ // This should be a singleton.
+ DCHECK(!about_source);
+ about_source = this;
+
+ // Add us to the global URL handler on the IO thread.
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ Singleton<ChromeURLDataManager>::get(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(this)));
+}
+
+AboutSource::~AboutSource() {
+ about_source = NULL;
+}
+
+void AboutSource::StartDataRequest(const std::string& path_raw,
+ bool is_off_the_record, int request_id) {
+ std::string path = path_raw;
+ std::string info;
+ if (path.find("/") != std::string::npos) {
+ size_t pos = path.find("/");
+ info = path.substr(pos + 1, path.length() - (pos + 1));
+ path = path.substr(0, pos);
+ }
+ path = StringToLowerASCII(path);
+
+ std::string response;
+ if (path == kDnsPath) {
+ AboutDnsHandler::Start(this, request_id);
+ return;
+ } else if (path == kHistogramsPath) {
+ response = AboutHistograms(info);
+ } else if (path == kMemoryPath) {
+ AboutMemory(this, request_id);
+ return;
+ } else if (path == kMemoryRedirectPath) {
+ response = GetAboutMemoryRedirectResponse();
+#ifdef TRACK_ALL_TASK_OBJECTS
+ } else if (path == kTasksPath) {
+ response = AboutObjects(info);
+#endif
+ } else if (path == kStatsPath) {
+ response = AboutStats();
+#if defined(USE_TCMALLOC)
+ } else if (path == kTcmallocPath) {
+ response = AboutTcmalloc(info);
+#endif
+ } else if (path == kVersionPath || path.empty()) {
+#if defined(OS_CHROMEOS)
+ new ChromeOSAboutVersionHandler(this, request_id);
+ return;
+#else
+ DictionaryValue value;
+ response = AboutVersion(&value);
+#endif
+ } else if (path == kCreditsPath) {
+ response = ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_CREDITS_HTML).as_string();
+ } else if (path == kAboutPath) {
+ response = AboutAbout();
+#if defined(OS_CHROMEOS)
+ } else if (path == kOSCreditsPath) {
+ response = ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_OS_CREDITS_HTML).as_string();
+ } else if (path == kNetworkPath) {
+ response = AboutNetwork(info);
+#endif
+ } else if (path == kTermsPath) {
+ response = ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_TERMS_HTML).as_string();
+#if defined(OS_LINUX)
+ } else if (path == kLinuxProxyConfigPath) {
+ response = AboutLinuxProxyConfig();
+ } else if (path == kSandboxPath) {
+ response = AboutSandbox();
+#endif
+ } else if (path == kSyncPath) {
+ response = AboutSync();
+#if defined(OS_CHROMEOS)
+ } else if (path == kSysPath) {
+ response = AboutSys();
+#endif
+ }
+
+ FinishDataRequest(response, request_id);
+}
+
+void AboutSource::FinishDataRequest(const std::string& response,
+ int request_id) {
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(response.size());
+ std::copy(response.begin(), response.end(), html_bytes->data.begin());
+ SendResponse(request_id, html_bytes);
+}
+
+// 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(L"ws_priv", static_cast<int>(info->working_set.priv));
+ data->SetInteger(L"ws_shareable",
+ static_cast<int>(info->working_set.shareable));
+ data->SetInteger(L"ws_shared", static_cast<int>(info->working_set.shared));
+ data->SetInteger(L"comm_priv", static_cast<int>(info->committed.priv));
+ data->SetInteger(L"comm_map", static_cast<int>(info->committed.mapped));
+ data->SetInteger(L"comm_image", static_cast<int>(info->committed.image));
+ data->SetInteger(L"pid", info->pid);
+ data->SetString(L"version", info->version);
+ data->SetInteger(L"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::wstring child_label(ChildProcessInfo::GetTypeNameInEnglish(info->type));
+ if (info->is_diagnostics)
+ child_label.append(L" (diagnostics)");
+ child->SetString(L"child_name", child_label);
+ ListValue* titles = new ListValue();
+ child->Set(L"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(L"browsers", browsers);
+
+ const std::vector<ProcessData>& 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.size() == 0)
+ 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(L"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(browser_processes[index].name);
+ log_string.append(L", ");
+ log_string.append(Int64ToWString(aggregate.working_set.priv));
+ log_string.append(L", ");
+ log_string.append(Int64ToWString(aggregate.working_set.shared));
+ log_string.append(L", ");
+ log_string.append(Int64ToWString(aggregate.working_set.shareable));
+ }
+ if (log_string.length() > 0)
+ LOG(INFO) << "memory: " << log_string;
+
+ // Set the browser & renderer detailed process data.
+ DictionaryValue* browser_data = new DictionaryValue();
+ root.Set(L"browzr_data", browser_data);
+ ListValue* child_data = new ListValue();
+ root.Set(L"child_data", child_data);
+
+ ProcessData process = browser_processes[0]; // Chrome is the first browser.
+ root.SetString(L"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(L"show_other_browsers",
+ browser_defaults::kShowOtherBrowsersInAboutMemory);
+
+ // Get about_memory.html
+ static const base::StringPiece memory_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_MEMORY_HTML));
+
+ // Create jstemplate and return.
+ std::string template_html = jstemplate_builder::GetTemplateHtml(
+ memory_html, &root, "t" /* template root node id */);
+
+ source_->FinishDataRequest(template_html, request_id_);
+}
+
+#if defined(OS_CHROMEOS)
+// ChromeOSAboutVersionHandler -----------------------------------------------
+
+ChromeOSAboutVersionHandler::ChromeOSAboutVersionHandler(AboutSource* source,
+ int request_id)
+ : source_(source),
+ request_id_(request_id) {
+ loader_.GetVersion(&consumer_,
+ NewCallback(this, &ChromeOSAboutVersionHandler::OnVersion));
+}
+
+void ChromeOSAboutVersionHandler::OnVersion(
+ chromeos::VersionLoader::Handle handle,
+ std::string version) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString(L"os_name",
+ l10n_util::GetString(IDS_PRODUCT_OS_NAME));
+ localized_strings.SetString(L"os_version", UTF8ToWide(version));
+ localized_strings.SetBoolean(L"is_chrome_os", true);
+ source_->FinishDataRequest(AboutVersion(&localized_strings), 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
+
+// Returns true if |url|'s spec starts with |about_specifier|, and is
+// terminated by the start of a path.
+bool StartsWithAboutSpecifier(const GURL& url, const char* about_specifier) {
+ return StartsWithASCII(url.spec(), about_specifier, true) &&
+ (url.spec().size() == strlen(about_specifier) ||
+ url.spec()[strlen(about_specifier)] == '/');
+}
+
+// Transforms a URL of the form "about:foo/XXX" to <url_prefix> + "XXX".
+GURL RemapAboutURL(const std::string& url_prefix, const GURL& url) {
+ std::string path;
+ size_t split = url.spec().find('/');
+ if (split != std::string::npos)
+ path = url.spec().substr(split + 1);
+ return GURL(url_prefix + path);
+}
+
+} // namespace
+
+// -----------------------------------------------------------------------------
+
+bool WillHandleBrowserAboutURL(GURL* url, Profile* profile) {
+ // We only handle about: schemes.
+ if (!url->SchemeIs(chrome::kAboutScheme))
+ return false;
+
+ // about:blank is special. Frames are allowed to access about:blank,
+ // but they are not allowed to access other types of about pages.
+ // Just ignore the about:blank and let the TAB_CONTENTS_WEB handle it.
+ if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutBlankURL))
+ return false;
+
+ // Rewrite about:cache/* URLs to chrome://view-http-cache/*
+ if (StartsWithAboutSpecifier(*url, chrome::kAboutCacheURL)) {
+ *url = RemapAboutURL(chrome::kNetworkViewCacheURL, *url);
+ return true;
+ }
+
+ // Rewrite about:net-internals/* URLs to chrome://net-internals/*
+ if (StartsWithAboutSpecifier(*url, chrome::kAboutNetInternalsURL)) {
+ *url = RemapAboutURL(chrome::kNetworkViewInternalsURL, *url);
+ return true;
+ }
+
+ // Rewrite about:appcache-internals/* URLs to chrome://appcache/*
+ if (StartsWithAboutSpecifier(*url, chrome::kAboutAppCacheInternalsURL)) {
+ *url = RemapAboutURL(chrome::kAppCacheViewInternalsURL, *url);
+ return true;
+ }
+
+ // Rewrite about:plugins to chrome://plugins/.
+ if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutPluginsURL)) {
+ *url = GURL(chrome::kChromeUIPluginsURL);
+ return true;
+ }
+
+ // Handle URL to crash the browser process.
+ if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutBrowserCrash)) {
+ // Induce an intentional crash in the browser process.
+ int* bad_pointer = NULL;
+ *bad_pointer = 42;
+ return true;
+ }
+
+ // There are a few about: URLs that we hand over to the renderer. If the
+ // renderer wants them, don't do any rewriting.
+ if (chrome_about_handler::WillHandle(*url))
+ return false;
+
+ // Anything else requires our special handler, make sure its initialized.
+ // We only need to register the AboutSource once and it is kept globally.
+ // There is currently no way to remove a data source.
+ static bool initialized = false;
+ if (!initialized) {
+ about_source = new AboutSource();
+ initialized = true;
+ }
+
+ // Special case about:memory to go through a redirect before ending up on
+ // the final page. See GetAboutMemoryRedirectResponse above for why.
+ if (LowerCaseEqualsASCII(url->path(), kMemoryPath)) {
+ *url = GURL("chrome://about/memory-redirect");
+ return true;
+ }
+
+ // Rewrite the about URL to use chrome:. WebKit treats all about URLS the
+ // same (blank page), so if we want to display content, we need another
+ // scheme.
+ std::string about_url = "chrome://about/";
+ about_url.append(url->path());
+ *url = GURL(about_url);
+ return true;
+}
+
+// This function gets called with the fixed-up chrome: URLs, so we have to
+// compare against those instead of "about:blah".
+bool HandleNonNavigationAboutURL(const GURL& url) {
+ // about: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.
+ AboutIPCDialog::RunDialog();
+ return true;
+ }
+#endif
+
+#endif // OFFICIAL_BUILD
+
+ return false;
+}