bluetooth_agent_service_provider.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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/bluetooth_agent_service_provider.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/chromeos/chromeos_version.h"
11#include "base/logging.h"
12#include "base/memory/ref_counted.h"
13#include "base/threading/platform_thread.h"
14#include "dbus/bus.h"
15#include "dbus/exported_object.h"
16#include "dbus/message.h"
17#include "dbus/object_path.h"
18#include "third_party/cros_system_api/dbus/service_constants.h"
19
20namespace {
21
22// Constants used by BlueZ for the ConfirmModeChange method.
23const char kModeOff[] = "off";
24const char kModeConnectable[] = "connectable";
25const char kModeDiscoverable[] = "discoverable";
26
27}  // namespace
28
29namespace chromeos {
30
31// The BluetoothAgentServiceProvider implementation used in production.
32class BluetoothAgentServiceProviderImpl : public BluetoothAgentServiceProvider {
33 public:
34  BluetoothAgentServiceProviderImpl(dbus::Bus* bus,
35                                    const dbus::ObjectPath& object_path,
36                                    Delegate* delegate)
37      : origin_thread_id_(base::PlatformThread::CurrentId()),
38        bus_(bus),
39        delegate_(delegate),
40        object_path_(object_path),
41        weak_ptr_factory_(this) {
42    DVLOG(1) << "Creating BluetoothAdapterClientImpl for "
43             << object_path.value();
44
45    exported_object_ = bus_->GetExportedObject(object_path_);
46
47    exported_object_->ExportMethod(
48        bluetooth_agent::kBluetoothAgentInterface,
49        bluetooth_agent::kRelease,
50        base::Bind(&BluetoothAgentServiceProviderImpl::Release,
51                   weak_ptr_factory_.GetWeakPtr()),
52        base::Bind(&BluetoothAgentServiceProviderImpl::ReleaseExported,
53                   weak_ptr_factory_.GetWeakPtr()));
54
55    exported_object_->ExportMethod(
56        bluetooth_agent::kBluetoothAgentInterface,
57        bluetooth_agent::kRequestPinCode,
58        base::Bind(&BluetoothAgentServiceProviderImpl::RequestPinCode,
59                   weak_ptr_factory_.GetWeakPtr()),
60        base::Bind(&BluetoothAgentServiceProviderImpl::RequestPinCodeExported,
61                   weak_ptr_factory_.GetWeakPtr()));
62
63    exported_object_->ExportMethod(
64        bluetooth_agent::kBluetoothAgentInterface,
65        bluetooth_agent::kRequestPasskey,
66        base::Bind(&BluetoothAgentServiceProviderImpl::RequestPasskey,
67                   weak_ptr_factory_.GetWeakPtr()),
68        base::Bind(&BluetoothAgentServiceProviderImpl::RequestPasskeyExported,
69                   weak_ptr_factory_.GetWeakPtr()));
70
71    exported_object_->ExportMethod(
72        bluetooth_agent::kBluetoothAgentInterface,
73        bluetooth_agent::kDisplayPinCode,
74        base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPinCode,
75                   weak_ptr_factory_.GetWeakPtr()),
76        base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPinCodeExported,
77                   weak_ptr_factory_.GetWeakPtr()));
78
79    exported_object_->ExportMethod(
80        bluetooth_agent::kBluetoothAgentInterface,
81        bluetooth_agent::kDisplayPasskey,
82        base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPasskey,
83                   weak_ptr_factory_.GetWeakPtr()),
84        base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPasskeyExported,
85                   weak_ptr_factory_.GetWeakPtr()));
86
87    exported_object_->ExportMethod(
88        bluetooth_agent::kBluetoothAgentInterface,
89        bluetooth_agent::kRequestConfirmation,
90        base::Bind(&BluetoothAgentServiceProviderImpl::RequestConfirmation,
91                   weak_ptr_factory_.GetWeakPtr()),
92        base::Bind(
93            &BluetoothAgentServiceProviderImpl::RequestConfirmationExported,
94            weak_ptr_factory_.GetWeakPtr()));
95
96    exported_object_->ExportMethod(
97        bluetooth_agent::kBluetoothAgentInterface,
98        bluetooth_agent::kAuthorize,
99        base::Bind(&BluetoothAgentServiceProviderImpl::Authorize,
100                   weak_ptr_factory_.GetWeakPtr()),
101        base::Bind(&BluetoothAgentServiceProviderImpl::AuthorizeExported,
102                   weak_ptr_factory_.GetWeakPtr()));
103
104    exported_object_->ExportMethod(
105        bluetooth_agent::kBluetoothAgentInterface,
106        bluetooth_agent::kConfirmModeChange,
107        base::Bind(&BluetoothAgentServiceProviderImpl::ConfirmModeChange,
108                   weak_ptr_factory_.GetWeakPtr()),
109        base::Bind(
110            &BluetoothAgentServiceProviderImpl::ConfirmModeChangeExported,
111            weak_ptr_factory_.GetWeakPtr()));
112
113    exported_object_->ExportMethod(
114        bluetooth_agent::kBluetoothAgentInterface,
115        bluetooth_agent::kCancel,
116        base::Bind(&BluetoothAgentServiceProviderImpl::Cancel,
117                   weak_ptr_factory_.GetWeakPtr()),
118        base::Bind(&BluetoothAgentServiceProviderImpl::CancelExported,
119                   weak_ptr_factory_.GetWeakPtr()));
120  }
121
122  virtual ~BluetoothAgentServiceProviderImpl() {
123    // Unregister the object path so we can reuse with a new agent.
124    bus_->UnregisterExportedObject(object_path_);
125  }
126
127 private:
128  // Returns true if the current thread is on the origin thread.
129  bool OnOriginThread() {
130    return base::PlatformThread::CurrentId() == origin_thread_id_;
131  }
132
133  // Called by dbus:: when the agent is unregistered from the Bluetooth
134  // daemon, generally at the end of a pairing request.
135  void Release(dbus::MethodCall* method_call,
136               dbus::ExportedObject::ResponseSender response_sender) {
137    DCHECK(OnOriginThread());
138    DCHECK(delegate_);
139
140    delegate_->Release();
141
142    dbus::Response* response = dbus::Response::FromMethodCall(method_call);
143    response_sender.Run(response);
144  }
145
146  // Called by dbus:: when the Release method is exported.
147  void ReleaseExported(const std::string& interface_name,
148                       const std::string& method_name,
149                       bool success) {
150    LOG_IF(WARNING, !success) << "Failed to export "
151                              << interface_name << "." << method_name;
152  }
153
154  // Called by dbus:: when the Bluetooth daemon requires a PIN Code for
155  // device authentication.
156  void RequestPinCode(dbus::MethodCall* method_call,
157                      dbus::ExportedObject::ResponseSender response_sender) {
158    DCHECK(OnOriginThread());
159    DCHECK(delegate_);
160
161    dbus::MessageReader reader(method_call);
162    dbus::ObjectPath device_path;
163    if (!reader.PopObjectPath(&device_path)) {
164      LOG(WARNING) << "RequestPinCode called with incorrect paramters: "
165                   << method_call->ToString();
166      return;
167    }
168
169    Delegate::PinCodeCallback callback = base::Bind(
170        &BluetoothAgentServiceProviderImpl::OnPinCode,
171        weak_ptr_factory_.GetWeakPtr(),
172        method_call,
173        response_sender);
174
175    delegate_->RequestPinCode(device_path, callback);
176  }
177
178  // Called by dbus:: when the RequestPinCode method is exported.
179  void RequestPinCodeExported(const std::string& interface_name,
180                              const std::string& method_name,
181                              bool success) {
182    LOG_IF(WARNING, !success) << "Failed to export "
183                              << interface_name << "." << method_name;
184  }
185
186  // Called by dbus:: when the Bluetooth daemon requires a Passkey for
187  // device authentication.
188  void RequestPasskey(dbus::MethodCall* method_call,
189                      dbus::ExportedObject::ResponseSender response_sender) {
190    DCHECK(OnOriginThread());
191    DCHECK(delegate_);
192
193    dbus::MessageReader reader(method_call);
194    dbus::ObjectPath device_path;
195    if (!reader.PopObjectPath(&device_path)) {
196      LOG(WARNING) << "RequestPasskey called with incorrect paramters: "
197                   << method_call->ToString();
198      return;
199    }
200
201    Delegate::PasskeyCallback callback = base::Bind(
202        &BluetoothAgentServiceProviderImpl::OnPasskey,
203        weak_ptr_factory_.GetWeakPtr(),
204        method_call,
205        response_sender);
206
207    delegate_->RequestPasskey(device_path, callback);
208  }
209
210  // Called by dbus:: when the RequestPasskey method is exported.
211  void RequestPasskeyExported(const std::string& interface_name,
212                              const std::string& method_name,
213                              bool success) {
214    LOG_IF(WARNING, !success) << "Failed to export "
215                              << interface_name << "." << method_name;
216  }
217
218  // Called by dbus:: when the Bluetooth daemon requires that the user
219  // enter a PIN Code into the remote device so that it may be
220  // authenticated.
221  void DisplayPinCode(dbus::MethodCall* method_call,
222                      dbus::ExportedObject::ResponseSender response_sender) {
223    DCHECK(OnOriginThread());
224    DCHECK(delegate_);
225
226    dbus::MessageReader reader(method_call);
227    dbus::ObjectPath device_path;
228    std::string pincode;
229    if (!reader.PopObjectPath(&device_path) ||
230        !reader.PopString(&pincode)) {
231      LOG(WARNING) << "DisplayPinCode called with incorrect paramters: "
232                   << method_call->ToString();
233      return;
234    }
235
236    delegate_->DisplayPinCode(device_path, pincode);
237
238    dbus::Response* response = dbus::Response::FromMethodCall(method_call);
239    response_sender.Run(response);
240  }
241
242  // Called by dbus:: when the DisplayPinCode method is exported.
243  void DisplayPinCodeExported(const std::string& interface_name,
244                              const std::string& method_name,
245                              bool success) {
246    LOG_IF(WARNING, !success) << "Failed to export "
247                              << interface_name << "." << method_name;
248  }
249
250  // Called by dbus:: when the Bluetooth daemon requires that the user
251  // enter a Passkey into the remote device so that it may be
252  // authenticated.
253  void DisplayPasskey(dbus::MethodCall* method_call,
254                      dbus::ExportedObject::ResponseSender response_sender) {
255    DCHECK(OnOriginThread());
256    DCHECK(delegate_);
257
258    dbus::MessageReader reader(method_call);
259    dbus::ObjectPath device_path;
260    uint32 passkey;
261    if (!reader.PopObjectPath(&device_path) ||
262        !reader.PopUint32(&passkey)) {
263      LOG(WARNING) << "DisplayPasskey called with incorrect paramters: "
264                   << method_call->ToString();
265      return;
266    }
267
268    delegate_->DisplayPasskey(device_path, passkey);
269
270    dbus::Response* response = dbus::Response::FromMethodCall(method_call);
271    response_sender.Run(response);
272  }
273
274  // Called by dbus:: when the DisplayPasskey method is exported.
275  void DisplayPasskeyExported(const std::string& interface_name,
276                              const std::string& method_name,
277                              bool success) {
278    LOG_IF(WARNING, !success) << "Failed to export "
279                              << interface_name << "." << method_name;
280  }
281
282  // Called by dbus:: when the Bluetooth daemon requires that the user
283  // confirm that a Passkey is displayed on the screen of the remote
284  // device so that it may be authenticated.
285  void RequestConfirmation(
286      dbus::MethodCall* method_call,
287      dbus::ExportedObject::ResponseSender response_sender) {
288    DCHECK(OnOriginThread());
289    DCHECK(delegate_);
290
291    dbus::MessageReader reader(method_call);
292    dbus::ObjectPath device_path;
293    uint32 passkey;
294    if (!reader.PopObjectPath(&device_path) ||
295        !reader.PopUint32(&passkey)) {
296      LOG(WARNING) << "RequestConfirmation called with incorrect paramters: "
297                   << method_call->ToString();
298      return;
299    }
300
301    Delegate::ConfirmationCallback callback = base::Bind(
302        &BluetoothAgentServiceProviderImpl::OnConfirmation,
303        weak_ptr_factory_.GetWeakPtr(),
304        method_call,
305        response_sender);
306
307    delegate_->RequestConfirmation(device_path, passkey, callback);
308  }
309
310  // Called by dbus:: when the RequestConfirmation method is exported.
311  void RequestConfirmationExported(const std::string& interface_name,
312                                   const std::string& method_name,
313                                   bool success) {
314    LOG_IF(WARNING, !success) << "Failed to export "
315                              << interface_name << "." << method_name;
316  }
317
318  // Called by dbus:: when the Bluetooth daemon requires that the user
319  // confirm that that a remote device is authorized to connect to a service
320  // UUID.
321  void Authorize(dbus::MethodCall* method_call,
322                 dbus::ExportedObject::ResponseSender response_sender) {
323    DCHECK(OnOriginThread());
324    DCHECK(delegate_);
325
326    dbus::MessageReader reader(method_call);
327    dbus::ObjectPath device_path;
328    std::string uuid;
329    if (!reader.PopObjectPath(&device_path) ||
330        !reader.PopString(&uuid)) {
331      LOG(WARNING) << "Authorize called with incorrect paramters: "
332                   << method_call->ToString();
333      return;
334    }
335
336    Delegate::ConfirmationCallback callback = base::Bind(
337        &BluetoothAgentServiceProviderImpl::OnConfirmation,
338        weak_ptr_factory_.GetWeakPtr(),
339        method_call,
340        response_sender);
341
342    delegate_->Authorize(device_path, uuid, callback);
343  }
344
345  // Called by dbus:: when the Authorize method is exported.
346  void AuthorizeExported(const std::string& interface_name,
347                         const std::string& method_name,
348                         bool success) {
349    LOG_IF(WARNING, !success) << "Failed to export "
350                              << interface_name << "." << method_name;
351  }
352
353  // Called by dbus:: when the Bluetooth daemon requires that the user
354  // confirm that the adapter may change mode.
355  void ConfirmModeChange(dbus::MethodCall* method_call,
356                         dbus::ExportedObject::ResponseSender response_sender) {
357    DCHECK(OnOriginThread());
358    DCHECK(delegate_);
359
360    dbus::MessageReader reader(method_call);
361    std::string mode_str;
362    if (!reader.PopString(&mode_str)) {
363      LOG(WARNING) << "ConfirmModeChange called with incorrect paramters: "
364                   << method_call->ToString();
365      return;
366    }
367
368    Delegate::Mode mode;
369    if (mode_str == kModeOff) {
370      mode = Delegate::OFF;
371    } else if (mode_str == kModeConnectable) {
372      mode = Delegate::CONNECTABLE;
373    } else if (mode_str == kModeDiscoverable) {
374      mode = Delegate::DISCOVERABLE;
375    } else {
376      LOG(WARNING) << "ConfirmModeChange called with unknown mode: "
377                   << mode_str;
378      return;
379    }
380
381    Delegate::ConfirmationCallback callback = base::Bind(
382        &BluetoothAgentServiceProviderImpl::OnConfirmation,
383        weak_ptr_factory_.GetWeakPtr(),
384        method_call,
385        response_sender);
386
387    delegate_->ConfirmModeChange(mode, callback);
388  }
389
390  // Called by dbus:: when the ConfirmModeChange method is exported.
391  void ConfirmModeChangeExported(const std::string& interface_name,
392                                 const std::string& method_name,
393                                 bool success) {
394    LOG_IF(WARNING, !success) << "Failed to export "
395                              << interface_name << "." << method_name;
396  }
397
398  // Called by dbus:: when the request failed before a reply was returned
399  // from the device.
400  void Cancel(dbus::MethodCall* method_call,
401              dbus::ExportedObject::ResponseSender response_sender) {
402    DCHECK(OnOriginThread());
403    DCHECK(delegate_);
404
405    delegate_->Cancel();
406
407    dbus::Response* response = dbus::Response::FromMethodCall(method_call);
408    response_sender.Run(response);
409  }
410
411  // Called by dbus:: when the Cancel method is exported.
412  void CancelExported(const std::string& interface_name,
413                      const std::string& method_name,
414                      bool success) {
415    LOG_IF(WARNING, !success) << "Failed to export "
416                              << interface_name << "." << method_name;
417  }
418
419  // Called by the Delegate to response to a method requesting a PIN code.
420  void OnPinCode(dbus::MethodCall* method_call,
421                 dbus::ExportedObject::ResponseSender response_sender,
422                 Delegate::Status status,
423                 const std::string& pincode) {
424    DCHECK(OnOriginThread());
425
426    switch (status) {
427      case Delegate::SUCCESS: {
428        dbus::Response* response = dbus::Response::FromMethodCall(method_call);
429        dbus::MessageWriter writer(response);
430        writer.AppendString(pincode);
431        response_sender.Run(response);
432        break;
433      }
434      case Delegate::REJECTED: {
435        dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall(
436            method_call, bluetooth_agent::kErrorRejected, "rejected");
437        response_sender.Run(response);
438        break;
439      }
440      case Delegate::CANCELLED: {
441        dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall(
442            method_call, bluetooth_agent::kErrorCanceled, "canceled");
443        response_sender.Run(response);
444        break;
445      }
446      default:
447        NOTREACHED() << "Unexpected status code from delegate: " << status;
448    }
449  }
450
451  // Called by the Delegate to response to a method requesting a Passkey.
452  void OnPasskey(dbus::MethodCall* method_call,
453                 dbus::ExportedObject::ResponseSender response_sender,
454                 Delegate::Status status,
455                 uint32 passkey) {
456    DCHECK(OnOriginThread());
457
458    switch (status) {
459      case Delegate::SUCCESS: {
460        dbus::Response* response = dbus::Response::FromMethodCall(method_call);
461        dbus::MessageWriter writer(response);
462        writer.AppendUint32(passkey);
463        response_sender.Run(response);
464        break;
465      }
466      case Delegate::REJECTED: {
467        dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall(
468            method_call, bluetooth_agent::kErrorRejected, "rejected");
469        response_sender.Run(response);
470        break;
471      }
472      case Delegate::CANCELLED: {
473        dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall(
474            method_call, bluetooth_agent::kErrorCanceled, "canceled");
475        response_sender.Run(response);
476        break;
477      }
478      default:
479        NOTREACHED() << "Unexpected status code from delegate: " << status;
480    }
481  }
482
483  // Called by the Delegate in response to a method requiring confirmation.
484  void OnConfirmation(dbus::MethodCall* method_call,
485                      dbus::ExportedObject::ResponseSender response_sender,
486                      Delegate::Status status) {
487    DCHECK(OnOriginThread());
488
489    switch (status) {
490      case Delegate::SUCCESS: {
491        dbus::Response* response = dbus::Response::FromMethodCall(method_call);
492        response_sender.Run(response);
493        break;
494      }
495      case Delegate::REJECTED: {
496        dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall(
497            method_call, bluetooth_agent::kErrorRejected, "rejected");
498        response_sender.Run(response);
499        break;
500      }
501      case Delegate::CANCELLED: {
502        dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall(
503            method_call, bluetooth_agent::kErrorCanceled, "canceled");
504        response_sender.Run(response);
505        break;
506      }
507      default:
508        NOTREACHED() << "Unexpected status code from delegate: " << status;
509    }
510  }
511
512  // Origin thread (i.e. the UI thread in production).
513  base::PlatformThreadId origin_thread_id_;
514
515  // D-Bus bus object is exported on, not owned by this object and must
516  // outlive it.
517  dbus::Bus* bus_;
518
519  // All incoming method calls are passed on to the Delegate and a callback
520  // passed to generate the reply. |delegate_| is generally the object that
521  // owns this one, and must outlive it.
522  Delegate* delegate_;
523
524  // D-Bus object path of object we are exporting, kept so we can unregister
525  // again in our destructor.
526  dbus::ObjectPath object_path_;
527
528  // D-Bus object we are exporting, owned by this object.
529  scoped_refptr<dbus::ExportedObject> exported_object_;
530
531  // Weak pointer factory for generating 'this' pointers that might live longer
532  // than we do.
533  // Note: This should remain the last member so it'll be destroyed and
534  // invalidate its weak pointers before any other members are destroyed.
535  base::WeakPtrFactory<BluetoothAgentServiceProviderImpl> weak_ptr_factory_;
536
537  DISALLOW_COPY_AND_ASSIGN(BluetoothAgentServiceProviderImpl);
538};
539
540// The BluetoothAgentServiceProvider implementation used on Linux desktop,
541// which does nothing.
542class BluetoothAgentServiceProviderStubImpl
543    : public BluetoothAgentServiceProvider {
544 public:
545  explicit BluetoothAgentServiceProviderStubImpl(Delegate* delegate_) {
546  }
547
548  virtual ~BluetoothAgentServiceProviderStubImpl() {
549  }
550};
551
552BluetoothAgentServiceProvider::BluetoothAgentServiceProvider() {
553}
554
555BluetoothAgentServiceProvider::~BluetoothAgentServiceProvider() {
556}
557
558// static
559BluetoothAgentServiceProvider* BluetoothAgentServiceProvider::Create(
560    dbus::Bus* bus,
561    const dbus::ObjectPath& object_path,
562    Delegate* delegate) {
563  if (base::chromeos::IsRunningOnChromeOS()) {
564    return new BluetoothAgentServiceProviderImpl(bus, object_path, delegate);
565  } else {
566    return new BluetoothAgentServiceProviderStubImpl(delegate);
567  }
568}
569
570}  // namespace chromeos
571