| 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) |
| 37 : DBus::ObjectProxy(connection, kFlimflamManagerPath, | 38 : DBus::ObjectProxy(connection, kFlimflamManagerPath, |
| 38 kFlimflamManagerName), | 39 kFlimflamManagerName), |
| 39 connection_(connection), cashew_server_(NULL), | 40 connection_(connection), main_loop_(CHECK_NOTNULL(main_loop)), |
| 40 default_technology_(Service::kTypeUnknown), | 41 cashew_server_(NULL), default_technology_(Service::kTypeUnknown), |
| 41 default_cellular_service_(NULL), | 42 default_cellular_service_(NULL), |
| 42 connectivity_state_(kConnectivityStateUnknown), | 43 connectivity_state_(kConnectivityStateUnknown), |
| 43 get_properties_source_id_(0), retrying_get_properties_(false) { | 44 get_properties_source_id_(0), retrying_get_properties_(false), |
| 45 deferred_service_deletion_source_id_(0) { |
| 44 // schedule a GetProperties() call to Flimflam to init our state | 46 // schedule a GetProperties() call to Flimflam to init our state |
| 45 // we'll keep trying periodically until we succeed | 47 // we'll keep trying periodically until we succeed |
| 46 // we'll subsequently update this state by monitoring PropertyChanged signals | 48 // we'll subsequently update this state by monitoring PropertyChanged signals |
| 47 get_properties_source_id_ = | 49 get_properties_source_id_ = |
| 48 g_idle_add(StaticGetFlimflamPropertiesCallback, this); | 50 g_idle_add(StaticGetFlimflamPropertiesCallback, this); |
| 49 if (get_properties_source_id_ == 0) { | 51 if (get_properties_source_id_ == 0) { |
| 50 LOG(ERROR) << "ctor: g_idle_add failed"; | 52 LOG(ERROR) << "ctor: g_idle_add failed"; |
| 51 } | 53 } |
| 52 } | 54 } |
| 53 | 55 |
| 54 ServiceManager::~ServiceManager() { | 56 ServiceManager::~ServiceManager() { |
| 57 DCHECK(!g_main_loop_is_running(main_loop_)); |
| 55 ClearDefaultCellularService(); | 58 ClearDefaultCellularService(); |
| 56 DeleteServices(&services_); | 59 // we're not in the main loop, so we can delete services immediately |
| 60 bool defer = false; |
| 61 DeleteServices(&services_, defer); |
| 62 DeletePendingServices(); |
| 57 if (get_properties_source_id_ != 0 && | 63 if (get_properties_source_id_ != 0 && |
| 58 !g_source_remove(get_properties_source_id_)) { | 64 !g_source_remove(get_properties_source_id_)) { |
| 59 DLOG(WARNING) << "dtor: g_source_remove failed"; | 65 DLOG(WARNING) << "dtor: g_source_remove failed for source id " |
| 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_; |
| 60 } | 72 } |
| 61 } | 73 } |
| 62 | 74 |
| 63 const Service* ServiceManager::GetService(const std::string& service_path) | 75 const Service* ServiceManager::GetService(const std::string& service_path) |
| 64 const { | 76 const { |
| 65 ServiceMap::const_iterator it = services_.find(service_path); | 77 ServiceMap::const_iterator it = services_.find(service_path); |
| 66 if (it == services_.end()) { | 78 if (it == services_.end()) { |
| 67 return NULL; | 79 return NULL; |
| 68 } | 80 } |
| 69 DCHECK(it->second != NULL); | 81 DCHECK(it->second != NULL); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 } | 174 } |
| 163 | 175 |
| 164 bool ServiceManager::RetryingGetProperties() const { | 176 bool ServiceManager::RetryingGetProperties() const { |
| 165 return retrying_get_properties_; | 177 return retrying_get_properties_; |
| 166 } | 178 } |
| 167 | 179 |
| 168 void ServiceManager::OnRetryingGetProperties(bool retrying) { | 180 void ServiceManager::OnRetryingGetProperties(bool retrying) { |
| 169 retrying_get_properties_ = retrying; | 181 retrying_get_properties_ = retrying; |
| 170 } | 182 } |
| 171 | 183 |
| 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 |
| 172 // Private methods | 192 // Private methods |
| 173 | 193 |
| 174 void ServiceManager::DeleteServices(ServiceMap *service_map) { | 194 void ServiceManager::DeleteServices(ServiceMap *service_map, bool defer) { |
| 195 DLOG(INFO) << "DeleteServices: defer = " << defer; |
| 175 DCHECK(service_map != NULL); | 196 DCHECK(service_map != NULL); |
| 176 while (!service_map->empty()) { | 197 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; | |
| 180 Service *service = static_cast<Service *>(service_map->begin()->second); | 198 Service *service = static_cast<Service *>(service_map->begin()->second); |
| 181 DCHECK(service != NULL); | 199 DCHECK(service != NULL); |
| 182 DCHECK(service != default_cellular_service_); | 200 DCHECK(service != default_cellular_service_); |
| 183 DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL); | 201 DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL); |
| 184 delete service; | 202 if (defer) { |
| 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 } |
| 185 service_map->erase(service_map->begin()); | 210 service_map->erase(service_map->begin()); |
| 186 } | 211 } |
| 187 } | 212 } |
| 188 | 213 |
| 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 |
| 189 // static | 257 // static |
| 190 gboolean ServiceManager::StaticGetFlimflamPropertiesCallback(gpointer data) { | 258 gboolean ServiceManager::StaticGetFlimflamPropertiesCallback(gpointer data) { |
| 191 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data); | 259 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data); |
| 192 CHECK_NOTNULL(service_manager); | 260 CHECK_NOTNULL(service_manager); |
| 193 DCHECK_NE(service_manager->GetGetPropertiesSourceId(), 0); | 261 DCHECK_NE(service_manager->GetGetPropertiesSourceId(), 0); |
| 194 if (!service_manager->GetFlimflamProperties()) { | 262 if (!service_manager->GetFlimflamProperties()) { |
| 195 // call failed, so try again later | 263 // call failed, so try again later |
| 196 DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: " | 264 DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: " |
| 197 << "GetFlimflamProperties failed, will retry in " | 265 << "GetFlimflamProperties failed, will retry in " |
| 198 << kGetFlimflamPropertiesIntervalSeconds << " secs"; | 266 << kGetFlimflamPropertiesIntervalSeconds << " secs"; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 | 380 |
| 313 ServiceMap::iterator old_it = old_services.find(path); | 381 ServiceMap::iterator old_it = old_services.find(path); |
| 314 if (old_it != old_services.end()) { | 382 if (old_it != old_services.end()) { |
| 315 // service is old: move it from old_services to services_ | 383 // service is old: move it from old_services to services_ |
| 316 Service *service = static_cast<Service *>(old_it->second); | 384 Service *service = static_cast<Service *>(old_it->second); |
| 317 DCHECK(service != NULL); | 385 DCHECK(service != NULL); |
| 318 old_services.erase(old_it); | 386 old_services.erase(old_it); |
| 319 services_[path] = service; | 387 services_[path] = service; |
| 320 } else { | 388 } else { |
| 321 // service is new: create a Service obj for it and add it to services_ | 389 // 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. |
| 322 OnNewService(path); | 393 OnNewService(path); |
| 323 } | 394 } |
| 324 } | 395 } |
| 325 | 396 |
| 326 // clear default service if it failed to appear in the update and we're | 397 // clear default service if it failed to appear in the update and we're |
| 327 // about to delete it | 398 // about to delete it |
| 328 if (default_cellular_service_ != NULL) { | 399 if (default_cellular_service_ != NULL) { |
| 329 ServiceMap::const_iterator it = | 400 ServiceMap::const_iterator it = |
| 330 old_services.find(default_cellular_service_->GetPath()); | 401 old_services.find(default_cellular_service_->GetPath()); |
| 331 if (it != old_services.end()) { | 402 if (it != old_services.end()) { |
| 332 ClearDefaultCellularService(); | 403 ClearDefaultCellularService(); |
| 333 } | 404 } |
| 334 } | 405 } |
| 335 | 406 |
| 336 // services left in old_services failed to appear in the update: delete them | 407 // services left in old_services failed to appear in the update: delete them |
| 337 DeleteServices(&old_services); | 408 // NOTE: We're in a D-Bus callback so we can't delete these services |
| 409 // immediately without triggering a potential deadlock. We schedule them for |
| 410 // deferred deletion. |
| 411 bool defer = true; |
| 412 DeleteServices(&old_services, defer); |
| 338 | 413 |
| 339 // Flimflam always places the default service first in its list of services, | 414 // Flimflam always places the default service first in its list of services, |
| 340 // so we'll take a look at the first element in the paths list and see if the | 415 // so we'll take a look at the first element in the paths list and see if the |
| 341 // default service has changed. Note that |paths| can be empty. We still want | 416 // default service has changed. Note that |paths| can be empty. We still want |
| 342 // to know about this, since it means that there is no default service. | 417 // to know about this, since it means that there is no default service. |
| 343 const DBus::Path *default_service_path = NULL; | 418 const DBus::Path *default_service_path = NULL; |
| 344 if (!paths.empty()) { | 419 if (!paths.empty()) { |
| 345 default_service_path = &*paths.begin(); | 420 default_service_path = &*paths.begin(); |
| 346 } | 421 } |
| 347 OnDefaultServiceUpdate(default_service_path); | 422 OnDefaultServiceUpdate(default_service_path); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 // notify our child services | 506 // notify our child services |
| 432 ServiceMap::iterator it; | 507 ServiceMap::iterator it; |
| 433 for (it = services_.begin(); it != services_.end(); ++it) { | 508 for (it = services_.begin(); it != services_.end(); ++it) { |
| 434 Service *service = static_cast<Service*>(it->second); | 509 Service *service = static_cast<Service*>(it->second); |
| 435 DCHECK(service != NULL); | 510 DCHECK(service != NULL); |
| 436 service->OnFlimflamOffline(); | 511 service->OnFlimflamOffline(); |
| 437 } | 512 } |
| 438 } | 513 } |
| 439 | 514 |
| 440 } // namespace cashew | 515 } // namespace cashew |
| OLD | NEW |