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) ? 0 : kAttemptUpdateFlagNonInteractive, 53 nullptr); 54} 55 56bool DBusUpdateEngineClient::GetStatus(int64_t* out_last_checked_time, 57 double* out_progress, 58 UpdateStatus* out_update_status, 59 string* out_new_version, 60 int64_t* out_new_size) const { 61 string status_as_string; 62 const bool success = proxy_->GetStatus(out_last_checked_time, 63 out_progress, 64 &status_as_string, 65 out_new_version, 66 out_new_size, 67 nullptr); 68 if (!success) { 69 return false; 70 } 71 72 return StringToUpdateStatus(status_as_string, out_update_status); 73} 74 75bool DBusUpdateEngineClient::SetCohortHint(const string& cohort_hint) { 76 return proxy_->SetCohortHint(cohort_hint, nullptr); 77} 78 79bool DBusUpdateEngineClient::GetCohortHint(string* cohort_hint) const { 80 return proxy_->GetCohortHint(cohort_hint, nullptr); 81} 82 83bool DBusUpdateEngineClient::SetUpdateOverCellularPermission(bool allowed) { 84 return proxy_->SetUpdateOverCellularPermission(allowed, nullptr); 85} 86 87bool DBusUpdateEngineClient::GetUpdateOverCellularPermission( 88 bool* allowed) const { 89 return proxy_->GetUpdateOverCellularPermission(allowed, nullptr); 90} 91 92bool DBusUpdateEngineClient::SetP2PUpdatePermission(bool enabled) { 93 return proxy_->SetP2PUpdatePermission(enabled, nullptr); 94} 95 96bool DBusUpdateEngineClient::GetP2PUpdatePermission(bool* enabled) const { 97 return proxy_->GetP2PUpdatePermission(enabled, nullptr); 98} 99 100bool DBusUpdateEngineClient::Rollback(bool powerwash) { 101 return proxy_->AttemptRollback(powerwash, nullptr); 102} 103 104bool DBusUpdateEngineClient::GetRollbackPartition( 105 string* rollback_partition) const { 106 return proxy_->GetRollbackPartition(rollback_partition, nullptr); 107} 108 109bool DBusUpdateEngineClient::GetPrevVersion(string* prev_version) const { 110 return proxy_->GetPrevVersion(prev_version, nullptr); 111} 112 113void DBusUpdateEngineClient::RebootIfNeeded() { 114 bool ret = proxy_->RebootIfNeeded(nullptr); 115 if (!ret) { 116 // Reboot error code doesn't necessarily mean that a reboot 117 // failed. For example, D-Bus may be shutdown before we receive the 118 // result. 119 LOG(INFO) << "RebootIfNeeded() failure ignored."; 120 } 121} 122 123bool DBusUpdateEngineClient::ResetStatus() { 124 return proxy_->ResetStatus(nullptr); 125} 126 127void DBusUpdateEngineClient::DBusStatusHandlersRegistered( 128 const string& interface, 129 const string& signal_name, 130 bool success) const { 131 if (!success) { 132 for (auto handler : handlers_) { 133 handler->IPCError("Could not connect to" + signal_name + 134 " on " + interface); 135 } 136 } else { 137 StatusUpdateHandlersRegistered(nullptr); 138 } 139} 140 141void DBusUpdateEngineClient::StatusUpdateHandlersRegistered( 142 StatusUpdateHandler* handler) const { 143 int64_t last_checked_time; 144 double progress; 145 UpdateStatus update_status; 146 string new_version; 147 int64_t new_size; 148 149 if (!GetStatus(&last_checked_time, 150 &progress, 151 &update_status, 152 &new_version, 153 &new_size)) { 154 handler->IPCError("Could not query current status"); 155 return; 156 } 157 158 std::vector<update_engine::StatusUpdateHandler*> just_handler = {handler}; 159 for (auto h : handler ? just_handler : handlers_) { 160 h->HandleStatusUpdate( 161 last_checked_time, progress, update_status, new_version, new_size); 162 } 163} 164 165void DBusUpdateEngineClient::RunStatusUpdateHandlers( 166 int64_t last_checked_time, 167 double progress, 168 const string& current_operation, 169 const string& new_version, 170 int64_t new_size) { 171 UpdateStatus status; 172 StringToUpdateStatus(current_operation, &status); 173 174 for (auto handler : handlers_) { 175 handler->HandleStatusUpdate( 176 last_checked_time, progress, status, new_version, new_size); 177 } 178} 179 180bool DBusUpdateEngineClient::UnregisterStatusUpdateHandler( 181 StatusUpdateHandler* handler) { 182 auto it = std::find(handlers_.begin(), handlers_.end(), handler); 183 if (it != handlers_.end()) { 184 handlers_.erase(it); 185 return true; 186 } 187 188 return false; 189} 190 191bool DBusUpdateEngineClient::RegisterStatusUpdateHandler( 192 StatusUpdateHandler* handler) { 193 if (!base::MessageLoopForIO::current()) { 194 LOG(FATAL) << "Cannot get UpdateEngineClient outside of message loop."; 195 return false; 196 } 197 198 handlers_.push_back(handler); 199 200 if (dbus_handler_registered_) { 201 StatusUpdateHandlersRegistered(handler); 202 return true; 203 } 204 205 proxy_->RegisterStatusUpdateSignalHandler( 206 base::Bind(&DBusUpdateEngineClient::RunStatusUpdateHandlers, 207 base::Unretained(this)), 208 base::Bind(&DBusUpdateEngineClient::DBusStatusHandlersRegistered, 209 base::Unretained(this))); 210 211 dbus_handler_registered_ = true; 212 213 return true; 214} 215 216bool DBusUpdateEngineClient::SetTargetChannel(const string& in_target_channel, 217 bool allow_powerwash) { 218 return proxy_->SetChannel(in_target_channel, allow_powerwash, nullptr); 219} 220 221bool DBusUpdateEngineClient::GetTargetChannel(string* out_channel) const { 222 return proxy_->GetChannel(false, // Get the target channel. 223 out_channel, 224 nullptr); 225} 226 227bool DBusUpdateEngineClient::GetChannel(string* out_channel) const { 228 return proxy_->GetChannel(true, // Get the current channel. 229 out_channel, 230 nullptr); 231} 232 233bool DBusUpdateEngineClient::GetLastAttemptError( 234 int32_t* last_attempt_error) const { 235 return proxy_->GetLastAttemptError(last_attempt_error, nullptr); 236} 237 238bool DBusUpdateEngineClient::GetEolStatus(int32_t* eol_status) const { 239 return proxy_->GetEolStatus(eol_status, nullptr); 240} 241 242} // namespace internal 243} // namespace update_engine 244