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

Unified Diff: src/service_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_impl.h ('k') | src/service_manager.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/service_impl.cc
diff --git a/src/service_impl.cc b/src/service_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..da04095e89661261ce3614a743d11a41e02bf610
--- /dev/null
+++ b/src/service_impl.cc
@@ -0,0 +1,923 @@
+// 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_impl.h"
+
+#include <glog/logging.h>
+
+#include "src/data_plan_provider.h"
+#include "src/device.h"
+#include "src/policy.h"
+#include "src/service_manager.h"
+
+namespace cashew {
+
+// Flimflam Service D-Bus identifiers
+static const char *kFlimflamServiceName = "org.chromium.flimflam";
+
+// Flimflam Service property names
+static const char *kFlimflamServiceConnectivityStateProperty =
+ "ConnectivityState";
+static const char *kFlimflamServiceDeviceProperty = "Device";
+static const char *kFlimflamServiceStateProperty = "State";
+static const char *kFlimflamServiceTypeProperty = "Type";
+static const char *kFlimflamServiceUsageUrlProperty = "Cellular.UsageUrl";
+
+// Flimflam Service on-the-wire ConnectivityState values
+static const char *kFlimflamServiceConnectivityStateUnknown = "unknown";
+static const char *kFlimflamServiceConnectivityStateRestricted = "restricted";
+static const char *kFlimflamServiceConnectivityStateUnrestricted =
+ "unrestricted";
+static const char *kFlimflamServiceConnectivityStateNone = "none";
+
+// Flimflam Service on-the-wire State values
+static const char *kFlimflamServiceStateIdle = "idle";
+static const char *kFlimflamServiceStateCarrier = "carrier";
+static const char *kFlimflamServiceStateAssociation = "association";
+static const char *kFlimflamServiceStateConfiguration = "configuration";
+static const char *kFlimflamServiceStateReady = "ready";
+static const char *kFlimflamServiceStateDisconnect = "disconnect";
+static const char *kFlimflamServiceStateFailure = "failure";
+static const char *kFlimflamServiceStateActivationFailure =
+ "activation-failure";
+
+// Flimflam Service on-the-wire Type values
+static const char *kFlimflamServiceTypeEthernet = "ethernet";
+static const char *kFlimflamServiceTypeWifi = "wifi";
+static const char *kFlimflamServiceTypeWimax = "wimax";
+static const char *kFlimflamServiceTypeBluetooth = "bluetooth";
+static const char *kFlimflamServiceTypeCellular = "cellular";
+
+// Chromium OS Usage API property names
+static const char *kCrosUsageVersionProperty = "version";
+static const char *kCrosUsageStatusProperty = "status";
+static const char *kCrosUsageRestrictedProperty = "restricted";
+static const char *kCrosUsagePlansProperty = "plans";
+
+// Chromium OS Usage API version values
+static const int kCrosUsageVersionMinSupported = 1;
+static const int kCrosUsageVersionMaxSupported = 1;
+
+// Chromium OS Usage API status values
+// NOTE: add new values to IsValidCrosUsageStatus below also
+static const char *kCrosUsageStatusOk = "OK";
+static const char *kCrosUsageStatusError = "ERROR";
+static const char *kCrosUsageStatusMalformedRequest = "MALFORMED REQUEST";
+static const char *kCrosUsageStatusInternalError = "INTERNAL ERROR";
+static const char *kCrosUsageStatusServiceUnavailable = "SERVICE UNAVAILABLE";
+static const char *kCrosUsageStatusRequestRefused = "REQUEST REFUSED";
+static const char *kCrosUsageStatusUnknownDevice = "UNKNOWN DEVICE";
+
+// GetServiceProperties retry interval
+static const guint kSecondsPerMinute = 60;
+static const guint kGetServicePropertiesIntervalSeconds = 1 * kSecondsPerMinute;
+
+ServiceImpl::ServiceImpl(ServiceManager * const parent,
+ DBus::Connection& connection, // NOLINT
+ const DBus::Path& path)
+ : DBus::ObjectProxy(connection, path, kFlimflamServiceName),
+ parent_(CHECK_NOTNULL(parent)), connection_(connection), path_(path),
+ state_(kStateUnknown), type_(kTypeUnknown), device_(NULL),
+ provider_(NULL), request_in_progress_(false),
+ update_timeout_source_(NULL), policy_(NULL),
+ is_default_service_(false), get_properties_source_id_(0),
+ retrying_get_properties_(false),
+ connectivity_state_(kConnectivityStateUnknown) {
+ // schedule a GetProperties() call to our Flimflam service path to init 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(StaticGetServicePropertiesCallback, this);
+ if (get_properties_source_id_ == 0) {
+ LOG(ERROR) << path_ << ": ctor: g_idle_add failed";
+ }
+ property_changed_handler_.delegate(this);
+}
+
+ServiceImpl::~ServiceImpl() {
+ DeleteCarrierState();
+ DeleteDataPlans(&data_plans_);
+ if (device_ != NULL) {
+ DLOG(INFO) << path_ << ": deleting device " << device_->GetPath();
+ delete device_;
+ device_ = NULL;
+ }
+ if (get_properties_source_id_ != 0 &&
+ !g_source_remove(get_properties_source_id_)) {
+ DLOG(WARNING) << path_ << ": dtor: g_source_remove failed";
+ }
+}
+
+const DBus::Path& ServiceImpl::GetPath() const {
+ return path_;
+}
+
+Service::State ServiceImpl::GetState() const {
+ return state_;
+}
+
+Service::Type ServiceImpl::GetType() const {
+ return type_;
+}
+
+// static
+Service::Type ServiceImpl::TypeFromString(const std::string& type) {
+ if (type == kFlimflamServiceTypeEthernet) {
+ return kTypeEthernet;
+ }
+ if (type == kFlimflamServiceTypeWifi) {
+ return kTypeWifi;
+ }
+ if (type == kFlimflamServiceTypeWimax) {
+ return kTypeWimax;
+ }
+ if (type == kFlimflamServiceTypeBluetooth) {
+ return kTypeBluetooth;
+ }
+ if (type == kFlimflamServiceTypeCellular) {
+ return kTypeCellular;
+ }
+ return kTypeUnknown;
+}
+
+Device* ServiceImpl::GetDevice() const {
+ return device_;
+}
+
+DBusDataPlanList ServiceImpl::GetDBusDataPlans() const {
+ DBusDataPlanList dbus_data_plans;
+ DataPlanList::const_iterator it;
+ for (it = data_plans_.begin(); it != data_plans_.end(); ++it) {
+ DataPlan *plan = *it;
+ DCHECK(plan != NULL);
+ // filter out inactive plans
+ if (plan->IsActive()) {
+ dbus_data_plans.push_back(plan->ToDBusFormat());
+ } else {
+ DLOG(INFO) << path_ << ": GetBusDataPlans: skipping inactive plan: \""
+ << plan->GetName() << "\"";
+ }
+ }
+ return dbus_data_plans;
+}
+
+bool ServiceImpl::IsDefaultService() const {
+ if (is_default_service_) {
+ // cross-check with parent's idea of default technology
+ if (parent_->GetDefaultTechnology() != kTypeCellular) {
+ DLOG(WARNING) << path_ << ": IsDefaultService: "
+ << "service manager doesn't think default technology is cellular";
+ }
+ return true;
+ }
+ return false;
+}
+
+Service::ConnectivityState ServiceImpl::GetConnectivityState() const {
+ return connectivity_state_;
+}
+
+// Flimflam Service D-Bus Proxy methods
+
+void ServiceImpl::PropertyChanged(const std::string& property_name,
+ const DBus::Variant& new_value) {
+ DLOG(INFO) << path_ << ": 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);
+}
+
+// PropertyChangedDelegate methods
+
+void ServiceImpl::OnPropertyChanged(const PropertyChangedHandler *handler,
+ const std::string& property_name,
+ const DBus::Variant& new_value) {
+ DCHECK(handler == &property_changed_handler_);
+ DLOG(INFO) << path_ << ": OnPropertyChanged: property_name = "
+ << property_name;
+ if (property_name == kFlimflamServiceDeviceProperty) {
+ OnDeviceUpdate(new_value.reader().get_path());
+ } else if (property_name == kFlimflamServiceStateProperty) {
+ OnStateUpdate(new_value.reader().get_string());
+ } else if (property_name == kFlimflamServiceTypeProperty) {
+ OnTypeUpdate(new_value.reader().get_string());
+ } else if (property_name == kFlimflamServiceUsageUrlProperty) {
+ OnUsageUrlUpdate(new_value.reader().get_string());
+ } else if (property_name == kFlimflamServiceConnectivityStateProperty) {
+ OnConnectivityStateUpdate(new_value.reader().get_string());
+ } else {
+ // we don't care about this property
+ }
+}
+
+// Device methods
+
+void ServiceImpl::OnCarrierUpdate(const std::string& carrier) {
+ DLOG(INFO) << path_ << ": OnCarrierUpdate: carrier = " << carrier;
+ DCHECK(device_ != NULL);
+ DCHECK(carrier == device_->GetCarrier());
+
+ // get rid of state associated with old carrier
+ if (provider_ != NULL) {
+ DCHECK(carrier != provider_->GetCarrier());
+ }
+ DeleteCarrierState();
+
+ // if we don't have new carrier info, we can't do anything now
+ if (carrier.empty()) {
+ return;
+ }
+
+ // create state for new carrier
+ DLOG(INFO) << path_ << ": OnCarrierUpdate: creating data plan provider";
+ provider_ = new(std::nothrow) DataPlanProvider(carrier);
+ if (provider_ == NULL) {
+ LOG(ERROR) << path_
+ << ": OnCarrierUpdate: could not create data plan provider";
+ return;
+ }
+ provider_->SetDelegate(this);
+ DLOG(INFO) << path_ << ": OnCarrierUpdate: getting policy for " << carrier;
+ policy_ = Policy::GetPolicy(carrier);
+ if (policy_ == NULL) {
+ LOG(ERROR) << path_ << ": OnCarrierUpdate: could not get policy for "
+ << carrier;
+ DeleteCarrierState();
+ return;
+ }
+
+ // if we already have usage url, set new provider in motion
+ if (!usage_url_.empty()) {
+ provider_->SetUsageUrl(usage_url_);
+ ReconsiderSendingUsageRequests();
+ } else {
+ // we'll do this later in OnUsageUrlUpdate
+ }
+}
+
+void ServiceImpl::OnByteCounterUpdate(uint64 rx_bytes, uint64 tx_bytes) {
+ DCHECK(device_ != NULL);
+ DCHECK(device_->ByteCounterRunning());
+ DLOG(INFO) << path_ << ": OnByteCounterUpdate: rx_bytes = " << rx_bytes
+ << ", tx_bytes = " << tx_bytes;
+ DataPlan *active_plan = DataPlan::GetActivePlan(data_plans_);
+ if (active_plan == NULL) {
+ DLOG(WARNING) << path_ << ": OnByteCounterUpdate: no active plan";
+ return;
+ }
+ Bytes local_bytes_used = rx_bytes + tx_bytes;
+ DLOG(INFO) << path_ << ": OnByteCounterUpdate: local_bytes_used = "
+ << local_bytes_used;
+ // try to detect two error conditions:
+ // (1) overflow of the unsigned addition above prior to the assignment
+ // (2) no overflow, but result has high order bit set and so is interpreted as
+ // a negative number when assigned to |local_bytes_used|
+ if (local_bytes_used < 0 ||
+ static_cast<uint64>(local_bytes_used) < rx_bytes ||
+ static_cast<uint64>(local_bytes_used) < tx_bytes) {
+ LOG(WARNING) << path_ << ": OnByteCounterUpdate: overflow detected";
+ return;
+ }
+ active_plan->SetLocalBytesUsed(local_bytes_used);
+ DLOG(INFO) << path_
+ << ": OnByteCounterUpdate: updated plan state: data bytes used = "
+ << active_plan->GetDataBytesUsed() << ", local bytes used = "
+ << active_plan->GetLocalBytesUsed() << ", total bytes used = "
+ << active_plan->GetTotalBytesUsed();
+ MaybeEmitDataPlansUpdate();
+}
+
+// DataPlanProviderDelegate methods
+
+void ServiceImpl::OnRequestComplete(const DataPlanProvider *provider,
+ bool successful,
+ const Value *parsed_usage_update) {
+ DCHECK(provider != NULL);
+ DCHECK(!successful || parsed_usage_update != NULL);
+ if (provider != provider_) {
+ DLOG(WARNING) << path_ << ": OnRequestComplete: wrong provider";
+ return;
+ }
+ DCHECK(request_in_progress_);
+ DCHECK(policy_ != NULL);
+ DLOG(INFO) << path_ << ": OnRequestComplete: result = " << successful;
+ request_in_progress_ = false;
+ if (!successful) {
+ LOG(WARNING) << path_ << ": OnRequestComplete: request failed";
+ return;
+ }
+
+ // interpret and validate parsed usage update
+ if (!parsed_usage_update->IsType(Value::TYPE_DICTIONARY)) {
+ LOG(WARNING) << path_
+ << ": OnRequestComplete: root value is not a dictionary";
+ return;
+ }
+ const DictionaryValue *root =
+ static_cast<const DictionaryValue*>(parsed_usage_update);
+
+ int version;
+ if (!root->GetInteger(kCrosUsageVersionProperty, &version)) {
+ LOG(WARNING) << path_ << ": OnRequestComplete: no version property";
+ return;
+ }
+ DLOG(INFO) << path_ << ": OnRequestComplete: version = " << version;
+ if (version < kCrosUsageVersionMinSupported ||
+ version > kCrosUsageVersionMaxSupported) {
+ LOG(WARNING) << path_ << ": OnRequestComplete: version " << version
+ << " not in supported range of [" << kCrosUsageVersionMinSupported
+ << ", " << kCrosUsageVersionMaxSupported << "]";
+ return;
+ }
+
+ std::string status;
+ if (!root->GetString(kCrosUsageStatusProperty, &status)) {
+ LOG(WARNING) << path_ << ": OnRequestComplete: no status property";
+ return;
+ }
+ DLOG(INFO) << path_ << ": OnRequestComplete: status = " << status;
+ if (!IsValidCrosUsageStatus(status)) {
+ LOG(WARNING) << path_ << ": OnRequestComplete: invalid status: " << status;
+ return;
+ }
+ if (status != kCrosUsageStatusOk) {
+ LOG(WARNING) << path_ << ": OnRequestComplete: status: " << status;
+ OnCrosUsageErrorResult(status);
+ return;
+ }
+
+ bool restricted = false;
+ if (root->GetBoolean(kCrosUsageRestrictedProperty, &restricted)) {
+ DLOG(INFO) << path_ << ": OnRequestComplete: restricted = " << restricted;
+ // TODO(vlaviano): this should probably be combined with flimflam's
+ // ConnectivityState property to arrive at a conclusion.
+
+ } else {
+ DLOG(INFO) << path_ << ": OnRequestComplete: no restricted property";
+ // restricted property is optional
+ }
+
+ ListValue *plans = NULL; // list to which this points is owned by dictionary
+ if (!root->GetList(kCrosUsagePlansProperty, &plans)) {
+ LOG(WARNING) << path_ << ": OnRequestComplete: no plans property";
+ return;
+ }
+ DCHECK(plans != NULL);
+ size_t plans_size = plans->GetSize();
+ DLOG(INFO) << path_ << ": OnRequestComplete: plans list has size "
+ << plans_size;
+
+ // walk plans list and convert each into a DataPlan object
+ DataPlanList new_plans;
+ for (size_t i = 0; i < plans_size; ++i) {
+ DictionaryValue *plan_dict = NULL;
+ if (!plans->GetDictionary(i, &plan_dict)) {
+ LOG(WARNING) << path_
+ << ": OnRequestComplete: could not get plan[" << i << "]";
+ continue;
+ }
+ DCHECK(plan_dict != NULL);
+ DataPlan *plan = DataPlan::FromDictionaryValue(plan_dict, policy_);
+ if (plan == NULL) {
+ LOG(WARNING) << path_
+ << ": OnRequestComplete: could not convert plan[" << i << "]";
+ continue;
+ }
+ DLOG(INFO) << path_ << ": OnRequestComplete: converted plan[" << i << "]";
+ new_plans.push_back(plan);
+ }
+
+ // store new info, causing it to be used for subsequent updates to clients
+ DataPlanList old_plans = data_plans_;
+ data_plans_ = new_plans;
+ LOG(INFO) << path_ << ": OnRequestComplete: updated data plans";
+
+ MaybeEmitDataPlansUpdate();
+
+ DLOG(INFO) << path_ << ": OnRequestComplete: deleting old data plans";
+ DeleteDataPlans(&old_plans);
+
+ // start local byte counter so that we can stop hitting usage API
+ // we'll stop the counter when we disconnect
+ // we don't bother if carrier told us that there are no active data plans
+ DataPlan *active_plan = DataPlan::GetActivePlan(data_plans_);
+ if (active_plan == NULL) {
+ DLOG(INFO) << path_
+ << ": OnRequestComplete: no active plans, not starting byte counter";
+ return;
+ }
+ DCHECK(device_ != NULL);
+ DCHECK(!device_->ByteCounterRunning());
+ if (!device_->StartByteCounter()) {
+ LOG(WARNING) << path_
+ << ": OnRequestComplete: could not start byte counter";
+ // we'll keep the update timer running and try again later
+ }
+ DLOG(INFO) << path_ << ": OnRequestComplete: started byte counter";
+ ReconsiderSendingUsageRequests();
+}
+
+// Service Manager methods
+
+void ServiceImpl::OnDefaultServiceUpdate(bool is_default_service) {
+ DCHECK(is_default_service_ == !is_default_service);
+ DLOG(INFO) << path_ << ": OnDefaultServiceUpdate: is_default_service = "
+ << is_default_service;
+ is_default_service_ = is_default_service;
+ if (is_default_service_) {
+ // we just became the default service
+ // cross-check with parent's idea of default technology
+ if (parent_->GetDefaultTechnology() != kTypeCellular) {
+ DLOG(WARNING) << path_ << ": OnDefaultServiceUpdate: "
+ << "service manager doesn't think default technology is cellular";
+ }
+ }
+ ReconsiderSendingUsageRequests();
+}
+
+void ServiceImpl::OnFlimflamOnline() {
+ DLOG(INFO) << path_ << ": OnFlimflamOnline";
+ ReconsiderSendingUsageRequests();
+}
+
+void ServiceImpl::OnFlimflamOffline() {
+ DLOG(INFO) << path_ << ": OnFlimflamOffline";
+ ReconsiderSendingUsageRequests();
+}
+
+// Private methods
+
+// static
+Service::ConnectivityState ServiceImpl::ConnectivityStateFromString(
+ const std::string& connectivity_state) {
+ if (connectivity_state == kFlimflamServiceConnectivityStateUnknown) {
+ return kConnectivityStateUnknown;
+ }
+ if (connectivity_state == kFlimflamServiceConnectivityStateRestricted) {
+ return kConnectivityStateRestricted;
+ }
+ if (connectivity_state == kFlimflamServiceConnectivityStateUnrestricted) {
+ return kConnectivityStateUnrestricted;
+ }
+ if (connectivity_state == kFlimflamServiceConnectivityStateNone) {
+ return kConnectivityStateNone;
+ }
+ return kConnectivityStateUnknown;
+}
+
+// static
+Service::State ServiceImpl::StateFromString(const std::string& state) {
+ if (state == kFlimflamServiceStateIdle) {
+ return kStateIdle;
+ }
+ if (state == kFlimflamServiceStateCarrier) {
+ return kStateCarrier;
+ }
+ if (state == kFlimflamServiceStateAssociation) {
+ return kStateAssociation;
+ }
+ if (state == kFlimflamServiceStateConfiguration) {
+ return kStateConfiguration;
+ }
+ if (state == kFlimflamServiceStateReady) {
+ return kStateReady;
+ }
+ if (state == kFlimflamServiceStateDisconnect) {
+ return kStateDisconnect;
+ }
+ if (state == kFlimflamServiceStateFailure) {
+ return kStateFailure;
+ }
+ if (state == kFlimflamServiceStateActivationFailure) {
+ return kStateActivationFailure;
+ }
+ return kStateUnknown;
+}
+
+void ServiceImpl::OnDeviceUpdate(const DBus::Path& device_path) {
+ DLOG(INFO) << path_ << ": OnDeviceUpdate: device_path = " << device_path;
+
+ // if there's an existing device with a non-matching path: destroy it and
+ // fall through to make a new one below.
+ if (device_ != NULL && device_->GetPath() != device_path) {
+ LOG(WARNING) << path_ << ": OnDeviceUpdate: device path changed from "
+ << device_->GetPath() << " to " << device_path;
+ delete device_;
+ device_ = NULL;
+ }
+
+ // if there's an existing device with matching path: all is well
+ if (device_ != NULL) {
+ return;
+ }
+
+ // if there's no existing device: make one
+ device_ = Device::NewDevice(this, connection_, device_path);
+ if (device_ == NULL) {
+ LOG(ERROR) << path_ << ": OnDeviceUpdate: couldn't create device for "
+ << device_path;
+ return;
+ }
+ DLOG(INFO) << path_ << ": OnDeviceUpdate: created device for "
+ << device_path;
+}
+
+void ServiceImpl::OnConnectivityStateUpdate(
+ const std::string& connectivity_state) {
+ DLOG(INFO) << path_ << ": OnConnectivityStateUpdate: connectivity_state = "
+ << connectivity_state;
+ Service::ConnectivityState new_connectivity_state =
+ ConnectivityStateFromString(connectivity_state);
+ if (connectivity_state_ == new_connectivity_state) {
+ return;
+ }
+ connectivity_state_ = new_connectivity_state;
+ ReconsiderSendingUsageRequests();
+}
+
+void ServiceImpl::OnStateUpdate(const std::string& state) {
+ DLOG(INFO) << path_ << ": OnStateUpdate: state = " << state;
+ Service::State old_state = state_;
+ state_ = StateFromString(state);
+ if (old_state != kStateReady && IsConnected()) {
+ OnConnected();
+ } else if (old_state == kStateReady && !IsConnected()) {
+ OnDisconnected();
+ }
+}
+
+void ServiceImpl::OnTypeUpdate(const std::string& type) {
+ DLOG(INFO) << path_ << ": OnTypeUpdate: type = " << type;
+ type_ = TypeFromString(type);
+ if (type_ != kTypeCellular) {
+ LOG(WARNING) << path_ << ": OnTypeUpdate: type is not cellular!";
+ }
+}
+
+void ServiceImpl::OnUsageUrlUpdate(const std::string& usage_url) {
+ DLOG(INFO) << path_ << ": OnUsageUrlUpdate: url = " << usage_url;
+ if (usage_url == usage_url_) {
+ return;
+ }
+ usage_url_ = usage_url;
+ if (provider_ != NULL) {
+ DCHECK(usage_url_ != provider_->GetUsageUrl());
+ StopSendingUsageRequests();
+ provider_->SetUsageUrl(usage_url_);
+ ReconsiderSendingUsageRequests();
+ }
+}
+
+// static
+gboolean ServiceImpl::StaticGetServicePropertiesCallback(gpointer data) {
+ ServiceImpl *service = reinterpret_cast<ServiceImpl*>(data);
+ CHECK_NOTNULL(service);
+ DCHECK_NE(service->get_properties_source_id_, 0);
+ if (!service->GetServiceProperties()) {
+ // call failed, so try again later
+ DLOG(WARNING) << service->GetPath()
+ << ": StaticGetServicePropertiesCallback: "
+ << "GetServiceProperties failed, will retry in "
+ << kGetServicePropertiesIntervalSeconds << " secs";
+ // if we've arrived here from our first g_idle_add call, set up a timer
+ if (!service->retrying_get_properties_) {
+ guint source_id =
+ g_timeout_add_seconds(kGetServicePropertiesIntervalSeconds,
+ StaticGetServicePropertiesCallback, service);
+ service->get_properties_source_id_ = source_id;
+ if (source_id == 0) {
+ LOG(ERROR) << service->GetPath()
+ << ": StaticGetServicePropertiesCallback: "
+ << "g_timeout_add_seconds failed";
+ return FALSE; // get rid of old glib source and give up
+ }
+ service->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->get_properties_source_id_ = 0;
+ service->retrying_get_properties_ = false;
+ return FALSE; // we succeeded, so don't repeat
+}
+
+bool ServiceImpl::GetServiceProperties() {
+ DLOG(INFO) << path_ << ": GetServiceProperties";
+ 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) << path_
+ << ": GetServiceProperties: GetProperties() -> Exception: "
+ << error.name() << ": " << error.message();
+ return false;
+ } catch (...) { // NOLINT
+ LOG(WARNING) << path_
+ << ": GetServiceProperties: GetProperties() -> Exception";
+ return false;
+ }
+ DLOG(INFO) << path_ << ": GetServiceProperties: Received "
+ << properties.size() << " properties";
+
+ // grab the properties in which we're interested
+ PropertyMap::const_iterator it;
+ it = properties.find(kFlimflamServiceDeviceProperty);
+ if (it != properties.end()) {
+ const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
+ OnDeviceUpdate(value.reader().get_path());
+ } else {
+ DLOG(WARNING) << path_ << ": GetServiceProperties: no Device property";
+ }
+ it = properties.find(kFlimflamServiceStateProperty);
+ if (it != properties.end()) {
+ const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
+ OnStateUpdate(value.reader().get_string());
+ } else {
+ DLOG(WARNING) << path_ << ": GetServiceProperties: no State property";
+ }
+ it = properties.find(kFlimflamServiceTypeProperty);
+ if (it != properties.end()) {
+ const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
+ OnTypeUpdate(value.reader().get_string());
+ } else {
+ DLOG(WARNING) << path_ << ": GetServiceProperties: no Type property";
+ }
+ // don't expect to find Cellular.* properties if we're not a cellular service
+ if (type_ != kTypeCellular) {
+ return true;
+ }
+ it = properties.find(kFlimflamServiceUsageUrlProperty);
+ if (it != properties.end()) {
+ const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
+ OnUsageUrlUpdate(value.reader().get_string());
+ } else {
+ DLOG(WARNING) << path_
+ << ": GetServiceProperties: no Cellular.UsageUrl property";
+ }
+ // flimflam docs re: ConnectivityState: "This state is currently only
+ // computed for services of type Cellular"
+ it = properties.find(kFlimflamServiceConnectivityStateProperty);
+ if (it != properties.end()) {
+ const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
+ OnConnectivityStateUpdate(value.reader().get_string());
+ } else {
+ DLOG(WARNING) << path_
+ << ": GetServiceProperties: no ConnectivityState property";
+ }
+ return true;
+}
+
+void ServiceImpl::DeleteDataPlans(DataPlanList *data_plans) {
+ DCHECK(data_plans != NULL);
+ while (!data_plans->empty()) {
+ DataPlan *plan = *data_plans->begin();
+ DCHECK(plan != NULL);
+ DLOG(INFO) << path_ << ": DeleteDataPlans: deleting plan: "
+ << plan->GetName();
+ delete plan;
+ data_plans->erase(data_plans->begin());
+ }
+}
+
+void ServiceImpl::AddHardcodedDataPlan() {
+ const std::string name = "Chromium OS Test Plan";
+ DataPlan::Type type = DataPlan::kTypeMeteredPaid;
+ base::Time update_time = base::Time::Now();
+ base::TimeDelta twelve_hours = base::TimeDelta::FromHours(12);
+ base::Time start_time = base::Time::Now() - twelve_hours;
+ base::Time end_time = base::Time::Now() + twelve_hours;
+ Bytes data_bytes_max = 100*1024*1024; // 100 MB
+ Bytes data_bytes_used = 30*1024*1024; // 30 MB
+
+ DataPlan *plan = new(std::nothrow) DataPlan(name, type, update_time,
+ start_time, end_time,
+ data_bytes_max, data_bytes_used);
+ if (plan == NULL) {
+ LOG(ERROR) << path_ << ": AddHardcodedDataPlan: could not create plan";
+ return;
+ }
+
+ data_plans_.push_back(plan);
+}
+
+void ServiceImpl::RequestUsageUpdate() {
+ DCHECK(ShouldSendUsageRequests());
+ if (request_in_progress_) {
+ DLOG(WARNING) << path_
+ << ": RequestUsageUpdate: request already in progress";
+ return;
+ }
+ request_in_progress_ = true;
+ if (!provider_->RequestUsageUpdate()) {
+ DLOG(WARNING) << path_ << ": RequestUsageUpdate: request failed";
+ request_in_progress_ = false;
+ } else {
+ DLOG(INFO) << path_ << ": RequestUsageUpdate: request succeeded";
+ }
+}
+
+void ServiceImpl::CancelPendingRequests() {
+ if (provider_ != NULL && request_in_progress_) {
+ provider_->CancelPendingRequests();
+ request_in_progress_ = false;
+ }
+}
+
+gboolean ServiceImpl::UpdateTimeoutCallback() {
+ DLOG(INFO) << path_ << ": UpdateTimeoutCallback";
+ RequestUsageUpdate();
+ return TRUE;
+}
+
+// static
+gboolean ServiceImpl::StaticUpdateTimeoutCallback(gpointer data) {
+ ServiceImpl *service = reinterpret_cast<ServiceImpl*>(data);
+ CHECK_NOTNULL(service);
+ return service->UpdateTimeoutCallback();
+}
+
+bool ServiceImpl::CreateUpdateTimer() {
+ DCHECK(provider_ != NULL);
+ DCHECK(policy_ != NULL);
+ guint idle_seconds = policy_->GetUpdateTimerIdleSecs(data_plans_);
+ DLOG(INFO) << path_ << ": CreateUpdateTimer: idle_seconds = " << idle_seconds;
+ if (update_timeout_source_ != NULL) {
+ DLOG(WARNING) << path_ << ": CreateUpdateTimer: timer already running";
+ return false;
+ }
+ update_timeout_source_ = g_timeout_source_new_seconds(idle_seconds);
+ if (update_timeout_source_ == NULL) {
+ DLOG(WARNING) << path_
+ << ": CreateUpdateTimer: could not create timeout source";
+ return false;
+ }
+ g_source_set_callback(update_timeout_source_, StaticUpdateTimeoutCallback,
+ this, NULL);
+ g_source_attach(update_timeout_source_, NULL);
+ return true;
+}
+
+void ServiceImpl::DestroyUpdateTimer() {
+ DLOG(INFO) << path_ << ": DestroyUpdateTimer";
+ if (update_timeout_source_ != NULL) {
+ g_source_destroy(update_timeout_source_);
+ update_timeout_source_ = NULL;
+ }
+}
+
+void ServiceImpl::DeleteCarrierState() {
+ DLOG(INFO) << path_ << ": DeleteCarrierState";
+ if (policy_ != NULL) {
+ DLOG(INFO) << path_ << ": DeleteCarrierState: deleting policy";
+ delete policy_;
+ policy_ = NULL;
+ }
+ StopSendingUsageRequests();
+ if (provider_ != NULL) {
+ DLOG(INFO) << path_ << ": DeleteCarrierState: deleting data plan provider";
+ delete provider_;
+ provider_ = NULL;
+ }
+}
+
+bool ServiceImpl::IsValidCrosUsageStatus(const std::string& status) const {
+ if (status == kCrosUsageStatusOk ||
+ status == kCrosUsageStatusError ||
+ status == kCrosUsageStatusMalformedRequest ||
+ status == kCrosUsageStatusInternalError ||
+ status == kCrosUsageStatusServiceUnavailable ||
+ status == kCrosUsageStatusRequestRefused ||
+ status == kCrosUsageStatusUnknownDevice) {
+ return true;
+ }
+ return false;
+}
+
+void ServiceImpl::OnCrosUsageErrorResult(const std::string& status) {
+ DLOG(WARNING) << path_ << ": OnCrosUsageErrorResult: " << status;
+ // TODO(vlaviano): hook for future use
+}
+
+bool ServiceImpl::IsConnected() const {
+ if (state_ != kStateReady) {
+ return false;
+ }
+ // cross-check with parent Service Manager's idea of Flimflam global
+ // connectivity state
+ if (ServiceManager::IsOfflineConnectivityState(
+ parent_->GetConnectivityState())) {
+ DLOG(WARNING) << path_
+ << ": IsConnected: service manager thinks we're offline";
+ return false;
+ }
+ return true;
+}
+
+void ServiceImpl::OnConnected() {
+ DLOG(INFO) << path_ << ": OnConnected";
+ DCHECK(IsConnected());
+ ReconsiderSendingUsageRequests();
+}
+
+void ServiceImpl::OnDisconnected() {
+ DLOG(INFO) << path_ << ": OnDisconnected";
+ DCHECK(!IsConnected());
+ // stop byte counter
+ // we'll issue a new usage API request when we reconnect
+ if (device_ != NULL) {
+ device_->StopByteCounter();
+ }
+ ReconsiderSendingUsageRequests();
+}
+
+bool ServiceImpl::IsSendingUsageRequests() const {
+ return request_in_progress_ || update_timeout_source_ != NULL;
+}
+
+// NOTE: we centralize our decisionmaking here to avoid insanity and just call
+// ReconsiderSendingUsageRequests when anything changes
+bool ServiceImpl::ShouldSendUsageRequests() const {
+ if (provider_ == NULL) {
+ DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: no provider";
+ DCHECK(policy_ == NULL);
+ return false;
+ }
+ DCHECK(device_ != NULL);
+ DCHECK(!device_->GetCarrier().empty());
+ DCHECK(policy_ != NULL);
+ if (usage_url_.empty()) {
+ DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: no usage url";
+ return false;
+ }
+ if (ServiceManager::IsOfflineConnectivityState(
+ parent_->GetConnectivityState())) {
+ DLOG(INFO) << path_
+ << ": ShouldSendUsageRequests: no: flimflam is offline";
+ return false;
+ }
+ if (!IsConnected()) {
+ DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: not connected";
+ return false;
+ }
+ if (!IsDefaultService()) {
+ DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: not default service";
+ return false;
+ }
+ // TODO(vlaviano): this is a blunt way to ensure that we don't count local
+ // traffic if we're already in the restricted pool when cashew starts
+ if (GetConnectivityState() == kConnectivityStateRestricted) {
+ DLOG(INFO) << path_ << ": ShouldSendUsageRequests: no: in restricted pool";
+ return false;
+ }
+ if (device_->ByteCounterRunning()) {
+ DLOG(INFO) << path_
+ << ": ShouldSendUsageRequests: no: local byte counter is running";
+ return false;
+ }
+ DLOG(INFO) << path_ << ": ShouldSendUsageRequests: yes";
+ return true;
+}
+
+void ServiceImpl::StopSendingUsageRequests() {
+ DLOG(INFO) << path_ << ": StopSendingUsageRequests";
+ DestroyUpdateTimer();
+ CancelPendingRequests();
+}
+
+void ServiceImpl::StartSendingUsageRequests() {
+ DLOG(INFO) << path_ << ": StartSendingUsageRequests";
+ DCHECK(!IsSendingUsageRequests());
+ RequestUsageUpdate();
+ CreateUpdateTimer();
+}
+
+void ServiceImpl::ReconsiderSendingUsageRequests() {
+ DLOG(INFO) << path_ << ": ReconsiderSendingUsageRequests";
+ if (!IsSendingUsageRequests() && ShouldSendUsageRequests()) {
+ StartSendingUsageRequests();
+ } else if (IsSendingUsageRequests() && !ShouldSendUsageRequests()) {
+ StopSendingUsageRequests();
+ }
+}
+
+void ServiceImpl::MaybeEmitDataPlansUpdate() {
+ DCHECK(policy_ != NULL);
+ if (policy_->ShouldEmitDataPlansUpdate(data_plans_)) {
+ DLOG(INFO) << path_ << ": MaybeEmitDataPlansUpdate: sending update";
+ parent_->EmitDataPlansUpdate(*this);
+ } else {
+ DLOG(INFO) << path_ << ": MaybeEmitDataPlansUpdate: not sending update";
+ }
+}
+
+} // namespace cashew
« no previous file with comments | « src/service_impl.h ('k') | src/service_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698