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_descriptor_service_provider.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/memory/weak_ptr.h"
     10 #include "base/strings/string_util.h"
     11 #include "base/sys_info.h"
     12 #include "base/threading/platform_thread.h"
     13 #include "chromeos/dbus/fake_bluetooth_gatt_descriptor_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 const char kErrorFailed[] =
     25     "org.freedesktop.DBus.Error.Failed";
     26 }  // namespace
     27 
     28 // The BluetoothGattDescriptorServiceProvider implementation used in production.
     29 class BluetoothGattDescriptorServiceProviderImpl
     30     : public BluetoothGattDescriptorServiceProvider {
     31  public:
     32   BluetoothGattDescriptorServiceProviderImpl(
     33       dbus::Bus* bus,
     34       const dbus::ObjectPath& object_path,
     35       Delegate* delegate,
     36       const std::string& uuid,
     37       const std::vector<std::string>& permissions,
     38       const dbus::ObjectPath& characteristic_path)
     39       : origin_thread_id_(base::PlatformThread::CurrentId()),
     40         uuid_(uuid),
     41         bus_(bus),
     42         delegate_(delegate),
     43         object_path_(object_path),
     44         characteristic_path_(characteristic_path),
     45         weak_ptr_factory_(this) {
     46     VLOG(1) << "Created Bluetooth GATT characteristic descriptor: "
     47             << object_path.value() << " UUID: " << uuid;
     48     DCHECK(bus_);
     49     DCHECK(delegate_);
     50     DCHECK(!uuid_.empty());
     51     DCHECK(object_path_.IsValid());
     52     DCHECK(characteristic_path_.IsValid());
     53     DCHECK(StartsWithASCII(
     54         object_path_.value(), characteristic_path_.value() + "/", true));
     55 
     56     exported_object_ = bus_->GetExportedObject(object_path_);
     57 
     58     exported_object_->ExportMethod(
     59         dbus::kDBusPropertiesInterface,
     60         dbus::kDBusPropertiesGet,
     61         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::Get,
     62                    weak_ptr_factory_.GetWeakPtr()),
     63         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
     64                    weak_ptr_factory_.GetWeakPtr()));
     65 
     66     exported_object_->ExportMethod(
     67         dbus::kDBusPropertiesInterface,
     68         dbus::kDBusPropertiesSet,
     69         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::Set,
     70                    weak_ptr_factory_.GetWeakPtr()),
     71         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
     72                    weak_ptr_factory_.GetWeakPtr()));
     73 
     74     exported_object_->ExportMethod(
     75         dbus::kDBusPropertiesInterface,
     76         dbus::kDBusPropertiesGetAll,
     77         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::GetAll,
     78                    weak_ptr_factory_.GetWeakPtr()),
     79         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
     80                    weak_ptr_factory_.GetWeakPtr()));
     81   }
     82 
     83   virtual ~BluetoothGattDescriptorServiceProviderImpl() {
     84     VLOG(1) << "Cleaning up Bluetooth GATT characteristic descriptor: "
     85             << object_path_.value();
     86     bus_->UnregisterExportedObject(object_path_);
     87   }
     88 
     89   // BluetoothGattDescriptorServiceProvider override.
     90   virtual void SendValueChanged(const std::vector<uint8>& value) OVERRIDE {
     91     VLOG(2) << "Emitting a PropertiesChanged signal for descriptor value.";
     92     dbus::Signal signal(
     93         dbus::kDBusPropertiesInterface,
     94         dbus::kDBusPropertiesChangedSignal);
     95     dbus::MessageWriter writer(&signal);
     96     dbus::MessageWriter array_writer(NULL);
     97     dbus::MessageWriter dict_entry_writer(NULL);
     98     dbus::MessageWriter variant_writer(NULL);
     99 
    100     // interface_name
    101     writer.AppendString(
    102         bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface);
    103 
    104     // changed_properties
    105     writer.OpenArray("{sv}", &array_writer);
    106     array_writer.OpenDictEntry(&dict_entry_writer);
    107     dict_entry_writer.AppendString(bluetooth_gatt_descriptor::kValueProperty);
    108     dict_entry_writer.OpenVariant("ay", &variant_writer);
    109     variant_writer.AppendArrayOfBytes(value.data(), value.size());
    110     dict_entry_writer.CloseContainer(&variant_writer);
    111     array_writer.CloseContainer(&dict_entry_writer);
    112     writer.CloseContainer(&array_writer);
    113 
    114     // invalidated_properties.
    115     writer.OpenArray("s", &array_writer);
    116     writer.CloseContainer(&array_writer);
    117 
    118     exported_object_->SendSignal(&signal);
    119   }
    120 
    121  private:
    122   // Returns true if the current thread is on the origin thread.
    123   bool OnOriginThread() {
    124     return base::PlatformThread::CurrentId() == origin_thread_id_;
    125   }
    126 
    127   // Called by dbus:: when the Bluetooth daemon fetches a single property of
    128   // the descriptor.
    129   void Get(dbus::MethodCall* method_call,
    130            dbus::ExportedObject::ResponseSender response_sender) {
    131     VLOG(2) << "BluetoothGattDescriptorServiceProvider::Get: "
    132             << object_path_.value();
    133     DCHECK(OnOriginThread());
    134 
    135     dbus::MessageReader reader(method_call);
    136 
    137     std::string interface_name;
    138     std::string property_name;
    139     if (!reader.PopString(&interface_name) ||
    140         !reader.PopString(&property_name) ||
    141         reader.HasMoreData()) {
    142       scoped_ptr<dbus::ErrorResponse> error_response =
    143           dbus::ErrorResponse::FromMethodCall(
    144               method_call, kErrorInvalidArgs, "Expected 'ss'.");
    145       response_sender.Run(error_response.PassAs<dbus::Response>());
    146       return;
    147     }
    148 
    149     // Only the GATT descriptor interface is supported.
    150     if (interface_name !=
    151         bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
    152       scoped_ptr<dbus::ErrorResponse> error_response =
    153           dbus::ErrorResponse::FromMethodCall(
    154               method_call, kErrorInvalidArgs,
    155               "No such interface: '" + interface_name + "'.");
    156       response_sender.Run(error_response.PassAs<dbus::Response>());
    157       return;
    158     }
    159 
    160     // If getting the "Value" property, obtain the value from the delegate.
    161     if (property_name == bluetooth_gatt_descriptor::kValueProperty) {
    162       DCHECK(delegate_);
    163       delegate_->GetDescriptorValue(
    164           base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnGet,
    165                      weak_ptr_factory_.GetWeakPtr(),
    166                      method_call, response_sender),
    167           base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
    168                      weak_ptr_factory_.GetWeakPtr(),
    169                      method_call, response_sender));
    170       return;
    171     }
    172 
    173     scoped_ptr<dbus::Response> response =
    174         dbus::Response::FromMethodCall(method_call);
    175     dbus::MessageWriter writer(response.get());
    176     dbus::MessageWriter variant_writer(NULL);
    177 
    178     // TODO(armansito): Process the "Permissions" property below.
    179     if (property_name == bluetooth_gatt_descriptor::kUUIDProperty) {
    180       writer.OpenVariant("s", &variant_writer);
    181       variant_writer.AppendString(uuid_);
    182       writer.CloseContainer(&variant_writer);
    183     } else if (property_name ==
    184                bluetooth_gatt_descriptor::kCharacteristicProperty) {
    185       writer.OpenVariant("o", &variant_writer);
    186       variant_writer.AppendObjectPath(characteristic_path_);
    187       writer.CloseContainer(&variant_writer);
    188     } else {
    189       response = dbus::ErrorResponse::FromMethodCall(
    190           method_call, kErrorInvalidArgs,
    191           "No such property: '" + property_name + "'.")
    192           .PassAs<dbus::Response>();
    193     }
    194 
    195     response_sender.Run(response.Pass());
    196   }
    197 
    198   // Called by dbus:: when the Bluetooth daemon sets a single property of the
    199   // descriptor.
    200   void Set(dbus::MethodCall* method_call,
    201            dbus::ExportedObject::ResponseSender response_sender) {
    202     VLOG(2) << "BluetoothGattDescriptorServiceProvider::Set: "
    203             << object_path_.value();
    204     DCHECK(OnOriginThread());
    205 
    206     dbus::MessageReader reader(method_call);
    207 
    208     std::string interface_name;
    209     std::string property_name;
    210     dbus::MessageReader variant_reader(NULL);
    211     if (!reader.PopString(&interface_name) ||
    212         !reader.PopString(&property_name) ||
    213         !reader.PopVariant(&variant_reader) ||
    214         reader.HasMoreData()) {
    215       scoped_ptr<dbus::ErrorResponse> error_response =
    216           dbus::ErrorResponse::FromMethodCall(
    217               method_call, kErrorInvalidArgs, "Expected 'ssv'.");
    218       response_sender.Run(error_response.PassAs<dbus::Response>());
    219       return;
    220     }
    221 
    222     // Only the GATT descriptor interface is allowed.
    223     if (interface_name !=
    224         bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
    225       scoped_ptr<dbus::ErrorResponse> error_response =
    226           dbus::ErrorResponse::FromMethodCall(
    227               method_call, kErrorInvalidArgs,
    228               "No such interface: '" + interface_name + "'.");
    229       response_sender.Run(error_response.PassAs<dbus::Response>());
    230       return;
    231     }
    232 
    233     // Only the "Value" property is writeable.
    234     if (property_name != bluetooth_gatt_descriptor::kValueProperty) {
    235       std::string error_name;
    236       std::string error_message;
    237       if (property_name == bluetooth_gatt_descriptor::kUUIDProperty ||
    238           property_name == bluetooth_gatt_descriptor::kCharacteristicProperty) {
    239         error_name = kErrorPropertyReadOnly;
    240         error_message = "Read-only property: '" + property_name + "'.";
    241       } else {
    242         error_name = kErrorInvalidArgs;
    243         error_message = "No such property: '" + property_name + "'.";
    244       }
    245       scoped_ptr<dbus::ErrorResponse> error_response =
    246           dbus::ErrorResponse::FromMethodCall(
    247               method_call, error_name, error_message);
    248       response_sender.Run(error_response.PassAs<dbus::Response>());
    249       return;
    250     }
    251 
    252     // Obtain the value.
    253     const uint8* bytes = NULL;
    254     size_t length = 0;
    255     if (!variant_reader.PopArrayOfBytes(&bytes, &length)) {
    256       scoped_ptr<dbus::ErrorResponse> error_response =
    257           dbus::ErrorResponse::FromMethodCall(
    258               method_call, kErrorInvalidArgs,
    259               "Property '" + property_name + "' has type 'ay'.");
    260       response_sender.Run(error_response.PassAs<dbus::Response>());
    261       return;
    262     }
    263 
    264     // Pass the set request onto the delegate.
    265     std::vector<uint8> value(bytes, bytes + length);
    266     DCHECK(delegate_);
    267     delegate_->SetDescriptorValue(
    268         value,
    269         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnSet,
    270                    weak_ptr_factory_.GetWeakPtr(),
    271                    method_call, response_sender),
    272         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
    273                    weak_ptr_factory_.GetWeakPtr(),
    274                    method_call, response_sender));
    275   }
    276 
    277   // Called by dbus:: when the Bluetooth daemon fetches all properties of the
    278   // descriptor.
    279   void GetAll(dbus::MethodCall* method_call,
    280               dbus::ExportedObject::ResponseSender response_sender) {
    281     VLOG(2) << "BluetoothGattDescriptorServiceProvider::GetAll: "
    282             << object_path_.value();
    283     DCHECK(OnOriginThread());
    284 
    285     dbus::MessageReader reader(method_call);
    286 
    287     std::string interface_name;
    288     if (!reader.PopString(&interface_name) || reader.HasMoreData()) {
    289       scoped_ptr<dbus::ErrorResponse> error_response =
    290           dbus::ErrorResponse::FromMethodCall(
    291               method_call, kErrorInvalidArgs, "Expected 's'.");
    292       response_sender.Run(error_response.PassAs<dbus::Response>());
    293       return;
    294     }
    295 
    296     // Only the GATT descriptor interface is supported.
    297     if (interface_name !=
    298         bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
    299       scoped_ptr<dbus::ErrorResponse> error_response =
    300           dbus::ErrorResponse::FromMethodCall(
    301               method_call, kErrorInvalidArgs,
    302               "No such interface: '" + interface_name + "'.");
    303       response_sender.Run(error_response.PassAs<dbus::Response>());
    304       return;
    305     }
    306 
    307     // Try to obtain the value from the delegate. We will construct the
    308     // response in the success callback.
    309     DCHECK(delegate_);
    310     delegate_->GetDescriptorValue(
    311         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnGetAll,
    312                    weak_ptr_factory_.GetWeakPtr(),
    313                    method_call, response_sender),
    314         base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
    315                    weak_ptr_factory_.GetWeakPtr(),
    316                    method_call, response_sender));
    317   }
    318 
    319   // Called by dbus:: when a method is exported.
    320   void OnExported(const std::string& interface_name,
    321                   const std::string& method_name,
    322                   bool success) {
    323     LOG_IF(WARNING, !success) << "Failed to export "
    324                               << interface_name << "." << method_name;
    325   }
    326 
    327   // Called by the Delegate in response to a method to call to get all
    328   // properties, in which the delegate has successfully returned the
    329   // descriptor value.
    330   void OnGetAll(dbus::MethodCall* method_call,
    331                 dbus::ExportedObject::ResponseSender response_sender,
    332                 const std::vector<uint8>& value) {
    333     VLOG(2) << "Descriptor value obtained from delegate. Responding to "
    334             << "GetAll.";
    335 
    336     scoped_ptr<dbus::Response> response =
    337         dbus::Response::FromMethodCall(method_call);
    338     dbus::MessageWriter writer(response.get());
    339     dbus::MessageWriter array_writer(NULL);
    340     dbus::MessageWriter dict_entry_writer(NULL);
    341     dbus::MessageWriter variant_writer(NULL);
    342 
    343     writer.OpenArray("{sv}", &array_writer);
    344 
    345     array_writer.OpenDictEntry(&dict_entry_writer);
    346     dict_entry_writer.AppendString(
    347         bluetooth_gatt_descriptor::kUUIDProperty);
    348     dict_entry_writer.AppendVariantOfString(uuid_);
    349     array_writer.CloseContainer(&dict_entry_writer);
    350 
    351     array_writer.OpenDictEntry(&dict_entry_writer);
    352     dict_entry_writer.AppendString(
    353         bluetooth_gatt_descriptor::kCharacteristicProperty);
    354     dict_entry_writer.AppendVariantOfObjectPath(characteristic_path_);
    355     array_writer.CloseContainer(&dict_entry_writer);
    356 
    357     array_writer.OpenDictEntry(&dict_entry_writer);
    358     dict_entry_writer.AppendString(
    359         bluetooth_gatt_descriptor::kValueProperty);
    360     dict_entry_writer.OpenVariant("ay", &variant_writer);
    361     variant_writer.AppendArrayOfBytes(value.data(), value.size());
    362     dict_entry_writer.CloseContainer(&variant_writer);
    363     array_writer.CloseContainer(&dict_entry_writer);
    364 
    365     // TODO(armansito): Process "Permissions" property.
    366 
    367     writer.CloseContainer(&array_writer);
    368 
    369     response_sender.Run(response.Pass());
    370   }
    371 
    372   // Called by the Delegate in response to a successful method call to get the
    373   // descriptor value.
    374   void OnGet(dbus::MethodCall* method_call,
    375              dbus::ExportedObject::ResponseSender response_sender,
    376              const std::vector<uint8>& value) {
    377     VLOG(2) << "Returning descriptor value obtained from delegate.";
    378     scoped_ptr<dbus::Response> response =
    379         dbus::Response::FromMethodCall(method_call);
    380     dbus::MessageWriter writer(response.get());
    381     dbus::MessageWriter variant_writer(NULL);
    382 
    383     writer.OpenVariant("ay", &variant_writer);
    384     variant_writer.AppendArrayOfBytes(value.data(), value.size());
    385     writer.CloseContainer(&variant_writer);
    386 
    387     response_sender.Run(response.Pass());
    388   }
    389 
    390   // Called by the Delegate in response to a successful method call to set the
    391   // descriptor value.
    392   void OnSet(dbus::MethodCall* method_call,
    393              dbus::ExportedObject::ResponseSender response_sender) {
    394     VLOG(2) << "Successfully set descriptor value. Return success.";
    395     response_sender.Run(dbus::Response::FromMethodCall(method_call));
    396   }
    397 
    398   // Called by the Delegate in response to a failed method call to get or set
    399   // the descriptor value.
    400   void OnFailure(dbus::MethodCall* method_call,
    401                  dbus::ExportedObject::ResponseSender response_sender) {
    402     VLOG(2) << "Failed to get/set descriptor value. Report error.";
    403     scoped_ptr<dbus::ErrorResponse> error_response =
    404         dbus::ErrorResponse::FromMethodCall(
    405             method_call, kErrorFailed,
    406             "Failed to get/set descriptor value.");
    407     response_sender.Run(error_response.PassAs<dbus::Response>());
    408   }
    409 
    410   // Origin thread (i.e. the UI thread in production).
    411   base::PlatformThreadId origin_thread_id_;
    412 
    413   // 128-bit descriptor UUID of this object.
    414   std::string uuid_;
    415 
    416   // D-Bus bus object is exported on, not owned by this object and must
    417   // outlive it.
    418   dbus::Bus* bus_;
    419 
    420   // Incoming methods to get and set the "Value" property are passed on to the
    421   // delegate and callbacks passed to generate a reply. |delegate_| is generally
    422   // the object that owns this one and must outlive it.
    423   Delegate* delegate_;
    424 
    425   // D-Bus object path of object we are exporting, kept so we can unregister
    426   // again in our destructor.
    427   dbus::ObjectPath object_path_;
    428 
    429   // Object path of the GATT characteristic that the exported descriptor belongs
    430   // to.
    431   dbus::ObjectPath characteristic_path_;
    432 
    433   // D-Bus object we are exporting, owned by this object.
    434   scoped_refptr<dbus::ExportedObject> exported_object_;
    435 
    436   // Weak pointer factory for generating 'this' pointers that might live longer
    437   // than we do.
    438   // Note: This should remain the last member so it'll be destroyed and
    439   // invalidate its weak pointers before any other members are destroyed.
    440   base::WeakPtrFactory<BluetoothGattDescriptorServiceProviderImpl>
    441       weak_ptr_factory_;
    442 
    443   DISALLOW_COPY_AND_ASSIGN(BluetoothGattDescriptorServiceProviderImpl);
    444 };
    445 
    446 BluetoothGattDescriptorServiceProvider::
    447     BluetoothGattDescriptorServiceProvider() {
    448 }
    449 
    450 BluetoothGattDescriptorServiceProvider::
    451     ~BluetoothGattDescriptorServiceProvider() {
    452 }
    453 
    454 // static
    455 BluetoothGattDescriptorServiceProvider*
    456 BluetoothGattDescriptorServiceProvider::Create(
    457     dbus::Bus* bus,
    458     const dbus::ObjectPath& object_path,
    459     Delegate* delegate,
    460     const std::string& uuid,
    461     const std::vector<std::string>& permissions,
    462     const dbus::ObjectPath& characteristic_path) {
    463   if (base::SysInfo::IsRunningOnChromeOS()) {
    464     return new BluetoothGattDescriptorServiceProviderImpl(
    465         bus, object_path, delegate, uuid, permissions, characteristic_path);
    466   }
    467   return new FakeBluetoothGattDescriptorServiceProvider(
    468       object_path, delegate, uuid, permissions, characteristic_path);
    469 }
    470 
    471 }  // namespace chromeos
    472