blob: b7a209f7eb1795485bb39893b28cb579b42d2fa0 [file]
// Copyright 2025 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_H_
#define ANDROID_WEBVIEW_BROWSER_PREFETCH_AW_PREFETCH_MANAGER_H_
#include <jni.h>
#include <mutex>
#include <optional>
#include <vector>
#include "android_webview/browser/aw_contents.h"
#include "android_webview/browser/prefetch/aw_prefetch_handle_wrapper.h"
#include "android_webview/browser/prefetch/aw_prefetch_manager_data.h"
#include "android_webview/browser/prefetch/aw_prefetch_prefs.h"
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/containers/circular_deque.h"
#include "base/memory/raw_ref.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/pre_prefetch_handle.h"
#include "content/public/browser/pre_prefetch_service.h"
#include "content/public/browser/prefetch_handle.h"
#include "content/public/browser/prefetch_request_status_listener.h"
#include "net/http/http_no_vary_search_data.h"
#include "net/http/http_request_headers.h"
#include "services/network/public/cpp/resource_request.h"
#include "url/gurl.h"
namespace android_webview {
// The suffix used for generating `//content` prefetch internal histogram names
// recorded per trigger.
// TODO(crbug.com/379140429): Merge this with prerender one.
inline constexpr char AW_PREFETCH_METRICS_SUFFIX[] = "WebView";
// Manages prefetch operations for this Profile.
//
// Lifetime: Profile
//
// Thread model:
// - Must be created on UI thread.
// - Public non-test methods can be categorized as below:
// - `StartPrePrefetchRequest()` is called from the worker thread.
// - `StartPrefetchRequest()`, `StartPrefetchFromPrePrefetch()`,
// `CancelPrefetch()`, `SetTtlInSec()`, `SetMaxPrefetches()` are called
// from the UI thread.
// - They will possibly access the `AwPrefetchManagerData` simultaneously,
// which is safe because `AwPrefetchManagerData` is thread-safe. Please see
// its class comment for more details.
// - `AwPrefetchManager` is owned by `AwBrowserContext(Store)` as a
// static `base::NoDestructor`, so `this` will never be destructed. This
// prevents the data race for `AwPrefetchManagerData` etc between a non-main
// thread API call and the main thread dtor of `this`.
// TODO(crbug.com/497983835): This should be reconsidered upon future
// `AwBrowserContext` changes.
class AwPrefetchManager {
public:
explicit AwPrefetchManager(content::BrowserContext* browser_context);
AwPrefetchManager(const AwPrefetchManager&) = delete;
AwPrefetchManager& operator=(const AwPrefetchManager&) = delete;
~AwPrefetchManager();
// Returns `true` if the `resource_request` is also a prefetch request.
// NOTE: A prefetch request can also be a prerender request i.e.
// this method & `IsPrerenderRequest` can both return `true` for it,
// however this is not always the case.
static bool IsPrefetchRequest(
const network::ResourceRequest& resource_request);
// Returns `true` if the `resource_request` is also a prerender request.
// NOTE: A prerender request will always be a prefetch request i.e.
// this method & `IsPrefetchRequest` will always return `true` for it
// as prefetching a always required for prerendering.
static bool IsPrerenderRequest(
const network::ResourceRequest& resource_request);
// Returns `true` if the `blink::kSecPurposeHeaderName` header is associated
// with a prefetch request.
static bool IsSecPurposeForPrefetch(
std::optional<std::string> sec_purpose_header_value);
static void SetPrefServiceForTesting(PrefService* prefs);
// Functions to start Prefetch/PrePrefetch.
// Returns the key associated with the outgoing prefetch request
// and thus the prefetch handle inside of `all_prefetches_map_` (if
// successful), otherwise returns `NO_PREFETCH_KEY`.
//
// Called from Java side UI thread to start a Prefetch request.
AwPrefetchKey StartPrefetchRequest(
JNIEnv* env,
const std::string& url,
const base::android::JavaRef<jobject>& prefetch_params,
const base::android::JavaRef<jobject>& callback,
const base::android::JavaRef<jobject>& callback_executor);
// From `AwContents::StartPrerendering()`.
AwPrefetchKey StartPrefetchRequestAheadOfPrerender(
base::PassKey<AwContents>,
JNIEnv* env,
const std::string& url,
const base::android::JavaRef<jobject>& prefetch_params,
scoped_refptr<content::PreloadPipelineInfo> preload_pipeline_info);
// Called from Java side worker thread to start a PrePrefetch request.
AwPrefetchKey StartPrePrefetchRequest(
JNIEnv* env,
const std::string& url,
const base::android::JavaRef<jobject>& prefetch_params,
const base::android::JavaRef<jobject>& callback,
const base::android::JavaRef<jobject>& callback_executor);
// Called from Java side UI thread to start a Prefetch request from a
// previously completed PrePrefetch request.
AwPrefetchKey StartPrefetchFromPrePrefetch(JNIEnv* env,
AwPrefetchKey prefetch_key);
void CancelPrefetch(JNIEnv* env, AwPrefetchKey prefetch_key);
// Updates Time-To-Live (TTL) for the prefetched content in seconds.
void SetTtlInSec(JNIEnv* env, int ttl_in_sec);
// Updates the maximum number of allowed prefetches in cache
void SetMaxPrefetches(JNIEnv* env, int max_prefetches);
// Returns the Time-To-Live (TTL) for the prefetched content in seconds.
int GetTtlInSec(JNIEnv* env) const;
// Returns the maximum number of allowed prefetches in cache.
size_t GetMaxPrefetches(JNIEnv* env) const;
// Updates the maximum number of allowed prefetches in cache to the default
// value.
void ClearTtl(JNIEnv* env);
// Updates the Time-To-Live (TTL) for the prefetched content in seconds to the
// default value.
void ClearMaxPrefetches(JNIEnv* env);
std::vector<AwPrefetchKey> GetAllPrefetchKeysForTesting() const;
AwPrefetchKey GetLastPrefetchKeyForTesting() const;
bool GetIsPrefetchInCacheForTesting(JNIEnv* env,
AwPrefetchKey prefetch_key) const;
base::android::ScopedJavaLocalRef<jobject> GetJavaPrefetchManager();
private:
// Registers an external experiment (synthetic trial) in UMA for the current
// prefetch request. The experiment ID is derived from the Variations ID
// provided by the embedder.
//
// This is called during `StartRequest()` to ensure the metrics state reflects
// the parameters of the most recent request. If no Variations ID is provided,
// any previously registered prefetch experiment will be cleared.
//
// Must be called on the UI thread.
static void SetOrClearExternalPrefetchExperiment(
std::optional<int> variations_id);
// Actually read/write the latest prefetch info to/from `PrefService`.
// Must be called on the UI thread, since `PrefService` is bound to the UI
// thread.
// Only used when `kWebViewPrefetchOffTheMainThread` is enabled.
PrefService* GetPrefService();
std::optional<AwPrefetchLatestInfoPref> ReadLatestPrefetchInfoFromPref();
void WriteLatestPrefetchInfoToPref(AwPrefetchLatestInfoPref pref);
// Called from either:
// - `StartPrefetchRequest` with `is_pre_prefetch` set to false (on UI thread)
// - `StartPrefetchRequestAheadOfPrerender` with `is_pre_prefetch` set to
// false (on UI thread)
// - `StartPrePrefetchRequest` with `is_pre_prefetch` set to true (on worker
// thread)
AwPrefetchKey StartRequest(
JNIEnv* env,
const std::string& url,
bool is_pre_prefetch,
scoped_refptr<content::PreloadPipelineInfo> preload_pipeline_info,
const base::android::JavaRef<jobject>& prefetch_params,
const base::android::JavaRef<jobject>& callback,
const base::android::JavaRef<jobject>& callback_executor);
const raw_ref<content::BrowserContext> browser_context_;
// Manages all the mutable states of `this`. Acquires a lock internally so
// it should be thread safe from any accesses from any threads.
// Should be initialized prior to `aw_pre_prefetch_service_`, because
// `aw_prefetch_manager_data_` is needed for `PrePrefetchService`'s
// construction.
AwPrefetchManagerData aw_prefetch_manager_data_;
// Since `AwPrefetchManager` is owned by `AwBrowserContext(Store)` as a static
// `base::NoDestructor`, `content::PrePrefetchService`'s dtor will never be
// called.
const std::unique_ptr<content::PrePrefetchService> aw_pre_prefetch_service_;
// Java object reference.
base::android::ScopedJavaGlobalRef<jobject> java_obj_;
};
} // namespace android_webview
#endif // ANDROID_WEBVIEW_BROWSER_PREFETCH_AW_PREFETCH_MANAGER_H_