| 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" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 static const char *kFlimflamStateOnline = "online"; | 26 static const char *kFlimflamStateOnline = "online"; |
| 27 | 27 |
| 28 // Flimflam service types | 28 // Flimflam service types |
| 29 static const char *kTypeCellular = "cellular"; | 29 static const char *kTypeCellular = "cellular"; |
| 30 | 30 |
| 31 // GetFlimflamProperties retry interval | 31 // GetFlimflamProperties retry interval |
| 32 static const guint kSecondsPerMinute = 60; | 32 static const guint kSecondsPerMinute = 60; |
| 33 static const guint kGetFlimflamPropertiesIntervalSeconds = | 33 static const guint kGetFlimflamPropertiesIntervalSeconds = |
| 34 1 * kSecondsPerMinute; | 34 1 * kSecondsPerMinute; |
| 35 | 35 |
| 36 ServiceManager::ServiceManager(DBus::Connection& connection, // NOLINT | 36 ServiceManager::ServiceManager(DBus::Connection& connection) // NOLINT |
| 37 GMainLoop * const main_loop) | |
| 38 : DBus::ObjectProxy(connection, kFlimflamManagerPath, | 37 : DBus::ObjectProxy(connection, kFlimflamManagerPath, |
| 39 kFlimflamManagerName), | 38 kFlimflamManagerName), |
| 40 connection_(connection), main_loop_(CHECK_NOTNULL(main_loop)), | 39 connection_(connection), cashew_server_(NULL), |
| 41 cashew_server_(NULL), default_technology_(Service::kTypeUnknown), | 40 default_technology_(Service::kTypeUnknown), |
| 42 default_cellular_service_(NULL), | 41 default_cellular_service_(NULL), |
| 43 connectivity_state_(kConnectivityStateUnknown), | 42 connectivity_state_(kConnectivityStateUnknown), |
| 44 get_properties_source_id_(0), retrying_get_properties_(false), | 43 get_properties_source_id_(0), retrying_get_properties_(false) { |
| 45 deferred_service_deletion_source_id_(0) { | |
| 46 // schedule a GetProperties() call to Flimflam to init our state | 44 // schedule a GetProperties() call to Flimflam to init our state |
| 47 // we'll keep trying periodically until we succeed | 45 // we'll keep trying periodically until we succeed |
| 48 // we'll subsequently update this state by monitoring PropertyChanged signals | 46 // we'll subsequently update this state by monitoring PropertyChanged signals |
| 49 get_properties_source_id_ = | 47 get_properties_source_id_ = |
| 50 g_idle_add(StaticGetFlimflamPropertiesCallback, this); | 48 g_idle_add(StaticGetFlimflamPropertiesCallback, this); |
| 51 if (get_properties_source_id_ == 0) { | 49 if (get_properties_source_id_ == 0) { |
| 52 LOG(ERROR) << "ctor: g_idle_add failed"; | 50 LOG(ERROR) << "ctor: g_idle_add failed"; |
| 53 } | 51 } |
| 54 } | 52 } |
| 55 | 53 |
| 56 ServiceManager::~ServiceManager() { | 54 ServiceManager::~ServiceManager() { |
| 57 DCHECK(!g_main_loop_is_running(main_loop_)); | |
| 58 ClearDefaultCellularService(); | 55 ClearDefaultCellularService(); |
| 59 // we're not in the main loop, so we can delete services immediately | 56 DeleteServices(&services_); |
| 60 bool defer = false; | |
| 61 DeleteServices(&services_, defer); | |
| 62 DeletePendingServices(); | |
| 63 if (get_properties_source_id_ != 0 && | 57 if (get_properties_source_id_ != 0 && |
| 64 !g_source_remove(get_properties_source_id_)) { | 58 !g_source_remove(get_properties_source_id_)) { |
| 65 DLOG(WARNING) << "dtor: g_source_remove failed for source id " | 59 DLOG(WARNING) << "dtor: g_source_remove failed"; |
| 66 << get_properties_source_id_; | |
| 67 } | |
| 68 if (deferred_service_deletion_source_id_ != 0 && | |
| 69 !g_source_remove(deferred_service_deletion_source_id_)) { | |
| 70 DLOG(WARNING) << "dtor: g_source_remove failed for source id " | |
| 71 << deferred_service_deletion_source_id_; | |
| 72 } | 60 } |
| 73 } | 61 } |
| 74 | 62 |
| 75 const Service* ServiceManager::GetService(const std::string& service_path) | 63 const Service* ServiceManager::GetService(const std::string& service_path) |
| 76 const { | 64 const { |
| 77 ServiceMap::const_iterator it = services_.find(service_path); | 65 ServiceMap::const_iterator it = services_.find(service_path); |
| 78 if (it == services_.end()) { | 66 if (it == services_.end()) { |
| 79 return NULL; | 67 return NULL; |
| 80 } | 68 } |
| 81 DCHECK(it->second != NULL); | 69 DCHECK(it->second != NULL); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 } | 162 } |
| 175 | 163 |
| 176 bool ServiceManager::RetryingGetProperties() const { | 164 bool ServiceManager::RetryingGetProperties() const { |
| 177 return retrying_get_properties_; | 165 return retrying_get_properties_; |
| 178 } | 166 } |
| 179 | 167 |
| 180 void ServiceManager::OnRetryingGetProperties(bool retrying) { | 168 void ServiceManager::OnRetryingGetProperties(bool retrying) { |
| 181 retrying_get_properties_ = retrying; | 169 retrying_get_properties_ = retrying; |
| 182 } | 170 } |
| 183 | 171 |
| 184 guint ServiceManager::GetDeferredServiceDeletionSourceId() const { | |
| 185 return deferred_service_deletion_source_id_; | |
| 186 } | |
| 187 | |
| 188 void ServiceManager::SetDeferredServiceDeletionSourceId(guint source_id) { | |
| 189 deferred_service_deletion_source_id_ = source_id; | |
| 190 } | |
| 191 | |
| 192 // Private methods | 172 // Private methods |
| 193 | 173 |
| 194 void ServiceManager::DeleteServices(ServiceMap *service_map, bool defer) { | 174 void ServiceManager::DeleteServices(ServiceMap *service_map) { |
| 195 DLOG(INFO) << "DeleteServices: defer = " << defer; | |
| 196 DCHECK(service_map != NULL); | 175 DCHECK(service_map != NULL); |
| 197 while (!service_map->empty()) { | 176 while (!service_map->empty()) { |
| 177 const std::string& path = |
| 178 static_cast<std::string>(service_map->begin()->first); |
| 179 DLOG(INFO) << "DeleteServices: deleting service: " << path; |
| 198 Service *service = static_cast<Service *>(service_map->begin()->second); | 180 Service *service = static_cast<Service *>(service_map->begin()->second); |
| 199 DCHECK(service != NULL); | 181 DCHECK(service != NULL); |
| 200 DCHECK(service != default_cellular_service_); | 182 DCHECK(service != default_cellular_service_); |
| 201 DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL); | 183 DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL); |
| 202 if (defer) { | 184 delete service; |
| 203 DLOG(INFO) << "DeleteServices: scheduling service for later deletion: " | |
| 204 << service->GetPath(); | |
| 205 ScheduleServiceForLaterDeletion(service); | |
| 206 } else { | |
| 207 DLOG(INFO) << "DeleteServices: deleting service: " << service->GetPath(); | |
| 208 delete service; | |
| 209 } | |
| 210 service_map->erase(service_map->begin()); | 185 service_map->erase(service_map->begin()); |
| 211 } | 186 } |
| 212 } | 187 } |
| 213 | 188 |
| 214 void ServiceManager::DeletePendingServices() { | |
| 215 while (!services_pending_deletion_.empty()) { | |
| 216 Service *service = *(services_pending_deletion_.begin()); | |
| 217 DCHECK(service != NULL); | |
| 218 DLOG(INFO) << "DeletePendingServices: deleting service: " | |
| 219 << service->GetPath(); | |
| 220 DCHECK(service != default_cellular_service_); | |
| 221 delete service; | |
| 222 services_pending_deletion_.erase(services_pending_deletion_.begin()); | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 void ServiceManager::ScheduleServiceForLaterDeletion(Service *service) { | |
| 227 DCHECK(service != NULL); | |
| 228 DCHECK(service != default_cellular_service_); | |
| 229 // we might be inside of a D-Bus callback. | |
| 230 // add the service to our |services_pending_deletion_| list, and schedule a | |
| 231 // glib callback to delete these services later from the main loop if such | |
| 232 // a callback is not already scheduled | |
| 233 services_pending_deletion_.push_back(service); | |
| 234 if (deferred_service_deletion_source_id_ != 0) { | |
| 235 return; | |
| 236 } | |
| 237 deferred_service_deletion_source_id_ = | |
| 238 g_idle_add(StaticDeletePendingServicesCallback, this); | |
| 239 if (deferred_service_deletion_source_id_ == 0) { | |
| 240 LOG(ERROR) << "ScheduleServiceForLaterDeletion: g_idle_add failed"; | |
| 241 return; | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 // static | |
| 246 gboolean ServiceManager::StaticDeletePendingServicesCallback(gpointer data) { | |
| 247 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data); | |
| 248 DCHECK(service_manager != NULL); | |
| 249 DCHECK_NE(service_manager->GetDeferredServiceDeletionSourceId(), 0); | |
| 250 service_manager->DeletePendingServices(); | |
| 251 // we don't want to be run again automatically | |
| 252 // DeleteServiceOrScheduleForLaterDeletion will schedule us as needed | |
| 253 service_manager->SetDeferredServiceDeletionSourceId(0); | |
| 254 return FALSE; | |
| 255 } | |
| 256 | |
| 257 // static | 189 // static |
| 258 gboolean ServiceManager::StaticGetFlimflamPropertiesCallback(gpointer data) { | 190 gboolean ServiceManager::StaticGetFlimflamPropertiesCallback(gpointer data) { |
| 259 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data); | 191 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data); |
| 260 CHECK_NOTNULL(service_manager); | 192 CHECK_NOTNULL(service_manager); |
| 261 DCHECK_NE(service_manager->GetGetPropertiesSourceId(), 0); | 193 DCHECK_NE(service_manager->GetGetPropertiesSourceId(), 0); |
| 262 if (!service_manager->GetFlimflamProperties()) { | 194 if (!service_manager->GetFlimflamProperties()) { |
| 263 // call failed, so try again later | 195 // call failed, so try again later |
| 264 DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: " | 196 DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: " |
| 265 << "GetFlimflamProperties failed, will retry in " | 197 << "GetFlimflamProperties failed, will retry in " |
| 266 << kGetFlimflamPropertiesIntervalSeconds << " secs"; | 198 << kGetFlimflamPropertiesIntervalSeconds << " secs"; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 | 312 |
| 381 ServiceMap::iterator old_it = old_services.find(path); | 313 ServiceMap::iterator old_it = old_services.find(path); |
| 382 if (old_it != old_services.end()) { | 314 if (old_it != old_services.end()) { |
| 383 // service is old: move it from old_services to services_ | 315 // service is old: move it from old_services to services_ |
| 384 Service *service = static_cast<Service *>(old_it->second); | 316 Service *service = static_cast<Service *>(old_it->second); |
| 385 DCHECK(service != NULL); | 317 DCHECK(service != NULL); |
| 386 old_services.erase(old_it); | 318 old_services.erase(old_it); |
| 387 services_[path] = service; | 319 services_[path] = service; |
| 388 } else { | 320 } else { |
| 389 // service is new: create a Service obj for it and add it to services_ | 321 // service is new: create a Service obj for it and add it to services_ |
| 390 // TODO(vlaviano): If a service went away and came back immediately, there | |
| 391 // might still be a corresponding service object pending deletion. We | |
| 392 // could rescue it rather than allocating a new object here. | |
| 393 OnNewService(path); | 322 OnNewService(path); |
| 394 } | 323 } |
| 395 } | 324 } |
| 396 | 325 |
| 397 // clear default service if it failed to appear in the update and we're | 326 // clear default service if it failed to appear in the update and we're |
| 398 // about to delete it | 327 // about to delete it |
| 399 if (default_cellular_service_ != NULL) { | 328 if (default_cellular_service_ != NULL) { |
| 400 ServiceMap::const_iterator it = | 329 ServiceMap::const_iterator it = |
| 401 old_services.find(default_cellular_service_->GetPath()); | 330 old_services.find(default_cellular_service_->GetPath()); |
| 402 if (it != old_services.end()) { | 331 if (it != old_services.end()) { |
| 403 ClearDefaultCellularService(); | 332 ClearDefaultCellularService(); |
| 404 } | 333 } |
| 405 } | 334 } |
| 406 | 335 |
| 407 // services left in old_services failed to appear in the update: delete them | 336 // services left in old_services failed to appear in the update: delete them |
| 408 // NOTE: We're in a D-Bus callback so we can't delete these services | 337 DeleteServices(&old_services); |
| 409 // immediately without triggering a potential deadlock. We schedule them for | |
| 410 // deferred deletion. | |
| 411 bool defer = true; | |
| 412 DeleteServices(&old_services, defer); | |
| 413 | 338 |
| 414 // Flimflam always places the default service first in its list of services, | 339 // Flimflam always places the default service first in its list of services, |
| 415 // so we'll take a look at the first element in the paths list and see if the | 340 // so we'll take a look at the first element in the paths list and see if the |
| 416 // default service has changed. Note that |paths| can be empty. We still want | 341 // default service has changed. Note that |paths| can be empty. We still want |
| 417 // to know about this, since it means that there is no default service. | 342 // to know about this, since it means that there is no default service. |
| 418 const DBus::Path *default_service_path = NULL; | 343 const DBus::Path *default_service_path = NULL; |
| 419 if (!paths.empty()) { | 344 if (!paths.empty()) { |
| 420 default_service_path = &*paths.begin(); | 345 default_service_path = &*paths.begin(); |
| 421 } | 346 } |
| 422 OnDefaultServiceUpdate(default_service_path); | 347 OnDefaultServiceUpdate(default_service_path); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 // notify our child services | 431 // notify our child services |
| 507 ServiceMap::iterator it; | 432 ServiceMap::iterator it; |
| 508 for (it = services_.begin(); it != services_.end(); ++it) { | 433 for (it = services_.begin(); it != services_.end(); ++it) { |
| 509 Service *service = static_cast<Service*>(it->second); | 434 Service *service = static_cast<Service*>(it->second); |
| 510 DCHECK(service != NULL); | 435 DCHECK(service != NULL); |
| 511 service->OnFlimflamOffline(); | 436 service->OnFlimflamOffline(); |
| 512 } | 437 } |
| 513 } | 438 } |
| 514 | 439 |
| 515 } // namespace cashew | 440 } // namespace cashew |
| OLD | NEW |