diff options
Diffstat (limited to 'chromium/components/precache/content/precache_manager.cc')
-rw-r--r-- | chromium/components/precache/content/precache_manager.cc | 514 |
1 files changed, 0 insertions, 514 deletions
diff --git a/chromium/components/precache/content/precache_manager.cc b/chromium/components/precache/content/precache_manager.cc deleted file mode 100644 index d9ad0ae9809..00000000000 --- a/chromium/components/precache/content/precache_manager.cc +++ /dev/null @@ -1,514 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/precache/content/precache_manager.h" - -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/user_metrics.h" -#include "base/metrics/user_metrics_action.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/time/time.h" -#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h" -#include "components/history/core/browser/history_service.h" -#include "components/precache/core/precache_database.h" -#include "components/precache/core/precache_switches.h" -#include "components/precache/core/proto/precache.pb.h" -#include "components/precache/core/proto/unfinished_work.pb.h" -#include "components/prefs/pref_service.h" -#include "components/sync/driver/sync_service.h" -#include "components/variations/metrics_util.h" -#include "components/variations/variations_associated_data.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/storage_partition.h" -#include "net/base/network_change_notifier.h" -#include "net/http/http_cache.h" -#include "net/url_request/url_request_context.h" -#include "net/url_request/url_request_context_getter.h" - -using content::BrowserThread; - -namespace precache { - -const char kPrecacheFieldTrialName[] = "Precache"; -const char kMinCacheSizeParam[] = "min_cache_size"; - -namespace { - -const char kPrecacheFieldTrialEnabledGroup[] = "Enabled"; -const char kPrecacheFieldTrialControlGroup[] = "Control"; -const char kConfigURLParam[] = "config_url"; -const char kManifestURLPrefixParam[] = "manifest_url_prefix"; -const char kDataReductionProxyParam[] = "disable_if_data_reduction_proxy"; -const size_t kNumTopHosts = 100; - -} // namespace - -size_t NumTopHosts() { - return kNumTopHosts; -} - -PrecacheManager::PrecacheManager( - content::BrowserContext* browser_context, - const syncer::SyncService* const sync_service, - const history::HistoryService* const history_service, - const data_reduction_proxy::DataReductionProxySettings* - data_reduction_proxy_settings, - Delegate* delegate, - const base::FilePath& db_path, - std::unique_ptr<PrecacheDatabase> precache_database) - : browser_context_(browser_context), - sync_service_(sync_service), - history_service_(history_service), - data_reduction_proxy_settings_(data_reduction_proxy_settings), - delegate_(delegate), - is_precaching_(false) { - precache_database_ = std::move(precache_database); - BrowserThread::PostTask( - BrowserThread::DB, FROM_HERE, - base::Bind(base::IgnoreResult(&PrecacheDatabase::Init), - base::Unretained(precache_database_.get()), db_path)); -} - -PrecacheManager::~PrecacheManager() { - // DeleteSoon posts a non-nestable task to the task runner, so any previously - // posted tasks that rely on an Unretained precache_database_ will finish - // before it is deleted. - BrowserThread::DeleteSoon(BrowserThread::DB, FROM_HERE, - precache_database_.release()); -} - -bool PrecacheManager::IsInExperimentGroup() const { - // Verify IsPrecachingAllowed() before calling FieldTrialList::FindFullName(). - // This is because field trials are only assigned when requested. This allows - // us to create Control and Experiment groups that are limited to users for - // whom PrecachingAllowed() is true, thus accentuating the impact of - // precaching. - return IsPrecachingAllowed() && - (base::StartsWith( - base::FieldTrialList::FindFullName(kPrecacheFieldTrialName), - kPrecacheFieldTrialEnabledGroup, base::CompareCase::SENSITIVE) || - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnablePrecache)); -} - -bool PrecacheManager::IsInControlGroup() const { - // Verify IsPrecachingAllowed() before calling FindFullName(). See - // PrecacheManager::IsInExperimentGroup() for an explanation of why. - return IsPrecachingAllowed() && - base::StartsWith( - base::FieldTrialList::FindFullName(kPrecacheFieldTrialName), - kPrecacheFieldTrialControlGroup, base::CompareCase::SENSITIVE); -} - -bool PrecacheManager::IsPrecachingAllowed() const { - return PrecachingAllowed() == AllowedType::ALLOWED; -} - -PrecacheManager::AllowedType PrecacheManager::PrecachingAllowed() const { - bool disable_if_proxy = !variations::GetVariationParamValue( - kPrecacheFieldTrialName, kDataReductionProxyParam).empty(); - if (disable_if_proxy && - (!data_reduction_proxy_settings_ || - data_reduction_proxy_settings_->IsDataReductionProxyEnabled())) - return AllowedType::DISALLOWED; - - if (!(sync_service_ && sync_service_->IsEngineInitialized())) - return AllowedType::PENDING; - - // SyncService delegates to SyncPrefs, which must be called on the UI thread. - if (history_service_ && !sync_service_->IsLocalSyncEnabled() && - sync_service_->GetActiveDataTypes().Has(syncer::SESSIONS) && - !sync_service_->GetEncryptedDataTypes().Has(syncer::SESSIONS)) { - return AllowedType::ALLOWED; - } - - return AllowedType::DISALLOWED; -} - -void PrecacheManager::OnCacheBackendReceived(int net_error_code) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (net_error_code != net::OK) { - // Assume there is no cache. - cache_backend_ = nullptr; - OnCacheSizeReceived(0); - return; - } - DCHECK(cache_backend_); - int result = cache_backend_->CalculateSizeOfAllEntries(base::Bind( - &PrecacheManager::OnCacheSizeReceived, base::Unretained(this))); - if (result == net::ERR_IO_PENDING) { - // Wait for the callback. - } else if (result >= 0) { - // The result is the expected bytes already. - OnCacheSizeReceived(result); - } else { - // Error occurred. Couldn't get the size. Assume there is no cache. - OnCacheSizeReceived(0); - } - cache_backend_ = nullptr; -} - -void PrecacheManager::OnCacheSizeReceived(int cache_size_bytes) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&PrecacheManager::OnCacheSizeReceivedInUIThread, - base::Unretained(this), cache_size_bytes)); -} - -void PrecacheManager::OnCacheSizeReceivedInUIThread(int cache_size_bytes) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - UMA_HISTOGRAM_MEMORY_KB("Precache.CacheSize.AllEntries", - cache_size_bytes / 1024); - - if (cache_size_bytes < min_cache_size_bytes_) { - OnDone(); // Do not continue. - } else { - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::DB, FROM_HERE, - base::Bind(&PrecacheDatabase::GetUnfinishedWork, - base::Unretained(precache_database_.get())), - base::Bind(&PrecacheManager::OnGetUnfinishedWorkDone, AsWeakPtr())); - } -} - -void PrecacheManager::PrecacheIfCacheIsBigEnough( - scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - CHECK(url_request_context_getter); - - // Continue with OnGetUnfinishedWorkDone only if the size of the cache is - // at least min_cache_size_bytes_. - // Class disk_cache::Backend does not expose its maximum size. However, caches - // are usually full, so we can use the size of all the entries stored in the - // cache (via CalculateSizeOfAllEntries) as a proxy of its maximum size. - net::URLRequestContext* context = - url_request_context_getter->GetURLRequestContext(); - if (!context) { - OnCacheSizeReceived(0); - return; - } - net::HttpTransactionFactory* factory = context->http_transaction_factory(); - if (!factory) { - OnCacheSizeReceived(0); - return; - } - net::HttpCache* cache = factory->GetCache(); - if (!cache) { - // There is no known cache. Assume that there is no cache. - // TODO(jamartin): I'm not sure this can be an actual posibility. Consider - // making this a CHECK(cache). - OnCacheSizeReceived(0); - return; - } - const int net_error_code = cache->GetBackend( - &cache_backend_, base::Bind(&PrecacheManager::OnCacheBackendReceived, - base::Unretained(this))); - if (net_error_code != net::ERR_IO_PENDING) { - // No need to wait for the callback. The callback hasn't been called with - // the appropriate code, so we call it directly. - OnCacheBackendReceived(net_error_code); - } -} - -void PrecacheManager::StartPrecaching( - const PrecacheCompletionCallback& precache_completion_callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (is_precaching_) { - DLOG(WARNING) << "Cannot start precaching because precaching is already " - "in progress."; - return; - } - precache_completion_callback_ = precache_completion_callback; - - is_precaching_ = true; - BrowserThread::PostTask( - BrowserThread::DB, FROM_HERE, - base::Bind(&PrecacheDatabase::SetLastPrecacheTimestamp, - base::Unretained(precache_database_.get()), - base::Time::Now())); - - // Ignore boolean return value. In all documented failure cases, it sets the - // int to a reasonable value. - base::StringToInt(variations::GetVariationParamValue(kPrecacheFieldTrialName, - kMinCacheSizeParam), - &min_cache_size_bytes_); - if (min_cache_size_bytes_ <= 0) { - // Skip looking up the cache size, because it doesn't matter. - OnCacheSizeReceivedInUIThread(0); - return; - } - - scoped_refptr<net::URLRequestContextGetter> url_request_context_getter( - content::BrowserContext::GetDefaultStoragePartition(browser_context_) - ->GetURLRequestContext()); - if (!url_request_context_getter) { - OnCacheSizeReceivedInUIThread(0); - return; - } - - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&PrecacheManager::PrecacheIfCacheIsBigEnough, AsWeakPtr(), - std::move(url_request_context_getter))); -} - -void PrecacheManager::OnGetUnfinishedWorkDone( - std::unique_ptr<PrecacheUnfinishedWork> unfinished_work) { - // Reset progress on a prefetch that has taken too long to complete. - if (unfinished_work->has_start_time() && - base::Time::Now() - - base::Time::FromInternalValue(unfinished_work->start_time()) > - base::TimeDelta::FromHours(6)) { - PrecacheFetcher::RecordCompletionStatistics( - *unfinished_work, unfinished_work->top_host_size(), - unfinished_work->resource_size()); - unfinished_work.reset(new PrecacheUnfinishedWork); - } - // If this prefetch is new, set the start time. - if (!unfinished_work->has_start_time()) - unfinished_work->set_start_time(base::Time::Now().ToInternalValue()); - unfinished_work_ = std::move(unfinished_work); - bool needs_top_hosts = unfinished_work_->top_host_size() == 0; - - base::RecordAction(base::UserMetricsAction("Precache.Fetch.Begin")); - - if (IsInExperimentGroup()) { - BrowserThread::PostTask( - BrowserThread::DB, FROM_HERE, - base::Bind(&PrecacheDatabase::DeleteExpiredPrecacheHistory, - base::Unretained(precache_database_.get()), - base::Time::Now())); - - // Request NumTopHosts() top hosts. Note that PrecacheFetcher is further - // bound by the value of PrecacheConfigurationSettings.top_sites_count, as - // retrieved from the server. - if (needs_top_hosts) { - history_service_->TopHosts( - NumTopHosts(), - base::Bind(&PrecacheManager::OnHostsReceived, AsWeakPtr())); - } else { - InitializeAndStartFetcher(); - } - } else if (IsInControlGroup()) { - // Calculate TopHosts solely for metrics purposes. - if (needs_top_hosts) { - history_service_->TopHosts( - NumTopHosts(), - base::Bind(&PrecacheManager::OnHostsReceivedThenDone, AsWeakPtr())); - } else { - OnDone(); - } - } else { - if (PrecachingAllowed() != AllowedType::PENDING) { - // We are not waiting on the sync engine to be initialized. The user - // either is not in the field trial, or does not have sync enabled. - // Pretend that precaching started, so that the PrecacheServiceLauncher - // doesn't try to start it again. - } - - OnDone(); - } -} - -void PrecacheManager::CancelPrecaching() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!is_precaching_) { - // Do nothing if precaching is not in progress. - return; - } - is_precaching_ = false; - // If cancellation occurs after StartPrecaching but before OnHostsReceived, - // is_precaching will be true, but the precache_fetcher_ will not yet be - // constructed. - if (precache_fetcher_) { - std::unique_ptr<PrecacheUnfinishedWork> unfinished_work = - precache_fetcher_->CancelPrecaching(); - if (unfinished_work) { - BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, - base::Bind(&PrecacheDatabase::SaveUnfinishedWork, - precache_database_->GetWeakPtr(), - base::Passed(&unfinished_work))); - } - // Destroying the |precache_fetcher_| will cancel any fetch in progress. - precache_fetcher_.reset(); - } - precache_completion_callback_.Reset(); -} - -bool PrecacheManager::IsPrecaching() const { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return is_precaching_; -} - -void PrecacheManager::UpdatePrecacheMetricsAndState( - const GURL& url, - const GURL& referrer, - const base::Time& fetch_time, - const net::HttpResponseInfo& info, - int64_t size, - bool is_user_traffic, - const base::Callback<void(base::Time)>& register_synthetic_trial) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::DB, FROM_HERE, - base::Bind(&PrecacheDatabase::GetLastPrecacheTimestamp, - base::Unretained(precache_database_.get())), - base::Bind(&PrecacheManager::RecordStatsForFetch, AsWeakPtr(), url, - referrer, fetch_time, info, size, register_synthetic_trial)); - - if (is_user_traffic && IsPrecaching()) - CancelPrecaching(); -} - -void PrecacheManager::RecordStatsForFetch( - const GURL& url, - const GURL& referrer, - const base::Time& fetch_time, - const net::HttpResponseInfo& info, - int64_t size, - const base::Callback<void(base::Time)>& register_synthetic_trial, - base::Time last_precache_time) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - register_synthetic_trial.Run(last_precache_time); - - if (size == 0 || url.is_empty() || !url.SchemeIsHTTPOrHTTPS()) { - // Ignore empty responses, empty URLs, or URLs that aren't HTTP or HTTPS. - return; - } - - if (!history_service_) - return; - - history_service_->HostRankIfAvailable( - referrer, - base::Bind(&PrecacheManager::RecordStatsForFetchInternal, AsWeakPtr(), - url, referrer.host(), fetch_time, info, size)); -} - -void PrecacheManager::RecordStatsForFetchInternal( - const GURL& url, - const std::string& referrer_host, - const base::Time& fetch_time, - const net::HttpResponseInfo& info, - int64_t size, - int host_rank) { - if (is_precaching_) { - // Assume that precache is responsible for all requests made while - // precaching is currently in progress. - // TODO(sclittle): Make PrecacheFetcher explicitly mark precache-motivated - // fetches, and use that to determine whether or not a fetch was motivated - // by precaching. - BrowserThread::PostTask( - BrowserThread::DB, FROM_HERE, - base::Bind(&PrecacheDatabase::RecordURLPrefetchMetrics, - base::Unretained(precache_database_.get()), info)); - } else { - bool is_connection_cellular = - net::NetworkChangeNotifier::IsConnectionCellular( - net::NetworkChangeNotifier::GetConnectionType()); - - BrowserThread::PostTask( - BrowserThread::DB, FROM_HERE, - base::Bind(&PrecacheDatabase::RecordURLNonPrefetch, - base::Unretained(precache_database_.get()), url, fetch_time, - info, size, host_rank, is_connection_cellular)); - } -} - -void PrecacheManager::ClearHistory() { - // PrecacheDatabase::ClearHistory must run after PrecacheDatabase::Init has - // finished. Using PostNonNestableTask guarantees this, by definition. See - // base::SequencedTaskRunner for details. - BrowserThread::PostNonNestableTask( - BrowserThread::DB, FROM_HERE, - base::Bind(&PrecacheDatabase::ClearHistory, - base::Unretained(precache_database_.get()))); -} - -void PrecacheManager::Shutdown() { - CancelPrecaching(); -} - -void PrecacheManager::OnDone() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - precache_fetcher_.reset(); - - // Run completion callback if not null. It's null if the client is in the - // Control group and CancelPrecaching is called before TopHosts computation - // finishes. - if (!precache_completion_callback_.is_null()) { - precache_completion_callback_.Run(!is_precaching_); - // Uninitialize the callback so that any scoped_refptrs in it are released. - precache_completion_callback_.Reset(); - } - - is_precaching_ = false; -} - -void PrecacheManager::OnManifestFetched(const std::string& host, - const PrecacheManifest& manifest) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (delegate_) - delegate_->OnManifestFetched(host, manifest); -} - -void PrecacheManager::OnHostsReceived( - const history::TopHostsList& host_counts) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - for (const auto& host_count : host_counts) { - TopHost* top_host = unfinished_work_->add_top_host(); - top_host->set_hostname(host_count.first); - top_host->set_visits(host_count.second); - } - InitializeAndStartFetcher(); -} - -void PrecacheManager::InitializeAndStartFetcher() { - if (!is_precaching_) { - // Don't start precaching if it was canceled while waiting for the list of - // hosts. - return; - } - // Start precaching. - precache_fetcher_.reset(new PrecacheFetcher( - content::BrowserContext::GetDefaultStoragePartition(browser_context_) - ->GetURLRequestContext(), - GURL(variations::GetVariationParamValue(kPrecacheFieldTrialName, - kConfigURLParam)), - variations::GetVariationParamValue(kPrecacheFieldTrialName, - kManifestURLPrefixParam), - std::move(unfinished_work_), - metrics::HashName( - base::FieldTrialList::FindFullName(kPrecacheFieldTrialName)), - precache_database_->GetWeakPtr(), - content::BrowserThread::GetTaskRunnerForThread( - content::BrowserThread::DB), - this)); - precache_fetcher_->Start(); -} - -void PrecacheManager::OnHostsReceivedThenDone( - const history::TopHostsList& host_counts) { - OnDone(); -} - -} // namespace precache |