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/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