| // Copyright (c) 2021 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 "content/browser/starscan_load_observer.h" |
| |
| #include "base/allocator/partition_allocator/starscan/pcscan.h" |
| #include "base/logging.h" |
| #include "content/browser/renderer_host/frame_tree.h" |
| #include "content/browser/renderer_host/render_frame_host_impl.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/navigation_handle.h" |
| |
| namespace content { |
| |
| namespace { |
| size_t g_loading_webcontents_ = 0; |
| } |
| |
| // Start observing right away. |
| StarScanLoadObserver::StarScanLoadObserver(WebContents* contents) |
| : WebContentsObserver(contents) {} |
| |
| StarScanLoadObserver::~StarScanLoadObserver() { |
| // WebContents can be destructed while loading is still in progress. |
| DidStopLoading(); |
| } |
| |
| void StarScanLoadObserver::ReadyToCommitNavigation( |
| NavigationHandle* navigation_handle) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| |
| // We don't disable PCScan for a prerendering page's navigation since |
| // it doesn't invoke DidStopLoading. |
| RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>( |
| navigation_handle->GetRenderFrameHost()); |
| if (rfh->frame_tree()->type() == FrameTree::Type::kPrerender) |
| return; |
| |
| // Protect against ReadyToCommitNavigation() being called twice in a row. |
| if (is_loading_) |
| return; |
| is_loading_ = true; |
| |
| if (!g_loading_webcontents_) { |
| VLOG(3) << "Disabling *Scan due to loading"; |
| base::internal::PCScan::Disable(); |
| } |
| ++g_loading_webcontents_; |
| |
| // Set timer as a fallback if loading is too slow. |
| constexpr base::TimeDelta kReenableStarScanDelta = base::Seconds(10); |
| timer_.Start(FROM_HERE, kReenableStarScanDelta, this, |
| &StarScanLoadObserver::DidStopLoading); |
| } |
| |
| void StarScanLoadObserver::DidStopLoading() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (is_loading_) { |
| DecrementCounterAndReenableStarScanIfNeeded(); |
| is_loading_ = false; |
| } |
| } |
| |
| void StarScanLoadObserver::DecrementCounterAndReenableStarScanIfNeeded() { |
| CHECK(g_loading_webcontents_); |
| --g_loading_webcontents_; |
| if (!g_loading_webcontents_) { |
| VLOG(3) << "Reenabling *Scan after finishing loading"; |
| base::internal::PCScan::Reenable(); |
| } |
| } |
| |
| } // namespace content |