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_device_client.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/callback_helpers.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "chromeos/dbus/shill/shill_manager_client.h"
20 #include "chromeos/dbus/shill/shill_property_changed_observer.h"
21 #include "dbus/bus.h"
22 #include "dbus/message.h"
23 #include "dbus/object_path.h"
24 #include "dbus/object_proxy.h"
25 #include "dbus/values_util.h"
26 #include "net/base/ip_endpoint.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
28
29 namespace chromeos {
30
31 namespace {
32
33 const int kSimPinMinLength = 4;
34 const int kSimPukRetryCount = 10;
35 const char kFailedMessage[] = "Failed";
36
ErrorFunction(const std::string & device_path,const std::string & error_name,const std::string & error_message)37 void ErrorFunction(const std::string& device_path,
38 const std::string& error_name,
39 const std::string& error_message) {
40 LOG(ERROR) << "Shill Error for: " << device_path << ": " << error_name
41 << " : " << error_message;
42 }
43
PostError(const std::string & error,ShillDeviceClient::ErrorCallback error_callback)44 void PostError(const std::string& error,
45 ShillDeviceClient::ErrorCallback error_callback) {
46 base::ThreadTaskRunnerHandle::Get()->PostTask(
47 FROM_HERE,
48 base::BindOnce(std::move(error_callback), error, kFailedMessage));
49 }
50
PostNotFoundError(ShillDeviceClient::ErrorCallback error_callback)51 void PostNotFoundError(ShillDeviceClient::ErrorCallback error_callback) {
52 PostError(shill::kErrorResultNotFound, std::move(error_callback));
53 }
54
55 } // namespace
56
57 // Matches pseudomodem.
58 const char FakeShillDeviceClient::kSimPuk[] = "12345678";
59
60 const char FakeShillDeviceClient::kDefaultSimPin[] = "1111";
61 const int FakeShillDeviceClient::kSimPinRetryCount = 3;
62
FakeShillDeviceClient()63 FakeShillDeviceClient::FakeShillDeviceClient() {}
64
65 FakeShillDeviceClient::~FakeShillDeviceClient() = default;
66
67 // ShillDeviceClient overrides.
68
AddPropertyChangedObserver(const dbus::ObjectPath & device_path,ShillPropertyChangedObserver * observer)69 void FakeShillDeviceClient::AddPropertyChangedObserver(
70 const dbus::ObjectPath& device_path,
71 ShillPropertyChangedObserver* observer) {
72 GetObserverList(device_path).AddObserver(observer);
73 }
74
RemovePropertyChangedObserver(const dbus::ObjectPath & device_path,ShillPropertyChangedObserver * observer)75 void FakeShillDeviceClient::RemovePropertyChangedObserver(
76 const dbus::ObjectPath& device_path,
77 ShillPropertyChangedObserver* observer) {
78 GetObserverList(device_path).RemoveObserver(observer);
79 }
80
GetProperties(const dbus::ObjectPath & device_path,DBusMethodCallback<base::Value> callback)81 void FakeShillDeviceClient::GetProperties(
82 const dbus::ObjectPath& device_path,
83 DBusMethodCallback<base::Value> callback) {
84 base::ThreadTaskRunnerHandle::Get()->PostTask(
85 FROM_HERE,
86 base::BindOnce(&FakeShillDeviceClient::PassStubDeviceProperties,
87 weak_ptr_factory_.GetWeakPtr(), device_path,
88 std::move(callback)));
89 }
90
SetProperty(const dbus::ObjectPath & device_path,const std::string & name,const base::Value & value,base::OnceClosure callback,ErrorCallback error_callback)91 void FakeShillDeviceClient::SetProperty(const dbus::ObjectPath& device_path,
92 const std::string& name,
93 const base::Value& value,
94 base::OnceClosure callback,
95 ErrorCallback error_callback) {
96 SetPropertyInternal(device_path, name, value, std::move(callback),
97 std::move(error_callback),
98 /*notify_changed=*/true);
99 }
100
SetPropertyInternal(const dbus::ObjectPath & device_path,const std::string & name,const base::Value & value,base::OnceClosure callback,ErrorCallback error_callback,bool notify_changed)101 void FakeShillDeviceClient::SetPropertyInternal(
102 const dbus::ObjectPath& device_path,
103 const std::string& name,
104 const base::Value& value,
105 base::OnceClosure callback,
106 ErrorCallback error_callback,
107 bool notify_changed) {
108 base::Value* device_properties =
109 stub_devices_.FindDictKey(device_path.value());
110 if (!device_properties) {
111 PostNotFoundError(std::move(error_callback));
112 return;
113 }
114 device_properties->SetKey(name, value.Clone());
115 if (notify_changed) {
116 base::ThreadTaskRunnerHandle::Get()->PostTask(
117 FROM_HERE,
118 base::BindOnce(&FakeShillDeviceClient::NotifyObserversPropertyChanged,
119 weak_ptr_factory_.GetWeakPtr(), device_path, name));
120 }
121 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
122 }
123
ClearProperty(const dbus::ObjectPath & device_path,const std::string & name,VoidDBusMethodCallback callback)124 void FakeShillDeviceClient::ClearProperty(const dbus::ObjectPath& device_path,
125 const std::string& name,
126 VoidDBusMethodCallback callback) {
127 base::Value* device_properties =
128 stub_devices_.FindDictKey(device_path.value());
129 if (!device_properties) {
130 PostVoidCallback(std::move(callback), false);
131 return;
132 }
133 device_properties->RemoveKey(name);
134 PostVoidCallback(std::move(callback), true);
135 }
136
RequirePin(const dbus::ObjectPath & device_path,const std::string & pin,bool require,base::OnceClosure callback,ErrorCallback error_callback)137 void FakeShillDeviceClient::RequirePin(const dbus::ObjectPath& device_path,
138 const std::string& pin,
139 bool require,
140 base::OnceClosure callback,
141 ErrorCallback error_callback) {
142 VLOG(1) << "RequirePin: " << device_path.value();
143 if (!stub_devices_.FindKey(device_path.value())) {
144 PostNotFoundError(std::move(error_callback));
145 return;
146 }
147 if (!SimTryPin(device_path.value(), pin)) {
148 base::ThreadTaskRunnerHandle::Get()->PostTask(
149 FROM_HERE, base::BindOnce(std::move(error_callback),
150 shill::kErrorResultIncorrectPin, ""));
151 return;
152 }
153 SimLockStatus status = GetSimLockStatus(device_path.value());
154 status.lock_enabled = require;
155 SetSimLockStatus(device_path.value(), status);
156
157 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
158 }
159
EnterPin(const dbus::ObjectPath & device_path,const std::string & pin,base::OnceClosure callback,ErrorCallback error_callback)160 void FakeShillDeviceClient::EnterPin(const dbus::ObjectPath& device_path,
161 const std::string& pin,
162 base::OnceClosure callback,
163 ErrorCallback error_callback) {
164 VLOG(1) << "EnterPin: " << device_path.value();
165 if (!stub_devices_.FindKey(device_path.value())) {
166 PostNotFoundError(std::move(error_callback));
167 return;
168 }
169 if (!SimTryPin(device_path.value(), pin)) {
170 base::ThreadTaskRunnerHandle::Get()->PostTask(
171 FROM_HERE, base::BindOnce(std::move(error_callback),
172 shill::kErrorResultIncorrectPin, ""));
173 return;
174 }
175 SetSimLocked(device_path.value(), false);
176
177 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
178 }
179
UnblockPin(const dbus::ObjectPath & device_path,const std::string & puk,const std::string & pin,base::OnceClosure callback,ErrorCallback error_callback)180 void FakeShillDeviceClient::UnblockPin(const dbus::ObjectPath& device_path,
181 const std::string& puk,
182 const std::string& pin,
183 base::OnceClosure callback,
184 ErrorCallback error_callback) {
185 VLOG(1) << "UnblockPin: " << device_path.value();
186 if (!stub_devices_.FindKey(device_path.value())) {
187 PostNotFoundError(std::move(error_callback));
188 return;
189 }
190 if (!SimTryPuk(device_path.value(), puk)) {
191 base::ThreadTaskRunnerHandle::Get()->PostTask(
192 FROM_HERE, base::BindOnce(std::move(error_callback),
193 shill::kErrorResultIncorrectPin, ""));
194 return;
195 }
196 if (pin.length() < kSimPinMinLength) {
197 base::ThreadTaskRunnerHandle::Get()->PostTask(
198 FROM_HERE, base::BindOnce(std::move(error_callback),
199 shill::kErrorResultInvalidArguments, ""));
200 return;
201 }
202 sim_pin_[device_path.value()] = pin;
203 SetSimLocked(device_path.value(), false);
204
205 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
206 }
207
ChangePin(const dbus::ObjectPath & device_path,const std::string & old_pin,const std::string & new_pin,base::OnceClosure callback,ErrorCallback error_callback)208 void FakeShillDeviceClient::ChangePin(const dbus::ObjectPath& device_path,
209 const std::string& old_pin,
210 const std::string& new_pin,
211 base::OnceClosure callback,
212 ErrorCallback error_callback) {
213 VLOG(1) << "ChangePin: " << device_path.value();
214 if (!stub_devices_.FindKey(device_path.value())) {
215 PostNotFoundError(std::move(error_callback));
216 return;
217 }
218 if (!SimTryPin(device_path.value(), old_pin)) {
219 base::ThreadTaskRunnerHandle::Get()->PostTask(
220 FROM_HERE, base::BindOnce(std::move(error_callback),
221 shill::kErrorResultIncorrectPin, ""));
222 return;
223 }
224 if (new_pin.length() < kSimPinMinLength) {
225 base::ThreadTaskRunnerHandle::Get()->PostTask(
226 FROM_HERE, base::BindOnce(std::move(error_callback),
227 shill::kErrorResultInvalidArguments, ""));
228 return;
229 }
230 sim_pin_[device_path.value()] = new_pin;
231
232 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
233 }
234
Register(const dbus::ObjectPath & device_path,const std::string & network_id,base::OnceClosure callback,ErrorCallback error_callback)235 void FakeShillDeviceClient::Register(const dbus::ObjectPath& device_path,
236 const std::string& network_id,
237 base::OnceClosure callback,
238 ErrorCallback error_callback) {
239 base::Value* device_properties =
240 stub_devices_.FindDictKey(device_path.value());
241 if (!device_properties) {
242 PostNotFoundError(std::move(error_callback));
243 return;
244 }
245 base::Value* scan_results =
246 device_properties->FindKey(shill::kFoundNetworksProperty);
247 if (!scan_results) {
248 PostError("No Cellular scan results", std::move(error_callback));
249 return;
250 }
251 for (auto& network : scan_results->GetList()) {
252 std::string id = network.FindKey(shill::kNetworkIdProperty)->GetString();
253 std::string status = id == network_id ? "current" : "available";
254 network.SetKey(shill::kStatusProperty, base::Value(status));
255 }
256 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
257 }
258
Reset(const dbus::ObjectPath & device_path,base::OnceClosure callback,ErrorCallback error_callback)259 void FakeShillDeviceClient::Reset(const dbus::ObjectPath& device_path,
260 base::OnceClosure callback,
261 ErrorCallback error_callback) {
262 if (!stub_devices_.FindKey(device_path.value())) {
263 PostNotFoundError(std::move(error_callback));
264 return;
265 }
266 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
267 }
268
AddWakeOnPacketConnection(const dbus::ObjectPath & device_path,const net::IPEndPoint & ip_endpoint,base::OnceClosure callback,ErrorCallback error_callback)269 void FakeShillDeviceClient::AddWakeOnPacketConnection(
270 const dbus::ObjectPath& device_path,
271 const net::IPEndPoint& ip_endpoint,
272 base::OnceClosure callback,
273 ErrorCallback error_callback) {
274 if (!stub_devices_.FindKey(device_path.value())) {
275 PostNotFoundError(std::move(error_callback));
276 return;
277 }
278
279 wake_on_packet_connections_[device_path].insert(ip_endpoint);
280
281 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
282 }
283
AddWakeOnPacketOfTypes(const dbus::ObjectPath & device_path,const std::vector<std::string> & types,base::OnceClosure callback,ErrorCallback error_callback)284 void FakeShillDeviceClient::AddWakeOnPacketOfTypes(
285 const dbus::ObjectPath& device_path,
286 const std::vector<std::string>& types,
287 base::OnceClosure callback,
288 ErrorCallback error_callback) {
289 if (!stub_devices_.FindKey(device_path.value())) {
290 PostNotFoundError(std::move(error_callback));
291 return;
292 }
293
294 wake_on_packet_types_[device_path].insert(types.begin(), types.end());
295 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
296 }
297
RemoveWakeOnPacketConnection(const dbus::ObjectPath & device_path,const net::IPEndPoint & ip_endpoint,base::OnceClosure callback,ErrorCallback error_callback)298 void FakeShillDeviceClient::RemoveWakeOnPacketConnection(
299 const dbus::ObjectPath& device_path,
300 const net::IPEndPoint& ip_endpoint,
301 base::OnceClosure callback,
302 ErrorCallback error_callback) {
303 const auto device_iter = wake_on_packet_connections_.find(device_path);
304 if (!stub_devices_.FindKey(device_path.value()) ||
305 device_iter == wake_on_packet_connections_.end()) {
306 PostNotFoundError(std::move(error_callback));
307 return;
308 }
309
310 const auto endpoint_iter = device_iter->second.find(ip_endpoint);
311 if (endpoint_iter == device_iter->second.end()) {
312 PostNotFoundError(std::move(error_callback));
313 return;
314 }
315
316 device_iter->second.erase(endpoint_iter);
317
318 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
319 }
320
RemoveWakeOnPacketOfTypes(const dbus::ObjectPath & device_path,const std::vector<std::string> & types,base::OnceClosure callback,ErrorCallback error_callback)321 void FakeShillDeviceClient::RemoveWakeOnPacketOfTypes(
322 const dbus::ObjectPath& device_path,
323 const std::vector<std::string>& types,
324 base::OnceClosure callback,
325 ErrorCallback error_callback) {
326 if (!stub_devices_.FindKey(device_path.value())) {
327 PostNotFoundError(std::move(error_callback));
328 return;
329 }
330
331 const auto registered_types_iter = wake_on_packet_types_.find(device_path);
332 if (registered_types_iter == wake_on_packet_types_.end()) {
333 PostNotFoundError(std::move(error_callback));
334 return;
335 }
336
337 std::set<std::string>& registered_types = registered_types_iter->second;
338 for (auto it = types.begin(); it != types.end(); it++)
339 registered_types.erase(*it);
340
341 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
342 }
343
RemoveAllWakeOnPacketConnections(const dbus::ObjectPath & device_path,base::OnceClosure callback,ErrorCallback error_callback)344 void FakeShillDeviceClient::RemoveAllWakeOnPacketConnections(
345 const dbus::ObjectPath& device_path,
346 base::OnceClosure callback,
347 ErrorCallback error_callback) {
348 const auto iter = wake_on_packet_connections_.find(device_path);
349 if (!stub_devices_.FindKey(device_path.value()) ||
350 iter == wake_on_packet_connections_.end()) {
351 PostNotFoundError(std::move(error_callback));
352 return;
353 }
354
355 wake_on_packet_connections_.erase(iter);
356
357 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
358 }
359
SetUsbEthernetMacAddressSource(const dbus::ObjectPath & device_path,const std::string & source,base::OnceClosure callback,ErrorCallback error_callback)360 void FakeShillDeviceClient::SetUsbEthernetMacAddressSource(
361 const dbus::ObjectPath& device_path,
362 const std::string& source,
363 base::OnceClosure callback,
364 ErrorCallback error_callback) {
365 if (!stub_devices_.FindKey(device_path.value())) {
366 PostNotFoundError(std::move(error_callback));
367 return;
368 }
369
370 const auto error_name_iter =
371 set_usb_ethernet_mac_address_source_error_names_.find(
372 device_path.value());
373 if (error_name_iter !=
374 set_usb_ethernet_mac_address_source_error_names_.end() &&
375 !error_name_iter->second.empty()) {
376 PostError(error_name_iter->second, std::move(error_callback));
377 return;
378 }
379
380 SetDeviceProperty(device_path.value(),
381 shill::kUsbEthernetMacAddressSourceProperty,
382 base::Value(source), /*notify_changed=*/true);
383
384 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
385 }
386
GetTestInterface()387 ShillDeviceClient::TestInterface* FakeShillDeviceClient::GetTestInterface() {
388 return this;
389 }
390
391 // ShillDeviceClient::TestInterface overrides.
392
AddDevice(const std::string & device_path,const std::string & type,const std::string & name)393 void FakeShillDeviceClient::AddDevice(const std::string& device_path,
394 const std::string& type,
395 const std::string& name) {
396 ShillManagerClient::Get()->GetTestInterface()->AddDevice(device_path);
397
398 base::Value* properties = GetDeviceProperties(device_path);
399 properties->SetKey(shill::kTypeProperty, base::Value(type));
400 properties->SetKey(shill::kNameProperty, base::Value(name));
401 properties->SetKey(shill::kDBusObjectProperty, base::Value(device_path));
402 properties->SetKey(shill::kDBusServiceProperty,
403 base::Value(modemmanager::kModemManager1ServiceName));
404 if (type == shill::kTypeCellular) {
405 properties->SetKey(shill::kCellularAllowRoamingProperty,
406 base::Value(false));
407 }
408 }
409
RemoveDevice(const std::string & device_path)410 void FakeShillDeviceClient::RemoveDevice(const std::string& device_path) {
411 ShillManagerClient::Get()->GetTestInterface()->RemoveDevice(device_path);
412 stub_devices_.RemoveKey(device_path);
413 }
414
ClearDevices()415 void FakeShillDeviceClient::ClearDevices() {
416 ShillManagerClient::Get()->GetTestInterface()->ClearDevices();
417 stub_devices_ = base::Value(base::Value::Type::DICTIONARY);
418 }
419
SetDeviceProperty(const std::string & device_path,const std::string & name,const base::Value & value,bool notify_changed)420 void FakeShillDeviceClient::SetDeviceProperty(const std::string& device_path,
421 const std::string& name,
422 const base::Value& value,
423 bool notify_changed) {
424 VLOG(1) << "SetDeviceProperty: " << device_path << ": " << name << " = "
425 << value;
426 SetPropertyInternal(
427 dbus::ObjectPath(device_path), name, value, base::DoNothing(),
428 base::BindOnce(&ErrorFunction, device_path), notify_changed);
429 }
430
GetDevicePathForType(const std::string & type)431 std::string FakeShillDeviceClient::GetDevicePathForType(
432 const std::string& type) {
433 for (auto iter : stub_devices_.DictItems()) {
434 if (!iter.second.is_dict())
435 continue;
436 const std::string* prop_type =
437 iter.second.FindStringKey(shill::kTypeProperty);
438 if (!prop_type || *prop_type != type)
439 continue;
440 return iter.first;
441 }
442 return std::string();
443 }
444
SetSimLocked(const std::string & device_path,bool locked)445 void FakeShillDeviceClient::SetSimLocked(const std::string& device_path,
446 bool locked) {
447 SimLockStatus status = GetSimLockStatus(device_path);
448 status.type = locked ? shill::kSIMLockPin : "";
449 status.retries_left = kSimPinRetryCount;
450 SetSimLockStatus(device_path, status);
451 }
452
AddCellularFoundNetwork(const std::string & device_path)453 void FakeShillDeviceClient::AddCellularFoundNetwork(
454 const std::string& device_path) {
455 base::Value* device_properties = stub_devices_.FindDictKey(device_path);
456 if (!device_properties) {
457 LOG(ERROR) << "Device path not found: " << device_path;
458 return;
459 }
460 std::string type =
461 device_properties->FindKey(shill::kTypeProperty)->GetString();
462 if (type != shill::kTypeCellular) {
463 LOG(ERROR) << "AddCellularNetwork called for non Cellular network: "
464 << device_path;
465 return;
466 }
467
468 // Add a new scan result entry
469 base::Value* scan_results =
470 device_properties->FindKey(shill::kFoundNetworksProperty);
471 if (!scan_results) {
472 scan_results = device_properties->SetKey(shill::kFoundNetworksProperty,
473 base::ListValue());
474 }
475 base::Value new_result(base::Value::Type::DICTIONARY);
476 int idx = static_cast<int>(scan_results->GetList().size());
477 new_result.SetKey(shill::kNetworkIdProperty,
478 base::Value(base::StringPrintf("network%d", idx)));
479 new_result.SetKey(shill::kLongNameProperty,
480 base::Value(base::StringPrintf("Network %d", idx)));
481 new_result.SetKey(shill::kTechnologyProperty, base::Value("GSM"));
482 new_result.SetKey(shill::kStatusProperty, base::Value("available"));
483 scan_results->Append(std::move(new_result));
484 base::ThreadTaskRunnerHandle::Get()->PostTask(
485 FROM_HERE,
486 base::BindOnce(&FakeShillDeviceClient::NotifyObserversPropertyChanged,
487 weak_ptr_factory_.GetWeakPtr(),
488 dbus::ObjectPath(device_path),
489 shill::kFoundNetworksProperty));
490 }
491
SetUsbEthernetMacAddressSourceError(const std::string & device_path,const std::string & error_name)492 void FakeShillDeviceClient::SetUsbEthernetMacAddressSourceError(
493 const std::string& device_path,
494 const std::string& error_name) {
495 set_usb_ethernet_mac_address_source_error_names_[device_path] = error_name;
496 }
497
498 // Private Methods -------------------------------------------------------------
499
GetSimLockStatus(const std::string & device_path)500 FakeShillDeviceClient::SimLockStatus FakeShillDeviceClient::GetSimLockStatus(
501 const std::string& device_path) {
502 SimLockStatus status;
503 base::Value* device_properties = stub_devices_.FindDictKey(device_path);
504 if (!device_properties)
505 return status;
506 base::Value* simlock_dict =
507 device_properties->FindDictKey(shill::kSIMLockStatusProperty);
508 if (!simlock_dict)
509 return status;
510 const std::string* type =
511 simlock_dict->FindStringKey(shill::kSIMLockTypeProperty);
512 if (type)
513 status.type = *type;
514 status.retries_left =
515 simlock_dict->FindIntKey(shill::kSIMLockRetriesLeftProperty).value_or(0);
516 status.lock_enabled =
517 simlock_dict->FindBoolKey(shill::kSIMLockEnabledProperty).value_or(false);
518 if (status.type == shill::kSIMLockPin && status.retries_left == 0)
519 status.retries_left = kSimPinRetryCount;
520 return status;
521 }
522
SetSimLockStatus(const std::string & device_path,const SimLockStatus & status)523 void FakeShillDeviceClient::SetSimLockStatus(const std::string& device_path,
524 const SimLockStatus& status) {
525 base::Value* device_properties = stub_devices_.FindDictKey(device_path);
526 if (!device_properties) {
527 NOTREACHED() << "Device not found: " << device_path;
528 return;
529 }
530
531 base::Value* simlock_dict =
532 device_properties->SetKey(shill::kSIMLockStatusProperty,
533 base::Value(base::Value::Type::DICTIONARY));
534
535 simlock_dict->SetKey(shill::kSIMLockTypeProperty, base::Value(status.type));
536 simlock_dict->SetKey(shill::kSIMLockRetriesLeftProperty,
537 base::Value(status.retries_left));
538 simlock_dict->SetKey(shill::kSIMLockEnabledProperty,
539 base::Value(status.lock_enabled));
540 NotifyObserversPropertyChanged(dbus::ObjectPath(device_path),
541 shill::kSIMLockStatusProperty);
542 }
543
SimTryPin(const std::string & device_path,const std::string & pin)544 bool FakeShillDeviceClient::SimTryPin(const std::string& device_path,
545 const std::string& pin) {
546 SimLockStatus status = GetSimLockStatus(device_path);
547 if (status.type == shill::kSIMLockPuk) {
548 VLOG(1) << "SimTryPin called with PUK locked.";
549 return false; // PUK locked, PIN won't work.
550 }
551 if (pin.length() < kSimPinMinLength)
552 return false;
553 std::string sim_pin = sim_pin_[device_path];
554 if (sim_pin.empty()) {
555 sim_pin = kDefaultSimPin;
556 sim_pin_[device_path] = sim_pin;
557 }
558 if (pin == sim_pin) {
559 status.type = "";
560 status.retries_left = kSimPinRetryCount;
561 SetSimLockStatus(device_path, status);
562 return true;
563 }
564
565 VLOG(1) << "SIM PIN: " << pin << " != " << sim_pin
566 << " Retries left: " << (status.retries_left - 1);
567 if (--status.retries_left <= 0) {
568 status.retries_left = kSimPukRetryCount;
569 status.type = shill::kSIMLockPuk;
570 status.lock_enabled = true;
571 }
572 SetSimLockStatus(device_path, status);
573 return false;
574 }
575
SimTryPuk(const std::string & device_path,const std::string & puk)576 bool FakeShillDeviceClient::SimTryPuk(const std::string& device_path,
577 const std::string& puk) {
578 SimLockStatus status = GetSimLockStatus(device_path);
579 if (status.type != shill::kSIMLockPuk) {
580 VLOG(1) << "PUK Not locked";
581 return true; // Not PUK locked.
582 }
583 if (status.retries_left == 0) {
584 VLOG(1) << "PUK: No retries left";
585 return false; // Permanently locked.
586 }
587
588 if (puk == kSimPuk) {
589 status.type = "";
590 status.retries_left = kSimPinRetryCount;
591 SetSimLockStatus(device_path, status);
592 return true;
593 }
594
595 --status.retries_left;
596 VLOG(1) << "SIM PUK: " << puk << " != " << kSimPuk
597 << " Retries left: " << status.retries_left;
598 SetSimLockStatus(device_path, status);
599 return false;
600 }
601
PassStubDeviceProperties(const dbus::ObjectPath & device_path,DBusMethodCallback<base::Value> callback) const602 void FakeShillDeviceClient::PassStubDeviceProperties(
603 const dbus::ObjectPath& device_path,
604 DBusMethodCallback<base::Value> callback) const {
605 const base::Value* device_properties =
606 stub_devices_.FindDictKey(device_path.value());
607 if (!device_properties) {
608 std::move(callback).Run(base::nullopt);
609 return;
610 }
611 std::move(callback).Run(device_properties->Clone());
612 }
613
614 // Posts a task to run a void callback with status code |status|.
PostVoidCallback(VoidDBusMethodCallback callback,bool result)615 void FakeShillDeviceClient::PostVoidCallback(VoidDBusMethodCallback callback,
616 bool result) {
617 base::ThreadTaskRunnerHandle::Get()->PostTask(
618 FROM_HERE, base::BindOnce(std::move(callback), result));
619 }
620
NotifyObserversPropertyChanged(const dbus::ObjectPath & device_path,const std::string & property)621 void FakeShillDeviceClient::NotifyObserversPropertyChanged(
622 const dbus::ObjectPath& device_path,
623 const std::string& property) {
624 std::string path = device_path.value();
625 base::Value* device_properties = stub_devices_.FindDictKey(path);
626 if (!device_properties) {
627 LOG(ERROR) << "Notify for unknown device: " << path;
628 return;
629 }
630 base::Value* value = device_properties->FindKey(property);
631 if (!value) {
632 LOG(ERROR) << "Notify for unknown property: " << path << " : " << property;
633 return;
634 }
635 for (auto& observer : GetObserverList(device_path))
636 observer.OnPropertyChanged(property, *value);
637 }
638
GetDeviceProperties(const std::string & device_path)639 base::Value* FakeShillDeviceClient::GetDeviceProperties(
640 const std::string& device_path) {
641 base::Value* properties = stub_devices_.FindDictKey(device_path);
642 if (!properties) {
643 properties = stub_devices_.SetKey(
644 device_path, base::Value(base::Value::Type::DICTIONARY));
645 }
646 return properties;
647 }
648
649 FakeShillDeviceClient::PropertyObserverList&
GetObserverList(const dbus::ObjectPath & device_path)650 FakeShillDeviceClient::GetObserverList(const dbus::ObjectPath& device_path) {
651 auto iter = observer_list_.find(device_path);
652 if (iter != observer_list_.end())
653 return *(iter->second);
654 PropertyObserverList* observer_list = new PropertyObserverList();
655 observer_list_[device_path] = base::WrapUnique(observer_list);
656 return *observer_list;
657 }
658
659 } // namespace chromeos
660