chromium/chrome/browser/lacros/net/network_change_manager_bridge.cc

// 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/lacros/net/network_change_manager_bridge.h"

#include "base/functional/bind.h"
#include "chromeos/lacros/lacros_service.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/network_service_util.h"
#include "net/base/network_change_notifier_passive.h"
#include "services/network/public/mojom/network_service.mojom.h"

// Check ConnectionType and ConnectionSubtype values are the same for
// network::mojom and crosapi::mojom.
#define STATIC_ASSERT_CONNECTION_TYPE(v)                 \
  static_assert(static_cast<int>(crosapi::mojom::v) ==   \
                    static_cast<int>(network::mojom::v), \
                "mismatching enums: " #v)
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_UNKNOWN);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_ETHERNET);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_WIFI);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_2G);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_3G);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_4G);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_NONE);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_BLUETOOTH);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_5G);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionType::CONNECTION_LAST);

STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_UNKNOWN);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_NONE);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_OTHER);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_GSM);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_IDEN);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_CDMA);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_1XRTT);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_GPRS);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_EDGE);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_UMTS);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_EVDO_REV_0);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_EVDO_REV_A);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_HSPA);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_EVDO_REV_B);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_HSDPA);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_HSUPA);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_EHRPD);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_HSPAP);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_LTE);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_LTE_ADVANCED);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_BLUETOOTH_1_2);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_BLUETOOTH_2_1);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_BLUETOOTH_3_0);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_BLUETOOTH_4_0);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_ETHERNET);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_FAST_ETHERNET);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_GIGABIT_ETHERNET);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_10_GIGABIT_ETHERNET);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_WIFI_B);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_WIFI_G);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_WIFI_N);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_WIFI_AC);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_WIFI_AD);
STATIC_ASSERT_CONNECTION_TYPE(ConnectionSubtype::SUBTYPE_LAST);

NetworkChangeManagerBridge::NetworkChangeManagerBridge()
    : network_change_notifier_(static_cast<net::NetworkChangeNotifierPassive*>(
          content::GetNetworkChangeNotifier())) {
  auto* lacros_service = chromeos::LacrosService::Get();
  // If NetworkChange crosapi is not supported, fallback to use
  // NetworkChangeNotifierLinux instead.
  if (!lacros_service->IsAvailable<crosapi::mojom::NetworkChange>())
    return;

  if (content::IsOutOfProcessNetworkService())
    ConnectToNetworkChangeManager();

  lacros_service->GetRemote<crosapi::mojom::NetworkChange>()->AddObserver(
      receiver_.BindNewPipeAndPassRemoteWithVersion());
}

NetworkChangeManagerBridge::~NetworkChangeManagerBridge() = default;

void NetworkChangeManagerBridge::OnNetworkChanged(
    bool dns_changed,
    bool ip_address_changed,
    bool connection_type_changed,
    crosapi::mojom::ConnectionType new_connection_type,
    bool connection_subtype_changed,
    crosapi::mojom::ConnectionSubtype new_connection_subtype) {
  // If `test_notifications_only_` is set for registered notifier, skip
  // notifying.
  if (network_change_notifier_->IsTestNotificationsOnly())
    return;

  DCHECK(network_change_notifier_);
  if (ip_address_changed)
    network_change_notifier_->OnIPAddressChanged();
  if (dns_changed)
    network_change_notifier_->OnDNSChanged();
  if (connection_type_changed)
    network_change_notifier_->OnConnectionChanged(
        net::NetworkChangeNotifier::ConnectionType(new_connection_type));
  if (connection_type_changed || connection_subtype_changed) {
    network_change_notifier_->OnConnectionSubtypeChanged(
        net::NetworkChangeNotifier::ConnectionType(new_connection_type),
        net::NetworkChangeNotifier::ConnectionSubtype(new_connection_subtype));
  }

  if (network_change_manager_) {
    network_change_manager_->OnNetworkChanged(
        dns_changed, ip_address_changed, connection_type_changed,
        network::mojom::ConnectionType(new_connection_type),
        connection_subtype_changed,
        network::mojom::ConnectionSubtype(new_connection_subtype));
  }

  // Update cached values.
  connection_type_ =
      net::NetworkChangeNotifier::ConnectionType(new_connection_type);
  connection_subtype_ =
      net::NetworkChangeNotifier::ConnectionSubtype(new_connection_subtype);
}

void NetworkChangeManagerBridge::ConnectToNetworkChangeManager() {
  if (network_change_manager_.is_bound())
    network_change_manager_.reset();

  content::GetNetworkService()->GetNetworkChangeManager(
      network_change_manager_.BindNewPipeAndPassReceiver());
  network_change_manager_.set_disconnect_handler(base::BindOnce(
      &NetworkChangeManagerBridge::ReconnectToNetworkChangeManager,
      base::Unretained(this)));
}

void NetworkChangeManagerBridge::ReconnectToNetworkChangeManager() {
  ConnectToNetworkChangeManager();

  network_change_manager_->OnNetworkChanged(
      /*dns_changed=*/false, /*ip_address_changed=*/false,
      /*connection_type_changed=*/true,
      network::mojom::ConnectionType(connection_type_),
      /*connection_subtype_changed=*/true,
      network::mojom::ConnectionSubtype(connection_subtype_));
}