1 // 2 // Copyright (C) 2014 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "update_engine/update_manager/real_shill_provider.h" 18 19 #include <string> 20 21 #include <base/logging.h> 22 #include <base/strings/stringprintf.h> 23 #include <brillo/type_name_undecorate.h> 24 #include <shill/dbus-constants.h> 25 #include <shill/dbus-proxies.h> 26 27 using chromeos_update_engine::connection_utils::ParseConnectionType; 28 using org::chromium::flimflam::ManagerProxyInterface; 29 using org::chromium::flimflam::ServiceProxyInterface; 30 using std::string; 31 32 namespace chromeos_update_manager { 33 34 bool RealShillProvider::Init() { 35 ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy(); 36 if (!manager_proxy) 37 return false; 38 39 // Subscribe to the manager's PropertyChanged signal. 40 manager_proxy->RegisterPropertyChangedSignalHandler( 41 base::Bind(&RealShillProvider::OnManagerPropertyChanged, 42 base::Unretained(this)), 43 base::Bind(&RealShillProvider::OnSignalConnected, 44 base::Unretained(this))); 45 46 // Attempt to read initial connection status. Even if this fails because shill 47 // is not responding (e.g. it is down) we'll be notified via "PropertyChanged" 48 // signal as soon as it comes up, so this is not a critical step. 49 brillo::VariantDictionary properties; 50 brillo::ErrorPtr error; 51 if (!manager_proxy->GetProperties(&properties, &error)) 52 return true; 53 54 const auto& prop_default_service = 55 properties.find(shill::kDefaultServiceProperty); 56 if (prop_default_service != properties.end()) { 57 OnManagerPropertyChanged(prop_default_service->first, 58 prop_default_service->second); 59 } 60 61 return true; 62 } 63 64 void RealShillProvider::OnManagerPropertyChanged(const string& name, 65 const brillo::Any& value) { 66 if (name == shill::kDefaultServiceProperty) { 67 dbus::ObjectPath service_path = value.TryGet<dbus::ObjectPath>(); 68 if (!service_path.IsValid()) { 69 LOG(WARNING) << "Got an invalid DefaultService path. The property value " 70 "contains a " 71 << value.GetUndecoratedTypeName() 72 << ", read as the object path: '" << service_path.value() 73 << "'"; 74 } 75 ProcessDefaultService(service_path); 76 } 77 } 78 79 void RealShillProvider::OnSignalConnected(const string& interface_name, 80 const string& signal_name, 81 bool successful) { 82 if (!successful) { 83 LOG(ERROR) << "Couldn't connect to the signal " << interface_name << "." 84 << signal_name; 85 } 86 } 87 88 bool RealShillProvider::ProcessDefaultService( 89 const dbus::ObjectPath& default_service_path) { 90 // We assume that if the service path didn't change, then the connection 91 // type and the tethering status of it also didn't change. 92 if (default_service_path_ == default_service_path) 93 return true; 94 95 // Update the connection status. 96 default_service_path_ = default_service_path; 97 bool is_connected = 98 (default_service_path_.IsValid() && default_service_path_.value() != "/"); 99 var_is_connected_.SetValue(is_connected); 100 var_conn_last_changed_.SetValue(clock_->GetWallclockTime()); 101 102 if (!is_connected) { 103 var_conn_type_.UnsetValue(); 104 var_conn_tethering_.UnsetValue(); 105 return true; 106 } 107 108 // We create and dispose the ServiceProxyInterface on every request. 109 std::unique_ptr<ServiceProxyInterface> service = 110 shill_proxy_->GetServiceForPath(default_service_path_); 111 112 // Get the connection properties synchronously. 113 brillo::VariantDictionary properties; 114 brillo::ErrorPtr error; 115 if (!service->GetProperties(&properties, &error)) { 116 var_conn_type_.UnsetValue(); 117 var_conn_tethering_.UnsetValue(); 118 return false; 119 } 120 121 // Get the connection tethering mode. 122 const auto& prop_tethering = properties.find(shill::kTetheringProperty); 123 if (prop_tethering == properties.end()) { 124 // Remove the value if not present on the service. This most likely means an 125 // error in shill and the policy will handle it, but we will print a log 126 // message as well for accessing an unused variable. 127 var_conn_tethering_.UnsetValue(); 128 LOG(ERROR) << "Could not find connection type (service: " 129 << default_service_path_.value() << ")"; 130 } else { 131 // If the property doesn't contain a string value, the empty string will 132 // become kUnknown. 133 var_conn_tethering_.SetValue( 134 chromeos_update_engine::connection_utils::ParseConnectionTethering( 135 prop_tethering->second.TryGet<string>())); 136 } 137 138 // Get the connection type. 139 const auto& prop_type = properties.find(shill::kTypeProperty); 140 if (prop_type == properties.end()) { 141 var_conn_type_.UnsetValue(); 142 LOG(ERROR) << "Could not find connection tethering mode (service: " 143 << default_service_path_.value() << ")"; 144 } else { 145 string type_str = prop_type->second.TryGet<string>(); 146 if (type_str == shill::kTypeVPN) { 147 const auto& prop_physical = 148 properties.find(shill::kPhysicalTechnologyProperty); 149 if (prop_physical == properties.end()) { 150 LOG(ERROR) << "No PhysicalTechnology property found for a VPN" 151 << " connection (service: " << default_service_path_.value() 152 << "). Using default kUnknown value."; 153 var_conn_type_.SetValue( 154 chromeos_update_engine::ConnectionType::kUnknown); 155 } else { 156 var_conn_type_.SetValue( 157 ParseConnectionType(prop_physical->second.TryGet<string>())); 158 } 159 } else { 160 var_conn_type_.SetValue(ParseConnectionType(type_str)); 161 } 162 } 163 164 return true; 165 } 166 167 } // namespace chromeos_update_manager 168