This source file includes following definitions.
- GetListValue
- handler_
- OnPropertyChanged
- shill_manager_
- Init
- UpdateManagerProperties
- IsTechnologyAvailable
- IsTechnologyEnabled
- IsTechnologyEnabling
- IsTechnologyUninitialized
- SetTechnologyEnabled
- SetCheckPortalList
- RequestScan
- ConnectToBestServices
- RequestProperties
- OnPropertyChanged
- ManagerPropertiesCallback
- CheckPendingStateListUpdates
- ManagerPropertyChanged
- UpdateProperties
- UpdateObserved
- UpdateAvailableTechnologies
- UpdateEnabledTechnologies
- UpdateUninitializedTechnologies
- EnableTechnologyFailed
- GetPropertiesCallback
- PropertyChangedCallback
- NetworkServicePropertyChangedCallback
- GetIPConfigCallback
- UpdateIPConfigProperty
- NetworkDevicePropertyChangedCallback
#include "chromeos/network/shill_property_handler.h"
#include "base/bind.h"
#include "base/format_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_device_client.h"
#include "chromeos/dbus/shill_ipconfig_client.h"
#include "chromeos/dbus/shill_manager_client.h"
#include "chromeos/dbus/shill_profile_client.h"
#include "chromeos/dbus/shill_service_client.h"
#include "chromeos/network/network_event_log.h"
#include "chromeos/network/network_state.h"
#include "dbus/object_path.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace {
const size_t kMaxObserved = 100;
const base::ListValue* GetListValue(const std::string& key,
const base::Value& value) {
const base::ListValue* vlist = NULL;
if (!value.GetAsList(&vlist)) {
LOG(ERROR) << "Error parsing key as list: " << key;
return NULL;
}
return vlist;
}
}
namespace chromeos {
namespace internal {
class ShillPropertyObserver : public ShillPropertyChangedObserver {
public:
typedef base::Callback<void(ManagedState::ManagedType type,
const std::string& service,
const std::string& name,
const base::Value& value)> Handler;
ShillPropertyObserver(ManagedState::ManagedType type,
const std::string& path,
const Handler& handler)
: type_(type),
path_(path),
handler_(handler) {
if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
DBusThreadManager::Get()->GetShillServiceClient()->
AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
} else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
DBusThreadManager::Get()->GetShillDeviceClient()->
AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
} else {
NOTREACHED();
}
}
virtual ~ShillPropertyObserver() {
if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
DBusThreadManager::Get()->GetShillServiceClient()->
RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
} else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
DBusThreadManager::Get()->GetShillDeviceClient()->
RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
} else {
NOTREACHED();
}
}
virtual void OnPropertyChanged(const std::string& key,
const base::Value& value) OVERRIDE {
handler_.Run(type_, path_, key, value);
}
private:
ManagedState::ManagedType type_;
std::string path_;
Handler handler_;
DISALLOW_COPY_AND_ASSIGN(ShillPropertyObserver);
};
ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
: listener_(listener),
shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()) {
}
ShillPropertyHandler::~ShillPropertyHandler() {
STLDeleteContainerPairSecondPointers(
observed_networks_.begin(), observed_networks_.end());
STLDeleteContainerPairSecondPointers(
observed_devices_.begin(), observed_devices_.end());
CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
shill_manager_->RemovePropertyChangedObserver(this);
}
void ShillPropertyHandler::Init() {
UpdateManagerProperties();
shill_manager_->AddPropertyChangedObserver(this);
}
void ShillPropertyHandler::UpdateManagerProperties() {
NET_LOG_EVENT("UpdateManagerProperties", "");
shill_manager_->GetProperties(
base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback,
AsWeakPtr()));
}
bool ShillPropertyHandler::IsTechnologyAvailable(
const std::string& technology) const {
return available_technologies_.count(technology) != 0;
}
bool ShillPropertyHandler::IsTechnologyEnabled(
const std::string& technology) const {
return enabled_technologies_.count(technology) != 0;
}
bool ShillPropertyHandler::IsTechnologyEnabling(
const std::string& technology) const {
return enabling_technologies_.count(technology) != 0;
}
bool ShillPropertyHandler::IsTechnologyUninitialized(
const std::string& technology) const {
return uninitialized_technologies_.count(technology) != 0;
}
void ShillPropertyHandler::SetTechnologyEnabled(
const std::string& technology,
bool enabled,
const network_handler::ErrorCallback& error_callback) {
if (enabled) {
enabling_technologies_.insert(technology);
shill_manager_->EnableTechnology(
technology,
base::Bind(&base::DoNothing),
base::Bind(&ShillPropertyHandler::EnableTechnologyFailed,
AsWeakPtr(), technology, error_callback));
} else {
enabled_technologies_.erase(technology);
enabling_technologies_.erase(technology);
shill_manager_->DisableTechnology(
technology,
base::Bind(&base::DoNothing),
base::Bind(&network_handler::ShillErrorCallbackFunction,
"SetTechnologyEnabled Failed",
technology, error_callback));
}
}
void ShillPropertyHandler::SetCheckPortalList(
const std::string& check_portal_list) {
base::StringValue value(check_portal_list);
shill_manager_->SetProperty(
shill::kCheckPortalListProperty,
value,
base::Bind(&base::DoNothing),
base::Bind(&network_handler::ShillErrorCallbackFunction,
"SetCheckPortalList Failed",
"", network_handler::ErrorCallback()));
}
void ShillPropertyHandler::RequestScan() const {
shill_manager_->RequestScan(
"",
base::Bind(&base::DoNothing),
base::Bind(&network_handler::ShillErrorCallbackFunction,
"RequestScan Failed",
"", network_handler::ErrorCallback()));
}
void ShillPropertyHandler::ConnectToBestServices() const {
NET_LOG_EVENT("ConnectToBestServices", "");
shill_manager_->ConnectToBestServices(
base::Bind(&base::DoNothing),
base::Bind(&network_handler::ShillErrorCallbackFunction,
"ConnectToBestServices Failed",
"", network_handler::ErrorCallback()));
}
void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
const std::string& path) {
if (pending_updates_[type].find(path) != pending_updates_[type].end())
return;
NET_LOG_DEBUG("Request Properties", path);
pending_updates_[type].insert(path);
if (type == ManagedState::MANAGED_TYPE_NETWORK ||
type == ManagedState::MANAGED_TYPE_FAVORITE) {
DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
dbus::ObjectPath(path),
base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
AsWeakPtr(), type, path));
} else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
dbus::ObjectPath(path),
base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
AsWeakPtr(), type, path));
} else {
NOTREACHED();
}
}
void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
const base::Value& value) {
ManagerPropertyChanged(key, value);
CheckPendingStateListUpdates(key);
}
void ShillPropertyHandler::ManagerPropertiesCallback(
DBusMethodCallStatus call_status,
const base::DictionaryValue& properties) {
if (call_status != DBUS_METHOD_CALL_SUCCESS) {
NET_LOG_ERROR("ManagerPropertiesCallback",
base::StringPrintf("Failed: %d", call_status));
return;
}
NET_LOG_EVENT("ManagerPropertiesCallback", "Success");
const base::Value* update_service_value = NULL;
const base::Value* update_service_complete_value = NULL;
for (base::DictionaryValue::Iterator iter(properties);
!iter.IsAtEnd(); iter.Advance()) {
if (iter.key() == shill::kServicesProperty)
update_service_value = &iter.value();
else if (iter.key() == shill::kServiceCompleteListProperty)
update_service_complete_value = &iter.value();
else
ManagerPropertyChanged(iter.key(), iter.value());
}
if (update_service_value)
ManagerPropertyChanged(shill::kServicesProperty, *update_service_value);
if (update_service_complete_value) {
ManagerPropertyChanged(shill::kServiceCompleteListProperty,
*update_service_complete_value);
}
CheckPendingStateListUpdates("");
}
void ShillPropertyHandler::CheckPendingStateListUpdates(
const std::string& key) {
if ((key.empty() || key == shill::kServicesProperty) &&
pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
}
if ((key.empty() || key == shill::kServiceCompleteListProperty) &&
pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0 &&
pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) {
listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE);
}
if ((key.empty() || key == shill::kDevicesProperty) &&
pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
}
}
void ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
const base::Value& value) {
if (key == shill::kDefaultServiceProperty) {
std::string service_path;
value.GetAsString(&service_path);
listener_->DefaultNetworkServiceChanged(service_path);
} else if (key == shill::kServicesProperty) {
const base::ListValue* vlist = GetListValue(key, value);
if (vlist) {
listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
}
} else if (key == shill::kServiceCompleteListProperty) {
const base::ListValue* vlist = GetListValue(key, value);
if (vlist) {
listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_FAVORITE, *vlist);
UpdateProperties(ManagedState::MANAGED_TYPE_FAVORITE, *vlist);
}
} else if (key == shill::kDevicesProperty) {
const base::ListValue* vlist = GetListValue(key, value);
if (vlist) {
listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
}
} else if (key == shill::kAvailableTechnologiesProperty) {
const base::ListValue* vlist = GetListValue(key, value);
if (vlist)
UpdateAvailableTechnologies(*vlist);
} else if (key == shill::kEnabledTechnologiesProperty) {
const base::ListValue* vlist = GetListValue(key, value);
if (vlist)
UpdateEnabledTechnologies(*vlist);
} else if (key == shill::kUninitializedTechnologiesProperty) {
const base::ListValue* vlist = GetListValue(key, value);
if (vlist)
UpdateUninitializedTechnologies(*vlist);
} else if (key == shill::kProfilesProperty) {
listener_->ProfileListChanged();
} else if (key == shill::kCheckPortalListProperty) {
std::string check_portal_list;
if (value.GetAsString(&check_portal_list))
listener_->CheckPortalListChanged(check_portal_list);
} else {
VLOG(2) << "Ignored Manager Property: " << key;
}
}
void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type,
const base::ListValue& entries) {
std::set<std::string>& requested_updates = requested_updates_[type];
std::set<std::string>& requested_service_updates =
requested_updates_[ManagedState::MANAGED_TYPE_NETWORK];
std::set<std::string> new_requested_updates;
NET_LOG_DEBUG(
base::StringPrintf("UpdateProperties: %" PRIuS, entries.GetSize()),
ManagedState::TypeToString(type));
for (base::ListValue::const_iterator iter = entries.begin();
iter != entries.end(); ++iter) {
std::string path;
(*iter)->GetAsString(&path);
if (path.empty())
continue;
if (type == ManagedState::MANAGED_TYPE_FAVORITE &&
requested_service_updates.count(path) > 0)
continue;
if (type == ManagedState::MANAGED_TYPE_DEVICE ||
requested_updates.find(path) == requested_updates.end())
RequestProperties(type, path);
new_requested_updates.insert(path);
}
requested_updates.swap(new_requested_updates);
}
void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
const base::ListValue& entries) {
DCHECK(type == ManagedState::MANAGED_TYPE_NETWORK ||
type == ManagedState::MANAGED_TYPE_DEVICE);
ShillPropertyObserverMap& observer_map =
(type == ManagedState::MANAGED_TYPE_NETWORK)
? observed_networks_ : observed_devices_;
ShillPropertyObserverMap new_observed;
for (base::ListValue::const_iterator iter1 = entries.begin();
iter1 != entries.end(); ++iter1) {
std::string path;
(*iter1)->GetAsString(&path);
if (path.empty())
continue;
ShillPropertyObserverMap::iterator iter2 = observer_map.find(path);
if (iter2 != observer_map.end()) {
new_observed[path] = iter2->second;
} else {
new_observed[path] = new ShillPropertyObserver(
type, path, base::Bind(
&ShillPropertyHandler::PropertyChangedCallback, AsWeakPtr()));
}
observer_map.erase(path);
if (new_observed.size() >= kMaxObserved)
break;
}
for (ShillPropertyObserverMap::iterator iter = observer_map.begin();
iter != observer_map.end(); ++iter) {
delete iter->second;
}
observer_map.swap(new_observed);
}
void ShillPropertyHandler::UpdateAvailableTechnologies(
const base::ListValue& technologies) {
available_technologies_.clear();
NET_LOG_EVENT("AvailableTechnologiesChanged",
base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
for (base::ListValue::const_iterator iter = technologies.begin();
iter != technologies.end(); ++iter) {
std::string technology;
(*iter)->GetAsString(&technology);
DCHECK(!technology.empty());
available_technologies_.insert(technology);
}
listener_->TechnologyListChanged();
}
void ShillPropertyHandler::UpdateEnabledTechnologies(
const base::ListValue& technologies) {
enabled_technologies_.clear();
NET_LOG_EVENT("EnabledTechnologiesChanged",
base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
for (base::ListValue::const_iterator iter = technologies.begin();
iter != technologies.end(); ++iter) {
std::string technology;
(*iter)->GetAsString(&technology);
DCHECK(!technology.empty());
enabled_technologies_.insert(technology);
enabling_technologies_.erase(technology);
}
listener_->TechnologyListChanged();
}
void ShillPropertyHandler::UpdateUninitializedTechnologies(
const base::ListValue& technologies) {
uninitialized_technologies_.clear();
NET_LOG_EVENT("UninitializedTechnologiesChanged",
base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
for (base::ListValue::const_iterator iter = technologies.begin();
iter != technologies.end(); ++iter) {
std::string technology;
(*iter)->GetAsString(&technology);
DCHECK(!technology.empty());
uninitialized_technologies_.insert(technology);
}
listener_->TechnologyListChanged();
}
void ShillPropertyHandler::EnableTechnologyFailed(
const std::string& technology,
const network_handler::ErrorCallback& error_callback,
const std::string& dbus_error_name,
const std::string& dbus_error_message) {
enabling_technologies_.erase(technology);
network_handler::ShillErrorCallbackFunction(
"EnableTechnology Failed",
technology, error_callback,
dbus_error_name, dbus_error_message);
}
void ShillPropertyHandler::GetPropertiesCallback(
ManagedState::ManagedType type,
const std::string& path,
DBusMethodCallStatus call_status,
const base::DictionaryValue& properties) {
NET_LOG_DEBUG("GetPropertiesCallback: " + ManagedState::TypeToString(type),
path);
pending_updates_[type].erase(path);
if (call_status != DBUS_METHOD_CALL_SUCCESS) {
NET_LOG_DEBUG("Failed to get properties",
base::StringPrintf("%s: %d", path.c_str(), call_status));
return;
}
if (type == ManagedState::MANAGED_TYPE_NETWORK) {
std::string profile_path;
properties.GetStringWithoutPathExpansion(
shill::kProfileProperty, &profile_path);
if (!profile_path.empty()) {
listener_->UpdateManagedStateProperties(
ManagedState::MANAGED_TYPE_FAVORITE, path, properties);
}
}
listener_->UpdateManagedStateProperties(type, path, properties);
if (type == ManagedState::MANAGED_TYPE_NETWORK &&
properties.HasKey(shill::kIPConfigProperty)) {
std::string ip_config_path;
if (properties.GetString(shill::kIPConfigProperty, &ip_config_path)) {
DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
dbus::ObjectPath(ip_config_path),
base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
AsWeakPtr(), path));
}
}
if (pending_updates_[type].size() == 0) {
listener_->ManagedStateListChanged(type);
if (type == ManagedState::MANAGED_TYPE_NETWORK &&
pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) {
listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE);
}
}
}
void ShillPropertyHandler::PropertyChangedCallback(
ManagedState::ManagedType type,
const std::string& path,
const std::string& key,
const base::Value& value) {
if (type == ManagedState::MANAGED_TYPE_NETWORK)
NetworkServicePropertyChangedCallback(path, key, value);
else if (type == ManagedState::MANAGED_TYPE_DEVICE)
NetworkDevicePropertyChangedCallback(path, key, value);
else
NOTREACHED();
}
void ShillPropertyHandler::NetworkServicePropertyChangedCallback(
const std::string& path,
const std::string& key,
const base::Value& value) {
if (key == shill::kIPConfigProperty) {
std::string ip_config_path;
value.GetAsString(&ip_config_path);
DCHECK(!ip_config_path.empty());
DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
dbus::ObjectPath(ip_config_path),
base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
AsWeakPtr(), path));
} else {
listener_->UpdateNetworkServiceProperty(path, key, value);
}
}
void ShillPropertyHandler::GetIPConfigCallback(
const std::string& service_path,
DBusMethodCallStatus call_status,
const base::DictionaryValue& properties) {
if (call_status != DBUS_METHOD_CALL_SUCCESS) {
NET_LOG_ERROR("Failed to get IP Config properties",
base::StringPrintf("%s: %d",
service_path.c_str(), call_status));
return;
}
UpdateIPConfigProperty(service_path, properties, shill::kAddressProperty);
UpdateIPConfigProperty(service_path, properties, shill::kNameServersProperty);
UpdateIPConfigProperty(service_path, properties, shill::kPrefixlenProperty);
UpdateIPConfigProperty(service_path, properties, shill::kGatewayProperty);
UpdateIPConfigProperty(service_path, properties,
shill::kWebProxyAutoDiscoveryUrlProperty);
}
void ShillPropertyHandler::UpdateIPConfigProperty(
const std::string& service_path,
const base::DictionaryValue& properties,
const char* property) {
const base::Value* value;
if (!properties.GetWithoutPathExpansion(property, &value)) {
LOG(ERROR) << "Failed to get IPConfig property: " << property
<< ", for: " << service_path;
return;
}
listener_->UpdateNetworkServiceProperty(
service_path, NetworkState::IPConfigProperty(property), *value);
}
void ShillPropertyHandler::NetworkDevicePropertyChangedCallback(
const std::string& path,
const std::string& key,
const base::Value& value) {
listener_->UpdateDeviceProperty(path, key, value);
}
}
}