blob: dfd574cacee2836faca37cc63a8e651a87fc9146 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/crosapi/networking_private_ash.h"
#include "base/values.h"
#include "chrome/browser/ash/crosapi/crosapi_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chromeos/ash/components/network/device_state.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/crosapi/mojom/networking_private.mojom-forward.h"
#include "chromeos/crosapi/mojom/networking_private.mojom.h"
#include "extensions/browser/api/networking_private/networking_private_delegate.h"
#include "extensions/browser/api/networking_private/networking_private_delegate_factory.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
using ::ash::NetworkHandler;
using ::ash::NetworkState;
using ::ash::NetworkStateHandler;
namespace crosapi {
namespace {
extensions::NetworkingPrivateDelegate* GetDelegate() {
Profile* primary_profile =
g_browser_process->profile_manager()->GetPrimaryUserProfile();
return extensions::NetworkingPrivateDelegateFactory::GetForBrowserContext(
primary_profile);
}
// Following are several adapter callbacks which make the mojo callbacks
// compatible with the NetworkingPrivateDelegate callbacks.
//
// Some The crosapi::mojom::NetworkingPrivate calls expect a single callback,
// whereas the API passes in two (one for success and one for failure).
// A failure will be signaled by a non empty string.
//
// See networking_private_lacros.cc for the reverse operation.
// This function splits the callback into a void success call and an error call.
using VoidSuccessOrFailureCallback =
base::OnceCallback<void(const std::string& error_message)>;
std::pair<extensions::NetworkingPrivateDelegate::VoidCallback,
extensions::NetworkingPrivateDelegate::FailureCallback>
SplitVoidAdapterCallback(VoidSuccessOrFailureCallback callback) {
auto [success, failure] = base::SplitOnceCallback(std::move(callback));
return {base::BindOnce(
[](VoidSuccessOrFailureCallback callback) {
std::move(callback).Run("");
},
std::move(success)),
base::BindOnce(
[](VoidSuccessOrFailureCallback callback,
const std::string& error) { std::move(callback).Run(error); },
std::move(failure))};
}
// This function splits the callback into a success call returning a string and
// an error call.
using StringSuccessOrFailureCallback =
base::OnceCallback<void(mojom::StringSuccessOrErrorReturnPtr result)>;
std::pair<extensions::NetworkingPrivateDelegate::StringCallback,
extensions::NetworkingPrivateDelegate::FailureCallback>
SplitStringAdapterCallback(StringSuccessOrFailureCallback callback) {
auto [success, failure] = base::SplitOnceCallback(std::move(callback));
return {
base::BindOnce(
[](StringSuccessOrFailureCallback callback,
const std::string& result) {
std::move(callback).Run(
mojom::StringSuccessOrErrorReturn::NewSuccessResult(result));
},
std::move(success)),
base::BindOnce(
[](StringSuccessOrFailureCallback callback,
const std::string& error) {
std::move(callback).Run(
mojom::StringSuccessOrErrorReturn::NewError(error));
},
std::move(failure))};
}
// This function splits the callback into a success call returning a Dictionary
// and an error call.
using DictionarySuccessOrFailureCallback =
base::OnceCallback<void(mojom::DictionarySuccessOrErrorReturnPtr result)>;
std::pair<extensions::NetworkingPrivateDelegate::DictionaryCallback,
extensions::NetworkingPrivateDelegate::FailureCallback>
SplitDictionaryAdapterCallback(DictionarySuccessOrFailureCallback callback) {
auto [success, failure] = base::SplitOnceCallback(std::move(callback));
return {
base::BindOnce(
[](DictionarySuccessOrFailureCallback callback,
base::Value::Dict result) {
std::move(callback).Run(
mojom::DictionarySuccessOrErrorReturn::NewSuccessResult(
std::move(result)));
},
std::move(success)),
base::BindOnce(
[](DictionarySuccessOrFailureCallback callback,
const std::string& error) {
std::move(callback).Run(
mojom::DictionarySuccessOrErrorReturn::NewError(error));
},
std::move(failure))};
}
// This function splits the callback into a success call returning a list and
// an error call.
using ListValueSuccessOrFailureCallback =
base::OnceCallback<void(mojom::ListValueSuccessOrErrorReturnPtr)>;
std::pair<base::OnceCallback<void(base::Value::List)>,
extensions::NetworkingPrivateDelegate::FailureCallback>
SplitListValueAdapterCallback(ListValueSuccessOrFailureCallback callback) {
auto [success, failure] = base::SplitOnceCallback(std::move(callback));
return {base::BindOnce(
[](ListValueSuccessOrFailureCallback callback,
base::Value::List result) {
std::move(callback).Run(
mojom::ListValueSuccessOrErrorReturn::NewSuccessResult(
std::move(result)));
},
std::move(success)),
base::BindOnce(
[](ListValueSuccessOrFailureCallback callback,
const std::string& error) {
std::move(callback).Run(
mojom::ListValueSuccessOrErrorReturn::NewError(error));
},
std::move(failure))};
}
// This adapter will handle the case where a list get returned.
using ValueListMojoCallback =
base::OnceCallback<void(absl::optional<base::Value::List>)>;
using ValueListDelegateCallback =
base::OnceCallback<void(base::Value::List result)>;
ValueListDelegateCallback ValueListAdapterCallback(
ValueListMojoCallback result_callback) {
return base::BindOnce(
[](ValueListMojoCallback callback, base::Value::List result) {
std::move(callback).Run(std::move(result));
},
std::move(result_callback));
}
// This adapter will handle the properties call back to Lacros using the mojo
// api. It assumes that there can be either a result - or an error, but not
// both.
using PropertiesMojoCallback =
base::OnceCallback<void(mojom::PropertiesSuccessOrErrorReturnPtr result)>;
using PropertiesDelegateCallback =
base::OnceCallback<void(absl::optional<::base::Value::Dict> result,
const absl::optional<std::string>& error)>;
PropertiesDelegateCallback PropertiesAdapterCallback(
PropertiesMojoCallback result_callback) {
return base::BindOnce(
[](PropertiesMojoCallback callback,
absl::optional<::base::Value::Dict> result,
const absl::optional<std::string>& error) {
if (result) {
std::move(callback).Run(
mojom::PropertiesSuccessOrErrorReturn::NewSuccessResult(
base::Value(std::move(*result))));
} else {
std::move(callback).Run(
mojom::PropertiesSuccessOrErrorReturn::NewError(*error));
}
},
std::move(result_callback));
}
void DeviceStateListCallbackAdapter(
NetworkingPrivateAsh::GetDeviceStateListCallback callback,
std::unique_ptr<extensions::NetworkingPrivateDelegate::DeviceStateList>
result) {
if (!result) {
std::move(callback).Run(absl::nullopt);
return;
}
std::vector<absl::optional<base::Value::Dict>> list;
for (size_t i = 0; i < result->size(); ++i) {
if (result->at(i)) {
list.push_back(result->at(i)->ToValue());
} else {
list.push_back(base::Value::Dict());
}
}
std::move(callback).Run(std::move(list));
}
mojom::CaptivePortalStatus GetCaptivePortalStatusFromNetworkState(
const NetworkState* network) {
if (!network) {
return mojom::CaptivePortalStatus::kUnknown;
}
if (!network->IsConnectedState()) {
return mojom::CaptivePortalStatus::kOnline;
}
switch (network->GetPortalState()) {
case NetworkState::PortalState::kUnknown:
return mojom::CaptivePortalStatus::kUnknown;
case NetworkState::PortalState::kOnline:
return mojom::CaptivePortalStatus::kOnline;
case NetworkState::PortalState::kPortalSuspected:
case NetworkState::PortalState::kPortal:
case NetworkState::PortalState::kNoInternet:
return mojom::CaptivePortalStatus::kPortal;
case NetworkState::PortalState::kProxyAuthRequired:
return mojom::CaptivePortalStatus::kProxyAuthRequired;
}
}
} // namespace
NetworkingPrivateAsh::NetworkingPrivateAsh() {
observers_.set_disconnect_handler(base::BindRepeating(
&NetworkingPrivateAsh::OnObserverDisconnected, base::Unretained(this)));
}
NetworkingPrivateAsh::~NetworkingPrivateAsh() = default;
void NetworkingPrivateAsh::BindReceiver(
mojo::PendingReceiver<mojom::NetworkingPrivate> receiver) {
receivers_.Add(this, std::move(receiver));
}
void NetworkingPrivateAsh::GetProperties(const std::string& guid,
GetPropertiesCallback callback) {
GetDelegate()->GetProperties(guid,
PropertiesAdapterCallback(std::move(callback)));
}
void NetworkingPrivateAsh::GetManagedProperties(
const std::string& guid,
GetManagedPropertiesCallback callback) {
GetDelegate()->GetManagedProperties(
guid, PropertiesAdapterCallback(std::move(callback)));
}
void NetworkingPrivateAsh::GetState(const std::string& guid,
GetStateCallback callback) {
auto [success, failure] = SplitDictionaryAdapterCallback(std::move(callback));
GetDelegate()->GetState(guid, std::move(success), std::move(failure));
}
void NetworkingPrivateAsh::SetProperties(const std::string& guid,
base::Value::Dict properties,
bool allow_set_shared_config,
SetPropertiesCallback callback) {
auto [success, failure] = SplitVoidAdapterCallback(std::move(callback));
GetDelegate()->SetProperties(guid, std::move(properties),
allow_set_shared_config, std::move(success),
std::move(failure));
}
void NetworkingPrivateAsh::CreateNetwork(bool shared,
base::Value properties,
CreateNetworkCallback callback) {
auto [success, failure] = SplitStringAdapterCallback(std::move(callback));
GetDelegate()->CreateNetwork(shared, std::move(properties).TakeDict(),
std::move(success), std::move(failure));
}
void NetworkingPrivateAsh::ForgetNetwork(const std::string& guid,
bool allow_forget_shared_config,
ForgetNetworkCallback callback) {
auto [success, failure] = SplitVoidAdapterCallback(std::move(callback));
GetDelegate()->ForgetNetwork(guid, allow_forget_shared_config,
std::move(success), std::move(failure));
}
void NetworkingPrivateAsh::GetNetworks(const std::string& network_type,
bool configured_only,
bool visible_only,
int limit,
GetNetworksCallback callback) {
auto [success, failure] = SplitListValueAdapterCallback(std::move(callback));
GetDelegate()->GetNetworks(network_type, configured_only, visible_only, limit,
std::move(success), std::move(failure));
}
void NetworkingPrivateAsh::StartConnect(const std::string& guid,
StartConnectCallback callback) {
auto [success, failure] = SplitVoidAdapterCallback(std::move(callback));
GetDelegate()->StartConnect(guid, std::move(success), std::move(failure));
}
void NetworkingPrivateAsh::StartDisconnect(const std::string& guid,
StartDisconnectCallback callback) {
auto [success, failure] = SplitVoidAdapterCallback(std::move(callback));
GetDelegate()->StartDisconnect(guid, std::move(success), std::move(failure));
}
void NetworkingPrivateAsh::StartActivate(const std::string& guid,
const std::string& carrier,
StartActivateCallback callback) {
auto [success, failure] = SplitVoidAdapterCallback(std::move(callback));
GetDelegate()->StartActivate(guid, carrier, std::move(success),
std::move(failure));
}
void NetworkingPrivateAsh::GetCaptivePortalStatus(
const std::string& guid,
GetCaptivePortalStatusCallback callback) {
auto [success, failure] = SplitStringAdapterCallback(std::move(callback));
GetDelegate()->GetCaptivePortalStatus(guid, std::move(success),
std::move(failure));
}
void NetworkingPrivateAsh::UnlockCellularSim(
const std::string& guid,
const std::string& pin,
const std::string& puk,
UnlockCellularSimCallback callback) {
auto [success, failure] = SplitVoidAdapterCallback(std::move(callback));
GetDelegate()->UnlockCellularSim(guid, pin, puk, std::move(success),
std::move(failure));
}
void NetworkingPrivateAsh::SetCellularSimState(
const std::string& guid,
bool require_pin,
const std::string& current_pin,
const std::string& new_pin,
SetCellularSimStateCallback callback) {
auto [success, failure] = SplitVoidAdapterCallback(std::move(callback));
GetDelegate()->SetCellularSimState(guid, require_pin, current_pin, new_pin,
std::move(success), std::move(failure));
}
void NetworkingPrivateAsh::SelectCellularMobileNetwork(
const std::string& guid,
const std::string& network_id,
SelectCellularMobileNetworkCallback callback) {
auto [success, failure] = SplitVoidAdapterCallback(std::move(callback));
GetDelegate()->SelectCellularMobileNetwork(
guid, network_id, std::move(success), std::move(failure));
}
void NetworkingPrivateAsh::GetEnabledNetworkTypes(
GetEnabledNetworkTypesCallback callback) {
GetDelegate()->GetEnabledNetworkTypes(
ValueListAdapterCallback(std::move(callback)));
}
void NetworkingPrivateAsh::GetDeviceStateList(
GetDeviceStateListCallback callback) {
GetDelegate()->GetDeviceStateList(
base::BindOnce(&DeviceStateListCallbackAdapter, std::move(callback)));
}
void NetworkingPrivateAsh::GetGlobalPolicy(GetGlobalPolicyCallback callback) {
GetDelegate()->GetGlobalPolicy(std::move(callback));
}
void NetworkingPrivateAsh::GetCertificateLists(
GetCertificateListsCallback callback) {
GetDelegate()->GetCertificateLists(std::move(callback));
}
void NetworkingPrivateAsh::EnableNetworkType(
const std::string& type,
EnableNetworkTypeCallback callback) {
GetDelegate()->EnableNetworkType(type, std::move(callback));
}
void NetworkingPrivateAsh::DisableNetworkType(
const std::string& type,
DisableNetworkTypeCallback callback) {
GetDelegate()->DisableNetworkType(type, std::move(callback));
}
void NetworkingPrivateAsh::RequestScan(const std::string& type,
RequestScanCallback callback) {
GetDelegate()->RequestScan(type, std::move(callback));
}
void NetworkingPrivateAsh::AddObserver(
mojo::PendingRemote<mojom::NetworkingPrivateDelegateObserver> observer) {
const bool is_listening_network_state = !observers_.empty();
observers_.Add(mojo::Remote<mojom::NetworkingPrivateDelegateObserver>(
std::move(observer)));
if (!is_listening_network_state) {
auto* net_handler = NetworkHandler::Get();
network_state_observation_.Observe(net_handler->network_state_handler());
network_certificate_observation_.Observe(
net_handler->network_certificate_handler());
}
}
void NetworkingPrivateAsh::DeviceListChanged() {
for (auto& observer : observers_) {
observer->OnDeviceStateListChanged();
}
}
void NetworkingPrivateAsh::DevicePropertiesUpdated(
const ash::DeviceState* device) {
// networkingPrivate uses a single event for device changes.
DeviceListChanged();
// DeviceState changes may affect Cellular networks.
if (device->type() != shill::kTypeCellular)
return;
NetworkStateHandler::NetworkStateList cellular_networks;
NetworkHandler::Get()->network_state_handler()->GetNetworkListByType(
ash::NetworkTypePattern::Cellular(), false /* configured_only */,
true /* visible_only */, -1 /* default limit */, &cellular_networks);
for (const NetworkState* network : cellular_networks) {
NetworkPropertiesUpdated(network);
}
}
void NetworkingPrivateAsh::NetworkListChanged() {
NetworkStateHandler::NetworkStateList networks;
NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkList(
&networks);
std::vector<std::string> changes;
for (NetworkStateHandler::NetworkStateList::const_iterator iter =
networks.begin();
iter != networks.end(); ++iter) {
changes.push_back((*iter)->guid());
}
for (auto& observer : observers_) {
observer->OnNetworkListChangedEvent(changes);
}
}
void NetworkingPrivateAsh::NetworkPropertiesUpdated(
const NetworkState* network) {
for (auto& observer : observers_) {
observer->OnNetworksChangedEvent(
std::vector<std::string>(1, network->guid()));
}
}
void NetworkingPrivateAsh::PortalStateChanged(
const NetworkState* network,
NetworkState::PortalState portal_state) {
const std::string guid = network ? network->guid() : std::string();
const mojom::CaptivePortalStatus status =
GetCaptivePortalStatusFromNetworkState(network);
for (auto& observer : observers_) {
observer->OnPortalDetectionCompleted(guid, status);
}
}
void NetworkingPrivateAsh::OnCertificatesChanged() {
for (auto& observer : observers_) {
observer->OnCertificateListsChanged();
}
}
void NetworkingPrivateAsh::OnObserverDisconnected(mojo::RemoteSetElementId id) {
if (observers_.empty()) {
network_state_observation_.Reset();
network_certificate_observation_.Reset();
}
}
} // namespace crosapi