1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/client_library/client_dbus.h"
18
19#include <base/message_loop/message_loop.h>
20
21#include <dbus/bus.h>
22#include <update_engine/dbus-constants.h>
23
24#include "update_engine/update_status_utils.h"
25
26using chromeos_update_engine::StringToUpdateStatus;
27using dbus::Bus;
28using org::chromium::UpdateEngineInterfaceProxy;
29using std::string;
30
31namespace update_engine {
32namespace internal {
33
34bool DBusUpdateEngineClient::Init() {
35  Bus::Options options;
36  options.bus_type = Bus::SYSTEM;
37  scoped_refptr<Bus> bus{new Bus{options}};
38
39  if (!bus->Connect())
40    return false;
41
42  proxy_.reset(new UpdateEngineInterfaceProxy{bus});
43  return true;
44}
45
46bool DBusUpdateEngineClient::AttemptUpdate(const string& in_app_version,
47                                           const string& in_omaha_url,
48                                           bool at_user_request) {
49  return proxy_->AttemptUpdateWithFlags(
50      in_app_version,
51      in_omaha_url,
52      (at_user_request)
53          ? 0
54          : update_engine::UpdateAttemptFlags::kFlagNonInteractive,
55      nullptr);
56}
57
58bool DBusUpdateEngineClient::GetStatus(int64_t* out_last_checked_time,
59                                       double* out_progress,
60                                       UpdateStatus* out_update_status,
61                                       string* out_new_version,
62                                       int64_t* out_new_size) const {
63  string status_as_string;
64  const bool success = proxy_->GetStatus(out_last_checked_time,
65                                         out_progress,
66                                         &status_as_string,
67                                         out_new_version,
68                                         out_new_size,
69                                         nullptr);
70  if (!success) {
71    return false;
72  }
73
74  return StringToUpdateStatus(status_as_string, out_update_status);
75}
76
77bool DBusUpdateEngineClient::SetCohortHint(const string& cohort_hint) {
78  return proxy_->SetCohortHint(cohort_hint, nullptr);
79}
80
81bool DBusUpdateEngineClient::GetCohortHint(string* cohort_hint) const {
82  return proxy_->GetCohortHint(cohort_hint, nullptr);
83}
84
85bool DBusUpdateEngineClient::SetUpdateOverCellularPermission(bool allowed) {
86  return proxy_->SetUpdateOverCellularPermission(allowed, nullptr);
87}
88
89bool DBusUpdateEngineClient::GetUpdateOverCellularPermission(
90    bool* allowed) const {
91  return proxy_->GetUpdateOverCellularPermission(allowed, nullptr);
92}
93
94bool DBusUpdateEngineClient::SetP2PUpdatePermission(bool enabled) {
95  return proxy_->SetP2PUpdatePermission(enabled, nullptr);
96}
97
98bool DBusUpdateEngineClient::GetP2PUpdatePermission(bool* enabled) const {
99  return proxy_->GetP2PUpdatePermission(enabled, nullptr);
100}
101
102bool DBusUpdateEngineClient::Rollback(bool powerwash) {
103  return proxy_->AttemptRollback(powerwash, nullptr);
104}
105
106bool DBusUpdateEngineClient::GetRollbackPartition(
107    string* rollback_partition) const {
108  return proxy_->GetRollbackPartition(rollback_partition, nullptr);
109}
110
111bool DBusUpdateEngineClient::GetPrevVersion(string* prev_version) const {
112  return proxy_->GetPrevVersion(prev_version, nullptr);
113}
114
115void DBusUpdateEngineClient::RebootIfNeeded() {
116  bool ret = proxy_->RebootIfNeeded(nullptr);
117  if (!ret) {
118    // Reboot error code doesn't necessarily mean that a reboot
119    // failed. For example, D-Bus may be shutdown before we receive the
120    // result.
121    LOG(INFO) << "RebootIfNeeded() failure ignored.";
122  }
123}
124
125bool DBusUpdateEngineClient::ResetStatus() {
126  return proxy_->ResetStatus(nullptr);
127}
128
129void DBusUpdateEngineClient::DBusStatusHandlersRegistered(
130    const string& interface,
131    const string& signal_name,
132    bool success) const {
133  if (!success) {
134    for (auto handler : handlers_) {
135      handler->IPCError("Could not connect to" + signal_name +
136                        " on " + interface);
137    }
138  } else {
139    StatusUpdateHandlersRegistered(nullptr);
140  }
141}
142
143void DBusUpdateEngineClient::StatusUpdateHandlersRegistered(
144    StatusUpdateHandler* handler) const {
145  int64_t last_checked_time;
146  double progress;
147  UpdateStatus update_status;
148  string new_version;
149  int64_t new_size;
150
151  if (!GetStatus(&last_checked_time,
152                 &progress,
153                 &update_status,
154                 &new_version,
155                 &new_size)) {
156    handler->IPCError("Could not query current status");
157    return;
158  }
159
160  std::vector<update_engine::StatusUpdateHandler*> just_handler = {handler};
161  for (auto h : handler ? just_handler : handlers_) {
162    h->HandleStatusUpdate(
163        last_checked_time, progress, update_status, new_version, new_size);
164  }
165}
166
167void DBusUpdateEngineClient::RunStatusUpdateHandlers(
168    int64_t last_checked_time,
169    double progress,
170    const string& current_operation,
171    const string& new_version,
172    int64_t new_size) {
173  UpdateStatus status;
174  StringToUpdateStatus(current_operation, &status);
175
176  for (auto handler : handlers_) {
177    handler->HandleStatusUpdate(
178        last_checked_time, progress, status, new_version, new_size);
179  }
180}
181
182bool DBusUpdateEngineClient::UnregisterStatusUpdateHandler(
183    StatusUpdateHandler* handler) {
184  auto it = std::find(handlers_.begin(), handlers_.end(), handler);
185  if (it != handlers_.end()) {
186    handlers_.erase(it);
187    return true;
188  }
189
190  return false;
191}
192
193bool DBusUpdateEngineClient::RegisterStatusUpdateHandler(
194    StatusUpdateHandler* handler) {
195  if (!base::MessageLoopForIO::current()) {
196    LOG(FATAL) << "Cannot get UpdateEngineClient outside of message loop.";
197    return false;
198  }
199
200  handlers_.push_back(handler);
201
202  if (dbus_handler_registered_) {
203    StatusUpdateHandlersRegistered(handler);
204    return true;
205  }
206
207  proxy_->RegisterStatusUpdateSignalHandler(
208      base::Bind(&DBusUpdateEngineClient::RunStatusUpdateHandlers,
209                 base::Unretained(this)),
210      base::Bind(&DBusUpdateEngineClient::DBusStatusHandlersRegistered,
211                 base::Unretained(this)));
212
213  dbus_handler_registered_ = true;
214
215  return true;
216}
217
218bool DBusUpdateEngineClient::SetTargetChannel(const string& in_target_channel,
219                                              bool allow_powerwash) {
220  return proxy_->SetChannel(in_target_channel, allow_powerwash, nullptr);
221}
222
223bool DBusUpdateEngineClient::GetTargetChannel(string* out_channel) const {
224  return proxy_->GetChannel(false,  // Get the target channel.
225                            out_channel,
226                            nullptr);
227}
228
229bool DBusUpdateEngineClient::GetChannel(string* out_channel) const {
230  return proxy_->GetChannel(true,  // Get the current channel.
231                            out_channel,
232                            nullptr);
233}
234
235bool DBusUpdateEngineClient::GetLastAttemptError(
236    int32_t* last_attempt_error) const {
237  return proxy_->GetLastAttemptError(last_attempt_error, nullptr);
238}
239
240bool DBusUpdateEngineClient::GetEolStatus(int32_t* eol_status) const {
241  return proxy_->GetEolStatus(eol_status, nullptr);
242}
243
244}  // namespace internal
245}  // namespace update_engine
246