Home | History | Annotate | Download | only in update_manager
      1 //
      2 // Copyright (C) 2014 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/update_manager/real_shill_provider.h"
     18 
     19 #include <string>
     20 
     21 #include <base/logging.h>
     22 #include <base/strings/stringprintf.h>
     23 #include <brillo/type_name_undecorate.h>
     24 #include <shill/dbus-constants.h>
     25 #include <shill/dbus-proxies.h>
     26 
     27 using org::chromium::flimflam::ManagerProxyInterface;
     28 using org::chromium::flimflam::ServiceProxyInterface;
     29 using std::string;
     30 
     31 namespace chromeos_update_manager {
     32 
     33 ConnectionType RealShillProvider::ParseConnectionType(const string& type_str) {
     34   if (type_str == shill::kTypeEthernet) {
     35     return ConnectionType::kEthernet;
     36   } else if (type_str == shill::kTypeWifi) {
     37     return ConnectionType::kWifi;
     38   } else if (type_str == shill::kTypeWimax) {
     39     return ConnectionType::kWimax;
     40   } else if (type_str == shill::kTypeBluetooth) {
     41     return ConnectionType::kBluetooth;
     42   } else if (type_str == shill::kTypeCellular) {
     43     return ConnectionType::kCellular;
     44   }
     45   return ConnectionType::kUnknown;
     46 }
     47 
     48 ConnectionTethering RealShillProvider::ParseConnectionTethering(
     49     const string& tethering_str) {
     50   if (tethering_str == shill::kTetheringNotDetectedState) {
     51     return ConnectionTethering::kNotDetected;
     52   } else if (tethering_str == shill::kTetheringSuspectedState) {
     53     return ConnectionTethering::kSuspected;
     54   } else if (tethering_str == shill::kTetheringConfirmedState) {
     55     return ConnectionTethering::kConfirmed;
     56   }
     57   return ConnectionTethering::kUnknown;
     58 }
     59 
     60 bool RealShillProvider::Init() {
     61   ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy();
     62   if (!manager_proxy)
     63     return false;
     64 
     65   // Subscribe to the manager's PropertyChanged signal.
     66   manager_proxy->RegisterPropertyChangedSignalHandler(
     67       base::Bind(&RealShillProvider::OnManagerPropertyChanged,
     68                  base::Unretained(this)),
     69       base::Bind(&RealShillProvider::OnSignalConnected,
     70                  base::Unretained(this)));
     71 
     72   // Attempt to read initial connection status. Even if this fails because shill
     73   // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
     74   // signal as soon as it comes up, so this is not a critical step.
     75   brillo::VariantDictionary properties;
     76   brillo::ErrorPtr error;
     77   if (!manager_proxy->GetProperties(&properties, &error))
     78     return true;
     79 
     80   const auto& prop_default_service =
     81       properties.find(shill::kDefaultServiceProperty);
     82   if (prop_default_service != properties.end()) {
     83     OnManagerPropertyChanged(prop_default_service->first,
     84                              prop_default_service->second);
     85   }
     86 
     87   return true;
     88 }
     89 
     90 void RealShillProvider::OnManagerPropertyChanged(const string& name,
     91                                                  const brillo::Any& value) {
     92   if (name == shill::kDefaultServiceProperty) {
     93     dbus::ObjectPath service_path = value.TryGet<dbus::ObjectPath>();
     94     if (!service_path.IsValid()) {
     95       LOG(WARNING) << "Got an invalid DefaultService path. The property value "
     96                       "contains a "
     97                    << value.GetUndecoratedTypeName()
     98                    << ", read as the object path: '" << service_path.value()
     99                    << "'";
    100     }
    101     ProcessDefaultService(service_path);
    102   }
    103 }
    104 
    105 void RealShillProvider::OnSignalConnected(const string& interface_name,
    106                                           const string& signal_name,
    107                                           bool successful) {
    108   if (!successful) {
    109     LOG(ERROR) << "Couldn't connect to the signal " << interface_name << "."
    110                << signal_name;
    111   }
    112 }
    113 
    114 bool RealShillProvider::ProcessDefaultService(
    115     const dbus::ObjectPath& default_service_path) {
    116   // We assume that if the service path didn't change, then the connection
    117   // type and the tethering status of it also didn't change.
    118   if (default_service_path_ == default_service_path)
    119     return true;
    120 
    121   // Update the connection status.
    122   default_service_path_ = default_service_path;
    123   bool is_connected = (default_service_path_.IsValid() &&
    124                        default_service_path_.value() != "/");
    125   var_is_connected_.SetValue(is_connected);
    126   var_conn_last_changed_.SetValue(clock_->GetWallclockTime());
    127 
    128   if (!is_connected) {
    129     var_conn_type_.UnsetValue();
    130     var_conn_tethering_.UnsetValue();
    131     return true;
    132   }
    133 
    134   // We create and dispose the ServiceProxyInterface on every request.
    135   std::unique_ptr<ServiceProxyInterface> service =
    136       shill_proxy_->GetServiceForPath(default_service_path_);
    137 
    138   // Get the connection properties synchronously.
    139   brillo::VariantDictionary properties;
    140   brillo::ErrorPtr error;
    141   if (!service->GetProperties(&properties, &error)) {
    142     var_conn_type_.UnsetValue();
    143     var_conn_tethering_.UnsetValue();
    144     return false;
    145   }
    146 
    147   // Get the connection tethering mode.
    148   const auto& prop_tethering = properties.find(shill::kTetheringProperty);
    149   if (prop_tethering == properties.end()) {
    150     // Remove the value if not present on the service. This most likely means an
    151     // error in shill and the policy will handle it, but we will print a log
    152     // message as well for accessing an unused variable.
    153     var_conn_tethering_.UnsetValue();
    154     LOG(ERROR) << "Could not find connection type (service: "
    155                << default_service_path_.value() << ")";
    156   } else {
    157     // If the property doesn't contain a string value, the empty string will
    158     // become kUnknown.
    159     var_conn_tethering_.SetValue(
    160         ParseConnectionTethering(prop_tethering->second.TryGet<string>()));
    161   }
    162 
    163   // Get the connection type.
    164   const auto& prop_type = properties.find(shill::kTypeProperty);
    165   if (prop_type == properties.end()) {
    166     var_conn_type_.UnsetValue();
    167     LOG(ERROR) << "Could not find connection tethering mode (service: "
    168                << default_service_path_.value() << ")";
    169   } else {
    170     string type_str = prop_type->second.TryGet<string>();
    171     if (type_str == shill::kTypeVPN) {
    172       const auto& prop_physical =
    173           properties.find(shill::kPhysicalTechnologyProperty);
    174       if (prop_physical == properties.end()) {
    175         LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
    176                    << " connection (service: " << default_service_path_.value()
    177                    << "). Using default kUnknown value.";
    178         var_conn_type_.SetValue(ConnectionType::kUnknown);
    179       } else {
    180         var_conn_type_.SetValue(
    181             ParseConnectionType(prop_physical->second.TryGet<string>()));
    182       }
    183     } else {
    184       var_conn_type_.SetValue(ParseConnectionType(type_str));
    185     }
    186   }
    187 
    188   return true;
    189 }
    190 
    191 }  // namespace chromeos_update_manager
    192