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(const Observer
* observer
) const 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(const Observer
* observer
) const override
{
419 virtual void RequestUpdateCheck(
420 const UpdateCheckCallback
& callback
) override
{
421 callback
.Run(UPDATE_RESULT_NOTIMPLEMENTED
);
423 virtual void RebootAfterUpdate() override
{}
424 virtual void Rollback() override
{}
425 virtual void CanRollbackCheck(
426 const RollbackCheckCallback
& callback
) override
{
429 virtual Status
GetLastStatus() override
{ return Status(); }
430 virtual void SetChannel(const std::string
& target_channel
,
431 bool is_powerwash_allowed
) override
{
432 VLOG(1) << "Requesting to set channel: "
433 << "target_channel=" << target_channel
<< ", "
434 << "is_powerwash_allowed=" << is_powerwash_allowed
;
435 target_channel_
= target_channel
;
437 virtual void GetChannel(bool get_current_channel
,
438 const GetChannelCallback
& callback
) override
{
439 VLOG(1) << "Requesting to get channel, get_current_channel="
440 << get_current_channel
;
441 if (get_current_channel
)
442 callback
.Run(current_channel_
);
444 callback
.Run(target_channel_
);
447 std::string current_channel_
;
448 std::string target_channel_
;
451 // The UpdateEngineClient implementation used on Linux desktop, which
452 // tries to emulate real update engine client.
453 class UpdateEngineClientFakeImpl
: public UpdateEngineClientStubImpl
{
455 UpdateEngineClientFakeImpl() : weak_factory_(this) {
458 virtual ~UpdateEngineClientFakeImpl() {
461 // UpdateEngineClient implementation:
462 virtual void AddObserver(Observer
* observer
) override
{
464 observers_
.AddObserver(observer
);
467 virtual void RemoveObserver(Observer
* observer
) override
{
469 observers_
.RemoveObserver(observer
);
472 virtual bool HasObserver(const Observer
* observer
) const override
{
473 return observers_
.HasObserver(observer
);
476 virtual void RequestUpdateCheck(
477 const UpdateCheckCallback
& callback
) override
{
478 if (last_status_
.status
!= UPDATE_STATUS_IDLE
) {
479 callback
.Run(UPDATE_RESULT_FAILED
);
482 callback
.Run(UPDATE_RESULT_SUCCESS
);
483 last_status_
.status
= UPDATE_STATUS_CHECKING_FOR_UPDATE
;
484 last_status_
.download_progress
= 0.0;
485 last_status_
.last_checked_time
= 0;
486 last_status_
.new_size
= 0;
487 base::MessageLoop::current()->PostDelayedTask(
489 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
490 weak_factory_
.GetWeakPtr()),
491 base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs
));
494 virtual Status
GetLastStatus() override
{ return last_status_
; }
497 void StateTransition() {
498 UpdateStatusOperation next_status
= UPDATE_STATUS_ERROR
;
499 int delay_ms
= kStateTransitionDefaultDelayMs
;
500 switch (last_status_
.status
) {
501 case UPDATE_STATUS_ERROR
:
502 case UPDATE_STATUS_IDLE
:
503 case UPDATE_STATUS_UPDATED_NEED_REBOOT
:
504 case UPDATE_STATUS_REPORTING_ERROR_EVENT
:
505 case UPDATE_STATUS_ATTEMPTING_ROLLBACK
:
507 case UPDATE_STATUS_CHECKING_FOR_UPDATE
:
508 next_status
= UPDATE_STATUS_UPDATE_AVAILABLE
;
510 case UPDATE_STATUS_UPDATE_AVAILABLE
:
511 next_status
= UPDATE_STATUS_DOWNLOADING
;
513 case UPDATE_STATUS_DOWNLOADING
:
514 if (last_status_
.download_progress
>= 1.0) {
515 next_status
= UPDATE_STATUS_VERIFYING
;
517 next_status
= UPDATE_STATUS_DOWNLOADING
;
518 last_status_
.download_progress
+= 0.01;
519 last_status_
.new_size
= kDownloadSizeDelta
;
520 delay_ms
= kStateTransitionDownloadingDelayMs
;
523 case UPDATE_STATUS_VERIFYING
:
524 next_status
= UPDATE_STATUS_FINALIZING
;
526 case UPDATE_STATUS_FINALIZING
:
527 next_status
= UPDATE_STATUS_IDLE
;
530 last_status_
.status
= next_status
;
531 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(last_status_
));
532 if (last_status_
.status
!= UPDATE_STATUS_IDLE
) {
533 base::MessageLoop::current()->PostDelayedTask(
535 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
536 weak_factory_
.GetWeakPtr()),
537 base::TimeDelta::FromMilliseconds(delay_ms
));
541 ObserverList
<Observer
> observers_
;
544 base::WeakPtrFactory
<UpdateEngineClientFakeImpl
> weak_factory_
;
546 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientFakeImpl
);
549 UpdateEngineClient::UpdateEngineClient() {
552 UpdateEngineClient::~UpdateEngineClient() {
556 UpdateEngineClient::UpdateCheckCallback
557 UpdateEngineClient::EmptyUpdateCheckCallback() {
558 return base::Bind(&EmptyUpdateCheckCallbackBody
);
562 UpdateEngineClient
* UpdateEngineClient::Create(
563 DBusClientImplementationType type
) {
564 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
565 return new UpdateEngineClientImpl();
566 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
567 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
568 switches::kTestAutoUpdateUI
))
569 return new UpdateEngineClientFakeImpl();
571 return new UpdateEngineClientStubImpl();
575 bool UpdateEngineClient::IsTargetChannelMoreStable(
576 const std::string
& current_channel
,
577 const std::string
& target_channel
) {
578 auto cix
= std::find(kReleaseChannelsList
,
579 kReleaseChannelsList
+ arraysize(kReleaseChannelsList
),
581 auto tix
= std::find(kReleaseChannelsList
,
582 kReleaseChannelsList
+ arraysize(kReleaseChannelsList
),
587 } // namespace chromeos