blob: f6ac011bf82437e6ed18e0c7a628182a741d7d35 [file] [log] [blame]
Gilad Arnold55f39b72014-01-28 12:51:45 -08001// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gilad Arnold55f39b72014-01-28 12:51:45 -08005#include "update_engine/policy_manager/real_shill_provider.h"
6
Gilad Arnold5ef9c482014-03-03 13:51:02 -08007#include <string>
8
9#include <base/logging.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070010#include <base/strings/stringprintf.h>
Gilad Arnold5ef9c482014-03-03 13:51:02 -080011#include <chromeos/dbus/service_constants.h>
12
Gilad Arnold5ef9c482014-03-03 13:51:02 -080013#include "update_engine/utils.h"
14
15using std::string;
16
17namespace {
18
Gilad Arnoldef120fa2014-04-09 12:52:10 -070019// Looks up a |key| in a GLib |hash_table| and returns the unboxed string from
20// the corresponding GValue, if found.
Gilad Arnold5ef9c482014-03-03 13:51:02 -080021const char* GetStrProperty(GHashTable* hash_table, const char* key) {
22 auto gval = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table, key));
23 return (gval ? g_value_get_string(gval) : NULL);
24}
25
26}; // namespace
27
28
Gilad Arnold55f39b72014-01-28 12:51:45 -080029namespace chromeos_policy_manager {
30
Gilad Arnoldef120fa2014-04-09 12:52:10 -070031const char* RealShillProvider::kConnStatusUnavailable =
32 "Connection status unavailable";
33const char* RealShillProvider::kConnTypeUnavailable =
34 "Connection type unavailable";
35const char* RealShillProvider::kConnTetheringUnavailable =
36 "Connection tethering mode unavailable";
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070037
Gilad Arnoldef120fa2014-04-09 12:52:10 -070038RealShillProvider::~RealShillProvider() {
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070039 // Detach signal handler, free manager proxy.
40 dbus_->ProxyDisconnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
Gilad Arnoldef120fa2014-04-09 12:52:10 -070041 G_CALLBACK(HandlePropertyChangedStatic),
42 this);
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070043 dbus_->ProxyUnref(manager_proxy_);
44}
45
Gilad Arnoldef120fa2014-04-09 12:52:10 -070046ConnectionType RealShillProvider::ParseConnectionType(const char* type_str) {
47 if (!strcmp(type_str, shill::kTypeEthernet))
48 return ConnectionType::kEthernet;
49 if (!strcmp(type_str, shill::kTypeWifi))
50 return ConnectionType::kWifi;
51 if (!strcmp(type_str, shill::kTypeWimax))
52 return ConnectionType::kWimax;
53 if (!strcmp(type_str, shill::kTypeBluetooth))
54 return ConnectionType::kBluetooth;
55 if (!strcmp(type_str, shill::kTypeCellular))
56 return ConnectionType::kCellular;
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070057
Gilad Arnoldef120fa2014-04-09 12:52:10 -070058 return ConnectionType::kUnknown;
59}
60
61ConnectionTethering RealShillProvider::ParseConnectionTethering(
62 const char* tethering_str) {
63 if (!strcmp(tethering_str, shill::kTetheringNotDetectedState))
64 return ConnectionTethering::kNotDetected;
65 if (!strcmp(tethering_str, shill::kTetheringSuspectedState))
66 return ConnectionTethering::kSuspected;
67 if (!strcmp(tethering_str, shill::kTetheringConfirmedState))
68 return ConnectionTethering::kConfirmed;
69
70 return ConnectionTethering::kUnknown;
71}
72
73bool RealShillProvider::DoInit() {
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070074 // Obtain a DBus connection.
Gilad Arnold5ef9c482014-03-03 13:51:02 -080075 GError* error = NULL;
76 connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
77 if (!connection_) {
78 LOG(ERROR) << "Failed to initialize DBus connection: "
79 << chromeos_update_engine::utils::GetAndFreeGError(&error);
80 return false;
81 }
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070082
83 // Allocate a shill manager proxy.
Gilad Arnold5ef9c482014-03-03 13:51:02 -080084 manager_proxy_ = GetProxy(shill::kFlimflamServicePath,
85 shill::kFlimflamManagerInterface);
Gilad Arnold55f39b72014-01-28 12:51:45 -080086
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070087 // Subscribe to the manager's PropertyChanged signal.
88 dbus_->ProxyAddSignal_2(manager_proxy_, shill::kMonitorPropertyChanged,
89 G_TYPE_STRING, G_TYPE_VALUE);
90 dbus_->ProxyConnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
Gilad Arnoldef120fa2014-04-09 12:52:10 -070091 G_CALLBACK(HandlePropertyChangedStatic),
92 this, NULL);
Gilad Arnold5ef9c482014-03-03 13:51:02 -080093
Gilad Arnoldef120fa2014-04-09 12:52:10 -070094 // Attempt to read initial connection status. Even if this fails because shill
95 // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
96 // signal as soon as it comes up, so this is not a critical step.
Gilad Arnold5ef9c482014-03-03 13:51:02 -080097 GHashTable* hash_table = NULL;
Gilad Arnoldef120fa2014-04-09 12:52:10 -070098 if (GetProperties(manager_proxy_, &hash_table)) {
99 GValue* value = reinterpret_cast<GValue*>(
100 g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
101 ProcessDefaultService(value);
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800102 g_hash_table_unref(hash_table);
103 }
104
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700105 return true;
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800106}
107
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700108DBusGProxy* RealShillProvider::GetProxy(const char* path,
109 const char* interface) {
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800110 return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
111 path, interface);
112}
113
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700114bool RealShillProvider::GetProperties(DBusGProxy* proxy,
115 GHashTable** result_p) {
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800116 GError* error = NULL;
117 if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
118 result_p)) {
119 LOG(ERROR) << "Calling shill via DBus proxy failed: "
120 << chromeos_update_engine::utils::GetAndFreeGError(&error);
121 return false;
122 }
123 return true;
124}
125
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700126bool RealShillProvider::ProcessDefaultService(GValue* value) {
127 // Decode the string from the boxed value.
128 const char* default_service_path_str = NULL;
129 if (!(value && (default_service_path_str = g_value_get_string(value))))
130 return false;
131
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700132 // Anything changed?
133 if (default_service_path_ == default_service_path_str)
134 return true;
135
136 // Update the connection status, invalidate all attributes.
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700137 default_service_path_ = default_service_path_str;
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700138 is_connected_ = (default_service_path_ != "/");
139 conn_last_changed_ = clock_->GetWallclockTime();
140 conn_type_is_valid_ = false;
141 conn_tethering_is_valid_ = false;
142
143 // If connected, update the connection attributes.
144 if (is_connected_) {
145 DBusGProxy* service_proxy = GetProxy(default_service_path_.c_str(),
146 shill::kFlimflamServiceInterface);
147 GHashTable* hash_table = NULL;
148 if (GetProperties(service_proxy, &hash_table)) {
149 // Get the connection type.
150 const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
151 if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
152 type_str = GetStrProperty(hash_table,
153 shill::kPhysicalTechnologyProperty);
154 }
155 if (type_str) {
156 conn_type_ = ParseConnectionType(type_str);
157 conn_type_is_valid_ = true;
158 } else {
159 LOG(ERROR) << "Could not find connection type ("
160 << default_service_path_ << ")";
161 }
162
163 // Get the connection tethering mode.
164 const char* tethering_str = GetStrProperty(hash_table,
165 shill::kTetheringProperty);
166 if (tethering_str) {
167 conn_tethering_ = ParseConnectionTethering(tethering_str);
168 conn_tethering_is_valid_ = true;
169 } else {
170 LOG(ERROR) << "Could not find connection tethering mode ("
171 << default_service_path_ << ")";
172 }
173
174 g_hash_table_unref(hash_table);
175 }
176 dbus_->ProxyUnref(service_proxy);
177 }
Gilad Arnolddf3dd242014-04-09 07:15:51 -0700178
179 // Mark the connection status as initialized.
180 is_conn_status_init_ = true;
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700181 return true;
182}
183
184void RealShillProvider::HandlePropertyChanged(DBusGProxy* proxy,
185 const char* name, GValue* value) {
186 if (!strcmp(name, shill::kDefaultServiceProperty))
187 ProcessDefaultService(value);
188}
189
190void RealShillProvider::HandlePropertyChangedStatic(DBusGProxy* proxy,
191 const char* name,
192 GValue* value,
193 void* data) {
194 auto obj = reinterpret_cast<RealShillProvider*>(data);
195 obj->HandlePropertyChanged(proxy, name, value);
196}
197
Gilad Arnold55f39b72014-01-28 12:51:45 -0800198} // namespace chromeos_policy_manager