blob: 609fd0191c70bb9e86508dadea0fa794f230b00d [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
Alex Deymo63784a52014-05-28 10:46:14 -07005#include "update_engine/update_manager/real_shill_provider.h"
Gilad Arnold55f39b72014-01-28 12:51:45 -08006
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
Alex Deymo44666f92014-07-22 20:29:24 -070013#include "update_engine/glib_utils.h"
Gilad Arnold5ef9c482014-03-03 13:51:02 -080014
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));
Alex Vakulenko88b591f2014-08-28 16:48:57 -070023 return (gval ? g_value_get_string(gval) : nullptr);
Gilad Arnold5ef9c482014-03-03 13:51:02 -080024}
25
26}; // namespace
27
28
Alex Deymo63784a52014-05-28 10:46:14 -070029namespace chromeos_update_manager {
Gilad Arnold55f39b72014-01-28 12:51:45 -080030
Gilad Arnoldef120fa2014-04-09 12:52:10 -070031RealShillProvider::~RealShillProvider() {
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070032 // Detach signal handler, free manager proxy.
33 dbus_->ProxyDisconnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
Gilad Arnoldef120fa2014-04-09 12:52:10 -070034 G_CALLBACK(HandlePropertyChangedStatic),
35 this);
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070036 dbus_->ProxyUnref(manager_proxy_);
37}
38
Gilad Arnoldef120fa2014-04-09 12:52:10 -070039ConnectionType RealShillProvider::ParseConnectionType(const char* type_str) {
40 if (!strcmp(type_str, shill::kTypeEthernet))
41 return ConnectionType::kEthernet;
42 if (!strcmp(type_str, shill::kTypeWifi))
43 return ConnectionType::kWifi;
44 if (!strcmp(type_str, shill::kTypeWimax))
45 return ConnectionType::kWimax;
46 if (!strcmp(type_str, shill::kTypeBluetooth))
47 return ConnectionType::kBluetooth;
48 if (!strcmp(type_str, shill::kTypeCellular))
49 return ConnectionType::kCellular;
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070050
Gilad Arnoldef120fa2014-04-09 12:52:10 -070051 return ConnectionType::kUnknown;
52}
53
54ConnectionTethering RealShillProvider::ParseConnectionTethering(
55 const char* tethering_str) {
56 if (!strcmp(tethering_str, shill::kTetheringNotDetectedState))
57 return ConnectionTethering::kNotDetected;
58 if (!strcmp(tethering_str, shill::kTetheringSuspectedState))
59 return ConnectionTethering::kSuspected;
60 if (!strcmp(tethering_str, shill::kTetheringConfirmedState))
61 return ConnectionTethering::kConfirmed;
62
63 return ConnectionTethering::kUnknown;
64}
65
Alex Deymo42c30c32014-04-24 18:41:18 -070066bool RealShillProvider::Init() {
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070067 // Obtain a DBus connection.
Alex Vakulenko88b591f2014-08-28 16:48:57 -070068 GError* error = nullptr;
Gilad Arnold5ef9c482014-03-03 13:51:02 -080069 connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
70 if (!connection_) {
71 LOG(ERROR) << "Failed to initialize DBus connection: "
72 << chromeos_update_engine::utils::GetAndFreeGError(&error);
73 return false;
74 }
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070075
76 // Allocate a shill manager proxy.
Gilad Arnold5ef9c482014-03-03 13:51:02 -080077 manager_proxy_ = GetProxy(shill::kFlimflamServicePath,
78 shill::kFlimflamManagerInterface);
Gilad Arnold55f39b72014-01-28 12:51:45 -080079
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070080 // Subscribe to the manager's PropertyChanged signal.
81 dbus_->ProxyAddSignal_2(manager_proxy_, shill::kMonitorPropertyChanged,
82 G_TYPE_STRING, G_TYPE_VALUE);
83 dbus_->ProxyConnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
Gilad Arnoldef120fa2014-04-09 12:52:10 -070084 G_CALLBACK(HandlePropertyChangedStatic),
Alex Vakulenko88b591f2014-08-28 16:48:57 -070085 this, nullptr);
Gilad Arnold5ef9c482014-03-03 13:51:02 -080086
Gilad Arnoldef120fa2014-04-09 12:52:10 -070087 // Attempt to read initial connection status. Even if this fails because shill
88 // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
89 // signal as soon as it comes up, so this is not a critical step.
Alex Vakulenko88b591f2014-08-28 16:48:57 -070090 GHashTable* hash_table = nullptr;
Gilad Arnoldef120fa2014-04-09 12:52:10 -070091 if (GetProperties(manager_proxy_, &hash_table)) {
92 GValue* value = reinterpret_cast<GValue*>(
93 g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
94 ProcessDefaultService(value);
Gilad Arnold5ef9c482014-03-03 13:51:02 -080095 g_hash_table_unref(hash_table);
96 }
97
Gilad Arnoldef120fa2014-04-09 12:52:10 -070098 return true;
Gilad Arnold5ef9c482014-03-03 13:51:02 -080099}
100
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700101DBusGProxy* RealShillProvider::GetProxy(const char* path,
102 const char* interface) {
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800103 return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
104 path, interface);
105}
106
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700107bool RealShillProvider::GetProperties(DBusGProxy* proxy,
108 GHashTable** result_p) {
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700109 GError* error = nullptr;
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800110 if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
111 result_p)) {
112 LOG(ERROR) << "Calling shill via DBus proxy failed: "
113 << chromeos_update_engine::utils::GetAndFreeGError(&error);
114 return false;
115 }
116 return true;
117}
118
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700119bool RealShillProvider::ProcessDefaultService(GValue* value) {
120 // Decode the string from the boxed value.
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700121 const char* default_service_path_str = nullptr;
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700122 if (!(value && (default_service_path_str = g_value_get_string(value))))
123 return false;
124
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700125 // Anything changed?
126 if (default_service_path_ == default_service_path_str)
127 return true;
128
Gilad Arnoldd3df25f2014-04-22 08:39:48 -0700129 // Update the connection status.
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700130 default_service_path_ = default_service_path_str;
Gilad Arnoldd3df25f2014-04-22 08:39:48 -0700131 bool is_connected = (default_service_path_ != "/");
132 var_is_connected_.SetValue(is_connected);
133 var_conn_last_changed_.SetValue(clock_->GetWallclockTime());
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700134
Gilad Arnoldd3df25f2014-04-22 08:39:48 -0700135 // Update the connection attributes.
136 if (is_connected) {
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700137 DBusGProxy* service_proxy = GetProxy(default_service_path_.c_str(),
138 shill::kFlimflamServiceInterface);
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700139 GHashTable* hash_table = nullptr;
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700140 if (GetProperties(service_proxy, &hash_table)) {
141 // Get the connection type.
142 const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
143 if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
144 type_str = GetStrProperty(hash_table,
145 shill::kPhysicalTechnologyProperty);
146 }
147 if (type_str) {
Gilad Arnoldd3df25f2014-04-22 08:39:48 -0700148 var_conn_type_.SetValue(ParseConnectionType(type_str));
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700149 } else {
Gilad Arnoldd3df25f2014-04-22 08:39:48 -0700150 var_conn_type_.UnsetValue();
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700151 LOG(ERROR) << "Could not find connection type ("
152 << default_service_path_ << ")";
153 }
154
155 // Get the connection tethering mode.
156 const char* tethering_str = GetStrProperty(hash_table,
157 shill::kTetheringProperty);
158 if (tethering_str) {
Gilad Arnoldd3df25f2014-04-22 08:39:48 -0700159 var_conn_tethering_.SetValue(ParseConnectionTethering(tethering_str));
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700160 } else {
Gilad Arnoldd3df25f2014-04-22 08:39:48 -0700161 var_conn_tethering_.UnsetValue();
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700162 LOG(ERROR) << "Could not find connection tethering mode ("
163 << default_service_path_ << ")";
164 }
165
166 g_hash_table_unref(hash_table);
167 }
168 dbus_->ProxyUnref(service_proxy);
Gilad Arnoldd3df25f2014-04-22 08:39:48 -0700169 } else {
170 var_conn_type_.UnsetValue();
171 var_conn_tethering_.UnsetValue();
Gilad Arnoldef120fa2014-04-09 12:52:10 -0700172 }
Gilad Arnolddf3dd242014-04-09 07:15:51 -0700173
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700174 return true;
175}
176
177void RealShillProvider::HandlePropertyChanged(DBusGProxy* proxy,
178 const char* name, GValue* value) {
179 if (!strcmp(name, shill::kDefaultServiceProperty))
180 ProcessDefaultService(value);
181}
182
183void RealShillProvider::HandlePropertyChangedStatic(DBusGProxy* proxy,
184 const char* name,
185 GValue* value,
186 void* data) {
187 auto obj = reinterpret_cast<RealShillProvider*>(data);
188 obj->HandlePropertyChanged(proxy, name, value);
189}
190
Alex Deymo63784a52014-05-28 10:46:14 -0700191} // namespace chromeos_update_manager