170 lines
6.2 KiB
C++
170 lines
6.2 KiB
C++
|
//
|
||
|
// Copyright (C) 2014 The Android Open Source Project
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
//
|
||
|
|
||
|
#include "update_engine/update_manager/real_shill_provider.h"
|
||
|
|
||
|
#include <string>
|
||
|
|
||
|
#include <base/logging.h>
|
||
|
#include <base/strings/stringprintf.h>
|
||
|
#include <brillo/type_name_undecorate.h>
|
||
|
#include <shill/dbus-constants.h>
|
||
|
#include <shill/dbus-proxies.h>
|
||
|
|
||
|
using chromeos_update_engine::SystemState;
|
||
|
using chromeos_update_engine::connection_utils::ParseConnectionType;
|
||
|
using org::chromium::flimflam::ManagerProxyInterface;
|
||
|
using org::chromium::flimflam::ServiceProxyInterface;
|
||
|
using std::string;
|
||
|
|
||
|
namespace chromeos_update_manager {
|
||
|
|
||
|
bool RealShillProvider::Init() {
|
||
|
ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy();
|
||
|
if (!manager_proxy)
|
||
|
return false;
|
||
|
|
||
|
// Subscribe to the manager's PropertyChanged signal.
|
||
|
manager_proxy->RegisterPropertyChangedSignalHandler(
|
||
|
base::Bind(&RealShillProvider::OnManagerPropertyChanged,
|
||
|
base::Unretained(this)),
|
||
|
base::Bind(&RealShillProvider::OnSignalConnected,
|
||
|
base::Unretained(this)));
|
||
|
|
||
|
// Attempt to read initial connection status. Even if this fails because shill
|
||
|
// is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
|
||
|
// signal as soon as it comes up, so this is not a critical step.
|
||
|
brillo::VariantDictionary properties;
|
||
|
brillo::ErrorPtr error;
|
||
|
if (!manager_proxy->GetProperties(&properties, &error))
|
||
|
return true;
|
||
|
|
||
|
const auto& prop_default_service =
|
||
|
properties.find(shill::kDefaultServiceProperty);
|
||
|
if (prop_default_service != properties.end()) {
|
||
|
OnManagerPropertyChanged(prop_default_service->first,
|
||
|
prop_default_service->second);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void RealShillProvider::OnManagerPropertyChanged(const string& name,
|
||
|
const brillo::Any& value) {
|
||
|
if (name == shill::kDefaultServiceProperty) {
|
||
|
dbus::ObjectPath service_path = value.TryGet<dbus::ObjectPath>();
|
||
|
if (!service_path.IsValid()) {
|
||
|
LOG(WARNING) << "Got an invalid DefaultService path. The property value "
|
||
|
"contains a "
|
||
|
<< value.GetUndecoratedTypeName()
|
||
|
<< ", read as the object path: '" << service_path.value()
|
||
|
<< "'";
|
||
|
}
|
||
|
ProcessDefaultService(service_path);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void RealShillProvider::OnSignalConnected(const string& interface_name,
|
||
|
const string& signal_name,
|
||
|
bool successful) {
|
||
|
if (!successful) {
|
||
|
LOG(ERROR) << "Couldn't connect to the signal " << interface_name << "."
|
||
|
<< signal_name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool RealShillProvider::ProcessDefaultService(
|
||
|
const dbus::ObjectPath& default_service_path) {
|
||
|
// We assume that if the service path didn't change, then the connection
|
||
|
// type and the tethering status of it also didn't change.
|
||
|
if (default_service_path_ == default_service_path)
|
||
|
return true;
|
||
|
|
||
|
// Update the connection status.
|
||
|
default_service_path_ = default_service_path;
|
||
|
bool is_connected =
|
||
|
(default_service_path_.IsValid() && default_service_path_.value() != "/");
|
||
|
var_is_connected_.SetValue(is_connected);
|
||
|
var_conn_last_changed_.SetValue(
|
||
|
SystemState::Get()->clock()->GetWallclockTime());
|
||
|
|
||
|
if (!is_connected) {
|
||
|
var_conn_type_.UnsetValue();
|
||
|
var_conn_tethering_.UnsetValue();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// We create and dispose the ServiceProxyInterface on every request.
|
||
|
std::unique_ptr<ServiceProxyInterface> service =
|
||
|
shill_proxy_->GetServiceForPath(default_service_path_);
|
||
|
|
||
|
// Get the connection properties synchronously.
|
||
|
brillo::VariantDictionary properties;
|
||
|
brillo::ErrorPtr error;
|
||
|
if (!service->GetProperties(&properties, &error)) {
|
||
|
var_conn_type_.UnsetValue();
|
||
|
var_conn_tethering_.UnsetValue();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Get the connection tethering mode.
|
||
|
const auto& prop_tethering = properties.find(shill::kTetheringProperty);
|
||
|
if (prop_tethering == properties.end()) {
|
||
|
// Remove the value if not present on the service. This most likely means an
|
||
|
// error in shill and the policy will handle it, but we will print a log
|
||
|
// message as well for accessing an unused variable.
|
||
|
var_conn_tethering_.UnsetValue();
|
||
|
LOG(ERROR) << "Could not find connection type (service: "
|
||
|
<< default_service_path_.value() << ")";
|
||
|
} else {
|
||
|
// If the property doesn't contain a string value, the empty string will
|
||
|
// become kUnknown.
|
||
|
var_conn_tethering_.SetValue(
|
||
|
chromeos_update_engine::connection_utils::ParseConnectionTethering(
|
||
|
prop_tethering->second.TryGet<string>()));
|
||
|
}
|
||
|
|
||
|
// Get the connection type.
|
||
|
const auto& prop_type = properties.find(shill::kTypeProperty);
|
||
|
if (prop_type == properties.end()) {
|
||
|
var_conn_type_.UnsetValue();
|
||
|
LOG(ERROR) << "Could not find connection tethering mode (service: "
|
||
|
<< default_service_path_.value() << ")";
|
||
|
} else {
|
||
|
string type_str = prop_type->second.TryGet<string>();
|
||
|
if (type_str == shill::kTypeVPN) {
|
||
|
const auto& prop_physical =
|
||
|
properties.find(shill::kPhysicalTechnologyProperty);
|
||
|
if (prop_physical == properties.end()) {
|
||
|
LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
|
||
|
<< " connection (service: " << default_service_path_.value()
|
||
|
<< "). Using default kUnknown value.";
|
||
|
var_conn_type_.SetValue(
|
||
|
chromeos_update_engine::ConnectionType::kUnknown);
|
||
|
} else {
|
||
|
var_conn_type_.SetValue(
|
||
|
ParseConnectionType(prop_physical->second.TryGet<string>()));
|
||
|
}
|
||
|
} else {
|
||
|
var_conn_type_.SetValue(ParseConnectionType(type_str));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
} // namespace chromeos_update_manager
|