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

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

Powered by Google App Engine
This is Rietveld 408576698