Revert of Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320) (patchset...
[chromium-blink-merge.git] / chromeos / dbus / update_engine_client.cc
blob31b9366cfbc67a571b5bcf8b62cadbf5b90f2b4a
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/macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/string_util.h"
14 #include "chromeos/chromeos_switches.h"
15 #include "dbus/bus.h"
16 #include "dbus/message.h"
17 #include "dbus/object_path.h"
18 #include "dbus/object_proxy.h"
19 #include "third_party/cros_system_api/dbus/service_constants.h"
21 namespace chromeos {
23 namespace {
25 const char kReleaseChannelDev[] = "dev-channel";
26 const char kReleaseChannelBeta[] = "beta-channel";
27 const char kReleaseChannelStable[] = "stable-channel";
29 // List of release channels ordered by stability.
30 const char* kReleaseChannelsList[] = {kReleaseChannelDev,
31 kReleaseChannelBeta,
32 kReleaseChannelStable};
34 // Delay between successive state transitions during AU.
35 const int kStateTransitionDefaultDelayMs = 3000;
37 // Delay between successive notifications about downloading progress
38 // during fake AU.
39 const int kStateTransitionDownloadingDelayMs = 250;
41 // Size of parts of a "new" image which are downloaded each
42 // |kStateTransitionDownloadingDelayMs| during fake AU.
43 const int64_t kDownloadSizeDelta = 1 << 19;
45 // Returns UPDATE_STATUS_ERROR on error.
46 UpdateEngineClient::UpdateStatusOperation UpdateStatusFromString(
47 const std::string& str) {
48 VLOG(1) << "UpdateStatusFromString got " << str << " as input.";
49 if (str == update_engine::kUpdateStatusIdle)
50 return UpdateEngineClient::UPDATE_STATUS_IDLE;
51 if (str == update_engine::kUpdateStatusCheckingForUpdate)
52 return UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE;
53 if (str == update_engine::kUpdateStatusUpdateAvailable)
54 return UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE;
55 if (str == update_engine::kUpdateStatusDownloading)
56 return UpdateEngineClient::UPDATE_STATUS_DOWNLOADING;
57 if (str == update_engine::kUpdateStatusVerifying)
58 return UpdateEngineClient::UPDATE_STATUS_VERIFYING;
59 if (str == update_engine::kUpdateStatusFinalizing)
60 return UpdateEngineClient::UPDATE_STATUS_FINALIZING;
61 if (str == update_engine::kUpdateStatusUpdatedNeedReboot)
62 return UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT;
63 if (str == update_engine::kUpdateStatusReportingErrorEvent)
64 return UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT;
65 if (str == update_engine::kUpdateStatusAttemptingRollback)
66 return UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK;
67 return UpdateEngineClient::UPDATE_STATUS_ERROR;
70 // Used in UpdateEngineClient::EmptyUpdateCheckCallback().
71 void EmptyUpdateCheckCallbackBody(
72 UpdateEngineClient::UpdateCheckResult unused_result) {
75 bool IsValidChannel(const std::string& channel) {
76 return channel == kReleaseChannelDev || channel == kReleaseChannelBeta ||
77 channel == kReleaseChannelStable;
80 } // namespace
82 // The UpdateEngineClient implementation used in production.
83 class UpdateEngineClientImpl : public UpdateEngineClient {
84 public:
85 UpdateEngineClientImpl()
86 : update_engine_proxy_(NULL), last_status_(), weak_ptr_factory_(this) {}
88 ~UpdateEngineClientImpl() override {}
90 // UpdateEngineClient implementation:
91 void AddObserver(Observer* observer) override {
92 observers_.AddObserver(observer);
95 void RemoveObserver(Observer* observer) override {
96 observers_.RemoveObserver(observer);
99 bool HasObserver(const Observer* observer) const override {
100 return observers_.HasObserver(observer);
103 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
104 dbus::MethodCall method_call(
105 update_engine::kUpdateEngineInterface,
106 update_engine::kAttemptUpdate);
107 dbus::MessageWriter writer(&method_call);
108 writer.AppendString(""); // Unused.
109 writer.AppendString(""); // Unused.
111 VLOG(1) << "Requesting an update check";
112 update_engine_proxy_->CallMethod(
113 &method_call,
114 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
115 base::Bind(&UpdateEngineClientImpl::OnRequestUpdateCheck,
116 weak_ptr_factory_.GetWeakPtr(),
117 callback));
120 void RebootAfterUpdate() override {
121 dbus::MethodCall method_call(
122 update_engine::kUpdateEngineInterface,
123 update_engine::kRebootIfNeeded);
125 VLOG(1) << "Requesting a reboot";
126 update_engine_proxy_->CallMethod(
127 &method_call,
128 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
129 base::Bind(&UpdateEngineClientImpl::OnRebootAfterUpdate,
130 weak_ptr_factory_.GetWeakPtr()));
133 void Rollback() override {
134 VLOG(1) << "Requesting a rollback";
135 dbus::MethodCall method_call(
136 update_engine::kUpdateEngineInterface,
137 update_engine::kAttemptRollback);
138 dbus::MessageWriter writer(&method_call);
139 writer.AppendBool(true /* powerwash */);
141 update_engine_proxy_->CallMethod(
142 &method_call,
143 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
144 base::Bind(&UpdateEngineClientImpl::OnRollback,
145 weak_ptr_factory_.GetWeakPtr()));
148 void CanRollbackCheck(const RollbackCheckCallback& callback) override {
149 dbus::MethodCall method_call(
150 update_engine::kUpdateEngineInterface,
151 update_engine::kCanRollback);
153 VLOG(1) << "Requesting to get rollback availability status";
154 update_engine_proxy_->CallMethod(
155 &method_call,
156 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
157 base::Bind(&UpdateEngineClientImpl::OnCanRollbackCheck,
158 weak_ptr_factory_.GetWeakPtr(),
159 callback));
162 Status GetLastStatus() override { return last_status_; }
164 void SetChannel(const std::string& target_channel,
165 bool is_powerwash_allowed) override {
166 if (!IsValidChannel(target_channel)) {
167 LOG(ERROR) << "Invalid channel name: " << target_channel;
168 return;
171 dbus::MethodCall method_call(
172 update_engine::kUpdateEngineInterface,
173 update_engine::kSetChannel);
174 dbus::MessageWriter writer(&method_call);
175 writer.AppendString(target_channel);
176 writer.AppendBool(is_powerwash_allowed);
178 VLOG(1) << "Requesting to set channel: "
179 << "target_channel=" << target_channel << ", "
180 << "is_powerwash_allowed=" << is_powerwash_allowed;
181 update_engine_proxy_->CallMethod(
182 &method_call,
183 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
184 base::Bind(&UpdateEngineClientImpl::OnSetChannel,
185 weak_ptr_factory_.GetWeakPtr()));
188 void GetChannel(bool get_current_channel,
189 const GetChannelCallback& callback) override {
190 dbus::MethodCall method_call(
191 update_engine::kUpdateEngineInterface,
192 update_engine::kGetChannel);
193 dbus::MessageWriter writer(&method_call);
194 writer.AppendBool(get_current_channel);
196 VLOG(1) << "Requesting to get channel, get_current_channel="
197 << get_current_channel;
198 update_engine_proxy_->CallMethod(
199 &method_call,
200 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
201 base::Bind(&UpdateEngineClientImpl::OnGetChannel,
202 weak_ptr_factory_.GetWeakPtr(),
203 callback));
206 protected:
207 void Init(dbus::Bus* bus) override {
208 update_engine_proxy_ = bus->GetObjectProxy(
209 update_engine::kUpdateEngineServiceName,
210 dbus::ObjectPath(update_engine::kUpdateEngineServicePath));
212 // Monitor the D-Bus signal for brightness changes. Only the power
213 // manager knows the actual brightness level. We don't cache the
214 // brightness level in Chrome as it will make things less reliable.
215 update_engine_proxy_->ConnectToSignal(
216 update_engine::kUpdateEngineInterface,
217 update_engine::kStatusUpdate,
218 base::Bind(&UpdateEngineClientImpl::StatusUpdateReceived,
219 weak_ptr_factory_.GetWeakPtr()),
220 base::Bind(&UpdateEngineClientImpl::StatusUpdateConnected,
221 weak_ptr_factory_.GetWeakPtr()));
223 // Get update engine status for the initial status. Update engine won't
224 // send StatusUpdate signal unless there is a status change. If chrome
225 // crashes after UPDATE_STATUS_UPDATED_NEED_REBOOT status is set,
226 // restarted chrome would not get this status. See crbug.com/154104.
227 GetUpdateEngineStatus();
230 private:
231 void GetUpdateEngineStatus() {
232 dbus::MethodCall method_call(
233 update_engine::kUpdateEngineInterface,
234 update_engine::kGetStatus);
235 update_engine_proxy_->CallMethodWithErrorCallback(
236 &method_call,
237 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
238 base::Bind(&UpdateEngineClientImpl::OnGetStatus,
239 weak_ptr_factory_.GetWeakPtr()),
240 base::Bind(&UpdateEngineClientImpl::OnGetStatusError,
241 weak_ptr_factory_.GetWeakPtr()));
244 // Called when a response for RequestUpdateCheck() is received.
245 void OnRequestUpdateCheck(const UpdateCheckCallback& callback,
246 dbus::Response* response) {
247 if (!response) {
248 LOG(ERROR) << "Failed to request update check";
249 callback.Run(UPDATE_RESULT_FAILED);
250 return;
252 callback.Run(UPDATE_RESULT_SUCCESS);
255 // Called when a response for RebootAfterUpdate() is received.
256 void OnRebootAfterUpdate(dbus::Response* response) {
257 if (!response) {
258 LOG(ERROR) << "Failed to request rebooting after update";
259 return;
263 // Called when a response for Rollback() is received.
264 void OnRollback(dbus::Response* response) {
265 if (!response) {
266 LOG(ERROR) << "Failed to rollback";
267 return;
271 // Called when a response for CanRollbackCheck() is received.
272 void OnCanRollbackCheck(const RollbackCheckCallback& callback,
273 dbus::Response* response) {
274 if (!response) {
275 LOG(ERROR) << "Failed to request rollback availability status";
276 callback.Run(false);
277 return;
279 dbus::MessageReader reader(response);
280 bool can_rollback;
281 if (!reader.PopBool(&can_rollback)) {
282 LOG(ERROR) << "Incorrect response: " << response->ToString();
283 callback.Run(false);
284 return;
286 VLOG(1) << "Rollback availability status received: " << can_rollback;
287 callback.Run(can_rollback);
290 // Called when a response for GetStatus is received.
291 void OnGetStatus(dbus::Response* response) {
292 if (!response) {
293 LOG(ERROR) << "Failed to get response for GetStatus request.";
294 return;
297 dbus::MessageReader reader(response);
298 std::string current_operation;
299 Status status;
300 if (!(reader.PopInt64(&status.last_checked_time) &&
301 reader.PopDouble(&status.download_progress) &&
302 reader.PopString(&current_operation) &&
303 reader.PopString(&status.new_version) &&
304 reader.PopInt64(&status.new_size))) {
305 LOG(ERROR) << "GetStatus had incorrect response: "
306 << response->ToString();
307 return;
309 status.status = UpdateStatusFromString(current_operation);
310 last_status_ = status;
311 FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(status));
314 // Called when GetStatus call failed.
315 void OnGetStatusError(dbus::ErrorResponse* error) {
316 LOG(ERROR) << "GetStatus request failed with error: "
317 << (error ? error->ToString() : "");
320 // Called when a response for SetReleaseChannel() is received.
321 void OnSetChannel(dbus::Response* response) {
322 if (!response) {
323 LOG(ERROR) << "Failed to request setting channel";
324 return;
326 VLOG(1) << "Succeeded to set channel";
329 // Called when a response for GetChannel() is received.
330 void OnGetChannel(const GetChannelCallback& callback,
331 dbus::Response* response) {
332 if (!response) {
333 LOG(ERROR) << "Failed to request getting channel";
334 callback.Run("");
335 return;
337 dbus::MessageReader reader(response);
338 std::string channel;
339 if (!reader.PopString(&channel)) {
340 LOG(ERROR) << "Incorrect response: " << response->ToString();
341 callback.Run("");
342 return;
344 VLOG(1) << "The channel received: " << channel;
345 callback.Run(channel);
348 // Called when a status update signal is received.
349 void StatusUpdateReceived(dbus::Signal* signal) {
350 VLOG(1) << "Status update signal received: " << signal->ToString();
351 dbus::MessageReader reader(signal);
352 int64 last_checked_time = 0;
353 double progress = 0.0;
354 std::string current_operation;
355 std::string new_version;
356 int64_t new_size = 0;
357 if (!(reader.PopInt64(&last_checked_time) &&
358 reader.PopDouble(&progress) &&
359 reader.PopString(&current_operation) &&
360 reader.PopString(&new_version) &&
361 reader.PopInt64(&new_size))) {
362 LOG(ERROR) << "Status changed signal had incorrect parameters: "
363 << signal->ToString();
364 return;
366 Status status;
367 status.last_checked_time = last_checked_time;
368 status.download_progress = progress;
369 status.status = UpdateStatusFromString(current_operation);
370 status.new_version = new_version;
371 status.new_size = new_size;
373 last_status_ = status;
374 FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(status));
377 // Called when the status update signal is initially connected.
378 void StatusUpdateConnected(const std::string& interface_name,
379 const std::string& signal_name,
380 bool success) {
381 LOG_IF(WARNING, !success)
382 << "Failed to connect to status updated signal.";
385 dbus::ObjectProxy* update_engine_proxy_;
386 ObserverList<Observer> observers_;
387 Status last_status_;
389 // Note: This should remain the last member so it'll be destroyed and
390 // invalidate its weak pointers before any other members are destroyed.
391 base::WeakPtrFactory<UpdateEngineClientImpl> weak_ptr_factory_;
393 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl);
396 // The UpdateEngineClient implementation used on Linux desktop,
397 // which does nothing.
398 class UpdateEngineClientStubImpl : public UpdateEngineClient {
399 public:
400 UpdateEngineClientStubImpl()
401 : current_channel_(kReleaseChannelBeta),
402 target_channel_(kReleaseChannelBeta) {}
404 // UpdateEngineClient implementation:
405 void Init(dbus::Bus* bus) override {}
406 void AddObserver(Observer* observer) override {}
407 void RemoveObserver(Observer* observer) override {}
408 bool HasObserver(const Observer* observer) const override { return false; }
410 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
411 callback.Run(UPDATE_RESULT_NOTIMPLEMENTED);
413 void RebootAfterUpdate() override {}
414 void Rollback() override {}
415 void CanRollbackCheck(const RollbackCheckCallback& callback) override {
416 callback.Run(true);
418 Status GetLastStatus() override { return Status(); }
419 void SetChannel(const std::string& target_channel,
420 bool is_powerwash_allowed) override {
421 VLOG(1) << "Requesting to set channel: "
422 << "target_channel=" << target_channel << ", "
423 << "is_powerwash_allowed=" << is_powerwash_allowed;
424 target_channel_ = target_channel;
426 void GetChannel(bool get_current_channel,
427 const GetChannelCallback& callback) override {
428 VLOG(1) << "Requesting to get channel, get_current_channel="
429 << get_current_channel;
430 if (get_current_channel)
431 callback.Run(current_channel_);
432 else
433 callback.Run(target_channel_);
436 std::string current_channel_;
437 std::string target_channel_;
440 // The UpdateEngineClient implementation used on Linux desktop, which
441 // tries to emulate real update engine client.
442 class UpdateEngineClientFakeImpl : public UpdateEngineClientStubImpl {
443 public:
444 UpdateEngineClientFakeImpl() : weak_factory_(this) {
447 ~UpdateEngineClientFakeImpl() override {}
449 // UpdateEngineClient implementation:
450 void AddObserver(Observer* observer) override {
451 if (observer)
452 observers_.AddObserver(observer);
455 void RemoveObserver(Observer* observer) override {
456 if (observer)
457 observers_.RemoveObserver(observer);
460 bool HasObserver(const Observer* observer) const override {
461 return observers_.HasObserver(observer);
464 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
465 if (last_status_.status != UPDATE_STATUS_IDLE) {
466 callback.Run(UPDATE_RESULT_FAILED);
467 return;
469 callback.Run(UPDATE_RESULT_SUCCESS);
470 last_status_.status = UPDATE_STATUS_CHECKING_FOR_UPDATE;
471 last_status_.download_progress = 0.0;
472 last_status_.last_checked_time = 0;
473 last_status_.new_size = 0;
474 base::MessageLoop::current()->PostDelayedTask(
475 FROM_HERE,
476 base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
477 weak_factory_.GetWeakPtr()),
478 base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs));
481 Status GetLastStatus() override { return last_status_; }
483 private:
484 void StateTransition() {
485 UpdateStatusOperation next_status = UPDATE_STATUS_ERROR;
486 int delay_ms = kStateTransitionDefaultDelayMs;
487 switch (last_status_.status) {
488 case UPDATE_STATUS_ERROR:
489 case UPDATE_STATUS_IDLE:
490 case UPDATE_STATUS_UPDATED_NEED_REBOOT:
491 case UPDATE_STATUS_REPORTING_ERROR_EVENT:
492 case UPDATE_STATUS_ATTEMPTING_ROLLBACK:
493 return;
494 case UPDATE_STATUS_CHECKING_FOR_UPDATE:
495 next_status = UPDATE_STATUS_UPDATE_AVAILABLE;
496 break;
497 case UPDATE_STATUS_UPDATE_AVAILABLE:
498 next_status = UPDATE_STATUS_DOWNLOADING;
499 break;
500 case UPDATE_STATUS_DOWNLOADING:
501 if (last_status_.download_progress >= 1.0) {
502 next_status = UPDATE_STATUS_VERIFYING;
503 } else {
504 next_status = UPDATE_STATUS_DOWNLOADING;
505 last_status_.download_progress += 0.01;
506 last_status_.new_size = kDownloadSizeDelta;
507 delay_ms = kStateTransitionDownloadingDelayMs;
509 break;
510 case UPDATE_STATUS_VERIFYING:
511 next_status = UPDATE_STATUS_FINALIZING;
512 break;
513 case UPDATE_STATUS_FINALIZING:
514 next_status = UPDATE_STATUS_IDLE;
515 break;
517 last_status_.status = next_status;
518 FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(last_status_));
519 if (last_status_.status != UPDATE_STATUS_IDLE) {
520 base::MessageLoop::current()->PostDelayedTask(
521 FROM_HERE,
522 base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
523 weak_factory_.GetWeakPtr()),
524 base::TimeDelta::FromMilliseconds(delay_ms));
528 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