Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Side by Side Diff: components/quirks/quirks_manager.cc

Issue 1528963002: Quirks Client for downloading and providing display profiles (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: stevenjb@'s latest code review (small tweaks) Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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.
4
5 #include "components/quirks/quirks_manager.h"
6
7 #include <utility>
8
9 #include "base/command_line.h"
10 #include "base/files/file_util.h"
11 #include "base/format_macros.h"
12 #include "base/path_service.h"
13 #include "base/rand_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/task_runner_util.h"
16 #include "components/prefs/pref_registry_simple.h"
17 #include "components/prefs/scoped_user_pref_update.h"
18 #include "components/quirks/pref_names.h"
19 #include "components/quirks/quirks_client.h"
20 #include "components/quirks/switches.h"
21 #include "net/url_request/url_fetcher.h"
22 #include "net/url_request/url_request_context_getter.h"
23 #include "url/gurl.h"
24
25 namespace quirks {
26
27 namespace {
28
29 QuirksManager* g_manager = nullptr;
30
31 const char kIccExtension[] = ".icc";
32
33 // How often we query Quirks Server.
34 const int kDaysBetweenServerChecks = 30;
35
36 // Check if file exists, VLOG results.
37 bool CheckAndLogFile(const base::FilePath& path) {
38 const bool exists = base::PathExists(path);
39 VLOG(1) << (exists ? "File" : "No File") << " found at " << path.value();
40 // TODO(glevin): If file exists, do we want to implement a hash to verify that
41 // the file hasn't been corrupted or tampered with?
42 return exists;
43 }
44
45 base::FilePath CheckForIccFile(base::FilePath built_in_path,
46 base::FilePath download_path) {
47 // First, look for icc file in old read-only location. If there, we don't use
48 // the Quirks server.
49 // TODO(glevin): Awaiting final decision on how to handle old read-only files.
50 if (CheckAndLogFile(built_in_path))
51 return built_in_path;
52
53 // If experimental Quirks flag isn't set, no other icc file is available.
54 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
55 switches::kEnableQuirksClient)) {
56 VLOG(1) << "Quirks Client disabled, no built-in icc file available.";
57 return base::FilePath();
58 }
59
60 // Check if QuirksClient has already downloaded icc file from server.
61 if (CheckAndLogFile(download_path))
62 return download_path;
63
64 return base::FilePath();
65 }
66
67 } // namespace
68
69 std::string IdToHexString(int64_t product_id) {
70 return base::StringPrintf("%08" PRIx64, product_id);
71 }
72
73 std::string IdToFileName(int64_t product_id) {
74 return IdToHexString(product_id).append(kIccExtension);
75 }
76
77 ////////////////////////////////////////////////////////////////////////////////
78 // QuirksManager
79
80 QuirksManager::QuirksManager(
81 scoped_ptr<Delegate> delegate,
82 scoped_refptr<base::SequencedWorkerPool> blocking_pool,
83 PrefService* local_state,
84 scoped_refptr<net::URLRequestContextGetter> url_context_getter)
85 : waiting_for_login_(true),
86 delegate_(std::move(delegate)),
87 blocking_pool_(blocking_pool),
88 local_state_(local_state),
89 url_context_getter_(url_context_getter),
90 weak_ptr_factory_(this) {}
91
92 QuirksManager::~QuirksManager() {
93 clients_.clear();
94 g_manager = nullptr;
95 }
96
97 // static
98 void QuirksManager::Initialize(
99 scoped_ptr<Delegate> delegate,
100 scoped_refptr<base::SequencedWorkerPool> blocking_pool,
101 PrefService* local_state,
102 scoped_refptr<net::URLRequestContextGetter> url_context_getter) {
103 g_manager = new QuirksManager(std::move(delegate), blocking_pool, local_state,
104 url_context_getter);
105 }
106
107 // static
108 void QuirksManager::Shutdown() {
109 delete g_manager;
110 }
111
112 // static
113 QuirksManager* QuirksManager::Get() {
114 DCHECK(g_manager);
115 return g_manager;
116 }
117
118 // static
119 void QuirksManager::RegisterPrefs(PrefRegistrySimple* registry) {
120 registry->RegisterDictionaryPref(prefs::kQuirksClientLastServerCheck);
121 }
122
123 // Delay downloads until after login, to ensure that device policy has been set.
124 void QuirksManager::OnLoginCompleted() {
125 if (!waiting_for_login_)
126 return;
127
128 waiting_for_login_ = false;
129 for (const scoped_ptr<QuirksClient>& client : clients_)
130 client->StartDownload();
131 }
132
133 void QuirksManager::RequestIccProfilePath(
134 int64_t product_id,
135 const RequestFinishedCallback& on_request_finished) {
136 DCHECK(thread_checker_.CalledOnValidThread());
137
138 std::string name = IdToFileName(product_id);
139 base::PostTaskAndReplyWithResult(
140 blocking_pool_.get(), FROM_HERE,
141 base::Bind(&CheckForIccFile,
142 delegate_->GetBuiltInDisplayProfileDirectory().Append(name),
143 delegate_->GetDownloadDisplayProfileDirectory().Append(name)),
144 base::Bind(&QuirksManager::OnIccFilePathRequestCompleted,
145 weak_ptr_factory_.GetWeakPtr(), product_id,
146 on_request_finished));
147 }
148
149 void QuirksManager::ClientFinished(QuirksClient* client) {
150 SetLastServerCheck(client->product_id(), base::Time::Now());
151 auto it = std::find_if(clients_.begin(), clients_.end(),
152 [client](const scoped_ptr<QuirksClient>& c) {
153 return c.get() == client;
154 });
155 CHECK(it != clients_.end());
156 clients_.erase(it);
157 }
158
159 scoped_ptr<net::URLFetcher> QuirksManager::CreateURLFetcher(
160 const GURL& url,
161 net::URLFetcherDelegate* delegate) {
162 if (!fake_quirks_fetcher_creator_.is_null())
163 return fake_quirks_fetcher_creator_.Run(url, delegate);
164
165 return net::URLFetcher::Create(url, net::URLFetcher::GET, delegate);
166 }
167
168 void QuirksManager::OnIccFilePathRequestCompleted(
169 int64_t product_id,
170 const RequestFinishedCallback& on_request_finished,
171 base::FilePath path) {
172 DCHECK(thread_checker_.CalledOnValidThread());
173
174 // If we found a file or client is disabled, inform requester.
175 if (!path.empty() ||
176 !base::CommandLine::ForCurrentProcess()->HasSwitch(
177 switches::kEnableQuirksClient)) {
178 on_request_finished.Run(path, false);
179 // TODO(glevin): If Quirks files are ever modified on the server, we'll need
180 // to modify this logic to check for updates. See crbug.com/595024.
181 return;
182 }
183
184 double last_check = 0.0;
185 local_state_->GetDictionary(prefs::kQuirksClientLastServerCheck)
186 ->GetDouble(IdToHexString(product_id), &last_check);
187
188 // If never checked server before, need to check for new device.
189 if (last_check == 0.0) {
190 delegate_->GetDaysSinceOobe(base::Bind(
191 &QuirksManager::OnDaysSinceOobeReceived, weak_ptr_factory_.GetWeakPtr(),
192 product_id, on_request_finished));
193 return;
194 }
195
196 const base::TimeDelta time_since =
197 base::Time::Now() - base::Time::FromDoubleT(last_check);
198
199 // Don't need server check if we've checked within last 30 days.
200 if (time_since < base::TimeDelta::FromDays(kDaysBetweenServerChecks)) {
201 VLOG(2) << time_since.InDays()
202 << " days since last Quirks Server check for display "
203 << IdToHexString(product_id);
204 on_request_finished.Run(base::FilePath(), false);
205 return;
206 }
207
208 CreateClient(product_id, on_request_finished);
209 }
210
211 void QuirksManager::OnDaysSinceOobeReceived(
212 int64_t product_id,
213 const RequestFinishedCallback& on_request_finished,
214 int days_since_oobe) {
215 // On newer devices, we want to check server immediately (after OOBE/login).
216 if (days_since_oobe <= kDaysBetweenServerChecks) {
217 CreateClient(product_id, on_request_finished);
218 return;
219 }
220
221 // Otherwise, for the first check on an older device, we want to stagger
222 // it over 30 days, so artificially set last check accordingly.
223 // TODO(glevin): I believe that it makes sense to remove this random delay
224 // in the next Chrome release.
225 const int rand_days = base::RandInt(0, kDaysBetweenServerChecks);
226 const base::Time fake_last_check =
227 base::Time::Now() - base::TimeDelta::FromDays(rand_days);
228 SetLastServerCheck(product_id, fake_last_check);
229 VLOG(2) << "Delaying first Quirks Server check by "
230 << kDaysBetweenServerChecks - rand_days << " days.";
231
232 on_request_finished.Run(base::FilePath(), false);
233 }
234
235 void QuirksManager::CreateClient(
236 int64_t product_id,
237 const RequestFinishedCallback& on_request_finished) {
238 QuirksClient* client =
239 new QuirksClient(product_id, on_request_finished, this);
240 clients_.insert(make_scoped_ptr(client));
241 if (!waiting_for_login_)
242 client->StartDownload();
243 else
244 VLOG(2) << "Quirks Client created; waiting for login to begin download.";
245 }
246
247 void QuirksManager::SetLastServerCheck(int64_t product_id,
248 const base::Time& last_check) {
249 DCHECK(thread_checker_.CalledOnValidThread());
250 DictionaryPrefUpdate dict(local_state_, prefs::kQuirksClientLastServerCheck);
251 dict->SetDouble(IdToHexString(product_id), last_check.ToDoubleT());
252 }
253
254 } // namespace quirks
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698