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/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"
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"
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
,
32 kReleaseChannelStable
};
34 // Delay between successive state transitions during AU.
35 const int kStateTransitionDefaultDelayMs
= 3000;
37 // Delay between successive notifications about downloading progress
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
;
82 // The UpdateEngineClient implementation used in production.
83 class UpdateEngineClientImpl
: public UpdateEngineClient
{
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(
114 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
115 base::Bind(&UpdateEngineClientImpl::OnRequestUpdateCheck
,
116 weak_ptr_factory_
.GetWeakPtr(),
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(
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(
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(
156 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
157 base::Bind(&UpdateEngineClientImpl::OnCanRollbackCheck
,
158 weak_ptr_factory_
.GetWeakPtr(),
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
;
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(
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(
200 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
201 base::Bind(&UpdateEngineClientImpl::OnGetChannel
,
202 weak_ptr_factory_
.GetWeakPtr(),
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();
231 void GetUpdateEngineStatus() {
232 dbus::MethodCall
method_call(
233 update_engine::kUpdateEngineInterface
,
234 update_engine::kGetStatus
);
235 update_engine_proxy_
->CallMethodWithErrorCallback(
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
) {
248 LOG(ERROR
) << "Failed to request update check";
249 callback
.Run(UPDATE_RESULT_FAILED
);
252 callback
.Run(UPDATE_RESULT_SUCCESS
);
255 // Called when a response for RebootAfterUpdate() is received.
256 void OnRebootAfterUpdate(dbus::Response
* response
) {
258 LOG(ERROR
) << "Failed to request rebooting after update";
263 // Called when a response for Rollback() is received.
264 void OnRollback(dbus::Response
* response
) {
266 LOG(ERROR
) << "Failed to rollback";
271 // Called when a response for CanRollbackCheck() is received.
272 void OnCanRollbackCheck(const RollbackCheckCallback
& callback
,
273 dbus::Response
* response
) {
275 LOG(ERROR
) << "Failed to request rollback availability status";
279 dbus::MessageReader
reader(response
);
281 if (!reader
.PopBool(&can_rollback
)) {
282 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
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
) {
293 LOG(ERROR
) << "Failed to get response for GetStatus request.";
297 dbus::MessageReader
reader(response
);
298 std::string current_operation
;
300 if (!(reader
.PopInt64(&status
.last_checked_time
) &&
301 reader
.PopDouble(&status
.download_progress
) &&
302 reader
.PopString(¤t_operation
) &&
303 reader
.PopString(&status
.new_version
) &&
304 reader
.PopInt64(&status
.new_size
))) {
305 LOG(ERROR
) << "GetStatus had incorrect response: "
306 << response
->ToString();
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
) {
323 LOG(ERROR
) << "Failed to request setting channel";
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
) {
333 LOG(ERROR
) << "Failed to request getting channel";
337 dbus::MessageReader
reader(response
);
339 if (!reader
.PopString(&channel
)) {
340 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
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(¤t_operation
) &&
360 reader
.PopString(&new_version
) &&
361 reader
.PopInt64(&new_size
))) {
362 LOG(ERROR
) << "Status changed signal had incorrect parameters: "
363 << signal
->ToString();
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
,
381 LOG_IF(WARNING
, !success
)
382 << "Failed to connect to status updated signal.";
385 dbus::ObjectProxy
* update_engine_proxy_
;
386 ObserverList
<Observer
> observers_
;
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
{
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
{
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_
);
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
{
444 UpdateEngineClientFakeImpl() : weak_factory_(this) {
447 ~UpdateEngineClientFakeImpl() override
{}
449 // UpdateEngineClient implementation:
450 void AddObserver(Observer
* observer
) override
{
452 observers_
.AddObserver(observer
);
455 void RemoveObserver(Observer
* observer
) override
{
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
);
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(
476 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
477 weak_factory_
.GetWeakPtr()),
478 base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs
));
481 Status
GetLastStatus() override
{ return last_status_
; }
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
:
494 case UPDATE_STATUS_CHECKING_FOR_UPDATE
:
495 next_status
= UPDATE_STATUS_UPDATE_AVAILABLE
;
497 case UPDATE_STATUS_UPDATE_AVAILABLE
:
498 next_status
= UPDATE_STATUS_DOWNLOADING
;
500 case UPDATE_STATUS_DOWNLOADING
:
501 if (last_status_
.download_progress
>= 1.0) {
502 next_status
= UPDATE_STATUS_VERIFYING
;
504 next_status
= UPDATE_STATUS_DOWNLOADING
;
505 last_status_
.download_progress
+= 0.01;
506 last_status_
.new_size
= kDownloadSizeDelta
;
507 delay_ms
= kStateTransitionDownloadingDelayMs
;
510 case UPDATE_STATUS_VERIFYING
:
511 next_status
= UPDATE_STATUS_FINALIZING
;
513 case UPDATE_STATUS_FINALIZING
:
514 next_status
= UPDATE_STATUS_IDLE
;
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(
522 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
523 weak_factory_
.GetWeakPtr()),
524 base::TimeDelta::FromMilliseconds(delay_ms
));
528 ObserverList
<Observer
> observers_
;
531 base::WeakPtrFactory
<UpdateEngineClientFakeImpl
> weak_factory_
;
533 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientFakeImpl
);
536 UpdateEngineClient::UpdateEngineClient() {
539 UpdateEngineClient::~UpdateEngineClient() {
543 UpdateEngineClient::UpdateCheckCallback
544 UpdateEngineClient::EmptyUpdateCheckCallback() {
545 return base::Bind(&EmptyUpdateCheckCallbackBody
);
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();
558 return new UpdateEngineClientStubImpl();
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
),
568 auto tix
= std::find(kReleaseChannelsList
,
569 kReleaseChannelsList
+ arraysize(kReleaseChannelsList
),
574 } // namespace chromeos