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

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: A few 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
« no previous file with comments | « components/quirks/quirks_manager.h ('k') | components/quirks/switches.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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* 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 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 manager_ = new QuirksManager(std::move(delegate), blocking_pool, local_state,
104 url_context_getter);
105 }
106
107 // static
108 void QuirksManager::Shutdown() {
109 delete manager_;
110 }
111
112 // static
113 QuirksManager* QuirksManager::Get() {
114 DCHECK(manager_);
115 return 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 DCHECK(thread_checker_.CalledOnValidThread());
151 SetLastServerCheck(client->product_id(), base::Time::Now());
152 auto it = std::find_if(clients_.begin(), clients_.end(),
153 [client](const scoped_ptr<QuirksClient>& c) {
154 return c.get() == client;
155 });
156 CHECK(it != clients_.end());
157 clients_.erase(it);
158 }
159
160 scoped_ptr<net::URLFetcher> QuirksManager::CreateURLFetcher(
161 const GURL& url,
162 net::URLFetcherDelegate* delegate) {
163 if (!fake_quirks_fetcher_creator_.is_null())
164 return fake_quirks_fetcher_creator_.Run(url, delegate);
165
166 return net::URLFetcher::Create(url, net::URLFetcher::GET, delegate);
167 }
168
169 void QuirksManager::OnIccFilePathRequestCompleted(
170 int64_t product_id,
171 const RequestFinishedCallback& on_request_finished,
172 base::FilePath path) {
173 DCHECK(thread_checker_.CalledOnValidThread());
174
175 // If we found a file or client is disabled, inform requester.
176 if (!path.empty() ||
177 !base::CommandLine::ForCurrentProcess()->HasSwitch(
178 switches::kEnableQuirksClient)) {
179 on_request_finished.Run(path, false);
180 // TODO(glevin): If Quirks files are ever modified on the server, we'll need
181 // to modify this logic to check for updates. See crbug.com/595024.
182 return;
183 }
184
185 double last_check = 0.0;
186 local_state_->GetDictionary(prefs::kQuirksClientLastServerCheck)
187 ->GetDouble(IdToHexString(product_id), &last_check);
188
189 // If never checked server before, need to check for new device.
190 if (last_check == 0.0) {
191 delegate_->GetDaysSinceOobe(base::Bind(
192 &QuirksManager::OnDaysSinceOobeReceived, weak_ptr_factory_.GetWeakPtr(),
193 product_id, on_request_finished));
194 return;
195 }
196
197 const base::TimeDelta time_since =
198 base::Time::Now() - base::Time::FromDoubleT(last_check);
199
200 // Don't need server check if we've checked within last 30 days.
201 if (time_since < base::TimeDelta::FromDays(kDaysBetweenServerChecks)) {
202 VLOG(2) << time_since.InDays()
203 << " days since last Quirks Server check for display "
204 << IdToHexString(product_id);
205 on_request_finished.Run(base::FilePath(), false);
206 return;
207 }
208
209 CreateClient(product_id, on_request_finished);
210 }
211
212 void QuirksManager::OnDaysSinceOobeReceived(
213 int64_t product_id,
214 const RequestFinishedCallback& on_request_finished,
215 int days_since_oobe) {
216 DCHECK(thread_checker_.CalledOnValidThread());
217 // On newer devices, we want to check server immediately (after OOBE/login).
218 if (days_since_oobe <= kDaysBetweenServerChecks) {
219 CreateClient(product_id, on_request_finished);
220 return;
221 }
222
223 // Otherwise, for the first check on an older device, we want to stagger
224 // it over 30 days, so artificially set last check accordingly.
225 // TODO(glevin): I believe that it makes sense to remove this random delay
226 // in the next Chrome release.
227 const int rand_days = base::RandInt(0, kDaysBetweenServerChecks);
228 const base::Time fake_last_check =
229 base::Time::Now() - base::TimeDelta::FromDays(rand_days);
230 SetLastServerCheck(product_id, fake_last_check);
231 VLOG(2) << "Delaying first Quirks Server check by "
232 << kDaysBetweenServerChecks - rand_days << " days.";
233
234 on_request_finished.Run(base::FilePath(), false);
235 }
236
237 void QuirksManager::CreateClient(
238 int64_t product_id,
239 const RequestFinishedCallback& on_request_finished) {
240 DCHECK(thread_checker_.CalledOnValidThread());
241 QuirksClient* client =
242 new QuirksClient(product_id, on_request_finished, this);
243 clients_.insert(make_scoped_ptr(client));
244 if (!waiting_for_login_)
245 client->StartDownload();
246 else
247 VLOG(2) << "Quirks Client created; waiting for login to begin download.";
248 }
249
250 void QuirksManager::SetLastServerCheck(int64_t product_id,
251 const base::Time& last_check) {
252 DCHECK(thread_checker_.CalledOnValidThread());
253 DictionaryPrefUpdate dict(local_state_, prefs::kQuirksClientLastServerCheck);
254 dict->SetDouble(IdToHexString(product_id), last_check.ToDoubleT());
255 }
256
257 } // namespace quirks
OLDNEW
« no previous file with comments | « components/quirks/quirks_manager.h ('k') | components/quirks/switches.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698