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 <memory>
22 
23 #include <dbus/bus.h>
24 #include <update_engine/dbus-constants.h>
25 
26 #include "update_engine/update_status_utils.h"
27 
28 using dbus::Bus;
29 using org::chromium::UpdateEngineInterfaceProxy;
30 using std::string;
31 using std::unique_ptr;
32 using std::vector;
33 
34 namespace update_engine {
35 
CreateInstance()36 unique_ptr<UpdateEngineClient> UpdateEngineClient::CreateInstance() {
37   auto ret = std::make_unique<internal::DBusUpdateEngineClient>();
38   if (!ret->Init()) {
39     ret.reset();
40   }
41   return ret;
42 }
43 
44 namespace internal {
45 
46 namespace {
47 // This converts the status from Protobuf |StatusResult| to The internal
48 // |UpdateEngineStatus| struct.
ConvertToUpdateEngineStatus(const StatusResult & status,UpdateEngineStatus * out_status)49 void ConvertToUpdateEngineStatus(const StatusResult& status,
50                                  UpdateEngineStatus* out_status) {
51   out_status->last_checked_time = status.last_checked_time();
52   out_status->progress = status.progress();
53   out_status->new_version = status.new_version();
54   out_status->new_size_bytes = status.new_size();
55   out_status->status = static_cast<UpdateStatus>(status.current_operation());
56   out_status->is_enterprise_rollback = status.is_enterprise_rollback();
57   out_status->is_install = status.is_install();
58   out_status->eol_date = status.eol_date();
59   out_status->will_powerwash_after_reboot =
60       status.will_powerwash_after_reboot();
61 }
62 }  // namespace
63 
Init()64 bool DBusUpdateEngineClient::Init() {
65   Bus::Options options;
66   options.bus_type = Bus::SYSTEM;
67   scoped_refptr<Bus> bus{new Bus{options}};
68 
69   if (!bus->Connect())
70     return false;
71 
72   proxy_.reset(new UpdateEngineInterfaceProxy{bus});
73   return true;
74 }
75 
AttemptUpdate(const string & in_app_version,const string & in_omaha_url,bool at_user_request)76 bool DBusUpdateEngineClient::AttemptUpdate(const string& in_app_version,
77                                            const string& in_omaha_url,
78                                            bool at_user_request) {
79   return proxy_->AttemptUpdateWithFlags(
80       in_app_version,
81       in_omaha_url,
82       (at_user_request)
83           ? 0
84           : update_engine::UpdateAttemptFlags::kFlagNonInteractive,
85       nullptr);
86 }
87 
AttemptInstall(const string & omaha_url,const vector<string> & dlc_ids)88 bool DBusUpdateEngineClient::AttemptInstall(const string& omaha_url,
89                                             const vector<string>& dlc_ids) {
90   return proxy_->AttemptInstall(omaha_url, dlc_ids, nullptr);
91 }
92 
SetDlcActiveValue(bool is_active,const std::string & dlc_id)93 bool DBusUpdateEngineClient::SetDlcActiveValue(bool is_active,
94                                                const std::string& dlc_id) {
95   return proxy_->SetDlcActiveValue(is_active, dlc_id, /*error=*/nullptr);
96 }
97 
GetStatus(UpdateEngineStatus * out_status) const98 bool DBusUpdateEngineClient::GetStatus(UpdateEngineStatus* out_status) const {
99   StatusResult status;
100   if (!proxy_->GetStatusAdvanced(&status, nullptr)) {
101     return false;
102   }
103 
104   ConvertToUpdateEngineStatus(status, out_status);
105   return true;
106 }
107 
SetCohortHint(const string & cohort_hint)108 bool DBusUpdateEngineClient::SetCohortHint(const string& cohort_hint) {
109   return proxy_->SetCohortHint(cohort_hint, nullptr);
110 }
111 
GetCohortHint(string * cohort_hint) const112 bool DBusUpdateEngineClient::GetCohortHint(string* cohort_hint) const {
113   return proxy_->GetCohortHint(cohort_hint, nullptr);
114 }
115 
SetUpdateOverCellularPermission(bool allowed)116 bool DBusUpdateEngineClient::SetUpdateOverCellularPermission(bool allowed) {
117   return proxy_->SetUpdateOverCellularPermission(allowed, nullptr);
118 }
119 
GetUpdateOverCellularPermission(bool * allowed) const120 bool DBusUpdateEngineClient::GetUpdateOverCellularPermission(
121     bool* allowed) const {
122   return proxy_->GetUpdateOverCellularPermission(allowed, nullptr);
123 }
124 
SetP2PUpdatePermission(bool enabled)125 bool DBusUpdateEngineClient::SetP2PUpdatePermission(bool enabled) {
126   return proxy_->SetP2PUpdatePermission(enabled, nullptr);
127 }
128 
GetP2PUpdatePermission(bool * enabled) const129 bool DBusUpdateEngineClient::GetP2PUpdatePermission(bool* enabled) const {
130   return proxy_->GetP2PUpdatePermission(enabled, nullptr);
131 }
132 
Rollback(bool powerwash)133 bool DBusUpdateEngineClient::Rollback(bool powerwash) {
134   return proxy_->AttemptRollback(powerwash, nullptr);
135 }
136 
GetRollbackPartition(string * rollback_partition) const137 bool DBusUpdateEngineClient::GetRollbackPartition(
138     string* rollback_partition) const {
139   return proxy_->GetRollbackPartition(rollback_partition, nullptr);
140 }
141 
GetPrevVersion(string * prev_version) const142 bool DBusUpdateEngineClient::GetPrevVersion(string* prev_version) const {
143   return proxy_->GetPrevVersion(prev_version, nullptr);
144 }
145 
RebootIfNeeded()146 void DBusUpdateEngineClient::RebootIfNeeded() {
147   bool ret = proxy_->RebootIfNeeded(nullptr);
148   if (!ret) {
149     // Reboot error code doesn't necessarily mean that a reboot
150     // failed. For example, D-Bus may be shutdown before we receive the
151     // result.
152     LOG(INFO) << "RebootIfNeeded() failure ignored.";
153   }
154 }
155 
ResetStatus()156 bool DBusUpdateEngineClient::ResetStatus() {
157   return proxy_->ResetStatus(nullptr);
158 }
159 
DBusStatusHandlersRegistered(const string & interface,const string & signal_name,bool success) const160 void DBusUpdateEngineClient::DBusStatusHandlersRegistered(
161     const string& interface, const string& signal_name, bool success) const {
162   if (!success) {
163     for (auto handler : handlers_) {
164       handler->IPCError("Could not connect to" + signal_name + " on " +
165                         interface);
166     }
167   } else {
168     StatusUpdateHandlersRegistered(nullptr);
169   }
170 }
171 
StatusUpdateHandlersRegistered(StatusUpdateHandler * handler) const172 void DBusUpdateEngineClient::StatusUpdateHandlersRegistered(
173     StatusUpdateHandler* handler) const {
174   UpdateEngineStatus status;
175   if (!GetStatus(&status)) {
176     handler->IPCError("Could not query current status");
177     return;
178   }
179 
180   std::vector<update_engine::StatusUpdateHandler*> just_handler = {handler};
181   for (auto h : handler ? just_handler : handlers_) {
182     h->HandleStatusUpdate(status);
183   }
184 }
185 
RunStatusUpdateHandlers(const StatusResult & status)186 void DBusUpdateEngineClient::RunStatusUpdateHandlers(
187     const StatusResult& status) {
188   UpdateEngineStatus ue_status;
189   ConvertToUpdateEngineStatus(status, &ue_status);
190 
191   for (auto handler : handlers_) {
192     handler->HandleStatusUpdate(ue_status);
193   }
194 }
195 
UnregisterStatusUpdateHandler(StatusUpdateHandler * handler)196 bool DBusUpdateEngineClient::UnregisterStatusUpdateHandler(
197     StatusUpdateHandler* handler) {
198   auto it = std::find(handlers_.begin(), handlers_.end(), handler);
199   if (it != handlers_.end()) {
200     handlers_.erase(it);
201     return true;
202   }
203 
204   return false;
205 }
206 
RegisterStatusUpdateHandler(StatusUpdateHandler * handler)207 bool DBusUpdateEngineClient::RegisterStatusUpdateHandler(
208     StatusUpdateHandler* handler) {
209   if (!base::MessageLoopCurrent::IsSet()) {
210     LOG(FATAL) << "Cannot get UpdateEngineClient outside of message loop.";
211     return false;
212   }
213 
214   handlers_.push_back(handler);
215 
216   if (dbus_handler_registered_) {
217     StatusUpdateHandlersRegistered(handler);
218     return true;
219   }
220 
221   proxy_->RegisterStatusUpdateAdvancedSignalHandler(
222       base::Bind(&DBusUpdateEngineClient::RunStatusUpdateHandlers,
223                  base::Unretained(this)),
224       base::Bind(&DBusUpdateEngineClient::DBusStatusHandlersRegistered,
225                  base::Unretained(this)));
226 
227   dbus_handler_registered_ = true;
228 
229   return true;
230 }
231 
SetTargetChannel(const string & in_target_channel,bool allow_powerwash)232 bool DBusUpdateEngineClient::SetTargetChannel(const string& in_target_channel,
233                                               bool allow_powerwash) {
234   return proxy_->SetChannel(in_target_channel, allow_powerwash, nullptr);
235 }
236 
GetTargetChannel(string * out_channel) const237 bool DBusUpdateEngineClient::GetTargetChannel(string* out_channel) const {
238   return proxy_->GetChannel(false,  // Get the target channel.
239                             out_channel,
240                             nullptr);
241 }
242 
GetChannel(string * out_channel) const243 bool DBusUpdateEngineClient::GetChannel(string* out_channel) const {
244   return proxy_->GetChannel(true,  // Get the current channel.
245                             out_channel,
246                             nullptr);
247 }
248 
GetLastAttemptError(int32_t * last_attempt_error) const249 bool DBusUpdateEngineClient::GetLastAttemptError(
250     int32_t* last_attempt_error) const {
251   return proxy_->GetLastAttemptError(last_attempt_error, nullptr);
252 }
253 
254 }  // namespace internal
255 }  // namespace update_engine
256