Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Unified Diff: src/service_manager_impl.cc

Issue 6395007: cashew: gmock integration (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/cashew.git@master
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/service_manager_impl.h ('k') | src/service_manager_mock.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/service_manager_impl.cc
diff --git a/src/service_manager_impl.cc b/src/service_manager_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1069a06b79e8a64c623c575c8f9c51556b2cb062
--- /dev/null
+++ b/src/service_manager_impl.cc
@@ -0,0 +1,453 @@
+// Copyright (c) 2010, 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/service_manager_impl.h"
+
+#include <glog/logging.h>
+
+#include "src/cashew_server.h"
+#include "src/service.h"
+
+namespace cashew {
+
+// Flimflam D-Bus indentifiers
+static const char *kFlimflamManagerName = "org.chromium.flimflam";
+static const char *kFlimflamManagerPath = "/";
+
+// Flimflam property names
+static const char *kDefaultTechnologyProperty = "DefaultTechnology";
+static const char *kServicesProperty = "Services";
+static const char *kStateProperty = "State";
+
+// Flimflam on-the-wire State values
+static const char *kFlimflamStateOffline = "offline";
+static const char *kFlimflamStateConnected = "connected";
+static const char *kFlimflamStateOnline = "online";
+
+// Flimflam service types
+static const char *kTypeCellular = "cellular";
+
+// GetFlimflamProperties retry interval
+static const guint kSecondsPerMinute = 60;
+static const guint kGetFlimflamPropertiesIntervalSeconds =
+ 1 * kSecondsPerMinute;
+
+ServiceManagerImpl::ServiceManagerImpl(DBus::Connection& connection, // NOLINT
+ GMainLoop * const main_loop)
+ : DBus::ObjectProxy(connection, kFlimflamManagerPath,
+ kFlimflamManagerName),
+ connection_(connection), main_loop_(CHECK_NOTNULL(main_loop)),
+ cashew_server_(NULL), default_technology_(Service::kTypeUnknown),
+ default_cellular_service_(NULL),
+ connectivity_state_(kConnectivityStateUnknown),
+ get_properties_source_id_(0), retrying_get_properties_(false) {
+ // schedule a GetProperties() call to Flimflam to init our state
+ // we'll keep trying periodically until we succeed
+ // we'll subsequently update this state by monitoring PropertyChanged signals
+ get_properties_source_id_ =
+ g_idle_add(StaticGetFlimflamPropertiesCallback, this);
+ if (get_properties_source_id_ == 0) {
+ LOG(ERROR) << "ctor: g_idle_add failed";
+ }
+ property_changed_handler_.delegate(this);
+}
+
+ServiceManagerImpl::~ServiceManagerImpl() {
+ DCHECK(!g_main_loop_is_running(main_loop_));
+ ClearDefaultCellularService();
+ DeleteServices(&services_);
+ if (get_properties_source_id_ != 0 &&
+ !g_source_remove(get_properties_source_id_)) {
+ DLOG(WARNING) << "dtor: g_source_remove failed";
+ }
+}
+
+const Service* ServiceManagerImpl::GetService(const std::string& service_path)
+ const {
+ ServiceMap::const_iterator it = services_.find(service_path);
+ if (it == services_.end()) {
+ return NULL;
+ }
+ DCHECK(it->second != NULL);
+ return static_cast<const Service *>(it->second);
+}
+
+void ServiceManagerImpl::SetCashewServer(CashewServer *cashew_server) {
+ DLOG(INFO) << "SetCashewServer";
+ cashew_server_ = cashew_server;
+}
+
+Service::Type ServiceManagerImpl::GetDefaultTechnology() const {
+ return default_technology_;
+}
+
+ServiceManager::ConnectivityState ServiceManagerImpl::GetConnectivityState()
+ const {
+ return connectivity_state_;
+}
+
+// static
+bool ServiceManagerImpl::IsOfflineConnectivityState(
+ ServiceManager::ConnectivityState state) {
+ if (state == kConnectivityStateUnknown ||
+ state == kConnectivityStateOffline) {
+ return true;
+ }
+ return false;
+}
+
+// static
+bool ServiceManagerImpl::IsOnlineConnectivityState(
+ ServiceManager::ConnectivityState state) {
+ if (state == kConnectivityStateConnected ||
+ state == kConnectivityStateOnline) {
+ return true;
+ }
+ return false;
+}
+
+// Flimflam Manager D-Bus Proxy methods
+
+void ServiceManagerImpl::PropertyChanged(const std::string& property_name,
+ const DBus::Variant& new_value) {
+ DLOG(INFO) << "PropertyChanged: property_name = " << property_name;
+ // Queue a tuple representing this signal for later processing from the glib
+ // main loop. We do this to avoid libdbus-c++ deadlocks that can occur when
+ // sending a dbus message from within a dbus callback like this one.
+ PropertyChangedSignal signal(property_name, new_value);
+ property_changed_handler_.EnqueueSignal(signal);
+}
+
+void ServiceManagerImpl::StateChanged(const std::string& new_state_string) {
+ DLOG(INFO) << "StateChanged: new_state_string = " << new_state_string;
+ // Queue a tuple representing this signal for later processing from the glib
+ // main loop. See comments in PropertyChanged above.
+ DBus::Variant new_value;
+ new_value.writer().append_string(new_state_string.c_str());
+ // StateChanged is a special case of PropertyChanged, so we just construct a
+ // PropertyChanged signal containing the new state info
+ PropertyChangedSignal signal(kStateProperty, new_value);
+ property_changed_handler_.EnqueueSignal(signal);
+}
+
+// PropertyChangedDelegate methods
+
+void ServiceManagerImpl::OnPropertyChanged(
+ const PropertyChangedHandler *handler,
+ const std::string& property_name,
+ const DBus::Variant& new_value) {
+ DCHECK(handler == &property_changed_handler_);
+ DLOG(INFO) << "OnPropertyChanged: property_name = " << property_name;
+ if (property_name == kDefaultTechnologyProperty) {
+ OnDefaultTechnologyUpdate(new_value.reader().get_string());
+ } else if (property_name == kServicesProperty) {
+ // interpret new_value as a vector of service paths
+ ServicePathList paths;
+ DBus::MessageIter reader = new_value.reader();
+ reader >> paths;
+ OnServicesUpdate(paths);
+ } else if (property_name == kStateProperty) {
+ OnStateUpdate(new_value.reader().get_string());
+ } else {
+ // we don't care about this property
+ }
+}
+
+// Service methods
+
+void ServiceManagerImpl::EmitDataPlansUpdate(const Service& service) {
+ DLOG(INFO) << "EmitDataPlansUpdate: service = " << service.GetPath();
+ if (cashew_server_ == NULL) {
+ DLOG(WARNING) << "EmitDataPlansUpdate: no Cashew server";
+ return;
+ }
+ cashew_server_->EmitDataPlansUpdate(service);
+}
+
+// Private methods
+
+void ServiceManagerImpl::DeleteServices(ServiceMap *service_map) {
+ DCHECK(service_map != NULL);
+ while (!service_map->empty()) {
+ const std::string& path =
+ static_cast<std::string>(service_map->begin()->first);
+ DLOG(INFO) << "DeleteServices: deleting service: " << path;
+ Service *service = static_cast<Service *>(service_map->begin()->second);
+ DCHECK(service != NULL);
+ DCHECK(service != default_cellular_service_);
+ DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL);
+ delete service;
+ service_map->erase(service_map->begin());
+ }
+}
+
+// static
+gboolean ServiceManagerImpl::StaticGetFlimflamPropertiesCallback(
+ gpointer data) {
+ ServiceManagerImpl *service_manager =
+ reinterpret_cast<ServiceManagerImpl*>(data);
+ CHECK_NOTNULL(service_manager);
+ DCHECK_NE(service_manager->get_properties_source_id_, 0);
+ if (!service_manager->GetFlimflamProperties()) {
+ // call failed, so try again later
+ DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: "
+ << "GetFlimflamProperties failed, will retry in "
+ << kGetFlimflamPropertiesIntervalSeconds << " secs";
+ // if we've arrived here from our first g_idle_add call, set up a timer
+ if (!service_manager->retrying_get_properties_) {
+ guint source_id =
+ g_timeout_add_seconds(kGetFlimflamPropertiesIntervalSeconds,
+ StaticGetFlimflamPropertiesCallback,
+ service_manager);
+ service_manager->get_properties_source_id_ = source_id;
+ if (source_id == 0) {
+ LOG(ERROR) << "StaticGetFlimflamPropertiesCallback: "
+ << "g_timeout_add_seconds failed";
+ return FALSE; // get rid of old glib source and give up
+ }
+ service_manager->retrying_get_properties_ = true;
+ // get rid of our old glib source, but our new timer will call us
+ return FALSE;
+ }
+ // otherwise, our timer is already set up
+ // return TRUE to indicate that we want to be called again later
+ return TRUE;
+ }
+ service_manager->get_properties_source_id_ = 0;
+ service_manager->retrying_get_properties_ = false;
+ return FALSE; // we succeeded, so don't repeat
+}
+
+bool ServiceManagerImpl::GetFlimflamProperties() {
+ DLOG(INFO) << "GetFlimflamProperties";
+ PropertyMap properties;
+ // dbus-c++ throws exceptions
+ // invoke the "Existing Non-conformant Code" clause of the style guide and
+ // isolate the rest of the system from this
+ try {
+ // TODO(vlaviano): make this call asynchronous
+ properties = GetProperties();
+ } catch (DBus::Error& error) { // NOLINT
+ LOG(WARNING) << "GetFlimflamProperties: GetProperties() -> Exception: "
+ << error.name() << ": " << error.message();
+ return false;
+ } catch (...) { // NOLINT
+ LOG(WARNING) << "GetFlimflamProperties: GetProperties() -> Exception";
+ return false;
+ }
+ DLOG(INFO) << "GetFlimflamProperties: Received " << properties.size()
+ << " properties";
+
+ // grab the properties in which we're interested
+ PropertyMap::const_iterator it = properties.find(kDefaultTechnologyProperty);
+ if (it != properties.end()) {
+ const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
+ OnDefaultTechnologyUpdate(value.reader().get_string());
+ } else {
+ DLOG(WARNING) << "GetFlimflamProperties: no DefaultTechnology property";
+ }
+ it = properties.find(kServicesProperty);
+ if (it != properties.end()) {
+ const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
+ // interpret value as vector of service paths
+ ServicePathList paths;
+ DBus::MessageIter reader = value.reader();
+ reader >> paths;
+ OnServicesUpdate(paths);
+ } else {
+ DLOG(WARNING) << "GetFlimflamProperties: no Services property";
+ }
+ it = properties.find(kStateProperty);
+ if (it != properties.end()) {
+ const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
+ StateChanged(value.reader().get_string());
+ } else {
+ DLOG(WARNING) << "GetFlimflamProperties: no State property";
+ }
+ return true;
+}
+
+void ServiceManagerImpl::OnStateUpdate(const std::string& new_state_string) {
+ DLOG(INFO) << "OnStateUpdate: new_state = " << new_state_string;
+ ConnectivityState old_state = connectivity_state_;
+ connectivity_state_ = ConnectivityStateFromString(new_state_string);
+ // see if we're coming online or going offline
+ // NOTE: we consider "unknown" to be offline
+ if (IsOfflineConnectivityState(old_state) &&
+ IsOnlineConnectivityState(connectivity_state_)) {
+ OnFlimflamOnline();
+ } else if (IsOnlineConnectivityState(old_state) &&
+ IsOfflineConnectivityState(connectivity_state_)) {
+ OnFlimflamOffline();
+ }
+}
+
+void ServiceManagerImpl::OnDefaultTechnologyUpdate(
+ const std::string& default_technology) {
+ DLOG(INFO) << "OnDefaultTechnologyUpdate: default technology = "
+ << default_technology;
+ default_technology_ = Service::TypeFromString(default_technology);
+ if (default_technology_ == Service::kTypeUnknown) {
+ LOG(WARNING) << "OnDefaultTechnologyUpdate: unknown default technology: "
+ << default_technology;
+ }
+ if (default_technology_ != Service::kTypeCellular &&
+ default_cellular_service_ != NULL) {
+ // if the default technology isn't cellular and yet we think that one of
+ // our cellular services is the default service, then we need to update
+ // our view of the world.
+ ClearDefaultCellularService();
+ }
+}
+
+void ServiceManagerImpl::OnServicesUpdate(const ServicePathList& paths) {
+ // Remember old set of services. This is the baseline from which we will
+ // determine what has changed.
+ ServiceMap old_services = services_;
+ services_.clear();
+
+ // Flimflam service types are embedded in their path names, so we can use
+ // the pattern "/cellular_" to decide which paths are cellular services.
+ static const std::string cellular_pattern = std::string("/") + kTypeCellular
+ + "_";
+
+ // Walk paths in this update and see if they're new to us
+ DLOG(INFO) << "OnServicesUpdate: " << paths.size() << " service paths";
+ ServicePathList::const_iterator it;
+ for (it = paths.begin(); it != paths.end(); ++it) {
+ const DBus::Path& path = *it;
+
+ // We only care about cellular services
+ if (path.find(cellular_pattern) == std::string::npos) {
+ continue;
+ }
+
+ ServiceMap::iterator old_it = old_services.find(path);
+ if (old_it != old_services.end()) {
+ // service is old: move it from old_services to services_
+ Service *service = static_cast<Service *>(old_it->second);
+ DCHECK(service != NULL);
+ old_services.erase(old_it);
+ services_[path] = service;
+ } else {
+ // service is new: create a Service obj for it and add it to services_
+ OnNewService(path);
+ }
+ }
+
+ // clear default service if it failed to appear in the update and we're
+ // about to delete it
+ if (default_cellular_service_ != NULL) {
+ ServiceMap::const_iterator it =
+ old_services.find(default_cellular_service_->GetPath());
+ if (it != old_services.end()) {
+ ClearDefaultCellularService();
+ }
+ }
+
+ // services left in old_services failed to appear in the update: delete them
+ DeleteServices(&old_services);
+
+ // Flimflam always places the default service first in its list of services,
+ // so we'll take a look at the first element in the paths list and see if the
+ // default service has changed. Note that |paths| can be empty. We still want
+ // to know about this, since it means that there is no default service.
+ const DBus::Path *default_service_path = NULL;
+ if (!paths.empty()) {
+ default_service_path = &*paths.begin();
+ }
+ OnDefaultServiceUpdate(default_service_path);
+}
+
+void ServiceManagerImpl::OnNewService(const DBus::Path& path) {
+ DLOG(INFO) << "OnNewService: " << path;
+ DCHECK(GetService(path) == NULL);
+ Service *service = Service::NewService(this, connection_, path);
+ if (service == NULL) {
+ LOG(ERROR) << "OnNewService: couldn't create service for " << path;
+ return;
+ }
+ services_[path] = service;
+}
+
+void ServiceManagerImpl::OnDefaultServiceUpdate(const DBus::Path *path) {
+ DLOG(INFO) << "OnDefaultServiceUpdate: new default service = "
+ << ((path == NULL) ? "None" : *path);
+ // check if new default service path (if any) corresponds to one of our
+ // cellular services
+ Service *new_default_cellular_service = NULL;
+ if (path != NULL) {
+ new_default_cellular_service = const_cast<Service*>(GetService(*path));
+ }
+ if (new_default_cellular_service != NULL) {
+ SetDefaultCellularService(new_default_cellular_service);
+ } else {
+ ClearDefaultCellularService();
+ }
+}
+
+void ServiceManagerImpl::ClearDefaultCellularService() {
+ DLOG(INFO) << "ClearDefaultCellularService";
+ if (default_cellular_service_ != NULL) {
+ DCHECK(default_cellular_service_->IsDefaultService());
+ default_cellular_service_->OnDefaultServiceUpdate(false);
+ default_cellular_service_ = NULL;
+ }
+}
+
+void ServiceManagerImpl::SetDefaultCellularService(Service *service) {
+ DLOG(INFO) << "SetDefaultCellularService: "
+ << ((service == NULL) ? "None" : service->GetPath());
+ if (default_cellular_service_ == service) {
+ return;
+ }
+ if (default_cellular_service_ != NULL) {
+ ClearDefaultCellularService();
+ }
+ DCHECK(default_cellular_service_ == NULL);
+ if (service != NULL) {
+ DCHECK(!service->IsDefaultService());
+ service->OnDefaultServiceUpdate(true);
+ default_cellular_service_ = service;
+ }
+}
+
+// static
+ServiceManager::ConnectivityState
+ServiceManagerImpl::ConnectivityStateFromString(const std::string& state) {
+ if (state == kFlimflamStateOffline) {
+ return kConnectivityStateOffline;
+ }
+ if (state == kFlimflamStateConnected) {
+ return kConnectivityStateConnected;
+ }
+ if (state == kFlimflamStateOnline) {
+ return kConnectivityStateOnline;
+ }
+ return kConnectivityStateUnknown;
+}
+
+void ServiceManagerImpl::OnFlimflamOnline() {
+ DLOG(INFO) << "OnFlimflamOnline";
+ // notify our child services
+ ServiceMap::iterator it;
+ for (it = services_.begin(); it != services_.end(); ++it) {
+ Service *service = static_cast<Service*>(it->second);
+ DCHECK(service != NULL);
+ service->OnFlimflamOnline();
+ }
+}
+
+void ServiceManagerImpl::OnFlimflamOffline() {
+ DLOG(INFO) << "OnFlimflamOffline";
+ // notify our child services
+ ServiceMap::iterator it;
+ for (it = services_.begin(); it != services_.end(); ++it) {
+ Service *service = static_cast<Service*>(it->second);
+ DCHECK(service != NULL);
+ service->OnFlimflamOffline();
+ }
+}
+
+} // namespace cashew
« no previous file with comments | « src/service_manager_impl.h ('k') | src/service_manager_mock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698