summaryrefslogtreecommitdiffstats
path: root/chrome/browser/browser_about_handler.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/browser_about_handler.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/browser_about_handler.cc')
-rw-r--r--chrome/browser/browser_about_handler.cc645
1 files changed, 645 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..fca4e8d
--- /dev/null
+++ b/chrome/browser/browser_about_handler.cc
@@ -0,0 +1,645 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/browser_about_handler.h"
+
+#include <string>
+#include <vector>
+
+#include "base/file_version_info.h"
+#include "base/histogram.h"
+#include "base/image_util.h"
+#include "base/process_util.h"
+#include "base/stats_table.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/tracked_objects.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_resources.h"
+#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/browser/ipc_status_view.h"
+#include "chrome/browser/memory_details.h"
+#include "chrome/browser/net/dns_global.h"
+#include "chrome/browser/plugin_process_host.h"
+#include "chrome/browser/plugin_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/render_process_host.h"
+#include "chrome/browser/render_view_host.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/renderer/about_handler.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/glue/webkit_glue.h"
+
+#include "generated_resources.h"
+
+// The URL scheme used for the about ui.
+static const char kAboutScheme[] = "about";
+
+// The paths used for the about pages.
+static const char kCachePath[] = "cache";
+static const char kDnsPath[] = "dns";
+static const char kHistogramsPath[] = "histograms";
+static const char kObjectsPath[] = "objects";
+static const char kMemoryPath[] = "memory";
+static const char kPluginsPath[] = "plugins";
+static const char kStatsPath[] = "stats";
+static const char kVersionPath[] = "version";
+
+class AboutSource : public ChromeURLDataManager::DataSource {
+ public:
+ // Creates our datasource.
+ AboutSource();
+ virtual ~AboutSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path, int request_id);
+
+ // Send the response data.
+ void FinishDataRequest(const std::string& html, int request_id);
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(AboutSource);
+};
+
+// Handling about:memory is complicated enough to encapsulate it's
+// related methods into a single class.
+class AboutMemoryHandler : public MemoryDetails {
+ public:
+ AboutMemoryHandler(AboutSource* source, int request_id);
+
+ virtual void OnDetailsAvailable();
+
+ private:
+ void BindProcessMetrics(DictionaryValue* data,
+ ProcessMemoryInformation* info);
+ void GetTabContentsTitles(RenderProcessHost* rph, ListValue* titles);
+ void AppendProcess(ListValue* renderers, ProcessMemoryInformation* info);
+ void FinishAboutMemory();
+
+ AboutSource* source_;
+ int request_id_;
+ DISALLOW_EVIL_CONSTRUCTORS(AboutMemoryHandler);
+};
+
+AboutSource::AboutSource()
+ : DataSource(kAboutScheme, MessageLoop::current()) {
+}
+
+AboutSource::~AboutSource() {
+}
+
+void AboutSource::StartDataRequest(const std::string& path_raw,
+ int request_id) {
+ std::string path = path_raw;
+ std::string info;
+ if (path.find("/") != -1) {
+ 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) {
+ response = BrowserAboutHandler::AboutDns();
+ } else if (path == kHistogramsPath) {
+ response = BrowserAboutHandler::AboutHistograms(info);
+ } else if (path == kMemoryPath) {
+ BrowserAboutHandler::AboutMemory(this, request_id);
+ return;
+ } else if (path == kObjectsPath) {
+ response = BrowserAboutHandler::AboutObjects(info);
+ } else if (path == kPluginsPath) {
+ response = BrowserAboutHandler::AboutPlugins();
+ } else if (path == kStatsPath) {
+ response = BrowserAboutHandler::AboutStats();
+ } else if (path == kVersionPath || path.empty()) {
+ response = BrowserAboutHandler::AboutVersion();
+ }
+ 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);
+}
+
+// This is the top-level URL handler for chrome-internal: URLs, and exposed in
+// our header file.
+bool BrowserAboutHandler::MaybeHandle(GURL* url,
+ TabContentsType* result_type) {
+ if (!url->SchemeIs(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 (StringToLowerASCII(url->path()) == "blank") {
+ return false;
+ }
+
+ // We create an about:cache mapping to the view-cache: internal URL.
+ if (StringToLowerASCII(url->path()) == kCachePath) {
+ *url = GURL("view-cache:");
+ *result_type = TAB_CONTENTS_WEB;
+ return true;
+ }
+
+ if (LowerCaseEqualsASCII(url->path(), "network")) {
+ // about:network doesn't have an internal protocol, so don't modify |url|.
+ *result_type = TAB_CONTENTS_NETWORK_STATUS_VIEW;
+ return true;
+ }
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ if ((LowerCaseEqualsASCII(url->path(), "ipc")) &&
+ (IPCStatusView::current() == NULL)) {
+ // about:ipc doesn't have an internal protocol, so don't modify |url|.
+ *result_type = TAB_CONTENTS_IPC_STATUS_VIEW;
+ return true;
+ }
+#endif
+
+ if (LowerCaseEqualsASCII(url->path(), "internets")) {
+ // about:internets doesn't have an internal protocol, so don't modify |url|.
+ *result_type = TAB_CONTENTS_ABOUT_INTERNETS_STATUS_VIEW;
+ return true;
+ }
+
+ // There are a few about URLs that we hand over to the renderer.
+ // If the renderer wants them, let it have them.
+ if (AboutHandler::WillHandle(*url))
+ return false;
+
+ *result_type = TAB_CONTENTS_ABOUT_UI;
+ std::string about_url = "chrome-resource://about/";
+ about_url.append(url->path());
+ *url = GURL(about_url);
+ return true;
+}
+
+BrowserAboutHandler::BrowserAboutHandler(Profile* profile,
+ SiteInstance* instance,
+ RenderViewHostFactory* render_view_factory) :
+ WebContents(profile, instance, render_view_factory, MSG_ROUTING_NONE, NULL) {
+ type_ = TAB_CONTENTS_ABOUT_UI;
+
+ // 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();
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(&chrome_url_data_manager,
+ &ChromeURLDataManager::AddDataSource,
+ about_source_));
+ initialized = true;
+ }
+}
+
+bool BrowserAboutHandler::SupportsURL(GURL* url) {
+ // Enable this tab contents to access javascript urls.
+ if (url->SchemeIs("javascript"))
+ return true;
+ return WebContents::SupportsURL(url);
+}
+
+
+// static
+std::string BrowserAboutHandler::AboutVersion() {
+ // Strings used in the JsTemplate file.
+ DictionaryValue localized_strings;
+ localized_strings.SetString(L"title",
+ l10n_util::GetString(IDS_ABOUT_VERSION_TITLE));
+ scoped_ptr<FileVersionInfo> version_info(
+ FileVersionInfo::CreateFileVersionInfoForCurrentModule());
+ if (version_info == NULL) {
+ DLOG(ERROR) << "Unable to create FileVersionInfo object";
+ return std::string();
+ }
+ localized_strings.SetString(L"name",
+ l10n_util::GetString(IDS_PRODUCT_NAME));
+ localized_strings.SetString(L"version", version_info->file_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"useragent",
+ UTF8ToWide(webkit_glue::GetDefaultUserAgent()));
+
+ static const StringPiece version_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_VERSION_HTML));
+
+ return jstemplate_builder::GetTemplateHtml(
+ version_html, &localized_strings, "t" /* template root node id */);
+}
+
+// static
+std::string BrowserAboutHandler::AboutPlugins() {
+ // Strings used in the JsTemplate file.
+ DictionaryValue localized_strings;
+ localized_strings.SetString(L"title",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_TITLE));
+ localized_strings.SetString(L"headingPlugs",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_HEADING_PLUGS));
+ localized_strings.SetString(L"headingNoPlugs",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_HEADING_NOPLUGS));
+ localized_strings.SetString(L"filename",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_FILENAME_LABEL));
+ localized_strings.SetString(L"mimetype",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_MIMETYPE_LABEL));
+ localized_strings.SetString(L"description",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_DESCRIPTION_LABEL));
+ localized_strings.SetString(L"suffixes",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_SUFFIX_LABEL));
+ localized_strings.SetString(L"enabled",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_ENABLED_LABEL));
+ localized_strings.SetString(L"enabled_yes",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_ENABLED_YES));
+ localized_strings.SetString(L"enabled_no",
+ l10n_util::GetString(IDS_ABOUT_PLUGINS_ENABLED_NO));
+
+ static const StringPiece plugins_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ABOUT_PLUGINS_HTML));
+
+ return jstemplate_builder::GetTemplateHtml(
+ plugins_html, &localized_strings, "t" /* template root node id */);
+}
+
+// static
+std::string BrowserAboutHandler::AboutHistograms(const std::string query) {
+ std::string data;
+ StatisticsRecorder::WriteHTMLGraph(query, &data);
+ return data;
+}
+
+// static
+std::string BrowserAboutHandler::AboutObjects(const std::string& query) {
+ std::string data;
+ tracked_objects::ThreadData::WriteHTML(query, &data);
+ return data;
+}
+
+// static
+std::string BrowserAboutHandler::AboutDns() {
+ std::string data;
+ chrome_browser_net::DnsPrefetchGetHtmlInfo(&data);
+ return data;
+}
+
+// static
+std::string BrowserAboutHandler::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::wstring full_name = table->GetRowName(index);
+ if (full_name.length() == 0)
+ break;
+ DCHECK(full_name[1] == L':');
+ wchar_t counter_type = full_name[0];
+ std::wstring name = full_name.substr(2);
+
+ // JSON doesn't allow '.' in names.
+ size_t pos;
+ while ( ( pos = name.find(L".") ) != -1 )
+ name.replace(pos, 1, L":");
+
+ // 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) &&
+ scan_name == name) {
+ counter = dictionary;
+ }
+ } else {
+ NOTREACHED(); // Should always be there
+ }
+ }
+
+ if (counter == NULL) {
+ counter = new DictionaryValue();
+ counter->SetString(L"name", name);
+ counters->Append(counter);
+ }
+
+ switch (counter_type) {
+ case L'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 L'm':
+ {
+ // TODO(mbelshe): implement me.
+ }
+ break;
+ case L'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 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;
+}
+
+AboutMemoryHandler::AboutMemoryHandler(AboutSource* source, int request_id)
+ : source_(source),
+ request_id_(request_id) {
+ StartFetch();
+}
+
+// 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 iterate over a RenderProcessHost's listeners
+// and retrieve the tab titles.
+void AboutMemoryHandler::GetTabContentsTitles(RenderProcessHost* rph,
+ ListValue* titles) {
+ RenderProcessHost::listeners_iterator iter;
+ // NOTE: This is a bit dangerous. We know that for now, listeners
+ // are always RenderWidgetHosts. But in theory, they don't
+ // have to be.
+ for (iter = rph->listeners_begin(); iter != rph->listeners_end(); iter++) {
+ RenderWidgetHost* widget = static_cast<RenderWidgetHost*>(iter->second);
+ DCHECK(widget);
+ if (!widget || !widget->IsRenderView())
+ continue;
+
+ RenderViewHost* host = static_cast<RenderViewHost*>(widget);
+ TabContents* contents = static_cast<WebContents*>(host->delegate());
+ DCHECK(contents);
+ if (!contents)
+ continue;
+
+ std::wstring title = contents->GetTitle();
+ StringValue* val = NULL;
+ if (!title.length())
+ title = L"Untitled";
+ val = new StringValue(title);
+ titles->Append(val);
+ }
+}
+
+// Helper for AboutMemory to append memory usage information for all
+// sub-processes (renderers & plugins) used by chrome.
+void AboutMemoryHandler::AppendProcess(ListValue* renderers,
+ ProcessMemoryInformation* info) {
+ DCHECK(renderers && info);
+
+ // Append a new DictionaryValue for this renderer to our list.
+ DictionaryValue* renderer = new DictionaryValue();
+ renderers->Append(renderer);
+ BindProcessMetrics(renderer, info);
+
+ // Now get more information about the process.
+
+ // First, figure out if it is a renderer.
+ RenderProcessHost::iterator renderer_iter;
+ for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
+ RenderProcessHost::end(); ++renderer_iter) {
+ if (renderer_iter->second->pid() == info->pid)
+ break;
+ }
+ if (renderer_iter != RenderProcessHost::end()) {
+ std::wstring renderer_label(L"Tab ");
+ renderer_label.append(FormatNumber(renderer_iter->second->host_id()));
+ if (info->is_diagnostics)
+ renderer_label.append(L" (diagnostics)");
+ renderer->SetString(L"renderer_id", renderer_label);
+ ListValue* titles = new ListValue();
+ renderer->Set(L"titles", titles);
+ GetTabContentsTitles(renderer_iter->second, titles);
+ return;
+ }
+
+ // Figure out if this is a plugin process.
+ for (size_t index = 0; index < plugins()->size(); ++index) {
+ if (info->pid == (*plugins())[index].pid) {
+ // It is a plugin!
+ std::wstring label(L"Plug-in");
+ std::wstring name;
+ renderer->SetString(L"renderer_id", label);
+ FileVersionInfo* version_info =
+ FileVersionInfo::CreateFileVersionInfo(
+ (*plugins())[index].dll_path);
+ if (version_info)
+ name = version_info->product_name();
+ ListValue* titles = new ListValue();
+ renderer->Set(L"titles", titles);
+ titles->Append(new StringValue(name));
+ return;
+ }
+ }
+}
+
+
+void AboutMemoryHandler::OnDetailsAvailable() {
+ // the root of the JSON hierarchy for about:memory jstemplate
+ DictionaryValue root;
+ ListValue* browsers = new ListValue();
+ root.Set(L"browsers", browsers);
+
+ ProcessData* browser_processes = processes();
+
+ // Aggregate per-process data into browser summary data.
+ std::wstring log_string;
+ for (int index = 0; index < MemoryDetails::MAX_BROWSERS; index++) {
+ if (browser_processes[index].processes.size() == 0)
+ continue;
+
+ // Sum the information for the processes within this browser.
+ ProcessMemoryInformation aggregate;
+ ProcessMemoryInformationList::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* renderer_data = new ListValue();
+ root.Set(L"renderer_data", renderer_data);
+
+ DWORD browser_pid = GetCurrentProcessId();
+ ProcessData process = browser_processes[0]; // Chrome is the first browser.
+ for (size_t index = 0; index < process.processes.size(); index++) {
+ if (process.processes[index].pid == browser_pid)
+ BindProcessMetrics(browser_data, &process.processes[index]);
+ else
+ AppendProcess(renderer_data, &process.processes[index]);
+ }
+
+ // Get about_memory.html
+ static const 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 */);
+
+ AboutSource* about_source = static_cast<AboutSource*>(source_);
+ about_source->FinishDataRequest(template_html, request_id_);
+}
+
+// static
+void BrowserAboutHandler::AboutMemory(AboutSource* source, int request_id) {
+ // The AboutMemoryHandler cleans itself up.
+ new AboutMemoryHandler(source, request_id);
+}