| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/performance_manager/public/resource_attribution/process_context.h" |
| |
| #include <optional> |
| #include <utility> |
| #include <variant> |
| |
| #include "base/check.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "components/performance_manager/graph/process_node_impl.h" |
| #include "components/performance_manager/public/browser_child_process_host_id.h" |
| #include "components/performance_manager/public/graph/graph.h" |
| #include "components/performance_manager/public/performance_manager.h" |
| #include "components/performance_manager/public/render_process_host_id.h" |
| #include "components/performance_manager/resource_attribution/performance_manager_aliases.h" |
| #include "content/public/browser/browser_child_process_host.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/child_process_data.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "third_party/abseil-cpp/absl/functional/overload.h" |
| |
| namespace resource_attribution { |
| |
| ProcessContext::ProcessContext(AnyProcessHostId id, |
| base::WeakPtr<ProcessNode> weak_node) |
| : id_(id), weak_node_(weak_node) {} |
| |
| ProcessContext::~ProcessContext() = default; |
| |
| ProcessContext::ProcessContext(const ProcessContext& other) = default; |
| |
| ProcessContext& ProcessContext::operator=(const ProcessContext& other) = |
| default; |
| |
| ProcessContext::ProcessContext(ProcessContext&& other) = default; |
| |
| ProcessContext& ProcessContext::operator=(ProcessContext&& other) = default; |
| |
| // static |
| std::optional<ProcessContext> ProcessContext::FromBrowserProcess() { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| base::WeakPtr<ProcessNode> process_node = |
| PerformanceManager::GetProcessNodeForBrowserProcess(); |
| if (!process_node.MaybeValid()) { |
| return std::nullopt; |
| } |
| return ProcessContext(BrowserProcessTag{}, std::move(process_node)); |
| } |
| |
| // static |
| std::optional<ProcessContext> ProcessContext::FromRenderProcessHost( |
| content::RenderProcessHost* host) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| CHECK(host); |
| RenderProcessHostId id(host->GetID()); |
| CHECK(!id.is_null()); |
| base::WeakPtr<ProcessNode> process_node = |
| PerformanceManager::GetProcessNodeForRenderProcessHost(host); |
| if (!process_node.MaybeValid()) { |
| return std::nullopt; |
| } |
| return ProcessContext(std::move(id), std::move(process_node)); |
| } |
| |
| // static |
| std::optional<ProcessContext> ProcessContext::FromBrowserChildProcessHost( |
| content::BrowserChildProcessHost* host) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| CHECK(host); |
| BrowserChildProcessHostId id(host->GetData().id); |
| CHECK(!id.is_null()); |
| base::WeakPtr<ProcessNode> process_node = |
| PerformanceManager::GetProcessNodeForBrowserChildProcessHost(host); |
| if (!process_node.MaybeValid()) { |
| return std::nullopt; |
| } |
| return ProcessContext(std::move(id), std::move(process_node)); |
| } |
| |
| bool ProcessContext::IsBrowserProcessContext() const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| return std::holds_alternative<BrowserProcessTag>(id_); |
| } |
| |
| bool ProcessContext::IsRenderProcessContext() const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| return std::holds_alternative<RenderProcessHostId>(id_); |
| } |
| |
| bool ProcessContext::IsBrowserChildProcessContext() const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| return std::holds_alternative<BrowserChildProcessHostId>(id_); |
| } |
| |
| content::RenderProcessHost* ProcessContext::GetRenderProcessHost() const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| const auto* rph_id = std::get_if<RenderProcessHostId>(&id_); |
| return rph_id ? content::RenderProcessHost::FromID(rph_id->GetUnsafeValue()) |
| : nullptr; |
| } |
| |
| RenderProcessHostId ProcessContext::GetRenderProcessHostId() const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| const auto* rph_id = std::get_if<RenderProcessHostId>(&id_); |
| return rph_id ? *rph_id : RenderProcessHostId(); |
| } |
| |
| content::BrowserChildProcessHost* ProcessContext::GetBrowserChildProcessHost() |
| const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| const auto* bcph_id = std::get_if<BrowserChildProcessHostId>(&id_); |
| return bcph_id ? content::BrowserChildProcessHost::FromID( |
| bcph_id->GetUnsafeValue()) |
| : nullptr; |
| } |
| |
| BrowserChildProcessHostId ProcessContext::GetBrowserChildProcessHostId() const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| const auto* bcph_id = std::get_if<BrowserChildProcessHostId>(&id_); |
| return bcph_id ? *bcph_id : BrowserChildProcessHostId(); |
| } |
| |
| base::WeakPtr<ProcessNode> ProcessContext::GetWeakProcessNode() const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| return weak_node_; |
| } |
| |
| // static |
| ProcessContext ProcessContext::FromProcessNode(const ProcessNode* node) { |
| CHECK(node); |
| DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph()); |
| auto* node_impl = ProcessNodeImpl::FromNode(node); |
| AnyProcessHostId id; |
| switch (node_impl->GetProcessType()) { |
| case content::PROCESS_TYPE_BROWSER: |
| id = BrowserProcessTag{}; |
| break; |
| case content::PROCESS_TYPE_RENDERER: |
| id = node_impl->GetRenderProcessHostId(); |
| CHECK(!std::get<RenderProcessHostId>(id).is_null()); |
| break; |
| default: |
| id = node_impl->GetBrowserChildProcessHostProxy() |
| .browser_child_process_host_id(); |
| CHECK(!std::get<BrowserChildProcessHostId>(id).is_null()); |
| break; |
| } |
| return ProcessContext(std::move(id), node_impl->GetWeakPtr()); |
| } |
| |
| // static |
| std::optional<ProcessContext> ProcessContext::FromWeakProcessNode( |
| base::WeakPtr<ProcessNode> node) { |
| if (!node) { |
| return std::nullopt; |
| } |
| return FromProcessNode(node.get()); |
| } |
| |
| ProcessNode* ProcessContext::GetProcessNode() const { |
| if (weak_node_) { |
| // `weak_node` will check anyway if dereferenced from the wrong sequence, |
| // but let's be explicit. |
| DCHECK_ON_GRAPH_SEQUENCE(weak_node_->GetGraph()); |
| return weak_node_.get(); |
| } |
| return nullptr; |
| } |
| |
| std::string ProcessContext::ToString() const { |
| return std::visit( |
| absl::Overload{ |
| [](const BrowserProcessTag&) -> std::string { |
| return "ProcessContext:Browser"; |
| }, |
| [](const RenderProcessHostId& id) -> std::string { |
| return base::StrCat({"ProcessContext:Renderer:", |
| base::NumberToString(id.GetUnsafeValue())}); |
| }, |
| [](const BrowserChildProcessHostId& id) -> std::string { |
| return base::StrCat({"ProcessContext:BrowserChild:", |
| base::NumberToString(id.GetUnsafeValue())}); |
| }, |
| }, |
| id_); |
| } |
| |
| } // namespace resource_attribution |