chromium/android_webview/browser/aw_browser_context.cc

// Copyright 2012 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_browser_context.h"

#include <memory>
#include <string>
#include <string_view>
#include <utility>

#include "android_webview/browser/aw_browser_context_store.h"
#include "android_webview/browser/aw_browser_process.h"
#include "android_webview/browser/aw_client_hints_controller_delegate.h"
#include "android_webview/browser/aw_content_browser_client.h"
#include "android_webview/browser/aw_contents_origin_matcher.h"
#include "android_webview/browser/aw_download_manager_delegate.h"
#include "android_webview/browser/aw_form_database_service.h"
#include "android_webview/browser/aw_permission_manager.h"
#include "android_webview/browser/aw_quota_manager_bridge.h"
#include "android_webview/browser/aw_web_ui_controller_factory.h"
#include "android_webview/browser/cookie_manager.h"
#include "android_webview/browser/ip_protection/aw_ip_protection_config_provider.h"
#include "android_webview/browser/metrics/aw_metrics_service_client.h"
#include "android_webview/browser/network_service/net_helpers.h"
#include "android_webview/browser/safe_browsing/aw_safe_browsing_allowlist_manager.h"
#include "android_webview/common/aw_features.h"
#include "android_webview/common/aw_switches.h"
#include "android_webview/common/crash_reporter/crash_keys.h"
#include "base/android/callback_android.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/base_paths_posix.h"
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/path_service.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/cdm/browser/media_drm_storage_impl.h"
#include "components/download/public/common/in_progress_download_manager.h"
#include "components/keyed_service/core/simple_key_map.h"
#include "components/origin_trials/browser/leveldb_persistence_provider.h"
#include "components/origin_trials/browser/origin_trials.h"
#include "components/origin_trials/common/features.h"
#include "components/policy/core/browser/browser_policy_connector_base.h"
#include "components/policy/core/browser/configuration_policy_pref_store.h"
#include "components/policy/core/browser/url_blocklist_manager.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/in_memory_pref_store.h"
#include "components/prefs/json_pref_store.h"
#include "components/prefs/pref_name_set.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_service_factory.h"
#include "components/prefs/segregated_pref_store.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/url_formatter/url_fixer.h"
#include "components/user_prefs/user_prefs.h"
#include "components/visitedlink/browser/visitedlink_writer.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_request_utils.h"
#include "content/public/browser/ssl_host_state_delegate.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/zoom_level_delegate.h"
#include "media/mojo/buildflags.h"
#include "net/base/features.h"
#include "net/http/http_util.h"
#include "net/proxy_resolution/proxy_config_service_android.h"
#include "net/proxy_resolution/proxy_resolution_service.h"
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "android_webview/browser_jni_headers/AwBrowserContext_jni.h"

using base::FilePath;
using content::BrowserThread;

namespace android_webview {

namespace {

const void* const kDownloadManagerDelegateKey = &kDownloadManagerDelegateKey;

// Empty method to skip origin security check as DownloadManager will set its
// own method.
bool IgnoreOriginSecurityCheck(const GURL& url) {
  return true;
}

void MigrateProfileData(base::FilePath cache_path,
                        base::FilePath context_storage_path) {
  TRACE_EVENT0("startup", "MigrateProfileData");
  FilePath old_cache_path;
  base::PathService::Get(base::DIR_CACHE, &old_cache_path);
  old_cache_path = old_cache_path.DirName().Append(
      FILE_PATH_LITERAL("org.chromium.android_webview"));

  if (base::PathExists(old_cache_path)) {
    bool success = base::CreateDirectory(cache_path);
    if (success)
      success &= base::Move(old_cache_path, cache_path);
    DCHECK(success);
  }

  base::FilePath old_context_storage_path;
  base::PathService::Get(base::DIR_ANDROID_APP_DATA, &old_context_storage_path);

  if (!base::PathExists(context_storage_path)) {
    base::CreateDirectory(context_storage_path);
  }

  auto migrate_context_storage_data = [&old_context_storage_path,
                                       &context_storage_path](auto& suffix) {
    FilePath old_file = old_context_storage_path.Append(suffix);
    if (base::PathExists(old_file)) {
      FilePath new_file = context_storage_path.Append(suffix);

      if (base::PathExists(new_file)) {
        bool success =
            base::Move(new_file, new_file.AddExtension(".partial-migration"));
        DCHECK(success);
      }
      bool success = base::Move(old_file, new_file);
      DCHECK(success);
    }
  };

  // These were handled in the initial migration
  migrate_context_storage_data("Web Data");
  migrate_context_storage_data("Web Data-journal");
  migrate_context_storage_data("GPUCache");
  migrate_context_storage_data("blob_storage");
  migrate_context_storage_data("Session Storage");

  // These were missed in the initial migration
  migrate_context_storage_data("File System");
  migrate_context_storage_data("IndexedDB");
  migrate_context_storage_data("Local Storage");
  migrate_context_storage_data("QuotaManager");
  migrate_context_storage_data("QuotaManager-journal");
  migrate_context_storage_data("Service Worker");
  migrate_context_storage_data("VideoDecodeStats");
  migrate_context_storage_data("databases");
  migrate_context_storage_data("shared_proto_db");
  migrate_context_storage_data("webrtc_event_logs");
}

base::FilePath BuildCachePath(const base::FilePath& relative_path) {
  FilePath cache_path;
  if (!base::PathService::Get(base::DIR_CACHE, &cache_path)) {
    NOTREACHED() << "Failed to get app cache directory for Android WebView";
  }
  return cache_path.Append(relative_path);
}

base::FilePath BuildHttpCachePath(const base::FilePath& relative_path) {
  return BuildCachePath(relative_path).Append(FILE_PATH_LITERAL("HTTP Cache"));
}

}  // namespace

AwBrowserContext::AwBrowserContext(std::string name,
                                   base::FilePath relative_path,
                                   const bool is_default)
    : name_(std::move(name)),
      relative_path_(std::move(relative_path)),
      is_default_(is_default),
      context_storage_path_(BuildStoragePath(relative_path_)),
      http_cache_path_(BuildHttpCachePath(relative_path_)),
      simple_factory_key_(GetPath(), IsOffTheRecord()),
      service_worker_xrw_allowlist_matcher_(
          base::MakeRefCounted<AwContentsOriginMatcher>()) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  TRACE_EVENT0("startup", "AwBrowserContext::AwBrowserContext");

  profile_metrics::SetBrowserProfileType(
      this, profile_metrics::BrowserProfileType::kRegular);

  if (IsDefaultBrowserContext()) {
    MigrateProfileData(GetHttpCachePath(), GetPath());
  } else {
    cookie_manager_ = std::make_unique<CookieManager>(this);
  }

  SimpleKeyMap::GetInstance()->Associate(this, &simple_factory_key_);

  CreateUserPrefService();

  visitedlink_writer_ =
      std::make_unique<visitedlink::VisitedLinkWriter>(this, this, false);
  visitedlink_writer_->Init();

  form_database_service_ =
      std::make_unique<AwFormDatabaseService>(context_storage_path_);

  EnsureResourceContextInitialized();
}

AwBrowserContext::~AwBrowserContext() {
  NotifyWillBeDestroyed();
  SimpleKeyMap::GetInstance()->Dissociate(this);
  ShutdownStoragePartitions();
}

// static
AwBrowserContext* AwBrowserContext::GetDefault() {
  return AwBrowserContextStore::GetInstance()->GetDefault();
}

// static
AwBrowserContext* AwBrowserContext::FromWebContents(
    content::WebContents* web_contents) {
  // This cast is safe; this is the only implementation of the browser context.
  return static_cast<AwBrowserContext*>(web_contents->GetBrowserContext());
}

base::FilePath AwBrowserContext::GetHttpCachePath() {
  return http_cache_path_;
}

base::FilePath AwBrowserContext::GetPrefStorePath() {
  return GetPath().Append(FILE_PATH_LITERAL("Preferences"));
}

base::FilePath AwBrowserContext::GetCookieStorePath() {
  return GetCookieManager()->GetCookieStorePath();
}

base::android::ScopedJavaLocalRef<jobjectArray>
AwBrowserContext::UpdateServiceWorkerXRequestedWithAllowListOriginMatcher(
    JNIEnv* env,
    const base::android::JavaParamRef<jobjectArray>& jrules) {
  std::vector<std::string> rules;
  base::android::AppendJavaStringArrayToStringVector(env, jrules, &rules);
  std::vector<std::string> bad_rules =
      service_worker_xrw_allowlist_matcher_->UpdateRuleList(rules);
  return base::android::ToJavaArrayOfStrings(env, bad_rules);
}

// static
void AwBrowserContext::RegisterPrefs(PrefRegistrySimple* registry) {
  safe_browsing::RegisterProfilePrefs(registry);

  // Register the Autocomplete Data Retention Policy pref.
  // The default value '0' represents the latest Chrome major version on which
  // the retention policy ran. By setting it to a low default value, we're
  // making sure it runs now (as it only runs once per major version).
  registry->RegisterIntegerPref(
      autofill::prefs::kAutocompleteLastVersionRetentionPolicy, 0);

  // We only use the autocomplete feature of Autofill, which is controlled via
  // the manager_delegate. We don't use the rest of Autofill, which is why it is
  // hardcoded as disabled here.
  // TODO(crbug.com/40589187): The following also disables autocomplete.
  // Investigate what the intended behavior is.
  registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileEnabled,
                                false);
  registry->RegisterBooleanPref(autofill::prefs::kAutofillCreditCardEnabled,
                                false);

  // This contains a map from a given origin to the client hint headers
  // requested to be sent next time that origin is loaded.
  registry->RegisterDictionaryPref(prefs::kClientHintsCachedPerOriginMap);

#if BUILDFLAG(ENABLE_MOJO_CDM)
  cdm::MediaDrmStorageImpl::RegisterProfilePrefs(registry);
#endif
}

void AwBrowserContext::CreateUserPrefService() {
  TRACE_EVENT0("startup", "AwBrowserContext::CreateUserPrefService");
  auto pref_registry = base::MakeRefCounted<user_prefs::PrefRegistrySyncable>();

  RegisterPrefs(pref_registry.get());

  PrefServiceFactory pref_service_factory;

  PrefNameSet persistent_prefs;
  // Persisted to avoid having to provision MediaDrm every time the
  // application tries to play protected content after restart.
  persistent_prefs.insert(cdm::prefs::kMediaDrmStorage);
  // Persisted to ensure client hints can be sent on next page load.
  persistent_prefs.insert(prefs::kClientHintsCachedPerOriginMap);

  pref_service_factory.set_user_prefs(base::MakeRefCounted<SegregatedPrefStore>(
      base::MakeRefCounted<InMemoryPrefStore>(),
      base::MakeRefCounted<JsonPrefStore>(GetPrefStorePath()),
      std::move(persistent_prefs)));

  policy::URLBlocklistManager::RegisterProfilePrefs(pref_registry.get());
  AwBrowserPolicyConnector* browser_policy_connector =
      AwBrowserProcess::GetInstance()->browser_policy_connector();
  pref_service_factory.set_managed_prefs(
      base::MakeRefCounted<policy::ConfigurationPolicyPrefStore>(
          browser_policy_connector,
          browser_policy_connector->GetPolicyService(),
          browser_policy_connector->GetHandlerList(),
          policy::POLICY_LEVEL_MANDATORY));
  {
    // TODO(crbug.com/40268809): We can potentially use
    // pref_service_factory.set_async(true) instead of ScopedAllowBlocking in
    // order to avoid blocking here or to at least parallelize work in the
    // background, but it might require additional cross-thread synchronization.
    //
    // Note that for the default profile blocking IO is already permitted on the
    // UI thread due to being called during Chromium/browser
    // initialization. ScopedAllowBlocking is explicitly needed for non-default
    // profiles as they are instead created from a calling environment where
    // normal threading restrictions apply.
    base::ScopedAllowBlocking scoped_allow_blocking;
    user_pref_service_ = pref_service_factory.Create(pref_registry);
  }

  if (IsDefaultBrowserContext()) {
    MigrateLocalStatePrefs();
  }

  user_prefs::UserPrefs::Set(this, user_pref_service_.get());
}

void AwBrowserContext::MigrateLocalStatePrefs() {
  PrefService* local_state = AwBrowserProcess::GetInstance()->local_state();
  if (!local_state->HasPrefPath(cdm::prefs::kMediaDrmStorage)) {
    return;
  }

  user_pref_service_->Set(cdm::prefs::kMediaDrmStorage,
                          local_state->GetValue(cdm::prefs::kMediaDrmStorage));
  local_state->ClearPref(cdm::prefs::kMediaDrmStorage);
}

// static
std::vector<std::string> AwBrowserContext::GetAuthSchemes() {
  // In Chrome this is configurable via the AuthSchemes policy. For WebView
  // there is no interest to have it available so far.
  std::vector<std::string> supported_schemes = {"basic", "digest", "ntlm",
                                                "negotiate"};
  return supported_schemes;
}

void AwBrowserContext::AddVisitedURLs(const std::vector<GURL>& urls) {
  DCHECK(visitedlink_writer_);
  visitedlink_writer_->AddURLs(urls);
}

AwQuotaManagerBridge* AwBrowserContext::GetQuotaManagerBridge() {
  if (!quota_manager_bridge_.get()) {
    quota_manager_bridge_ = AwQuotaManagerBridge::Create(this);
  }
  return quota_manager_bridge_.get();
}

AwFormDatabaseService* AwBrowserContext::GetFormDatabaseService() {
  return form_database_service_.get();
}

CookieManager* AwBrowserContext::GetCookieManager() {
  if (IsDefaultBrowserContext()) {
    // For the default context, the CookieManager isn't owned by the context,
    // and may be initialized externally.
    CHECK(!cookie_manager_);
    return CookieManager::GetDefaultInstance();
  } else {
    // Non-default contexts own their cookie managers
    CHECK(cookie_manager_);
    return cookie_manager_.get();
  }
}

bool AwBrowserContext::IsDefaultBrowserContext() const {
  return is_default_;
}

base::FilePath AwBrowserContext::GetPath() {
  return context_storage_path_;
}

bool AwBrowserContext::IsOffTheRecord() {
  // Android WebView does not support off the record profile yet.
  return false;
}

content::DownloadManagerDelegate*
AwBrowserContext::GetDownloadManagerDelegate() {
  if (!GetUserData(kDownloadManagerDelegateKey)) {
    SetUserData(kDownloadManagerDelegateKey,
                std::make_unique<AwDownloadManagerDelegate>());
  }
  return static_cast<AwDownloadManagerDelegate*>(
      GetUserData(kDownloadManagerDelegateKey));
}

content::BrowserPluginGuestManager* AwBrowserContext::GetGuestManager() {
  return NULL;
}

storage::SpecialStoragePolicy* AwBrowserContext::GetSpecialStoragePolicy() {
  // Intentionally returning NULL as 'Extensions' and 'Apps' not supported.
  return NULL;
}

content::PlatformNotificationService*
AwBrowserContext::GetPlatformNotificationService() {
  return nullptr;
}

content::PushMessagingService* AwBrowserContext::GetPushMessagingService() {
  // TODO(johnme): Support push messaging in WebView.
  return NULL;
}

content::StorageNotificationService*
AwBrowserContext::GetStorageNotificationService() {
  return nullptr;
}

content::SSLHostStateDelegate* AwBrowserContext::GetSSLHostStateDelegate() {
  if (!ssl_host_state_delegate_.get()) {
    ssl_host_state_delegate_ = std::make_unique<AwSSLHostStateDelegate>();
  }
  return ssl_host_state_delegate_.get();
}

AwPermissionManager* AwBrowserContext::GetPermissionControllerDelegate() {
  if (!permission_manager_.get())
    permission_manager_ = std::make_unique<AwPermissionManager>(*this);
  return permission_manager_.get();
}

content::ClientHintsControllerDelegate*
AwBrowserContext::GetClientHintsControllerDelegate() {
  if (!client_hints_controller_delegate_.get()) {
    client_hints_controller_delegate_ =
        std::make_unique<AwClientHintsControllerDelegate>(GetPrefService());
  }
  return client_hints_controller_delegate_.get();
}

content::BackgroundFetchDelegate*
AwBrowserContext::GetBackgroundFetchDelegate() {
  return nullptr;
}

content::BackgroundSyncController*
AwBrowserContext::GetBackgroundSyncController() {
  return nullptr;
}

content::BrowsingDataRemoverDelegate*
AwBrowserContext::GetBrowsingDataRemoverDelegate() {
  return nullptr;
}

content::ReduceAcceptLanguageControllerDelegate*
AwBrowserContext::GetReduceAcceptLanguageControllerDelegate() {
  return nullptr;
}

std::unique_ptr<download::InProgressDownloadManager>
AwBrowserContext::RetrieveInProgressDownloadManager() {
  return std::make_unique<download::InProgressDownloadManager>(
      nullptr, base::FilePath(), nullptr,
      base::BindRepeating(&IgnoreOriginSecurityCheck),
      base::BindRepeating(&content::DownloadRequestUtils::IsURLSafe),
      /*wake_lock_provider_binder*/ base::NullCallback());
}

content::OriginTrialsControllerDelegate*
AwBrowserContext::GetOriginTrialsControllerDelegate() {
  if (!origin_trials::features::IsPersistentOriginTrialsEnabled())
    return nullptr;

  if (!origin_trials_controller_delegate_) {
    origin_trials_controller_delegate_ =
        std::make_unique<origin_trials::OriginTrials>(
            std::make_unique<origin_trials::LevelDbPersistenceProvider>(
                GetPath(),
                GetDefaultStoragePartition()->GetProtoDatabaseProvider()),
            std::make_unique<blink::TrialTokenValidator>());
  }
  return origin_trials_controller_delegate_.get();
}

std::unique_ptr<content::ZoomLevelDelegate>
AwBrowserContext::CreateZoomLevelDelegate(
    const base::FilePath& partition_path) {
  return nullptr;
}

void AwBrowserContext::RebuildTable(
    const scoped_refptr<URLEnumerator>& enumerator) {
  // Android WebView rebuilds from WebChromeClient.getVisitedHistory. The client
  // can change in the lifetime of this WebView and may not yet be set here.
  // Therefore this initialization path is not used.
  enumerator->OnComplete(true);
}

void AwBrowserContext::BuildVisitedLinkTable(
    const scoped_refptr<VisitedLinkEnumerator>& enumerator) {
  // Partitioned visited link hashtables are not supported in Android WebView,
  // so this initialization path is not used.
  enumerator->OnVisitedLinkComplete(true);
}

void AwBrowserContext::SetExtendedReportingAllowed(bool allowed) {
  user_pref_service_->SetBoolean(
      ::prefs::kSafeBrowsingExtendedReportingOptInAllowed, allowed);
}

// TODO(amalova): Make sure NetworkContextParams is configured correctly when
// off-the-record
void AwBrowserContext::ConfigureNetworkContextParams(
    bool in_memory,
    const base::FilePath& relative_partition_path,
    network::mojom::NetworkContextParams* context_params,
    cert_verifier::mojom::CertVerifierCreationParams*
        cert_verifier_creation_params) {
  context_params->user_agent = android_webview::GetUserAgent();

  // TODO(ntfschr): set this value to a proper value based on the user's
  // preferred locales (http://crbug.com/898555). For now, set this to
  // "en-US,en" instead of "en-us,en", since Android guarantees region codes
  // will be uppercase.
  context_params->accept_language =
      net::HttpUtil::GenerateAcceptLanguageHeader("en-US,en");

  // HTTP cache
  context_params->http_cache_enabled = true;
  context_params->http_cache_max_size = GetHttpCacheSize();

  // WebView should persist and restore cookies between app sessions (including
  // session cookies).
  context_params->file_paths = network::mojom::NetworkContextFilePaths::New();
  // Adding HTTP cache dir here
  context_params->file_paths->http_cache_directory = GetHttpCachePath();
  base::FilePath cookie_path = AwBrowserContext::GetCookieStorePath();
  context_params->file_paths->data_directory = cookie_path.DirName();
  context_params->file_paths->cookie_database_name = cookie_path.BaseName();
  context_params->restore_old_session_cookies = true;
  context_params->persist_session_cookies = true;
  context_params->cookie_manager_params =
      network::mojom::CookieManagerParams::New();
  context_params->cookie_manager_params->allow_file_scheme_cookies =
      GetCookieManager()->GetAllowFileSchemeCookies();
  context_params->cookie_manager_params->cookie_access_delegate_type =
      base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kWebViewEnableModernCookieSameSite)
          ? network::mojom::CookieAccessDelegateType::ALWAYS_NONLEGACY
          : network::mojom::CookieAccessDelegateType::ALWAYS_LEGACY;

  context_params->initial_ssl_config = network::mojom::SSLConfig::New();
  // Allow SHA-1 to be used for locally-installed trust anchors, as WebView
  // should behave like the Android system would.
  context_params->initial_ssl_config->sha1_local_anchors_enabled = true;
  // Do not enforce the Legacy Symantec PKI policies outlined in
  // https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html,
  // defer to the Android system.
  context_params->initial_ssl_config->symantec_enforcement_disabled = true;

  // WebView does not currently support Certificate Transparency
  // (http://crbug.com/921750).
  context_params->enforce_chrome_ct_policy = false;

  context_params->enable_brotli = true;
  context_params->enable_zstd =
      base::FeatureList::IsEnabled(net::features::kZstdContentEncoding);

  context_params->check_clear_text_permitted =
      AwContentBrowserClient::get_check_cleartext_permitted();

  AwIpProtectionConfigProvider* aw_ipp_config_provider =
      AwIpProtectionConfigProvider::Get(this);
  if (aw_ipp_config_provider) {
    aw_ipp_config_provider->AddNetworkService(
        context_params->ip_protection_config_getter
            .InitWithNewPipeAndPassReceiver(),
        context_params->ip_protection_proxy_delegate
            .InitWithNewPipeAndPassRemote());
    context_params->enable_ip_protection =
        aw_ipp_config_provider->IsIpProtectionEnabled();
  }

  // Add proxy settings
  AwProxyConfigMonitor::GetInstance()->AddProxyToNetworkContextParams(
      context_params);
}

base::android::ScopedJavaLocalRef<jobject> JNI_AwBrowserContext_GetDefaultJava(
    JNIEnv* env) {
  AwBrowserContext* default_context = AwBrowserContext::GetDefault();
  CHECK(default_context);
  return default_context->GetJavaBrowserContext();
}

base::android::ScopedJavaLocalRef<jstring>
JNI_AwBrowserContext_GetDefaultContextName(JNIEnv* env) {
  return base::android::ConvertUTF8ToJavaString(
      env, AwBrowserContextStore::kDefaultContextName);
}

base::android::ScopedJavaLocalRef<jstring>
JNI_AwBrowserContext_GetDefaultContextRelativePath(JNIEnv* env) {
  return base::android::ConvertUTF8ToJavaString(
      env, AwBrowserContextStore::kDefaultContextPath);
}

void AwBrowserContext::ClearPersistentOriginTrialStorageForTesting(
    JNIEnv* env) {
  content::OriginTrialsControllerDelegate* delegate =
      GetOriginTrialsControllerDelegate();
  if (delegate)
    delegate->ClearPersistedTokens();
}

jboolean AwBrowserContext::HasFormData(JNIEnv* env) {
  return GetFormDatabaseService()->HasFormData();
}

void AwBrowserContext::ClearFormData(JNIEnv* env) {
  return GetFormDatabaseService()->ClearFormData();
}

base::android::ScopedJavaLocalRef<jobject>
AwBrowserContext::GetJavaBrowserContext() {
  if (!obj_) {
    JNIEnv* env = base::android::AttachCurrentThread();
    obj_ = Java_AwBrowserContext_create(
        env, reinterpret_cast<intptr_t>(this),
        base::android::ConvertUTF8ToJavaString(env, name_),
        base::android::ConvertUTF8ToJavaString(env, relative_path_.value()),
        GetCookieManager()->GetJavaCookieManager(), IsDefaultBrowserContext());
  }
  return base::android::ScopedJavaLocalRef<jobject>(obj_);
}

jlong AwBrowserContext::GetQuotaManagerBridge(JNIEnv* env) {
  return reinterpret_cast<intptr_t>(GetQuotaManagerBridge());
}

scoped_refptr<AwContentsOriginMatcher>
AwBrowserContext::service_worker_xrw_allowlist_matcher() {
  return service_worker_xrw_allowlist_matcher_;
}

void AwBrowserContext::SetExtraHeaders(const GURL& url,
                                       const std::string& headers) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (!url.is_valid()) {
    return;
  }
  if (!headers.empty()) {
    extra_headers_[url.spec()] = headers;
  } else {
    extra_headers_.erase(url.spec());
  }
}

std::string AwBrowserContext::GetExtraHeaders(const GURL& url) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (!url.is_valid()) {
    return std::string();
  }
  std::map<std::string, std::string>::iterator iter =
      extra_headers_.find(url.spec());
  return iter != extra_headers_.end() ? iter->second : std::string();
}

void AwBrowserContext::SetServiceWorkerIoThreadClient(
    JNIEnv* const env,
    const base::android::JavaParamRef<jobject>& io_thread_client) {
  sw_io_thread_client_ =
      base::android::ScopedJavaGlobalRef<jobject>(io_thread_client);
}

std::unique_ptr<AwContentsIoThreadClient>
AwBrowserContext::GetServiceWorkerIoThreadClientThreadSafe() {
  base::android::ScopedJavaLocalRef<jobject> java_delegate =
      base::android::ScopedJavaLocalRef<jobject>(sw_io_thread_client_);
  if (java_delegate) {
    return std::make_unique<AwContentsIoThreadClient>(java_delegate);
  }
  return nullptr;
}

// static
base::FilePath AwBrowserContext::BuildStoragePath(
    const base::FilePath& relative_path) {
  base::FilePath user_data_dir;
  if (!base::PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir)) {
    NOTREACHED() << "Failed to get app data directory for Android WebView";
  }
  return user_data_dir.Append(relative_path);
}

// static
void AwBrowserContext::PrepareNewContext(const base::FilePath& relative_path) {
  base::ScopedAllowBlocking scoped_allow_blocking;
  const base::FilePath storage_path = BuildStoragePath(relative_path);
  bool storage_created = base::CreateDirectory(storage_path);
  CHECK(storage_created);
}

// static
void AwBrowserContext::DeleteContext(const base::FilePath& relative_path) {
  // The default profile handles its own directory creation in migration code
  // and (as of writing) should never be deleted.
  CHECK_NE(relative_path.value(), AwBrowserContextStore::kDefaultContextPath);

  // TODO(crbug.com/40268809): This could be partially backgrounded by deleting
  // on the thread pool. Ideally, any interrupted profile directory deletion
  // would be resumed in the background on startup. For now, this just deletes
  // synchronously.
  //
  // We probably also won't want to CHECK in the final solution, but perhaps
  // instead allow for some kind of retry-later logic.
  base::ScopedAllowBlocking scoped_allow_blocking;
  const base::FilePath storage_path = BuildStoragePath(relative_path);
  const base::FilePath cache_path = BuildCachePath(relative_path);
  bool storage_deleted = base::DeletePathRecursively(storage_path);
  CHECK(storage_deleted);
  bool cache_deleted = base::DeletePathRecursively(cache_path);
  CHECK(cache_deleted);

  JNIEnv* env = base::android::AttachCurrentThread();
  Java_AwBrowserContext_deleteSharedPreferences(
      env, base::android::ConvertUTF8ToJavaString(env, relative_path.value()));
}
blink::mojom::PermissionStatus AwBrowserContext::GetGeolocationPermission(
    const GURL& origin) const {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  JNIEnv* env = base::android::AttachCurrentThread();
  if (!obj_) {
    return blink::mojom::PermissionStatus::ASK;
  }

  base::android::ScopedJavaLocalRef<jstring> j_origin(
      base::android::ConvertUTF8ToJavaString(env, origin.spec()));
  return static_cast<blink::mojom::PermissionStatus>(
      Java_AwBrowserContext_getGeolocationPermission(env, obj_, j_origin));
}

mojo::PendingRemote<network::mojom::URLLoaderFactory>
AwBrowserContext::CreateURLLoaderFactory() {
  auto url_loader_factory_params =
      network::mojom::URLLoaderFactoryParams::New();
  url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
  url_loader_factory_params->is_orb_enabled = false;
  mojo::PendingRemote<network::mojom::URLLoaderFactory> factory;

  GetDefaultStoragePartition()->GetNetworkContext()->CreateURLLoaderFactory(
      factory.InitWithNewPipeAndPassReceiver(),
      std::move(url_loader_factory_params));

  return factory;
}

}  // namespace android_webview