PM: ShillProvider now provides the connection tethering mode.
This adds a connection tethering variable to the RealShillProvider. In
doing so, we:
* Query the default service attributes (type, tethering) eagerly, as
soon as a default service signal is received (but only if the default
service has actually changed).
* All variables are reduced to CopyVariable instances, migrating all
DBus communication logic into the RealShillProvider and eliminating
the ShillConnector helper class. This also allows us to turn variables
into contained members and initialize them during construction.
BUG=chromium:355732
TEST=Unit tests.
Change-Id: I8d9798075a4bd5b9e2cec65cb437d0018654d2c6
Reviewed-on: https://chromium-review.googlesource.com/193927
Tested-by: Gilad Arnold <garnold@chromium.org>
Reviewed-by: Alex Deymo <deymo@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
diff --git a/policy_manager/fake_shill_provider.h b/policy_manager/fake_shill_provider.h
index d3e3697..d15668d 100644
--- a/policy_manager/fake_shill_provider.h
+++ b/policy_manager/fake_shill_provider.h
@@ -23,6 +23,11 @@
return &var_conn_type_;
}
+ virtual inline FakeVariable<ConnectionTethering>*
+ var_conn_tethering() override {
+ return &var_conn_tethering_;
+ }
+
virtual inline FakeVariable<base::Time>* var_conn_last_changed() override {
return &var_conn_last_changed_;
}
@@ -33,8 +38,10 @@
private:
FakeVariable<bool> var_is_connected_{"is_connected", kVariableModePoll};
FakeVariable<ConnectionType> var_conn_type_{"conn_type", kVariableModePoll};
- FakeVariable<base::Time> var_conn_last_changed_{"conn_last_changed",
- kVariableModePoll};
+ FakeVariable<ConnectionTethering> var_conn_tethering_{
+ "conn_tethering", kVariableModePoll};
+ FakeVariable<base::Time> var_conn_last_changed_{
+ "conn_last_changed", kVariableModePoll};
DISALLOW_COPY_AND_ASSIGN(FakeShillProvider);
};
diff --git a/policy_manager/real_device_policy_provider.cc b/policy_manager/real_device_policy_provider.cc
index 4e192a0..46e4416 100644
--- a/policy_manager/real_device_policy_provider.cc
+++ b/policy_manager/real_device_policy_provider.cc
@@ -81,7 +81,8 @@
}
allowed_types->clear();
for (auto& type_str : allowed_types_str) {
- ConnectionType type = ShillConnector::ParseConnectionType(type_str.c_str());
+ ConnectionType type =
+ RealShillProvider::ParseConnectionType(type_str.c_str());
if (type != ConnectionType::kUnknown) {
allowed_types->insert(type);
} else {
diff --git a/policy_manager/real_shill_provider.cc b/policy_manager/real_shill_provider.cc
index 03e7f18..f6ac011 100644
--- a/policy_manager/real_shill_provider.cc
+++ b/policy_manager/real_shill_provider.cc
@@ -10,17 +10,14 @@
#include <base/strings/stringprintf.h>
#include <chromeos/dbus/service_constants.h>
-#include "update_engine/policy_manager/generic_variables.h"
#include "update_engine/utils.h"
using std::string;
namespace {
-const char* kConnInfoNotAvailErrMsg = "Connection information not available";
-
-// Looks up a key in a hash table and returns the string inside of the returned
-// GValue.
+// Looks up a |key| in a GLib |hash_table| and returns the unboxed string from
+// the corresponding GValue, if found.
const char* GetStrProperty(GHashTable* hash_table, const char* key) {
auto gval = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table, key));
return (gval ? g_value_get_string(gval) : NULL);
@@ -31,30 +28,49 @@
namespace chromeos_policy_manager {
-// ShillConnector methods.
+const char* RealShillProvider::kConnStatusUnavailable =
+ "Connection status unavailable";
+const char* RealShillProvider::kConnTypeUnavailable =
+ "Connection type unavailable";
+const char* RealShillProvider::kConnTetheringUnavailable =
+ "Connection tethering mode unavailable";
-const ShillConnector::ConnStrToType ShillConnector::shill_conn_str_to_type[] = {
- {shill::kTypeEthernet, ConnectionType::kEthernet},
- {shill::kTypeWifi, ConnectionType::kWifi},
- {shill::kTypeWimax, ConnectionType::kWimax},
- {shill::kTypeBluetooth, ConnectionType::kBluetooth},
- {shill::kTypeCellular, ConnectionType::kCellular},
-};
-
-ShillConnector::~ShillConnector() {
- if (!is_init_)
- return;
-
+RealShillProvider::~RealShillProvider() {
// Detach signal handler, free manager proxy.
dbus_->ProxyDisconnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
- G_CALLBACK(signal_handler_), signal_data_);
+ G_CALLBACK(HandlePropertyChangedStatic),
+ this);
dbus_->ProxyUnref(manager_proxy_);
}
-bool ShillConnector::Init() {
- if (is_init_)
- return true;
+ConnectionType RealShillProvider::ParseConnectionType(const char* type_str) {
+ if (!strcmp(type_str, shill::kTypeEthernet))
+ return ConnectionType::kEthernet;
+ if (!strcmp(type_str, shill::kTypeWifi))
+ return ConnectionType::kWifi;
+ if (!strcmp(type_str, shill::kTypeWimax))
+ return ConnectionType::kWimax;
+ if (!strcmp(type_str, shill::kTypeBluetooth))
+ return ConnectionType::kBluetooth;
+ if (!strcmp(type_str, shill::kTypeCellular))
+ return ConnectionType::kCellular;
+ return ConnectionType::kUnknown;
+}
+
+ConnectionTethering RealShillProvider::ParseConnectionTethering(
+ const char* tethering_str) {
+ if (!strcmp(tethering_str, shill::kTetheringNotDetectedState))
+ return ConnectionTethering::kNotDetected;
+ if (!strcmp(tethering_str, shill::kTetheringSuspectedState))
+ return ConnectionTethering::kSuspected;
+ if (!strcmp(tethering_str, shill::kTetheringConfirmedState))
+ return ConnectionTethering::kConfirmed;
+
+ return ConnectionTethering::kUnknown;
+}
+
+bool RealShillProvider::DoInit() {
// Obtain a DBus connection.
GError* error = NULL;
connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
@@ -72,57 +88,31 @@
dbus_->ProxyAddSignal_2(manager_proxy_, shill::kMonitorPropertyChanged,
G_TYPE_STRING, G_TYPE_VALUE);
dbus_->ProxyConnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
- G_CALLBACK(signal_handler_), signal_data_, NULL);
+ G_CALLBACK(HandlePropertyChangedStatic),
+ this, NULL);
- return is_init_ = true;
-}
-
-bool ShillConnector::GetConnectionType(const string& service_path,
- ConnectionType* conn_type_p) {
- // Obtain a proxy for the service path.
- DBusGProxy* service_proxy = GetProxy(service_path.c_str(),
- shill::kFlimflamServiceInterface);
-
+ // Attempt to read initial connection status. Even if this fails because shill
+ // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
+ // signal as soon as it comes up, so this is not a critical step.
GHashTable* hash_table = NULL;
- bool success = false;
- bool is_vpn = false;
- if (GetProperties(service_proxy, &hash_table)) {
- const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
- if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
- is_vpn = true;
- type_str = GetStrProperty(hash_table, shill::kPhysicalTechnologyProperty);
- }
- if (type_str) {
- success = true;
- *conn_type_p = ParseConnectionType(type_str);
- }
+ if (GetProperties(manager_proxy_, &hash_table)) {
+ GValue* value = reinterpret_cast<GValue*>(
+ g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
+ ProcessDefaultService(value);
g_hash_table_unref(hash_table);
}
- if (!success) {
- LOG(ERROR) << "Could not find type of "
- << (is_vpn ? "physical connection underlying VPN " : "")
- << "connection (" << service_path << ")";
- }
-
- dbus_->ProxyUnref(service_proxy);
- return success;
+ return true;
}
-DBusGProxy* ShillConnector::GetProxy(const char* path, const char* interface) {
+DBusGProxy* RealShillProvider::GetProxy(const char* path,
+ const char* interface) {
return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
path, interface);
}
-ConnectionType ShillConnector::ParseConnectionType(const char* str) {
- for (unsigned i = 0; i < arraysize(shill_conn_str_to_type); i++)
- if (!strcmp(str, shill_conn_str_to_type[i].str))
- return shill_conn_str_to_type[i].type;
-
- return ConnectionType::kUnknown;
-}
-
-bool ShillConnector::GetProperties(DBusGProxy* proxy, GHashTable** result_p) {
+bool RealShillProvider::GetProperties(DBusGProxy* proxy,
+ GHashTable** result_p) {
GError* error = NULL;
if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
result_p)) {
@@ -133,102 +123,58 @@
return true;
}
-
-// A variable returning the curent connection type.
-class ConnTypeVariable : public Variable<ConnectionType> {
- public:
- ConnTypeVariable(const string& name, ShillConnector* connector,
- RealShillProvider* provider)
- : Variable<ConnectionType>(name, kVariableModePoll),
- connector_(connector), provider_(provider) {}
-
- protected:
- // TODO(garnold) Shift to a non-blocking version, respect the timeout.
- virtual const ConnectionType* GetValue(base::TimeDelta /* timeout */,
- string* errmsg) {
- if (!(provider_->is_conn_status_init_)) {
- if (errmsg)
- *errmsg = kConnInfoNotAvailErrMsg;
- return NULL;
- }
-
- if (!(provider_->is_connected_)) {
- if (errmsg)
- *errmsg = "No connection detected";
- return NULL;
- }
-
- if (!provider_->is_conn_type_valid_) {
- if (!connector_->GetConnectionType(provider_->default_service_path_,
- &provider_->conn_type_)) {
- if (errmsg)
- *errmsg = base::StringPrintf(
- "Could not retrieve type of default connection (%s)",
- provider_->default_service_path_.c_str());
- return NULL;
- }
- provider_->is_conn_type_valid_ = true;
- }
-
- return new ConnectionType(provider_->conn_type_);
- }
-
- private:
- // The DBus connector.
- ShillConnector* connector_;
-
- // The shill provider object (we need to read/update some internal members).
- RealShillProvider* provider_;
-
- DISALLOW_COPY_AND_ASSIGN(ConnTypeVariable);
-};
-
-
-// RealShillProvider methods.
-
-bool RealShillProvider::DoInit() {
- // Initialize a DBus connection and obtain the shill manager proxy.
- connector_.reset(new ShillConnector(dbus_, HandlePropertyChangedStatic,
- this));
- if (!connector_->Init())
- return false;
-
- // Attempt to read initial connection status. Even if this fails because shill
- // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
- // signal as soon as it comes up, so this is not a critical step.
- GHashTable* hash_table = NULL;
- if (connector_->GetManagerProperties(&hash_table)) {
- GValue* value = reinterpret_cast<GValue*>(
- g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
- ProcessDefaultService(value);
- g_hash_table_unref(hash_table);
- }
-
- // Initialize variables.
- var_is_connected_.reset(
- new CopyVariable<bool>("is_connected", kVariableModePoll, is_connected_,
- &is_conn_status_init_, kConnInfoNotAvailErrMsg));
- var_conn_type_.reset(
- new ConnTypeVariable("conn_type", connector_.get(), this));
- var_conn_last_changed_.reset(
- new CopyVariable<base::Time>("conn_last_changed", kVariableModePoll,
- conn_last_changed_, &is_conn_status_init_,
- kConnInfoNotAvailErrMsg));
- return true;
-}
-
bool RealShillProvider::ProcessDefaultService(GValue* value) {
// Decode the string from the boxed value.
const char* default_service_path_str = NULL;
if (!(value && (default_service_path_str = g_value_get_string(value))))
return false;
- // Update the connection status.
- is_connected_ = strcmp(default_service_path_str, "/");
- if (default_service_path_ != default_service_path_str)
- conn_last_changed_ = clock_->GetWallclockTime();
+ // Anything changed?
+ if (default_service_path_ == default_service_path_str)
+ return true;
+
+ // Update the connection status, invalidate all attributes.
default_service_path_ = default_service_path_str;
- is_conn_type_valid_ = false;
+ is_connected_ = (default_service_path_ != "/");
+ conn_last_changed_ = clock_->GetWallclockTime();
+ conn_type_is_valid_ = false;
+ conn_tethering_is_valid_ = false;
+
+ // If connected, update the connection attributes.
+ if (is_connected_) {
+ DBusGProxy* service_proxy = GetProxy(default_service_path_.c_str(),
+ shill::kFlimflamServiceInterface);
+ GHashTable* hash_table = NULL;
+ if (GetProperties(service_proxy, &hash_table)) {
+ // Get the connection type.
+ const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
+ if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
+ type_str = GetStrProperty(hash_table,
+ shill::kPhysicalTechnologyProperty);
+ }
+ if (type_str) {
+ conn_type_ = ParseConnectionType(type_str);
+ conn_type_is_valid_ = true;
+ } else {
+ LOG(ERROR) << "Could not find connection type ("
+ << default_service_path_ << ")";
+ }
+
+ // Get the connection tethering mode.
+ const char* tethering_str = GetStrProperty(hash_table,
+ shill::kTetheringProperty);
+ if (tethering_str) {
+ conn_tethering_ = ParseConnectionTethering(tethering_str);
+ conn_tethering_is_valid_ = true;
+ } else {
+ LOG(ERROR) << "Could not find connection tethering mode ("
+ << default_service_path_ << ")";
+ }
+
+ g_hash_table_unref(hash_table);
+ }
+ dbus_->ProxyUnref(service_proxy);
+ }
// Mark the connection status as initialized.
is_conn_status_init_ = true;
diff --git a/policy_manager/real_shill_provider.h b/policy_manager/real_shill_provider.h
index 13f0fe4..833e147 100644
--- a/policy_manager/real_shill_provider.h
+++ b/policy_manager/real_shill_provider.h
@@ -15,6 +15,7 @@
#include "update_engine/clock_interface.h"
#include "update_engine/dbus_wrapper_interface.h"
+#include "update_engine/policy_manager/generic_variables.h"
#include "update_engine/policy_manager/shill_provider.h"
using chromeos_update_engine::ClockInterface;
@@ -22,91 +23,51 @@
namespace chromeos_policy_manager {
-// A DBus connector for making all shill related calls.
-class ShillConnector {
- public:
- // Expected type for the PropertyChanged signal handler.
- typedef void (*PropertyChangedHandler)(DBusGProxy*, const char*, GValue*,
- void*);
-
- ShillConnector(DBusWrapperInterface* dbus,
- PropertyChangedHandler signal_handler, void* signal_data)
- : dbus_(dbus), signal_handler_(signal_handler),
- signal_data_(signal_data) {}
-
- ~ShillConnector();
-
- // Initializes the DBus connector. Returns |true| on success.
- bool Init();
-
- // Obtains the type of a network connection described by |service_path|,
- // storing it to |*conn_type_p|. Returns |true| on success; |false| on
- // failure, in which case no value is written.
- bool GetConnectionType(const std::string& service_path,
- ConnectionType* conn_type_p);
-
- // Issues a GetProperties call to shill's manager interface, storing the
- // result to |*result_p|. Returns |true| on success.
- bool GetManagerProperties(GHashTable** result_p) {
- return GetProperties(manager_proxy_, result_p);
- }
-
- // Converts a shill connection type string into a symbolic value.
- static ConnectionType ParseConnectionType(const char* str);
-
- private:
- // Issues a GetProperties call through a given |proxy|, storing the result to
- // |*result_p|. Returns |true| on success.
- bool GetProperties(DBusGProxy* proxy, GHashTable** result_p);
-
- struct ConnStrToType {
- const char *str;
- ConnectionType type;
- };
-
- // A mapping from shill connection type strings to enum values.
- static const ConnStrToType shill_conn_str_to_type[];
-
- // An initialization flag.
- bool is_init_ = false;
-
- // The DBus interface and connection, and a shill manager proxy.
- DBusWrapperInterface* dbus_;
- DBusGConnection* connection_ = NULL;
- DBusGProxy* manager_proxy_ = NULL;
-
- // The shill manager signal handler credentials.
- PropertyChangedHandler signal_handler_ = NULL;
- void* signal_data_ = NULL;
-
- // Return a DBus proxy for a given |path| and |interface| within shill.
- DBusGProxy* GetProxy(const char* path, const char* interface);
-
- DISALLOW_COPY_AND_ASSIGN(ShillConnector);
-};
-
// ShillProvider concrete implementation.
class RealShillProvider : public ShillProvider {
public:
RealShillProvider(DBusWrapperInterface* dbus, ClockInterface* clock)
: dbus_(dbus), clock_(clock) {}
+ virtual ~RealShillProvider();
+
virtual inline Variable<bool>* var_is_connected() override {
- return var_is_connected_.get();
+ return &var_is_connected_;
}
virtual inline Variable<ConnectionType>* var_conn_type() override {
- return var_conn_type_.get();
+ return &var_conn_type_;
+ }
+
+ virtual inline Variable<ConnectionTethering>* var_conn_tethering() override {
+ return &var_conn_tethering_;
}
virtual inline Variable<base::Time>* var_conn_last_changed() override {
- return var_conn_last_changed_.get();
+ return &var_conn_last_changed_;
}
+ // Helper methods for converting shill strings into symbolic values.
+ static ConnectionType ParseConnectionType(const char* type_str);
+ static ConnectionTethering ParseConnectionTethering(
+ const char* tethering_str);
+
protected:
virtual bool DoInit() override;
private:
+ // Default error strings for variables.
+ static const char* kConnStatusUnavailable;
+ static const char* kConnTypeUnavailable;
+ static const char* kConnTetheringUnavailable;
+
+ // Return a DBus proxy for a given |path| and |interface| within shill.
+ DBusGProxy* GetProxy(const char* path, const char* interface);
+
+ // Issues a GetProperties call through a given |proxy|, storing the result to
+ // |*result_p|. Returns true on success.
+ bool GetProperties(DBusGProxy* proxy, GHashTable** result_p);
+
// Process a default connection value, update last change time as needed.
bool ProcessDefaultService(GValue* value);
@@ -116,7 +77,6 @@
static void HandlePropertyChangedStatic(DBusGProxy* proxy, const char* name,
GValue* value, void* data);
-
// Whether the connection status has been properly initialized.
bool is_conn_status_init_ = false;
@@ -126,30 +86,39 @@
// The current connection status.
bool is_connected_;
+ // The default connection type and whether its value is valid.
+ ConnectionType conn_type_;
+ bool conn_type_is_valid_ = false;
+
+ // The default connection tethering mode and whether its value is valid.
+ ConnectionTethering conn_tethering_;
+ bool conn_tethering_is_valid_ = false;
+
// The current default service path, if connected.
std::string default_service_path_;
- // The last known type of the default connection.
- ConnectionType conn_type_ = ConnectionType::kUnknown;
-
- // Whether the last known connection type is valid.
- bool is_conn_type_valid_ = false;
-
- // A shill DBus connector.
- scoped_ptr<ShillConnector> connector_;
-
- // The DBus interface object (mockable).
+ // The DBus interface (mockable), connection, and a shill manager proxy.
DBusWrapperInterface* const dbus_;
+ DBusGConnection* connection_ = NULL;
+ DBusGProxy* manager_proxy_ = NULL;
// A clock abstraction (mockable).
ClockInterface* const clock_;
- // Pointers to all variable objects.
- scoped_ptr<Variable<bool>> var_is_connected_;
- scoped_ptr<Variable<ConnectionType>> var_conn_type_;
- scoped_ptr<Variable<base::Time>> var_conn_last_changed_;
+ // The provider's variable.
+ CopyVariable<bool> var_is_connected_{
+ "is_connected", kVariableModePoll, is_connected_, &is_conn_status_init_,
+ kConnStatusUnavailable};
+ CopyVariable<ConnectionType> var_conn_type_{
+ "conn_type", kVariableModePoll, conn_type_, &conn_type_is_valid_,
+ kConnTypeUnavailable};
+ CopyVariable<ConnectionTethering> var_conn_tethering_{
+ "conn_tethering", kVariableModePoll, conn_tethering_,
+ &conn_tethering_is_valid_, kConnTetheringUnavailable};
+ CopyVariable<base::Time> var_conn_last_changed_{
+ "conn_last_changed", kVariableModePoll, conn_last_changed_,
+ &is_conn_status_init_, kConnStatusUnavailable};
- friend class ConnTypeVariable;
DISALLOW_COPY_AND_ASSIGN(RealShillProvider);
};
diff --git a/policy_manager/real_shill_provider_unittest.cc b/policy_manager/real_shill_provider_unittest.cc
index d9aef4e..38f3905 100644
--- a/policy_manager/real_shill_provider_unittest.cc
+++ b/policy_manager/real_shill_provider_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <utility>
+
#include <base/memory/scoped_ptr.h>
#include <base/time/time.h>
#include <chromeos/dbus/service_constants.h>
@@ -17,18 +19,19 @@
using base::Time;
using base::TimeDelta;
using chromeos_update_engine::FakeClock;
-using chromeos_update_engine::GValueNewString;
using chromeos_update_engine::GValueFree;
+using chromeos_update_engine::GValueNewString;
using chromeos_update_engine::MockDBusWrapper;
using std::pair;
-using testing::_;
using testing::Eq;
+using testing::Mock;
using testing::NiceMock;
using testing::Return;
using testing::SaveArg;
using testing::SetArgPointee;
using testing::StrEq;
using testing::StrictMock;
+using testing::_;
namespace {
@@ -101,9 +104,10 @@
EXPECT_CALL(mock_dbus_, ProxyConnectSignal(
kFakeManagerProxy, StrEq(shill::kMonitorPropertyChanged),
_, _, _))
- .WillOnce(DoAll(SaveArg<2>(&signal_handler_),
- SaveArg<3>(&signal_data_),
- Return()));
+ .WillOnce(
+ DoAll(SaveArg<2>(reinterpret_cast<void (**)()>(&signal_handler_)),
+ SaveArg<3>(&signal_data_),
+ Return()));
// Mock a response to an initial connection check (optional).
GHashTable* manager_properties = nullptr;
@@ -120,12 +124,12 @@
// Check that provider initializes corrrectly.
ASSERT_TRUE(provider_->Init());
+ // All mocked calls should have been exercised by now.
+ Mock::VerifyAndClear(&mock_dbus_);
+
// Release properties hash table (if provided).
if (manager_properties)
g_hash_table_unref(manager_properties);
-
- // Verify and clear all expectations.
- testing::Mock::VerifyAndClear(&mock_dbus_);
}
// Deletes the RealShillProvider under test.
@@ -133,13 +137,14 @@
// Make sure that DBus resources get freed.
EXPECT_CALL(mock_dbus_, ProxyDisconnectSignal(
kFakeManagerProxy, StrEq(shill::kMonitorPropertyChanged),
- Eq(signal_handler_), Eq(signal_data_)))
+ Eq(reinterpret_cast<void (*)()>(signal_handler_)),
+ Eq(signal_data_)))
.WillOnce(Return());
EXPECT_CALL(mock_dbus_, ProxyUnref(kFakeManagerProxy)).WillOnce(Return());
provider_.reset();
- // Verify and clear all expectations.
- testing::Mock::VerifyAndClear(&mock_dbus_);
+ // All mocked calls should have been exercised by now.
+ Mock::VerifyAndClear(&mock_dbus_);
}
// These methods generate fixed timestamps for use in faking the current time.
@@ -196,23 +201,49 @@
.WillOnce(Return(false));
}
- // Programs the mock DBus interface to return an non-VPN service and ensures
- // that the shill provider reads it correctly, including updating the last
- // changed time on each of the queries.
- void SetupConnectionAndTestType(const char* service_path,
- DBusGProxy* service_proxy,
- const char* shill_type_str,
- ConnectionType expected_conn_type) {
- // Send a signal about a new default service.
- auto callback = reinterpret_cast<ShillConnector::PropertyChangedHandler>(
- signal_handler_);
+ // Sends a signal informing the provider about a default connection
+ // |service_path|. Returns the fake connection change time.
+ Time SendDefaultServiceSignal(const char* service_path) {
auto default_service_gval = GValueNewString(service_path);
- Time conn_change_time = ConnChangedTime();
+ const Time conn_change_time = ConnChangedTime();
fake_clock_.SetWallclockTime(conn_change_time);
- callback(kFakeManagerProxy, shill::kDefaultServiceProperty,
- default_service_gval, signal_data_);
+ signal_handler_(kFakeManagerProxy, shill::kDefaultServiceProperty,
+ default_service_gval, signal_data_);
fake_clock_.SetWallclockTime(conn_change_time + TimeDelta::FromSeconds(5));
GValueFree(default_service_gval);
+ return conn_change_time;
+ }
+
+ // Sets up expectations for detection of a connection |service_path| with type
+ // |shill_type_str| and tethering mode |shill_tethering_str|. Ensures that the
+ // new connection status and change time are properly detected by the
+ // provider. Writes the fake connection change time to |conn_change_time_p|,
+ // if provided.
+ void SetupConnectionAndAttrs(const char* service_path,
+ DBusGProxy* service_proxy,
+ const char* shill_type_str,
+ const char* shill_tethering_str,
+ Time* conn_change_time_p) {
+ // Mock logic for querying the default service attributes.
+ EXPECT_CALL(mock_dbus_,
+ ProxyNewForName(
+ kFakeConnection, StrEq(shill::kFlimflamServiceName),
+ StrEq(service_path),
+ StrEq(shill::kFlimflamServiceInterface)))
+ .WillOnce(Return(service_proxy));
+ EXPECT_CALL(mock_dbus_, ProxyUnref(service_proxy)).WillOnce(Return());
+ pair<const char*, const char*> service_pairs[] = {
+ {shill::kTypeProperty, shill_type_str},
+ {shill::kTetheringProperty, shill_tethering_str},
+ };
+ auto service_properties = SetupGetPropertiesOkay(
+ service_proxy, arraysize(service_pairs), service_pairs);
+
+ // Send a signal about a new default service.
+ auto conn_change_time = SendDefaultServiceSignal(service_path);
+
+ // Release the service properties hash tables.
+ g_hash_table_unref(service_properties);
// Query the connection status, ensure last change time reported correctly.
scoped_ptr<const bool> is_connected(
@@ -220,24 +251,27 @@
PMTEST_ASSERT_NOT_NULL(is_connected.get());
EXPECT_TRUE(*is_connected);
- scoped_ptr<const Time> conn_last_changed_1(
+ scoped_ptr<const Time> conn_last_changed(
provider_->var_conn_last_changed()->GetValue(default_timeout_, NULL));
- PMTEST_ASSERT_NOT_NULL(conn_last_changed_1.get());
- EXPECT_EQ(conn_change_time, *conn_last_changed_1);
+ PMTEST_ASSERT_NOT_NULL(conn_last_changed.get());
+ EXPECT_EQ(conn_change_time, *conn_last_changed);
- // Mock logic for querying the type of the default service.
- EXPECT_CALL(mock_dbus_, ProxyNewForName(
- kFakeConnection, StrEq(shill::kFlimflamServiceName),
- StrEq(service_path),
- StrEq(shill::kFlimflamServiceInterface)))
- .WillOnce(Return(service_proxy));
- EXPECT_CALL(mock_dbus_,
- ProxyUnref(service_proxy)).WillOnce(Return());
- pair<const char*, const char*> service_pairs[] = {
- {shill::kTypeProperty, shill_type_str},
- };
- auto service_properties = SetupGetPropertiesOkay(
- service_proxy, arraysize(service_pairs), service_pairs);
+ // Write the connection change time to the output argument.
+ if (conn_change_time_p)
+ *conn_change_time_p = conn_change_time;
+ }
+
+ // Sets up a connection and tests that its type is being properly detected by
+ // the provider.
+ void SetupConnectionAndTestType(const char* service_path,
+ DBusGProxy* service_proxy,
+ const char* shill_type_str,
+ ConnectionType expected_conn_type) {
+ // Set up and test the connection, record the change time.
+ Time conn_change_time;
+ SetupConnectionAndAttrs(service_path, service_proxy, shill_type_str,
+ shill::kTetheringNotDetectedState,
+ &conn_change_time);
// Query the connection type, ensure last change time did not change.
scoped_ptr<const ConnectionType> conn_type(
@@ -245,20 +279,40 @@
PMTEST_ASSERT_NOT_NULL(conn_type.get());
EXPECT_EQ(expected_conn_type, *conn_type);
- scoped_ptr<const Time> conn_last_changed_2(
+ scoped_ptr<const Time> conn_last_changed(
provider_->var_conn_last_changed()->GetValue(default_timeout_, NULL));
- PMTEST_ASSERT_NOT_NULL(conn_last_changed_2.get());
- EXPECT_EQ(*conn_last_changed_1, *conn_last_changed_2);
+ PMTEST_ASSERT_NOT_NULL(conn_last_changed.get());
+ EXPECT_EQ(conn_change_time, *conn_last_changed);
+ }
- // Release properties hash tables.
- g_hash_table_unref(service_properties);
+ // Sets up a connection and tests that its tethering mode is being properly
+ // detected by the provider.
+ void SetupConnectionAndTestTethering(
+ const char* service_path, DBusGProxy* service_proxy,
+ const char* shill_tethering_str,
+ ConnectionTethering expected_conn_tethering) {
+ // Set up and test the connection, record the change time.
+ Time conn_change_time;
+ SetupConnectionAndAttrs(service_path, service_proxy, shill::kTypeEthernet,
+ shill_tethering_str, &conn_change_time);
+
+ // Query the connection tethering, ensure last change time did not change.
+ scoped_ptr<const ConnectionTethering> conn_tethering(
+ provider_->var_conn_tethering()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_tethering.get());
+ EXPECT_EQ(expected_conn_tethering, *conn_tethering);
+
+ scoped_ptr<const Time> conn_last_changed(
+ provider_->var_conn_last_changed()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_last_changed.get());
+ EXPECT_EQ(conn_change_time, *conn_last_changed);
}
const TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
StrictMock<MockDBusWrapper> mock_dbus_;
FakeClock fake_clock_;
scoped_ptr<RealShillProvider> provider_;
- GCallback signal_handler_;
+ void (*signal_handler_)(DBusGProxy*, const char*, GValue*, void*);
void* signal_data_;
};
@@ -282,7 +336,7 @@
}
// Test that Ethernet connection is identified correctly.
-TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaEthernet) {
+TEST_F(PmRealShillProviderTest, ReadConnTypeEthernet) {
SetupConnectionAndTestType(kFakeEthernetServicePath,
kFakeEthernetServiceProxy,
shill::kTypeEthernet,
@@ -290,7 +344,7 @@
}
// Test that Wifi connection is identified correctly.
-TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaWifi) {
+TEST_F(PmRealShillProviderTest, ReadConnTypeWifi) {
SetupConnectionAndTestType(kFakeWifiServicePath,
kFakeWifiServiceProxy,
shill::kTypeWifi,
@@ -298,7 +352,7 @@
}
// Test that Wimax connection is identified correctly.
-TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaWimax) {
+TEST_F(PmRealShillProviderTest, ReadConnTypeWimax) {
SetupConnectionAndTestType(kFakeWimaxServicePath,
kFakeWimaxServiceProxy,
shill::kTypeWimax,
@@ -306,7 +360,7 @@
}
// Test that Bluetooth connection is identified correctly.
-TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaBluetooth) {
+TEST_F(PmRealShillProviderTest, ReadConnTypeBluetooth) {
SetupConnectionAndTestType(kFakeBluetoothServicePath,
kFakeBluetoothServiceProxy,
shill::kTypeBluetooth,
@@ -314,7 +368,7 @@
}
// Test that Cellular connection is identified correctly.
-TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaCellular) {
+TEST_F(PmRealShillProviderTest, ReadConnTypeCellular) {
SetupConnectionAndTestType(kFakeCellularServicePath,
kFakeCellularServiceProxy,
shill::kTypeCellular,
@@ -322,8 +376,7 @@
}
// Test that an unknown connection is identified as such.
-TEST_F(PmRealShillProviderTest,
- ReadChangedValuesConnectedViaUnknown) {
+TEST_F(PmRealShillProviderTest, ReadConnTypeUnknown) {
SetupConnectionAndTestType(kFakeUnknownServicePath,
kFakeUnknownServiceProxy,
"FooConnectionType",
@@ -331,18 +384,7 @@
}
// Tests that VPN connection is identified correctly.
-TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaVpn) {
- // Send a signal about a new default service.
- auto callback = reinterpret_cast<ShillConnector::PropertyChangedHandler>(
- signal_handler_);
- auto default_service_gval = GValueNewString(kFakeVpnServicePath);
- Time conn_change_time = ConnChangedTime();
- fake_clock_.SetWallclockTime(conn_change_time);
- callback(kFakeManagerProxy, shill::kDefaultServiceProperty,
- default_service_gval, signal_data_);
- fake_clock_.SetWallclockTime(conn_change_time + TimeDelta::FromSeconds(5));
- GValueFree(default_service_gval);
-
+TEST_F(PmRealShillProviderTest, ReadConnTypeVpn) {
// Mock logic for returning a default service path and its type.
EXPECT_CALL(mock_dbus_, ProxyNewForName(
kFakeConnection, StrEq(shill::kFlimflamServiceName),
@@ -357,6 +399,9 @@
arraysize(service_pairs),
service_pairs);
+ // Send a signal about a new default service.
+ Time conn_change_time = SendDefaultServiceSignal(kFakeVpnServicePath);
+
// Query the connection type, ensure last change time reported correctly.
scoped_ptr<const ConnectionType> conn_type(
provider_->var_conn_type()->GetValue(default_timeout_, NULL));
@@ -372,8 +417,9 @@
g_hash_table_unref(service_properties);
}
-// Ensure that the connection type is properly cached in the provider.
-TEST_F(PmRealShillProviderTest, ConnectionTypeCached) {
+// Ensure that the connection type is properly cached in the provider through
+// subsequent variable readings.
+TEST_F(PmRealShillProviderTest, ConnTypeCacheUsed) {
SetupConnectionAndTestType(kFakeEthernetServicePath,
kFakeEthernetServiceProxy,
shill::kTypeEthernet,
@@ -385,23 +431,122 @@
EXPECT_EQ(ConnectionType::kEthernet, *conn_type);
}
-// Fake two DBus signal prompting about a default connection change, but
-// otherwise give the same service path. Check connection status and the time is
-// was last changed, make sure it is the same time when the first signal was
-// sent (and not the second).
-TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedTwoSignals) {
+// Ensure that the cached connection type remains valid even when a default
+// connection signal occurs but the connection is not changed.
+TEST_F(PmRealShillProviderTest, ConnTypeCacheRemainsValid) {
+ SetupConnectionAndTestType(kFakeEthernetServicePath,
+ kFakeEthernetServiceProxy,
+ shill::kTypeEthernet,
+ ConnectionType::kEthernet);
+
+ SendDefaultServiceSignal(kFakeEthernetServicePath);
+
+ scoped_ptr<const ConnectionType> conn_type(
+ provider_->var_conn_type()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_type.get());
+ EXPECT_EQ(ConnectionType::kEthernet, *conn_type);
+}
+
+// Ensure that the cached connection type is invalidated and re-read when the
+// default connection changes.
+TEST_F(PmRealShillProviderTest, ConnTypeCacheInvalidated) {
+ SetupConnectionAndTestType(kFakeEthernetServicePath,
+ kFakeEthernetServiceProxy,
+ shill::kTypeEthernet,
+ ConnectionType::kEthernet);
+
+ SetupConnectionAndTestType(kFakeWifiServicePath,
+ kFakeWifiServiceProxy,
+ shill::kTypeWifi,
+ ConnectionType::kWifi);
+}
+
+// Test that a non-tethering mode is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadConnTetheringNotDetected) {
+ SetupConnectionAndTestTethering(kFakeWifiServicePath,
+ kFakeWifiServiceProxy,
+ shill::kTetheringNotDetectedState,
+ ConnectionTethering::kNotDetected);
+}
+
+// Test that a suspected tethering mode is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadConnTetheringSuspected) {
+ SetupConnectionAndTestTethering(kFakeWifiServicePath,
+ kFakeWifiServiceProxy,
+ shill::kTetheringSuspectedState,
+ ConnectionTethering::kSuspected);
+}
+
+// Test that a confirmed tethering mode is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadConnTetheringConfirmed) {
+ SetupConnectionAndTestTethering(kFakeWifiServicePath,
+ kFakeWifiServiceProxy,
+ shill::kTetheringConfirmedState,
+ ConnectionTethering::kConfirmed);
+}
+
+// Test that an unknown tethering mode is identified as such.
+TEST_F(PmRealShillProviderTest, ReadConnTetheringUnknown) {
+ SetupConnectionAndTestTethering(kFakeWifiServicePath,
+ kFakeWifiServiceProxy,
+ "FooConnTethering",
+ ConnectionTethering::kUnknown);
+}
+
+// Ensure that the connection tethering mode is properly cached in the provider.
+TEST_F(PmRealShillProviderTest, ConnTetheringCacheUsed) {
+ SetupConnectionAndTestTethering(kFakeEthernetServicePath,
+ kFakeEthernetServiceProxy,
+ shill::kTetheringNotDetectedState,
+ ConnectionTethering::kNotDetected);
+
+ scoped_ptr<const ConnectionTethering> conn_tethering(
+ provider_->var_conn_tethering()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_tethering.get());
+ EXPECT_EQ(ConnectionTethering::kNotDetected, *conn_tethering);
+}
+
+// Ensure that the cached connection tethering mode remains valid even when a
+// default connection signal occurs but the connection is not changed.
+TEST_F(PmRealShillProviderTest, ConnTetheringCacheRemainsValid) {
+ SetupConnectionAndTestTethering(kFakeEthernetServicePath,
+ kFakeEthernetServiceProxy,
+ shill::kTetheringNotDetectedState,
+ ConnectionTethering::kNotDetected);
+
+ SendDefaultServiceSignal(kFakeEthernetServicePath);
+
+ scoped_ptr<const ConnectionTethering> conn_tethering(
+ provider_->var_conn_tethering()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_tethering.get());
+ EXPECT_EQ(ConnectionTethering::kNotDetected, *conn_tethering);
+}
+
+// Ensure that the cached connection tethering mode is invalidated and re-read
+// when the default connection changes.
+TEST_F(PmRealShillProviderTest, ConnTetheringCacheInvalidated) {
+ SetupConnectionAndTestTethering(kFakeEthernetServicePath,
+ kFakeEthernetServiceProxy,
+ shill::kTetheringNotDetectedState,
+ ConnectionTethering::kNotDetected);
+
+ SetupConnectionAndTestTethering(kFakeWifiServicePath,
+ kFakeWifiServiceProxy,
+ shill::kTetheringConfirmedState,
+ ConnectionTethering::kConfirmed);
+}
+
+// Fake two DBus signals prompting a default connection change, but otherwise
+// give the same service path. Check connection status and the time it was last
+// changed, making sure that it is the time when the first signal was sent (and
+// not the second).
+TEST_F(PmRealShillProviderTest, ReadLastChangedTimeTwoSignals) {
// Send a default service signal twice, advancing the clock in between.
- auto callback = reinterpret_cast<ShillConnector::PropertyChangedHandler>(
- signal_handler_);
- auto default_service_gval = GValueNewString(kFakeEthernetServicePath);
- Time conn_change_time = ConnChangedTime();
- fake_clock_.SetWallclockTime(conn_change_time);
- callback(kFakeManagerProxy, shill::kDefaultServiceProperty,
- default_service_gval, signal_data_);
- fake_clock_.SetWallclockTime(conn_change_time + TimeDelta::FromSeconds(5));
- callback(kFakeManagerProxy, shill::kDefaultServiceProperty,
- default_service_gval, signal_data_);
- GValueFree(default_service_gval);
+ Time conn_change_time;
+ SetupConnectionAndAttrs(kFakeEthernetServicePath, kFakeEthernetServiceProxy,
+ shill::kTypeEthernet,
+ shill::kTetheringNotDetectedState, &conn_change_time);
+ SendDefaultServiceSignal(kFakeEthernetServicePath);
// Query the connection status, ensure last change time reported correctly.
scoped_ptr<const bool> is_connected(
@@ -431,8 +576,7 @@
// Test that, once a signal is received, the connection status and other info
// can be read correctly.
-TEST_F(PmRealShillProviderTest,
- NoInitConnStatusReadChangedValuesConnectedViaEthernet) {
+TEST_F(PmRealShillProviderTest, NoInitConnStatusReadConnTypeEthernet) {
// Re-initialize the provider, no initial connection status response.
Init(false);
SetupConnectionAndTestType(kFakeEthernetServicePath,
diff --git a/policy_manager/shill_provider.h b/policy_manager/shill_provider.h
index 7b87903..b53266f 100644
--- a/policy_manager/shill_provider.h
+++ b/policy_manager/shill_provider.h
@@ -22,17 +22,29 @@
kUnknown
};
+enum class ConnectionTethering {
+ kNotDetected,
+ kSuspected,
+ kConfirmed,
+ kUnknown,
+};
+
// Provider for networking related information.
class ShillProvider : public Provider {
public:
- // Returns whether we currently have network connectivity.
+ // A variable returning whether we currently have network connectivity.
virtual Variable<bool>* var_is_connected() = 0;
- // Returns the current network connection type. Unknown if not connected.
+ // A variable returning the current network connection type. Unknown if not
+ // connected.
virtual Variable<ConnectionType>* var_conn_type() = 0;
- // Returns the time when network connection last changed; initialized to
- // current time.
+ // A variable returning the tethering mode of a network connection. Unknown if
+ // not connected.
+ virtual Variable<ConnectionTethering>* var_conn_tethering() = 0;
+
+ // A variable retruning the time when network connection last changed.
+ // Initialized to current time.
virtual Variable<base::Time>* var_conn_last_changed() = 0;
protected:
diff --git a/policy_manager/variable.h b/policy_manager/variable.h
index ae2b99e..cd13be1 100644
--- a/policy_manager/variable.h
+++ b/policy_manager/variable.h
@@ -181,9 +181,12 @@
FRIEND_TEST(PmRealRandomProviderTest, GetRandomValues);
friend class PmRealShillProviderTest;
FRIEND_TEST(PmRealShillProviderTest, ReadBaseValues);
- FRIEND_TEST(PmRealShillProviderTest, ReadChangedValuesConnectedViaVpn);
- FRIEND_TEST(PmRealShillProviderTest, ReadChangedValuesConnectedTwoSignals);
- FRIEND_TEST(PmRealShillProviderTest, ConnectionTypeCached);
+ FRIEND_TEST(PmRealShillProviderTest, ReadConnTypeVpn);
+ FRIEND_TEST(PmRealShillProviderTest, ReadLastChangedTimeTwoSignals);
+ FRIEND_TEST(PmRealShillProviderTest, ConnTypeCacheUsed);
+ FRIEND_TEST(PmRealShillProviderTest, ConnTypeCacheRemainsValid);
+ FRIEND_TEST(PmRealShillProviderTest, ConnTetheringCacheUsed);
+ FRIEND_TEST(PmRealShillProviderTest, ConnTetheringCacheRemainsValid);
FRIEND_TEST(PmRealShillProviderTest, NoInitConnStatusReadBaseValues);
friend class PmRealTimeProviderTest;
FRIEND_TEST(PmRealTimeProviderTest, CurrDateValid);