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"
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"
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"
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
,
33 kReleaseChannelStable
};
35 // Delay between successive state transitions during AU.
36 const int kStateTransitionDefaultDelayMs
= 3000;
38 // Delay between successive notifications about downloading progress
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
;
83 // The UpdateEngineClient implementation used in production.
84 class UpdateEngineClientImpl
: public UpdateEngineClient
{
86 UpdateEngineClientImpl()
87 : update_engine_proxy_(NULL
), last_status_(), weak_ptr_factory_(this) {}
89 virtual ~UpdateEngineClientImpl() {
92 // UpdateEngineClient implementation:
93 virtual void AddObserver(Observer
* observer
) override
{
94 observers_
.AddObserver(observer
);
97 virtual void RemoveObserver(Observer
* observer
) override
{
98 observers_
.RemoveObserver(observer
);
101 virtual bool HasObserver(Observer
* observer
) override
{
102 return observers_
.HasObserver(observer
);
105 virtual void RequestUpdateCheck(
106 const UpdateCheckCallback
& callback
) override
{
107 dbus::MethodCall
method_call(
108 update_engine::kUpdateEngineInterface
,
109 update_engine::kAttemptUpdate
);
110 dbus::MessageWriter
writer(&method_call
);
111 writer
.AppendString(""); // Unused.
112 writer
.AppendString(""); // Unused.
114 VLOG(1) << "Requesting an update check";
115 update_engine_proxy_
->CallMethod(
117 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
118 base::Bind(&UpdateEngineClientImpl::OnRequestUpdateCheck
,
119 weak_ptr_factory_
.GetWeakPtr(),
123 virtual void RebootAfterUpdate() override
{
124 dbus::MethodCall
method_call(
125 update_engine::kUpdateEngineInterface
,
126 update_engine::kRebootIfNeeded
);
128 VLOG(1) << "Requesting a reboot";
129 update_engine_proxy_
->CallMethod(
131 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
132 base::Bind(&UpdateEngineClientImpl::OnRebootAfterUpdate
,
133 weak_ptr_factory_
.GetWeakPtr()));
136 virtual void Rollback() override
{
137 VLOG(1) << "Requesting a rollback";
138 dbus::MethodCall
method_call(
139 update_engine::kUpdateEngineInterface
,
140 update_engine::kAttemptRollback
);
141 dbus::MessageWriter
writer(&method_call
);
142 writer
.AppendBool(true /* powerwash */);
144 update_engine_proxy_
->CallMethod(
146 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
147 base::Bind(&UpdateEngineClientImpl::OnRollback
,
148 weak_ptr_factory_
.GetWeakPtr()));
152 virtual void CanRollbackCheck(
153 const RollbackCheckCallback
& callback
) override
{
154 dbus::MethodCall
method_call(
155 update_engine::kUpdateEngineInterface
,
156 update_engine::kCanRollback
);
158 VLOG(1) << "Requesting to get rollback availability status";
159 update_engine_proxy_
->CallMethod(
161 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
162 base::Bind(&UpdateEngineClientImpl::OnCanRollbackCheck
,
163 weak_ptr_factory_
.GetWeakPtr(),
167 virtual Status
GetLastStatus() override
{
171 virtual void SetChannel(const std::string
& target_channel
,
172 bool is_powerwash_allowed
) override
{
173 if (!IsValidChannel(target_channel
)) {
174 LOG(ERROR
) << "Invalid channel name: " << target_channel
;
178 dbus::MethodCall
method_call(
179 update_engine::kUpdateEngineInterface
,
180 update_engine::kSetChannel
);
181 dbus::MessageWriter
writer(&method_call
);
182 writer
.AppendString(target_channel
);
183 writer
.AppendBool(is_powerwash_allowed
);
185 VLOG(1) << "Requesting to set channel: "
186 << "target_channel=" << target_channel
<< ", "
187 << "is_powerwash_allowed=" << is_powerwash_allowed
;
188 update_engine_proxy_
->CallMethod(
190 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
191 base::Bind(&UpdateEngineClientImpl::OnSetChannel
,
192 weak_ptr_factory_
.GetWeakPtr()));
195 virtual void GetChannel(bool get_current_channel
,
196 const GetChannelCallback
& callback
) override
{
197 dbus::MethodCall
method_call(
198 update_engine::kUpdateEngineInterface
,
199 update_engine::kGetChannel
);
200 dbus::MessageWriter
writer(&method_call
);
201 writer
.AppendBool(get_current_channel
);
203 VLOG(1) << "Requesting to get channel, get_current_channel="
204 << get_current_channel
;
205 update_engine_proxy_
->CallMethod(
207 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
208 base::Bind(&UpdateEngineClientImpl::OnGetChannel
,
209 weak_ptr_factory_
.GetWeakPtr(),
214 virtual void Init(dbus::Bus
* bus
) override
{
215 update_engine_proxy_
= bus
->GetObjectProxy(
216 update_engine::kUpdateEngineServiceName
,
217 dbus::ObjectPath(update_engine::kUpdateEngineServicePath
));
219 // Monitor the D-Bus signal for brightness changes. Only the power
220 // manager knows the actual brightness level. We don't cache the
221 // brightness level in Chrome as it will make things less reliable.
222 update_engine_proxy_
->ConnectToSignal(
223 update_engine::kUpdateEngineInterface
,
224 update_engine::kStatusUpdate
,
225 base::Bind(&UpdateEngineClientImpl::StatusUpdateReceived
,
226 weak_ptr_factory_
.GetWeakPtr()),
227 base::Bind(&UpdateEngineClientImpl::StatusUpdateConnected
,
228 weak_ptr_factory_
.GetWeakPtr()));
230 // Get update engine status for the initial status. Update engine won't
231 // send StatusUpdate signal unless there is a status change. If chrome
232 // crashes after UPDATE_STATUS_UPDATED_NEED_REBOOT status is set,
233 // restarted chrome would not get this status. See crbug.com/154104.
234 GetUpdateEngineStatus();
238 void GetUpdateEngineStatus() {
239 dbus::MethodCall
method_call(
240 update_engine::kUpdateEngineInterface
,
241 update_engine::kGetStatus
);
242 update_engine_proxy_
->CallMethodWithErrorCallback(
244 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
245 base::Bind(&UpdateEngineClientImpl::OnGetStatus
,
246 weak_ptr_factory_
.GetWeakPtr()),
247 base::Bind(&UpdateEngineClientImpl::OnGetStatusError
,
248 weak_ptr_factory_
.GetWeakPtr()));
251 // Called when a response for RequestUpdateCheck() is received.
252 void OnRequestUpdateCheck(const UpdateCheckCallback
& callback
,
253 dbus::Response
* response
) {
255 LOG(ERROR
) << "Failed to request update check";
256 callback
.Run(UPDATE_RESULT_FAILED
);
259 callback
.Run(UPDATE_RESULT_SUCCESS
);
262 // Called when a response for RebootAfterUpdate() is received.
263 void OnRebootAfterUpdate(dbus::Response
* response
) {
265 LOG(ERROR
) << "Failed to request rebooting after update";
270 // Called when a response for Rollback() is received.
271 void OnRollback(dbus::Response
* response
) {
273 LOG(ERROR
) << "Failed to rollback";
278 // Called when a response for CanRollbackCheck() is received.
279 void OnCanRollbackCheck(const RollbackCheckCallback
& callback
,
280 dbus::Response
* response
) {
282 LOG(ERROR
) << "Failed to request rollback availability status";
286 dbus::MessageReader
reader(response
);
288 if (!reader
.PopBool(&can_rollback
)) {
289 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
293 VLOG(1) << "Rollback availability status received: " << can_rollback
;
294 callback
.Run(can_rollback
);
297 // Called when a response for GetStatus is received.
298 void OnGetStatus(dbus::Response
* response
) {
300 LOG(ERROR
) << "Failed to get response for GetStatus request.";
304 dbus::MessageReader
reader(response
);
305 std::string current_operation
;
307 if (!(reader
.PopInt64(&status
.last_checked_time
) &&
308 reader
.PopDouble(&status
.download_progress
) &&
309 reader
.PopString(¤t_operation
) &&
310 reader
.PopString(&status
.new_version
) &&
311 reader
.PopInt64(&status
.new_size
))) {
312 LOG(ERROR
) << "GetStatus had incorrect response: "
313 << response
->ToString();
316 status
.status
= UpdateStatusFromString(current_operation
);
317 last_status_
= status
;
318 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(status
));
321 // Called when GetStatus call failed.
322 void OnGetStatusError(dbus::ErrorResponse
* error
) {
323 LOG(ERROR
) << "GetStatus request failed with error: "
324 << (error
? error
->ToString() : "");
327 // Called when a response for SetReleaseChannel() is received.
328 void OnSetChannel(dbus::Response
* response
) {
330 LOG(ERROR
) << "Failed to request setting channel";
333 VLOG(1) << "Succeeded to set channel";
336 // Called when a response for GetChannel() is received.
337 void OnGetChannel(const GetChannelCallback
& callback
,
338 dbus::Response
* response
) {
340 LOG(ERROR
) << "Failed to request getting channel";
344 dbus::MessageReader
reader(response
);
346 if (!reader
.PopString(&channel
)) {
347 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
351 VLOG(1) << "The channel received: " << channel
;
352 callback
.Run(channel
);
355 // Called when a status update signal is received.
356 void StatusUpdateReceived(dbus::Signal
* signal
) {
357 VLOG(1) << "Status update signal received: " << signal
->ToString();
358 dbus::MessageReader
reader(signal
);
359 int64 last_checked_time
= 0;
360 double progress
= 0.0;
361 std::string current_operation
;
362 std::string new_version
;
363 int64_t new_size
= 0;
364 if (!(reader
.PopInt64(&last_checked_time
) &&
365 reader
.PopDouble(&progress
) &&
366 reader
.PopString(¤t_operation
) &&
367 reader
.PopString(&new_version
) &&
368 reader
.PopInt64(&new_size
))) {
369 LOG(ERROR
) << "Status changed signal had incorrect parameters: "
370 << signal
->ToString();
374 status
.last_checked_time
= last_checked_time
;
375 status
.download_progress
= progress
;
376 status
.status
= UpdateStatusFromString(current_operation
);
377 status
.new_version
= new_version
;
378 status
.new_size
= new_size
;
380 last_status_
= status
;
381 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(status
));
384 // Called when the status update signal is initially connected.
385 void StatusUpdateConnected(const std::string
& interface_name
,
386 const std::string
& signal_name
,
388 LOG_IF(WARNING
, !success
)
389 << "Failed to connect to status updated signal.";
392 dbus::ObjectProxy
* update_engine_proxy_
;
393 ObserverList
<Observer
> observers_
;
396 // Note: This should remain the last member so it'll be destroyed and
397 // invalidate its weak pointers before any other members are destroyed.
398 base::WeakPtrFactory
<UpdateEngineClientImpl
> weak_ptr_factory_
;
400 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl
);
403 // The UpdateEngineClient implementation used on Linux desktop,
404 // which does nothing.
405 class UpdateEngineClientStubImpl
: public UpdateEngineClient
{
407 UpdateEngineClientStubImpl()
408 : current_channel_(kReleaseChannelBeta
),
409 target_channel_(kReleaseChannelBeta
) {}
411 // UpdateEngineClient implementation:
412 virtual void Init(dbus::Bus
* bus
) override
{}
413 virtual void AddObserver(Observer
* observer
) override
{}
414 virtual void RemoveObserver(Observer
* observer
) override
{}
415 virtual bool HasObserver(Observer
* observer
) override
{ return false; }
417 virtual void RequestUpdateCheck(
418 const UpdateCheckCallback
& callback
) override
{
419 callback
.Run(UPDATE_RESULT_NOTIMPLEMENTED
);
421 virtual void RebootAfterUpdate() override
{}
422 virtual void Rollback() override
{}
423 virtual void CanRollbackCheck(
424 const RollbackCheckCallback
& callback
) override
{
427 virtual Status
GetLastStatus() override
{ return Status(); }
428 virtual void SetChannel(const std::string
& target_channel
,
429 bool is_powerwash_allowed
) override
{
430 VLOG(1) << "Requesting to set channel: "
431 << "target_channel=" << target_channel
<< ", "
432 << "is_powerwash_allowed=" << is_powerwash_allowed
;
433 target_channel_
= target_channel
;
435 virtual void GetChannel(bool get_current_channel
,
436 const GetChannelCallback
& callback
) override
{
437 VLOG(1) << "Requesting to get channel, get_current_channel="
438 << get_current_channel
;
439 if (get_current_channel
)
440 callback
.Run(current_channel_
);
442 callback
.Run(target_channel_
);
445 std::string current_channel_
;
446 std::string target_channel_
;
449 // The UpdateEngineClient implementation used on Linux desktop, which
450 // tries to emulate real update engine client.
451 class UpdateEngineClientFakeImpl
: public UpdateEngineClientStubImpl
{
453 UpdateEngineClientFakeImpl() : weak_factory_(this) {
456 virtual ~UpdateEngineClientFakeImpl() {
459 // UpdateEngineClient implementation:
460 virtual void AddObserver(Observer
* observer
) override
{
462 observers_
.AddObserver(observer
);
465 virtual void RemoveObserver(Observer
* observer
) override
{
467 observers_
.RemoveObserver(observer
);
470 virtual bool HasObserver(Observer
* observer
) override
{
471 return observers_
.HasObserver(observer
);
474 virtual void RequestUpdateCheck(
475 const UpdateCheckCallback
& callback
) override
{
476 if (last_status_
.status
!= UPDATE_STATUS_IDLE
) {
477 callback
.Run(UPDATE_RESULT_FAILED
);
480 callback
.Run(UPDATE_RESULT_SUCCESS
);
481 last_status_
.status
= UPDATE_STATUS_CHECKING_FOR_UPDATE
;
482 last_status_
.download_progress
= 0.0;
483 last_status_
.last_checked_time
= 0;
484 last_status_
.new_size
= 0;
485 base::MessageLoop::current()->PostDelayedTask(
487 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
488 weak_factory_
.GetWeakPtr()),
489 base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs
));
492 virtual Status
GetLastStatus() override
{ return last_status_
; }
495 void StateTransition() {
496 UpdateStatusOperation next_status
= UPDATE_STATUS_ERROR
;
497 int delay_ms
= kStateTransitionDefaultDelayMs
;
498 switch (last_status_
.status
) {
499 case UPDATE_STATUS_ERROR
:
500 case UPDATE_STATUS_IDLE
:
501 case UPDATE_STATUS_UPDATED_NEED_REBOOT
:
502 case UPDATE_STATUS_REPORTING_ERROR_EVENT
:
503 case UPDATE_STATUS_ATTEMPTING_ROLLBACK
:
505 case UPDATE_STATUS_CHECKING_FOR_UPDATE
:
506 next_status
= UPDATE_STATUS_UPDATE_AVAILABLE
;
508 case UPDATE_STATUS_UPDATE_AVAILABLE
:
509 next_status
= UPDATE_STATUS_DOWNLOADING
;
511 case UPDATE_STATUS_DOWNLOADING
:
512 if (last_status_
.download_progress
>= 1.0) {
513 next_status
= UPDATE_STATUS_VERIFYING
;
515 next_status
= UPDATE_STATUS_DOWNLOADING
;
516 last_status_
.download_progress
+= 0.01;
517 last_status_
.new_size
= kDownloadSizeDelta
;
518 delay_ms
= kStateTransitionDownloadingDelayMs
;
521 case UPDATE_STATUS_VERIFYING
:
522 next_status
= UPDATE_STATUS_FINALIZING
;
524 case UPDATE_STATUS_FINALIZING
:
525 next_status
= UPDATE_STATUS_IDLE
;
528 last_status_
.status
= next_status
;
529 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(last_status_
));
530 if (last_status_
.status
!= UPDATE_STATUS_IDLE
) {
531 base::MessageLoop::current()->PostDelayedTask(
533 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
534 weak_factory_
.GetWeakPtr()),
535 base::TimeDelta::FromMilliseconds(delay_ms
));
539 ObserverList
<Observer
> observers_
;
542 base::WeakPtrFactory
<UpdateEngineClientFakeImpl
> weak_factory_
;
544 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientFakeImpl
);
547 UpdateEngineClient::UpdateEngineClient() {
550 UpdateEngineClient::~UpdateEngineClient() {
554 UpdateEngineClient::UpdateCheckCallback
555 UpdateEngineClient::EmptyUpdateCheckCallback() {
556 return base::Bind(&EmptyUpdateCheckCallbackBody
);
560 UpdateEngineClient
* UpdateEngineClient::Create(
561 DBusClientImplementationType type
) {
562 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
563 return new UpdateEngineClientImpl();
564 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
565 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestAutoUpdateUI
))
566 return new UpdateEngineClientFakeImpl();
568 return new UpdateEngineClientStubImpl();
572 bool UpdateEngineClient::IsTargetChannelMoreStable(
573 const std::string
& current_channel
,
574 const std::string
& target_channel
) {
575 auto cix
= std::find(kReleaseChannelsList
,
576 kReleaseChannelsList
+ arraysize(kReleaseChannelsList
),
578 auto tix
= std::find(kReleaseChannelsList
,
579 kReleaseChannelsList
+ arraysize(kReleaseChannelsList
),
584 } // namespace chromeos