real_shill_provider.cc revision 44666f97392f1f0f8be292fe6a4edcf9237540df
1// 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 5#include "update_engine/update_manager/real_shill_provider.h" 6 7#include <string> 8 9#include <base/logging.h> 10#include <base/strings/stringprintf.h> 11#include <chromeos/dbus/service_constants.h> 12 13#include "update_engine/glib_utils.h" 14 15using std::string; 16 17namespace { 18 19// Looks up a |key| in a GLib |hash_table| and returns the unboxed string from 20// the corresponding GValue, if found. 21const 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 29namespace chromeos_update_manager { 30 31RealShillProvider::~RealShillProvider() { 32 // Detach signal handler, free manager proxy. 33 dbus_->ProxyDisconnectSignal(manager_proxy_, shill::kMonitorPropertyChanged, 34 G_CALLBACK(HandlePropertyChangedStatic), 35 this); 36 dbus_->ProxyUnref(manager_proxy_); 37} 38 39ConnectionType 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; 50 51 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 66bool RealShillProvider::Init() { 67 // Obtain a DBus connection. 68 GError* error = NULL; 69 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 } 75 76 // Allocate a shill manager proxy. 77 manager_proxy_ = GetProxy(shill::kFlimflamServicePath, 78 shill::kFlimflamManagerInterface); 79 80 // 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, 84 G_CALLBACK(HandlePropertyChangedStatic), 85 this, NULL); 86 87 // 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. 90 GHashTable* hash_table = NULL; 91 if (GetProperties(manager_proxy_, &hash_table)) { 92 GValue* value = reinterpret_cast<GValue*>( 93 g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty)); 94 ProcessDefaultService(value); 95 g_hash_table_unref(hash_table); 96 } 97 98 return true; 99} 100 101DBusGProxy* RealShillProvider::GetProxy(const char* path, 102 const char* interface) { 103 return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName, 104 path, interface); 105} 106 107bool RealShillProvider::GetProperties(DBusGProxy* proxy, 108 GHashTable** result_p) { 109 GError* error = NULL; 110 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 119bool RealShillProvider::ProcessDefaultService(GValue* value) { 120 // Decode the string from the boxed value. 121 const char* default_service_path_str = NULL; 122 if (!(value && (default_service_path_str = g_value_get_string(value)))) 123 return false; 124 125 // Anything changed? 126 if (default_service_path_ == default_service_path_str) 127 return true; 128 129 // Update the connection status. 130 default_service_path_ = default_service_path_str; 131 bool is_connected = (default_service_path_ != "/"); 132 var_is_connected_.SetValue(is_connected); 133 var_conn_last_changed_.SetValue(clock_->GetWallclockTime()); 134 135 // Update the connection attributes. 136 if (is_connected) { 137 DBusGProxy* service_proxy = GetProxy(default_service_path_.c_str(), 138 shill::kFlimflamServiceInterface); 139 GHashTable* hash_table = NULL; 140 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) { 148 var_conn_type_.SetValue(ParseConnectionType(type_str)); 149 } else { 150 var_conn_type_.UnsetValue(); 151 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) { 159 var_conn_tethering_.SetValue(ParseConnectionTethering(tethering_str)); 160 } else { 161 var_conn_tethering_.UnsetValue(); 162 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); 169 } else { 170 var_conn_type_.UnsetValue(); 171 var_conn_tethering_.UnsetValue(); 172 } 173 174 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 191} // namespace chromeos_update_manager 192