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