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 <policy/device_policy.h> 25 #include <shill/dbus-constants.h> 26 #include <shill/dbus-proxies.h> 27 28 #include "update_engine/common/prefs.h" 29 #include "update_engine/common/utils.h" 30 #include "update_engine/connection_utils.h" 31 #include "update_engine/shill_proxy.h" 32 #include "update_engine/system_state.h" 33 34 using org::chromium::flimflam::ManagerProxyInterface; 35 using org::chromium::flimflam::ServiceProxyInterface; 36 using std::set; 37 using std::string; 38 39 namespace chromeos_update_engine { 40 41 namespace connection_manager { 42 std::unique_ptr<ConnectionManagerInterface> CreateConnectionManager( 43 SystemState* system_state) { 44 return std::unique_ptr<ConnectionManagerInterface>( 45 new ConnectionManager(new ShillProxy(), system_state)); 46 } 47 } 48 49 ConnectionManager::ConnectionManager(ShillProxyInterface* shill_proxy, 50 SystemState* system_state) 51 : shill_proxy_(shill_proxy), system_state_(system_state) {} 52 53 bool ConnectionManager::IsUpdateAllowedOver( 54 ConnectionType type, ConnectionTethering tethering) const { 55 switch (type) { 56 case ConnectionType::kBluetooth: 57 return false; 58 59 case ConnectionType::kCellular: { 60 set<string> allowed_types; 61 const policy::DevicePolicy* device_policy = 62 system_state_->device_policy(); 63 64 // A device_policy is loaded in a lazy way right before an update check, 65 // so the device_policy should be already loaded at this point. If it's 66 // not, return a safe value for this setting. 67 if (!device_policy) { 68 LOG(INFO) << "Disabling updates over cellular networks as there's no " 69 "device policy loaded yet."; 70 return false; 71 } 72 73 if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) { 74 // The update setting is enforced by the device policy. 75 76 if (!ContainsKey(allowed_types, shill::kTypeCellular)) { 77 LOG(INFO) << "Disabling updates over cellular connection as it's not " 78 "allowed in the device policy."; 79 return false; 80 } 81 82 LOG(INFO) << "Allowing updates over cellular per device policy."; 83 return true; 84 } else { 85 // There's no update setting in the device policy, using the local user 86 // setting. 87 PrefsInterface* prefs = system_state_->prefs(); 88 89 if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) { 90 LOG(INFO) << "Disabling updates over cellular connection as there's " 91 "no device policy setting nor user preference present."; 92 return false; 93 } 94 95 bool stored_value; 96 if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission, 97 &stored_value)) { 98 return false; 99 } 100 101 if (!stored_value) { 102 LOG(INFO) << "Disabling updates over cellular connection per user " 103 "setting."; 104 return false; 105 } 106 LOG(INFO) << "Allowing updates over cellular per user setting."; 107 return true; 108 } 109 } 110 111 default: 112 if (tethering == ConnectionTethering::kConfirmed) { 113 // Treat this connection as if it is a cellular connection. 114 LOG(INFO) << "Current connection is confirmed tethered, using Cellular " 115 "setting."; 116 return IsUpdateAllowedOver(ConnectionType::kCellular, 117 ConnectionTethering::kUnknown); 118 } 119 return true; 120 } 121 } 122 123 bool ConnectionManager::GetConnectionProperties( 124 ConnectionType* out_type, ConnectionTethering* out_tethering) { 125 dbus::ObjectPath default_service_path; 126 TEST_AND_RETURN_FALSE(GetDefaultServicePath(&default_service_path)); 127 if (!default_service_path.IsValid()) 128 return false; 129 // Shill uses the "/" service path to indicate that it is not connected. 130 if (default_service_path.value() == "/") 131 return false; 132 TEST_AND_RETURN_FALSE( 133 GetServicePathProperties(default_service_path, out_type, out_tethering)); 134 return true; 135 } 136 137 bool ConnectionManager::GetDefaultServicePath(dbus::ObjectPath* out_path) { 138 brillo::VariantDictionary properties; 139 brillo::ErrorPtr error; 140 ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy(); 141 if (!manager_proxy) 142 return false; 143 TEST_AND_RETURN_FALSE(manager_proxy->GetProperties(&properties, &error)); 144 145 const auto& prop_default_service = 146 properties.find(shill::kDefaultServiceProperty); 147 if (prop_default_service == properties.end()) 148 return false; 149 150 *out_path = prop_default_service->second.TryGet<dbus::ObjectPath>(); 151 return out_path->IsValid(); 152 } 153 154 bool ConnectionManager::GetServicePathProperties( 155 const dbus::ObjectPath& path, 156 ConnectionType* out_type, 157 ConnectionTethering* out_tethering) { 158 // We create and dispose the ServiceProxyInterface on every request. 159 std::unique_ptr<ServiceProxyInterface> service = 160 shill_proxy_->GetServiceForPath(path); 161 162 brillo::VariantDictionary properties; 163 brillo::ErrorPtr error; 164 TEST_AND_RETURN_FALSE(service->GetProperties(&properties, &error)); 165 166 // Populate the out_tethering. 167 const auto& prop_tethering = properties.find(shill::kTetheringProperty); 168 if (prop_tethering == properties.end()) { 169 // Set to Unknown if not present. 170 *out_tethering = ConnectionTethering::kUnknown; 171 } else { 172 // If the property doesn't contain a string value, the empty string will 173 // become kUnknown. 174 *out_tethering = connection_utils::ParseConnectionTethering( 175 prop_tethering->second.TryGet<string>()); 176 } 177 178 // Populate the out_type property. 179 const auto& prop_type = properties.find(shill::kTypeProperty); 180 if (prop_type == properties.end()) { 181 // Set to Unknown if not present. 182 *out_type = ConnectionType::kUnknown; 183 return false; 184 } 185 186 string type_str = prop_type->second.TryGet<string>(); 187 if (type_str == shill::kTypeVPN) { 188 const auto& prop_physical = 189 properties.find(shill::kPhysicalTechnologyProperty); 190 if (prop_physical == properties.end()) { 191 LOG(ERROR) << "No PhysicalTechnology property found for a VPN" 192 " connection (service: " 193 << path.value() << "). Returning default kUnknown value."; 194 *out_type = ConnectionType::kUnknown; 195 } else { 196 *out_type = connection_utils::ParseConnectionType( 197 prop_physical->second.TryGet<string>()); 198 } 199 } else { 200 *out_type = connection_utils::ParseConnectionType(type_str); 201 } 202 return true; 203 } 204 205 } // namespace chromeos_update_engine 206