| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/service_manager.h" | 5 #include "src/service_manager.h" |
| 6 | 6 |
| 7 #include <glog/logging.h> | 7 #include <glog/logging.h> |
| 8 | 8 |
| 9 #include "src/cashew_server.h" | 9 #include "src/cashew_server.h" |
| 10 #include "src/service.h" | 10 #include "src/service.h" |
| 11 | 11 |
| 12 namespace cashew { | 12 namespace cashew { |
| 13 | 13 |
| 14 // Flimflam D-Bus indentifiers | 14 // Flimflam D-Bus indentifiers |
| 15 static const char* kFlimflamManagerName = "org.chromium.flimflam"; | 15 static const char *kFlimflamManagerName = "org.chromium.flimflam"; |
| 16 static const char* kFlimflamManagerPath = "/"; | 16 static const char *kFlimflamManagerPath = "/"; |
| 17 | 17 |
| 18 // Flimflam property names | 18 // Flimflam property names |
| 19 static const char* kServicesProperty = "Services"; | 19 static const char *kDefaultTechnologyProperty = "DefaultTechnology"; |
| 20 static const char *kServicesProperty = "Services"; |
| 21 static const char *kStateProperty = "State"; |
| 22 |
| 23 // Flimflam on-the-wire State values |
| 24 static const char *kFlimflamStateOffline = "offline"; |
| 25 static const char *kFlimflamStateConnected = "connected"; |
| 26 static const char *kFlimflamStateOnline = "online"; |
| 20 | 27 |
| 21 // Flimflam service types | 28 // Flimflam service types |
| 22 static const char* kTypeCellular = "cellular"; | 29 static const char *kTypeCellular = "cellular"; |
| 23 | 30 |
| 24 ServiceManager::ServiceManager(DBus::Connection& connection) // NOLINT | 31 ServiceManager::ServiceManager(DBus::Connection& connection) // NOLINT |
| 25 : DBus::ObjectProxy(connection, kFlimflamManagerPath, | 32 : DBus::ObjectProxy(connection, kFlimflamManagerPath, |
| 26 kFlimflamManagerName), | 33 kFlimflamManagerName), |
| 27 connection_(connection), cashew_server_(NULL) { | 34 connection_(connection), cashew_server_(NULL), |
| 35 default_technology_(Service::kTypeUnknown), |
| 36 default_cellular_service_(NULL), |
| 37 connectivity_state_(kConnectivityStateUnknown) { |
| 28 // init our state with a GetProperties() call to Flimflam | 38 // init our state with a GetProperties() call to Flimflam |
| 29 // we'll update this state by monitoring PropertyChanged signals | 39 // we'll update this state by monitoring PropertyChanged signals |
| 30 GetFlimflamServices(); | 40 GetFlimflamProperties(); |
| 31 } | 41 } |
| 32 | 42 |
| 33 ServiceManager::~ServiceManager() { | 43 ServiceManager::~ServiceManager() { |
| 44 ClearDefaultCellularService(); |
| 34 DeleteServices(&services_); | 45 DeleteServices(&services_); |
| 35 } | 46 } |
| 36 | 47 |
| 37 const Service* ServiceManager::GetService(const std::string& service_path) | 48 const Service* ServiceManager::GetService(const std::string& service_path) |
| 38 const { | 49 const { |
| 39 ServiceMap::const_iterator it = services_.find(service_path); | 50 ServiceMap::const_iterator it = services_.find(service_path); |
| 40 if (it == services_.end()) { | 51 if (it == services_.end()) { |
| 41 return NULL; | 52 return NULL; |
| 42 } | 53 } |
| 43 DCHECK(it->second != NULL); | 54 DCHECK(it->second != NULL); |
| 44 return static_cast<const Service *>(it->second); | 55 return static_cast<const Service *>(it->second); |
| 45 } | 56 } |
| 46 | 57 |
| 47 void ServiceManager::SetCashewServer(CashewServer *cashew_server) { | 58 void ServiceManager::SetCashewServer(CashewServer *cashew_server) { |
| 48 DLOG(INFO) << "SetCashewServer"; | 59 DLOG(INFO) << "SetCashewServer"; |
| 49 cashew_server_ = cashew_server; | 60 cashew_server_ = cashew_server; |
| 50 } | 61 } |
| 51 | 62 |
| 63 Service::Type ServiceManager::GetDefaultTechnology() const { |
| 64 return default_technology_; |
| 65 } |
| 66 |
| 67 ServiceManager::ConnectivityState ServiceManager::GetConnectivityState() |
| 68 const { |
| 69 return connectivity_state_; |
| 70 } |
| 71 |
| 72 // static |
| 73 bool ServiceManager::IsOfflineConnectivityState( |
| 74 ServiceManager::ConnectivityState state) { |
| 75 if (state == kConnectivityStateUnknown || |
| 76 state == kConnectivityStateOffline) { |
| 77 return true; |
| 78 } |
| 79 return false; |
| 80 } |
| 81 |
| 82 // static |
| 83 bool ServiceManager::IsOnlineConnectivityState( |
| 84 ServiceManager::ConnectivityState state) { |
| 85 if (state == kConnectivityStateConnected || |
| 86 state == kConnectivityStateOnline) { |
| 87 return true; |
| 88 } |
| 89 return false; |
| 90 } |
| 91 |
| 52 // Flimflam Manager D-Bus Proxy methods | 92 // Flimflam Manager D-Bus Proxy methods |
| 53 | 93 |
| 54 void ServiceManager::PropertyChanged(const std::string& property_name, | 94 void ServiceManager::PropertyChanged(const std::string& property_name, |
| 55 const DBus::Variant& new_value) { | 95 const DBus::Variant& new_value) { |
| 56 DLOG(INFO) << "PropertyChanged: property_name = " << property_name; | 96 DLOG(INFO) << "PropertyChanged: property_name = " << property_name; |
| 57 | 97 if (property_name == kDefaultTechnologyProperty) { |
| 58 // we only care about Services changes | 98 OnDefaultTechnologyUpdate(new_value.reader().get_string()); |
| 59 if (property_name.compare(kServicesProperty)) { | 99 } else if (property_name == kServicesProperty) { |
| 60 return; | 100 // interpret new_value as a vector of service paths |
| 101 ServicePathList paths; |
| 102 DBus::MessageIter reader = new_value.reader(); |
| 103 reader >> paths; |
| 104 OnServicesUpdate(paths); |
| 105 } else if (property_name == kStateProperty) { |
| 106 // this has its own signal, StateChanged, but just in case... |
| 107 StateChanged(new_value.reader().get_string()); |
| 108 } else { |
| 109 // we don't care about this property |
| 61 } | 110 } |
| 62 | |
| 63 // interpret new_value as a vector of service paths | |
| 64 ServicePathList paths; | |
| 65 DBus::MessageIter reader = new_value.reader(); | |
| 66 reader >> paths; | |
| 67 | |
| 68 OnServicesUpdate(paths); | |
| 69 } | 111 } |
| 70 | 112 |
| 71 void ServiceManager::StateChanged(const std::string& new_state) { | 113 void ServiceManager::StateChanged(const std::string& new_state_string) { |
| 72 DLOG(INFO) << "StateChanged: new_state = " << new_state; | 114 DLOG(INFO) << "StateChanged: new_state = " << new_state_string; |
| 73 // TODO(vlaviano): switch on state and call private onFlimflamOffline(), | 115 ConnectivityState old_state = connectivity_state_; |
| 74 // onFlimflamOnline() hooks. If we care. | 116 connectivity_state_ = ConnectivityStateFromString(new_state_string); |
| 117 // see if we're coming online or going offline |
| 118 // NOTE: we consider "unknown" to be offline |
| 119 if (IsOfflineConnectivityState(old_state) && |
| 120 IsOnlineConnectivityState(connectivity_state_)) { |
| 121 OnFlimflamOnline(); |
| 122 } else if (IsOnlineConnectivityState(old_state) && |
| 123 IsOfflineConnectivityState(connectivity_state_)) { |
| 124 OnFlimflamOffline(); |
| 125 } |
| 75 } | 126 } |
| 76 | 127 |
| 77 // Service methods | 128 // Service methods |
| 78 | 129 |
| 79 void ServiceManager::EmitDataPlansUpdate(const Service& service) { | 130 void ServiceManager::EmitDataPlansUpdate(const Service& service) { |
| 80 DLOG(INFO) << "EmitDataPlansUpdate: service = " << service.GetPath(); | 131 DLOG(INFO) << "EmitDataPlansUpdate: service = " << service.GetPath(); |
| 81 if (cashew_server_ == NULL) { | 132 if (cashew_server_ == NULL) { |
| 82 DLOG(WARNING) << "EmitDataPlansUpdate: no Cashew server"; | 133 DLOG(WARNING) << "EmitDataPlansUpdate: no Cashew server"; |
| 83 return; | 134 return; |
| 84 } | 135 } |
| 85 cashew_server_->EmitDataPlansUpdate(service); | 136 cashew_server_->EmitDataPlansUpdate(service); |
| 86 } | 137 } |
| 87 | 138 |
| 88 // Private methods | 139 // Private methods |
| 89 | 140 |
| 90 void ServiceManager::DeleteServices(ServiceMap *service_map) { | 141 void ServiceManager::DeleteServices(ServiceMap *service_map) { |
| 91 DCHECK(service_map != NULL); | 142 DCHECK(service_map != NULL); |
| 92 while (!service_map->empty()) { | 143 while (!service_map->empty()) { |
| 93 const std::string& path = | 144 const std::string& path = |
| 94 static_cast<std::string>(service_map->begin()->first); | 145 static_cast<std::string>(service_map->begin()->first); |
| 95 DLOG(INFO) << "DeleteServices: deleting service: " << path; | 146 DLOG(INFO) << "DeleteServices: deleting service: " << path; |
| 96 Service *service = static_cast<Service *>(service_map->begin()->second); | 147 Service *service = static_cast<Service *>(service_map->begin()->second); |
| 97 delete service; | 148 delete service; |
| 98 service_map->erase(service_map->begin()); | 149 service_map->erase(service_map->begin()); |
| 99 } | 150 } |
| 100 } | 151 } |
| 101 | 152 |
| 102 void ServiceManager::GetFlimflamServices() { | 153 void ServiceManager::GetFlimflamProperties() { |
| 103 DLOG(INFO) << "GetFlimflamServices"; | 154 DLOG(INFO) << "GetFlimflamProperties"; |
| 104 PropertyMap properties; | 155 PropertyMap properties; |
| 105 // dbus-c++ throws exceptions | 156 // dbus-c++ throws exceptions |
| 106 // invoke the "Existing Non-conformant Code" clause of the style guide and | 157 // invoke the "Existing Non-conformant Code" clause of the style guide and |
| 107 // isolate the rest of the system from this | 158 // isolate the rest of the system from this |
| 108 try { | 159 try { |
| 109 // TODO(vlaviano): make this call asynchronous | 160 // TODO(vlaviano): make this call asynchronous |
| 110 properties = GetProperties(); | 161 properties = GetProperties(); |
| 111 } catch (DBus::Error& error) { // NOLINT | 162 } catch (DBus::Error& error) { // NOLINT |
| 112 LOG(WARNING) << "GetFlimflamServices: GetProperties() -> Exception: " | 163 LOG(WARNING) << "GetFlimflamProperties: GetProperties() -> Exception: " |
| 113 << error.name() << ": " << error.message(); | 164 << error.name() << ": " << error.message(); |
| 114 // TODO(vlaviano): schedule another attempt later | 165 // TODO(vlaviano): schedule another attempt later |
| 115 return; | 166 return; |
| 116 } catch (...) { // NOLINT | 167 } catch (...) { // NOLINT |
| 117 LOG(WARNING) << "GetFlimflamServices: GetProperties() -> Exception"; | 168 LOG(WARNING) << "GetFlimflamProperties: GetProperties() -> Exception"; |
| 118 // TODO(vlaviano): schedule another attempt later | 169 // TODO(vlaviano): schedule another attempt later |
| 119 return; | 170 return; |
| 120 } | 171 } |
| 172 DLOG(INFO) << "GetFlimflamProperties: Received " << properties.size() |
| 173 << " properties"; |
| 121 | 174 |
| 122 // grab Services property from result | 175 // grab the properties in which we're interested |
| 123 PropertyMap::const_iterator it = properties.find(kServicesProperty); | 176 PropertyMap::const_iterator it = properties.find(kDefaultTechnologyProperty); |
| 124 if (it == properties.end()) { | 177 if (it != properties.end()) { |
| 125 DLOG(WARNING) << "GetFlimflamServices: no Services property"; | 178 const DBus::Variant& value = static_cast<DBus::Variant>(it->second); |
| 126 return; | 179 OnDefaultTechnologyUpdate(value.reader().get_string()); |
| 180 } else { |
| 181 DLOG(WARNING) << "GetFlimflamProperties: no DefaultTechnology property"; |
| 127 } | 182 } |
| 128 DBus::Variant value = static_cast<DBus::Variant>(it->second); | 183 it = properties.find(kServicesProperty); |
| 184 if (it != properties.end()) { |
| 185 const DBus::Variant& value = static_cast<DBus::Variant>(it->second); |
| 186 // interpret value as vector of service paths |
| 187 ServicePathList paths; |
| 188 DBus::MessageIter reader = value.reader(); |
| 189 reader >> paths; |
| 190 OnServicesUpdate(paths); |
| 191 } else { |
| 192 DLOG(WARNING) << "GetFlimflamProperties: no Services property"; |
| 193 } |
| 194 it = properties.find(kStateProperty); |
| 195 if (it != properties.end()) { |
| 196 const DBus::Variant& value = static_cast<DBus::Variant>(it->second); |
| 197 StateChanged(value.reader().get_string()); |
| 198 } else { |
| 199 DLOG(WARNING) << "GetFlimflamProperties: no State property"; |
| 200 } |
| 201 } |
| 129 | 202 |
| 130 // interpret value as vector of service paths | 203 void ServiceManager::OnDefaultTechnologyUpdate( |
| 131 ServicePathList paths; | 204 const std::string& default_technology) { |
| 132 DBus::MessageIter reader = value.reader(); | 205 DLOG(INFO) << "OnDefaultTechnologyUpdate: default technology = " |
| 133 reader >> paths; | 206 << default_technology; |
| 134 | 207 default_technology_ = Service::TypeFromString(default_technology); |
| 135 OnServicesUpdate(paths); | 208 if (default_technology_ == Service::kTypeUnknown) { |
| 209 LOG(WARNING) << "OnDefaultTechnologyUpdate: unknown default technology: " |
| 210 << default_technology; |
| 211 } |
| 212 if (default_technology_ != Service::kTypeCellular && |
| 213 default_cellular_service_ != NULL) { |
| 214 // if the default technology isn't cellular and yet we think that one of |
| 215 // our cellular services is the default service, then we need to update |
| 216 // our view of the world. |
| 217 ClearDefaultCellularService(); |
| 218 } |
| 136 } | 219 } |
| 137 | 220 |
| 138 void ServiceManager::OnServicesUpdate(const ServicePathList& paths) { | 221 void ServiceManager::OnServicesUpdate(const ServicePathList& paths) { |
| 139 // Remember old set of services. This is the baseline from which we will | 222 // Remember old set of services. This is the baseline from which we will |
| 140 // determine what has changed. | 223 // determine what has changed. |
| 141 ServiceMap old_services = services_; | 224 ServiceMap old_services = services_; |
| 142 services_.clear(); | 225 services_.clear(); |
| 143 | 226 |
| 144 // Flimflam service types are embedded in their path names, so we can use | 227 // Flimflam service types are embedded in their path names, so we can use |
| 145 // the pattern "/cellular_" to decide which paths are cellular services. | 228 // the pattern "/cellular_" to decide which paths are cellular services. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 165 old_services.erase(old_it); | 248 old_services.erase(old_it); |
| 166 services_[path] = service; | 249 services_[path] = service; |
| 167 } else { | 250 } else { |
| 168 // service is new: create a Service obj for it and add it to services_ | 251 // service is new: create a Service obj for it and add it to services_ |
| 169 OnNewService(path); | 252 OnNewService(path); |
| 170 } | 253 } |
| 171 } | 254 } |
| 172 | 255 |
| 173 // services left in old_services failed to appear in the update: delete them | 256 // services left in old_services failed to appear in the update: delete them |
| 174 DeleteServices(&old_services); | 257 DeleteServices(&old_services); |
| 258 |
| 259 // Flimflam always places the default service first in its list of services, |
| 260 // so we'll take a look at the first element in the paths list and see if the |
| 261 // default service has changed. Note that |paths| can be empty. We still want |
| 262 // to know about this, since it means that there is no default service. |
| 263 const DBus::Path *default_service_path = NULL; |
| 264 if (!paths.empty()) { |
| 265 default_service_path = &*paths.begin(); |
| 266 } |
| 267 OnDefaultServiceUpdate(default_service_path); |
| 175 } | 268 } |
| 176 | 269 |
| 177 void ServiceManager::OnNewService(const DBus::Path& path) { | 270 void ServiceManager::OnNewService(const DBus::Path& path) { |
| 178 DLOG(INFO) << "OnNewService: " << path; | 271 DLOG(INFO) << "OnNewService: " << path; |
| 179 DCHECK(GetService(path) == NULL); | 272 DCHECK(GetService(path) == NULL); |
| 180 Service *service = new(std::nothrow) Service(this, connection_, path); | 273 Service *service = new(std::nothrow) Service(this, connection_, path); |
| 181 if (service == NULL) { | 274 if (service == NULL) { |
| 182 LOG(ERROR) << "OnNewService: couldn't create service for " << path; | 275 LOG(ERROR) << "OnNewService: couldn't create service for " << path; |
| 183 return; | 276 return; |
| 184 } | 277 } |
| 185 services_[path] = service; | 278 services_[path] = service; |
| 186 } | 279 } |
| 187 | 280 |
| 281 void ServiceManager::OnDefaultServiceUpdate(const DBus::Path *path) { |
| 282 DLOG(INFO) << "OnDefaultServiceUpdate: new default service = " |
| 283 << ((path == NULL) ? "None" : *path); |
| 284 // check if new default service path (if any) corresponds to one of our |
| 285 // cellular services |
| 286 Service *new_default_cellular_service = NULL; |
| 287 if (path != NULL) { |
| 288 new_default_cellular_service = const_cast<Service*>(GetService(*path)); |
| 289 } |
| 290 if (new_default_cellular_service != NULL) { |
| 291 SetDefaultCellularService(new_default_cellular_service); |
| 292 } else { |
| 293 ClearDefaultCellularService(); |
| 294 } |
| 295 } |
| 296 |
| 297 void ServiceManager::ClearDefaultCellularService() { |
| 298 DLOG(INFO) << "ClearDefaultCellularService"; |
| 299 if (default_cellular_service_ != NULL) { |
| 300 DCHECK(default_cellular_service_->IsDefaultService()); |
| 301 default_cellular_service_->OnDefaultServiceUpdate(false); |
| 302 default_cellular_service_ = NULL; |
| 303 } |
| 304 } |
| 305 |
| 306 void ServiceManager::SetDefaultCellularService(Service *service) { |
| 307 DLOG(INFO) << "SetDefaultCellularService: " |
| 308 << ((service == NULL) ? "None" : service->GetPath()); |
| 309 if (default_cellular_service_ == service) { |
| 310 return; |
| 311 } |
| 312 if (default_cellular_service_ != NULL) { |
| 313 ClearDefaultCellularService(); |
| 314 } |
| 315 DCHECK(default_cellular_service_ == NULL); |
| 316 if (service != NULL) { |
| 317 DCHECK(!service->IsDefaultService()); |
| 318 service->OnDefaultServiceUpdate(true); |
| 319 default_cellular_service_ = service; |
| 320 } |
| 321 } |
| 322 |
| 323 // static |
| 324 ServiceManager::ConnectivityState ServiceManager::ConnectivityStateFromString( |
| 325 const std::string& state) { |
| 326 if (state == kFlimflamStateOffline) { |
| 327 return kConnectivityStateOffline; |
| 328 } |
| 329 if (state == kFlimflamStateConnected) { |
| 330 return kConnectivityStateConnected; |
| 331 } |
| 332 if (state == kFlimflamStateOnline) { |
| 333 return kConnectivityStateOnline; |
| 334 } |
| 335 return kConnectivityStateUnknown; |
| 336 } |
| 337 |
| 338 void ServiceManager::OnFlimflamOnline() { |
| 339 DLOG(INFO) << "OnFlimflamOnline"; |
| 340 // notify our child services |
| 341 ServiceMap::iterator it; |
| 342 for (it = services_.begin(); it != services_.end(); ++it) { |
| 343 Service *service = static_cast<Service*>(it->second); |
| 344 DCHECK(service != NULL); |
| 345 service->OnFlimflamOnline(); |
| 346 } |
| 347 } |
| 348 |
| 349 void ServiceManager::OnFlimflamOffline() { |
| 350 DLOG(INFO) << "OnFlimflamOffline"; |
| 351 // notify our child services |
| 352 ServiceMap::iterator it; |
| 353 for (it = services_.begin(); it != services_.end(); ++it) { |
| 354 Service *service = static_cast<Service*>(it->second); |
| 355 DCHECK(service != NULL); |
| 356 service->OnFlimflamOffline(); |
| 357 } |
| 358 } |
| 359 |
| 188 } // namespace cashew | 360 } // namespace cashew |
| OLD | NEW |