Home | History | Annotate | Download | only in dbus
      1 // Copyright 2014 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_gatt_service_service_provider.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/memory/ref_counted.h"
     10 #include "base/memory/weak_ptr.h"
     11 #include "base/threading/platform_thread.h"
     12 #include "chromeos/dbus/dbus_thread_manager.h"
     13 #include "chromeos/dbus/fake_bluetooth_gatt_service_service_provider.h"
     14 #include "dbus/exported_object.h"
     15 #include "dbus/message.h"
     16 #include "third_party/cros_system_api/dbus/service_constants.h"
     17 
     18 namespace chromeos {
     19 namespace {
     20 const char kErrorInvalidArgs[] =
     21     "org.freedesktop.DBus.Error.InvalidArgs";
     22 const char kErrorPropertyReadOnly[] =
     23     "org.freedesktop.DBus.Error.PropertyReadOnly";
     24 }  // namespace
     25 
     26 // The BluetoothGattServiceServiceProvider implementation used in production.
     27 class BluetoothGattServiceServiceProviderImpl
     28     : public BluetoothGattServiceServiceProvider {
     29  public:
     30   BluetoothGattServiceServiceProviderImpl(
     31       dbus::Bus* bus,
     32       const dbus::ObjectPath& object_path,
     33       const std::string& uuid,
     34       const std::vector<dbus::ObjectPath>& includes)
     35       : origin_thread_id_(base::PlatformThread::CurrentId()),
     36         uuid_(uuid),
     37         includes_(includes),
     38         bus_(bus),
     39         object_path_(object_path),
     40         weak_ptr_factory_(this) {
     41     VLOG(1) << "Creating Bluetooth GATT service: " << object_path_.value()
     42             << " UUID: " << uuid;
     43     DCHECK(!uuid_.empty());
     44     DCHECK(object_path_.IsValid());
     45     DCHECK(bus_);
     46 
     47     exported_object_ = bus_->GetExportedObject(object_path_);
     48 
     49     exported_object_->ExportMethod(
     50         dbus::kDBusPropertiesInterface,
     51         dbus::kDBusPropertiesGet,
     52         base::Bind(&BluetoothGattServiceServiceProviderImpl::Get,
     53                    weak_ptr_factory_.GetWeakPtr()),
     54         base::Bind(&BluetoothGattServiceServiceProviderImpl::OnExported,
     55                    weak_ptr_factory_.GetWeakPtr()));
     56 
     57     exported_object_->ExportMethod(
     58         dbus::kDBusPropertiesInterface,
     59         dbus::kDBusPropertiesSet,
     60         base::Bind(&BluetoothGattServiceServiceProviderImpl::Set,
     61                    weak_ptr_factory_.GetWeakPtr()),
     62         base::Bind(&BluetoothGattServiceServiceProviderImpl::OnExported,
     63                    weak_ptr_factory_.GetWeakPtr()));
     64 
     65     exported_object_->ExportMethod(
     66         dbus::kDBusPropertiesInterface,
     67         dbus::kDBusPropertiesGetAll,
     68         base::Bind(&BluetoothGattServiceServiceProviderImpl::GetAll,
     69                    weak_ptr_factory_.GetWeakPtr()),
     70         base::Bind(&BluetoothGattServiceServiceProviderImpl::OnExported,
     71                    weak_ptr_factory_.GetWeakPtr()));
     72   }
     73 
     74   virtual ~BluetoothGattServiceServiceProviderImpl() {
     75     VLOG(1) << "Cleaning up Bluetooth GATT service: " << object_path_.value();
     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 Bluetooth daemon fetches a single property of
     86   // the service.
     87   void Get(dbus::MethodCall* method_call,
     88            dbus::ExportedObject::ResponseSender response_sender) {
     89     VLOG(2) << "BluetoothGattServiceServiceProvider::Get: "
     90             << object_path_.value();
     91     DCHECK(OnOriginThread());
     92 
     93     dbus::MessageReader reader(method_call);
     94 
     95     std::string interface_name;
     96     std::string property_name;
     97     if (!reader.PopString(&interface_name) ||
     98         !reader.PopString(&property_name) ||
     99         reader.HasMoreData()) {
    100       scoped_ptr<dbus::ErrorResponse> error_response =
    101           dbus::ErrorResponse::FromMethodCall(
    102               method_call, kErrorInvalidArgs, "Expected 'ss'.");
    103       response_sender.Run(error_response.PassAs<dbus::Response>());
    104       return;
    105     }
    106 
    107     // Only the GATT service interface is allowed.
    108     if (interface_name !=
    109         bluetooth_gatt_service::kBluetoothGattServiceInterface) {
    110       scoped_ptr<dbus::ErrorResponse> error_response =
    111           dbus::ErrorResponse::FromMethodCall(
    112               method_call, kErrorInvalidArgs,
    113               "No such interface: '" + interface_name + "'.");
    114       response_sender.Run(error_response.PassAs<dbus::Response>());
    115       return;
    116     }
    117 
    118     // Return error if |property_name| is unknown.
    119     if (property_name != bluetooth_gatt_service::kUUIDProperty &&
    120         property_name != bluetooth_gatt_service::kIncludesProperty) {
    121       scoped_ptr<dbus::ErrorResponse> error_response =
    122           dbus::ErrorResponse::FromMethodCall(
    123               method_call, kErrorInvalidArgs,
    124               "No such property: '" + property_name + "'.");
    125       response_sender.Run(error_response.PassAs<dbus::Response>());
    126       return;
    127     }
    128 
    129     scoped_ptr<dbus::Response> response =
    130         dbus::Response::FromMethodCall(method_call);
    131     dbus::MessageWriter writer(response.get());
    132     dbus::MessageWriter variant_writer(NULL);
    133 
    134     if (property_name == bluetooth_gatt_service::kUUIDProperty) {
    135       writer.OpenVariant("s", &variant_writer);
    136       variant_writer.AppendString(uuid_);
    137       writer.CloseContainer(&variant_writer);
    138     } else {
    139       writer.OpenVariant("ao", &variant_writer);
    140       variant_writer.AppendArrayOfObjectPaths(includes_);
    141       writer.CloseContainer(&variant_writer);
    142     }
    143 
    144     response_sender.Run(response.Pass());
    145   }
    146 
    147   // Called by dbus:: when the Bluetooth daemon sets a single property of the
    148   // service.
    149   void Set(dbus::MethodCall* method_call,
    150            dbus::ExportedObject::ResponseSender response_sender) {
    151     VLOG(2) << "BluetoothGattServiceServiceProvider::Set: "
    152             << object_path_.value();
    153     DCHECK(OnOriginThread());
    154 
    155     // All of the properties on this interface are read-only, so just return
    156     // error.
    157     scoped_ptr<dbus::ErrorResponse> error_response =
    158         dbus::ErrorResponse::FromMethodCall(
    159             method_call, kErrorPropertyReadOnly,
    160             "All properties are read-only.");
    161     response_sender.Run(error_response.PassAs<dbus::Response>());
    162   }
    163 
    164   // Called by dbus:: when the Bluetooth daemon fetches all properties of the
    165   // service.
    166   void GetAll(dbus::MethodCall* method_call,
    167               dbus::ExportedObject::ResponseSender response_sender) {
    168     VLOG(2) << "BluetoothGattServiceServiceProvider::GetAll: "
    169             << object_path_.value();
    170     DCHECK(OnOriginThread());
    171 
    172     dbus::MessageReader reader(method_call);
    173 
    174     std::string interface_name;
    175     if (!reader.PopString(&interface_name) || reader.HasMoreData()) {
    176       scoped_ptr<dbus::ErrorResponse> error_response =
    177           dbus::ErrorResponse::FromMethodCall(
    178               method_call, kErrorInvalidArgs, "Expected 's'.");
    179       response_sender.Run(error_response.PassAs<dbus::Response>());
    180       return;
    181     }
    182 
    183     // Only the GATT service interface is allowed.
    184     if (interface_name !=
    185         bluetooth_gatt_service::kBluetoothGattServiceInterface) {
    186       scoped_ptr<dbus::ErrorResponse> error_response =
    187           dbus::ErrorResponse::FromMethodCall(
    188               method_call, kErrorInvalidArgs,
    189               "No such interface: '" + interface_name + "'.");
    190       response_sender.Run(error_response.PassAs<dbus::Response>());
    191       return;
    192     }
    193 
    194     scoped_ptr<dbus::Response> response =
    195         dbus::Response::FromMethodCall(method_call);
    196     dbus::MessageWriter writer(response.get());
    197     dbus::MessageWriter array_writer(NULL);
    198     dbus::MessageWriter dict_entry_writer(NULL);
    199     dbus::MessageWriter variant_writer(NULL);
    200 
    201     writer.OpenArray("{sv}", &array_writer);
    202 
    203     array_writer.OpenDictEntry(&dict_entry_writer);
    204     dict_entry_writer.AppendString(bluetooth_gatt_service::kUUIDProperty);
    205     dict_entry_writer.AppendVariantOfString(uuid_);
    206     array_writer.CloseContainer(&dict_entry_writer);
    207 
    208     array_writer.OpenDictEntry(&dict_entry_writer);
    209     dict_entry_writer.AppendString(bluetooth_gatt_service::kIncludesProperty);
    210     dict_entry_writer.OpenVariant("ao", &variant_writer);
    211     variant_writer.AppendArrayOfObjectPaths(includes_);
    212     dict_entry_writer.CloseContainer(&variant_writer);
    213     array_writer.CloseContainer(&dict_entry_writer);
    214 
    215     writer.CloseContainer(&array_writer);
    216 
    217     response_sender.Run(response.Pass());
    218   }
    219 
    220   // Called by dbus:: when a method is exported.
    221   void OnExported(const std::string& interface_name,
    222                   const std::string& method_name,
    223                   bool success) {
    224     LOG_IF(WARNING, !success) << "Failed to export "
    225                               << interface_name << "." << method_name;
    226   }
    227 
    228   // Origin thread (i.e. the UI thread in production).
    229   base::PlatformThreadId origin_thread_id_;
    230 
    231   // 128-bit service UUID of this object.
    232   std::string uuid_;
    233 
    234   // List of object paths that represent other exported GATT services that are
    235   // included from this service.
    236   std::vector<dbus::ObjectPath> includes_;
    237 
    238   // D-Bus bus object is exported on, not owned by this object and must
    239   // outlive it.
    240   dbus::Bus* bus_;
    241 
    242   // D-Bus object path of object we are exporting, kept so we can unregister
    243   // again in our destructor.
    244   dbus::ObjectPath object_path_;
    245 
    246   // D-Bus object we are exporting, owned by this object.
    247   scoped_refptr<dbus::ExportedObject> exported_object_;
    248 
    249   // Weak pointer factory for generating 'this' pointers that might live longer
    250   // than we do.
    251   // Note: This should remain the last member so it'll be destroyed and
    252   // invalidate its weak pointers before any other members are destroyed.
    253   base::WeakPtrFactory<BluetoothGattServiceServiceProviderImpl>
    254       weak_ptr_factory_;
    255 
    256   DISALLOW_COPY_AND_ASSIGN(BluetoothGattServiceServiceProviderImpl);
    257 };
    258 
    259 BluetoothGattServiceServiceProvider::BluetoothGattServiceServiceProvider() {
    260 }
    261 
    262 BluetoothGattServiceServiceProvider::~BluetoothGattServiceServiceProvider() {
    263 }
    264 
    265 // static
    266 BluetoothGattServiceServiceProvider*
    267 BluetoothGattServiceServiceProvider::Create(
    268     dbus::Bus* bus,
    269     const dbus::ObjectPath& object_path,
    270     const std::string& uuid,
    271     const std::vector<dbus::ObjectPath>& includes) {
    272   if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) {
    273     return new BluetoothGattServiceServiceProviderImpl(
    274         bus, object_path, uuid, includes);
    275   }
    276   return new FakeBluetoothGattServiceServiceProvider(
    277       object_path, uuid, includes);
    278 }
    279 
    280 }  // namespace chromeos
    281