Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(743)

Side by Side Diff: device/bluetooth/bluetooth_device_experimental_chromeos.cc

Issue 13637016: WIP: DO NOT SUBMIT (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: wip fake pairing Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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 "device/bluetooth/bluetooth_device_experimental_chromeos.h"
6
7 #include "base/bind.h"
8 #include "chromeos/dbus/dbus_thread_manager.h"
9 #include "chromeos/dbus/experimental_bluetooth_adapter_client.h"
10 #include "chromeos/dbus/experimental_bluetooth_agent_manager_client.h"
11 #include "chromeos/dbus/experimental_bluetooth_agent_service_provider.h"
12 #include "chromeos/dbus/experimental_bluetooth_device_client.h"
13 #include "dbus/bus.h"
14 #include "device/bluetooth/bluetooth_adapter_experimental_chromeos.h"
15 #include "device/bluetooth/bluetooth_socket.h"
16 #include "third_party/cros_system_api/dbus/service_constants.h"
17
18 using device::BluetoothDevice;
19
20 namespace {
21
22 // The agent path is relativel meaningless since BlueZ only supports one
23 // at time and will fail an attempt to register another with "Already Exists"
24 // (which we fail in OnRegisterAgentError with ERROR_INPROGRESS).
25 const dbus::ObjectPath kAgentPath("/org/chromium/bluetooth_agent");
26
27 // The capability of our agents.
28 const char* kAgentCapability =
29 bluetooth_agent_manager::kKeyboardDisplayCapability;
30
31 } // namespace
32
33 namespace chromeos {
34
35 BluetoothDeviceExperimentalChromeOS::BluetoothDeviceExperimentalChromeOS(
36 BluetoothAdapterExperimentalChromeOS* adapter,
37 const dbus::ObjectPath& object_path)
38 : adapter_(adapter),
39 object_path_(object_path),
40 connecting_calls_(0),
41 pairing_delegate_(NULL),
42 weak_ptr_factory_(this) {
43 }
44
45 BluetoothDeviceExperimentalChromeOS::~BluetoothDeviceExperimentalChromeOS() {
46 }
47
48 uint32 BluetoothDeviceExperimentalChromeOS::GetBluetoothClass() const {
49 ExperimentalBluetoothDeviceClient::Properties* properties =
50 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
51 GetProperties(object_path_);
52 DCHECK(properties);
53
54 return properties->bluetooth_class.value();
55 }
56
57 std::string BluetoothDeviceExperimentalChromeOS::GetDeviceName() const {
58 ExperimentalBluetoothDeviceClient::Properties* properties =
59 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
60 GetProperties(object_path_);
61 DCHECK(properties);
62
63 return properties->alias.value();
64 }
65
66 std::string BluetoothDeviceExperimentalChromeOS::GetAddress() const {
67 ExperimentalBluetoothDeviceClient::Properties* properties =
68 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
69 GetProperties(object_path_);
70 DCHECK(properties);
71
72 return properties->address.value();
73 }
74
75 bool BluetoothDeviceExperimentalChromeOS::IsPaired() const {
76 ExperimentalBluetoothDeviceClient::Properties* properties =
77 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
78 GetProperties(object_path_);
79 DCHECK(properties);
80
81 return properties->paired.value();
82 }
83
84 bool BluetoothDeviceExperimentalChromeOS::IsConnected() const {
85 ExperimentalBluetoothDeviceClient::Properties* properties =
86 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
87 GetProperties(object_path_);
88 DCHECK(properties);
89
90 return properties->connected.value();
91 }
92
93 bool BluetoothDeviceExperimentalChromeOS::IsConnectable() const {
94 // TODO(deymo): implement
95 return false;
96 }
97
98 bool BluetoothDeviceExperimentalChromeOS::IsConnecting() const {
99 return connecting_calls_ > 0;
100 }
101
102 BluetoothDeviceExperimentalChromeOS::ServiceList
103 BluetoothDeviceExperimentalChromeOS::GetServices() const {
104 ExperimentalBluetoothDeviceClient::Properties* properties =
105 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
106 GetProperties(object_path_);
107 DCHECK(properties);
108
109 return properties->uuids.value();
110 }
111
112 void BluetoothDeviceExperimentalChromeOS::GetServiceRecords(
113 const ServiceRecordsCallback& callback,
114 const ErrorCallback& error_callback) {
115 // TODO(keybuk): not implemented; remove
116 error_callback.Run();
117 }
118
119 void BluetoothDeviceExperimentalChromeOS::ProvidesServiceWithName(
120 const std::string& name,
121 const ProvidesServiceCallback& callback) {
122 // TODO(keybuk): not implemented; remove
123 callback.Run(false);
124 }
125
126 bool BluetoothDeviceExperimentalChromeOS::ExpectingPinCode() const {
127 return !pincode_callback_.is_null();
128 }
129
130 bool BluetoothDeviceExperimentalChromeOS::ExpectingPasskey() const {
131 return !passkey_callback_.is_null();
132 }
133
134 bool BluetoothDeviceExperimentalChromeOS::ExpectingConfirmation() const {
135 return !confirmation_callback_.is_null();
136 }
137
138 void BluetoothDeviceExperimentalChromeOS::Connect(
139 BluetoothDevice::PairingDelegate* pairing_delegate,
140 const base::Closure& callback,
141 const ConnectErrorCallback& error_callback) {
142 ++connecting_calls_;
143 VLOG(1) << object_path_.value() << ": Connecting, " << connecting_calls_
144 << " in progress";
145
146 if (IsPaired() || IsConnected() || !pairing_delegate) {
147 // No need to pair, skip straight to connection.
148 ConnectInternal(callback, error_callback);
149
150 } else {
151 // Initiate high-security connection with pairing.
152 DCHECK(!pairing_delegate_);
153 DCHECK(agent_.get() == NULL);
154
155 pairing_delegate_ = pairing_delegate;
156
157 // The agent path is relatively meaningless since BlueZ only supports
158 // one per application at a time.
159 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
160 agent_.reset(ExperimentalBluetoothAgentServiceProvider::Create(
161 system_bus, kAgentPath, this));
162 DCHECK(agent_.get());
163
164 VLOG(1) << object_path_.value() << ": Registering agent for pairing";
165 DBusThreadManager::Get()->GetExperimentalBluetoothAgentManagerClient()->
166 RegisterAgent(
167 kAgentPath,
168 kAgentCapability,
169 base::Bind(
170 &BluetoothDeviceExperimentalChromeOS::OnRegisterAgent,
171 weak_ptr_factory_.GetWeakPtr(),
172 callback, error_callback),
173 base::Bind(
174 &BluetoothDeviceExperimentalChromeOS::OnRegisterAgentError,
175 weak_ptr_factory_.GetWeakPtr(),
176 error_callback));
177 }
178 }
179
180 void BluetoothDeviceExperimentalChromeOS::SetPinCode(
181 const std::string& pincode) {
182 if (!agent_.get() || pincode_callback_.is_null())
183 return;
184
185 pincode_callback_.Run(SUCCESS, pincode);
186 pincode_callback_.Reset();
187 }
188
189 void BluetoothDeviceExperimentalChromeOS::SetPasskey(uint32 passkey) {
190 if (!agent_.get() || passkey_callback_.is_null())
191 return;
192
193 passkey_callback_.Run(SUCCESS, passkey);
194 passkey_callback_.Reset();
195 }
196
197 void BluetoothDeviceExperimentalChromeOS::ConfirmPairing() {
198 if (!agent_.get() || confirmation_callback_.is_null())
199 return;
200
201 confirmation_callback_.Run(SUCCESS);
202 confirmation_callback_.Reset();
203 }
204
205 void BluetoothDeviceExperimentalChromeOS::RejectPairing() {
206 if (!agent_.get())
207 return;
208
209 if (!pincode_callback_.is_null()) {
210 pincode_callback_.Run(REJECTED, "");
211 pincode_callback_.Reset();
212 }
213 if (!passkey_callback_.is_null()) {
214 passkey_callback_.Run(REJECTED, 0);
215 passkey_callback_.Reset();
216 }
217 if (!confirmation_callback_.is_null()) {
218 confirmation_callback_.Run(REJECTED);
219 confirmation_callback_.Reset();
220 }
221 }
222
223 void BluetoothDeviceExperimentalChromeOS::CancelPairing() {
224 bool have_callback = false;
225 if (agent_.get()) {
226 if (!pincode_callback_.is_null()) {
227 pincode_callback_.Run(CANCELLED, "");
228 pincode_callback_.Reset();
229 have_callback = true;
230 }
231 if (!passkey_callback_.is_null()) {
232 passkey_callback_.Run(CANCELLED, 0);
233 passkey_callback_.Reset();
234 have_callback = true;
235 }
236 if (!confirmation_callback_.is_null()) {
237 confirmation_callback_.Run(CANCELLED);
238 confirmation_callback_.Reset();
239 have_callback = true;
240 }
241 }
242
243 // If there wasn't a callback in progress that we can reply to then we
244 // have to send a CancelPairing() to the device instead.
245 if (!have_callback) {
246 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
247 CancelPairing(
248 object_path_,
249 base::Bind(&base::DoNothing),
250 base::Bind(
251 &BluetoothDeviceExperimentalChromeOS::OnCancelPairingError,
252 weak_ptr_factory_.GetWeakPtr()));
253
254 // Unregister the agent now since we don't have a callback and if the
255 // very next command is a pairing attempt, which registers a new agent,
256 // we want that to succeed.
257 UnregisterAgent();
258 }
259 }
260
261 void BluetoothDeviceExperimentalChromeOS::Disconnect(
262 const base::Closure& callback,
263 const ErrorCallback& error_callback) {
264 VLOG(1) << object_path_.value() << ": Disconnecting";
265 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
266 Disconnect(
267 object_path_,
268 base::Bind(
269 &BluetoothDeviceExperimentalChromeOS::OnDisconnect,
270 weak_ptr_factory_.GetWeakPtr(),
271 callback),
272 base::Bind(
273 &BluetoothDeviceExperimentalChromeOS::OnDisconnectError,
274 weak_ptr_factory_.GetWeakPtr(),
275 error_callback));
276 }
277
278 void BluetoothDeviceExperimentalChromeOS::Forget(
279 const ErrorCallback& error_callback) {
280 VLOG(1) << object_path_.value() << ": Removing device";
281 DBusThreadManager::Get()->GetExperimentalBluetoothAdapterClient()->
282 RemoveDevice(
283 adapter_->object_path_,
284 object_path_,
285 base::Bind(&base::DoNothing),
286 base::Bind(
287 &BluetoothDeviceExperimentalChromeOS::OnForgetError,
288 weak_ptr_factory_.GetWeakPtr(),
289 error_callback));
290 }
291
292 void BluetoothDeviceExperimentalChromeOS::ConnectToService(
293 const std::string& service_uuid,
294 const SocketCallback& callback) {
295 // TODO(keybuk): implement
296 callback.Run(scoped_refptr<device::BluetoothSocket>());
297 }
298
299 void BluetoothDeviceExperimentalChromeOS::ConnectToProfile(
300 device::BluetoothProfile* profile,
301 const ErrorCallback& error_callback) {
302 // TODO(keybuk): implement
303 error_callback.Run();
304 }
305
306 void BluetoothDeviceExperimentalChromeOS::SetOutOfBandPairingData(
307 const device::BluetoothOutOfBandPairingData& data,
308 const base::Closure& callback,
309 const ErrorCallback& error_callback) {
310 // TODO(keybuk): implement
311 error_callback.Run();
312 }
313
314 void BluetoothDeviceExperimentalChromeOS::ClearOutOfBandPairingData(
315 const base::Closure& callback,
316 const ErrorCallback& error_callback) {
317 // TODO(keybuk): implement
318 error_callback.Run();
319 }
320
321
322 void BluetoothDeviceExperimentalChromeOS::Release() {
323 DCHECK(agent_.get());
324 DCHECK(pairing_delegate_);
325 VLOG(1) << object_path_.value() << ": Release";
326
327 pincode_callback_.Reset();
328 passkey_callback_.Reset();
329 confirmation_callback_.Reset();
330
331 UnregisterAgent();
332 }
333
334 void BluetoothDeviceExperimentalChromeOS::RequestPinCode(
335 const dbus::ObjectPath& device_path,
336 const PinCodeCallback& callback) {
337 DCHECK(agent_.get());
338 DCHECK(device_path == object_path_);
339 VLOG(1) << object_path_.value() << ": RequestPinCode";
340
341 DCHECK(pairing_delegate_);
342 DCHECK(pincode_callback_.is_null());
343 pincode_callback_ = callback;
344 pairing_delegate_->RequestPinCode(this);
345 }
346
347 void BluetoothDeviceExperimentalChromeOS::DisplayPinCode(
348 const dbus::ObjectPath& device_path,
349 const std::string& pincode) {
350 DCHECK(agent_.get());
351 DCHECK(device_path == object_path_);
352 VLOG(1) << object_path_.value() << ": DisplayPinCode: " << pincode;
353
354 DCHECK(pairing_delegate_);
355 pairing_delegate_->DisplayPinCode(this, pincode);
356 }
357
358 void BluetoothDeviceExperimentalChromeOS::RequestPasskey(
359 const dbus::ObjectPath& device_path,
360 const PasskeyCallback& callback) {
361 DCHECK(agent_.get());
362 DCHECK(device_path == object_path_);
363 VLOG(1) << object_path_.value() << ": RequestPasskey";
364
365 DCHECK(pairing_delegate_);
366 DCHECK(passkey_callback_.is_null());
367 passkey_callback_ = callback;
368 pairing_delegate_->RequestPasskey(this);
369 }
370
371 void BluetoothDeviceExperimentalChromeOS::DisplayPasskey(
372 const dbus::ObjectPath& device_path,
373 uint32 passkey, int16 entered) {
374 DCHECK(agent_.get());
375 DCHECK(device_path == object_path_);
376 VLOG(1) << object_path_.value() << ": DisplayPasskey: " << passkey
377 << " (" << entered << " entered)";
378
379 // TODO(keybuk): disambiguate entered vs display
380
381 DCHECK(pairing_delegate_);
382 pairing_delegate_->DisplayPasskey(this, passkey);
383 }
384
385 void BluetoothDeviceExperimentalChromeOS::RequestConfirmation(
386 const dbus::ObjectPath& device_path,
387 uint32 passkey,
388 const ConfirmationCallback& callback) {
389 DCHECK(agent_.get());
390 DCHECK(device_path == object_path_);
391 VLOG(1) << object_path_.value() << ": RequestConfirmation: " << passkey;
392
393 DCHECK(pairing_delegate_);
394 DCHECK(confirmation_callback_.is_null());
395 confirmation_callback_ = callback;
396 pairing_delegate_->ConfirmPasskey(this, passkey);
397 }
398
399 void BluetoothDeviceExperimentalChromeOS::RequestAuthorization(
400 const dbus::ObjectPath& device_path,
401 const ConfirmationCallback& callback) {
402 // TODO(keybuk): implement
403 callback.Run(CANCELLED);
404 }
405
406 void BluetoothDeviceExperimentalChromeOS::AuthorizeService(
407 const dbus::ObjectPath& device_path,
408 const std::string& uuid,
409 const ConfirmationCallback& callback) {
410 // TODO(keybuk): implement
411 callback.Run(CANCELLED);
412 }
413
414 void BluetoothDeviceExperimentalChromeOS::Cancel() {
415 DCHECK(agent_.get());
416 VLOG(1) << object_path_.value() << ": Cancel";
417
418 DCHECK(pairing_delegate_);
419 pairing_delegate_->DismissDisplayOrConfirm();
420 }
421
422 void BluetoothDeviceExperimentalChromeOS::ConnectInternal(
423 const base::Closure& callback,
424 const ConnectErrorCallback& error_callback) {
425 VLOG(1) << object_path_.value() << ": Connecting";
426 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
427 Connect(
428 object_path_,
429 base::Bind(
430 &BluetoothDeviceExperimentalChromeOS::OnConnect,
431 weak_ptr_factory_.GetWeakPtr(),
432 callback),
433 base::Bind(
434 &BluetoothDeviceExperimentalChromeOS::OnConnectError,
435 weak_ptr_factory_.GetWeakPtr(),
436 error_callback));
437 }
438
439 void BluetoothDeviceExperimentalChromeOS::OnConnect(
440 const base::Closure& callback) {
441 --connecting_calls_;
442 VLOG(1) << object_path_.value() << ": Connected, " << connecting_calls_
443 << " still in progress";
444
445 callback.Run();
446 }
447
448 void BluetoothDeviceExperimentalChromeOS::OnConnectError(
449 const ConnectErrorCallback& error_callback,
450 const std::string& error_name,
451 const std::string& error_message) {
452 --connecting_calls_;
453 LOG(WARNING) << object_path_.value() << ": Failed to connect device: "
454 << error_name << ": " << error_message;
455 VLOG(1) << object_path_.value() << ": " << connecting_calls_
456 << " still in progress";
457
458 // Determine the error code from error_name.
459 ConnectErrorCode error_code = ERROR_UNKNOWN;
460 if (error_name == bluetooth_adapter::kErrorFailed) {
461 error_code = ERROR_FAILED;
462 } else if (error_name == bluetooth_adapter::kErrorInProgress) {
463 error_code = ERROR_INPROGRESS;
464 } else if (error_name == bluetooth_adapter::kErrorNotSupported) {
465 error_code = ERROR_UNSUPPORTED_DEVICE;
466 }
467
468 error_callback.Run(error_code);
469 }
470
471 void BluetoothDeviceExperimentalChromeOS::OnRegisterAgent(
472 const base::Closure& callback,
473 const ConnectErrorCallback& error_callback) {
474 VLOG(1) << object_path_.value() << ": Agent registered, now pairing";
475
476 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
477 Pair(
478 object_path_,
479 base::Bind(
480 &BluetoothDeviceExperimentalChromeOS::OnPair,
481 weak_ptr_factory_.GetWeakPtr(),
482 callback, error_callback),
483 base::Bind(
484 &BluetoothDeviceExperimentalChromeOS::OnPairError,
485 weak_ptr_factory_.GetWeakPtr(),
486 error_callback));
487 }
488
489 void BluetoothDeviceExperimentalChromeOS::OnRegisterAgentError(
490 const ConnectErrorCallback& error_callback,
491 const std::string& error_name,
492 const std::string& error_message) {
493 --connecting_calls_;
494 LOG(WARNING) << object_path_.value() << ": Failed to register agent: "
495 << error_name << ": " << error_message;
496 VLOG(1) << object_path_.value() << ": " << connecting_calls_
497 << " still in progress";
498
499 UnregisterAgent();
500
501 // Determine the error code from error_name.
502 ConnectErrorCode error_code = ERROR_UNKNOWN;
503 if (error_name == bluetooth_adapter::kErrorAlreadyExists) {
504 error_code = ERROR_INPROGRESS;
505 }
506
507 error_callback.Run(error_code);
508 }
509
510 void BluetoothDeviceExperimentalChromeOS::OnPair(
511 const base::Closure& callback,
512 const ConnectErrorCallback& error_callback) {
513 VLOG(1) << object_path_.value() << ": Paired";
514
515 // Now that we're paired, we need to set the device as trusted so that
516 // incoming connections will be accepted. This should only ever fail if
517 // the device is removed mid-pairing, so do it in the background while
518 // we connect and don't worry about errors.
519 DBusThreadManager::Get()->GetExperimentalBluetoothDeviceClient()->
520 GetProperties(object_path_)->trusted.Set(
521 true,
522 base::Bind(
523 &BluetoothDeviceExperimentalChromeOS::OnSetTrusted,
524 weak_ptr_factory_.GetWeakPtr()));
525
526 UnregisterAgent();
527
528 // Now we can connect to the device!
529 ConnectInternal(callback, error_callback);
530 }
531
532 void BluetoothDeviceExperimentalChromeOS::OnPairError(
533 const ConnectErrorCallback& error_callback,
534 const std::string& error_name,
535 const std::string& error_message) {
536 --connecting_calls_;
537 LOG(WARNING) << object_path_.value() << ": Failed to pair device: "
538 << error_name << ": " << error_message;
539 VLOG(1) << object_path_.value() << ": " << connecting_calls_
540 << " still in progress";
541
542 UnregisterAgent();
543
544 // Determine the error code from error_name.
545 ConnectErrorCode error_code = ERROR_UNKNOWN;
546 if (error_name == bluetooth_adapter::kErrorConnectionAttemptFailed) {
547 error_code = ERROR_FAILED;
548 } else if (error_name == bluetooth_adapter::kErrorAuthenticationFailed) {
549 error_code = ERROR_AUTH_FAILED;
550 } else if (error_name == bluetooth_adapter::kErrorAuthenticationRejected) {
551 error_code = ERROR_AUTH_REJECTED;
552 } else if (error_name == bluetooth_adapter::kErrorAuthenticationTimeout) {
553 error_code = ERROR_AUTH_TIMEOUT;
554 }
555
556 error_callback.Run(error_code);
557 }
558
559 void BluetoothDeviceExperimentalChromeOS::OnCancelPairingError(
560 const std::string& error_name,
561 const std::string& error_message) {
562 LOG(WARNING) << object_path_.value() << ": Failed to cancel pairing: "
563 << error_name << ": " << error_message;
564 }
565
566 void BluetoothDeviceExperimentalChromeOS::OnSetTrusted(bool success) {
567 LOG_IF(WARNING, !success) << object_path_.value()
568 << ": Failed to set device as trusted";
569 }
570
571 void BluetoothDeviceExperimentalChromeOS::UnregisterAgent() {
572 DCHECK(agent_.get());
573 DCHECK(pairing_delegate_);
574
575 DCHECK(pincode_callback_.is_null());
576 DCHECK(passkey_callback_.is_null());
577 DCHECK(confirmation_callback_.is_null());
578
579 pairing_delegate_->DismissDisplayOrConfirm();
580 pairing_delegate_ = NULL;
581
582 agent_.reset();
583
584 // Clean up after ourselves.
585 VLOG(1) << object_path_.value() << ": Unregistering pairing agent";
586 DBusThreadManager::Get()->GetExperimentalBluetoothAgentManagerClient()->
587 UnregisterAgent(
588 kAgentPath,
589 base::Bind(&base::DoNothing),
590 base::Bind(
591 &BluetoothDeviceExperimentalChromeOS::OnUnregisterAgentError,
592 weak_ptr_factory_.GetWeakPtr()));
593 }
594
595 void BluetoothDeviceExperimentalChromeOS::OnUnregisterAgentError(
596 const std::string& error_name,
597 const std::string& error_message) {
598 LOG(WARNING) << object_path_.value() << ": Failed to unregister agent: "
599 << error_name << ": " << error_message;
600 }
601
602 void BluetoothDeviceExperimentalChromeOS::OnDisconnect(
603 const base::Closure& callback) {
604 VLOG(1) << object_path_.value() << ": Disconnected";
605 callback.Run();
606 }
607
608 void BluetoothDeviceExperimentalChromeOS::OnDisconnectError(
609 const ErrorCallback& error_callback,
610 const std::string& error_name,
611 const std::string& error_message) {
612 LOG(WARNING) << object_path_.value() << ": Failed to disconnect device: "
613 << error_name << ": " << error_message;
614 error_callback.Run();
615 }
616
617 void BluetoothDeviceExperimentalChromeOS::OnForgetError(
618 const ErrorCallback& error_callback,
619 const std::string& error_name,
620 const std::string& error_message) {
621 LOG(WARNING) << object_path_.value() << ": Failed to remove device: "
622 << error_name << ": " << error_message;
623 error_callback.Run();
624 }
625
626 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698