connection_manager.cc revision aea4c1cea20dda7ae7e85fc8924a2d784f70d806
1// 2// Copyright (C) 2012 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/connection_manager.h" 18 19#include <set> 20#include <string> 21 22#include <base/stl_util.h> 23#include <base/strings/string_util.h> 24#include <chromeos/dbus/service_constants.h> 25#include <policy/device_policy.h> 26 27#include "update_engine/prefs.h" 28#include "update_engine/system_state.h" 29#include "update_engine/utils.h" 30 31using org::chromium::flimflam::ManagerProxyInterface; 32using org::chromium::flimflam::ServiceProxyInterface; 33using std::set; 34using std::string; 35 36namespace chromeos_update_engine { 37 38namespace { 39 40NetworkConnectionType ParseConnectionType(const string& type_str) { 41 if (type_str == shill::kTypeEthernet) { 42 return NetworkConnectionType::kEthernet; 43 } else if (type_str == shill::kTypeWifi) { 44 return NetworkConnectionType::kWifi; 45 } else if (type_str == shill::kTypeWimax) { 46 return NetworkConnectionType::kWimax; 47 } else if (type_str == shill::kTypeBluetooth) { 48 return NetworkConnectionType::kBluetooth; 49 } else if (type_str == shill::kTypeCellular) { 50 return NetworkConnectionType::kCellular; 51 } 52 return NetworkConnectionType::kUnknown; 53} 54 55NetworkTethering ParseTethering(const string& tethering_str) { 56 if (tethering_str == shill::kTetheringNotDetectedState) { 57 return NetworkTethering::kNotDetected; 58 } else if (tethering_str == shill::kTetheringSuspectedState) { 59 return NetworkTethering::kSuspected; 60 } else if (tethering_str == shill::kTetheringConfirmedState) { 61 return NetworkTethering::kConfirmed; 62 } 63 LOG(WARNING) << "Unknown Tethering value: " << tethering_str; 64 return NetworkTethering::kUnknown; 65} 66 67} // namespace 68 69ConnectionManager::ConnectionManager(ShillProxyInterface* shill_proxy, 70 SystemState* system_state) 71 : shill_proxy_(shill_proxy), system_state_(system_state) {} 72 73bool ConnectionManager::IsUpdateAllowedOver(NetworkConnectionType type, 74 NetworkTethering tethering) const { 75 switch (type) { 76 case NetworkConnectionType::kBluetooth: 77 return false; 78 79 case NetworkConnectionType::kCellular: { 80 set<string> allowed_types; 81 const policy::DevicePolicy* device_policy = 82 system_state_->device_policy(); 83 84 // A device_policy is loaded in a lazy way right before an update check, 85 // so the device_policy should be already loaded at this point. If it's 86 // not, return a safe value for this setting. 87 if (!device_policy) { 88 LOG(INFO) << "Disabling updates over cellular networks as there's no " 89 "device policy loaded yet."; 90 return false; 91 } 92 93 if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) { 94 // The update setting is enforced by the device policy. 95 96 if (!ContainsKey(allowed_types, shill::kTypeCellular)) { 97 LOG(INFO) << "Disabling updates over cellular connection as it's not " 98 "allowed in the device policy."; 99 return false; 100 } 101 102 LOG(INFO) << "Allowing updates over cellular per device policy."; 103 return true; 104 } else { 105 // There's no update setting in the device policy, using the local user 106 // setting. 107 PrefsInterface* prefs = system_state_->prefs(); 108 109 if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) { 110 LOG(INFO) << "Disabling updates over cellular connection as there's " 111 "no device policy setting nor user preference present."; 112 return false; 113 } 114 115 bool stored_value; 116 if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission, 117 &stored_value)) { 118 return false; 119 } 120 121 if (!stored_value) { 122 LOG(INFO) << "Disabling updates over cellular connection per user " 123 "setting."; 124 return false; 125 } 126 LOG(INFO) << "Allowing updates over cellular per user setting."; 127 return true; 128 } 129 } 130 131 default: 132 if (tethering == NetworkTethering::kConfirmed) { 133 // Treat this connection as if it is a cellular connection. 134 LOG(INFO) << "Current connection is confirmed tethered, using Cellular " 135 "setting."; 136 return IsUpdateAllowedOver(NetworkConnectionType::kCellular, 137 NetworkTethering::kUnknown); 138 } 139 return true; 140 } 141} 142 143// static 144const char* ConnectionManager::StringForConnectionType( 145 NetworkConnectionType type) { 146 switch (type) { 147 case NetworkConnectionType::kEthernet: 148 return shill::kTypeEthernet; 149 case NetworkConnectionType::kWifi: 150 return shill::kTypeWifi; 151 case NetworkConnectionType::kWimax: 152 return shill::kTypeWimax; 153 case NetworkConnectionType::kBluetooth: 154 return shill::kTypeBluetooth; 155 case NetworkConnectionType::kCellular: 156 return shill::kTypeCellular; 157 case NetworkConnectionType::kUnknown: 158 return "Unknown"; 159 } 160 return "Unknown"; 161} 162 163bool ConnectionManager::GetConnectionProperties( 164 NetworkConnectionType* out_type, 165 NetworkTethering* out_tethering) { 166 string default_service_path; 167 TEST_AND_RETURN_FALSE(GetDefaultServicePath(&default_service_path)); 168 if (default_service_path.empty()) 169 return false; 170 TEST_AND_RETURN_FALSE( 171 GetServicePathProperties(default_service_path, out_type, out_tethering)); 172 return true; 173} 174 175bool ConnectionManager::GetDefaultServicePath(string* out_path) { 176 chromeos::VariantDictionary properties; 177 chromeos::ErrorPtr error; 178 ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy(); 179 if (!manager_proxy) 180 return false; 181 TEST_AND_RETURN_FALSE(manager_proxy->GetProperties(&properties, &error)); 182 183 const auto& prop_default_service = 184 properties.find(shill::kDefaultServiceProperty); 185 if (prop_default_service == properties.end()) 186 return false; 187 188 *out_path = prop_default_service->second.TryGet<dbus::ObjectPath>().value(); 189 return !out_path->empty(); 190} 191 192bool ConnectionManager::GetServicePathProperties( 193 const string& path, 194 NetworkConnectionType* out_type, 195 NetworkTethering* out_tethering) { 196 // We create and dispose the ServiceProxyInterface on every request. 197 std::unique_ptr<ServiceProxyInterface> service = 198 shill_proxy_->GetServiceForPath(path); 199 200 chromeos::VariantDictionary properties; 201 chromeos::ErrorPtr error; 202 TEST_AND_RETURN_FALSE(service->GetProperties(&properties, &error)); 203 204 // Populate the out_tethering. 205 const auto& prop_tethering = properties.find(shill::kTetheringProperty); 206 if (prop_tethering == properties.end()) { 207 // Set to Unknown if not present. 208 *out_tethering = NetworkTethering::kUnknown; 209 } else { 210 // If the property doesn't contain a string value, the empty string will 211 // become kUnknown. 212 *out_tethering = ParseTethering(prop_tethering->second.TryGet<string>()); 213 } 214 215 // Populate the out_type property. 216 const auto& prop_type = properties.find(shill::kTypeProperty); 217 if (prop_type == properties.end()) { 218 // Set to Unknown if not present. 219 *out_type = NetworkConnectionType::kUnknown; 220 return false; 221 } 222 223 string type_str = prop_type->second.TryGet<string>(); 224 if (type_str == shill::kTypeVPN) { 225 const auto& prop_physical = 226 properties.find(shill::kPhysicalTechnologyProperty); 227 if (prop_physical == properties.end()) { 228 LOG(ERROR) << "No PhysicalTechnology property found for a VPN" 229 << " connection (service: " << path << "). Returning default" 230 << " kUnknown value."; 231 *out_type = NetworkConnectionType::kUnknown; 232 } else { 233 *out_type = ParseConnectionType(prop_physical->second.TryGet<string>()); 234 } 235 } else { 236 *out_type = ParseConnectionType(type_str); 237 } 238 return true; 239} 240 241} // namespace chromeos_update_engine 242