Home | History | Annotate | Download | only in dbus
      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/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 "chromeos/dbus/fake_bluetooth_agent_service_provider.h"
     15 #include "dbus/bus.h"
     16 #include "dbus/exported_object.h"
     17 #include "dbus/message.h"
     18 #include "dbus/object_path.h"
     19 #include "third_party/cros_system_api/dbus/service_constants.h"
     20 
     21 namespace chromeos {
     22 
     23 // The BluetoothAgentServiceProvider implementation used in production.
     24 class BluetoothAgentServiceProviderImpl
     25     : public BluetoothAgentServiceProvider {
     26  public:
     27   BluetoothAgentServiceProviderImpl(dbus::Bus* bus,
     28                                     const dbus::ObjectPath& object_path,
     29                                     Delegate* delegate)
     30       : origin_thread_id_(base::PlatformThread::CurrentId()),
     31         bus_(bus),
     32         delegate_(delegate),
     33         object_path_(object_path),
     34         weak_ptr_factory_(this) {
     35     VLOG(1) << "Creating Bluetooth Agent: " << object_path_.value();
     36 
     37     exported_object_ = bus_->GetExportedObject(object_path_);
     38 
     39     exported_object_->ExportMethod(
     40         bluetooth_agent::kBluetoothAgentInterface,
     41         bluetooth_agent::kRelease,
     42         base::Bind(&BluetoothAgentServiceProviderImpl::Release,
     43                    weak_ptr_factory_.GetWeakPtr()),
     44         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
     45                    weak_ptr_factory_.GetWeakPtr()));
     46 
     47     exported_object_->ExportMethod(
     48         bluetooth_agent::kBluetoothAgentInterface,
     49         bluetooth_agent::kRequestPinCode,
     50         base::Bind(&BluetoothAgentServiceProviderImpl::RequestPinCode,
     51                    weak_ptr_factory_.GetWeakPtr()),
     52         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
     53                    weak_ptr_factory_.GetWeakPtr()));
     54 
     55     exported_object_->ExportMethod(
     56         bluetooth_agent::kBluetoothAgentInterface,
     57         bluetooth_agent::kDisplayPinCode,
     58         base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPinCode,
     59                    weak_ptr_factory_.GetWeakPtr()),
     60         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
     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::OnExported,
     69                    weak_ptr_factory_.GetWeakPtr()));
     70 
     71     exported_object_->ExportMethod(
     72         bluetooth_agent::kBluetoothAgentInterface,
     73         bluetooth_agent::kDisplayPasskey,
     74         base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPasskey,
     75                    weak_ptr_factory_.GetWeakPtr()),
     76         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
     77                    weak_ptr_factory_.GetWeakPtr()));
     78 
     79     exported_object_->ExportMethod(
     80         bluetooth_agent::kBluetoothAgentInterface,
     81         bluetooth_agent::kRequestConfirmation,
     82         base::Bind(&BluetoothAgentServiceProviderImpl::RequestConfirmation,
     83                    weak_ptr_factory_.GetWeakPtr()),
     84         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
     85                    weak_ptr_factory_.GetWeakPtr()));
     86 
     87     exported_object_->ExportMethod(
     88         bluetooth_agent::kBluetoothAgentInterface,
     89         bluetooth_agent::kRequestAuthorization,
     90         base::Bind(&BluetoothAgentServiceProviderImpl::RequestAuthorization,
     91                    weak_ptr_factory_.GetWeakPtr()),
     92         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
     93                    weak_ptr_factory_.GetWeakPtr()));
     94 
     95     exported_object_->ExportMethod(
     96         bluetooth_agent::kBluetoothAgentInterface,
     97         bluetooth_agent::kAuthorizeService,
     98         base::Bind(&BluetoothAgentServiceProviderImpl::AuthorizeService,
     99                    weak_ptr_factory_.GetWeakPtr()),
    100         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
    101                    weak_ptr_factory_.GetWeakPtr()));
    102 
    103     exported_object_->ExportMethod(
    104         bluetooth_agent::kBluetoothAgentInterface,
    105         bluetooth_agent::kCancel,
    106         base::Bind(&BluetoothAgentServiceProviderImpl::Cancel,
    107                    weak_ptr_factory_.GetWeakPtr()),
    108         base::Bind(&BluetoothAgentServiceProviderImpl::OnExported,
    109                    weak_ptr_factory_.GetWeakPtr()));
    110   }
    111 
    112   virtual ~BluetoothAgentServiceProviderImpl() {
    113     VLOG(1) << "Cleaning up Bluetooth Agent: " << object_path_.value();
    114 
    115     // Unregister the object path so we can reuse with a new agent.
    116     bus_->UnregisterExportedObject(object_path_);
    117   }
    118 
    119  private:
    120   // Returns true if the current thread is on the origin thread.
    121   bool OnOriginThread() {
    122     return base::PlatformThread::CurrentId() == origin_thread_id_;
    123   }
    124 
    125   // Called by dbus:: when the agent is unregistered from the Bluetooth
    126   // daemon, generally at the end of a pairing request.
    127   void Release(dbus::MethodCall* method_call,
    128                dbus::ExportedObject::ResponseSender response_sender) {
    129     DCHECK(OnOriginThread());
    130     DCHECK(delegate_);
    131 
    132     delegate_->Release();
    133 
    134     response_sender.Run(dbus::Response::FromMethodCall(method_call));
    135   }
    136 
    137   // Called by dbus:: when the Bluetooth daemon requires a PIN Code for
    138   // device authentication.
    139   void RequestPinCode(dbus::MethodCall* method_call,
    140                       dbus::ExportedObject::ResponseSender response_sender) {
    141     DCHECK(OnOriginThread());
    142     DCHECK(delegate_);
    143 
    144     dbus::MessageReader reader(method_call);
    145     dbus::ObjectPath device_path;
    146     if (!reader.PopObjectPath(&device_path)) {
    147       LOG(WARNING) << "RequestPinCode called with incorrect paramters: "
    148                    << method_call->ToString();
    149       return;
    150     }
    151 
    152     Delegate::PinCodeCallback callback = base::Bind(
    153         &BluetoothAgentServiceProviderImpl::OnPinCode,
    154         weak_ptr_factory_.GetWeakPtr(),
    155         method_call,
    156         response_sender);
    157 
    158     delegate_->RequestPinCode(device_path, callback);
    159   }
    160 
    161   // Called by dbus:: when the Bluetooth daemon requires that the user
    162   // enter a PIN Code into the remote device so that it may be
    163   // authenticated.
    164   void DisplayPinCode(dbus::MethodCall* method_call,
    165                       dbus::ExportedObject::ResponseSender response_sender) {
    166     DCHECK(OnOriginThread());
    167     DCHECK(delegate_);
    168 
    169     dbus::MessageReader reader(method_call);
    170     dbus::ObjectPath device_path;
    171     std::string pincode;
    172     if (!reader.PopObjectPath(&device_path) ||
    173         !reader.PopString(&pincode)) {
    174       LOG(WARNING) << "DisplayPinCode called with incorrect paramters: "
    175                    << method_call->ToString();
    176       return;
    177     }
    178 
    179     delegate_->DisplayPinCode(device_path, pincode);
    180 
    181     response_sender.Run(dbus::Response::FromMethodCall(method_call));
    182   }
    183 
    184   // Called by dbus:: when the Bluetooth daemon requires a Passkey for
    185   // device authentication.
    186   void RequestPasskey(dbus::MethodCall* method_call,
    187                       dbus::ExportedObject::ResponseSender response_sender) {
    188     DCHECK(OnOriginThread());
    189     DCHECK(delegate_);
    190 
    191     dbus::MessageReader reader(method_call);
    192     dbus::ObjectPath device_path;
    193     if (!reader.PopObjectPath(&device_path)) {
    194       LOG(WARNING) << "RequestPasskey called with incorrect paramters: "
    195                    << method_call->ToString();
    196       return;
    197     }
    198 
    199     Delegate::PasskeyCallback callback = base::Bind(
    200         &BluetoothAgentServiceProviderImpl::OnPasskey,
    201         weak_ptr_factory_.GetWeakPtr(),
    202         method_call,
    203         response_sender);
    204 
    205     delegate_->RequestPasskey(device_path, callback);
    206   }
    207 
    208   // Called by dbus:: when the Bluetooth daemon requires that the user
    209   // enter a Passkey into the remote device so that it may be
    210   // authenticated.
    211   void DisplayPasskey(dbus::MethodCall* method_call,
    212                       dbus::ExportedObject::ResponseSender response_sender) {
    213     DCHECK(OnOriginThread());
    214     DCHECK(delegate_);
    215 
    216     dbus::MessageReader reader(method_call);
    217     dbus::ObjectPath device_path;
    218     uint32 passkey;
    219     uint16 entered;
    220     if (!reader.PopObjectPath(&device_path) ||
    221         !reader.PopUint32(&passkey) ||
    222         !reader.PopUint16(&entered)) {
    223       LOG(WARNING) << "DisplayPasskey called with incorrect paramters: "
    224                    << method_call->ToString();
    225       return;
    226     }
    227 
    228     delegate_->DisplayPasskey(device_path, passkey, entered);
    229 
    230     response_sender.Run(dbus::Response::FromMethodCall(method_call));
    231   }
    232 
    233   // Called by dbus:: when the Bluetooth daemon requires that the user
    234   // confirm that a Passkey is displayed on the screen of the remote
    235   // device so that it may be authenticated.
    236   void RequestConfirmation(
    237       dbus::MethodCall* method_call,
    238       dbus::ExportedObject::ResponseSender response_sender) {
    239     DCHECK(OnOriginThread());
    240     DCHECK(delegate_);
    241 
    242     dbus::MessageReader reader(method_call);
    243     dbus::ObjectPath device_path;
    244     uint32 passkey;
    245     if (!reader.PopObjectPath(&device_path) ||
    246         !reader.PopUint32(&passkey)) {
    247       LOG(WARNING) << "RequestConfirmation called with incorrect paramters: "
    248                    << method_call->ToString();
    249       return;
    250     }
    251 
    252     Delegate::ConfirmationCallback callback = base::Bind(
    253         &BluetoothAgentServiceProviderImpl::OnConfirmation,
    254         weak_ptr_factory_.GetWeakPtr(),
    255         method_call,
    256         response_sender);
    257 
    258     delegate_->RequestConfirmation(device_path, passkey, callback);
    259   }
    260 
    261   // Called by dbus:: when the Bluetooth daemon requires that the user
    262   // confirm an incoming just-works pairing.
    263   void RequestAuthorization(
    264         dbus::MethodCall* method_call,
    265         dbus::ExportedObject::ResponseSender response_sender) {
    266     DCHECK(OnOriginThread());
    267     DCHECK(delegate_);
    268 
    269     dbus::MessageReader reader(method_call);
    270     dbus::ObjectPath device_path;
    271     if (!reader.PopObjectPath(&device_path)) {
    272       LOG(WARNING) << "RequestAuthorization called with incorrect paramters: "
    273                    << method_call->ToString();
    274       return;
    275     }
    276 
    277     Delegate::ConfirmationCallback callback = base::Bind(
    278         &BluetoothAgentServiceProviderImpl::OnConfirmation,
    279         weak_ptr_factory_.GetWeakPtr(),
    280         method_call,
    281         response_sender);
    282 
    283     delegate_->RequestAuthorization(device_path, callback);
    284   }
    285 
    286   // Called by dbus:: when the Bluetooth daemon requires that the user
    287   // confirm that that a remote device is authorized to connect to a service
    288   // UUID.
    289   void AuthorizeService(dbus::MethodCall* method_call,
    290                         dbus::ExportedObject::ResponseSender response_sender) {
    291     DCHECK(OnOriginThread());
    292     DCHECK(delegate_);
    293 
    294     dbus::MessageReader reader(method_call);
    295     dbus::ObjectPath device_path;
    296     std::string uuid;
    297     if (!reader.PopObjectPath(&device_path) ||
    298         !reader.PopString(&uuid)) {
    299       LOG(WARNING) << "AuthorizeService called with incorrect paramters: "
    300                    << method_call->ToString();
    301       return;
    302     }
    303 
    304     Delegate::ConfirmationCallback callback = base::Bind(
    305         &BluetoothAgentServiceProviderImpl::OnConfirmation,
    306         weak_ptr_factory_.GetWeakPtr(),
    307         method_call,
    308         response_sender);
    309 
    310     delegate_->AuthorizeService(device_path, uuid, callback);
    311   }
    312 
    313   // Called by dbus:: when the request failed before a reply was returned
    314   // from the device.
    315   void Cancel(dbus::MethodCall* method_call,
    316               dbus::ExportedObject::ResponseSender response_sender) {
    317     DCHECK(OnOriginThread());
    318     DCHECK(delegate_);
    319 
    320     delegate_->Cancel();
    321 
    322     response_sender.Run(dbus::Response::FromMethodCall(method_call));
    323   }
    324 
    325   // Called by dbus:: when a method is exported.
    326   void OnExported(const std::string& interface_name,
    327                   const std::string& method_name,
    328                   bool success) {
    329     LOG_IF(WARNING, !success) << "Failed to export "
    330                               << interface_name << "." << method_name;
    331   }
    332 
    333   // Called by the Delegate to response to a method requesting a PIN code.
    334   void OnPinCode(dbus::MethodCall* method_call,
    335                  dbus::ExportedObject::ResponseSender response_sender,
    336                  Delegate::Status status,
    337                  const std::string& pincode) {
    338     DCHECK(OnOriginThread());
    339 
    340     switch (status) {
    341       case Delegate::SUCCESS: {
    342         scoped_ptr<dbus::Response> response(
    343             dbus::Response::FromMethodCall(method_call));
    344         dbus::MessageWriter writer(response.get());
    345         writer.AppendString(pincode);
    346         response_sender.Run(response.Pass());
    347         break;
    348       }
    349       case Delegate::REJECTED: {
    350         response_sender.Run(
    351             dbus::ErrorResponse::FromMethodCall(
    352                 method_call, bluetooth_agent::kErrorRejected, "rejected")
    353             .PassAs<dbus::Response>());
    354         break;
    355       }
    356       case Delegate::CANCELLED: {
    357         response_sender.Run(
    358             dbus::ErrorResponse::FromMethodCall(
    359                 method_call, bluetooth_agent::kErrorCanceled, "canceled")
    360             .PassAs<dbus::Response>());
    361         break;
    362       }
    363       default:
    364         NOTREACHED() << "Unexpected status code from delegate: " << status;
    365     }
    366   }
    367 
    368   // Called by the Delegate to response to a method requesting a Passkey.
    369   void OnPasskey(dbus::MethodCall* method_call,
    370                  dbus::ExportedObject::ResponseSender response_sender,
    371                  Delegate::Status status,
    372                  uint32 passkey) {
    373     DCHECK(OnOriginThread());
    374 
    375     switch (status) {
    376       case Delegate::SUCCESS: {
    377         scoped_ptr<dbus::Response> response(
    378             dbus::Response::FromMethodCall(method_call));
    379         dbus::MessageWriter writer(response.get());
    380         writer.AppendUint32(passkey);
    381         response_sender.Run(response.Pass());
    382         break;
    383       }
    384       case Delegate::REJECTED: {
    385         response_sender.Run(
    386             dbus::ErrorResponse::FromMethodCall(
    387                 method_call, bluetooth_agent::kErrorRejected, "rejected")
    388             .PassAs<dbus::Response>());
    389         break;
    390       }
    391       case Delegate::CANCELLED: {
    392         response_sender.Run(
    393             dbus::ErrorResponse::FromMethodCall(
    394                 method_call, bluetooth_agent::kErrorCanceled, "canceled")
    395             .PassAs<dbus::Response>());
    396         break;
    397       }
    398       default:
    399         NOTREACHED() << "Unexpected status code from delegate: " << status;
    400     }
    401   }
    402 
    403   // Called by the Delegate in response to a method requiring confirmation.
    404   void OnConfirmation(dbus::MethodCall* method_call,
    405                       dbus::ExportedObject::ResponseSender response_sender,
    406                       Delegate::Status status) {
    407     DCHECK(OnOriginThread());
    408 
    409     switch (status) {
    410       case Delegate::SUCCESS: {
    411         response_sender.Run(dbus::Response::FromMethodCall(method_call));
    412         break;
    413       }
    414       case Delegate::REJECTED: {
    415         response_sender.Run(
    416             dbus::ErrorResponse::FromMethodCall(
    417                 method_call, bluetooth_agent::kErrorRejected, "rejected")
    418             .PassAs<dbus::Response>());
    419         break;
    420       }
    421       case Delegate::CANCELLED: {
    422         response_sender.Run(
    423             dbus::ErrorResponse::FromMethodCall(
    424                 method_call, bluetooth_agent::kErrorCanceled, "canceled")
    425             .PassAs<dbus::Response>());
    426         break;
    427       }
    428       default:
    429         NOTREACHED() << "Unexpected status code from delegate: " << status;
    430     }
    431   }
    432 
    433   // Origin thread (i.e. the UI thread in production).
    434   base::PlatformThreadId origin_thread_id_;
    435 
    436   // D-Bus bus object is exported on, not owned by this object and must
    437   // outlive it.
    438   dbus::Bus* bus_;
    439 
    440   // All incoming method calls are passed on to the Delegate and a callback
    441   // passed to generate the reply. |delegate_| is generally the object that
    442   // owns this one, and must outlive it.
    443   Delegate* delegate_;
    444 
    445   // D-Bus object path of object we are exporting, kept so we can unregister
    446   // again in our destructor.
    447   dbus::ObjectPath object_path_;
    448 
    449   // D-Bus object we are exporting, owned by this object.
    450   scoped_refptr<dbus::ExportedObject> exported_object_;
    451 
    452   // Weak pointer factory for generating 'this' pointers that might live longer
    453   // than we do.
    454   // Note: This should remain the last member so it'll be destroyed and
    455   // invalidate its weak pointers before any other members are destroyed.
    456   base::WeakPtrFactory<BluetoothAgentServiceProviderImpl> weak_ptr_factory_;
    457 
    458   DISALLOW_COPY_AND_ASSIGN(BluetoothAgentServiceProviderImpl);
    459 };
    460 
    461 BluetoothAgentServiceProvider::BluetoothAgentServiceProvider() {
    462 }
    463 
    464 BluetoothAgentServiceProvider::~BluetoothAgentServiceProvider() {
    465 }
    466 
    467 // static
    468 BluetoothAgentServiceProvider* BluetoothAgentServiceProvider::Create(
    469     dbus::Bus* bus,
    470     const dbus::ObjectPath& object_path,
    471     Delegate* delegate) {
    472   if (base::chromeos::IsRunningOnChromeOS()) {
    473     return new BluetoothAgentServiceProviderImpl(bus, object_path, delegate);
    474   } else {
    475     return new FakeBluetoothAgentServiceProvider(object_path, delegate);
    476   }
    477 }
    478 
    479 }  // namespace chromeos
    480