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