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