[Cleanup] Use EXPECT_FALSE and EXPECT_TRUE in place of EXPECT_EQ where appropriate.
[chromium-blink-merge.git] / chromeos / dbus / update_engine_client.cc
blob28d5b00de6a69a1d1cf3952470660eaff65968ed
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/callback.h"
11 #include "base/command_line.h"
12 #include "base/macros.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_util.h"
15 #include "chromeos/chromeos_switches.h"
16 #include "dbus/bus.h"
17 #include "dbus/message.h"
18 #include "dbus/object_path.h"
19 #include "dbus/object_proxy.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
22 namespace chromeos {
24 namespace {
26 const char kReleaseChannelDev[] = "dev-channel";
27 const char kReleaseChannelBeta[] = "beta-channel";
28 const char kReleaseChannelStable[] = "stable-channel";
30 // List of release channels ordered by stability.
31 const char* kReleaseChannelsList[] = {kReleaseChannelDev,
32 kReleaseChannelBeta,
33 kReleaseChannelStable};
35 // Delay between successive state transitions during AU.
36 const int kStateTransitionDefaultDelayMs = 3000;
38 // Delay between successive notifications about downloading progress
39 // during fake AU.
40 const int kStateTransitionDownloadingDelayMs = 250;
42 // Size of parts of a "new" image which are downloaded each
43 // |kStateTransitionDownloadingDelayMs| during fake AU.
44 const int64_t kDownloadSizeDelta = 1 << 19;
46 // Returns UPDATE_STATUS_ERROR on error.
47 UpdateEngineClient::UpdateStatusOperation UpdateStatusFromString(
48 const std::string& str) {
49 VLOG(1) << "UpdateStatusFromString got " << str << " as input.";
50 if (str == update_engine::kUpdateStatusIdle)
51 return UpdateEngineClient::UPDATE_STATUS_IDLE;
52 if (str == update_engine::kUpdateStatusCheckingForUpdate)
53 return UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE;
54 if (str == update_engine::kUpdateStatusUpdateAvailable)
55 return UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE;
56 if (str == update_engine::kUpdateStatusDownloading)
57 return UpdateEngineClient::UPDATE_STATUS_DOWNLOADING;
58 if (str == update_engine::kUpdateStatusVerifying)
59 return UpdateEngineClient::UPDATE_STATUS_VERIFYING;
60 if (str == update_engine::kUpdateStatusFinalizing)
61 return UpdateEngineClient::UPDATE_STATUS_FINALIZING;
62 if (str == update_engine::kUpdateStatusUpdatedNeedReboot)
63 return UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT;
64 if (str == update_engine::kUpdateStatusReportingErrorEvent)
65 return UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT;
66 if (str == update_engine::kUpdateStatusAttemptingRollback)
67 return UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK;
68 return UpdateEngineClient::UPDATE_STATUS_ERROR;
71 // Used in UpdateEngineClient::EmptyUpdateCheckCallback().
72 void EmptyUpdateCheckCallbackBody(
73 UpdateEngineClient::UpdateCheckResult unused_result) {
76 bool IsValidChannel(const std::string& channel) {
77 return channel == kReleaseChannelDev || channel == kReleaseChannelBeta ||
78 channel == kReleaseChannelStable;
81 } // namespace
83 // The UpdateEngineClient implementation used in production.
84 class UpdateEngineClientImpl : public UpdateEngineClient {
85 public:
86 UpdateEngineClientImpl()
87 : update_engine_proxy_(NULL), last_status_(), weak_ptr_factory_(this) {}
89 ~UpdateEngineClientImpl() override {}
91 // UpdateEngineClient implementation:
92 void AddObserver(Observer* observer) override {
93 observers_.AddObserver(observer);
96 void RemoveObserver(Observer* observer) override {
97 observers_.RemoveObserver(observer);
100 bool HasObserver(const Observer* observer) const override {
101 return observers_.HasObserver(observer);
104 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
105 dbus::MethodCall method_call(
106 update_engine::kUpdateEngineInterface,
107 update_engine::kAttemptUpdate);
108 dbus::MessageWriter writer(&method_call);
109 writer.AppendString(""); // Unused.
110 writer.AppendString(""); // Unused.
112 VLOG(1) << "Requesting an update check";
113 update_engine_proxy_->CallMethod(
114 &method_call,
115 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
116 base::Bind(&UpdateEngineClientImpl::OnRequestUpdateCheck,
117 weak_ptr_factory_.GetWeakPtr(),
118 callback));
121 void RebootAfterUpdate() override {
122 dbus::MethodCall method_call(
123 update_engine::kUpdateEngineInterface,
124 update_engine::kRebootIfNeeded);
126 VLOG(1) << "Requesting a reboot";
127 update_engine_proxy_->CallMethod(
128 &method_call,
129 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
130 base::Bind(&UpdateEngineClientImpl::OnRebootAfterUpdate,
131 weak_ptr_factory_.GetWeakPtr()));
134 void Rollback() override {
135 VLOG(1) << "Requesting a rollback";
136 dbus::MethodCall method_call(
137 update_engine::kUpdateEngineInterface,
138 update_engine::kAttemptRollback);
139 dbus::MessageWriter writer(&method_call);
140 writer.AppendBool(true /* powerwash */);
142 update_engine_proxy_->CallMethod(
143 &method_call,
144 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
145 base::Bind(&UpdateEngineClientImpl::OnRollback,
146 weak_ptr_factory_.GetWeakPtr()));
149 void CanRollbackCheck(const RollbackCheckCallback& callback) override {
150 dbus::MethodCall method_call(
151 update_engine::kUpdateEngineInterface,
152 update_engine::kCanRollback);
154 VLOG(1) << "Requesting to get rollback availability status";
155 update_engine_proxy_->CallMethod(
156 &method_call,
157 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
158 base::Bind(&UpdateEngineClientImpl::OnCanRollbackCheck,
159 weak_ptr_factory_.GetWeakPtr(),
160 callback));
163 Status GetLastStatus() override { return last_status_; }
165 void SetChannel(const std::string& target_channel,
166 bool is_powerwash_allowed) override {
167 if (!IsValidChannel(target_channel)) {
168 LOG(ERROR) << "Invalid channel name: " << target_channel;
169 return;
172 dbus::MethodCall method_call(
173 update_engine::kUpdateEngineInterface,
174 update_engine::kSetChannel);
175 dbus::MessageWriter writer(&method_call);
176 writer.AppendString(target_channel);
177 writer.AppendBool(is_powerwash_allowed);
179 VLOG(1) << "Requesting to set channel: "
180 << "target_channel=" << target_channel << ", "
181 << "is_powerwash_allowed=" << is_powerwash_allowed;
182 update_engine_proxy_->CallMethod(
183 &method_call,
184 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
185 base::Bind(&UpdateEngineClientImpl::OnSetChannel,
186 weak_ptr_factory_.GetWeakPtr()));
189 void GetChannel(bool get_current_channel,
190 const GetChannelCallback& callback) override {
191 dbus::MethodCall method_call(
192 update_engine::kUpdateEngineInterface,
193 update_engine::kGetChannel);
194 dbus::MessageWriter writer(&method_call);
195 writer.AppendBool(get_current_channel);
197 VLOG(1) << "Requesting to get channel, get_current_channel="
198 << get_current_channel;
199 update_engine_proxy_->CallMethod(
200 &method_call,
201 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
202 base::Bind(&UpdateEngineClientImpl::OnGetChannel,
203 weak_ptr_factory_.GetWeakPtr(),
204 callback));
207 protected:
208 void Init(dbus::Bus* bus) override {
209 update_engine_proxy_ = bus->GetObjectProxy(
210 update_engine::kUpdateEngineServiceName,
211 dbus::ObjectPath(update_engine::kUpdateEngineServicePath));
213 // Monitor the D-Bus signal for brightness changes. Only the power
214 // manager knows the actual brightness level. We don't cache the
215 // brightness level in Chrome as it will make things less reliable.
216 update_engine_proxy_->ConnectToSignal(
217 update_engine::kUpdateEngineInterface,
218 update_engine::kStatusUpdate,
219 base::Bind(&UpdateEngineClientImpl::StatusUpdateReceived,
220 weak_ptr_factory_.GetWeakPtr()),
221 base::Bind(&UpdateEngineClientImpl::StatusUpdateConnected,
222 weak_ptr_factory_.GetWeakPtr()));
224 // Get update engine status for the initial status. Update engine won't
225 // send StatusUpdate signal unless there is a status change. If chrome
226 // crashes after UPDATE_STATUS_UPDATED_NEED_REBOOT status is set,
227 // restarted chrome would not get this status. See crbug.com/154104.
228 GetUpdateEngineStatus();
231 private:
232 void GetUpdateEngineStatus() {
233 dbus::MethodCall method_call(
234 update_engine::kUpdateEngineInterface,
235 update_engine::kGetStatus);
236 update_engine_proxy_->CallMethodWithErrorCallback(
237 &method_call,
238 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
239 base::Bind(&UpdateEngineClientImpl::OnGetStatus,
240 weak_ptr_factory_.GetWeakPtr()),
241 base::Bind(&UpdateEngineClientImpl::OnGetStatusError,
242 weak_ptr_factory_.GetWeakPtr()));
245 // Called when a response for RequestUpdateCheck() is received.
246 void OnRequestUpdateCheck(const UpdateCheckCallback& callback,
247 dbus::Response* response) {
248 if (!response) {
249 LOG(ERROR) << "Failed to request update check";
250 callback.Run(UPDATE_RESULT_FAILED);
251 return;
253 callback.Run(UPDATE_RESULT_SUCCESS);
256 // Called when a response for RebootAfterUpdate() is received.
257 void OnRebootAfterUpdate(dbus::Response* response) {
258 if (!response) {
259 LOG(ERROR) << "Failed to request rebooting after update";
260 return;
264 // Called when a response for Rollback() is received.
265 void OnRollback(dbus::Response* response) {
266 if (!response) {
267 LOG(ERROR) << "Failed to rollback";
268 return;
272 // Called when a response for CanRollbackCheck() is received.
273 void OnCanRollbackCheck(const RollbackCheckCallback& callback,
274 dbus::Response* response) {
275 if (!response) {
276 LOG(ERROR) << "Failed to request rollback availability status";
277 callback.Run(false);
278 return;
280 dbus::MessageReader reader(response);
281 bool can_rollback;
282 if (!reader.PopBool(&can_rollback)) {
283 LOG(ERROR) << "Incorrect response: " << response->ToString();
284 callback.Run(false);
285 return;
287 VLOG(1) << "Rollback availability status received: " << can_rollback;
288 callback.Run(can_rollback);
291 // Called when a response for GetStatus is received.
292 void OnGetStatus(dbus::Response* response) {
293 if (!response) {
294 LOG(ERROR) << "Failed to get response for GetStatus request.";
295 return;
298 dbus::MessageReader reader(response);
299 std::string current_operation;
300 Status status;
301 if (!(reader.PopInt64(&status.last_checked_time) &&
302 reader.PopDouble(&status.download_progress) &&
303 reader.PopString(&current_operation) &&
304 reader.PopString(&status.new_version) &&
305 reader.PopInt64(&status.new_size))) {
306 LOG(ERROR) << "GetStatus had incorrect response: "
307 << response->ToString();
308 return;
310 status.status = UpdateStatusFromString(current_operation);
311 last_status_ = status;
312 FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(status));
315 // Called when GetStatus call failed.
316 void OnGetStatusError(dbus::ErrorResponse* error) {
317 LOG(ERROR) << "GetStatus request failed with error: "
318 << (error ? error->ToString() : "");
321 // Called when a response for SetReleaseChannel() is received.
322 void OnSetChannel(dbus::Response* response) {
323 if (!response) {
324 LOG(ERROR) << "Failed to request setting channel";
325 return;
327 VLOG(1) << "Succeeded to set channel";
330 // Called when a response for GetChannel() is received.
331 void OnGetChannel(const GetChannelCallback& callback,
332 dbus::Response* response) {
333 if (!response) {
334 LOG(ERROR) << "Failed to request getting channel";
335 callback.Run("");
336 return;
338 dbus::MessageReader reader(response);
339 std::string channel;
340 if (!reader.PopString(&channel)) {
341 LOG(ERROR) << "Incorrect response: " << response->ToString();
342 callback.Run("");
343 return;
345 VLOG(1) << "The channel received: " << channel;
346 callback.Run(channel);
349 // Called when a status update signal is received.
350 void StatusUpdateReceived(dbus::Signal* signal) {
351 VLOG(1) << "Status update signal received: " << signal->ToString();
352 dbus::MessageReader reader(signal);
353 int64 last_checked_time = 0;
354 double progress = 0.0;
355 std::string current_operation;
356 std::string new_version;
357 int64_t new_size = 0;
358 if (!(reader.PopInt64(&last_checked_time) &&
359 reader.PopDouble(&progress) &&
360 reader.PopString(&current_operation) &&
361 reader.PopString(&new_version) &&
362 reader.PopInt64(&new_size))) {
363 LOG(ERROR) << "Status changed signal had incorrect parameters: "
364 << signal->ToString();
365 return;
367 Status status;
368 status.last_checked_time = last_checked_time;
369 status.download_progress = progress;
370 status.status = UpdateStatusFromString(current_operation);
371 status.new_version = new_version;
372 status.new_size = new_size;
374 last_status_ = status;
375 FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(status));
378 // Called when the status update signal is initially connected.
379 void StatusUpdateConnected(const std::string& interface_name,
380 const std::string& signal_name,
381 bool success) {
382 LOG_IF(WARNING, !success)
383 << "Failed to connect to status updated signal.";
386 dbus::ObjectProxy* update_engine_proxy_;
387 ObserverList<Observer> observers_;
388 Status last_status_;
390 // Note: This should remain the last member so it'll be destroyed and
391 // invalidate its weak pointers before any other members are destroyed.
392 base::WeakPtrFactory<UpdateEngineClientImpl> weak_ptr_factory_;
394 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl);
397 // The UpdateEngineClient implementation used on Linux desktop,
398 // which does nothing.
399 class UpdateEngineClientStubImpl : public UpdateEngineClient {
400 public:
401 UpdateEngineClientStubImpl()
402 : current_channel_(kReleaseChannelBeta),
403 target_channel_(kReleaseChannelBeta) {}
405 // UpdateEngineClient implementation:
406 void Init(dbus::Bus* bus) override {}
407 void AddObserver(Observer* observer) override {}
408 void RemoveObserver(Observer* observer) override {}
409 bool HasObserver(const Observer* observer) const override { return false; }
411 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
412 callback.Run(UPDATE_RESULT_NOTIMPLEMENTED);
414 void RebootAfterUpdate() override {}
415 void Rollback() override {}
416 void CanRollbackCheck(const RollbackCheckCallback& callback) override {
417 callback.Run(true);
419 Status GetLastStatus() override { return Status(); }
420 void SetChannel(const std::string& target_channel,
421 bool is_powerwash_allowed) override {
422 VLOG(1) << "Requesting to set channel: "
423 << "target_channel=" << target_channel << ", "
424 << "is_powerwash_allowed=" << is_powerwash_allowed;
425 target_channel_ = target_channel;
427 void GetChannel(bool get_current_channel,
428 const GetChannelCallback& callback) override {
429 VLOG(1) << "Requesting to get channel, get_current_channel="
430 << get_current_channel;
431 if (get_current_channel)
432 callback.Run(current_channel_);
433 else
434 callback.Run(target_channel_);
437 std::string current_channel_;
438 std::string target_channel_;
441 // The UpdateEngineClient implementation used on Linux desktop, which
442 // tries to emulate real update engine client.
443 class UpdateEngineClientFakeImpl : public UpdateEngineClientStubImpl {
444 public:
445 UpdateEngineClientFakeImpl() : weak_factory_(this) {
448 ~UpdateEngineClientFakeImpl() override {}
450 // UpdateEngineClient implementation:
451 void AddObserver(Observer* observer) override {
452 if (observer)
453 observers_.AddObserver(observer);
456 void RemoveObserver(Observer* observer) override {
457 if (observer)
458 observers_.RemoveObserver(observer);
461 bool HasObserver(const Observer* observer) const override {
462 return observers_.HasObserver(observer);
465 void RequestUpdateCheck(const UpdateCheckCallback& callback) override {
466 if (last_status_.status != UPDATE_STATUS_IDLE) {
467 callback.Run(UPDATE_RESULT_FAILED);
468 return;
470 callback.Run(UPDATE_RESULT_SUCCESS);
471 last_status_.status = UPDATE_STATUS_CHECKING_FOR_UPDATE;
472 last_status_.download_progress = 0.0;
473 last_status_.last_checked_time = 0;
474 last_status_.new_size = 0;
475 base::MessageLoop::current()->PostDelayedTask(
476 FROM_HERE,
477 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::MessageLoop::current()->PostDelayedTask(
522 FROM_HERE,
523 base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
524 weak_factory_.GetWeakPtr()),
525 base::TimeDelta::FromMilliseconds(delay_ms));
529 ObserverList<Observer> observers_;
530 Status last_status_;
532 base::WeakPtrFactory<UpdateEngineClientFakeImpl> weak_factory_;
534 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientFakeImpl);
537 UpdateEngineClient::UpdateEngineClient() {
540 UpdateEngineClient::~UpdateEngineClient() {
543 // static
544 UpdateEngineClient::UpdateCheckCallback
545 UpdateEngineClient::EmptyUpdateCheckCallback() {
546 return base::Bind(&EmptyUpdateCheckCallbackBody);
549 // static
550 UpdateEngineClient* UpdateEngineClient::Create(
551 DBusClientImplementationType type) {
552 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
553 return new UpdateEngineClientImpl();
554 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
555 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
556 switches::kTestAutoUpdateUI))
557 return new UpdateEngineClientFakeImpl();
558 else
559 return new UpdateEngineClientStubImpl();
562 // static
563 bool UpdateEngineClient::IsTargetChannelMoreStable(
564 const std::string& current_channel,
565 const std::string& target_channel) {
566 auto cix = std::find(kReleaseChannelsList,
567 kReleaseChannelsList + arraysize(kReleaseChannelsList),
568 current_channel);
569 auto tix = std::find(kReleaseChannelsList,
570 kReleaseChannelsList + arraysize(kReleaseChannelsList),
571 target_channel);
572 return tix > cix;
575 } // namespace chromeos