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 ~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(
115 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
116 base::Bind(&UpdateEngineClientImpl::OnRequestUpdateCheck
,
117 weak_ptr_factory_
.GetWeakPtr(),
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(
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(
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(
157 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
158 base::Bind(&UpdateEngineClientImpl::OnCanRollbackCheck
,
159 weak_ptr_factory_
.GetWeakPtr(),
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
;
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(
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(
201 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
202 base::Bind(&UpdateEngineClientImpl::OnGetChannel
,
203 weak_ptr_factory_
.GetWeakPtr(),
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();
232 void GetUpdateEngineStatus() {
233 dbus::MethodCall
method_call(
234 update_engine::kUpdateEngineInterface
,
235 update_engine::kGetStatus
);
236 update_engine_proxy_
->CallMethodWithErrorCallback(
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
) {
249 LOG(ERROR
) << "Failed to request update check";
250 callback
.Run(UPDATE_RESULT_FAILED
);
253 callback
.Run(UPDATE_RESULT_SUCCESS
);
256 // Called when a response for RebootAfterUpdate() is received.
257 void OnRebootAfterUpdate(dbus::Response
* response
) {
259 LOG(ERROR
) << "Failed to request rebooting after update";
264 // Called when a response for Rollback() is received.
265 void OnRollback(dbus::Response
* response
) {
267 LOG(ERROR
) << "Failed to rollback";
272 // Called when a response for CanRollbackCheck() is received.
273 void OnCanRollbackCheck(const RollbackCheckCallback
& callback
,
274 dbus::Response
* response
) {
276 LOG(ERROR
) << "Failed to request rollback availability status";
280 dbus::MessageReader
reader(response
);
282 if (!reader
.PopBool(&can_rollback
)) {
283 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
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
) {
294 LOG(ERROR
) << "Failed to get response for GetStatus request.";
298 dbus::MessageReader
reader(response
);
299 std::string current_operation
;
301 if (!(reader
.PopInt64(&status
.last_checked_time
) &&
302 reader
.PopDouble(&status
.download_progress
) &&
303 reader
.PopString(¤t_operation
) &&
304 reader
.PopString(&status
.new_version
) &&
305 reader
.PopInt64(&status
.new_size
))) {
306 LOG(ERROR
) << "GetStatus had incorrect response: "
307 << response
->ToString();
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
) {
324 LOG(ERROR
) << "Failed to request setting channel";
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
) {
334 LOG(ERROR
) << "Failed to request getting channel";
338 dbus::MessageReader
reader(response
);
340 if (!reader
.PopString(&channel
)) {
341 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
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(¤t_operation
) &&
361 reader
.PopString(&new_version
) &&
362 reader
.PopInt64(&new_size
))) {
363 LOG(ERROR
) << "Status changed signal had incorrect parameters: "
364 << signal
->ToString();
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
,
382 LOG_IF(WARNING
, !success
)
383 << "Failed to connect to status updated signal.";
386 dbus::ObjectProxy
* update_engine_proxy_
;
387 ObserverList
<Observer
> observers_
;
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
{
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
{
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_
);
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
{
445 UpdateEngineClientFakeImpl() : weak_factory_(this) {
448 ~UpdateEngineClientFakeImpl() override
{}
450 // UpdateEngineClient implementation:
451 void AddObserver(Observer
* observer
) override
{
453 observers_
.AddObserver(observer
);
456 void RemoveObserver(Observer
* observer
) override
{
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
);
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(
477 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
478 weak_factory_
.GetWeakPtr()),
479 base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs
));
482 Status
GetLastStatus() override
{ return last_status_
; }
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
:
495 case UPDATE_STATUS_CHECKING_FOR_UPDATE
:
496 next_status
= UPDATE_STATUS_UPDATE_AVAILABLE
;
498 case UPDATE_STATUS_UPDATE_AVAILABLE
:
499 next_status
= UPDATE_STATUS_DOWNLOADING
;
501 case UPDATE_STATUS_DOWNLOADING
:
502 if (last_status_
.download_progress
>= 1.0) {
503 next_status
= UPDATE_STATUS_VERIFYING
;
505 next_status
= UPDATE_STATUS_DOWNLOADING
;
506 last_status_
.download_progress
+= 0.01;
507 last_status_
.new_size
= kDownloadSizeDelta
;
508 delay_ms
= kStateTransitionDownloadingDelayMs
;
511 case UPDATE_STATUS_VERIFYING
:
512 next_status
= UPDATE_STATUS_FINALIZING
;
514 case UPDATE_STATUS_FINALIZING
:
515 next_status
= UPDATE_STATUS_IDLE
;
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(
523 base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
524 weak_factory_
.GetWeakPtr()),
525 base::TimeDelta::FromMilliseconds(delay_ms
));
529 ObserverList
<Observer
> observers_
;
532 base::WeakPtrFactory
<UpdateEngineClientFakeImpl
> weak_factory_
;
534 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientFakeImpl
);
537 UpdateEngineClient::UpdateEngineClient() {
540 UpdateEngineClient::~UpdateEngineClient() {
544 UpdateEngineClient::UpdateCheckCallback
545 UpdateEngineClient::EmptyUpdateCheckCallback() {
546 return base::Bind(&EmptyUpdateCheckCallbackBody
);
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();
559 return new UpdateEngineClientStubImpl();
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
),
569 auto tix
= std::find(kReleaseChannelsList
,
570 kReleaseChannelsList
+ arraysize(kReleaseChannelsList
),
575 } // namespace chromeos