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/location.h"
12 #include "base/macros.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/string_util.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chromeos/chromeos_switches.h"
18 #include "dbus/message.h"
19 #include "dbus/object_path.h"
20 #include "dbus/object_proxy.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
27 const char kReleaseChannelDev
[] = "dev-channel";
28 const char kReleaseChannelBeta
[] = "beta-channel";
29 const char kReleaseChannelStable
[] = "stable-channel";
31 // List of release channels ordered by stability.
32 const char* kReleaseChannelsList
[] = {kReleaseChannelDev
,
34 kReleaseChannelStable
};
36 // Delay between successive state transitions during AU.
37 const int kStateTransitionDefaultDelayMs
= 3000;
39 // Delay between successive notifications about downloading progress
41 const int kStateTransitionDownloadingDelayMs
= 250;
43 // Size of parts of a "new" image which are downloaded each
44 // |kStateTransitionDownloadingDelayMs| during fake AU.
45 const int64_t kDownloadSizeDelta
= 1 << 19;
47 // Returns UPDATE_STATUS_ERROR on error.
48 UpdateEngineClient::UpdateStatusOperation
UpdateStatusFromString(
49 const std::string
& str
) {
50 VLOG(1) << "UpdateStatusFromString got " << str
<< " as input.";
51 if (str
== update_engine::kUpdateStatusIdle
)
52 return UpdateEngineClient::UPDATE_STATUS_IDLE
;
53 if (str
== update_engine::kUpdateStatusCheckingForUpdate
)
54 return UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE
;
55 if (str
== update_engine::kUpdateStatusUpdateAvailable
)
56 return UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE
;
57 if (str
== update_engine::kUpdateStatusDownloading
)
58 return UpdateEngineClient::UPDATE_STATUS_DOWNLOADING
;
59 if (str
== update_engine::kUpdateStatusVerifying
)
60 return UpdateEngineClient::UPDATE_STATUS_VERIFYING
;
61 if (str
== update_engine::kUpdateStatusFinalizing
)
62 return UpdateEngineClient::UPDATE_STATUS_FINALIZING
;
63 if (str
== update_engine::kUpdateStatusUpdatedNeedReboot
)
64 return UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT
;
65 if (str
== update_engine::kUpdateStatusReportingErrorEvent
)
66 return UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT
;
67 if (str
== update_engine::kUpdateStatusAttemptingRollback
)
68 return UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK
;
69 return UpdateEngineClient::UPDATE_STATUS_ERROR
;
72 // Used in UpdateEngineClient::EmptyUpdateCheckCallback().
73 void EmptyUpdateCheckCallbackBody(
74 UpdateEngineClient::UpdateCheckResult unused_result
) {
77 bool IsValidChannel(const std::string
& channel
) {
78 return channel
== kReleaseChannelDev
|| channel
== kReleaseChannelBeta
||
79 channel
== kReleaseChannelStable
;
84 // The UpdateEngineClient implementation used in production.
85 class UpdateEngineClientImpl
: public UpdateEngineClient
{
87 UpdateEngineClientImpl()
88 : update_engine_proxy_(NULL
), last_status_(), weak_ptr_factory_(this) {}
90 ~UpdateEngineClientImpl() override
{}
92 // UpdateEngineClient implementation:
93 void AddObserver(Observer
* observer
) override
{
94 observers_
.AddObserver(observer
);
97 void RemoveObserver(Observer
* observer
) override
{
98 observers_
.RemoveObserver(observer
);
101 bool HasObserver(const Observer
* observer
) const override
{
102 return observers_
.HasObserver(observer
);
105 void RequestUpdateCheck(const UpdateCheckCallback
& callback
) override
{
106 dbus::MethodCall
method_call(
107 update_engine::kUpdateEngineInterface
,
108 update_engine::kAttemptUpdate
);
109 dbus::MessageWriter
writer(&method_call
);
110 writer
.AppendString(""); // Unused.
111 writer
.AppendString(""); // Unused.
113 VLOG(1) << "Requesting an update check";
114 update_engine_proxy_
->CallMethod(
116 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
117 base::Bind(&UpdateEngineClientImpl::OnRequestUpdateCheck
,
118 weak_ptr_factory_
.GetWeakPtr(),
122 void RebootAfterUpdate() override
{
123 dbus::MethodCall
method_call(
124 update_engine::kUpdateEngineInterface
,
125 update_engine::kRebootIfNeeded
);
127 VLOG(1) << "Requesting a reboot";
128 update_engine_proxy_
->CallMethod(
130 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
131 base::Bind(&UpdateEngineClientImpl::OnRebootAfterUpdate
,
132 weak_ptr_factory_
.GetWeakPtr()));
135 void Rollback() override
{
136 VLOG(1) << "Requesting a rollback";
137 dbus::MethodCall
method_call(
138 update_engine::kUpdateEngineInterface
,
139 update_engine::kAttemptRollback
);
140 dbus::MessageWriter
writer(&method_call
);
141 writer
.AppendBool(true /* powerwash */);
143 update_engine_proxy_
->CallMethod(
145 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
146 base::Bind(&UpdateEngineClientImpl::OnRollback
,
147 weak_ptr_factory_
.GetWeakPtr()));
150 void CanRollbackCheck(const RollbackCheckCallback
& callback
) override
{
151 dbus::MethodCall
method_call(
152 update_engine::kUpdateEngineInterface
,
153 update_engine::kCanRollback
);
155 VLOG(1) << "Requesting to get rollback availability status";
156 update_engine_proxy_
->CallMethod(
158 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
159 base::Bind(&UpdateEngineClientImpl::OnCanRollbackCheck
,
160 weak_ptr_factory_
.GetWeakPtr(),
164 Status
GetLastStatus() override
{ return last_status_
; }
166 void SetChannel(const std::string
& target_channel
,
167 bool is_powerwash_allowed
) override
{
168 if (!IsValidChannel(target_channel
)) {
169 LOG(ERROR
) << "Invalid channel name: " << target_channel
;
173 dbus::MethodCall
method_call(
174 update_engine::kUpdateEngineInterface
,
175 update_engine::kSetChannel
);
176 dbus::MessageWriter
writer(&method_call
);
177 writer
.AppendString(target_channel
);
178 writer
.AppendBool(is_powerwash_allowed
);
180 VLOG(1) << "Requesting to set channel: "
181 << "target_channel=" << target_channel
<< ", "
182 << "is_powerwash_allowed=" << is_powerwash_allowed
;
183 update_engine_proxy_
->CallMethod(
185 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
186 base::Bind(&UpdateEngineClientImpl::OnSetChannel
,
187 weak_ptr_factory_
.GetWeakPtr()));
190 void GetChannel(bool get_current_channel
,
191 const GetChannelCallback
& callback
) override
{
192 dbus::MethodCall
method_call(
193 update_engine::kUpdateEngineInterface
,
194 update_engine::kGetChannel
);
195 dbus::MessageWriter
writer(&method_call
);
196 writer
.AppendBool(get_current_channel
);
198 VLOG(1) << "Requesting to get channel, get_current_channel="
199 << get_current_channel
;
200 update_engine_proxy_
->CallMethod(
202 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
203 base::Bind(&UpdateEngineClientImpl::OnGetChannel
,
204 weak_ptr_factory_
.GetWeakPtr(),
209 void Init(dbus::Bus
* bus
) override
{
210 update_engine_proxy_
= bus
->GetObjectProxy(
211 update_engine::kUpdateEngineServiceName
,
212 dbus::ObjectPath(update_engine::kUpdateEngineServicePath
));
214 // Monitor the D-Bus signal for brightness changes. Only the power
215 // manager knows the actual brightness level. We don't cache the
216 // brightness level in Chrome as it will make things less reliable.
217 update_engine_proxy_
->ConnectToSignal(
218 update_engine::kUpdateEngineInterface
,
219 update_engine::kStatusUpdate
,
220 base::Bind(&UpdateEngineClientImpl::StatusUpdateReceived
,
221 weak_ptr_factory_
.GetWeakPtr()),
222 base::Bind(&UpdateEngineClientImpl::StatusUpdateConnected
,
223 weak_ptr_factory_
.GetWeakPtr()));
225 // Get update engine status for the initial status. Update engine won't
226 // send StatusUpdate signal unless there is a status change. If chrome
227 // crashes after UPDATE_STATUS_UPDATED_NEED_REBOOT status is set,
228 // restarted chrome would not get this status. See crbug.com/154104.
229 GetUpdateEngineStatus();
233 void GetUpdateEngineStatus() {
234 dbus::MethodCall
method_call(
235 update_engine::kUpdateEngineInterface
,
236 update_engine::kGetStatus
);
237 update_engine_proxy_
->CallMethodWithErrorCallback(
239 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
240 base::Bind(&UpdateEngineClientImpl::OnGetStatus
,
241 weak_ptr_factory_
.GetWeakPtr()),
242 base::Bind(&UpdateEngineClientImpl::OnGetStatusError
,
243 weak_ptr_factory_
.GetWeakPtr()));
246 // Called when a response for RequestUpdateCheck() is received.
247 void OnRequestUpdateCheck(const UpdateCheckCallback
& callback
,
248 dbus::Response
* response
) {
250 LOG(ERROR
) << "Failed to request update check";
251 callback
.Run(UPDATE_RESULT_FAILED
);
254 callback
.Run(UPDATE_RESULT_SUCCESS
);
257 // Called when a response for RebootAfterUpdate() is received.
258 void OnRebootAfterUpdate(dbus::Response
* response
) {
260 LOG(ERROR
) << "Failed to request rebooting after update";
265 // Called when a response for Rollback() is received.
266 void OnRollback(dbus::Response
* response
) {
268 LOG(ERROR
) << "Failed to rollback";
273 // Called when a response for CanRollbackCheck() is received.
274 void OnCanRollbackCheck(const RollbackCheckCallback
& callback
,
275 dbus::Response
* response
) {
277 LOG(ERROR
) << "Failed to request rollback availability status";
281 dbus::MessageReader
reader(response
);
283 if (!reader
.PopBool(&can_rollback
)) {
284 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
288 VLOG(1) << "Rollback availability status received: " << can_rollback
;
289 callback
.Run(can_rollback
);
292 // Called when a response for GetStatus is received.
293 void OnGetStatus(dbus::Response
* response
) {
295 LOG(ERROR
) << "Failed to get response for GetStatus request.";
299 dbus::MessageReader
reader(response
);
300 std::string current_operation
;
302 if (!(reader
.PopInt64(&status
.last_checked_time
) &&
303 reader
.PopDouble(&status
.download_progress
) &&
304 reader
.PopString(¤t_operation
) &&
305 reader
.PopString(&status
.new_version
) &&
306 reader
.PopInt64(&status
.new_size
))) {
307 LOG(ERROR
) << "GetStatus had incorrect response: "
308 << response
->ToString();
311 status
.status
= UpdateStatusFromString(current_operation
);
312 last_status_
= status
;
313 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(status
));
316 // Called when GetStatus call failed.
317 void OnGetStatusError(dbus::ErrorResponse
* error
) {
318 LOG(ERROR
) << "GetStatus request failed with error: "
319 << (error
? error
->ToString() : "");
322 // Called when a response for SetReleaseChannel() is received.
323 void OnSetChannel(dbus::Response
* response
) {
325 LOG(ERROR
) << "Failed to request setting channel";
328 VLOG(1) << "Succeeded to set channel";
331 // Called when a response for GetChannel() is received.
332 void OnGetChannel(const GetChannelCallback
& callback
,
333 dbus::Response
* response
) {
335 LOG(ERROR
) << "Failed to request getting channel";
339 dbus::MessageReader
reader(response
);
341 if (!reader
.PopString(&channel
)) {
342 LOG(ERROR
) << "Incorrect response: " << response
->ToString();
346 VLOG(1) << "The channel received: " << channel
;
347 callback
.Run(channel
);
350 // Called when a status update signal is received.
351 void StatusUpdateReceived(dbus::Signal
* signal
) {
352 VLOG(1) << "Status update signal received: " << signal
->ToString();
353 dbus::MessageReader
reader(signal
);
354 int64 last_checked_time
= 0;
355 double progress
= 0.0;
356 std::string current_operation
;
357 std::string new_version
;
358 int64_t new_size
= 0;
359 if (!(reader
.PopInt64(&last_checked_time
) &&
360 reader
.PopDouble(&progress
) &&
361 reader
.PopString(¤t_operation
) &&
362 reader
.PopString(&new_version
) &&
363 reader
.PopInt64(&new_size
))) {
364 LOG(ERROR
) << "Status changed signal had incorrect parameters: "
365 << signal
->ToString();
369 status
.last_checked_time
= last_checked_time
;
370 status
.download_progress
= progress
;
371 status
.status
= UpdateStatusFromString(current_operation
);
372 status
.new_version
= new_version
;
373 status
.new_size
= new_size
;
375 last_status_
= status
;
376 FOR_EACH_OBSERVER(Observer
, observers_
, UpdateStatusChanged(status
));
379 // Called when the status update signal is initially connected.
380 void StatusUpdateConnected(const std::string
& interface_name
,
381 const std::string
& signal_name
,
383 LOG_IF(WARNING
, !success
)
384 << "Failed to connect to status updated signal.";
387 dbus::ObjectProxy
* update_engine_proxy_
;
388 base::ObserverList
<Observer
> observers_
;
391 // Note: This should remain the last member so it'll be destroyed and
392 // invalidate its weak pointers before any other members are destroyed.
393 base::WeakPtrFactory
<UpdateEngineClientImpl
> weak_ptr_factory_
;
395 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl
);
398 // The UpdateEngineClient implementation used on Linux desktop,
399 // which does nothing.
400 class UpdateEngineClientStubImpl
: public UpdateEngineClient
{
402 UpdateEngineClientStubImpl()
403 : current_channel_(kReleaseChannelBeta
),
404 target_channel_(kReleaseChannelBeta
) {}
406 // UpdateEngineClient implementation:
407 void Init(dbus::Bus
* bus
) override
{}
408 void AddObserver(Observer
* observer
) override
{}
409 void RemoveObserver(Observer
* observer
) override
{}
410 bool HasObserver(const Observer
* observer
) const override
{ return false; }
412 void RequestUpdateCheck(const UpdateCheckCallback
& callback
) override
{
413 callback
.Run(UPDATE_RESULT_NOTIMPLEMENTED
);
415 void RebootAfterUpdate() override
{}
416 void Rollback() override
{}
417 void CanRollbackCheck(const RollbackCheckCallback
& callback
) override
{
420 Status
GetLastStatus() override
{ return Status(); }
421 void SetChannel(const std::string
& target_channel
,
422 bool is_powerwash_allowed
) override
{
423 VLOG(1) << "Requesting to set channel: "
424 << "target_channel=" << target_channel
<< ", "
425 << "is_powerwash_allowed=" << is_powerwash_allowed
;
426 target_channel_
= target_channel
;
428 void GetChannel(bool get_current_channel
,
429 const GetChannelCallback
& callback
) override
{
430 VLOG(1) << "Requesting to get channel, get_current_channel="
431 << get_current_channel
;
432 if (get_current_channel
)
433 callback
.Run(current_channel_
);
435 callback
.Run(target_channel_
);
438 std::string current_channel_
;
439 std::string target_channel_
;
442 // The UpdateEngineClient implementation used on Linux desktop, which
443 // tries to emulate real update engine client.
444 class UpdateEngineClientFakeImpl
: public UpdateEngineClientStubImpl
{
446 UpdateEngineClientFakeImpl() : weak_factory_(this) {
449 ~UpdateEngineClientFakeImpl() override
{}
451 // UpdateEngineClient implementation:
452 void AddObserver(Observer
* observer
) override
{
454 observers_
.AddObserver(observer
);
457 void RemoveObserver(Observer
* observer
) override
{
459 observers_
.RemoveObserver(observer
);
462 bool HasObserver(const Observer
* observer
) const override
{
463 return observers_
.HasObserver(observer
);
466 void RequestUpdateCheck(const UpdateCheckCallback
& callback
) override
{
467 if (last_status_
.status
!= UPDATE_STATUS_IDLE
) {
468 callback
.Run(UPDATE_RESULT_FAILED
);
471 callback
.Run(UPDATE_RESULT_SUCCESS
);
472 last_status_
.status
= UPDATE_STATUS_CHECKING_FOR_UPDATE
;
473 last_status_
.download_progress
= 0.0;
474 last_status_
.last_checked_time
= 0;
475 last_status_
.new_size
= 0;
476 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
477 FROM_HERE
, 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::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
522 FROM_HERE
, base::Bind(&UpdateEngineClientFakeImpl::StateTransition
,
523 weak_factory_
.GetWeakPtr()),
524 base::TimeDelta::FromMilliseconds(delay_ms
));
528 base::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