PM: Add a DBus backend to the shill provider.
This change integrates the necessary logic for the shill provider to
actually talk to shill over DBus.
* RealShillProviders now takes a DbusInterface object. PolicyManager and
RealState were extended to propagate this object, accordingly.
* New provider_utils and general glib_utils modules.
* Minor touch-ups: removal of redundant includes and unwarranted 'using'
clauses.
BUG=chromium:338585
TEST=Unit tests.
Change-Id: I4082b845557eff2a02a928c60c348dde0e784a2c
Reviewed-on: https://chromium-review.googlesource.com/189045
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
diff --git a/policy_manager/real_shill_provider.cc b/policy_manager/real_shill_provider.cc
index 279266d..60a953f 100644
--- a/policy_manager/real_shill_provider.cc
+++ b/policy_manager/real_shill_provider.cc
@@ -2,25 +2,206 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "update_engine/policy_manager/generic_variables.h"
#include "update_engine/policy_manager/real_shill_provider.h"
+#include <string>
+
+#include <base/logging.h>
+#include <chromeos/dbus/service_constants.h>
+
+#include "update_engine/policy_manager/generic_variables.h"
+#include "update_engine/utils.h"
+
+using std::string;
+
+namespace {
+
+// Looks up a key in a hash table and returns the string inside of the returned
+// GValue.
+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);
+}
+
+}; // namespace
+
+
namespace chromeos_policy_manager {
-// ShillProvider implementation.
+const ShillConnector::ConnStrToType ShillConnector::shill_conn_str_to_type[] = {
+ {shill::kTypeEthernet, kShillConnTypeEthernet},
+ {shill::kTypeWifi, kShillConnTypeWifi},
+ {shill::kTypeWimax, kShillConnTypeWimax},
+ {shill::kTypeBluetooth, kShillConnTypeBluetooth},
+ {shill::kTypeCellular, kShillConnTypeCellular},
+};
-bool RealShillProvider::DoInit(void) {
- // TODO(garnold) Initialize with actual (or fake) DBus connection.
+bool ShillConnector::Init() {
+ GError* error = NULL;
+ connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
+ if (!connection_) {
+ LOG(ERROR) << "Failed to initialize DBus connection: "
+ << chromeos_update_engine::utils::GetAndFreeGError(&error);
+ return false;
+ }
+ manager_proxy_ = GetProxy(shill::kFlimflamServicePath,
+ shill::kFlimflamManagerInterface);
+ return true;
+}
+bool ShillConnector::GetDefaultConnection(bool* is_connected_p,
+ string* default_service_path_p) {
+ GHashTable* hash_table = NULL;
+ if (!GetProperties(manager_proxy_, &hash_table))
+ return false;
+ GValue* value = reinterpret_cast<GValue*>(
+ g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
+ const char* default_service_path_str = NULL;
+ bool success = false;
+ if (value && (default_service_path_str = g_value_get_string(value))) {
+ success = true;
+ *is_connected_p = strcmp(default_service_path_str, "/");
+ if (*is_connected_p)
+ *default_service_path_p = default_service_path_str;
+ }
+ g_hash_table_unref(hash_table);
+
+ return success;
+}
+
+bool ShillConnector::GetConnectionType(const string& service_path,
+ ShillConnType* conn_type_p) {
+ // Obtain a proxy for the service path.
+ DBusGProxy* service_proxy = GetProxy(service_path.c_str(),
+ shill::kFlimflamServiceInterface);
+
+ 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 = ParseConnType(type_str);
+ }
+ 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;
+}
+
+DBusGProxy* ShillConnector::GetProxy(const char* path, const char* interface) {
+ return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
+ path, interface);
+}
+
+ShillConnType ShillConnector::ParseConnType(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 kShillConnTypeUnknown;
+}
+
+// Issues a GetProperties call through a given |proxy|, storing the result to
+// |*result_p|. Returns |true| on success.
+bool ShillConnector::GetProperties(DBusGProxy* proxy, GHashTable** result_p) {
+ GError* error = NULL;
+ if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
+ result_p)) {
+ LOG(ERROR) << "Calling shill via DBus proxy failed: "
+ << chromeos_update_engine::utils::GetAndFreeGError(&error);
+ return false;
+ }
+ return true;
+}
+
+// A variable returning whether or not we have a network connection.
+class IsConnectedVariable : public Variable<bool> {
+ public:
+ IsConnectedVariable(const string& name, ShillConnector* connector,
+ LastValueTracker<bool>* is_connected_tracker)
+ : Variable<bool>(name, kVariableModePoll),
+ connector_(connector),
+ is_connected_tracker_(is_connected_tracker) {}
+
+ protected:
+ virtual const bool* GetValue(base::TimeDelta timeout, string* errmsg) {
+ bool is_connected;
+ string default_service_path;
+ if (!connector_->GetDefaultConnection(&is_connected, &default_service_path))
+ return NULL;;
+
+ return new bool(is_connected_tracker_->Update(is_connected));
+ }
+
+ private:
+ ShillConnector* connector_;
+ LastValueTracker<bool>* is_connected_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(IsConnectedVariable);
+};
+
+// A variable returning the curent connection type.
+class ConnTypeVariable : public Variable<ShillConnType> {
+ public:
+ ConnTypeVariable(const string& name, ShillConnector* connector,
+ LastValueTracker<bool>* is_connected_tracker)
+ : Variable<ShillConnType>(name, kVariableModePoll),
+ connector_(connector),
+ is_connected_tracker_(is_connected_tracker) {}
+
+ protected:
+ virtual const ShillConnType* GetValue(base::TimeDelta timeout,
+ string* errmsg) {
+ bool is_connected;
+ string default_service_path;
+ ShillConnType conn_type;
+ if (!(connector_->GetDefaultConnection(&is_connected,
+ &default_service_path) &&
+ is_connected &&
+ connector_->GetConnectionType(default_service_path, &conn_type)))
+ return NULL;
+
+ is_connected_tracker_->Update(is_connected);
+ return new ShillConnType(conn_type);
+ }
+
+ private:
+ ShillConnector* connector_;
+ LastValueTracker<bool>* is_connected_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnTypeVariable);
+};
+
+// A real implementation of the ShillProvider.
+bool RealShillProvider::DoInit() {
+ // Initialize a DBus connection and obtain the shill manager proxy.
+ connector_.reset(new ShillConnector(dbus_));
+ if (!connector_->Init())
+ return false;
+
+ // Initialize variables.
set_var_is_connected(
- new CopyVariable<bool>("is_connected", kVariableModeAsync,
- is_connected_));
+ new IsConnectedVariable("is_connected", connector_.get(),
+ &is_connected_tracker_));
set_var_conn_type(
- new CopyVariable<ShillConnType>("conn_type", kVariableModeAsync,
- conn_type_));
+ new ConnTypeVariable("conn_type", connector_.get(),
+ &is_connected_tracker_));
set_var_conn_last_changed(
- new CopyVariable<Time>("conn_last_changed", kVariableModeAsync,
- conn_last_changed_));
+ new CopyVariable<base::Time>("conn_last_changed", kVariableModePoll,
+ conn_last_changed_));
return true;
}