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