Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2012 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 #include <TlHelp32.h>
      9 
     10 #include "base/bind.h"
     11 #include "base/file_version_info.h"
     12 #include "base/files/file_path.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/win/scoped_handle.h"
     16 #include "base/win/windows_version.h"
     17 #include "chrome/common/chrome_version_info.h"
     18 #include "chrome/common/url_constants.h"
     19 #include "chrome/grit/chromium_strings.h"
     20 #include "content/public/browser/browser_thread.h"
     21 #include "content/public/common/process_type.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 
     24 using content::BrowserThread;
     25 
     26 // Known browsers which we collect details for.
     27 enum {
     28   CHROME_BROWSER = 0,
     29   CHROME_NACL_PROCESS,
     30   IE_BROWSER,
     31   FIREFOX_BROWSER,
     32   OPERA_BROWSER,
     33   SAFARI_BROWSER,
     34   IE_64BIT_BROWSER,
     35   KONQUEROR_BROWSER,
     36   MAX_BROWSERS
     37 } BrowserProcess;
     38 
     39 MemoryDetails::MemoryDetails()
     40     : user_metrics_mode_(UPDATE_USER_METRICS),
     41       memory_growth_tracker_(NULL) {
     42   static const base::string16 google_browser_name =
     43       l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
     44   struct {
     45     const wchar_t* name;
     46     const wchar_t* process_name;
     47   } process_template[MAX_BROWSERS] = {
     48     { google_browser_name.c_str(), L"chrome.exe", },
     49     { google_browser_name.c_str(), L"nacl64.exe", },
     50     { L"IE", L"iexplore.exe", },
     51     { L"Firefox", L"firefox.exe", },
     52     { L"Opera", L"opera.exe", },
     53     { L"Safari", L"safari.exe", },
     54     { L"IE (64bit)", L"iexplore.exe", },
     55     { L"Konqueror", L"konqueror.exe", },
     56   };
     57 
     58   for (int index = 0; index < MAX_BROWSERS; ++index) {
     59     ProcessData process;
     60     process.name = process_template[index].name;
     61     process.process_name = process_template[index].process_name;
     62     process_data_.push_back(process);
     63   }
     64 }
     65 
     66 ProcessData* MemoryDetails::ChromeBrowser() {
     67   return &process_data_[CHROME_BROWSER];
     68 }
     69 
     70 void MemoryDetails::CollectProcessData(
     71     const std::vector<ProcessMemoryInformation>& child_info) {
     72   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     73 
     74   // Clear old data.
     75   for (unsigned int index = 0; index < process_data_.size(); index++)
     76     process_data_[index].processes.clear();
     77 
     78   base::win::OSInfo::WindowsArchitecture windows_architecture =
     79       base::win::OSInfo::GetInstance()->architecture();
     80 
     81   base::win::ScopedHandle snapshot(
     82       ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
     83   PROCESSENTRY32 process_entry = {sizeof(PROCESSENTRY32)};
     84   if (!snapshot.Get()) {
     85     LOG(ERROR) << "CreateToolhelp32Snaphot failed: " << GetLastError();
     86     return;
     87   }
     88   if (!::Process32First(snapshot.Get(), &process_entry)) {
     89     LOG(ERROR) << "Process32First failed: " << GetLastError();
     90     return;
     91   }
     92   do {
     93     base::ProcessId pid = process_entry.th32ProcessID;
     94     base::win::ScopedHandle process_handle(::OpenProcess(
     95         PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
     96     if (!process_handle.IsValid())
     97       continue;
     98     bool is_64bit_process =
     99         ((windows_architecture == base::win::OSInfo::X64_ARCHITECTURE) ||
    100          (windows_architecture == base::win::OSInfo::IA64_ARCHITECTURE)) &&
    101         (base::win::OSInfo::GetWOW64StatusForProcess(process_handle.Get()) ==
    102             base::win::OSInfo::WOW64_DISABLED);
    103     for (unsigned int index2 = 0; index2 < process_data_.size(); index2++) {
    104       if (_wcsicmp(process_data_[index2].process_name.c_str(),
    105                    process_entry.szExeFile) != 0)
    106         continue;
    107       if (index2 == IE_BROWSER && is_64bit_process)
    108         continue;  // Should use IE_64BIT_BROWSER
    109       // Get Memory Information.
    110       ProcessMemoryInformation info;
    111       info.pid = pid;
    112       if (info.pid == GetCurrentProcessId())
    113         info.process_type = content::PROCESS_TYPE_BROWSER;
    114       else
    115         info.process_type = content::PROCESS_TYPE_UNKNOWN;
    116 
    117       scoped_ptr<base::ProcessMetrics> metrics;
    118       metrics.reset(base::ProcessMetrics::CreateProcessMetrics(
    119                         process_handle.Get()));
    120       metrics->GetCommittedKBytes(&info.committed);
    121       metrics->GetWorkingSetKBytes(&info.working_set);
    122 
    123       // Get Version Information.
    124       TCHAR name[MAX_PATH];
    125       if (index2 == CHROME_BROWSER || index2 == CHROME_NACL_PROCESS) {
    126         chrome::VersionInfo version_info;
    127         if (version_info.is_valid())
    128           info.version = base::ASCIIToWide(version_info.Version());
    129         // Check if this is one of the child processes whose data we collected
    130         // on the IO thread, and if so copy over that data.
    131         for (size_t child = 0; child < child_info.size(); child++) {
    132           if (child_info[child].pid != info.pid)
    133             continue;
    134           info.titles = child_info[child].titles;
    135           info.process_type = child_info[child].process_type;
    136           break;
    137         }
    138       } else if (GetModuleFileNameEx(process_handle.Get(), NULL, name,
    139                                      MAX_PATH - 1)) {
    140         std::wstring str_name(name);
    141         scoped_ptr<FileVersionInfo> version_info(
    142             FileVersionInfo::CreateFileVersionInfo(base::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.Get(), &process_entry));
    159 
    160   // Finally return to the browser thread.
    161   BrowserThread::PostTask(
    162       BrowserThread::UI, FROM_HERE,
    163       base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this));
    164 }
    165