1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/net/network_health/network_health.h"
6 
7 #include <map>
8 #include <vector>
9 
10 #include "chromeos/network/network_event_log.h"
11 #include "chromeos/services/network_config/in_process_instance.h"
12 #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
13 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
14 #include "chromeos/services/network_health/public/mojom/network_health.mojom.h"
15 
16 namespace chromeos {
17 namespace network_health {
18 
19 namespace {
20 
DeviceStateToNetworkState(network_config::mojom::DeviceStateType device_state)21 constexpr mojom::NetworkState DeviceStateToNetworkState(
22     network_config::mojom::DeviceStateType device_state) {
23   switch (device_state) {
24     case network_config::mojom::DeviceStateType::kUninitialized:
25       return mojom::NetworkState::kUninitialized;
26     case network_config::mojom::DeviceStateType::kDisabled:
27     case network_config::mojom::DeviceStateType::kDisabling:
28     case network_config::mojom::DeviceStateType::kEnabling:
29       // Disabling and Enabling are intermediate state that we care about in the
30       // UI, but not for purposes of network health, we can treat as Disabled.
31       return mojom::NetworkState::kDisabled;
32     case network_config::mojom::DeviceStateType::kEnabled:
33       return mojom::NetworkState::kNotConnected;
34     case network_config::mojom::DeviceStateType::kProhibited:
35       return mojom::NetworkState::kProhibited;
36     case network_config::mojom::DeviceStateType::kUnavailable:
37       NOTREACHED();
38       return mojom::NetworkState::kUninitialized;
39   }
40 }
41 
ConnectionStateToNetworkState(network_config::mojom::ConnectionStateType connection_state)42 constexpr mojom::NetworkState ConnectionStateToNetworkState(
43     network_config::mojom::ConnectionStateType connection_state) {
44   switch (connection_state) {
45     case network_config::mojom::ConnectionStateType::kOnline:
46       return mojom::NetworkState::kOnline;
47     case network_config::mojom::ConnectionStateType::kConnected:
48       return mojom::NetworkState::kConnected;
49     case network_config::mojom::ConnectionStateType::kPortal:
50       return mojom::NetworkState::kPortal;
51     case network_config::mojom::ConnectionStateType::kConnecting:
52       return mojom::NetworkState::kConnecting;
53     case network_config::mojom::ConnectionStateType::kNotConnected:
54       return mojom::NetworkState::kNotConnected;
55   }
56 }
57 
58 // Populates a mojom::NetworkPtr based on the given |device_prop| and
59 // |network_prop| if a valid Network can be created. Returns a base::nullopt
60 // otherwise. This function assumes that |device_prop| is populated, while
61 // |network_prop| could be null.
CreateNetwork(const network_config::mojom::DeviceStatePropertiesPtr & device_prop,const network_config::mojom::NetworkStatePropertiesPtr & net_prop)62 mojom::NetworkPtr CreateNetwork(
63     const network_config::mojom::DeviceStatePropertiesPtr& device_prop,
64     const network_config::mojom::NetworkStatePropertiesPtr& net_prop) {
65   auto net = mojom::Network::New();
66   net->mac_address = device_prop->mac_address;
67   net->type = device_prop->type;
68 
69   if (net_prop) {
70     net->state = ConnectionStateToNetworkState(net_prop->connection_state);
71     net->name = net_prop->name;
72     net->guid = net_prop->guid;
73     if (chromeos::network_config::NetworkTypeMatchesType(
74             net_prop->type, network_config::mojom::NetworkType::kWireless)) {
75       net->signal_strength = network_health::mojom::UInt32Value::New(
76           network_config::GetWirelessSignalStrength(net_prop.get()));
77     }
78   } else {
79     net->state = DeviceStateToNetworkState(device_prop->device_state);
80   }
81 
82   return net;
83 }
84 
85 }  // namespace
86 
NetworkHealth()87 NetworkHealth::NetworkHealth() {
88   network_config::BindToInProcessInstance(
89       remote_cros_network_config_.BindNewPipeAndPassReceiver());
90   remote_cros_network_config_->AddObserver(
91       cros_network_config_observer_receiver_.BindNewPipeAndPassRemote());
92   RefreshNetworkHealthState();
93 }
94 
95 NetworkHealth::~NetworkHealth() = default;
96 
BindReceiver(mojo::PendingReceiver<mojom::NetworkHealthService> receiver)97 void NetworkHealth::BindReceiver(
98     mojo::PendingReceiver<mojom::NetworkHealthService> receiver) {
99   receivers_.Add(this, std::move(receiver));
100 }
101 
GetNetworkHealthState()102 const mojom::NetworkHealthStatePtr NetworkHealth::GetNetworkHealthState() {
103   NET_LOG(EVENT) << "Network Health State Requested";
104   return network_health_state_.Clone();
105 }
106 
GetNetworkList(GetNetworkListCallback callback)107 void NetworkHealth::GetNetworkList(GetNetworkListCallback callback) {
108   std::move(callback).Run(mojo::Clone(network_health_state_.networks));
109 }
110 
GetHealthSnapshot(GetHealthSnapshotCallback callback)111 void NetworkHealth::GetHealthSnapshot(GetHealthSnapshotCallback callback) {
112   std::move(callback).Run(network_health_state_.Clone());
113 }
114 
OnNetworkStateListChanged()115 void NetworkHealth::OnNetworkStateListChanged() {
116   RequestNetworkStateList();
117 }
118 
OnDeviceStateListChanged()119 void NetworkHealth::OnDeviceStateListChanged() {
120   RequestDeviceStateList();
121 }
122 
OnActiveNetworksChanged(std::vector<network_config::mojom::NetworkStatePropertiesPtr>)123 void NetworkHealth::OnActiveNetworksChanged(
124     std::vector<network_config::mojom::NetworkStatePropertiesPtr>) {}
125 
OnNetworkStateChanged(network_config::mojom::NetworkStatePropertiesPtr)126 void NetworkHealth::OnNetworkStateChanged(
127     network_config::mojom::NetworkStatePropertiesPtr) {}
128 
OnVpnProvidersChanged()129 void NetworkHealth::OnVpnProvidersChanged() {}
130 
OnNetworkCertificatesChanged()131 void NetworkHealth::OnNetworkCertificatesChanged() {}
132 
OnNetworkStateListReceived(std::vector<network_config::mojom::NetworkStatePropertiesPtr> props)133 void NetworkHealth::OnNetworkStateListReceived(
134     std::vector<network_config::mojom::NetworkStatePropertiesPtr> props) {
135   network_properties_.swap(props);
136   CreateNetworkHealthState();
137 }
138 
OnDeviceStateListReceived(std::vector<network_config::mojom::DeviceStatePropertiesPtr> props)139 void NetworkHealth::OnDeviceStateListReceived(
140     std::vector<network_config::mojom::DeviceStatePropertiesPtr> props) {
141   device_properties_.swap(props);
142   CreateNetworkHealthState();
143 }
144 
CreateNetworkHealthState()145 void NetworkHealth::CreateNetworkHealthState() {
146   // If the device information has not been collected, the NetworkHealthState
147   // cannot be created.
148   if (device_properties_.empty())
149     return;
150 
151   network_health_state_.networks.clear();
152 
153   std::map<network_config::mojom::NetworkType,
154            network_config::mojom::DeviceStatePropertiesPtr>
155       device_type_map;
156 
157   // This function only supports one Network structure per underlying device. If
158   // this assumption changes, this function will need to be reworked.
159   for (const auto& d : device_properties_) {
160     device_type_map[d->type] = mojo::Clone(d);
161   }
162 
163   // For each NetworkStateProperties, create a Network structure using the
164   // underlying DeviceStateProperties. Remove devices from the type map that
165   // have an associated NetworkStateProperties.
166   for (const auto& net_prop : network_properties_) {
167     auto device_iter = device_type_map.find(net_prop->type);
168     if (device_iter == device_type_map.end()) {
169       continue;
170     }
171     network_health_state_.networks.push_back(
172         CreateNetwork(device_iter->second, net_prop));
173     device_type_map.erase(device_iter);
174   }
175 
176   // For the remaining devices that do not have associated
177   // NetworkStateProperties, create Network structures.
178   for (const auto& device_prop : device_type_map) {
179     // Devices that have an kUnavailable state are not valid.
180     if (device_prop.second->device_state ==
181         network_config::mojom::DeviceStateType::kUnavailable) {
182       NET_LOG(ERROR) << "Device in unexpected unavailable state: "
183                      << device_prop.second->type;
184       continue;
185     }
186 
187     network_health_state_.networks.push_back(
188         CreateNetwork(device_prop.second, nullptr));
189   }
190 }
191 
RefreshNetworkHealthState()192 void NetworkHealth::RefreshNetworkHealthState() {
193   RequestNetworkStateList();
194   RequestDeviceStateList();
195 }
196 
RequestNetworkStateList()197 void NetworkHealth::RequestNetworkStateList() {
198   remote_cros_network_config_->GetNetworkStateList(
199       network_config::mojom::NetworkFilter::New(
200           network_config::mojom::FilterType::kActive,
201           network_config::mojom::NetworkType::kAll,
202           network_config::mojom::kNoLimit),
203       base::BindOnce(&NetworkHealth::OnNetworkStateListReceived,
204                      base::Unretained(this)));
205 }
206 
RequestDeviceStateList()207 void NetworkHealth::RequestDeviceStateList() {
208   remote_cros_network_config_->GetDeviceStateList(base::BindOnce(
209       &NetworkHealth::OnDeviceStateListReceived, base::Unretained(this)));
210 }
211 
212 }  // namespace network_health
213 }  // namespace chromeos
214