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