xref: /aosp_15_r20/external/cronet/components/cronet/cronet_prefs_manager.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/cronet/cronet_prefs_manager.h"
6 
7 #include <memory>
8 
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/functional/bind.h"
12 #include "base/functional/callback.h"
13 #include "base/location.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/task/sequenced_task_runner.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "base/time/time.h"
20 #include "build/build_config.h"
21 #include "components/cronet/host_cache_persistence_manager.h"
22 #include "components/prefs/json_pref_store.h"
23 #include "components/prefs/pref_change_registrar.h"
24 #include "components/prefs/pref_registry_simple.h"
25 #include "components/prefs/pref_service.h"
26 #include "components/prefs/pref_service_factory.h"
27 #include "net/http/http_server_properties.h"
28 #include "net/nqe/network_qualities_prefs_manager.h"
29 #include "net/url_request/url_request_context_builder.h"
30 
31 namespace cronet {
32 namespace {
33 
34 // Name of the pref used for HTTP server properties persistence.
35 const char kHttpServerPropertiesPref[] = "net.http_server_properties";
36 // Name of preference directory.
37 const base::FilePath::CharType kPrefsDirectoryName[] =
38     FILE_PATH_LITERAL("prefs");
39 // Name of preference file.
40 const base::FilePath::CharType kPrefsFileName[] =
41     FILE_PATH_LITERAL("local_prefs.json");
42 // Current version of disk storage.
43 const int32_t kStorageVersion = 1;
44 // Version number used when the version of disk storage is unknown.
45 const uint32_t kStorageVersionUnknown = 0;
46 // Name of the pref used for host cache persistence.
47 const char kHostCachePref[] = "net.host_cache";
48 // Name of the pref used for NQE persistence.
49 const char kNetworkQualitiesPref[] = "net.network_qualities";
50 
IsCurrentVersion(const base::FilePath & version_filepath)51 bool IsCurrentVersion(const base::FilePath& version_filepath) {
52   if (!base::PathExists(version_filepath))
53     return false;
54   base::File version_file(version_filepath,
55                           base::File::FLAG_OPEN | base::File::FLAG_READ);
56   uint32_t version = kStorageVersionUnknown;
57   int bytes_read =
58       version_file.Read(0, reinterpret_cast<char*>(&version), sizeof(version));
59   if (bytes_read != sizeof(version)) {
60     DLOG(WARNING) << "Cannot read from version file.";
61     return false;
62   }
63   return version == kStorageVersion;
64 }
65 
66 // TODO(xunjieli): Handle failures.
InitializeStorageDirectory(const base::FilePath & dir)67 void InitializeStorageDirectory(const base::FilePath& dir) {
68   // Checks version file and clear old storage.
69   base::FilePath version_filepath(dir.AppendASCII("version"));
70   if (IsCurrentVersion(version_filepath)) {
71     // The version is up to date, so there is nothing to do.
72     return;
73   }
74   // Delete old directory recursively and create a new directory.
75   // base::DeletePathRecursively() returns true if the directory does not exist,
76   // so it is fine if there is nothing on disk.
77   if (!(base::DeletePathRecursively(dir) && base::CreateDirectory(dir))) {
78     DLOG(WARNING) << "Cannot purge directory.";
79     return;
80   }
81   base::File new_version_file(version_filepath, base::File::FLAG_CREATE_ALWAYS |
82                                                     base::File::FLAG_WRITE);
83 
84   if (!new_version_file.IsValid()) {
85     DLOG(WARNING) << "Cannot create a version file.";
86     return;
87   }
88 
89   DCHECK(new_version_file.created());
90   uint32_t new_version = kStorageVersion;
91   int bytes_written = new_version_file.Write(
92       0, reinterpret_cast<char*>(&new_version), sizeof(new_version));
93   if (bytes_written != sizeof(new_version)) {
94     DLOG(WARNING) << "Cannot write to version file.";
95     return;
96   }
97   base::FilePath prefs_dir = dir.Append(kPrefsDirectoryName);
98   if (!base::CreateDirectory(prefs_dir)) {
99     DLOG(WARNING) << "Cannot create prefs directory";
100     return;
101   }
102 }
103 
104 // Connects the HttpServerProperties's storage to the prefs.
105 class PrefServiceAdapter : public net::HttpServerProperties::PrefDelegate {
106  public:
PrefServiceAdapter(PrefService * pref_service)107   explicit PrefServiceAdapter(PrefService* pref_service)
108       : pref_service_(pref_service), path_(kHttpServerPropertiesPref) {
109     pref_change_registrar_.Init(pref_service_);
110   }
111 
112   PrefServiceAdapter(const PrefServiceAdapter&) = delete;
113   PrefServiceAdapter& operator=(const PrefServiceAdapter&) = delete;
114 
~PrefServiceAdapter()115   ~PrefServiceAdapter() override {}
116 
117   // PrefDelegate implementation.
GetServerProperties() const118   const base::Value::Dict& GetServerProperties() const override {
119     return pref_service_->GetDict(path_);
120   }
121 
SetServerProperties(base::Value::Dict dict,base::OnceClosure callback)122   void SetServerProperties(base::Value::Dict dict,
123                            base::OnceClosure callback) override {
124     pref_service_->SetDict(path_, std::move(dict));
125     if (callback)
126       pref_service_->CommitPendingWrite(std::move(callback));
127   }
128 
WaitForPrefLoad(base::OnceClosure callback)129   void WaitForPrefLoad(base::OnceClosure callback) override {
130     // Notify the pref manager that settings are already loaded, as a result
131     // of initializing the pref store synchronously.
132     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
133         FROM_HERE, std::move(callback));
134   }
135 
136  private:
137   raw_ptr<PrefService> pref_service_;
138   const std::string path_;
139   PrefChangeRegistrar pref_change_registrar_;
140 };  // class PrefServiceAdapter
141 
142 class NetworkQualitiesPrefDelegateImpl
143     : public net::NetworkQualitiesPrefsManager::PrefDelegate {
144  public:
145   // Caller must guarantee that |pref_service| outlives |this|.
NetworkQualitiesPrefDelegateImpl(PrefService * pref_service)146   explicit NetworkQualitiesPrefDelegateImpl(PrefService* pref_service)
147       : pref_service_(pref_service), lossy_prefs_writing_task_posted_(false) {
148     DCHECK(pref_service_);
149   }
150 
151   NetworkQualitiesPrefDelegateImpl(const NetworkQualitiesPrefDelegateImpl&) =
152       delete;
153   NetworkQualitiesPrefDelegateImpl& operator=(
154       const NetworkQualitiesPrefDelegateImpl&) = delete;
155 
~NetworkQualitiesPrefDelegateImpl()156   ~NetworkQualitiesPrefDelegateImpl() override {}
157 
158   // net::NetworkQualitiesPrefsManager::PrefDelegate implementation.
SetDictionaryValue(const base::Value::Dict & dict)159   void SetDictionaryValue(const base::Value::Dict& dict) override {
160     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
161 
162     pref_service_->SetDict(kNetworkQualitiesPref, dict.Clone());
163     if (lossy_prefs_writing_task_posted_)
164       return;
165 
166     // Post the task that schedules the writing of the lossy prefs.
167     lossy_prefs_writing_task_posted_ = true;
168 
169     // Delay after which the task that schedules the writing of the lossy prefs.
170     // This is needed in case the writing of the lossy prefs is not scheduled
171     // automatically. The delay was chosen so that it is large enough that it
172     // does not affect the startup performance.
173     static const int32_t kUpdatePrefsDelaySeconds = 10;
174 
175     base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
176         FROM_HERE,
177         base::BindOnce(
178             &NetworkQualitiesPrefDelegateImpl::SchedulePendingLossyWrites,
179             weak_ptr_factory_.GetWeakPtr()),
180         base::Seconds(kUpdatePrefsDelaySeconds));
181   }
182 
GetDictionaryValue()183   base::Value::Dict GetDictionaryValue() override {
184     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
185     return pref_service_->GetDict(kNetworkQualitiesPref).Clone();
186   }
187 
188  private:
189   // Schedules the writing of the lossy prefs.
SchedulePendingLossyWrites()190   void SchedulePendingLossyWrites() {
191     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
192     pref_service_->SchedulePendingLossyWrites();
193     lossy_prefs_writing_task_posted_ = false;
194   }
195 
196   raw_ptr<PrefService> pref_service_;
197 
198   // True if the task that schedules the writing of the lossy prefs has been
199   // posted.
200   bool lossy_prefs_writing_task_posted_;
201 
202   THREAD_CHECKER(thread_checker_);
203 
204   base::WeakPtrFactory<NetworkQualitiesPrefDelegateImpl> weak_ptr_factory_{
205       this};
206 };
207 
208 }  // namespace
209 
CronetPrefsManager(const std::string & storage_path,scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,scoped_refptr<base::SequencedTaskRunner> file_task_runner,bool enable_network_quality_estimator,bool enable_host_cache_persistence,net::NetLog * net_log,net::URLRequestContextBuilder * context_builder)210 CronetPrefsManager::CronetPrefsManager(
211     const std::string& storage_path,
212     scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
213     scoped_refptr<base::SequencedTaskRunner> file_task_runner,
214     bool enable_network_quality_estimator,
215     bool enable_host_cache_persistence,
216     net::NetLog* net_log,
217     net::URLRequestContextBuilder* context_builder) {
218   DCHECK(network_task_runner->BelongsToCurrentThread());
219   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
220 
221 #if BUILDFLAG(IS_WIN)
222   base::FilePath storage_file_path(
223       base::FilePath::FromUTF8Unsafe(storage_path));
224 #else
225   base::FilePath storage_file_path(storage_path);
226 #endif
227 
228   // Make sure storage directory has correct version.
229   {
230     base::ScopedAllowBlocking allow_blocking;
231     InitializeStorageDirectory(storage_file_path);
232   }
233 
234   base::FilePath filepath =
235       storage_file_path.Append(kPrefsDirectoryName).Append(kPrefsFileName);
236 
237   json_pref_store_ = new JsonPrefStore(filepath, std::unique_ptr<PrefFilter>(),
238                                        file_task_runner);
239 
240   // Register prefs and set up the PrefService.
241   PrefServiceFactory factory;
242   factory.set_user_prefs(json_pref_store_);
243   scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple());
244   registry->RegisterDictionaryPref(kHttpServerPropertiesPref);
245 
246   if (enable_network_quality_estimator) {
247     // Use lossy prefs to limit the overhead of reading/writing the prefs.
248     registry->RegisterDictionaryPref(kNetworkQualitiesPref,
249                                      PrefRegistry::LOSSY_PREF);
250   }
251 
252   if (enable_host_cache_persistence) {
253     registry->RegisterListPref(kHostCachePref);
254   }
255 
256   {
257     base::ScopedAllowBlocking allow_blocking;
258     pref_service_ = factory.Create(registry.get());
259   }
260 
261   context_builder->SetHttpServerProperties(
262       std::make_unique<net::HttpServerProperties>(
263           std::make_unique<PrefServiceAdapter>(pref_service_.get()), net_log));
264 }
265 
~CronetPrefsManager()266 CronetPrefsManager::~CronetPrefsManager() {
267   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
268 }
269 
SetupNqePersistence(net::NetworkQualityEstimator * nqe)270 void CronetPrefsManager::SetupNqePersistence(
271     net::NetworkQualityEstimator* nqe) {
272   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
273   network_qualities_prefs_manager_ =
274       std::make_unique<net::NetworkQualitiesPrefsManager>(
275           std::make_unique<NetworkQualitiesPrefDelegateImpl>(
276               pref_service_.get()));
277 
278   network_qualities_prefs_manager_->InitializeOnNetworkThread(nqe);
279 }
280 
SetupHostCachePersistence(net::HostCache * host_cache,int host_cache_persistence_delay_ms,net::NetLog * net_log)281 void CronetPrefsManager::SetupHostCachePersistence(
282     net::HostCache* host_cache,
283     int host_cache_persistence_delay_ms,
284     net::NetLog* net_log) {
285   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
286   host_cache_persistence_manager_ =
287       std::make_unique<HostCachePersistenceManager>(
288           host_cache, pref_service_.get(), kHostCachePref,
289           base::Milliseconds(host_cache_persistence_delay_ms), net_log);
290 }
291 
PrepareForShutdown()292 void CronetPrefsManager::PrepareForShutdown() {
293   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
294   if (pref_service_)
295     pref_service_->CommitPendingWrite();
296 
297   // Shutdown managers on the Pref sequence.
298   if (network_qualities_prefs_manager_)
299     network_qualities_prefs_manager_->ShutdownOnPrefSequence();
300 
301   host_cache_persistence_manager_.reset();
302 }
303 
304 }  // namespace cronet
305