| // 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/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) { |
| DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
| |
| // 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)); |
| } |