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

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: Sixth round of review fixes, sorting out thread issues Created 4 years, 10 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 "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/format_macros.h"
10 #include "base/path_service.h"
11 #include "base/rand_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "components/prefs/pref_registry_simple.h"
15 #include "components/prefs/scoped_user_pref_update.h"
16 #include "components/quirks/pref_names.h"
17 #include "components/quirks/switches.h"
18 #include "net/url_request/url_fetcher.h"
19 #include "net/url_request/url_request_context_getter.h"
20 #include "url/gurl.h"
21
22 namespace quirks {
23
24 namespace {
25
26 QuirksManager* g_manager = nullptr;
27
28 const char kIccExtension[] = ".icc";
29
30 // How often we query Quirks Server.
31 const int kDaysBetweenServerChecks = 30;
32
33 // Check if file exists, VLOG results.
34 bool CheckAndLogFile(const base::FilePath& path) {
35 const bool exists = base::PathExists(path);
36 VLOG(1) << (exists ? "File" : "No File") << " found at " << path.value();
37 // TODO(glevin): If file exists, do we want to implement a hash to verify that
38 // the file hasn't been corrupted or tampered with?
39 return exists;
40 }
41
42 } // namespace
43
44 std::string IdToHexString(int64_t product_id) {
45 return base::StringPrintf("%08" PRIx64, product_id);
46 }
47
48 std::string IdToFileName(int64_t product_id) {
49 return IdToHexString(product_id).append(kIccExtension);
50 }
51
52 // Must be called on file thread.
53 base::FilePath RequestIccProfilePath(
54 int64_t product_id,
55 const DownloadFinishedCallback& on_download_finished) {
56 if (g_manager)
57 return g_manager->RequestIccFilePath(product_id, on_download_finished);
58
59 VLOG(1) << "Quirks Client Manager not initialized; can't get icc file.";
60 return base::FilePath();
61 }
62
63 ////////////////////////////////////////////////////////////////////////////////
64 // QuirksManager
65
66 QuirksManager::QuirksManager(
67 Delegate* delegate,
68 scoped_refptr<base::SequencedWorkerPool> blocking_pool,
69 PrefService* local_state,
70 scoped_refptr<net::URLRequestContextGetter> url_context_getter)
71 : delegate_(delegate),
72 blocking_pool_(blocking_pool),
73 local_state_(local_state),
74 url_context_getter_(url_context_getter),
75 client_task_runner_(base::ThreadTaskRunnerHandle::Get()),
76 is_new_device_(false),
77 weak_ptr_factory_(this) {}
78
79 QuirksManager::~QuirksManager() {
80 clients_.clear();
81 g_manager = nullptr;
82 }
83
84 // static
85 void QuirksManager::Initialize(
86 scoped_ptr<Delegate> delegate,
87 scoped_refptr<base::SequencedWorkerPool> blocking_pool,
88 PrefService* local_state,
89 scoped_refptr<net::URLRequestContextGetter> url_context_getter) {
90 g_manager = new QuirksManager(delegate.release(), blocking_pool, local_state,
91 url_context_getter);
92 }
93
94 // static
95 void QuirksManager::Shutdown() {
96 delete g_manager;
97 }
98
99 // static
100 QuirksManager* QuirksManager::Get() {
101 DCHECK(g_manager);
102 return g_manager;
103 }
104
105 // static
106 void QuirksManager::RegisterPrefs(PrefRegistrySimple* registry) {
107 registry->RegisterDictionaryPref(prefs::kQuirksClientLastServerCheck);
108 }
109
110 base::FilePath QuirksManager::RequestIccFilePath(
111 int64_t product_id,
112 const DownloadFinishedCallback& on_download_finished) {
113 DCHECK(blocking_pool()->RunsTasksOnCurrentThread());
114
115 // First, look for icc file in old read-only location. If there, we don't use
116 // the Quirks server.
117 // TODO(glevin): Awaiting final decision on how to handle old read-only files.
118 base::FilePath path = delegate_->GetBuiltInDisplayProfileDirectory().Append(
119 IdToFileName(product_id));
120 if (CheckAndLogFile(path))
121 return path;
122
123 // If experimental Quirks flag isn't set, no other icc file is available.
124 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
125 switches::kEnableDisplayQuirksClient)) {
126 VLOG(1) << "Quirks Client disabled, no built-in icc file available.";
127 return base::FilePath();
128 }
129
130 // Check if QuirksClient has already downloaded icc file from server.
131 path = delegate_->GetDownloadDisplayProfileDirectory().Append(
132 IdToFileName(product_id));
133 if (CheckAndLogFile(path))
134 return path;
135
136 // TODO(glevin): Eventually we'll want to check the server for updates to
137 // files, so we'll still want to get down here even if we find the icc file.
138
139 // Record this on file thread for future use on client task runner.
140 is_new_device_ = (delegate_->GetDaysSinceOobe() <= kDaysBetweenServerChecks);
141
142 client_task_runner_->PostTask(
143 FROM_HERE, base::Bind(&QuirksManager::RunClientOnTaskRunner,
144 weak_ptr_factory_.GetWeakPtr(), product_id,
145 on_download_finished));
146
147 return base::FilePath();
148 }
149
150 void QuirksManager::ClientFinished(QuirksClient* client) {
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 DCHECK(it != clients_.end());
157 if (it != clients_.end())
158 clients_.erase(it);
159 }
160
161 // TODO(glevin): Add code to record UMA stats here. Also need to set
162 // request_reason_ in QuirksClient.
163 void QuirksManager::RecordReasonUmaStat(QuirksClient::RequestReason reason) {}
164
165 void QuirksManager::RecordFileFoundUmaStat(bool success) {}
166
167 scoped_ptr<net::URLFetcher> QuirksManager::CreateURLFetcher(
168 const std::string& url,
169 net::URLFetcherDelegate* delegate) {
170 if (!fake_quirks_fetcher_creator_.is_null())
171 return fake_quirks_fetcher_creator_.Run(GURL(url), delegate);
172
173 return net::URLFetcher::Create(GURL(url), net::URLFetcher::GET, delegate);
174 }
175
176 bool QuirksManager::NeedToCheckServer(int64_t product_id) {
177 DCHECK(base::ThreadTaskRunnerHandle::IsSet());
178 double last_check = 0.0;
179 local_state_->GetDictionary(prefs::kQuirksClientLastServerCheck)
180 ->GetDouble(IdToHexString(product_id), &last_check);
181
182 if (last_check != 0.0) {
183 const base::TimeDelta time_since =
184 base::Time::Now() - base::Time::FromDoubleT(last_check);
185
186 // Don't need server check if we've checked within last 30 days.
187 if (time_since < base::TimeDelta::FromDays(kDaysBetweenServerChecks)) {
188 VLOG(2) << time_since.InDays()
189 << " days since last Quirks Server check for display "
190 << IdToHexString(product_id);
191 return false;
192 }
193
194 return true;
195 }
196
197 // On new devices, we want to check server immediately.
198 if (is_new_device_)
199 return true;
200
201 // Otherwise, for the first check on an older device, we want to stagger
202 // it over 30 days, so artificially set last check accordingly.
203 const int rand_days = base::RandInt(0, kDaysBetweenServerChecks);
204 const base::Time fake_last_check =
205 base::Time::Now() - base::TimeDelta::FromDays(rand_days);
206 SetLastServerCheck(product_id, fake_last_check);
207 VLOG(2) << "Delaying first Quirks Server check by "
208 << kDaysBetweenServerChecks - rand_days << " days.";
209 return false;
210 }
211
212 void QuirksManager::SetLastServerCheck(int64_t product_id,
213 const base::Time& last_check) {
214 DCHECK(base::ThreadTaskRunnerHandle::IsSet());
215 DictionaryPrefUpdate dict(local_state_, prefs::kQuirksClientLastServerCheck);
216 dict->SetDouble(IdToHexString(product_id), last_check.ToDoubleT());
217 }
218
219 // Initializes QuirksClient object on client task runner, where most of its work
220 // needs to be done.
221 void QuirksManager::RunClientOnTaskRunner(
222 int64_t product_id,
223 const DownloadFinishedCallback& on_download_finished) {
224 DCHECK(base::ThreadTaskRunnerHandle::IsSet());
225 if (!ValidateOnTaskRunner()) {
226 VLOG(1) << "Quirks Manager not correctly initialized.";
227 return;
228 }
229
230 if (!NeedToCheckServer(product_id))
231 return;
232
233 QuirksClient* client =
234 new QuirksClient(product_id, on_download_finished, this);
235 clients_.insert(make_scoped_ptr(client));
236 client->StartDownload();
237 }
238
239 bool QuirksManager::ValidateOnTaskRunner() {
240 return base::ThreadTaskRunnerHandle::IsSet() &&
241 local_state_->CalledOnValidThread() &&
242 client_task_runner_->RunsTasksOnCurrentThread();
243 }
244
245 } // namespace quirks
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698