memory_details_win.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/memory_details.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <psapi.h>
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/l10n_util.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_version_info.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_child_process_host.h"
13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/browser_thread.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/backing_store_manager.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_process_host.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/navigation_entry.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_version_info.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/chromium_strings.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Known browsers which we collect details for.
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochenum {
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHROME_BROWSER = 0,
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHROME_NACL_PROCESS,
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  IE_BROWSER,
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FIREFOX_BROWSER,
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OPERA_BROWSER,
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SAFARI_BROWSER,
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  IE_64BIT_BROWSER,
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  KONQUEROR_BROWSER,
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MAX_BROWSERS
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} BrowserProcess;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochMemoryDetails::MemoryDetails() {
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const std::wstring google_browser_name =
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      l10n_util::GetString(IDS_PRODUCT_NAME);
38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  struct {
39731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const wchar_t* name;
40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const wchar_t* process_name;
41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } process_template[MAX_BROWSERS] = {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { google_browser_name.c_str(), L"chrome.exe", },
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { google_browser_name.c_str(), L"nacl64.exe", },
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"IE", L"iexplore.exe", },
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"Firefox", L"firefox.exe", },
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"Opera", L"opera.exe", },
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"Safari", L"safari.exe", },
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"IE (64bit)", L"iexplore.exe", },
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"Konqueror", L"konqueror.exe", },
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (int index = 0; index < MAX_BROWSERS; ++index) {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProcessData process;
54731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    process.name = process_template[index].name;
55731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    process.process_name = process_template[index].process_name;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    process_data_.push_back(process);
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessData* MemoryDetails::ChromeBrowser() {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return &process_data_[CHROME_BROWSER];
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MemoryDetails::CollectProcessData(
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<ProcessMemoryInformation> child_info) {
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Clear old data.
69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (unsigned int index = 0; index < process_data_.size(); index++)
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    process_data_[index].processes.clear();
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SYSTEM_INFO system_info;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetNativeSystemInfo(&system_info);
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool is_64bit_os =
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedHandle snapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PROCESSENTRY32 process_entry = {sizeof(PROCESSENTRY32)};
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!snapshot.Get()) {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "CreateToolhelp32Snaphot failed: " << GetLastError();
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!::Process32First(snapshot, &process_entry)) {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Process32First failed: " << GetLastError();
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  do {
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::ProcessId pid = process_entry.th32ProcessID;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScopedHandle handle(::OpenProcess(
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!handle.Get())
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool is_64bit_process = false;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // IsWow64Process() returns FALSE for a 32bit process on a 32bit OS.
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We need to check if the real OS is 64bit.
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (is_64bit_os) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BOOL is_wow64 = FALSE;
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // IsWow64Process() is supported by Windows XP SP2 or later.
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      IsWow64Process(handle, &is_wow64);
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      is_64bit_process = !is_wow64;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    for (unsigned int index2 = 0; index2 < process_data_.size(); index2++) {
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (_wcsicmp(process_data_[index2].process_name.c_str(),
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   process_entry.szExeFile) != 0)
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (index2 == IE_BROWSER && is_64bit_process)
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;  // Should use IE_64BIT_BROWSER
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Get Memory Information.
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ProcessMemoryInformation info;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      info.pid = pid;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (info.pid == GetCurrentProcessId())
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        info.type = ChildProcessInfo::BROWSER_PROCESS;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      else
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        info.type = ChildProcessInfo::UNKNOWN_PROCESS;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<base::ProcessMetrics> metrics;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      metrics.reset(base::ProcessMetrics::CreateProcessMetrics(handle));
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      metrics->GetCommittedKBytes(&info.committed);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      metrics->GetWorkingSetKBytes(&info.working_set);
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Get Version Information.
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TCHAR name[MAX_PATH];
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (index2 == CHROME_BROWSER || index2 == CHROME_NACL_PROCESS) {
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        chrome::VersionInfo version_info;
1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (version_info.is_valid())
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          info.version = ASCIIToWide(version_info.Version());
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Check if this is one of the child processes whose data we collected
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // on the IO thread, and if so copy over that data.
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        for (size_t child = 0; child < child_info.size(); child++) {
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (child_info[child].pid != info.pid)
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            continue;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          info.titles = child_info[child].titles;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          info.type = child_info[child].type;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else if (GetModuleFileNameEx(handle, NULL, name, MAX_PATH - 1)) {
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::wstring str_name(name);
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        scoped_ptr<FileVersionInfo> version_info(
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            FileVersionInfo::CreateFileVersionInfo(str_name));
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (version_info != NULL) {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          info.version = version_info->product_version();
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          info.product_name = version_info->product_name();
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Add the process info to our list.
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (index2 == CHROME_NACL_PROCESS) {
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Add NaCl processes to Chrome's list
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        process_data_[CHROME_BROWSER].processes.push_back(info);
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        process_data_[index2].processes.push_back(info);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } while (::Process32Next(snapshot, &process_entry));
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Finally return to the browser thread.
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &MemoryDetails::CollectChildInfoOnUIThread));
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
162