1 // Copyright 2013 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 "chromeos/dbus/shill/fake_shill_manager_client.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/callback_helpers.h"
14 #include "base/command_line.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_split.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "chromeos/dbus/constants/dbus_switches.h"
24 #include "chromeos/dbus/shill/fake_shill_device_client.h"
25 #include "chromeos/dbus/shill/shill_device_client.h"
26 #include "chromeos/dbus/shill/shill_ipconfig_client.h"
27 #include "chromeos/dbus/shill/shill_profile_client.h"
28 #include "chromeos/dbus/shill/shill_property_changed_observer.h"
29 #include "chromeos/dbus/shill/shill_service_client.h"
30 #include "dbus/bus.h"
31 #include "dbus/message.h"
32 #include "dbus/object_path.h"
33 #include "dbus/values_util.h"
34 #include "third_party/cros_system_api/dbus/service_constants.h"
35
36 namespace chromeos {
37
38 namespace {
39
40 int s_extra_wifi_networks = 0;
41
42 // For testing dynamic WEP networks (uses wifi2).
43 bool s_dynamic_wep = false;
44
45 // Used to compare values for finding entries to erase in a ListValue.
46 // (ListValue only implements a const_iterator version of Find).
47 struct ValueEquals {
ValueEqualschromeos::__anondaa4869a0111::ValueEquals48 explicit ValueEquals(const base::Value* first) : first_(first) {}
operator ()chromeos::__anondaa4869a0111::ValueEquals49 bool operator()(const base::Value* second) const {
50 return first_->Equals(second);
51 }
52 const base::Value* first_;
53 };
54
GetBoolValue(const base::Value & dict,const char * key)55 bool GetBoolValue(const base::Value& dict, const char* key) {
56 const base::Value* value =
57 dict.FindKeyOfType(key, base::Value::Type::BOOLEAN);
58 return value ? value->GetBool() : false;
59 }
60
GetIntValue(const base::Value & dict,const char * key)61 int GetIntValue(const base::Value& dict, const char* key) {
62 const base::Value* value =
63 dict.FindKeyOfType(key, base::Value::Type::INTEGER);
64 return value ? value->GetInt() : 0;
65 }
66
GetString(const base::Value & dict,const char * key,std::string * result)67 bool GetString(const base::Value& dict, const char* key, std::string* result) {
68 // Note: FindPath uses path expansion which is currently required for the
69 // fake shill implementations.
70 const base::Value* v = dict.FindPathOfType(key, base::Value::Type::STRING);
71 if (!v)
72 return false;
73 return v->GetAsString(result);
74 }
75
GetStringValue(const base::Value & dict,const char * key)76 std::string GetStringValue(const base::Value& dict, const char* key) {
77 const base::Value* value = dict.FindKeyOfType(key, base::Value::Type::STRING);
78 return value ? value->GetString() : std::string();
79 }
80
IsPortalledState(const std::string & state)81 bool IsPortalledState(const std::string& state) {
82 return state == shill::kStatePortal || state == shill::kStateNoConnectivity ||
83 state == shill::kStateRedirectFound ||
84 state == shill::kStatePortalSuspected;
85 }
86
GetStateOrder(const base::Value & dict)87 int GetStateOrder(const base::Value& dict) {
88 std::string state = GetStringValue(dict, shill::kStateProperty);
89 if (state == shill::kStateOnline)
90 return 1;
91 if (state == shill::kStateReady)
92 return 2;
93 if (IsPortalledState(state))
94 return 3;
95 if (state == shill::kStateAssociation || state == shill::kStateConfiguration)
96 return 4;
97 return 5;
98 }
99
GetTechnologyOrder(const base::Value & dict)100 int GetTechnologyOrder(const base::Value& dict) {
101 std::string technology = GetStringValue(dict, shill::kTypeProperty);
102 // Note: In Shill, VPN is the highest priority network, but it is generally
103 // dependent on the underlying network and gets sorted after that network.
104 // For now, we simulate this by sorting VPN last. TODO(stevenjb): Support
105 // VPN dependencies.
106 if (technology == shill::kTypeVPN)
107 return 10;
108
109 if (technology == shill::kTypeEthernet)
110 return 1;
111 if (technology == shill::kTypeWifi)
112 return 2;
113 if (technology == shill::kTypeCellular)
114 return 3;
115 return 4;
116 }
117
GetSecurityOrder(const base::Value & dict)118 int GetSecurityOrder(const base::Value& dict) {
119 std::string security = GetStringValue(dict, shill::kSecurityProperty);
120 // No security is listed last.
121 if (security == shill::kSecurityNone)
122 return 3;
123
124 // 8021x is listed first.
125 if (security == shill::kSecurity8021x)
126 return 1;
127
128 // All other security types are equal priority.
129 return 2;
130 }
131
132 // Matches Shill's Service::Compare function.
CompareNetworks(const base::Value & a,const base::Value & b)133 bool CompareNetworks(const base::Value& a, const base::Value& b) {
134 // Connection State: Online, Connected, Portal, Connecting
135 int state_order_a = GetStateOrder(a);
136 int state_order_b = GetStateOrder(b);
137 if (state_order_a != state_order_b)
138 return state_order_a < state_order_b;
139
140 // Connectable (i.e. configured)
141 bool connectable_a = GetBoolValue(a, shill::kConnectableProperty);
142 bool connectable_b = GetBoolValue(b, shill::kConnectableProperty);
143 if (connectable_a != connectable_b)
144 return connectable_a;
145
146 // Note: VPN is normally sorted first because of dependencies, see comment
147 // in GetTechnologyOrder.
148
149 // Technology
150 int technology_order_a = GetTechnologyOrder(a);
151 int technology_order_b = GetTechnologyOrder(b);
152 if (technology_order_a != technology_order_b)
153 return technology_order_a < technology_order_b;
154
155 // Priority
156 int priority_a = GetIntValue(a, shill::kPriorityProperty);
157 int priority_b = GetIntValue(b, shill::kPriorityProperty);
158 if (priority_a != priority_b)
159 return priority_a > priority_b;
160
161 // TODO: Sort on: Managed
162
163 // AutoConnect
164 bool auto_connect_a = GetBoolValue(a, shill::kAutoConnectProperty);
165 bool auto_connect_b = GetBoolValue(b, shill::kAutoConnectProperty);
166 if (auto_connect_a != auto_connect_b)
167 return auto_connect_a;
168
169 // Security
170 int security_order_a = GetSecurityOrder(a);
171 int security_order_b = GetSecurityOrder(b);
172 if (security_order_a != security_order_b)
173 return security_order_a < security_order_b;
174
175 // TODO: Sort on: Profile: User profile < Device profile
176 // TODO: Sort on: Has ever connected
177
178 // SignalStrength
179 int strength_a = GetIntValue(a, shill::kSignalStrengthProperty);
180 int strength_b = GetIntValue(b, shill::kSignalStrengthProperty);
181 if (strength_a != strength_b)
182 return strength_a > strength_b;
183
184 // Arbitrary identifier: SSID
185 return GetStringValue(a, shill::kSSIDProperty) <
186 GetStringValue(b, shill::kSSIDProperty);
187 }
188
LogErrorCallback(const std::string & error_name,const std::string & error_message)189 void LogErrorCallback(const std::string& error_name,
190 const std::string& error_message) {
191 LOG(ERROR) << error_name << ": " << error_message;
192 }
193
IsConnectedState(const std::string & state)194 bool IsConnectedState(const std::string& state) {
195 return state == shill::kStateOnline || IsPortalledState(state) ||
196 state == shill::kStateReady;
197 }
198
UpdatePortaledWifiState(const std::string & service_path)199 void UpdatePortaledWifiState(const std::string& service_path) {
200 ShillServiceClient::Get()->GetTestInterface()->SetServiceProperty(
201 service_path, shill::kStateProperty,
202 base::Value(shill::kStateNoConnectivity));
203 }
204
IsCellularTechnology(const std::string & type)205 bool IsCellularTechnology(const std::string& type) {
206 return (type == shill::kNetworkTechnology1Xrtt ||
207 type == shill::kNetworkTechnologyEvdo ||
208 type == shill::kNetworkTechnologyGsm ||
209 type == shill::kNetworkTechnologyGprs ||
210 type == shill::kNetworkTechnologyEdge ||
211 type == shill::kNetworkTechnologyUmts ||
212 type == shill::kNetworkTechnologyHspa ||
213 type == shill::kNetworkTechnologyHspaPlus ||
214 type == shill::kNetworkTechnologyLte ||
215 type == shill::kNetworkTechnologyLteAdvanced);
216 }
217
SetInitialDeviceProperty(const std::string & device_path,const std::string & name,const base::Value & value)218 void SetInitialDeviceProperty(const std::string& device_path,
219 const std::string& name,
220 const base::Value& value) {
221 ShillDeviceClient::Get()->GetTestInterface()->SetDeviceProperty(
222 device_path, name, value, /*notify_changed=*/false);
223 }
224
225 const char kPathKey[] = "path";
226
227 const char kTechnologyUnavailable[] = "unavailable";
228 const char kTechnologyInitializing[] = "initializing";
229 const char kNetworkActivated[] = "activated";
230 const char kNetworkDisabled[] = "disabled";
231 const char kCellularServicePath[] = "/service/cellular1";
232 const char kRoamingRequired[] = "required";
233
234 } // namespace
235
236 // static
237 const char FakeShillManagerClient::kFakeEthernetNetworkGuid[] = "eth1_guid";
238
FakeShillManagerClient()239 FakeShillManagerClient::FakeShillManagerClient()
240 : cellular_technology_(shill::kNetworkTechnologyGsm) {
241 ParseCommandLineSwitch();
242 }
243
244 FakeShillManagerClient::~FakeShillManagerClient() = default;
245
246 // ShillManagerClient overrides.
247
AddPropertyChangedObserver(ShillPropertyChangedObserver * observer)248 void FakeShillManagerClient::AddPropertyChangedObserver(
249 ShillPropertyChangedObserver* observer) {
250 observer_list_.AddObserver(observer);
251 }
252
RemovePropertyChangedObserver(ShillPropertyChangedObserver * observer)253 void FakeShillManagerClient::RemovePropertyChangedObserver(
254 ShillPropertyChangedObserver* observer) {
255 observer_list_.RemoveObserver(observer);
256 }
257
GetProperties(DBusMethodCallback<base::Value> callback)258 void FakeShillManagerClient::GetProperties(
259 DBusMethodCallback<base::Value> callback) {
260 VLOG(1) << "Manager.GetProperties";
261 base::ThreadTaskRunnerHandle::Get()->PostTask(
262 FROM_HERE,
263 base::BindOnce(&FakeShillManagerClient::PassStubProperties,
264 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
265 }
266
GetNetworksForGeolocation(DBusMethodCallback<base::Value> callback)267 void FakeShillManagerClient::GetNetworksForGeolocation(
268 DBusMethodCallback<base::Value> callback) {
269 base::ThreadTaskRunnerHandle::Get()->PostTask(
270 FROM_HERE,
271 base::BindOnce(&FakeShillManagerClient::PassStubGeoNetworks,
272 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
273 }
274
SetProperty(const std::string & name,const base::Value & value,base::OnceClosure callback,ErrorCallback error_callback)275 void FakeShillManagerClient::SetProperty(const std::string& name,
276 const base::Value& value,
277 base::OnceClosure callback,
278 ErrorCallback error_callback) {
279 VLOG(2) << "SetProperty: " << name;
280 stub_properties_.SetKey(name, value.Clone());
281 CallNotifyObserversPropertyChanged(name);
282 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
283 }
284
RequestScan(const std::string & type,base::OnceClosure callback,ErrorCallback error_callback)285 void FakeShillManagerClient::RequestScan(const std::string& type,
286 base::OnceClosure callback,
287 ErrorCallback error_callback) {
288 VLOG(1) << "RequestScan: " << type;
289 // For Stub purposes, default to a Wifi scan.
290 std::string device_type = type.empty() ? shill::kTypeWifi : type;
291 ShillDeviceClient::TestInterface* device_client =
292 ShillDeviceClient::Get()->GetTestInterface();
293 std::string device_path = device_client->GetDevicePathForType(device_type);
294 if (!device_path.empty()) {
295 device_client->SetDeviceProperty(device_path, shill::kScanningProperty,
296 base::Value(true),
297 /*notify_changed=*/true);
298 if (device_type == shill::kTypeCellular)
299 device_client->AddCellularFoundNetwork(device_path);
300 }
301 // Trigger |callback| immediately to indicate that the scan started.
302 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
303 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
304 FROM_HERE,
305 base::BindOnce(&FakeShillManagerClient::ScanCompleted,
306 weak_ptr_factory_.GetWeakPtr(), device_path),
307 interactive_delay_);
308 }
309
EnableTechnology(const std::string & type,base::OnceClosure callback,ErrorCallback error_callback)310 void FakeShillManagerClient::EnableTechnology(const std::string& type,
311 base::OnceClosure callback,
312 ErrorCallback error_callback) {
313 base::Value* enabled_list =
314 stub_properties_.FindListKey(shill::kAvailableTechnologiesProperty);
315 if (!enabled_list) {
316 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
317 std::move(callback));
318 base::ThreadTaskRunnerHandle::Get()->PostTask(
319 FROM_HERE, base::BindOnce(std::move(error_callback), "StubError",
320 "Property not found"));
321 return;
322 }
323 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
324 FROM_HERE,
325 base::BindOnce(&FakeShillManagerClient::SetTechnologyEnabled,
326 weak_ptr_factory_.GetWeakPtr(), type, std::move(callback),
327 true),
328 interactive_delay_);
329 }
330
DisableTechnology(const std::string & type,base::OnceClosure callback,ErrorCallback error_callback)331 void FakeShillManagerClient::DisableTechnology(const std::string& type,
332 base::OnceClosure callback,
333 ErrorCallback error_callback) {
334 base::Value* enabled_list =
335 stub_properties_.FindListKey(shill::kAvailableTechnologiesProperty);
336 if (!enabled_list) {
337 base::ThreadTaskRunnerHandle::Get()->PostTask(
338 FROM_HERE, base::BindOnce(std::move(error_callback), "StubError",
339 "Property not found"));
340 return;
341 }
342 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
343 FROM_HERE,
344 base::BindOnce(&FakeShillManagerClient::SetTechnologyEnabled,
345 weak_ptr_factory_.GetWeakPtr(), type, std::move(callback),
346 false),
347 interactive_delay_);
348 }
349
ConfigureService(const base::Value & properties,ObjectPathCallback callback,ErrorCallback error_callback)350 void FakeShillManagerClient::ConfigureService(const base::Value& properties,
351 ObjectPathCallback callback,
352 ErrorCallback error_callback) {
353 switch (simulate_configuration_result_) {
354 case FakeShillSimulatedResult::kSuccess:
355 break;
356 case FakeShillSimulatedResult::kFailure:
357 base::ThreadTaskRunnerHandle::Get()->PostTask(
358 FROM_HERE, base::BindOnce(std::move(error_callback), "Error",
359 "Simulated failure"));
360 return;
361 case FakeShillSimulatedResult::kTimeout:
362 // No callbacks get executed and the caller should eventually timeout.
363 return;
364 }
365
366 ShillServiceClient::TestInterface* service_client =
367 ShillServiceClient::Get()->GetTestInterface();
368
369 std::string guid;
370 std::string type;
371 std::string name;
372 if (!GetString(properties, shill::kGuidProperty, &guid) ||
373 !GetString(properties, shill::kTypeProperty, &type)) {
374 LOG(ERROR) << "ConfigureService requires GUID and Type to be defined";
375 // If the properties aren't filled out completely, then just return an empty
376 // object path.
377 base::ThreadTaskRunnerHandle::Get()->PostTask(
378 FROM_HERE, base::BindOnce(std::move(callback), dbus::ObjectPath()));
379 return;
380 }
381
382 if (type == shill::kTypeWifi) {
383 GetString(properties, shill::kSSIDProperty, &name);
384
385 if (name.empty()) {
386 std::string hex_name;
387 GetString(properties, shill::kWifiHexSsid, &hex_name);
388 if (!hex_name.empty()) {
389 std::vector<uint8_t> bytes;
390 if (base::HexStringToBytes(hex_name, &bytes)) {
391 name.assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size());
392 }
393 }
394 }
395 }
396 if (name.empty())
397 GetString(properties, shill::kNameProperty, &name);
398 if (name.empty())
399 name = guid;
400
401 std::string ipconfig_path;
402 GetString(properties, shill::kIPConfigProperty, &ipconfig_path);
403
404 std::string service_path = service_client->FindServiceMatchingGUID(guid);
405 if (service_path.empty())
406 service_path = service_client->FindSimilarService(properties);
407 if (service_path.empty()) {
408 // In the stub, service paths don't have to be DBus paths, so build
409 // something out of the GUID as service path.
410 // Don't use the GUID itself, so tests are forced to distinguish between
411 // service paths and GUIDs instead of assuming that service path == GUID.
412 service_path = "service_path_for_" + guid;
413 service_client->AddServiceWithIPConfig(
414 service_path, guid /* guid */, name /* name */, type, shill::kStateIdle,
415 ipconfig_path, true /* visible */);
416 }
417
418 // Merge the new properties with existing properties.
419 base::Value merged_properties =
420 service_client->GetServiceProperties(service_path)->Clone();
421 merged_properties.MergeDictionary(&properties);
422
423 // Now set all the properties.
424 for (auto iter : merged_properties.DictItems())
425 service_client->SetServiceProperty(service_path, iter.first, iter.second);
426
427 // If the Profile property is set, add it to ProfileClient.
428 const std::string* profile_path =
429 merged_properties.FindStringKey(shill::kProfileProperty);
430 if (profile_path) {
431 auto* profile_client = ShillProfileClient::Get()->GetTestInterface();
432 if (!profile_client->UpdateService(*profile_path, service_path))
433 profile_client->AddService(*profile_path, service_path);
434 }
435
436 base::ThreadTaskRunnerHandle::Get()->PostTask(
437 FROM_HERE,
438 base::BindOnce(std::move(callback), dbus::ObjectPath(service_path)));
439 }
440
ConfigureServiceForProfile(const dbus::ObjectPath & profile_path,const base::Value & properties,ObjectPathCallback callback,ErrorCallback error_callback)441 void FakeShillManagerClient::ConfigureServiceForProfile(
442 const dbus::ObjectPath& profile_path,
443 const base::Value& properties,
444 ObjectPathCallback callback,
445 ErrorCallback error_callback) {
446 std::string profile_property;
447 GetString(properties, shill::kProfileProperty, &profile_property);
448 CHECK(profile_property == profile_path.value());
449 ConfigureService(properties, std::move(callback), std::move(error_callback));
450 }
451
GetService(const base::Value & properties,ObjectPathCallback callback,ErrorCallback error_callback)452 void FakeShillManagerClient::GetService(const base::Value& properties,
453 ObjectPathCallback callback,
454 ErrorCallback error_callback) {
455 base::ThreadTaskRunnerHandle::Get()->PostTask(
456 FROM_HERE, base::BindOnce(std::move(callback), dbus::ObjectPath()));
457 }
458
ConnectToBestServices(base::OnceClosure callback,ErrorCallback error_callback)459 void FakeShillManagerClient::ConnectToBestServices(
460 base::OnceClosure callback,
461 ErrorCallback error_callback) {
462 if (best_service_.empty()) {
463 VLOG(1) << "No 'best' service set.";
464 return;
465 }
466
467 ShillServiceClient::Get()->Connect(dbus::ObjectPath(best_service_),
468 std::move(callback),
469 std::move(error_callback));
470 }
471
GetTestInterface()472 ShillManagerClient::TestInterface* FakeShillManagerClient::GetTestInterface() {
473 return this;
474 }
475
476 // ShillManagerClient::TestInterface overrides.
477
AddDevice(const std::string & device_path)478 void FakeShillManagerClient::AddDevice(const std::string& device_path) {
479 if (GetListProperty(shill::kDevicesProperty)
480 ->AppendIfNotPresent(std::make_unique<base::Value>(device_path))) {
481 CallNotifyObserversPropertyChanged(shill::kDevicesProperty);
482 }
483 }
484
RemoveDevice(const std::string & device_path)485 void FakeShillManagerClient::RemoveDevice(const std::string& device_path) {
486 base::Value device_path_value(device_path);
487 if (GetListProperty(shill::kDevicesProperty)
488 ->Remove(device_path_value, nullptr)) {
489 CallNotifyObserversPropertyChanged(shill::kDevicesProperty);
490 }
491 }
492
ClearDevices()493 void FakeShillManagerClient::ClearDevices() {
494 GetListProperty(shill::kDevicesProperty)->Clear();
495 CallNotifyObserversPropertyChanged(shill::kDevicesProperty);
496 }
497
AddTechnology(const std::string & type,bool enabled)498 void FakeShillManagerClient::AddTechnology(const std::string& type,
499 bool enabled) {
500 if (GetListProperty(shill::kAvailableTechnologiesProperty)
501 ->AppendIfNotPresent(std::make_unique<base::Value>(type))) {
502 CallNotifyObserversPropertyChanged(shill::kAvailableTechnologiesProperty);
503 }
504 if (enabled &&
505 GetListProperty(shill::kEnabledTechnologiesProperty)
506 ->AppendIfNotPresent(std::make_unique<base::Value>(type))) {
507 CallNotifyObserversPropertyChanged(shill::kEnabledTechnologiesProperty);
508 }
509 }
510
RemoveTechnology(const std::string & type)511 void FakeShillManagerClient::RemoveTechnology(const std::string& type) {
512 base::Value type_value(type);
513 if (GetListProperty(shill::kAvailableTechnologiesProperty)
514 ->Remove(type_value, nullptr)) {
515 CallNotifyObserversPropertyChanged(shill::kAvailableTechnologiesProperty);
516 }
517 if (GetListProperty(shill::kEnabledTechnologiesProperty)
518 ->Remove(type_value, nullptr)) {
519 CallNotifyObserversPropertyChanged(shill::kEnabledTechnologiesProperty);
520 }
521 }
522
SetTechnologyInitializing(const std::string & type,bool initializing)523 void FakeShillManagerClient::SetTechnologyInitializing(const std::string& type,
524 bool initializing) {
525 if (initializing) {
526 if (GetListProperty(shill::kUninitializedTechnologiesProperty)
527 ->AppendIfNotPresent(std::make_unique<base::Value>(type))) {
528 CallNotifyObserversPropertyChanged(
529 shill::kUninitializedTechnologiesProperty);
530 }
531 } else {
532 if (GetListProperty(shill::kUninitializedTechnologiesProperty)
533 ->Remove(base::Value(type), nullptr)) {
534 CallNotifyObserversPropertyChanged(
535 shill::kUninitializedTechnologiesProperty);
536 }
537 }
538 }
539
SetTechnologyProhibited(const std::string & type,bool prohibited)540 void FakeShillManagerClient::SetTechnologyProhibited(const std::string& type,
541 bool prohibited) {
542 std::string prohibited_technologies =
543 GetStringValue(stub_properties_, shill::kProhibitedTechnologiesProperty);
544 std::vector<std::string> prohibited_list =
545 base::SplitString(prohibited_technologies, ",", base::TRIM_WHITESPACE,
546 base::SPLIT_WANT_NONEMPTY);
547 std::set<std::string> prohibited_set(prohibited_list.begin(),
548 prohibited_list.end());
549 if (prohibited) {
550 auto iter = prohibited_set.find(type);
551 if (iter != prohibited_set.end())
552 return;
553 prohibited_set.insert(type);
554 } else {
555 auto iter = prohibited_set.find(type);
556 if (iter == prohibited_set.end())
557 return;
558 prohibited_set.erase(iter);
559 }
560 prohibited_list =
561 std::vector<std::string>(prohibited_set.begin(), prohibited_set.end());
562 prohibited_technologies = base::JoinString(prohibited_list, ",");
563 stub_properties_.SetStringKey(shill::kProhibitedTechnologiesProperty,
564 prohibited_technologies);
565 CallNotifyObserversPropertyChanged(shill::kProhibitedTechnologiesProperty);
566 }
567
AddGeoNetwork(const std::string & technology,const base::Value & network)568 void FakeShillManagerClient::AddGeoNetwork(const std::string& technology,
569 const base::Value& network) {
570 base::Value* list_value =
571 stub_geo_networks_.FindKeyOfType(technology, base::Value::Type::LIST);
572 if (!list_value) {
573 list_value = stub_geo_networks_.SetKey(
574 technology, base::Value(base::Value::Type::LIST));
575 }
576 list_value->Append(network.Clone());
577 }
578
AddProfile(const std::string & profile_path)579 void FakeShillManagerClient::AddProfile(const std::string& profile_path) {
580 const char* key = shill::kProfilesProperty;
581 if (GetListProperty(key)->AppendIfNotPresent(
582 std::make_unique<base::Value>(profile_path))) {
583 CallNotifyObserversPropertyChanged(key);
584 }
585 }
586
ClearProperties()587 void FakeShillManagerClient::ClearProperties() {
588 stub_properties_ = base::Value(base::Value::Type::DICTIONARY);
589 }
590
SetManagerProperty(const std::string & key,const base::Value & value)591 void FakeShillManagerClient::SetManagerProperty(const std::string& key,
592 const base::Value& value) {
593 SetProperty(key, value, base::DoNothing(), base::BindOnce(&LogErrorCallback));
594 }
595
AddManagerService(const std::string & service_path,bool notify_observers)596 void FakeShillManagerClient::AddManagerService(const std::string& service_path,
597 bool notify_observers) {
598 VLOG(2) << "AddManagerService: " << service_path;
599 GetListProperty(shill::kServiceCompleteListProperty)
600 ->AppendIfNotPresent(std::make_unique<base::Value>(service_path));
601 SortManagerServices(false);
602 if (notify_observers)
603 CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
604 }
605
RemoveManagerService(const std::string & service_path)606 void FakeShillManagerClient::RemoveManagerService(
607 const std::string& service_path) {
608 VLOG(2) << "RemoveManagerService: " << service_path;
609 base::Value service_path_value(service_path);
610 GetListProperty(shill::kServiceCompleteListProperty)
611 ->Remove(service_path_value, nullptr);
612 CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
613 }
614
ClearManagerServices()615 void FakeShillManagerClient::ClearManagerServices() {
616 VLOG(1) << "ClearManagerServices";
617 GetListProperty(shill::kServiceCompleteListProperty)->Clear();
618 CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
619 }
620
ServiceStateChanged(const std::string & service_path,const std::string & state)621 void FakeShillManagerClient::ServiceStateChanged(
622 const std::string& service_path,
623 const std::string& state) {
624 if (service_path == default_service_ && !IsConnectedState(state)) {
625 // Default service is no longer connected; clear.
626 default_service_.clear();
627 base::Value default_service_value(default_service_);
628 SetManagerProperty(shill::kDefaultServiceProperty, default_service_value);
629 }
630 }
631
SortManagerServices(bool notify)632 void FakeShillManagerClient::SortManagerServices(bool notify) {
633 VLOG(1) << "SortManagerServices";
634
635 // ServiceCompleteList contains string path values for each service.
636 base::Value* complete_path_list =
637 stub_properties_.FindListKey(shill::kServiceCompleteListProperty);
638 if (!complete_path_list || complete_path_list->GetList().empty())
639 return;
640 base::Value prev_complete_path_list = complete_path_list->Clone();
641
642 base::Value* visible_services =
643 stub_properties_.FindListKey(shill::kServicesProperty);
644 if (!visible_services) {
645 visible_services = stub_properties_.SetKey(
646 shill::kServicesProperty, base::Value(base::Value::Type::LIST));
647 }
648
649 // Networks for disabled services get appended to the end without sorting.
650 std::vector<std::string> disabled_path_list;
651
652 // Build a list of dictionaries for each service in the list.
653 std::vector<base::Value> complete_dict_list;
654 for (const base::Value& value : complete_path_list->GetList()) {
655 std::string service_path = value.GetString();
656 const base::Value* properties =
657 ShillServiceClient::Get()->GetTestInterface()->GetServiceProperties(
658 service_path);
659 if (!properties) {
660 LOG(ERROR) << "Properties not found for service: " << service_path;
661 continue;
662 }
663
664 std::string type = GetStringValue(*properties, shill::kTypeProperty);
665 if (!TechnologyEnabled(type)) {
666 disabled_path_list.push_back(service_path);
667 continue;
668 }
669
670 base::Value properties_copy = properties->Clone();
671 properties_copy.SetKey(kPathKey, base::Value(service_path));
672 complete_dict_list.emplace_back(std::move(properties_copy));
673 }
674
675 if (complete_dict_list.empty())
676 return;
677
678 // Sort the service list using the same logic as Shill's Service::Compare.
679 std::sort(complete_dict_list.begin(), complete_dict_list.end(),
680 CompareNetworks);
681
682 // Rebuild |complete_path_list| and |visible_services| with the new sort
683 // order.
684 complete_path_list->ClearList();
685 visible_services->ClearList();
686 for (const base::Value& dict : complete_dict_list) {
687 std::string service_path = GetStringValue(dict, kPathKey);
688 complete_path_list->Append(base::Value(service_path));
689 if (dict.FindBoolKey(shill::kVisibleProperty).value_or(false))
690 visible_services->Append(base::Value(service_path));
691 }
692 // Append disabled networks to the end of the complete path list.
693 for (const std::string& path : disabled_path_list)
694 complete_path_list->Append(base::Value(path));
695
696 // Notify observers if the order changed.
697 if (notify && *complete_path_list != prev_complete_path_list)
698 CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
699
700 // Set the first connected service as the Default service. Note:
701 // |new_default_service| may be empty indicating no default network.
702 std::string new_default_service;
703 const base::Value& default_network = complete_dict_list[0];
704 if (IsConnectedState(
705 GetStringValue(default_network, shill::kStateProperty))) {
706 new_default_service = GetStringValue(default_network, kPathKey);
707 }
708 if (default_service_ != new_default_service) {
709 default_service_ = new_default_service;
710 SetManagerProperty(shill::kDefaultServiceProperty,
711 base::Value(default_service_));
712 }
713 }
714
GetInteractiveDelay() const715 base::TimeDelta FakeShillManagerClient::GetInteractiveDelay() const {
716 return interactive_delay_;
717 }
718
SetInteractiveDelay(base::TimeDelta delay)719 void FakeShillManagerClient::SetInteractiveDelay(base::TimeDelta delay) {
720 interactive_delay_ = delay;
721 }
722
SetBestServiceToConnect(const std::string & service_path)723 void FakeShillManagerClient::SetBestServiceToConnect(
724 const std::string& service_path) {
725 best_service_ = service_path;
726 }
727
728 const ShillManagerClient::NetworkThrottlingStatus&
GetNetworkThrottlingStatus()729 FakeShillManagerClient::GetNetworkThrottlingStatus() {
730 return network_throttling_status_;
731 }
732
SetNetworkThrottlingStatus(const NetworkThrottlingStatus & status,base::OnceClosure callback,ErrorCallback error_callback)733 void FakeShillManagerClient::SetNetworkThrottlingStatus(
734 const NetworkThrottlingStatus& status,
735 base::OnceClosure callback,
736 ErrorCallback error_callback) {
737 network_throttling_status_ = status;
738 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
739 }
740
GetFastTransitionStatus()741 bool FakeShillManagerClient::GetFastTransitionStatus() {
742 base::Value* fast_transition_status = stub_properties_.FindKey(
743 base::StringPiece(shill::kWifiGlobalFTEnabledProperty));
744 return fast_transition_status && fast_transition_status->GetBool();
745 }
746
SetSimulateConfigurationResult(FakeShillSimulatedResult configuration_result)747 void FakeShillManagerClient::SetSimulateConfigurationResult(
748 FakeShillSimulatedResult configuration_result) {
749 simulate_configuration_result_ = configuration_result;
750 }
751
SetupDefaultEnvironment()752 void FakeShillManagerClient::SetupDefaultEnvironment() {
753 // Bail out from setup if there is no message loop. This will be the common
754 // case for tests that are not testing Shill.
755 if (!base::ThreadTaskRunnerHandle::IsSet())
756 return;
757
758 ShillServiceClient::TestInterface* services =
759 ShillServiceClient::Get()->GetTestInterface();
760 DCHECK(services);
761 ShillProfileClient::TestInterface* profiles =
762 ShillProfileClient::Get()->GetTestInterface();
763 DCHECK(profiles);
764 ShillDeviceClient::TestInterface* devices =
765 ShillDeviceClient::Get()->GetTestInterface();
766 DCHECK(devices);
767 ShillIPConfigClient::TestInterface* ip_configs =
768 ShillIPConfigClient::Get()->GetTestInterface();
769 DCHECK(ip_configs);
770
771 const std::string shared_profile = ShillProfileClient::GetSharedProfilePath();
772 profiles->AddProfile(shared_profile, std::string());
773
774 const bool add_to_visible = true;
775
776 // IPConfigs
777 base::Value ipconfig_v4_dictionary(base::Value::Type::DICTIONARY);
778 ipconfig_v4_dictionary.SetKey(shill::kAddressProperty,
779 base::Value("100.0.0.1"));
780 ipconfig_v4_dictionary.SetKey(shill::kGatewayProperty,
781 base::Value("100.0.0.2"));
782 ipconfig_v4_dictionary.SetKey(shill::kPrefixlenProperty, base::Value(1));
783 ipconfig_v4_dictionary.SetKey(shill::kMethodProperty,
784 base::Value(shill::kTypeIPv4));
785 ipconfig_v4_dictionary.SetKey(shill::kWebProxyAutoDiscoveryUrlProperty,
786 base::Value("http://wpad.com/wpad.dat"));
787 ip_configs->AddIPConfig("ipconfig_v4_path", ipconfig_v4_dictionary);
788 base::Value ipconfig_v6_dictionary(base::Value::Type::DICTIONARY);
789 ipconfig_v6_dictionary.SetKey(shill::kAddressProperty,
790 base::Value("0:0:0:0:100:0:0:1"));
791 ipconfig_v6_dictionary.SetKey(shill::kMethodProperty,
792 base::Value(shill::kTypeIPv6));
793 ip_configs->AddIPConfig("ipconfig_v6_path", ipconfig_v6_dictionary);
794
795 bool enabled;
796 std::string state;
797
798 // Ethernet
799 state = GetInitialStateForType(shill::kTypeEthernet, &enabled);
800 if (state == shill::kStateOnline || state == shill::kStateIdle) {
801 AddTechnology(shill::kTypeEthernet, enabled);
802 devices->AddDevice("/device/eth1", shill::kTypeEthernet,
803 "stub_eth_device1");
804 SetInitialDeviceProperty("/device/eth1", shill::kAddressProperty,
805 base::Value("0123456789ab"));
806 base::ListValue eth_ip_configs;
807 eth_ip_configs.AppendString("ipconfig_v4_path");
808 eth_ip_configs.AppendString("ipconfig_v6_path");
809 SetInitialDeviceProperty("/device/eth1", shill::kIPConfigsProperty,
810 eth_ip_configs);
811 const std::string kFakeEthernetNetworkPath = "/service/eth1";
812 services->AddService(kFakeEthernetNetworkPath, kFakeEthernetNetworkGuid,
813 "eth1" /* name */, shill::kTypeEthernet, state,
814 add_to_visible);
815 profiles->AddService(shared_profile, kFakeEthernetNetworkPath);
816 }
817
818 // Wifi
819 state = GetInitialStateForType(shill::kTypeWifi, &enabled);
820 if (state != kTechnologyUnavailable) {
821 bool portaled = false;
822 if (IsPortalledState(state)) {
823 portaled = true;
824 state = shill::kStateIdle;
825 }
826 AddTechnology(shill::kTypeWifi, enabled);
827 devices->AddDevice("/device/wifi1", shill::kTypeWifi, "stub_wifi_device1");
828 SetInitialDeviceProperty("/device/wifi1", shill::kAddressProperty,
829 base::Value("23456789abcd"));
830 base::ListValue wifi_ip_configs;
831 wifi_ip_configs.AppendString("ipconfig_v4_path");
832 wifi_ip_configs.AppendString("ipconfig_v6_path");
833 SetInitialDeviceProperty("/device/wifi1", shill::kIPConfigsProperty,
834 wifi_ip_configs);
835
836 const std::string kWifi1Path = "/service/wifi1";
837 services->AddService(kWifi1Path, "wifi1_guid", "wifi1" /* name */,
838 shill::kTypeWifi, state, add_to_visible);
839 services->SetServiceProperty(kWifi1Path, shill::kSecurityClassProperty,
840 base::Value(shill::kSecurityWep));
841 services->SetServiceProperty(kWifi1Path, shill::kConnectableProperty,
842 base::Value(true));
843 profiles->AddService(shared_profile, kWifi1Path);
844
845 const std::string kWifi2Path = "/service/wifi2";
846 services->AddService(kWifi2Path, "wifi2_guid",
847 s_dynamic_wep ? "wifi2_WEP" : "wifi2_PSK" /* name */,
848 shill::kTypeWifi, shill::kStateIdle, add_to_visible);
849 if (s_dynamic_wep) {
850 services->SetServiceProperty(kWifi2Path, shill::kSecurityClassProperty,
851 base::Value(shill::kSecurityWep));
852 services->SetServiceProperty(kWifi2Path, shill::kEapKeyMgmtProperty,
853 base::Value(shill::kKeyManagementIEEE8021X));
854 services->SetServiceProperty(kWifi2Path, shill::kEapMethodProperty,
855 base::Value(shill::kEapMethodPEAP));
856 services->SetServiceProperty(kWifi2Path, shill::kEapIdentityProperty,
857 base::Value("John Doe"));
858 } else {
859 services->SetServiceProperty(kWifi2Path, shill::kSecurityClassProperty,
860 base::Value(shill::kSecurityPsk));
861 }
862 services->SetServiceProperty(kWifi2Path, shill::kConnectableProperty,
863 base::Value(false));
864 services->SetServiceProperty(kWifi2Path, shill::kPassphraseRequiredProperty,
865 base::Value(true));
866 services->SetServiceProperty(kWifi2Path, shill::kSignalStrengthProperty,
867 base::Value(80));
868 profiles->AddService(shared_profile, kWifi2Path);
869
870 const std::string kWifi3Path = "/service/wifi3";
871 services->AddService(kWifi3Path, "", /* empty GUID */
872 "wifi3" /* name */, shill::kTypeWifi,
873 shill::kStateIdle, add_to_visible);
874 services->SetServiceProperty(kWifi3Path, shill::kSignalStrengthProperty,
875 base::Value(40));
876
877 if (portaled) {
878 const std::string kPortaledWifiPath = "/service/portaled_wifi";
879 services->AddService(kPortaledWifiPath, "portaled_wifi_guid",
880 "Portaled Wifi" /* name */, shill::kTypeWifi,
881 shill::kStateIdle, add_to_visible);
882 services->SetServiceProperty(kPortaledWifiPath,
883 shill::kSecurityClassProperty,
884 base::Value(shill::kSecurityNone));
885 services->SetConnectBehavior(
886 kPortaledWifiPath,
887 base::BindRepeating(&UpdatePortaledWifiState, kPortaledWifiPath));
888 services->SetServiceProperty(
889 kPortaledWifiPath, shill::kConnectableProperty, base::Value(true));
890 profiles->AddService(shared_profile, kPortaledWifiPath);
891 }
892
893 for (int i = 0; i < s_extra_wifi_networks; ++i) {
894 int id = 4 + i;
895 std::string path = base::StringPrintf("/service/wifi%d", id);
896 std::string guid = base::StringPrintf("wifi%d_guid", id);
897 std::string name = base::StringPrintf("wifi%d", id);
898 services->AddService(path, guid, name, shill::kTypeWifi,
899 shill::kStateIdle, add_to_visible);
900 }
901 }
902
903 // Cellular
904 state = GetInitialStateForType(shill::kTypeCellular, &enabled);
905 VLOG(1) << "Cellular state: " << state << " Enabled: " << enabled;
906 if (state == kTechnologyInitializing) {
907 SetTechnologyInitializing(shill::kTypeCellular, true);
908 } else if (state != kTechnologyUnavailable) {
909 bool activated = false;
910 if (state == kNetworkActivated) {
911 activated = true;
912 state = shill::kStateOnline;
913 }
914 AddTechnology(shill::kTypeCellular, enabled);
915 devices->AddDevice("/device/cellular1", shill::kTypeCellular,
916 "stub_cellular_device1");
917 if (roaming_state_ == kRoamingRequired) {
918 SetInitialDeviceProperty("/device/cellular1",
919 shill::kProviderRequiresRoamingProperty,
920 base::Value(true));
921 }
922 if (cellular_technology_ == shill::kNetworkTechnologyGsm) {
923 SetInitialDeviceProperty("/device/cellular1",
924 shill::kSupportNetworkScanProperty,
925 base::Value(true));
926 SetInitialDeviceProperty("/device/cellular1", shill::kSIMPresentProperty,
927 base::Value(true));
928 devices->SetSimLocked("/device/cellular1", false);
929 }
930
931 if (state != shill::kStateIdle) {
932 services->AddService(kCellularServicePath, "cellular1_guid",
933 "cellular1" /* name */, shill::kTypeCellular, state,
934 add_to_visible);
935 base::Value technology_value(cellular_technology_);
936 SetInitialDeviceProperty("/device/cellular1",
937 shill::kTechnologyFamilyProperty,
938 technology_value);
939 services->SetServiceProperty(kCellularServicePath,
940 shill::kNetworkTechnologyProperty,
941 technology_value);
942 base::Value strength_value(50);
943 services->SetServiceProperty(
944 kCellularServicePath, shill::kSignalStrengthProperty, strength_value);
945
946 if (activated) {
947 services->SetServiceProperty(
948 kCellularServicePath, shill::kActivationStateProperty,
949 base::Value(shill::kActivationStateActivated));
950 services->SetServiceProperty(kCellularServicePath,
951 shill::kConnectableProperty,
952 base::Value(true));
953 } else {
954 services->SetServiceProperty(
955 kCellularServicePath, shill::kActivationStateProperty,
956 base::Value(shill::kActivationStateNotActivated));
957 }
958
959 base::Value payment_portal(base::Value::Type::DICTIONARY);
960 payment_portal.SetKey(shill::kPaymentPortalMethod, base::Value("POST"));
961 payment_portal.SetKey(shill::kPaymentPortalPostData,
962 base::Value("iccid=123&imei=456&mdn=789"));
963 payment_portal.SetKey(shill::kPaymentPortalURL,
964 base::Value(cellular_olp_));
965 services->SetServiceProperty(kCellularServicePath,
966 shill::kPaymentPortalProperty,
967 std::move(payment_portal));
968
969 std::string shill_roaming_state;
970 if (roaming_state_ == kRoamingRequired)
971 shill_roaming_state = shill::kRoamingStateRoaming;
972 else if (roaming_state_.empty())
973 shill_roaming_state = shill::kRoamingStateHome;
974 else // |roaming_state_| is expected to be a valid Shill state.
975 shill_roaming_state = roaming_state_;
976 services->SetServiceProperty(kCellularServicePath,
977 shill::kRoamingStateProperty,
978 base::Value(shill_roaming_state));
979
980 base::Value apn(base::Value::Type::DICTIONARY);
981 apn.SetKey(shill::kApnProperty, base::Value("testapn"));
982 apn.SetKey(shill::kApnNameProperty, base::Value("Test APN"));
983 apn.SetKey(shill::kApnLocalizedNameProperty,
984 base::Value("Localized Test APN"));
985 apn.SetKey(shill::kApnUsernameProperty, base::Value("User1"));
986 apn.SetKey(shill::kApnPasswordProperty, base::Value("password"));
987 apn.SetKey(shill::kApnAuthenticationProperty, base::Value("chap"));
988 base::Value apn2(base::Value::Type::DICTIONARY);
989 apn2.SetKey(shill::kApnProperty, base::Value("testapn2"));
990 services->SetServiceProperty(kCellularServicePath,
991 shill::kCellularApnProperty, apn);
992 services->SetServiceProperty(kCellularServicePath,
993 shill::kCellularLastGoodApnProperty, apn);
994 base::ListValue apn_list;
995 apn_list.Append(std::move(apn));
996 apn_list.Append(std::move(apn2));
997 SetInitialDeviceProperty("/device/cellular1",
998 shill::kCellularApnListProperty, apn_list);
999
1000 profiles->AddService(shared_profile, kCellularServicePath);
1001 }
1002 }
1003
1004 // VPN
1005 state = GetInitialStateForType(shill::kTypeVPN, &enabled);
1006 if (state != kTechnologyUnavailable) {
1007 // Set the "Provider" dictionary properties. Note: when setting these in
1008 // Shill, "Provider.Type", etc keys are used, but when reading the values
1009 // "Provider" . "Type", etc keys are used. Here we are setting the values
1010 // that will be read (by the UI, tests, etc).
1011 base::Value provider_properties_openvpn(base::Value::Type::DICTIONARY);
1012 provider_properties_openvpn.SetStringKey(shill::kTypeProperty,
1013 shill::kProviderOpenVpn);
1014 provider_properties_openvpn.SetStringKey(shill::kHostProperty, "vpn_host");
1015
1016 services->AddService("/service/vpn1", "vpn1_guid", "vpn1" /* name */,
1017 shill::kTypeVPN, state, add_to_visible);
1018 services->SetServiceProperty("/service/vpn1", shill::kProviderProperty,
1019 provider_properties_openvpn);
1020 profiles->AddService(shared_profile, "/service/vpn1");
1021
1022 base::Value provider_properties_l2tp(base::Value::Type::DICTIONARY);
1023 provider_properties_l2tp.SetStringKey(shill::kTypeProperty,
1024 shill::kProviderL2tpIpsec);
1025 provider_properties_l2tp.SetStringKey(shill::kHostProperty, "vpn_host2");
1026
1027 services->AddService("/service/vpn2", "vpn2_guid", "vpn2" /* name */,
1028 shill::kTypeVPN, shill::kStateIdle, add_to_visible);
1029 services->SetServiceProperty("/service/vpn2", shill::kProviderProperty,
1030 provider_properties_l2tp);
1031 }
1032
1033 // Additional device states
1034 for (const auto& iter1 : shill_device_property_map_) {
1035 std::string device_type = iter1.first;
1036 std::string device_path = devices->GetDevicePathForType(device_type);
1037 for (const auto& iter2 : iter1.second)
1038 SetInitialDeviceProperty(device_path, iter2.first, iter2.second);
1039 }
1040 shill_device_property_map_.clear();
1041
1042 SortManagerServices(true);
1043 }
1044
1045 // Private methods
1046
PassStubProperties(DBusMethodCallback<base::Value> callback) const1047 void FakeShillManagerClient::PassStubProperties(
1048 DBusMethodCallback<base::Value> callback) const {
1049 base::Value stub_properties = stub_properties_.Clone();
1050 stub_properties.SetKey(shill::kServiceCompleteListProperty,
1051 GetEnabledServiceList());
1052 std::move(callback).Run(std::move(stub_properties));
1053 }
1054
PassStubGeoNetworks(DBusMethodCallback<base::Value> callback) const1055 void FakeShillManagerClient::PassStubGeoNetworks(
1056 DBusMethodCallback<base::Value> callback) const {
1057 std::move(callback).Run(stub_geo_networks_.Clone());
1058 }
1059
CallNotifyObserversPropertyChanged(const std::string & property)1060 void FakeShillManagerClient::CallNotifyObserversPropertyChanged(
1061 const std::string& property) {
1062 // Avoid unnecessary delayed task if we have no observers (e.g. during
1063 // initial setup).
1064 if (!observer_list_.might_have_observers())
1065 return;
1066 base::ThreadTaskRunnerHandle::Get()->PostTask(
1067 FROM_HERE,
1068 base::BindOnce(&FakeShillManagerClient::NotifyObserversPropertyChanged,
1069 weak_ptr_factory_.GetWeakPtr(), property));
1070 }
1071
NotifyObserversPropertyChanged(const std::string & property)1072 void FakeShillManagerClient::NotifyObserversPropertyChanged(
1073 const std::string& property) {
1074 VLOG(1) << "NotifyObserversPropertyChanged: " << property;
1075 base::Value* value = stub_properties_.FindKey(property);
1076 if (!value) {
1077 LOG(ERROR) << "Notify for unknown property: " << property;
1078 return;
1079 }
1080 if (property == shill::kServiceCompleteListProperty) {
1081 base::Value services = GetEnabledServiceList();
1082 for (auto& observer : observer_list_)
1083 observer.OnPropertyChanged(property, services);
1084 return;
1085 }
1086 for (auto& observer : observer_list_)
1087 observer.OnPropertyChanged(property, *value);
1088 }
1089
GetListProperty(const std::string & property)1090 base::ListValue* FakeShillManagerClient::GetListProperty(
1091 const std::string& property) {
1092 base::Value* list_property =
1093 stub_properties_.FindKeyOfType(property, base::Value::Type::LIST);
1094 if (!list_property) {
1095 list_property =
1096 stub_properties_.SetKey(property, base::Value(base::Value::Type::LIST));
1097 }
1098 return static_cast<base::ListValue*>(list_property);
1099 }
1100
TechnologyEnabled(const std::string & type) const1101 bool FakeShillManagerClient::TechnologyEnabled(const std::string& type) const {
1102 if (type == shill::kTypeVPN)
1103 return true; // VPN is always "enabled" since there is no associated device
1104 if (type == shill::kTypeEthernetEap)
1105 return true;
1106 const base::Value* technologies =
1107 stub_properties_.FindListKey(shill::kEnabledTechnologiesProperty);
1108 if (technologies)
1109 return base::Contains(technologies->GetList(), base::Value(type));
1110 return false;
1111 }
1112
SetTechnologyEnabled(const std::string & type,base::OnceClosure callback,bool enabled)1113 void FakeShillManagerClient::SetTechnologyEnabled(const std::string& type,
1114 base::OnceClosure callback,
1115 bool enabled) {
1116 base::ListValue* enabled_list =
1117 GetListProperty(shill::kEnabledTechnologiesProperty);
1118 if (enabled)
1119 enabled_list->AppendIfNotPresent(std::make_unique<base::Value>(type));
1120 else
1121 enabled_list->Remove(base::Value(type), nullptr);
1122 CallNotifyObserversPropertyChanged(shill::kEnabledTechnologiesProperty);
1123 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
1124 // May affect available services.
1125 SortManagerServices(true);
1126 }
1127
GetEnabledServiceList() const1128 base::Value FakeShillManagerClient::GetEnabledServiceList() const {
1129 base::Value new_service_list(base::Value::Type::LIST);
1130 const base::Value* service_list =
1131 stub_properties_.FindListKey(shill::kServiceCompleteListProperty);
1132 if (service_list) {
1133 ShillServiceClient::TestInterface* service_client =
1134 ShillServiceClient::Get()->GetTestInterface();
1135 for (const base::Value& v : service_list->GetList()) {
1136 std::string service_path = v.GetString();
1137 const base::Value* properties =
1138 service_client->GetServiceProperties(service_path);
1139 if (!properties) {
1140 LOG(ERROR) << "Properties not found for service: " << service_path;
1141 continue;
1142 }
1143 const std::string* type = properties->FindStringKey(shill::kTypeProperty);
1144 if (type && TechnologyEnabled(*type))
1145 new_service_list.Append(v.Clone());
1146 }
1147 }
1148 return new_service_list;
1149 }
1150
ScanCompleted(const std::string & device_path)1151 void FakeShillManagerClient::ScanCompleted(const std::string& device_path) {
1152 VLOG(1) << "ScanCompleted: " << device_path;
1153 if (!device_path.empty()) {
1154 ShillDeviceClient::Get()->GetTestInterface()->SetDeviceProperty(
1155 device_path, shill::kScanningProperty, base::Value(false),
1156 /*notify_changed=*/true);
1157 }
1158 CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
1159 }
1160
ParseCommandLineSwitch()1161 void FakeShillManagerClient::ParseCommandLineSwitch() {
1162 // Default setup
1163 SetInitialNetworkState(shill::kTypeEthernet, shill::kStateOnline);
1164 SetInitialNetworkState(shill::kTypeWifi, shill::kStateOnline);
1165 SetInitialNetworkState(shill::kTypeCellular, shill::kStateIdle);
1166 SetInitialNetworkState(shill::kTypeVPN, shill::kStateIdle);
1167
1168 // Parse additional options
1169 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1170 if (!command_line->HasSwitch(switches::kShillStub))
1171 return;
1172
1173 std::string option_str =
1174 command_line->GetSwitchValueASCII(switches::kShillStub);
1175 VLOG(1) << "Parsing command line:" << option_str;
1176 base::StringPairs string_pairs;
1177 base::SplitStringIntoKeyValuePairs(option_str, '=', ',', &string_pairs);
1178 for (base::StringPairs::iterator iter = string_pairs.begin();
1179 iter != string_pairs.end(); ++iter) {
1180 ParseOption((*iter).first, (*iter).second);
1181 }
1182 }
1183
ParseOption(const std::string & arg0,const std::string & arg1)1184 bool FakeShillManagerClient::ParseOption(const std::string& arg0,
1185 const std::string& arg1) {
1186 VLOG(1) << "Parsing command line option: '" << arg0 << "=" << arg1 << "'";
1187 if ((arg0 == "clear" || arg0 == "reset") && arg1 == "1") {
1188 shill_initial_state_map_.clear();
1189 return true;
1190 } else if (arg0 == "interactive") {
1191 int seconds = 3;
1192 if (!arg1.empty())
1193 base::StringToInt(arg1, &seconds);
1194 interactive_delay_ = base::TimeDelta::FromSeconds(seconds);
1195 return true;
1196 } else if (arg0 == "sim_lock") {
1197 bool locked = (arg1 == "1");
1198 base::Value simlock_dict(base::Value::Type::DICTIONARY);
1199 simlock_dict.SetBoolKey(shill::kSIMLockEnabledProperty, true);
1200 std::string lock_type = locked ? shill::kSIMLockPin : "";
1201 simlock_dict.SetStringKey(shill::kSIMLockTypeProperty, lock_type);
1202 if (locked) {
1203 simlock_dict.SetIntKey(shill::kSIMLockRetriesLeftProperty,
1204 FakeShillDeviceClient::kSimPinRetryCount);
1205 }
1206 shill_device_property_map_[shill::kTypeCellular]
1207 [shill::kSIMPresentProperty] = base::Value(true);
1208 shill_device_property_map_[shill::kTypeCellular]
1209 [shill::kSIMLockStatusProperty] =
1210 std::move(simlock_dict);
1211 shill_device_property_map_[shill::kTypeCellular]
1212 [shill::kTechnologyFamilyProperty] =
1213 base::Value(shill::kNetworkTechnologyGsm);
1214 return true;
1215 } else if (arg0 == "sim_present") {
1216 bool present = (arg1 == "1");
1217 shill_device_property_map_[shill::kTypeCellular]
1218 [shill::kSIMPresentProperty] =
1219 base::Value(present);
1220 if (!present)
1221 shill_initial_state_map_[shill::kTypeCellular] = kNetworkDisabled;
1222 return true;
1223 } else if (arg0 == "olp") {
1224 cellular_olp_ = arg1;
1225 return true;
1226 } else if (arg0 == "roaming") {
1227 // "home", "roaming", or "required"
1228 roaming_state_ = arg1;
1229 return true;
1230 } else if (arg0 == "dynamic_wep" && arg1 == "1") {
1231 s_dynamic_wep = true;
1232 return true;
1233 }
1234 return SetInitialNetworkState(arg0, arg1);
1235 }
1236
SetInitialNetworkState(std::string type_arg,const std::string & state_arg)1237 bool FakeShillManagerClient::SetInitialNetworkState(
1238 std::string type_arg,
1239 const std::string& state_arg) {
1240 int state_arg_as_int = -1;
1241 base::StringToInt(state_arg, &state_arg_as_int);
1242
1243 std::string state;
1244 if (state_arg.empty() || state_arg == "1" || state_arg == "on" ||
1245 state_arg == "enabled" || state_arg == "connected" ||
1246 state_arg == "online" || state_arg == "inactive") {
1247 // Enabled and connected (default value)
1248 state = shill::kStateOnline;
1249 } else if (state_arg == "0" || state_arg == "off" ||
1250 state_arg == shill::kStateIdle) {
1251 // Technology enabled, services are created but are not connected.
1252 state = shill::kStateIdle;
1253 } else if (type_arg == shill::kTypeWifi && state_arg_as_int > 1) {
1254 // Enabled and connected, add extra wifi networks.
1255 state = shill::kStateOnline;
1256 s_extra_wifi_networks = state_arg_as_int - 1;
1257 } else if (state_arg == "disabled" || state_arg == "disconnect") {
1258 // Technology disabled but available, services created but not connected.
1259 state = kNetworkDisabled;
1260 } else if (state_arg == "none" || state_arg == "offline") {
1261 // Technology not available, do not create services.
1262 state = kTechnologyUnavailable;
1263 } else if (state_arg == "initializing") {
1264 // Technology available but not initialized.
1265 state = kTechnologyInitializing;
1266 } else if (state_arg == "portal") {
1267 // Technology is enabled, a service is connected and in Portal state.
1268 state = shill::kStateNoConnectivity;
1269 } else if (state_arg == "active" || state_arg == "activated") {
1270 // Technology is enabled, a service is connected and Activated.
1271 state = kNetworkActivated;
1272 } else if (type_arg == shill::kTypeCellular &&
1273 IsCellularTechnology(state_arg)) {
1274 state = shill::kStateOnline;
1275 cellular_technology_ = state_arg;
1276 } else if (type_arg == shill::kTypeCellular && state_arg == "LTEAdvanced") {
1277 // Special case, Shill name contains a ' '.
1278 state = shill::kStateOnline;
1279 cellular_technology_ = shill::kNetworkTechnologyLteAdvanced;
1280 } else {
1281 LOG(ERROR) << "Unrecognized initial state: " << type_arg << "="
1282 << state_arg;
1283 return false;
1284 }
1285
1286 // Special cases
1287 if (type_arg == "wireless") {
1288 shill_initial_state_map_[shill::kTypeWifi] = state;
1289 shill_initial_state_map_[shill::kTypeCellular] = state;
1290 return true;
1291 }
1292 // Convenience synonyms.
1293 if (type_arg == "eth")
1294 type_arg = shill::kTypeEthernet;
1295
1296 if (type_arg != shill::kTypeEthernet && type_arg != shill::kTypeWifi &&
1297 type_arg != shill::kTypeCellular && type_arg != shill::kTypeVPN) {
1298 LOG(WARNING) << "Unrecognized Shill network type: " << type_arg;
1299 return false;
1300 }
1301
1302 // Disabled ethernet is the same as unavailable.
1303 if (type_arg == shill::kTypeEthernet && state == kNetworkDisabled)
1304 state = kTechnologyUnavailable;
1305
1306 shill_initial_state_map_[type_arg] = state;
1307 return true;
1308 }
1309
GetInitialStateForType(const std::string & type,bool * enabled)1310 std::string FakeShillManagerClient::GetInitialStateForType(
1311 const std::string& type,
1312 bool* enabled) {
1313 std::string result;
1314 std::map<std::string, std::string>::const_iterator iter =
1315 shill_initial_state_map_.find(type);
1316 if (iter == shill_initial_state_map_.end()) {
1317 *enabled = false;
1318 result = kTechnologyUnavailable;
1319 } else {
1320 std::string state = iter->second;
1321 if (state == kNetworkDisabled) {
1322 *enabled = false;
1323 result = shill::kStateIdle;
1324 } else {
1325 *enabled = true;
1326 result = state;
1327 }
1328 if ((IsPortalledState(state) && type != shill::kTypeWifi) ||
1329 (state == kNetworkActivated && type != shill::kTypeCellular)) {
1330 LOG(WARNING) << "Invalid state: " << state << " for " << type;
1331 result = shill::kStateIdle;
1332 }
1333 }
1334 VLOG(1) << "Initial state for: " << type << " = " << result
1335 << " Enabled: " << *enabled;
1336 return result;
1337 }
1338
1339 } // namespace chromeos
1340