blob: 1258c27abd4183d733951b583dd18f68d7b4b466 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/memory_details.h"
#include <psapi.h>
#include <stddef.h>
#include <TlHelp32.h>
#include <memory>
#include "base/bind.h"
#include "base/file_version_info.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/chromium_strings.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/process_type.h"
#include "ui/base/l10n/l10n_util.h"
using content::BrowserThread;
// Known browsers which we collect details for.
enum BrowserProcess {
CHROME_BROWSER = 0,
};
MemoryDetails::MemoryDetails() {
base::FilePath browser_process_path;
PathService::Get(base::FILE_EXE, &browser_process_path);
ProcessData process;
process.name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
process.process_name = browser_process_path.BaseName().value();
process_data_.push_back(process);
}
ProcessData* MemoryDetails::ChromeBrowser() {
return &process_data_[0];
}
void MemoryDetails::CollectProcessData(
const std::vector<ProcessMemoryInformation>& child_info) {
base::ThreadRestrictions::AssertIOAllowed();
// Clear old data.
process_data_[0].processes.clear();
base::win::ScopedHandle snapshot(
::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
PROCESSENTRY32 process_entry = {sizeof(PROCESSENTRY32)};
if (!snapshot.Get()) {
LOG(ERROR) << "CreateToolhelp32Snapshot failed: " << GetLastError();
return;
}
if (!::Process32First(snapshot.Get(), &process_entry)) {
LOG(ERROR) << "Process32First failed: " << GetLastError();
return;
}
do {
base::ProcessId pid = process_entry.th32ProcessID;
base::win::ScopedHandle process_handle(::OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
if (!process_handle.IsValid())
continue;
if (_wcsicmp(process_data_[0].process_name.c_str(),
process_entry.szExeFile) != 0) {
continue;
}
// Get Memory Information.
ProcessMemoryInformation info;
info.pid = pid;
info.process_type = pid == GetCurrentProcessId()
? content::PROCESS_TYPE_BROWSER
: content::PROCESS_TYPE_UNKNOWN;
std::unique_ptr<base::ProcessMetrics> metrics =
base::ProcessMetrics::CreateProcessMetrics(process_handle.Get());
metrics->GetCommittedKBytes(&info.committed);
metrics->GetWorkingSetKBytes(&info.working_set);
// Get Version Information.
info.version = base::ASCIIToUTF16(version_info::GetVersionNumber());
// Check if this is one of the child processes whose data we collected
// on the IO thread, and if so copy over that data.
for (const ProcessMemoryInformation& child : child_info) {
if (child.pid == info.pid) {
info.titles = child.titles;
info.process_type = child.process_type;
break;
}
}
// Add the process info to our list.
process_data_[0].processes.push_back(info);
} while (::Process32Next(snapshot.Get(), &process_entry));
// Finally return to the browser thread.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this));
}