blob: 157aceaa7143c4c735e38693b588078afca2c1fb [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.
#ifndef ANDROID_WEBVIEW_BROWSER_PREFETCH_AW_PREFETCH_MANAGER_DATA_H_
#define ANDROID_WEBVIEW_BROWSER_PREFETCH_AW_PREFETCH_MANAGER_DATA_H_
#include "android_webview/browser/prefetch/aw_prefetch_handle_wrapper.h"
#include "android_webview/browser/prefetch/aw_prefetch_prefs.h"
#include "net/http/http_no_vary_search_data.h"
#include "url/gurl.h"
namespace android_webview {
using AwPrefetchKey = int;
// The default TTL value in `//content` is 10 minutes which is too long for most
// of WebView cases. This value here can change in the future and that shouldn't
// affect the `//content` TTL default value.
inline constexpr int kDefaultTtlInSec = 60;
// The MaxPrefetches number is not present in the `//content` layer, so it is
// specific to WebView.
inline constexpr size_t kDefaultMaxPrefetches = 10;
// This is the source of truth for the absolute maximum number of prefetches
// that can ever be cached in WebView. It can override the number set by the
// AndroidX API.
inline constexpr size_t kAbsoluteMaxPrefetches = 20;
// Returned from `AwPrefetchManager::StartPrefetchRequest` if the prefetch
// request was unsuccessful (i.e. there is no key for the prefetch).
inline constexpr AwPrefetchKey NO_PREFETCH_KEY = -1;
// An `AwPrefetchManager`-specific store that manages its mutable state, which
// can be modified by this public methods.
//
// Thread mode:
//
// This class is designed to be thread-safe.
//
// This should be created/owned/destructed by `AwPrefetchManager` on the UI
// thread.
//
// When `kWebViewPrefetchOffTheMainThread` feature is enabled:
// - All public methods acquire `lock_` before accessing member variables.
// And thus public methods shouldn't call other public methods, as annotated
// by LOCKS_EXCLUDED(lock_).
// - Private methods (`*Locked()`) must be called after acquiring `lock_`, as
// annotated by `EXCLUSIVE_LOCKS_REQUIRED(lock_)`.
// - To avoid unexpected reentrancy/deadlocks, any method shouldn't trigger any
// complex logic, external delegates/callbacks etc. `lock_` is not needed to
// be instantiated, and thus ignored by `AutoLockMaybe`.
//
// When `kWebViewPrefetchOffTheMainThread` feature is disabled, this class
// should only be accessed from the UI thread.
class AwPrefetchManagerData {
public:
AwPrefetchManagerData();
~AwPrefetchManagerData();
// Evicts the oldest prefetch from `all_prefetches_map_` to guarantee
// there is space for one new request when `max_prefetches_` is reached.
void MayEvictOldestPrefetchHandleForANewRequest() LOCKS_EXCLUDED(lock_);
// Stores the wrapper and returns its tracking key.
//
// Currently callers are expected to ensure there is available capacity and
// no deduplication before insertion, by calling
// `MayEvictOldestPrefetchHandleForANewRequest()` and `IsPrefetchDuplicate()`.
// For the latter, see `MayEvictOldestPrefetchHandleForANewRequest()`'s inner
// comment for more context.
// Used only when `kWebViewPrefetchOffTheMainThread` is disabled.
AwPrefetchKey AddNewPrefetchHandleWrapper(
std::unique_ptr<AwPrefetchHandleWrapper> prefetch_handle_wrapper)
LOCKS_EXCLUDED(lock_);
// The pair of functions to start and store a (Pre)Prefetch, used when
// `kWebViewPrefetchOffTheMainThread` is enabled.
//
// `ReservePrefetchHandleWrapper()` atomically checks for deduplication,
// evicts the oldest prefetch if necessary, and inserts an empty
// `AwPrefetchHandleWrapper` to `AwPrefetchManagerData` as a reservation.
// This prevents a TOCTOU race condition while (pre-)prefetch actually
// starts. Returns NO_PREFETCH_KEY if it is a duplicate.
// `CommitInitial(Pre)PrefetchHandle()` actually commits the
// `(Pre)PrefetchHandle` to the wrapper.
//
// Currently it is the caller's responsibility to clean up the wrapper from
// `all_prefetches_map_` when `ReservePrefetchHandleWrapper()` is called but
// `CommitInitial(Pre)PrefetchHandle()` can't eventually be called (e.g. if
// starting the (pre-)prefetch fails).
// TODO(crbug.com/452406598): This should ideally be mitigated by introducing
// a writer interface that grants write permission to the wrapper and
// automatically handles rollback on failure.
AwPrefetchKey ReservePrefetchHandleWrapper(
const GURL& url,
const std::optional<net::HttpNoVarySearchData>& expected_no_vary_search)
LOCKS_EXCLUDED(lock_);
void CommitInitialPrePrefetchHandle(
AwPrefetchKey prefetch_key,
std::unique_ptr<content::PrePrefetchHandle> pre_prefetch_handle)
LOCKS_EXCLUDED(lock_);
void CommitInitialPrefetchHandle(
AwPrefetchKey prefetch_key,
std::unique_ptr<content::PrefetchHandle> prefetch_handle)
LOCKS_EXCLUDED(lock_);
// The pair of functions to take `PrePrefetchHandle` from
// an existing `AwPrefetchHandleWrapper` and commit a `PrefetchHandle` to the
// same wrapper after PrePrefetch consumption.
//
// Currently it is the caller's responsibility to clean up the wrapper from
// `all_prefetches_map_`, when `TakePrePrefetchHandleForConsume` is called
// but `CommitPrefetchHandleAfterConsume` can't eventually be called (e.g. if
// starting the prefetch fails).
// TODO(crbug.com/452406598): This should ideally be mitigated by introducing
// a writer interface that grants write permission to the wrapper and
// automatically handles rollback on failure.
std::unique_ptr<content::PrePrefetchHandle> TakePrePrefetchHandleForConsume(
AwPrefetchKey prefetch_key) LOCKS_EXCLUDED(lock_);
void CommitPrefetchHandleAfterConsume(
AwPrefetchKey prefetch_key,
std::unique_ptr<content::PrefetchHandle> prefetch_handle)
LOCKS_EXCLUDED(lock_);
void CancelPrefetch(AwPrefetchKey prefetch_key) LOCKS_EXCLUDED(lock_);
size_t GetMaxPrefetches() const LOCKS_EXCLUDED(lock_);
void SetTtlInSec(int ttl_in_sec) LOCKS_EXCLUDED(lock_);
int GetTtlInSec() const LOCKS_EXCLUDED(lock_);
void SetMaxPrefetches(size_t max_prefetches) LOCKS_EXCLUDED(lock_);
// Updates the `latest_info_cache_`.
// Returns `true` if the settings were actually changed, which signals to the
// caller (`AwPrefetchManager`) that the new values should be written to the
// persistent `PrefService`.
// Only used when `kWebViewPrefetchOffTheMainThread` is enabled.
bool UpdateLatestPrefetchInfo(const AwPrefetchLatestInfoPref& info)
LOCKS_EXCLUDED(lock_);
// Testing utilities.
std::vector<AwPrefetchKey> GetAllPrefetchKeysForTesting() const
LOCKS_EXCLUDED(lock_);
AwPrefetchKey GetLastPrefetchKeyForTesting() const LOCKS_EXCLUDED(lock_);
bool GetIsPrefetchInCacheForTesting(AwPrefetchKey prefetch_key) const
LOCKS_EXCLUDED(lock_);
private:
// Utility functions that assume the lock is already held.
// Returns true if the prefetch with URL and NVS hint is considered a
// duplicate of existing `all_prefetches_map_`.
// Used only when `kWebViewPrefetchOffTheMainThread` is enabled.
bool IsPrefetchDuplicateLocked(const GURL& url,
const std::optional<net::HttpNoVarySearchData>&
expected_no_vary_search) const
EXCLUSIVE_LOCKS_REQUIRED(lock_);
std::vector<std::unique_ptr<AwPrefetchHandleWrapper>>
MayEvictOldestPrefetchHandleForANewRequestLocked()
EXCLUSIVE_LOCKS_REQUIRED(lock_);
AwPrefetchKey GetNextPrefetchKeyLocked() const
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void UpdateLastPrefetchKeyLocked(AwPrefetchKey new_key)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
// Guards the below non-const members. Allocated only when the
// `WebViewPrefetchOffTheMainThread` feature is enabled. Should be used with
// `base::AutoLockMaybe` to avoid lock overhead when the feature is
// disabled.
const std::unique_ptr<base::Lock> lock_;
// Memorizes and caches the latest prefetch request info. Used to prevent
// asking `PrefService` with redundant updates.
// Only used when `kWebViewPrefetchOffTheMainThread` is enabled.
AwPrefetchLatestInfoPref prefetch_latest_info_ GUARDED_BY(lock_) = {
url::Origin(), false};
int ttl_in_sec_ GUARDED_BY(lock_) = kDefaultTtlInSec;
size_t max_prefetches_ GUARDED_BY(lock_) = kDefaultMaxPrefetches;
std::map<AwPrefetchKey, std::unique_ptr<AwPrefetchHandleWrapper>>
all_prefetches_map_ GUARDED_BY(lock_);
// Should only be incremented. Acts as an "order added" mechanism
// inside of `all_prefetches_map_` since `std::map` stores keys
// in a sorted order.
AwPrefetchKey last_prefetch_key_ GUARDED_BY(lock_) = -1;
};
} // namespace android_webview
#endif // ANDROID_WEBVIEW_BROWSER_PREFETCH_AW_PREFETCH_MANAGER_DATA_H_