| // 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 "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(); |
| |
| // 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 IsPrefetchDuplicate(const GURL& url, |
| const std::optional<net::HttpNoVarySearchData>& |
| expected_no_vary_search) const |
| LOCKS_EXCLUDED(lock_); |
| |
| // 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. |
| // TODO(crbug.com/452406598): This procedure causes a potential race condition |
| // if enabled, since the look up and update for `all_prefetches_map_` is not |
| // an atomic operation. See crrev.com/c/7666497/comment/074daee9_6ca0a982/ for |
| // more details. |
| AwPrefetchKey AddNewPrefetchHandleWrapper( |
| std::unique_ptr<AwPrefetchHandleWrapper> prefetch_handle_wrapper) |
| 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_); |
| |
| // 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. |
| 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_; |
| |
| 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_ |