1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/precache/content/precache_manager.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/files/file_path.h"
14 #include "base/logging.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/time/time.h"
18 #include "components/history/core/browser/history_service.h"
19 #include "components/precache/core/precache_database.h"
20 #include "components/precache/core/precache_switches.h"
21 #include "components/sync_driver/sync_service.h"
22 #include "components/variations/variations_associated_data.h"
23 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "net/base/network_change_notifier.h"
27 using content::BrowserThread
;
31 const char kPrecacheFieldTrialName
[] = "Precache";
32 const char kPrecacheFieldTrialEnabledGroup
[] = "Enabled";
33 const char kManifestURLPrefixParam
[] = "manifest_url_prefix";
34 const int kNumTopHosts
= 100;
44 PrecacheManager::PrecacheManager(
45 content::BrowserContext
* browser_context
,
46 const sync_driver::SyncService
* const sync_service
)
47 : browser_context_(browser_context
),
48 sync_service_(sync_service
),
49 precache_database_(new PrecacheDatabase()),
50 is_precaching_(false) {
51 base::FilePath
db_path(browser_context_
->GetPath().Append(
52 base::FilePath(FILE_PATH_LITERAL("PrecacheDatabase"))));
54 BrowserThread::PostTask(
55 BrowserThread::DB
, FROM_HERE
,
56 base::Bind(base::IgnoreResult(&PrecacheDatabase::Init
),
57 precache_database_
, db_path
));
60 PrecacheManager::~PrecacheManager() {}
63 bool PrecacheManager::IsPrecachingEnabled() {
64 return base::FieldTrialList::FindFullName(kPrecacheFieldTrialName
) ==
65 kPrecacheFieldTrialEnabledGroup
||
66 base::CommandLine::ForCurrentProcess()->HasSwitch(
67 switches::kEnablePrecache
);
70 bool PrecacheManager::IsPrecachingAllowed() {
71 return sync_service_
&&
72 sync_service_
->GetActiveDataTypes().Has(syncer::SESSIONS
) &&
73 !sync_service_
->GetEncryptedDataTypes().Has(syncer::SESSIONS
);
76 void PrecacheManager::StartPrecaching(
77 const PrecacheCompletionCallback
& precache_completion_callback
,
78 const history::HistoryService
& history_service
) {
79 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
82 DLOG(WARNING
) << "Cannot start precaching because precaching is already "
86 is_precaching_
= true;
88 BrowserThread::PostTask(
89 BrowserThread::DB
, FROM_HERE
,
90 base::Bind(&PrecacheDatabase::DeleteExpiredPrecacheHistory
,
91 precache_database_
, base::Time::Now()));
93 precache_completion_callback_
= precache_completion_callback
;
95 // Request NumTopHosts() top hosts. Note that PrecacheFetcher is further bound
96 // by the value of PrecacheConfigurationSettings.top_sites_count, as retrieved
98 history_service
.TopHosts(
100 base::Bind(&PrecacheManager::OnHostsReceived
, AsWeakPtr()));
103 void PrecacheManager::CancelPrecaching() {
104 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
106 if (!is_precaching_
) {
107 // Do nothing if precaching is not in progress.
110 is_precaching_
= false;
112 // Destroying the |precache_fetcher_| will cancel any fetch in progress.
113 precache_fetcher_
.reset();
115 // Uninitialize the callback so that any scoped_refptrs in it are released.
116 precache_completion_callback_
.Reset();
119 bool PrecacheManager::IsPrecaching() const {
120 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
121 return is_precaching_
;
124 void PrecacheManager::RecordStatsForFetch(const GURL
& url
,
125 const base::Time
& fetch_time
,
128 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
130 if (size
== 0 || url
.is_empty() || !url
.SchemeIsHTTPOrHTTPS()) {
131 // Ignore empty responses, empty URLs, or URLs that aren't HTTP or HTTPS.
135 if (is_precaching_
) {
136 // Assume that precache is responsible for all requests made while
137 // precaching is currently in progress.
138 // TODO(sclittle): Make PrecacheFetcher explicitly mark precache-motivated
139 // fetches, and use that to determine whether or not a fetch was motivated
141 BrowserThread::PostTask(
142 BrowserThread::DB
, FROM_HERE
,
143 base::Bind(&PrecacheDatabase::RecordURLPrecached
, precache_database_
,
144 url
, fetch_time
, size
, was_cached
));
146 bool is_connection_cellular
=
147 net::NetworkChangeNotifier::IsConnectionCellular(
148 net::NetworkChangeNotifier::GetConnectionType());
150 BrowserThread::PostTask(
151 BrowserThread::DB
, FROM_HERE
,
152 base::Bind(&PrecacheDatabase::RecordURLFetched
, precache_database_
, url
,
153 fetch_time
, size
, was_cached
, is_connection_cellular
));
157 void PrecacheManager::ClearHistory() {
158 // PrecacheDatabase::ClearHistory must run after PrecacheDatabase::Init has
159 // finished. Using PostNonNestableTask guarantees this, by definition. See
160 // base::SequencedTaskRunner for details.
161 BrowserThread::PostNonNestableTask(
162 BrowserThread::DB
, FROM_HERE
,
163 base::Bind(&PrecacheDatabase::ClearHistory
, precache_database_
));
166 void PrecacheManager::Shutdown() {
170 void PrecacheManager::OnDone() {
171 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
173 // If OnDone has been called, then we should just be finishing precaching.
174 DCHECK(is_precaching_
);
175 is_precaching_
= false;
177 precache_fetcher_
.reset();
179 precache_completion_callback_
.Run();
180 // Uninitialize the callback so that any scoped_refptrs in it are released.
181 precache_completion_callback_
.Reset();
184 void PrecacheManager::OnHostsReceived(
185 const history::TopHostsList
& host_counts
) {
186 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
188 if (!is_precaching_
) {
189 // Don't start precaching if it was canceled while waiting for the list of
194 std::vector
<std::string
> hosts
;
195 for (const auto& host_count
: host_counts
)
196 hosts
.push_back(host_count
.first
);
199 precache_fetcher_
.reset(
200 new PrecacheFetcher(hosts
, browser_context_
->GetRequestContext(),
201 variations::GetVariationParamValue(
202 kPrecacheFieldTrialName
, kManifestURLPrefixParam
),
204 precache_fetcher_
->Start();
207 } // namespace precache