blob: 8dee927b34a4c415036e1c42036b599a16fc4108 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/aw_render_process_keep_alive.h"
#include <memory>
#include <utility>
#include "android_webview/browser/aw_render_process.h"
#include "android_webview/common/aw_features.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
namespace android_webview {
namespace {
const void* const kAwRenderProcessKeepAliveKey = &kAwRenderProcessKeepAliveKey;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// LINT.IfChange(RendererKeepAliveEvent)
enum class RendererKeepAliveEvent {
kReused = 0,
kTimedOut = 1,
kPendingReuse = 2,
kMaxValue = kPendingReuse,
};
// LINT.ThenChange(/tools/metrics/histograms/metadata/android/enums.xml:WebViewRendererKeepAliveEvent)
void RecordKeepAliveEvent(RendererKeepAliveEvent event) {
base::UmaHistogramEnumeration("Android.WebView.RendererKeepAlive.Event",
event);
}
} // namespace
// static
AwRenderProcessKeepAlive*
AwRenderProcessKeepAlive::GetInstanceForRenderProcessHost(
content::RenderProcessHost* host) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
AwRenderProcessKeepAlive* instance = static_cast<AwRenderProcessKeepAlive*>(
host->GetUserData(kAwRenderProcessKeepAliveKey));
if (!instance) {
auto created_instance =
base::WrapUnique(new AwRenderProcessKeepAlive(host));
instance = created_instance.get();
host->SetUserData(kAwRenderProcessKeepAliveKey,
std::move(created_instance));
}
return instance;
}
AwRenderProcessKeepAlive::AwRenderProcessKeepAlive(
content::RenderProcessHost* render_process_host)
: render_process_host_(render_process_host) {}
AwRenderProcessKeepAlive::~AwRenderProcessKeepAlive() = default;
void AwRenderProcessKeepAlive::AddAwContents() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
aw_contents_count_++;
if (keep_alive_timer_.IsRunning()) {
RecordKeepAliveEvent(RendererKeepAliveEvent::kReused);
base::UmaHistogramLongTimes100(
"Android.WebView.RendererKeepAlive.TimeToReuse",
base::TimeTicks::Now() - keep_alive_start_time_);
if (base::FeatureList::IsEnabled(features::kWebViewPrefetchNativeLibrary) &&
features::kWebViewPrefetchFromRenderer.Get() &&
base::FeatureList::IsEnabled(
features::kWebViewPrefetchOnRendererReuse)) {
AwRenderProcess* aw_render_process =
AwRenderProcess::GetInstanceForRenderProcessHost(
render_process_host_);
if (aw_render_process) {
aw_render_process->PrefetchNativeLibrary();
}
}
}
keep_alive_timer_.Stop();
if (!kept_alive_) {
render_process_host_->IncrementPendingReuseRefCount();
kept_alive_ = true;
}
}
void AwRenderProcessKeepAlive::RemoveAwContents() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
CHECK_GT(aw_contents_count_, 0);
aw_contents_count_--;
if (aw_contents_count_ == 0 && kept_alive_) {
RecordKeepAliveEvent(RendererKeepAliveEvent::kPendingReuse);
keep_alive_start_time_ = base::TimeTicks::Now();
keep_alive_timer_.Start(
FROM_HERE, features::kWebViewRendererKeepAliveDuration.Get(),
base::BindOnce(&AwRenderProcessKeepAlive::OnKeepAliveTimerFired,
weak_factory_.GetWeakPtr()));
}
}
void AwRenderProcessKeepAlive::OnKeepAliveTimerFired() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
CHECK(kept_alive_);
RecordKeepAliveEvent(RendererKeepAliveEvent::kTimedOut);
render_process_host_->DecrementPendingReuseRefCount();
kept_alive_ = false;
}
} // namespace android_webview