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.
4
5 #include "chromeos/dbus/update_engine_client.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <string>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/location.h"
17 #include "base/logging.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_util.h"
21 #include "base/threading/thread_task_runner_handle.h"
22 #include "chromeos/dbus/constants/dbus_switches.h"
23 #include "chromeos/dbus/util/version_loader.h"
24 #include "dbus/bus.h"
25 #include "dbus/message.h"
26 #include "dbus/object_path.h"
27 #include "dbus/object_proxy.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
29
30 namespace chromeos {
31
32 namespace {
33
34 const char kReleaseChannelCanary[] = "canary-channel";
35 const char kReleaseChannelDev[] = "dev-channel";
36 const char kReleaseChannelBeta[] = "beta-channel";
37 const char kReleaseChannelStable[] = "stable-channel";
38
39 // List of release channels ordered by stability.
40 const char* kReleaseChannelsList[] = {kReleaseChannelCanary, kReleaseChannelDev,
41 kReleaseChannelBeta,
42 kReleaseChannelStable};
43
44 // Delay between successive state transitions during AU.
45 const int kStateTransitionDefaultDelayMs = 3000;
46
47 // Delay between successive notifications about downloading progress
48 // during fake AU.
49 const int kStateTransitionDownloadingDelayMs = 250;
50
51 // Size of parts of a "new" image which are downloaded each
52 // |kStateTransitionDownloadingDelayMs| during fake AU.
53 const int64_t kDownloadSizeDelta = 1 << 19;
54
55 // Version number of the image being installed during fake AU.
56 const char kStubVersion[] = "1234.0.0.0";
57
IsValidChannel(const std::string & channel)58 bool IsValidChannel(const std::string& channel) {
59 return channel == kReleaseChannelDev || channel == kReleaseChannelBeta ||
60 channel == kReleaseChannelStable;
61 }
62
63 } // namespace
64
65 // The UpdateEngineClient implementation used in production.
66 class UpdateEngineClientImpl : public UpdateEngineClient {
67 public:
UpdateEngineClientImpl()68 UpdateEngineClientImpl() : update_engine_proxy_(nullptr), last_status_() {}
69
70 ~UpdateEngineClientImpl() override = default;
71
72 // UpdateEngineClient implementation:
AddObserver(Observer * observer)73 void AddObserver(Observer* observer) override {
74 observers_.AddObserver(observer);
75 }
76
RemoveObserver(Observer * observer)77 void RemoveObserver(Observer* observer) override {
78 observers_.RemoveObserver(observer);
79 }
80
HasObserver(const Observer * observer) const81 bool HasObserver(const Observer* observer) const override {
82 return observers_.HasObserver(observer);
83 }
84
RequestUpdateCheck(UpdateCheckCallback callback)85 void RequestUpdateCheck(UpdateCheckCallback callback) override {
86 if (!service_available_) {
87 // TODO(alemate): we probably need to remember callbacks only.
88 // When service becomes available, we can do a single request,
89 // and trigger all callbacks with the same return value.
90 pending_tasks_.push_back(
91 base::BindOnce(&UpdateEngineClientImpl::RequestUpdateCheck,
92 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
93 return;
94 }
95 // TODO(crbug.com/982438): Use newer version of kAttemptUpdate instead once
96 // it was enhanced with protobuf arguments.
97 dbus::MethodCall method_call(update_engine::kUpdateEngineInterface,
98 update_engine::kAttemptUpdateWithFlags);
99 dbus::MessageWriter writer(&method_call);
100 writer.AppendString(""); // app_version
101 writer.AppendString(""); // omaha_url
102 writer.AppendInt32(0); // flags, default is 0 (interactive). See
103 // org.chromium.UpdateEngineInterface.dbus-xml.
104
105 VLOG(1) << "Requesting an update check";
106 update_engine_proxy_->CallMethod(
107 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
108 base::BindOnce(&UpdateEngineClientImpl::OnRequestUpdateCheck,
109 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
110 }
111
RebootAfterUpdate()112 void RebootAfterUpdate() override {
113 dbus::MethodCall method_call(
114 update_engine::kUpdateEngineInterface,
115 update_engine::kRebootIfNeeded);
116
117 VLOG(1) << "Requesting a reboot";
118 update_engine_proxy_->CallMethod(
119 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
120 base::BindOnce(&UpdateEngineClientImpl::OnRebootAfterUpdate,
121 weak_ptr_factory_.GetWeakPtr()));
122 }
123
Rollback()124 void Rollback() override {
125 VLOG(1) << "Requesting a rollback";
126 dbus::MethodCall method_call(
127 update_engine::kUpdateEngineInterface,
128 update_engine::kAttemptRollback);
129 dbus::MessageWriter writer(&method_call);
130 writer.AppendBool(true /* powerwash */);
131
132 update_engine_proxy_->CallMethod(
133 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
134 base::BindOnce(&UpdateEngineClientImpl::OnRollback,
135 weak_ptr_factory_.GetWeakPtr()));
136 }
137
CanRollbackCheck(RollbackCheckCallback callback)138 void CanRollbackCheck(RollbackCheckCallback callback) override {
139 dbus::MethodCall method_call(
140 update_engine::kUpdateEngineInterface,
141 update_engine::kCanRollback);
142
143 VLOG(1) << "Requesting to get rollback availability status";
144 update_engine_proxy_->CallMethod(
145 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
146 base::BindOnce(&UpdateEngineClientImpl::OnCanRollbackCheck,
147 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
148 }
149
GetLastStatus()150 update_engine::StatusResult GetLastStatus() override { return last_status_; }
151
SetChannel(const std::string & target_channel,bool is_powerwash_allowed)152 void SetChannel(const std::string& target_channel,
153 bool is_powerwash_allowed) override {
154 if (!IsValidChannel(target_channel)) {
155 LOG(ERROR) << "Invalid channel name: " << target_channel;
156 return;
157 }
158
159 dbus::MethodCall method_call(
160 update_engine::kUpdateEngineInterface,
161 update_engine::kSetChannel);
162 dbus::MessageWriter writer(&method_call);
163 writer.AppendString(target_channel);
164 writer.AppendBool(is_powerwash_allowed);
165
166 VLOG(1) << "Requesting to set channel: "
167 << "target_channel=" << target_channel << ", "
168 << "is_powerwash_allowed=" << is_powerwash_allowed;
169 update_engine_proxy_->CallMethod(
170 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
171 base::BindOnce(&UpdateEngineClientImpl::OnSetChannel,
172 weak_ptr_factory_.GetWeakPtr()));
173 }
174
GetChannel(bool get_current_channel,GetChannelCallback callback)175 void GetChannel(bool get_current_channel,
176 GetChannelCallback callback) override {
177 dbus::MethodCall method_call(
178 update_engine::kUpdateEngineInterface,
179 update_engine::kGetChannel);
180 dbus::MessageWriter writer(&method_call);
181 writer.AppendBool(get_current_channel);
182
183 VLOG(1) << "Requesting to get channel, get_current_channel="
184 << get_current_channel;
185 update_engine_proxy_->CallMethod(
186 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
187 base::BindOnce(&UpdateEngineClientImpl::OnGetChannel,
188 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
189 }
190
GetEolInfo(GetEolInfoCallback callback)191 void GetEolInfo(GetEolInfoCallback callback) override {
192 dbus::MethodCall method_call(update_engine::kUpdateEngineInterface,
193 update_engine::kGetStatusAdvanced);
194
195 VLOG(1) << "Requesting to get end of life status";
196 update_engine_proxy_->CallMethod(
197 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
198 base::BindOnce(&UpdateEngineClientImpl::OnGetEolInfo,
199 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
200 }
201
SetUpdateOverCellularPermission(bool allowed,base::OnceClosure callback)202 void SetUpdateOverCellularPermission(bool allowed,
203 base::OnceClosure callback) override {
204 dbus::MethodCall method_call(
205 update_engine::kUpdateEngineInterface,
206 update_engine::kSetUpdateOverCellularPermission);
207 dbus::MessageWriter writer(&method_call);
208 writer.AppendBool(allowed);
209
210 VLOG(1) << "Requesting UpdateEngine to " << (allowed ? "allow" : "prohibit")
211 << " updates over cellular.";
212
213 return update_engine_proxy_->CallMethod(
214 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
215 base::BindOnce(
216 &UpdateEngineClientImpl::OnSetUpdateOverCellularPermission,
217 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
218 }
219
SetUpdateOverCellularOneTimePermission(const std::string & update_version,int64_t update_size,UpdateOverCellularOneTimePermissionCallback callback)220 void SetUpdateOverCellularOneTimePermission(
221 const std::string& update_version,
222 int64_t update_size,
223 UpdateOverCellularOneTimePermissionCallback callback) override {
224 // TODO(https://crbug.com/927439): Change 'kSetUpdateOverCellularTarget' to
225 // 'kSetUpdateOverCellularOneTimePermission'
226 dbus::MethodCall method_call(update_engine::kUpdateEngineInterface,
227 update_engine::kSetUpdateOverCellularTarget);
228 dbus::MessageWriter writer(&method_call);
229 writer.AppendString(update_version);
230 writer.AppendInt64(update_size);
231
232 VLOG(1) << "Requesting UpdateEngine to allow updates over cellular "
233 << "to target version: \"" << update_version << "\" "
234 << "target_size: " << update_size;
235
236 update_engine_proxy_->CallMethod(
237 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
238 base::BindOnce(
239 &UpdateEngineClientImpl::OnSetUpdateOverCellularOneTimePermission,
240 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
241 }
242
243 protected:
Init(dbus::Bus * bus)244 void Init(dbus::Bus* bus) override {
245 update_engine_proxy_ = bus->GetObjectProxy(
246 update_engine::kUpdateEngineServiceName,
247 dbus::ObjectPath(update_engine::kUpdateEngineServicePath));
248 update_engine_proxy_->ConnectToSignal(
249 update_engine::kUpdateEngineInterface,
250 update_engine::kStatusUpdateAdvanced,
251 base::BindRepeating(&UpdateEngineClientImpl::StatusUpdateReceived,
252 weak_ptr_factory_.GetWeakPtr()),
253 base::BindOnce(&UpdateEngineClientImpl::StatusUpdateConnected,
254 weak_ptr_factory_.GetWeakPtr()));
255 update_engine_proxy_->WaitForServiceToBeAvailable(
256 base::BindOnce(&UpdateEngineClientImpl::OnServiceInitiallyAvailable,
257 weak_ptr_factory_.GetWeakPtr()));
258 }
259
260 private:
OnServiceInitiallyAvailable(bool service_is_available)261 void OnServiceInitiallyAvailable(bool service_is_available) {
262 if (service_is_available) {
263 service_available_ = true;
264 std::vector<base::OnceClosure> callbacks;
265 callbacks.swap(pending_tasks_);
266 for (auto& callback : callbacks) {
267 std::move(callback).Run();
268 }
269
270 // Get update engine status for the initial status. Update engine won't
271 // send StatusUpdate signal unless there is a status change. If chrome
272 // crashes after UPDATED_NEED_REBOOT status is set, restarted chrome would
273 // not get this status. See crbug.com/154104.
274 GetUpdateEngineStatus();
275 } else {
276 LOG(ERROR) << "Failed to wait for D-Bus service to become available";
277 pending_tasks_.clear();
278 }
279 }
280
GetUpdateEngineStatus()281 void GetUpdateEngineStatus() {
282 // TODO(crbug.com/977320): Rename the method call back to GetStatus() after
283 // the interface changed.
284 dbus::MethodCall method_call(update_engine::kUpdateEngineInterface,
285 update_engine::kGetStatusAdvanced);
286 update_engine_proxy_->CallMethodWithErrorCallback(
287 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
288 base::BindOnce(&UpdateEngineClientImpl::OnGetStatus,
289 weak_ptr_factory_.GetWeakPtr()),
290 base::BindOnce(&UpdateEngineClientImpl::OnGetStatusError,
291 weak_ptr_factory_.GetWeakPtr()));
292 }
293
294 // Called when a response for RequestUpdateCheck() is received.
OnRequestUpdateCheck(UpdateCheckCallback callback,dbus::Response * response)295 void OnRequestUpdateCheck(UpdateCheckCallback callback,
296 dbus::Response* response) {
297 if (!response) {
298 LOG(ERROR) << "Failed to request update check";
299 std::move(callback).Run(UPDATE_RESULT_FAILED);
300 return;
301 }
302 std::move(callback).Run(UPDATE_RESULT_SUCCESS);
303 }
304
305 // Called when a response for RebootAfterUpdate() is received.
OnRebootAfterUpdate(dbus::Response * response)306 void OnRebootAfterUpdate(dbus::Response* response) {
307 if (!response) {
308 LOG(ERROR) << "Failed to request rebooting after update";
309 return;
310 }
311 }
312
313 // Called when a response for Rollback() is received.
OnRollback(dbus::Response * response)314 void OnRollback(dbus::Response* response) {
315 if (!response) {
316 LOG(ERROR) << "Failed to rollback";
317 return;
318 }
319 }
320
321 // Called when a response for CanRollbackCheck() is received.
OnCanRollbackCheck(RollbackCheckCallback callback,dbus::Response * response)322 void OnCanRollbackCheck(RollbackCheckCallback callback,
323 dbus::Response* response) {
324 if (!response) {
325 LOG(ERROR) << "Failed to request rollback availability status";
326 std::move(callback).Run(false);
327 return;
328 }
329 dbus::MessageReader reader(response);
330 bool can_rollback;
331 if (!reader.PopBool(&can_rollback)) {
332 LOG(ERROR) << "Incorrect response: " << response->ToString();
333 std::move(callback).Run(false);
334 return;
335 }
336 VLOG(1) << "Rollback availability status received: " << can_rollback;
337 std::move(callback).Run(can_rollback);
338 }
339
340 // Called when a response for GetStatus is received.
OnGetStatus(dbus::Response * response)341 void OnGetStatus(dbus::Response* response) {
342 if (!response) {
343 LOG(ERROR) << "Failed to get response for GetStatus request.";
344 return;
345 }
346
347 dbus::MessageReader reader(response);
348 update_engine::StatusResult status;
349 if (!reader.PopArrayOfBytesAsProto(&status)) {
350 LOG(ERROR) << "Failed to parse proto from DBus Response.";
351 return;
352 }
353
354 last_status_ = status;
355 for (auto& observer : observers_)
356 observer.UpdateStatusChanged(status);
357 }
358
359 // Called when GetStatus call failed.
OnGetStatusError(dbus::ErrorResponse * error)360 void OnGetStatusError(dbus::ErrorResponse* error) {
361 LOG(ERROR) << "GetStatus request failed with error: "
362 << (error ? error->ToString() : "");
363 }
364
365 // Called when a response for SetReleaseChannel() is received.
OnSetChannel(dbus::Response * response)366 void OnSetChannel(dbus::Response* response) {
367 if (!response) {
368 LOG(ERROR) << "Failed to request setting channel";
369 return;
370 }
371 VLOG(1) << "Succeeded to set channel";
372 }
373
374 // Called when a response for GetChannel() is received.
OnGetChannel(GetChannelCallback callback,dbus::Response * response)375 void OnGetChannel(GetChannelCallback callback, dbus::Response* response) {
376 if (!response) {
377 LOG(ERROR) << "Failed to request getting channel";
378 std::move(callback).Run("");
379 return;
380 }
381 dbus::MessageReader reader(response);
382 std::string channel;
383 if (!reader.PopString(&channel)) {
384 LOG(ERROR) << "Incorrect response: " << response->ToString();
385 std::move(callback).Run("");
386 return;
387 }
388 VLOG(1) << "The channel received: " << channel;
389 std::move(callback).Run(channel);
390 }
391
392 // Called when a response for GetStatusAdvanced() is
393 // received.
OnGetEolInfo(GetEolInfoCallback callback,dbus::Response * response)394 void OnGetEolInfo(GetEolInfoCallback callback, dbus::Response* response) {
395 if (!response) {
396 LOG(ERROR) << "Failed to request getting eol info.";
397 std::move(callback).Run(EolInfo());
398 return;
399 }
400
401 dbus::MessageReader reader(response);
402 update_engine::StatusResult status;
403 if (!reader.PopArrayOfBytesAsProto(&status)) {
404 LOG(ERROR) << "Failed to parse proto from DBus Response.";
405 std::move(callback).Run(EolInfo());
406 return;
407 }
408
409 VLOG(1) << "Eol date received: " << status.eol_date();
410
411 EolInfo eol_info;
412 if (status.eol_date() > 0) {
413 eol_info.eol_date = base::Time::UnixEpoch() +
414 base::TimeDelta::FromDays(status.eol_date());
415 }
416 std::move(callback).Run(eol_info);
417 }
418
419 // Called when a response for SetUpdateOverCellularPermission() is received.
OnSetUpdateOverCellularPermission(base::OnceClosure callback,dbus::Response * response)420 void OnSetUpdateOverCellularPermission(base::OnceClosure callback,
421 dbus::Response* response) {
422 if (!response) {
423 LOG(ERROR) << update_engine::kSetUpdateOverCellularPermission
424 << " call failed";
425 }
426
427 // Callback should run anyway, regardless of whether DBus call to enable
428 // update over cellular succeeded or failed.
429 std::move(callback).Run();
430 }
431
432 // Called when a response for SetUpdateOverCellularOneTimePermission() is
433 // received.
OnSetUpdateOverCellularOneTimePermission(UpdateOverCellularOneTimePermissionCallback callback,dbus::Response * response)434 void OnSetUpdateOverCellularOneTimePermission(
435 UpdateOverCellularOneTimePermissionCallback callback,
436 dbus::Response* response) {
437 bool success = true;
438 if (!response) {
439 success = false;
440 LOG(ERROR) << update_engine::kSetUpdateOverCellularTarget
441 << " call failed";
442 }
443
444 if (success) {
445 for (auto& observer : observers_) {
446 observer.OnUpdateOverCellularOneTimePermissionGranted();
447 }
448 }
449
450 std::move(callback).Run(success);
451 }
452
453 // Called when a status update signal is received.
StatusUpdateReceived(dbus::Signal * signal)454 void StatusUpdateReceived(dbus::Signal* signal) {
455 VLOG(1) << "Status update signal received: " << signal->ToString();
456 dbus::MessageReader reader(signal);
457 update_engine::StatusResult status;
458 if (!reader.PopArrayOfBytesAsProto(&status)) {
459 LOG(ERROR) << "Failed to parse proto from DBus Response.";
460 return;
461 }
462
463 last_status_ = status;
464 for (auto& observer : observers_)
465 observer.UpdateStatusChanged(status);
466 }
467
468 // Called when the status update signal is initially connected.
StatusUpdateConnected(const std::string & interface_name,const std::string & signal_name,bool success)469 void StatusUpdateConnected(const std::string& interface_name,
470 const std::string& signal_name,
471 bool success) {
472 LOG_IF(WARNING, !success)
473 << "Failed to connect to status updated signal.";
474 }
475
476 dbus::ObjectProxy* update_engine_proxy_;
477 base::ObserverList<Observer>::Unchecked observers_;
478 update_engine::StatusResult last_status_;
479
480 // True after update_engine's D-Bus service has become available.
481 bool service_available_ = false;
482
483 // This is a list of postponed calls to update engine to be called
484 // after it becomes available.
485 std::vector<base::OnceClosure> pending_tasks_;
486
487 // Note: This should remain the last member so it'll be destroyed and
488 // invalidate its weak pointers before any other members are destroyed.
489 base::WeakPtrFactory<UpdateEngineClientImpl> weak_ptr_factory_{this};
490
491 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl);
492 };
493
494 // The UpdateEngineClient implementation used on Linux desktop,
495 // which does nothing.
496 class UpdateEngineClientStubImpl : public UpdateEngineClient {
497 public:
UpdateEngineClientStubImpl()498 UpdateEngineClientStubImpl()
499 : current_channel_(kReleaseChannelBeta),
500 target_channel_(kReleaseChannelBeta) {}
501
502 // UpdateEngineClient implementation:
Init(dbus::Bus * bus)503 void Init(dbus::Bus* bus) override {}
504
AddObserver(Observer * observer)505 void AddObserver(Observer* observer) override {
506 observers_.AddObserver(observer);
507 }
508
RemoveObserver(Observer * observer)509 void RemoveObserver(Observer* observer) override {
510 observers_.RemoveObserver(observer);
511 }
512
HasObserver(const Observer * observer) const513 bool HasObserver(const Observer* observer) const override {
514 return observers_.HasObserver(observer);
515 }
516
RequestUpdateCheck(UpdateCheckCallback callback)517 void RequestUpdateCheck(UpdateCheckCallback callback) override {
518 if (last_status_.current_operation() != update_engine::Operation::IDLE) {
519 std::move(callback).Run(UPDATE_RESULT_FAILED);
520 return;
521 }
522 std::move(callback).Run(UPDATE_RESULT_SUCCESS);
523 last_status_.set_current_operation(
524 update_engine::Operation::CHECKING_FOR_UPDATE);
525 last_status_.set_progress(0.0);
526 last_status_.set_last_checked_time(0);
527 last_status_.set_new_version("0.0.0.0");
528 last_status_.set_new_size(0);
529 last_status_.set_is_enterprise_rollback(false);
530 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
531 FROM_HERE,
532 base::BindOnce(&UpdateEngineClientStubImpl::StateTransition,
533 weak_factory_.GetWeakPtr()),
534 base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs));
535 }
536
RebootAfterUpdate()537 void RebootAfterUpdate() override {}
538
Rollback()539 void Rollback() override {}
540
CanRollbackCheck(RollbackCheckCallback callback)541 void CanRollbackCheck(RollbackCheckCallback callback) override {
542 std::move(callback).Run(true);
543 }
544
GetLastStatus()545 update_engine::StatusResult GetLastStatus() override { return last_status_; }
546
SetChannel(const std::string & target_channel,bool is_powerwash_allowed)547 void SetChannel(const std::string& target_channel,
548 bool is_powerwash_allowed) override {
549 VLOG(1) << "Requesting to set channel: "
550 << "target_channel=" << target_channel << ", "
551 << "is_powerwash_allowed=" << is_powerwash_allowed;
552 target_channel_ = target_channel;
553 }
GetChannel(bool get_current_channel,GetChannelCallback callback)554 void GetChannel(bool get_current_channel,
555 GetChannelCallback callback) override {
556 VLOG(1) << "Requesting to get channel, get_current_channel="
557 << get_current_channel;
558 if (get_current_channel)
559 std::move(callback).Run(current_channel_);
560 else
561 std::move(callback).Run(target_channel_);
562 }
563
GetEolInfo(GetEolInfoCallback callback)564 void GetEolInfo(GetEolInfoCallback callback) override {
565 std::move(callback).Run(EolInfo());
566 }
567
SetUpdateOverCellularPermission(bool allowed,base::OnceClosure callback)568 void SetUpdateOverCellularPermission(bool allowed,
569 base::OnceClosure callback) override {
570 std::move(callback).Run();
571 }
572
SetUpdateOverCellularOneTimePermission(const std::string & update_version,int64_t update_size,UpdateOverCellularOneTimePermissionCallback callback)573 void SetUpdateOverCellularOneTimePermission(
574 const std::string& update_version,
575 int64_t update_size,
576 UpdateOverCellularOneTimePermissionCallback callback) override {}
577
578 private:
StateTransition()579 void StateTransition() {
580 update_engine::Operation next_operation = update_engine::Operation::ERROR;
581 int delay_ms = kStateTransitionDefaultDelayMs;
582 switch (last_status_.current_operation()) {
583 case update_engine::Operation::ERROR:
584 case update_engine::Operation::IDLE:
585 case update_engine::Operation::UPDATED_NEED_REBOOT:
586 case update_engine::Operation::REPORTING_ERROR_EVENT:
587 case update_engine::Operation::ATTEMPTING_ROLLBACK:
588 case update_engine::Operation::NEED_PERMISSION_TO_UPDATE:
589 case update_engine::Operation::DISABLED:
590 return;
591 case update_engine::Operation::CHECKING_FOR_UPDATE:
592 next_operation = update_engine::Operation::UPDATE_AVAILABLE;
593 break;
594 case update_engine::Operation::UPDATE_AVAILABLE:
595 next_operation = update_engine::Operation::DOWNLOADING;
596 break;
597 case update_engine::Operation::DOWNLOADING:
598 if (last_status_.progress() >= 1.0) {
599 next_operation = update_engine::Operation::VERIFYING;
600 } else {
601 next_operation = update_engine::Operation::DOWNLOADING;
602 last_status_.set_progress(last_status_.progress() + 0.01);
603 last_status_.set_new_version(kStubVersion);
604 last_status_.set_new_size(kDownloadSizeDelta);
605 delay_ms = kStateTransitionDownloadingDelayMs;
606 }
607 break;
608 case update_engine::Operation::VERIFYING:
609 next_operation = update_engine::Operation::FINALIZING;
610 break;
611 case update_engine::Operation::FINALIZING:
612 next_operation = update_engine::Operation::UPDATED_NEED_REBOOT;
613 break;
614 default:
615 NOTREACHED();
616 }
617 last_status_.set_current_operation(next_operation);
618 for (auto& observer : observers_)
619 observer.UpdateStatusChanged(last_status_);
620 if (last_status_.current_operation() != update_engine::Operation::IDLE) {
621 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
622 FROM_HERE,
623 base::BindOnce(&UpdateEngineClientStubImpl::StateTransition,
624 weak_factory_.GetWeakPtr()),
625 base::TimeDelta::FromMilliseconds(delay_ms));
626 }
627 }
628
629 base::ObserverList<Observer>::Unchecked observers_;
630
631 std::string current_channel_;
632 std::string target_channel_;
633
634 update_engine::StatusResult last_status_;
635
636 base::WeakPtrFactory<UpdateEngineClientStubImpl> weak_factory_{this};
637
638 DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientStubImpl);
639 };
640
641 UpdateEngineClient::UpdateEngineClient() = default;
642
643 UpdateEngineClient::~UpdateEngineClient() = default;
644
645 // static
Create(DBusClientImplementationType type)646 UpdateEngineClient* UpdateEngineClient::Create(
647 DBusClientImplementationType type) {
648 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
649 return new UpdateEngineClientImpl();
650 DCHECK_EQ(FAKE_DBUS_CLIENT_IMPLEMENTATION, type);
651 return new UpdateEngineClientStubImpl();
652 }
653
654 // static
IsTargetChannelMoreStable(const std::string & current_channel,const std::string & target_channel)655 bool UpdateEngineClient::IsTargetChannelMoreStable(
656 const std::string& current_channel,
657 const std::string& target_channel) {
658 const char** cix = std::find(
659 kReleaseChannelsList,
660 kReleaseChannelsList + base::size(kReleaseChannelsList), current_channel);
661 const char** tix = std::find(
662 kReleaseChannelsList,
663 kReleaseChannelsList + base::size(kReleaseChannelsList), target_channel);
664 return tix > cix;
665 }
666
667 } // namespace chromeos
668