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_profile_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_profile_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 BluetoothProfileServiceProvider implementation used in production.
     24 class BluetoothProfileServiceProviderImpl
     25     : public BluetoothProfileServiceProvider {
     26  public:
     27   BluetoothProfileServiceProviderImpl(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 Profile: " << object_path_.value();
     36 
     37     exported_object_ = bus_->GetExportedObject(object_path_);
     38 
     39     exported_object_->ExportMethod(
     40         bluetooth_profile::kBluetoothProfileInterface,
     41         bluetooth_profile::kRelease,
     42         base::Bind(&BluetoothProfileServiceProviderImpl::Release,
     43                    weak_ptr_factory_.GetWeakPtr()),
     44         base::Bind(&BluetoothProfileServiceProviderImpl::OnExported,
     45                    weak_ptr_factory_.GetWeakPtr()));
     46 
     47     exported_object_->ExportMethod(
     48         bluetooth_profile::kBluetoothProfileInterface,
     49         bluetooth_profile::kNewConnection,
     50         base::Bind(&BluetoothProfileServiceProviderImpl::NewConnection,
     51                    weak_ptr_factory_.GetWeakPtr()),
     52         base::Bind(&BluetoothProfileServiceProviderImpl::OnExported,
     53                    weak_ptr_factory_.GetWeakPtr()));
     54 
     55     exported_object_->ExportMethod(
     56         bluetooth_profile::kBluetoothProfileInterface,
     57         bluetooth_profile::kRequestDisconnection,
     58         base::Bind(&BluetoothProfileServiceProviderImpl::RequestDisconnection,
     59                    weak_ptr_factory_.GetWeakPtr()),
     60         base::Bind(&BluetoothProfileServiceProviderImpl::OnExported,
     61                    weak_ptr_factory_.GetWeakPtr()));
     62 
     63     exported_object_->ExportMethod(
     64         bluetooth_profile::kBluetoothProfileInterface,
     65         bluetooth_profile::kCancel,
     66         base::Bind(&BluetoothProfileServiceProviderImpl::Cancel,
     67                    weak_ptr_factory_.GetWeakPtr()),
     68         base::Bind(&BluetoothProfileServiceProviderImpl::OnExported,
     69                    weak_ptr_factory_.GetWeakPtr()));
     70   }
     71 
     72   virtual ~BluetoothProfileServiceProviderImpl() {
     73     VLOG(1) << "Cleaning up Bluetooth Profile: " << object_path_.value();
     74 
     75     // Unregister the object path so we can reuse with a new agent.
     76     bus_->UnregisterExportedObject(object_path_);
     77   }
     78 
     79  private:
     80   // Returns true if the current thread is on the origin thread.
     81   bool OnOriginThread() {
     82     return base::PlatformThread::CurrentId() == origin_thread_id_;
     83   }
     84 
     85   // Called by dbus:: when the profile is unregistered from the Bluetooth
     86   // daemon, generally by our request.
     87   void Release(dbus::MethodCall* method_call,
     88                dbus::ExportedObject::ResponseSender response_sender) {
     89     DCHECK(OnOriginThread());
     90     DCHECK(delegate_);
     91 
     92     delegate_->Release();
     93 
     94     response_sender.Run(dbus::Response::FromMethodCall(method_call));
     95   }
     96 
     97   // Called by dbus:: when the Bluetooth daemon establishes a new connection
     98   // to the profile.
     99   void NewConnection(dbus::MethodCall* method_call,
    100                      dbus::ExportedObject::ResponseSender response_sender) {
    101     DCHECK(OnOriginThread());
    102     DCHECK(delegate_);
    103 
    104     dbus::MessageReader reader(method_call);
    105     dbus::ObjectPath device_path;
    106     scoped_ptr<dbus::FileDescriptor> fd(new dbus::FileDescriptor());
    107     dbus::MessageReader array_reader(NULL);
    108     if (!reader.PopObjectPath(&device_path) ||
    109         !reader.PopFileDescriptor(fd.get()) ||
    110         !reader.PopArray(&array_reader)) {
    111       LOG(WARNING) << "NewConnection called with incorrect paramters: "
    112                    << method_call->ToString();
    113       return;
    114     }
    115 
    116     Delegate::Options options;
    117     while (array_reader.HasMoreData()) {
    118       dbus::MessageReader dict_entry_reader(NULL);
    119       std::string key;
    120       if (!array_reader.PopDictEntry(&dict_entry_reader) ||
    121           !dict_entry_reader.PopString(&key)) {
    122         LOG(WARNING) << "NewConnection called with incorrect paramters: "
    123                      << method_call->ToString();
    124       } else {
    125         if (key == bluetooth_profile::kVersionProperty)
    126           dict_entry_reader.PopVariantOfUint16(&options.version);
    127         else if (key == bluetooth_profile::kFeaturesProperty)
    128           dict_entry_reader.PopVariantOfUint16(&options.features);
    129       }
    130     }
    131 
    132     Delegate::ConfirmationCallback callback = base::Bind(
    133         &BluetoothProfileServiceProviderImpl::OnConfirmation,
    134         weak_ptr_factory_.GetWeakPtr(),
    135         method_call,
    136         response_sender);
    137 
    138     delegate_->NewConnection(device_path, fd.Pass(), options, callback);
    139   }
    140 
    141   // Called by dbus:: when the Bluetooth daemon is about to disconnect the
    142   // profile.
    143   void RequestDisconnection(
    144       dbus::MethodCall* method_call,
    145       dbus::ExportedObject::ResponseSender response_sender) {
    146     DCHECK(OnOriginThread());
    147     DCHECK(delegate_);
    148 
    149     dbus::MessageReader reader(method_call);
    150     dbus::ObjectPath device_path;
    151     if (!reader.PopObjectPath(&device_path)) {
    152       LOG(WARNING) << "RequestDisconnection called with incorrect paramters: "
    153                    << method_call->ToString();
    154       return;
    155     }
    156 
    157     Delegate::ConfirmationCallback callback = base::Bind(
    158         &BluetoothProfileServiceProviderImpl::OnConfirmation,
    159         weak_ptr_factory_.GetWeakPtr(),
    160         method_call,
    161         response_sender);
    162 
    163     delegate_->RequestDisconnection(device_path, callback);
    164   }
    165 
    166   // Called by dbus:: when the request failed before a reply was returned
    167   // from the device.
    168   void Cancel(dbus::MethodCall* method_call,
    169               dbus::ExportedObject::ResponseSender response_sender) {
    170     DCHECK(OnOriginThread());
    171     DCHECK(delegate_);
    172 
    173     delegate_->Cancel();
    174 
    175     response_sender.Run(dbus::Response::FromMethodCall(method_call));
    176   }
    177 
    178   // Called by dbus:: when a method is exported.
    179   void OnExported(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 the Delegate in response to a method requiring confirmation.
    187   void OnConfirmation(dbus::MethodCall* method_call,
    188                       dbus::ExportedObject::ResponseSender response_sender,
    189                       Delegate::Status status) {
    190     DCHECK(OnOriginThread());
    191 
    192     switch (status) {
    193       case Delegate::SUCCESS: {
    194         response_sender.Run(dbus::Response::FromMethodCall(method_call));
    195         break;
    196       }
    197       case Delegate::REJECTED: {
    198         response_sender.Run(
    199             dbus::ErrorResponse::FromMethodCall(
    200                 method_call, bluetooth_profile::kErrorRejected, "rejected")
    201             .PassAs<dbus::Response>());
    202         break;
    203       }
    204       case Delegate::CANCELLED: {
    205         response_sender.Run(
    206             dbus::ErrorResponse::FromMethodCall(
    207                 method_call, bluetooth_profile::kErrorCanceled, "canceled")
    208             .PassAs<dbus::Response>());
    209         break;
    210       }
    211       default:
    212         NOTREACHED() << "Unexpected status code from delegate: " << status;
    213     }
    214   }
    215 
    216   // Origin thread (i.e. the UI thread in production).
    217   base::PlatformThreadId origin_thread_id_;
    218 
    219   // D-Bus bus object is exported on, not owned by this object and must
    220   // outlive it.
    221   dbus::Bus* bus_;
    222 
    223   // All incoming method calls are passed on to the Delegate and a callback
    224   // passed to generate the reply. |delegate_| is generally the object that
    225   // owns this one, and must outlive it.
    226   Delegate* delegate_;
    227 
    228   // D-Bus object path of object we are exporting, kept so we can unregister
    229   // again in our destructor.
    230   dbus::ObjectPath object_path_;
    231 
    232   // D-Bus object we are exporting, owned by this object.
    233   scoped_refptr<dbus::ExportedObject> exported_object_;
    234 
    235   // Weak pointer factory for generating 'this' pointers that might live longer
    236   // than we do.
    237   // Note: This should remain the last member so it'll be destroyed and
    238   // invalidate its weak pointers before any other members are destroyed.
    239   base::WeakPtrFactory<BluetoothProfileServiceProviderImpl> weak_ptr_factory_;
    240 
    241   DISALLOW_COPY_AND_ASSIGN(BluetoothProfileServiceProviderImpl);
    242 };
    243 
    244 BluetoothProfileServiceProvider::BluetoothProfileServiceProvider() {
    245 }
    246 
    247 BluetoothProfileServiceProvider::~BluetoothProfileServiceProvider() {
    248 }
    249 
    250 // static
    251 BluetoothProfileServiceProvider* BluetoothProfileServiceProvider::Create(
    252     dbus::Bus* bus,
    253     const dbus::ObjectPath& object_path,
    254     Delegate* delegate) {
    255   if (base::chromeos::IsRunningOnChromeOS()) {
    256     return new BluetoothProfileServiceProviderImpl(bus, object_path, delegate);
    257   } else {
    258     return new FakeBluetoothProfileServiceProvider(object_path, delegate);
    259   }
    260 }
    261 
    262 }  // namespace chromeos
    263