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"
8 #include "base/callback.h"
9 #include "base/command_line.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/string_util.h"
12 #include "chromeos/chromeos_switches.h"
14 #include "dbus/message.h"
15 #include "dbus/object_path.h"
16 #include "dbus/object_proxy.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
23 const char kReleaseChannelDev
[] = "dev-channel";
24 const char kReleaseChannelBeta
[] = "beta-channel";
25 const char kReleaseChannelStable
[] = "stable-channel";
27 // Delay between successive state transitions during AU.
28 const int kStateTransitionDefaultDelayMs
= 3000;
30 // Delay between successive notifications about downloading progress
32 const int kStateTransitionDownloadingDelayMs
= 250;
34 // Size of parts of a "new" image which are downloaded each
35 // |kStateTransitionDownloadingDelayMs| during fake AU.
36 const int64_t kDownloadSizeDelta
= 1 << 19;
38 // Returns UPDATE_STATUS_ERROR on error.
39 UpdateEngineClient::UpdateStatusOperation
UpdateStatusFromString(
40 const std::string
& str
) {
41 if (str
== update_engine::kUpdateStatusIdle
)
42 return UpdateEngineClient::UPDATE_STATUS_IDLE
;
43 if (str
== update_engine::kUpdateStatusCheckingForUpdate
)
44 return UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE
;
45 if (str
== update_engine::kUpdateStatusUpdateAvailable
)
46 return UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE
;
47 if (str
== update_engine::kUpdateStatusDownloading
)
48 return UpdateEngineClient::UPDATE_STATUS_DOWNLOADING
;
49 if (str
== update_engine::kUpdateStatusVerifying
)
50 return UpdateEngineClient::UPDATE_STATUS_VERIFYING
;
51 if (str
== update_engine::kUpdateStatusFinalizing
)
52 return UpdateEngineClient::UPDATE_STATUS_FINALIZING
;
53 if (str
== update_engine::kUpdateStatusUpdatedNeedReboot
)
54 return UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT
;
55 if (str
== update_engine::kUpdateStatusReportingErrorEvent
)
56 return UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT
;
57 return UpdateEngineClient::UPDATE_STATUS_ERROR
;
60 // Used in UpdateEngineClient::EmptyUpdateCheckCallback().
61 void EmptyUpdateCheckCallbackBody(
62 UpdateEngineClient::UpdateCheckResult unused_result
) {
65 bool IsValidChannel(const std::string
& channel
) {
66 return channel
== kReleaseChannelDev
||
67 channel
== kReleaseChannelBeta
||
68 channel
== kReleaseChannelStable
;
73 // The UpdateEngineClient implementation used in production.
74 class UpdateEngineClientImpl
: public UpdateEngineClient
{
76 UpdateEngineClientImpl()
77 : update_engine_proxy_(NULL
), last_status_(), weak_ptr_factory_(this) {}
79 virtual ~UpdateEngineClientImpl() {
82 // UpdateEngineClient implementation:
83 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
84 observers_
.AddObserver(observer
);
87 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
88 observers_
.RemoveObserver(observer
);
91 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
92 return observers_
.HasObserver(observer
);
95 virtual void RequestUpdateCheck(
96 const UpdateCheckCallback
& callback
) OVERRIDE
{
97 dbus::MethodCall
method_call(
98 update_engine::kUpdateEngineInterface
,
99 update_engine::kAttemptUpdate
);
100 dbus::MessageWriter
writer(&method_call
);
101 writer
.AppendString(""); // Unused.
102 writer
.AppendString(""); // Unused.
104 VLOG(1) << "Requesting an update check";
105 update_engine_proxy_
->CallMethod(
107 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
108 base::Bind(&UpdateEngineClientImpl::OnRequestUpdateCheck
,
109 weak_ptr_factory_
.GetWeakPtr(),
113 virtual void RebootAfterUpdate() OVERRIDE
{
114 dbus::MethodCall
method_call(
115 update_engine::kUpdateEngineInterface
,
116 update_engine::kRebootIfNeeded
);
118 VLOG(1) << "Requesting a reboot";
119 update_engine_proxy_
->CallMethod(
121 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
122 base::Bind(&UpdateEngineClientImpl::OnRebootAfterUpdate
,
123 weak_ptr_factory_
.GetWeakPtr()));
126 virtual void Rollback() OVERRIDE
{
127 VLOG(1) << "Requesting a rollback";
128 dbus::MethodCall
method_call(
129 update_engine::kUpdateEngineInterface
,
130 update_engine::kAttemptRollback
);
131 dbus::MessageWriter
writer(&method_call
);
132 writer
.AppendBool(true /* powerwash */);
134 update_engine_proxy_
->CallMethod(
136 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
137 base::Bind(&UpdateEngineClientImpl::OnRollback
,
138 weak_ptr_factory_
.GetWeakPtr()));
142 virtual void CanRollbackCheck(
143 const RollbackCheckCallback
& callback
) OVERRIDE
{
144 dbus::MethodCall
method_call(
145 update_engine::kUpdateEngineInterface
,
146 update_engine::kCanRollback
);
148 VLOG(1) << "Requesting to get rollback availability status";
149 update_engine_proxy_
->CallMethod(
151 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
152 base::Bind(&UpdateEngineClientImpl::OnCanRollbackCheck
,
153 weak_ptr_factory_
.GetWeakPtr(),
157 virtual Status
GetLastStatus() OVERRIDE
{
161 virtual void SetChannel(const std::string
& target_channel
,
162 bool is_powerwash_allowed
) OVERRIDE
{
163 if (!IsValidChannel(target_channel
)) {
164 LOG(ERROR
) << "Invalid channel name: " << target_channel
;
168 dbus::MethodCall
method_call(
169 update_engine::kUpdateEngineInterface
,
170 update_engine::kSetChannel
);
171 dbus::MessageWriter
writer(&method_call
);
172 writer
.AppendString(target_channel
);
173 writer
.AppendBool(is_powerwash_allowed
);
175 VLOG(1) << "Requesting to set channel: "
176 << "target_channel=" << target_channel
<< ", "
177 << "is_powerwash_allowed=" << is_powerwash_allowed
;
178 update_engine_proxy_
->CallMethod(
180 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
181 base::Bind(&UpdateEngineClientImpl::OnSetChannel
,
182 weak_ptr_factory_
.GetWeakPtr()));
185 virtual void GetChannel(bool get_current_channel
,
186 const GetChannelCallback
& callback
) OVERRIDE
{
187 dbus::MethodCall
method_call(
188 update_engine::kUpdateEngineInterface
,
189 update_engine::kGetChannel
);
190 dbus::MessageWriter
writer(&method_call
);
191 writer
.AppendBool(get_current_channel
);
193 VLOG(1) << "Requesting to get channel, get_current_channel="
194 << get_current_channel
;
195 update_engine_proxy_
->CallMethod(
197 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
198 base::Bind(&UpdateEngineClientImpl::OnGetChannel
,
199 weak_ptr_factory_
.GetWeakPtr(),
204 virtual void Init(dbus::Bus
* bus
) OVERRIDE
{
205 update_engine_proxy_
= bus
->GetObjectProxy(
206 update_engine::kUpdateEngineServiceName
,
207 dbus::ObjectPath(update_engine::kUpdateEngineServicePath
));
209 // Monitor the D-Bus signal for brightness changes. Only the power
210 // manager knows the actual brightness level. We don't cache the
211 // brightness level in Chrome as it will make things less reliable.
212 update_engine_proxy_
->ConnectToSignal(
213 update_engine::kUpdateEngineInterface
,
214 update_engine::kStatusUpdate
,
215 base::Bind(&UpdateEngineClientImpl::StatusUpdateReceived
,
216 weak_ptr_factory_
.GetWeakPtr()),
217 base::Bind(&UpdateEngineClientImpl::StatusUpdateConnected
,
218 weak_ptr_factory_
.GetWeakPtr()));
220 // Get update engine status for the initial status. Update engine won't
221 // send StatusUpdate signal unless there is a status change. If chrome
222 // crashes after UPDATE_STATUS_UPDATED_NEED_REBOOT status is set,
223 // restarted chrome would not get this status. See crbug.com/154104.
224 GetUpdateEngineStatus();
228 void GetUpdateEngineStatus() {
229 dbus::MethodCall
method_call(
230 update_engine::kUpdateEngineInterface
,
231 update_engine::kGetStatus
);
232 update_engine_proxy_
->CallMethodWithErrorCallback(
234 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
235 base::Bind(&UpdateEngineClientImpl::OnGetStatus
,
236 weak_ptr_factory_
.GetWeakPtr()),
237 base::Bind(&UpdateEngineClientImpl::OnGetStatusError
,
238 weak_ptr_factory_
.GetWeakPtr()));
241 // Called when a response for RequestUpdateCheck() is received.
242 void OnRequestUpdateCheck(const UpdateCheckCallback
& callback
,
243 dbus::Response
* response
) {
245 LOG(ERROR
) << "Failed to request update check";
246 callback
.Run(UPDATE_RESULT_FAILED
);
249 callback
.Run(UPDATE_RESULT_SUCCESS
);
252 // Called when a response for RebootAfterUpdate() is received.
253 void OnRebootAfterUpdate(dbus::Response
* response
) {
255 LOG(ERROR
) << "Failed to request rebooting after update";
260 // Called when a response for Rollback() is received.
261 void OnRollback(dbus::Response
* response
) {
263 LOG(ERROR
) << "Failed to rollback";
268 // Called when a response for CanRollbackCheck() is received.
269 void OnCanRollbackCheck(const RollbackCheckCallback
& callback
,
270 dbus::Response
* response
) {
272 LOG(ERROR
) << "Failed to request rollback availability status";
276 dbus::MessageReader
reader(response
);
278 if (!reader
.PopBool(&can_rollback
)) {
279 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
283 VLOG(1) << "Rollback availability status received: " << can_rollback
;
284 callback
.Run(can_rollback
);
287 // Called when a response for GetStatus is received.
288 void OnGetStatus(dbus::Response
* response
) {
290 LOG(ERROR
) << "Failed to get response for GetStatus request.";
294 dbus::MessageReader
reader(response
);
295 std::string current_operation
;
297 if (!(reader
.PopInt64(&status
.last_checked_time
) &&
298 reader
.PopDouble(&status
.download_progress
) &&
299 reader
.PopString(¤t_operation
) &&
300 reader
.PopString(&status
.new_version
) &&
301 reader
.PopInt64(&status
.new_size
))) {
302 LOG(ERROR
) << "GetStatus had incorrect response: "
303 << response
->ToString();
306 status
.status
= UpdateStatusFromString(current_operation
);
307 last_status_
= status
;
308 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(status
));
311 // Called when GetStatus call failed.
312 void OnGetStatusError(dbus::ErrorResponse
* error
) {
313 LOG(ERROR
) << "GetStatus request failed with error: "
314 << (error
? error
->ToString() : "");
317 // Called when a response for SetReleaseChannel() is received.
318 void OnSetChannel(dbus::Response
* response
) {
320 LOG(ERROR
) << "Failed to request setting channel";
323 VLOG(1) << "Succeeded to set channel";
326 // Called when a response for GetChannel() is received.
327 void OnGetChannel(const GetChannelCallback
& callback
,
328 dbus::Response
* response
) {
330 LOG(ERROR
) << "Failed to request getting channel";
334 dbus::MessageReader
reader(response
);
336 if (!reader
.PopString(&channel
)) {
337 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
341 VLOG(1) << "The channel received: " << channel
;
342 callback
.Run(channel
);
345 // Called when a status update signal is received.
346 void StatusUpdateReceived(dbus::Signal
* signal
) {
347 VLOG(1) << "Status update signal received: " << signal
->ToString();
348 dbus::MessageReader
reader(signal
);
349 int64 last_checked_time
= 0;
350 double progress
= 0.0;
351 std::string current_operation
;
352 std::string new_version
;
353 int64_t new_size
= 0;
354 if (!(reader
.PopInt64(&last_checked_time
) &&
355 reader
.PopDouble(&progress
) &&
356 reader
.PopString(¤t_operation
) &&
357 reader
.PopString(&new_version
) &&
358 reader
.PopInt64(&new_size
))) {
359 LOG(ERROR
) << "Status changed signal had incorrect parameters: "
360 << signal
->ToString();
364 status
.last_checked_time
= last_checked_time
;
365 status
.download_progress
= progress
;
366 status
.status
= UpdateStatusFromString(current_operation
);
367 status
.new_version
= new_version
;
368 status
.new_size
= new_size
;
370 last_status_
= status
;
371 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(status
));
374 // Called when the status update signal is initially connected.
375 void StatusUpdateConnected(const std::string
& interface_name
,
376 const std::string
& signal_name
,
378 LOG_IF(WARNING
, !success
)
379 << "Failed to connect to status updated signal.";
382 dbus::ObjectProxy
* update_engine_proxy_
;
383 ObserverList
<Observer
> observers_
;
386 // Note: This should remain the last member so it'll be destroyed and
387 // invalidate its weak pointers before any other members are destroyed.
388 base::WeakPtrFactory
<UpdateEngineClientImpl
> weak_ptr_factory_
;
390 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl
);
393 // The UpdateEngineClient implementation used on Linux desktop,
394 // which does nothing.
395 class UpdateEngineClientStubImpl
: public UpdateEngineClient
{
396 // UpdateEngineClient implementation:
397 virtual void Init(dbus::Bus
* bus
) OVERRIDE
{}
398 virtual void AddObserver(Observer
* observer
) OVERRIDE
{}
399 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{}
400 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{ return false; }
402 virtual void RequestUpdateCheck(
403 const UpdateCheckCallback
& callback
) OVERRIDE
{
404 callback
.Run(UPDATE_RESULT_NOTIMPLEMENTED
);
406 virtual void RebootAfterUpdate() OVERRIDE
{}
407 virtual void Rollback() OVERRIDE
{}
408 virtual void CanRollbackCheck(
409 const RollbackCheckCallback
& callback
) OVERRIDE
{
412 virtual Status
GetLastStatus() OVERRIDE
{ return Status(); }
413 virtual void SetChannel(const std::string
& target_channel
,
414 bool is_powerwash_allowed
) OVERRIDE
{
415 VLOG(1) << "Requesting to set channel: "
416 << "target_channel=" << target_channel
<< ", "
417 << "is_powerwash_allowed=" << is_powerwash_allowed
;
419 virtual void GetChannel(bool get_current_channel
,
420 const GetChannelCallback
& callback
) OVERRIDE
{
421 VLOG(1) << "Requesting to get channel, get_current_channel="
422 << get_current_channel
;
423 callback
.Run(kReleaseChannelBeta
);
427 // The UpdateEngineClient implementation used on Linux desktop, which
428 // tries to emulate real update engine client.
429 class UpdateEngineClientFakeImpl
: public UpdateEngineClientStubImpl
{
431 UpdateEngineClientFakeImpl() : weak_factory_(this) {
434 virtual ~UpdateEngineClientFakeImpl() {
437 // UpdateEngineClient implementation:
438 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
440 observers_
.AddObserver(observer
);
443 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
445 observers_
.RemoveObserver(observer
);
448 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
449 return observers_
.HasObserver(observer
);
452 virtual void RequestUpdateCheck(
453 const UpdateCheckCallback
& callback
) OVERRIDE
{
454 if (last_status_
.status
!= UPDATE_STATUS_IDLE
) {
455 callback
.Run(UPDATE_RESULT_FAILED
);
458 callback
.Run(UPDATE_RESULT_SUCCESS
);
459 last_status_
.status
= UPDATE_STATUS_CHECKING_FOR_UPDATE
;
460 last_status_
.download_progress
= 0.0;
461 last_status_
.last_checked_time
= 0;
462 last_status_
.new_size
= 0;
463 base::MessageLoop::current()->PostDelayedTask(
465 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
466 weak_factory_
.GetWeakPtr()),
467 base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs
));
470 virtual Status
GetLastStatus() OVERRIDE
{ return last_status_
; }
473 void StateTransition() {
474 UpdateStatusOperation next_status
= UPDATE_STATUS_ERROR
;
475 int delay_ms
= kStateTransitionDefaultDelayMs
;
476 switch (last_status_
.status
) {
477 case UPDATE_STATUS_ERROR
:
478 case UPDATE_STATUS_IDLE
:
479 case UPDATE_STATUS_UPDATED_NEED_REBOOT
:
480 case UPDATE_STATUS_REPORTING_ERROR_EVENT
:
482 case UPDATE_STATUS_CHECKING_FOR_UPDATE
:
483 next_status
= UPDATE_STATUS_UPDATE_AVAILABLE
;
485 case UPDATE_STATUS_UPDATE_AVAILABLE
:
486 next_status
= UPDATE_STATUS_DOWNLOADING
;
488 case UPDATE_STATUS_DOWNLOADING
:
489 if (last_status_
.download_progress
>= 1.0) {
490 next_status
= UPDATE_STATUS_VERIFYING
;
492 next_status
= UPDATE_STATUS_DOWNLOADING
;
493 last_status_
.download_progress
+= 0.01;
494 last_status_
.new_size
= kDownloadSizeDelta
;
495 delay_ms
= kStateTransitionDownloadingDelayMs
;
498 case UPDATE_STATUS_VERIFYING
:
499 next_status
= UPDATE_STATUS_FINALIZING
;
501 case UPDATE_STATUS_FINALIZING
:
502 next_status
= UPDATE_STATUS_IDLE
;
505 last_status_
.status
= next_status
;
506 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(last_status_
));
507 if (last_status_
.status
!= UPDATE_STATUS_IDLE
) {
508 base::MessageLoop::current()->PostDelayedTask(
510 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
511 weak_factory_
.GetWeakPtr()),
512 base::TimeDelta::FromMilliseconds(delay_ms
));
516 ObserverList
<Observer
> observers_
;
519 base::WeakPtrFactory
<UpdateEngineClientFakeImpl
> weak_factory_
;
521 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientFakeImpl
);
524 UpdateEngineClient::UpdateEngineClient() {
527 UpdateEngineClient::~UpdateEngineClient() {
531 UpdateEngineClient::UpdateCheckCallback
532 UpdateEngineClient::EmptyUpdateCheckCallback() {
533 return base::Bind(&EmptyUpdateCheckCallbackBody
);
537 UpdateEngineClient
* UpdateEngineClient::Create(
538 DBusClientImplementationType type
) {
539 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
540 return new UpdateEngineClientImpl();
541 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
542 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestAutoUpdateUI
))
543 return new UpdateEngineClientFakeImpl();
545 return new UpdateEngineClientStubImpl();
548 } // namespace chromeos