| // Copyright 2020 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "content/browser/devtools/devtools_issue_storage.h" | |
| #include <bit> | |
| #include <cstdint> | |
| #include "base/debug/crash_logging.h" | |
| #include "content/browser/devtools/protocol/audits.h" | |
| #include "content/browser/devtools/render_frame_devtools_agent_host.h" | |
| #include "content/browser/renderer_host/render_frame_host_impl.h" | |
| #include "content/public/browser/navigation_handle.h" | |
| #include "content/public/browser/web_contents.h" | |
| #include "ui/base/page_transition_types.h" | |
| namespace content { | |
| static const unsigned kMaxIssueCount = 1000; | |
| PAGE_USER_DATA_KEY_IMPL(DevToolsIssueStorage); | |
| DevToolsIssueStorage::DevToolsIssueStorage(Page& page) | |
| : PageUserData<DevToolsIssueStorage>(page) { | |
| // DevToolsIssueStorage is only created for outermost pages. | |
| CHECK(!page.GetMainDocument().GetParentOrOuterDocument(), | |
| base::NotFatalUntil::M159); | |
| } | |
| DevToolsIssueStorage::~DevToolsIssueStorage() { | |
| // TOOD(1351587): remove explicit destructor once the bug is fixed. | |
| // This is so that crash key is scoped to issue destruction. | |
| SCOPED_CRASH_KEY_NUMBER("devtools", "audit_issue_count", | |
| std::bit_width<uint32_t>(total_added_issues_) - 1); | |
| issues_.clear(); | |
| } | |
| const protocol::Audits::InspectorIssue& DevToolsIssueStorage::AddInspectorIssue( | |
| RenderFrameHost* rfh, | |
| std::unique_ptr<protocol::Audits::InspectorIssue> issue) { | |
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| CHECK_LE(issues_.size(), kMaxIssueCount, base::NotFatalUntil::M159); | |
| if (issues_.size() == kMaxIssueCount) { | |
| issues_.pop_front(); | |
| } | |
| total_added_issues_++; | |
| issues_.emplace_back(rfh->GetGlobalId(), std::move(issue)); | |
| return *issues_.back().second.get(); | |
| } | |
| std::vector<const protocol::Audits::InspectorIssue*> | |
| DevToolsIssueStorage::FindIssuesForAgentOf( | |
| RenderFrameHost* render_frame_host) const { | |
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| RenderFrameHostImpl* render_frame_host_impl = | |
| static_cast<RenderFrameHostImpl*>(render_frame_host); | |
| RenderFrameHostImpl* main_rfh = | |
| static_cast<RenderFrameHostImpl*>(&page().GetMainDocument()); | |
| DevToolsAgentHostImpl* agent_host = | |
| RenderFrameDevToolsAgentHost::GetFor(render_frame_host_impl); | |
| CHECK_EQ(&render_frame_host->GetOutermostMainFrame()->GetPage(), &page(), | |
| base::NotFatalUntil::M159); | |
| CHECK(RenderFrameDevToolsAgentHost::ShouldCreateDevToolsForHost( | |
| render_frame_host_impl), | |
| base::NotFatalUntil::M159); | |
| CHECK(agent_host, base::NotFatalUntil::M159); | |
| bool is_main_agent = render_frame_host_impl == main_rfh; | |
| std::vector<const protocol::Audits::InspectorIssue*> issues; | |
| for (const auto& entry : issues_) { | |
| bool should_add; | |
| RenderFrameHostImpl* issue_rfh = RenderFrameHostImpl::FromID(entry.first); | |
| if (!issue_rfh) { | |
| // Issues that fall in this category are either associated with |main_rfh| | |
| // or with deleted subframe RFHs of |main_rfh|. In both cases, we only | |
| // want to retrieve them for |main_rfh|'s agent. | |
| // Note: This means that issues for deleted subframe RFHs get reparented | |
| // to |main_rfh| after deletion. | |
| should_add = is_main_agent; | |
| } else { | |
| should_add = | |
| RenderFrameDevToolsAgentHost::GetFor(issue_rfh) == agent_host; | |
| } | |
| if (should_add) | |
| issues.push_back(entry.second.get()); | |
| } | |
| return issues; | |
| } | |
| } // namespace content |