OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/update_client/update_engine.h" | 5 #include "components/update_client/update_engine.h" |
6 | 6 |
| 7 #include <utility> |
| 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
9 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/memory/ptr_util.h" |
10 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
11 #include "base/threading/thread_task_runner_handle.h" | 15 #include "base/threading/thread_task_runner_handle.h" |
12 #include "base/time/time.h" | |
13 #include "components/prefs/pref_service.h" | 16 #include "components/prefs/pref_service.h" |
14 #include "components/update_client/action_update_check.h" | 17 #include "components/update_client/component.h" |
15 #include "components/update_client/configurator.h" | 18 #include "components/update_client/configurator.h" |
16 #include "components/update_client/crx_update_item.h" | 19 #include "components/update_client/crx_update_item.h" |
17 #include "components/update_client/persisted_data.h" | 20 #include "components/update_client/persisted_data.h" |
18 #include "components/update_client/update_checker.h" | 21 #include "components/update_client/update_checker.h" |
19 #include "components/update_client/update_client_errors.h" | 22 #include "components/update_client/update_client_errors.h" |
| 23 #include "components/update_client/utils.h" |
20 | 24 |
21 namespace update_client { | 25 namespace update_client { |
22 | 26 |
23 UpdateContext::UpdateContext( | 27 UpdateContext::UpdateContext( |
24 const scoped_refptr<Configurator>& config, | 28 const scoped_refptr<Configurator>& config, |
25 bool is_foreground, | 29 bool is_foreground, |
26 const std::vector<std::string>& ids, | 30 const std::vector<std::string>& ids, |
27 const UpdateClient::CrxDataCallback& crx_data_callback, | 31 const UpdateClient::CrxDataCallback& crx_data_callback, |
28 const UpdateEngine::NotifyObserversCallback& notify_observers_callback, | 32 const UpdateEngine::NotifyObserversCallback& notify_observers_callback, |
29 const UpdateEngine::Callback& callback, | 33 const UpdateEngine::Callback& callback, |
30 UpdateChecker::Factory update_checker_factory, | 34 CrxDownloader::Factory crx_downloader_factory) |
31 CrxDownloader::Factory crx_downloader_factory, | |
32 PingManager* ping_manager) | |
33 : config(config), | 35 : config(config), |
34 is_foreground(is_foreground), | 36 is_foreground(is_foreground), |
35 enabled_component_updates(config->EnabledComponentUpdates()), | 37 enabled_component_updates(config->EnabledComponentUpdates()), |
36 ids(ids), | 38 ids(ids), |
37 crx_data_callback(crx_data_callback), | 39 crx_data_callback(crx_data_callback), |
38 notify_observers_callback(notify_observers_callback), | 40 notify_observers_callback(notify_observers_callback), |
39 callback(callback), | 41 callback(callback), |
40 main_task_runner(base::ThreadTaskRunnerHandle::Get()), | |
41 blocking_task_runner(config->GetSequencedTaskRunner()), | 42 blocking_task_runner(config->GetSequencedTaskRunner()), |
42 update_checker_factory(update_checker_factory), | 43 crx_downloader_factory(crx_downloader_factory) { |
43 crx_downloader_factory(crx_downloader_factory), | 44 for (const auto& id : ids) |
44 ping_manager(ping_manager), | 45 components.insert( |
45 retry_after_sec(0) {} | 46 std::make_pair(id, base::MakeUnique<Component>(*this, id))); |
| 47 } |
46 | 48 |
47 UpdateContext::~UpdateContext() {} | 49 UpdateContext::~UpdateContext() {} |
48 | 50 |
49 UpdateEngine::UpdateEngine( | 51 UpdateEngine::UpdateEngine( |
50 const scoped_refptr<Configurator>& config, | 52 const scoped_refptr<Configurator>& config, |
51 UpdateChecker::Factory update_checker_factory, | 53 UpdateChecker::Factory update_checker_factory, |
52 CrxDownloader::Factory crx_downloader_factory, | 54 CrxDownloader::Factory crx_downloader_factory, |
53 PingManager* ping_manager, | 55 PingManager* ping_manager, |
54 const NotifyObserversCallback& notify_observers_callback) | 56 const NotifyObserversCallback& notify_observers_callback) |
55 : config_(config), | 57 : config_(config), |
56 update_checker_factory_(update_checker_factory), | 58 update_checker_factory_(update_checker_factory), |
57 crx_downloader_factory_(crx_downloader_factory), | 59 crx_downloader_factory_(crx_downloader_factory), |
58 ping_manager_(ping_manager), | 60 ping_manager_(ping_manager), |
59 metadata_(new PersistedData(config->GetPrefService())), | 61 metadata_(new PersistedData(config->GetPrefService())), |
60 notify_observers_callback_(notify_observers_callback) {} | 62 notify_observers_callback_(notify_observers_callback) {} |
61 | 63 |
62 UpdateEngine::~UpdateEngine() { | 64 UpdateEngine::~UpdateEngine() { |
63 DCHECK(thread_checker_.CalledOnValidThread()); | 65 DCHECK(thread_checker_.CalledOnValidThread()); |
64 } | 66 } |
65 | 67 |
66 bool UpdateEngine::GetUpdateState(const std::string& id, | |
67 CrxUpdateItem* update_item) { | |
68 DCHECK(thread_checker_.CalledOnValidThread()); | |
69 for (const auto* context : update_contexts_) { | |
70 const auto& update_items = context->update_items; | |
71 const auto it = update_items.find(id); | |
72 if (it != update_items.end()) { | |
73 *update_item = *it->second.get(); | |
74 return true; | |
75 } | |
76 } | |
77 return false; | |
78 } | |
79 | |
80 void UpdateEngine::Update( | 68 void UpdateEngine::Update( |
81 bool is_foreground, | 69 bool is_foreground, |
82 const std::vector<std::string>& ids, | 70 const std::vector<std::string>& ids, |
83 const UpdateClient::CrxDataCallback& crx_data_callback, | 71 const UpdateClient::CrxDataCallback& crx_data_callback, |
84 const Callback& callback) { | 72 const Callback& callback) { |
85 DCHECK(thread_checker_.CalledOnValidThread()); | 73 DCHECK(thread_checker_.CalledOnValidThread()); |
86 | 74 |
87 if (IsThrottled(is_foreground)) { | 75 if (IsThrottled(is_foreground)) { |
88 base::ThreadTaskRunnerHandle::Get()->PostTask( | 76 base::ThreadTaskRunnerHandle::Get()->PostTask( |
89 FROM_HERE, base::Bind(callback, Error::RETRY_LATER)); | 77 FROM_HERE, base::Bind(callback, Error::RETRY_LATER)); |
90 return; | 78 return; |
91 } | 79 } |
92 | 80 |
93 std::unique_ptr<UpdateContext> update_context(new UpdateContext( | 81 const auto result = update_contexts_.insert(base::MakeUnique<UpdateContext>( |
94 config_, is_foreground, ids, crx_data_callback, | 82 config_, is_foreground, ids, crx_data_callback, |
95 notify_observers_callback_, callback, update_checker_factory_, | 83 notify_observers_callback_, callback, crx_downloader_factory_)); |
96 crx_downloader_factory_, ping_manager_)); | |
97 | 84 |
98 std::unique_ptr<ActionUpdateCheck> update_check_action(new ActionUpdateCheck( | 85 DCHECK(result.second); |
99 (*update_context->update_checker_factory)(config_, metadata_.get()), | |
100 config_->GetBrowserVersion(), config_->ExtraRequestParams())); | |
101 | 86 |
102 update_context->current_action = std::move(update_check_action); | 87 const auto& it = result.first; |
103 update_contexts_.insert(update_context.get()); | 88 const auto& update_context = *it; |
| 89 DCHECK(update_context); |
104 | 90 |
105 update_context->current_action->Run( | 91 // Calls out to get the corresponding CrxComponent data for the CRXs in this |
106 update_context.get(), | 92 // update context. |
107 base::Bind(&UpdateEngine::UpdateComplete, base::Unretained(this), | 93 DCHECK_EQ(ids.size(), update_context->ids.size()); |
108 update_context.get())); | 94 DCHECK_EQ(update_context->ids.size(), update_context->components.size()); |
| 95 std::vector<CrxComponent> crx_components; |
| 96 update_context->crx_data_callback.Run(update_context->ids, &crx_components); |
| 97 DCHECK_EQ(update_context->ids.size(), crx_components.size()); |
109 | 98 |
110 ignore_result(update_context.release()); | 99 for (size_t i = 0; i != update_context->ids.size(); ++i) { |
| 100 const auto& id = update_context->ids[i]; |
| 101 const auto& crx_component = crx_components[i]; |
| 102 |
| 103 DCHECK_EQ(id, GetCrxComponentID(crx_component)); |
| 104 DCHECK_EQ(1u, update_context->components.count(id)); |
| 105 DCHECK(update_context->components.at(id)); |
| 106 |
| 107 auto& component = *update_context->components.at(id); |
| 108 component.set_on_demand(update_context->is_foreground); |
| 109 component.set_crx_component(crx_component); |
| 110 component.set_previous_version(crx_component.version); |
| 111 component.set_previous_fp(crx_component.fingerprint); |
| 112 |
| 113 // Handle |kNew| state. This will transition the components to |kChecking|. |
| 114 component.Handle(base::Bind(&UpdateEngine::ComponentCheckingForUpdatesStart, |
| 115 base::Unretained(this), it, |
| 116 base::ConstRef(component))); |
| 117 } |
111 } | 118 } |
112 | 119 |
113 void UpdateEngine::UpdateComplete(UpdateContext* update_context, Error error) { | 120 void UpdateEngine::ComponentCheckingForUpdatesStart( |
| 121 const UpdateContextIterator& it, |
| 122 const Component& component) { |
114 DCHECK(thread_checker_.CalledOnValidThread()); | 123 DCHECK(thread_checker_.CalledOnValidThread()); |
115 DCHECK(update_contexts_.find(update_context) != update_contexts_.end()); | 124 |
| 125 const auto& update_context = *it; |
| 126 DCHECK(update_context); |
| 127 |
| 128 const auto id = component.id(); |
| 129 DCHECK_EQ(1u, update_context->components.count(id)); |
| 130 DCHECK(update_context->components.at(id)); |
| 131 |
| 132 // Handle |kChecking| state. |
| 133 auto& mutable_component = *update_context->components.at(id); |
| 134 mutable_component.Handle(base::Bind( |
| 135 &UpdateEngine::ComponentCheckingForUpdatesComplete, |
| 136 base::Unretained(this), it, base::ConstRef(mutable_component))); |
| 137 |
| 138 ++update_context->num_components_ready_to_check; |
| 139 if (update_context->num_components_ready_to_check < |
| 140 update_context->ids.size()) { |
| 141 return; |
| 142 } |
| 143 |
| 144 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 145 FROM_HERE, |
| 146 base::Bind(&UpdateEngine::DoUpdateCheck, base::Unretained(this), it)); |
| 147 } |
| 148 |
| 149 void UpdateEngine::DoUpdateCheck(const UpdateContextIterator& it) { |
| 150 DCHECK(thread_checker_.CalledOnValidThread()); |
| 151 |
| 152 auto& update_context = *it; |
| 153 DCHECK(update_context); |
| 154 |
| 155 update_context->update_checker = |
| 156 update_checker_factory_(config_, metadata_.get()); |
| 157 |
| 158 update_context->update_checker->CheckForUpdates( |
| 159 update_context->ids, update_context->components, |
| 160 config_->ExtraRequestParams(), update_context->enabled_component_updates, |
| 161 base::Bind(&UpdateEngine::UpdateCheckDone, base::Unretained(this), it)); |
| 162 } |
| 163 |
| 164 void UpdateEngine::UpdateCheckDone(const UpdateContextIterator& it, |
| 165 int error, |
| 166 int retry_after_sec) { |
| 167 DCHECK(thread_checker_.CalledOnValidThread()); |
| 168 |
| 169 auto& update_context = *it; |
| 170 DCHECK(update_context); |
| 171 |
| 172 update_context->retry_after_sec = retry_after_sec; |
116 | 173 |
117 const int throttle_sec(update_context->retry_after_sec); | 174 const int throttle_sec(update_context->retry_after_sec); |
118 DCHECK_LE(throttle_sec, 24 * 60 * 60); | 175 DCHECK_LE(throttle_sec, 24 * 60 * 60); |
119 | 176 |
120 // Only positive values for throttle_sec are effective. 0 means that no | 177 // Only positive values for throttle_sec are effective. 0 means that no |
121 // throttling occurs and has the effect of resetting the member. | 178 // throttling occurs and has the effect of resetting the member. |
122 // Negative values are not trusted and are ignored. | 179 // Negative values are not trusted and are ignored. |
123 if (throttle_sec >= 0) | 180 if (throttle_sec >= 0) { |
124 throttle_updates_until_ = | 181 throttle_updates_until_ = |
125 throttle_sec | 182 throttle_sec ? base::TimeTicks::Now() + |
126 ? base::TimeTicks::Now() + | 183 base::TimeDelta::FromSeconds(throttle_sec) |
127 base::TimeDelta::FromSeconds(throttle_sec) | 184 : base::TimeTicks(); |
128 : base::TimeTicks(); | 185 } |
129 | 186 |
130 auto callback = update_context->callback; | 187 update_context->update_check_error = error; |
131 | 188 |
132 update_contexts_.erase(update_context); | 189 for (const auto& id : update_context->ids) { |
133 delete update_context; | 190 DCHECK_EQ(1u, update_context->components.count(id)); |
| 191 DCHECK(update_context->components.at(id)); |
134 | 192 |
135 callback.Run(error); | 193 auto& component = *update_context->components.at(id); |
| 194 component.UpdateCheckComplete(); |
| 195 } |
| 196 } |
| 197 |
| 198 void UpdateEngine::ComponentCheckingForUpdatesComplete( |
| 199 const UpdateContextIterator& it, |
| 200 const Component& component) { |
| 201 DCHECK(thread_checker_.CalledOnValidThread()); |
| 202 |
| 203 const auto& update_context = *it; |
| 204 DCHECK(update_context); |
| 205 |
| 206 ++update_context->num_components_checked; |
| 207 if (update_context->num_components_checked < update_context->ids.size()) { |
| 208 return; |
| 209 } |
| 210 |
| 211 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 212 FROM_HERE, base::Bind(&UpdateEngine::UpdateCheckComplete, |
| 213 base::Unretained(this), it)); |
| 214 } |
| 215 |
| 216 void UpdateEngine::UpdateCheckComplete(const UpdateContextIterator& it) { |
| 217 DCHECK(thread_checker_.CalledOnValidThread()); |
| 218 |
| 219 const auto& update_context = *it; |
| 220 DCHECK(update_context); |
| 221 |
| 222 if (update_context->update_check_error) { |
| 223 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 224 FROM_HERE, |
| 225 base::Bind(&UpdateEngine::UpdateComplete, base::Unretained(this), it, |
| 226 Error::UPDATE_CHECK_ERROR)); |
| 227 return; |
| 228 } |
| 229 |
| 230 for (const auto& id : update_context->ids) |
| 231 update_context->component_queue.push(id); |
| 232 |
| 233 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 234 FROM_HERE, |
| 235 base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it)); |
| 236 } |
| 237 |
| 238 void UpdateEngine::HandleComponent(const UpdateContextIterator& it) { |
| 239 DCHECK(thread_checker_.CalledOnValidThread()); |
| 240 |
| 241 auto& update_context = *it; |
| 242 DCHECK(update_context); |
| 243 |
| 244 auto& queue = update_context->component_queue; |
| 245 |
| 246 if (queue.empty()) { |
| 247 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 248 FROM_HERE, base::Bind(&UpdateEngine::UpdateComplete, |
| 249 base::Unretained(this), it, Error::NONE)); |
| 250 return; |
| 251 } |
| 252 |
| 253 const auto& id = queue.front(); |
| 254 DCHECK_EQ(1u, update_context->components.count(id)); |
| 255 const auto& component = update_context->components.at(id); |
| 256 DCHECK(component); |
| 257 |
| 258 auto& next_update_delay = (*it)->next_update_delay; |
| 259 if (!next_update_delay.is_zero() && component->IsUpdateAvailable()) { |
| 260 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 261 FROM_HERE, |
| 262 base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it), |
| 263 next_update_delay); |
| 264 |
| 265 next_update_delay = base::TimeDelta(); |
| 266 |
| 267 notify_observers_callback_.Run( |
| 268 UpdateClient::Observer::Events::COMPONENT_WAIT, id); |
| 269 return; |
| 270 } |
| 271 |
| 272 component->Handle(base::Bind(&UpdateEngine::HandleComponentComplete, |
| 273 base::Unretained(this), it)); |
| 274 } |
| 275 |
| 276 void UpdateEngine::HandleComponentComplete(const UpdateContextIterator& it) { |
| 277 DCHECK(thread_checker_.CalledOnValidThread()); |
| 278 |
| 279 auto& update_context = *it; |
| 280 DCHECK(update_context); |
| 281 |
| 282 auto& queue = update_context->component_queue; |
| 283 DCHECK(!queue.empty()); |
| 284 |
| 285 const auto& id = queue.front(); |
| 286 DCHECK_EQ(1u, update_context->components.count(id)); |
| 287 const auto& component = update_context->components.at(id); |
| 288 DCHECK(component); |
| 289 |
| 290 if (component->IsHandled()) { |
| 291 (*it)->next_update_delay = component->GetUpdateDuration(); |
| 292 |
| 293 // Only ping when the server response included an update for this component. |
| 294 if (component->CanPing()) { |
| 295 ping_manager_->SendPing(*component); |
| 296 } |
| 297 |
| 298 queue.pop(); |
| 299 } |
| 300 |
| 301 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 302 FROM_HERE, |
| 303 base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it)); |
| 304 } |
| 305 |
| 306 void UpdateEngine::UpdateComplete(const UpdateContextIterator& it, |
| 307 Error error) { |
| 308 DCHECK(thread_checker_.CalledOnValidThread()); |
| 309 |
| 310 auto& update_context = *it; |
| 311 DCHECK(update_context); |
| 312 |
| 313 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 314 FROM_HERE, base::Bind(update_context->callback, error)); |
| 315 |
| 316 update_contexts_.erase(it); |
| 317 } |
| 318 |
| 319 bool UpdateEngine::GetUpdateState(const std::string& id, |
| 320 CrxUpdateItem* update_item) { |
| 321 DCHECK(thread_checker_.CalledOnValidThread()); |
| 322 for (const auto& context : update_contexts_) { |
| 323 const auto it = context->components.find(id); |
| 324 if (it != context->components.end()) { |
| 325 *update_item = it->second->GetCrxUpdateItem(); |
| 326 return true; |
| 327 } |
| 328 } |
| 329 return false; |
136 } | 330 } |
137 | 331 |
138 bool UpdateEngine::IsThrottled(bool is_foreground) const { | 332 bool UpdateEngine::IsThrottled(bool is_foreground) const { |
| 333 DCHECK(thread_checker_.CalledOnValidThread()); |
| 334 |
139 if (is_foreground || throttle_updates_until_.is_null()) | 335 if (is_foreground || throttle_updates_until_.is_null()) |
140 return false; | 336 return false; |
141 | 337 |
142 const auto now(base::TimeTicks::Now()); | 338 const auto now(base::TimeTicks::Now()); |
143 | 339 |
144 // Throttle the calls in the interval (t - 1 day, t) to limit the effect of | 340 // Throttle the calls in the interval (t - 1 day, t) to limit the effect of |
145 // unset clocks or clock drift. | 341 // unset clocks or clock drift. |
146 return throttle_updates_until_ - base::TimeDelta::FromDays(1) < now && | 342 return throttle_updates_until_ - base::TimeDelta::FromDays(1) < now && |
147 now < throttle_updates_until_; | 343 now < throttle_updates_until_; |
148 } | 344 } |
149 | 345 |
| 346 void UpdateEngine::SendUninstallPing(const std::string& id, |
| 347 const base::Version& version, |
| 348 int reason, |
| 349 const Callback& callback) { |
| 350 DCHECK(thread_checker_.CalledOnValidThread()); |
| 351 |
| 352 const auto result = update_contexts_.insert(base::MakeUnique<UpdateContext>( |
| 353 config_, false, std::vector<std::string>{id}, |
| 354 UpdateClient::CrxDataCallback(), UpdateEngine::NotifyObserversCallback(), |
| 355 callback, nullptr)); |
| 356 |
| 357 DCHECK(result.second); |
| 358 |
| 359 const auto& it = result.first; |
| 360 const auto& update_context = *it; |
| 361 DCHECK(update_context); |
| 362 DCHECK_EQ(1u, update_context->ids.size()); |
| 363 DCHECK_EQ(1u, update_context->components.count(id)); |
| 364 const auto& component = update_context->components.at(id); |
| 365 |
| 366 component->Uninstall(version, reason); |
| 367 |
| 368 update_context->component_queue.push(id); |
| 369 |
| 370 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 371 FROM_HERE, |
| 372 base::Bind(&UpdateEngine::HandleComponent, base::Unretained(this), it)); |
| 373 } |
| 374 |
150 } // namespace update_client | 375 } // namespace update_client |
OLD | NEW |