13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 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"
63f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <psapi.h>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/file_path.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_version_info.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/win/scoped_handle.h"
14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/win/windows_version.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_version_info.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_child_process_host.h"
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/backing_store_manager.h"
20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_process_host.h"
21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_entry.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/chromium_strings.h"
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Known browsers which we collect details for.
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochenum {
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHROME_BROWSER = 0,
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHROME_NACL_PROCESS,
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  IE_BROWSER,
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FIREFOX_BROWSER,
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OPERA_BROWSER,
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SAFARI_BROWSER,
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  IE_64BIT_BROWSER,
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  KONQUEROR_BROWSER,
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MAX_BROWSERS
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} BrowserProcess;
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochMemoryDetails::MemoryDetails() {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const std::wstring google_browser_name =
403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      UTF16ToWide(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  struct {
42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const wchar_t* name;
43731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const wchar_t* process_name;
44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } process_template[MAX_BROWSERS] = {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { google_browser_name.c_str(), L"chrome.exe", },
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { google_browser_name.c_str(), L"nacl64.exe", },
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"IE", L"iexplore.exe", },
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"Firefox", L"firefox.exe", },
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"Opera", L"opera.exe", },
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"Safari", L"safari.exe", },
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"IE (64bit)", L"iexplore.exe", },
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { L"Konqueror", L"konqueror.exe", },
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (int index = 0; index < MAX_BROWSERS; ++index) {
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProcessData process;
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    process.name = process_template[index].name;
58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    process.process_name = process_template[index].process_name;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    process_data_.push_back(process);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessData* MemoryDetails::ChromeBrowser() {
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return &process_data_[CHROME_BROWSER];
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MemoryDetails::CollectProcessData(
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::vector<ProcessMemoryInformation>& child_info) {
69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Clear old data.
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (unsigned int index = 0; index < process_data_.size(); index++)
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    process_data_[index].processes.clear();
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::win::OSInfo::WindowsArchitecture windows_architecture =
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      base::win::OSInfo::GetInstance()->architecture();
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::win::ScopedHandle snapshot(
793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PROCESSENTRY32 process_entry = {sizeof(PROCESSENTRY32)};
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!snapshot.Get()) {
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "CreateToolhelp32Snaphot failed: " << GetLastError();
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!::Process32First(snapshot, &process_entry)) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Process32First failed: " << GetLastError();
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  do {
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::ProcessId pid = process_entry.th32ProcessID;
91dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    base::win::ScopedHandle process_handle(::OpenProcess(
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!process_handle.Get())
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    bool is_64bit_process =
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ((windows_architecture == base::win::OSInfo::X64_ARCHITECTURE) ||
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         (windows_architecture == base::win::OSInfo::IA64_ARCHITECTURE)) &&
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        (base::win::OSInfo::GetWOW64StatusForProcess(process_handle) ==
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            base::win::OSInfo::WOW64_DISABLED);
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    for (unsigned int index2 = 0; index2 < process_data_.size(); index2++) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (_wcsicmp(process_data_[index2].process_name.c_str(),
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   process_entry.szExeFile) != 0)
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (index2 == IE_BROWSER && is_64bit_process)
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;  // Should use IE_64BIT_BROWSER
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Get Memory Information.
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ProcessMemoryInformation info;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      info.pid = pid;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (info.pid == GetCurrentProcessId())
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        info.type = ChildProcessInfo::BROWSER_PROCESS;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      else
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        info.type = ChildProcessInfo::UNKNOWN_PROCESS;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<base::ProcessMetrics> metrics;
115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      metrics.reset(base::ProcessMetrics::CreateProcessMetrics(process_handle));
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      metrics->GetCommittedKBytes(&info.committed);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      metrics->GetWorkingSetKBytes(&info.working_set);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Get Version Information.
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TCHAR name[MAX_PATH];
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (index2 == CHROME_BROWSER || index2 == CHROME_NACL_PROCESS) {
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        chrome::VersionInfo version_info;
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (version_info.is_valid())
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          info.version = ASCIIToWide(version_info.Version());
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Check if this is one of the child processes whose data we collected
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // on the IO thread, and if so copy over that data.
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        for (size_t child = 0; child < child_info.size(); child++) {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (child_info[child].pid != info.pid)
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            continue;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          info.titles = child_info[child].titles;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          info.type = child_info[child].type;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      } else if (GetModuleFileNameEx(process_handle, NULL, name,
135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                     MAX_PATH - 1)) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::wstring str_name(name);
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        scoped_ptr<FileVersionInfo> version_info(
13821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen            FileVersionInfo::CreateFileVersionInfo(FilePath(str_name)));
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (version_info != NULL) {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          info.version = version_info->product_version();
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          info.product_name = version_info->product_name();
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Add the process info to our list.
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (index2 == CHROME_NACL_PROCESS) {
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Add NaCl processes to Chrome's list
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        process_data_[CHROME_BROWSER].processes.push_back(info);
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        process_data_[index2].processes.push_back(info);
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } while (::Process32Next(snapshot, &process_entry));
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Finally return to the browser thread.
157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &MemoryDetails::CollectChildInfoOnUIThread));
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
161