15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/memory_details.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <psapi.h>
8bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include <TlHelp32.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_version_info.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_version_info.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
1903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/chromium_strings.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/process_type.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Known browsers which we collect details for.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHROME_BROWSER = 0,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHROME_NACL_PROCESS,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IE_BROWSER,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FIREFOX_BROWSER,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OPERA_BROWSER,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SAFARI_BROWSER,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IE_64BIT_BROWSER,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KONQUEROR_BROWSER,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MAX_BROWSERS
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} BrowserProcess;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MemoryDetails::MemoryDetails()
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : user_metrics_mode_(UPDATE_USER_METRICS),
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      memory_growth_tracker_(NULL) {
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static const base::string16 google_browser_name =
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* name;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* process_name;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } process_template[MAX_BROWSERS] = {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { google_browser_name.c_str(), L"chrome.exe", },
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { google_browser_name.c_str(), L"nacl64.exe", },
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { L"IE", L"iexplore.exe", },
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { L"Firefox", L"firefox.exe", },
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { L"Opera", L"opera.exe", },
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { L"Safari", L"safari.exe", },
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { L"IE (64bit)", L"iexplore.exe", },
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { L"Konqueror", L"konqueror.exe", },
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int index = 0; index < MAX_BROWSERS; ++index) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProcessData process;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process.name = process_template[index].name;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process.process_name = process_template[index].process_name;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process_data_.push_back(process);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessData* MemoryDetails::ChromeBrowser() {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &process_data_[CHROME_BROWSER];
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryDetails::CollectProcessData(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ProcessMemoryInformation>& child_info) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear old data.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int index = 0; index < process_data_.size(); index++)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process_data_[index].processes.clear();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::OSInfo::WindowsArchitecture windows_architecture =
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::win::OSInfo::GetInstance()->architecture();
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle snapshot(
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PROCESSENTRY32 process_entry = {sizeof(PROCESSENTRY32)};
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!snapshot.Get()) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "CreateToolhelp32Snaphot failed: " << GetLastError();
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!::Process32First(snapshot.Get(), &process_entry)) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Process32First failed: " << GetLastError();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ProcessId pid = process_entry.th32ProcessID;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::ScopedHandle process_handle(::OpenProcess(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!process_handle.IsValid())
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_64bit_process =
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ((windows_architecture == base::win::OSInfo::X64_ARCHITECTURE) ||
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (windows_architecture == base::win::OSInfo::IA64_ARCHITECTURE)) &&
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        (base::win::OSInfo::GetWOW64StatusForProcess(process_handle.Get()) ==
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::win::OSInfo::WOW64_DISABLED);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (unsigned int index2 = 0; index2 < process_data_.size(); index2++) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (_wcsicmp(process_data_[index2].process_name.c_str(),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   process_entry.szExeFile) != 0)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index2 == IE_BROWSER && is_64bit_process)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;  // Should use IE_64BIT_BROWSER
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Get Memory Information.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProcessMemoryInformation info;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info.pid = pid;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (info.pid == GetCurrentProcessId())
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        info.process_type = content::PROCESS_TYPE_BROWSER;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        info.process_type = content::PROCESS_TYPE_UNKNOWN;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_ptr<base::ProcessMetrics> metrics;
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      metrics.reset(base::ProcessMetrics::CreateProcessMetrics(
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        process_handle.Get()));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      metrics->GetCommittedKBytes(&info.committed);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      metrics->GetWorkingSetKBytes(&info.working_set);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Get Version Information.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TCHAR name[MAX_PATH];
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index2 == CHROME_BROWSER || index2 == CHROME_NACL_PROCESS) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chrome::VersionInfo version_info;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (version_info.is_valid())
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          info.version = base::ASCIIToWide(version_info.Version());
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Check if this is one of the child processes whose data we collected
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // on the IO thread, and if so copy over that data.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t child = 0; child < child_info.size(); child++) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (child_info[child].pid != info.pid)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          info.titles = child_info[child].titles;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          info.process_type = child_info[child].process_type;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      } else if (GetModuleFileNameEx(process_handle.Get(), NULL, name,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     MAX_PATH - 1)) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::wstring str_name(name);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        scoped_ptr<FileVersionInfo> version_info(
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            FileVersionInfo::CreateFileVersionInfo(base::FilePath(str_name)));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (version_info != NULL) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          info.version = version_info->product_version();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          info.product_name = version_info->product_name();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add the process info to our list.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index2 == CHROME_NACL_PROCESS) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Add NaCl processes to Chrome's list
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        process_data_[CHROME_BROWSER].processes.push_back(info);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        process_data_[index2].processes.push_back(info);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } while (::Process32Next(snapshot.Get(), &process_entry));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally return to the browser thread.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI, FROM_HERE,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this));
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
165