Don't preload rarely seen large images
[chromium-blink-merge.git] / chromeos / dbus / update_engine_client.cc
blobf77c5de41dcdf5913500b68439d97b0420d36d66
1 // Copyright (c) 2012 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.
5 #include "chromeos/dbus/update_engine_client.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/location.h"
12 #include "base/macros.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/string_util.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chromeos/chromeos_switches.h"
17 #include "dbus/bus.h"
18 #include "dbus/message.h"
19 #include "dbus/object_path.h"
20 #include "dbus/object_proxy.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
23 namespace chromeos {
25 namespace {
27 const char kReleaseChannelDev[] = "dev-channel";
28 const char kReleaseChannelBeta[] = "beta-channel";
29 const char kReleaseChannelStable[] = "stable-channel";
31 // List of release channels ordered by stability.
32 const char* kReleaseChannelsList[] = {kReleaseChannelDev,
33 kReleaseChannelBeta,
34 kReleaseChannelStable};
36 // Delay between successive state transitions during AU.
37 const int kStateTransitionDefaultDelayMs = 3000;
39 // Delay between successive notifications about downloading progress
40 // during fake AU.
41 const int kStateTransitionDownloadingDelayMs = 250;
43 // Size of parts of a "new" image which are downloaded each
44 // |kStateTransitionDownloadingDelayMs| during fake AU.
45 const int64_t kDownloadSizeDelta = 1 << 19;
47 // Returns UPDATE_STATUS_ERROR on error.
48 UpdateEngineClient::UpdateStatusOperation UpdateStatusFromString(
49 const std::string& str) {
50 VLOG(1) << "UpdateStatusFromString got " << str << " as input.";
51 if (str == update_engine::kUpdateStatusIdle)
52 return UpdateEngineClient::UPDATE_STATUS_IDLE;
53 if (str == update_engine::kUpdateStatusCheckingForUpdate)
54 return UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE;
55 if (str == update_engine::kUpdateStatusUpdateAvailable)
56 return UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE;
57 if (str == update_engine::kUpdateStatusDownloading)
58 return UpdateEngineClient::UPDATE_STATUS_DOWNLOADING;
59 if (str == update_engine::kUpdateStatusVerifying)
60 return UpdateEngineClient::UPDATE_STATUS_VERIFYING;
61 if (str == update_engine::kUpdateStatusFinalizing)
62 return UpdateEngineClient::UPDATE_STATUS_FINALIZING;
63 if (str == update_engine::kUpdateStatusUpdatedNeedReboot)
64 return UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT;
65 if (str == update_engine::kUpdateStatusReportingErrorEvent)
66 return UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT;
67 if (str == update_engine::kUpdateStatusAttemptingRollback)
68 return UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK;
69 return UpdateEngineClient::UPDATE_STATUS_ERROR;
72 // Used in UpdateEngineClient::EmptyUpdateCheckCallback().
73 void EmptyUpdateCheckCallbackBody(
74 UpdateEngineClient::UpdateCheckResult unused_result) {
77 bool IsValidChannel(const std::string& channel) {
78 return channel == kReleaseChannelDev || channel == kReleaseChannelBeta ||
79 channel == kReleaseChannelStable;
82 } // namespace
84 // The UpdateEngineClient implementation used in production.
85 class UpdateEngineClientImpl : public UpdateEngineClient {
86 public:
87 UpdateEngineClientImpl()
88 : update_engine_proxy_(NULL), last_status_(), weak_ptr_factory_(this) {}
90 ~UpdateEngineClientImpl() override {}
92 // UpdateEngineClient implementation:
93 void AddObserver(Observer* observer) override {
94 observers_.AddObserver(observer);
97 void RemoveObserver(Observer* observer) override {
98 observers_.RemoveObserver(observer);
101 bool HasObserver(const Observer* observer) const override {
102 return observers_.HasObserver(observer);
105 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
106 dbus::MethodCall method_call(
107 update_engine::kUpdateEngineInterface,
108 update_engine::kAttemptUpdate);
109 dbus::MessageWriter writer(&method_call);
110 writer.AppendString(""); // Unused.
111 writer.AppendString(""); // Unused.
113 VLOG(1) << "Requesting an update check";
114 update_engine_proxy_->CallMethod(
115 &method_call,
116 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
117 base::Bind(&UpdateEngineClientImpl::OnRequestUpdateCheck,
118 weak_ptr_factory_.GetWeakPtr(),
119 callback));
122 void RebootAfterUpdate() override {
123 dbus::MethodCall method_call(
124 update_engine::kUpdateEngineInterface,
125 update_engine::kRebootIfNeeded);
127 VLOG(1) << "Requesting a reboot";
128 update_engine_proxy_->CallMethod(
129 &method_call,
130 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
131 base::Bind(&UpdateEngineClientImpl::OnRebootAfterUpdate,
132 weak_ptr_factory_.GetWeakPtr()));
135 void Rollback() override {
136 VLOG(1) << "Requesting a rollback";
137 dbus::MethodCall method_call(
138 update_engine::kUpdateEngineInterface,
139 update_engine::kAttemptRollback);
140 dbus::MessageWriter writer(&method_call);
141 writer.AppendBool(true /* powerwash */);
143 update_engine_proxy_->CallMethod(
144 &method_call,
145 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
146 base::Bind(&UpdateEngineClientImpl::OnRollback,
147 weak_ptr_factory_.GetWeakPtr()));
150 void CanRollbackCheck(const RollbackCheckCallback& callback) override {
151 dbus::MethodCall method_call(
152 update_engine::kUpdateEngineInterface,
153 update_engine::kCanRollback);
155 VLOG(1) << "Requesting to get rollback availability status";
156 update_engine_proxy_->CallMethod(
157 &method_call,
158 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
159 base::Bind(&UpdateEngineClientImpl::OnCanRollbackCheck,
160 weak_ptr_factory_.GetWeakPtr(),
161 callback));
164 Status GetLastStatus() override { return last_status_; }
166 void SetChannel(const std::string& target_channel,
167 bool is_powerwash_allowed) override {
168 if (!IsValidChannel(target_channel)) {
169 LOG(ERROR) << "Invalid channel name: " << target_channel;
170 return;
173 dbus::MethodCall method_call(
174 update_engine::kUpdateEngineInterface,
175 update_engine::kSetChannel);
176 dbus::MessageWriter writer(&method_call);
177 writer.AppendString(target_channel);
178 writer.AppendBool(is_powerwash_allowed);
180 VLOG(1) << "Requesting to set channel: "
181 << "target_channel=" << target_channel << ", "
182 << "is_powerwash_allowed=" << is_powerwash_allowed;
183 update_engine_proxy_->CallMethod(
184 &method_call,
185 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
186 base::Bind(&UpdateEngineClientImpl::OnSetChannel,
187 weak_ptr_factory_.GetWeakPtr()));
190 void GetChannel(bool get_current_channel,
191 const GetChannelCallback& callback) override {
192 dbus::MethodCall method_call(
193 update_engine::kUpdateEngineInterface,
194 update_engine::kGetChannel);
195 dbus::MessageWriter writer(&method_call);
196 writer.AppendBool(get_current_channel);
198 VLOG(1) << "Requesting to get channel, get_current_channel="
199 << get_current_channel;
200 update_engine_proxy_->CallMethod(
201 &method_call,
202 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
203 base::Bind(&UpdateEngineClientImpl::OnGetChannel,
204 weak_ptr_factory_.GetWeakPtr(),
205 callback));
208 protected:
209 void Init(dbus::Bus* bus) override {
210 update_engine_proxy_ = bus->GetObjectProxy(
211 update_engine::kUpdateEngineServiceName,
212 dbus::ObjectPath(update_engine::kUpdateEngineServicePath));
214 // Monitor the D-Bus signal for brightness changes. Only the power
215 // manager knows the actual brightness level. We don't cache the
216 // brightness level in Chrome as it will make things less reliable.
217 update_engine_proxy_->ConnectToSignal(
218 update_engine::kUpdateEngineInterface,
219 update_engine::kStatusUpdate,
220 base::Bind(&UpdateEngineClientImpl::StatusUpdateReceived,
221 weak_ptr_factory_.GetWeakPtr()),
222 base::Bind(&UpdateEngineClientImpl::StatusUpdateConnected,
223 weak_ptr_factory_.GetWeakPtr()));
225 // Get update engine status for the initial status. Update engine won't
226 // send StatusUpdate signal unless there is a status change. If chrome
227 // crashes after UPDATE_STATUS_UPDATED_NEED_REBOOT status is set,
228 // restarted chrome would not get this status. See crbug.com/154104.
229 GetUpdateEngineStatus();
232 private:
233 void GetUpdateEngineStatus() {
234 dbus::MethodCall method_call(
235 update_engine::kUpdateEngineInterface,
236 update_engine::kGetStatus);
237 update_engine_proxy_->CallMethodWithErrorCallback(
238 &method_call,
239 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
240 base::Bind(&UpdateEngineClientImpl::OnGetStatus,
241 weak_ptr_factory_.GetWeakPtr()),
242 base::Bind(&UpdateEngineClientImpl::OnGetStatusError,
243 weak_ptr_factory_.GetWeakPtr()));
246 // Called when a response for RequestUpdateCheck() is received.
247 void OnRequestUpdateCheck(const UpdateCheckCallback& callback,
248 dbus::Response* response) {
249 if (!response) {
250 LOG(ERROR) << "Failed to request update check";
251 callback.Run(UPDATE_RESULT_FAILED);
252 return;
254 callback.Run(UPDATE_RESULT_SUCCESS);
257 // Called when a response for RebootAfterUpdate() is received.
258 void OnRebootAfterUpdate(dbus::Response* response) {
259 if (!response) {
260 LOG(ERROR) << "Failed to request rebooting after update";
261 return;
265 // Called when a response for Rollback() is received.
266 void OnRollback(dbus::Response* response) {
267 if (!response) {
268 LOG(ERROR) << "Failed to rollback";
269 return;
273 // Called when a response for CanRollbackCheck() is received.
274 void OnCanRollbackCheck(const RollbackCheckCallback& callback,
275 dbus::Response* response) {
276 if (!response) {
277 LOG(ERROR) << "Failed to request rollback availability status";
278 callback.Run(false);
279 return;
281 dbus::MessageReader reader(response);
282 bool can_rollback;
283 if (!reader.PopBool(&can_rollback)) {
284 LOG(ERROR) << "Incorrect response: " << response->ToString();
285 callback.Run(false);
286 return;
288 VLOG(1) << "Rollback availability status received: " << can_rollback;
289 callback.Run(can_rollback);
292 // Called when a response for GetStatus is received.
293 void OnGetStatus(dbus::Response* response) {
294 if (!response) {
295 LOG(ERROR) << "Failed to get response for GetStatus request.";
296 return;
299 dbus::MessageReader reader(response);
300 std::string current_operation;
301 Status status;
302 if (!(reader.PopInt64(&status.last_checked_time) &&
303 reader.PopDouble(&status.download_progress) &&
304 reader.PopString(&current_operation) &&
305 reader.PopString(&status.new_version) &&
306 reader.PopInt64(&status.new_size))) {
307 LOG(ERROR) << "GetStatus had incorrect response: "
308 << response->ToString();
309 return;
311 status.status = UpdateStatusFromString(current_operation);
312 last_status_ = status;
313 FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(status));
316 // Called when GetStatus call failed.
317 void OnGetStatusError(dbus::ErrorResponse* error) {
318 LOG(ERROR) << "GetStatus request failed with error: "
319 << (error ? error->ToString() : "");
322 // Called when a response for SetReleaseChannel() is received.
323 void OnSetChannel(dbus::Response* response) {
324 if (!response) {
325 LOG(ERROR) << "Failed to request setting channel";
326 return;
328 VLOG(1) << "Succeeded to set channel";
331 // Called when a response for GetChannel() is received.
332 void OnGetChannel(const GetChannelCallback& callback,
333 dbus::Response* response) {
334 if (!response) {
335 LOG(ERROR) << "Failed to request getting channel";
336 callback.Run("");
337 return;
339 dbus::MessageReader reader(response);
340 std::string channel;
341 if (!reader.PopString(&channel)) {
342 LOG(ERROR) << "Incorrect response: " << response->ToString();
343 callback.Run("");
344 return;
346 VLOG(1) << "The channel received: " << channel;
347 callback.Run(channel);
350 // Called when a status update signal is received.
351 void StatusUpdateReceived(dbus::Signal* signal) {
352 VLOG(1) << "Status update signal received: " << signal->ToString();
353 dbus::MessageReader reader(signal);
354 int64 last_checked_time = 0;
355 double progress = 0.0;
356 std::string current_operation;
357 std::string new_version;
358 int64_t new_size = 0;
359 if (!(reader.PopInt64(&last_checked_time) &&
360 reader.PopDouble(&progress) &&
361 reader.PopString(&current_operation) &&
362 reader.PopString(&new_version) &&
363 reader.PopInt64(&new_size))) {
364 LOG(ERROR) << "Status changed signal had incorrect parameters: "
365 << signal->ToString();
366 return;
368 Status status;
369 status.last_checked_time = last_checked_time;
370 status.download_progress = progress;
371 status.status = UpdateStatusFromString(current_operation);
372 status.new_version = new_version;
373 status.new_size = new_size;
375 last_status_ = status;
376 FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(status));
379 // Called when the status update signal is initially connected.
380 void StatusUpdateConnected(const std::string& interface_name,
381 const std::string& signal_name,
382 bool success) {
383 LOG_IF(WARNING, !success)
384 << "Failed to connect to status updated signal.";
387 dbus::ObjectProxy* update_engine_proxy_;
388 base::ObserverList<Observer> observers_;
389 Status last_status_;
391 // Note: This should remain the last member so it'll be destroyed and
392 // invalidate its weak pointers before any other members are destroyed.
393 base::WeakPtrFactory<UpdateEngineClientImpl> weak_ptr_factory_;
395 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl);
398 // The UpdateEngineClient implementation used on Linux desktop,
399 // which does nothing.
400 class UpdateEngineClientStubImpl : public UpdateEngineClient {
401 public:
402 UpdateEngineClientStubImpl()
403 : current_channel_(kReleaseChannelBeta),
404 target_channel_(kReleaseChannelBeta) {}
406 // UpdateEngineClient implementation:
407 void Init(dbus::Bus* bus) override {}
408 void AddObserver(Observer* observer) override {}
409 void RemoveObserver(Observer* observer) override {}
410 bool HasObserver(const Observer* observer) const override { return false; }
412 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
413 callback.Run(UPDATE_RESULT_NOTIMPLEMENTED);
415 void RebootAfterUpdate() override {}
416 void Rollback() override {}
417 void CanRollbackCheck(const RollbackCheckCallback& callback) override {
418 callback.Run(true);
420 Status GetLastStatus() override { return Status(); }
421 void SetChannel(const std::string& target_channel,
422 bool is_powerwash_allowed) override {
423 VLOG(1) << "Requesting to set channel: "
424 << "target_channel=" << target_channel << ", "
425 << "is_powerwash_allowed=" << is_powerwash_allowed;
426 target_channel_ = target_channel;
428 void GetChannel(bool get_current_channel,
429 const GetChannelCallback& callback) override {
430 VLOG(1) << "Requesting to get channel, get_current_channel="
431 << get_current_channel;
432 if (get_current_channel)
433 callback.Run(current_channel_);
434 else
435 callback.Run(target_channel_);
438 std::string current_channel_;
439 std::string target_channel_;
442 // The UpdateEngineClient implementation used on Linux desktop, which
443 // tries to emulate real update engine client.
444 class UpdateEngineClientFakeImpl : public UpdateEngineClientStubImpl {
445 public:
446 UpdateEngineClientFakeImpl() : weak_factory_(this) {
449 ~UpdateEngineClientFakeImpl() override {}
451 // UpdateEngineClient implementation:
452 void AddObserver(Observer* observer) override {
453 if (observer)
454 observers_.AddObserver(observer);
457 void RemoveObserver(Observer* observer) override {
458 if (observer)
459 observers_.RemoveObserver(observer);
462 bool HasObserver(const Observer* observer) const override {
463 return observers_.HasObserver(observer);
466 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
467 if (last_status_.status != UPDATE_STATUS_IDLE) {
468 callback.Run(UPDATE_RESULT_FAILED);
469 return;
471 callback.Run(UPDATE_RESULT_SUCCESS);
472 last_status_.status = UPDATE_STATUS_CHECKING_FOR_UPDATE;
473 last_status_.download_progress = 0.0;
474 last_status_.last_checked_time = 0;
475 last_status_.new_size = 0;
476 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
477 FROM_HERE, base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
478 weak_factory_.GetWeakPtr()),
479 base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs));
482 Status GetLastStatus() override { return last_status_; }
484 private:
485 void StateTransition() {
486 UpdateStatusOperation next_status = UPDATE_STATUS_ERROR;
487 int delay_ms = kStateTransitionDefaultDelayMs;
488 switch (last_status_.status) {
489 case UPDATE_STATUS_ERROR:
490 case UPDATE_STATUS_IDLE:
491 case UPDATE_STATUS_UPDATED_NEED_REBOOT:
492 case UPDATE_STATUS_REPORTING_ERROR_EVENT:
493 case UPDATE_STATUS_ATTEMPTING_ROLLBACK:
494 return;
495 case UPDATE_STATUS_CHECKING_FOR_UPDATE:
496 next_status = UPDATE_STATUS_UPDATE_AVAILABLE;
497 break;
498 case UPDATE_STATUS_UPDATE_AVAILABLE:
499 next_status = UPDATE_STATUS_DOWNLOADING;
500 break;
501 case UPDATE_STATUS_DOWNLOADING:
502 if (last_status_.download_progress >= 1.0) {
503 next_status = UPDATE_STATUS_VERIFYING;
504 } else {
505 next_status = UPDATE_STATUS_DOWNLOADING;
506 last_status_.download_progress += 0.01;
507 last_status_.new_size = kDownloadSizeDelta;
508 delay_ms = kStateTransitionDownloadingDelayMs;
510 break;
511 case UPDATE_STATUS_VERIFYING:
512 next_status = UPDATE_STATUS_FINALIZING;
513 break;
514 case UPDATE_STATUS_FINALIZING:
515 next_status = UPDATE_STATUS_IDLE;
516 break;
518 last_status_.status = next_status;
519 FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(last_status_));
520 if (last_status_.status != UPDATE_STATUS_IDLE) {
521 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
522 FROM_HERE, base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
523 weak_factory_.GetWeakPtr()),
524 base::TimeDelta::FromMilliseconds(delay_ms));
528 base::ObserverList<Observer> observers_;
529 Status last_status_;
531 base::WeakPtrFactory<UpdateEngineClientFakeImpl> weak_factory_;
533 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientFakeImpl);
536 UpdateEngineClient::UpdateEngineClient() {
539 UpdateEngineClient::~UpdateEngineClient() {
542 // static
543 UpdateEngineClient::UpdateCheckCallback
544 UpdateEngineClient::EmptyUpdateCheckCallback() {
545 return base::Bind(&EmptyUpdateCheckCallbackBody);
548 // static
549 UpdateEngineClient* UpdateEngineClient::Create(
550 DBusClientImplementationType type) {
551 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
552 return new UpdateEngineClientImpl();
553 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
554 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
555 switches::kTestAutoUpdateUI))
556 return new UpdateEngineClientFakeImpl();
557 else
558 return new UpdateEngineClientStubImpl();
561 // static
562 bool UpdateEngineClient::IsTargetChannelMoreStable(
563 const std::string& current_channel,
564 const std::string& target_channel) {
565 auto cix = std::find(kReleaseChannelsList,
566 kReleaseChannelsList + arraysize(kReleaseChannelsList),
567 current_channel);
568 auto tix = std::find(kReleaseChannelsList,
569 kReleaseChannelsList + arraysize(kReleaseChannelsList),
570 target_channel);
571 return tix > cix;
574 } // namespace chromeos