[Bluetooth][gatt] Add registerService method 82/239782/27
authorPawel Wasowski <p.wasowski2@samsung.com>
Wed, 12 Aug 2020 11:25:10 +0000 (13:25 +0200)
committerDawid Juszczak <d.juszczak@samsung.com>
Wed, 26 Aug 2020 11:08:00 +0000 (13:08 +0200)
https://code.sec.samsung.net/jira/browse/TWDAPI-263

[Description]
Added:
+ BluetoothGATTServer::RegisterService()
+ BluetoothGATTServer::services getter

[Verification]
tested on chrome console

Change-Id: I9588d6c613293d3c5f139263c0e8703de8ab02c3
Signed-off-by: Dawid Juszczak <d.juszczak@samsung.com>
Signed-off-by: Pawel Wasowski <p.wasowski2@samsung.com>
src/bluetooth/bluetooth.gyp
src/bluetooth/bluetooth_api.js
src/bluetooth/bluetooth_gatt_server.cc
src/bluetooth/bluetooth_gatt_server.h
src/bluetooth/bluetooth_gatt_server_service.cc [new file with mode: 0644]
src/bluetooth/bluetooth_gatt_server_service.h [new file with mode: 0644]
src/bluetooth/bluetooth_instance.cc
src/bluetooth/bluetooth_instance.h

index f99eb6b7cef70fa72ea703f2d244b2a4ace15901..560710d83d47ba7b7a735a1c7e0e3800c17c8087 100644 (file)
@@ -44,7 +44,9 @@
         'uuid.cc',
         'uuid.h',
         'bluetooth_gatt_server.cc',
-        'bluetooth_gatt_server.h'
+        'bluetooth_gatt_server.h',
+        'bluetooth_gatt_server_service.cc',
+        'bluetooth_gatt_server_service.h'
       ],
       'includes': [
         '../common/pkg-config.gypi',
index 09677975139779e9ce2047d0ef12c0383a165832..5cd600554649f7a9069d0df52f7a2fe3d543ee99 100755 (executable)
@@ -3219,20 +3219,83 @@ BluetoothAdapter.prototype.getBluetoothProfileHandler = function() {
 };
 
 // class BluetoothGATTServer ////////////////////////
+var _BluetoothGATTServerServices = [];
+
 var BluetoothGATTServer = function() {
-  var services_ = [];
-  Object.defineProperties(this, {
-    services: {
-      get: function() {
-        return services_;
-      },
-      set: function() {}
-    }
-  });
-}
+    Object.defineProperties(this, {
+        services: {
+            enumerable: true,
+            get: function() {
+                return _BluetoothGATTServerServices;
+            },
+            set: function() {}
+        }
+    });
+};
 
 var AbortError = new WebAPIException('AbortError', 'An unknown error occurred');
 
+var BluetoothGATTServer_valid_registerService_errors = [
+    'InvalidStateError',
+    'NotSupportedError',
+    'InvalidValuesError',
+    'AbortError'
+];
+var BluetoothGATTServer_valid_registerService_exceptions = [
+    'InvalidStateError',
+    'TypeMismatchError',
+    'SecurityError'
+];
+
+BluetoothGATTServer.prototype.registerService = function() {
+    var args = AV.validateArgs(arguments, [
+        {
+            name: 'service',
+            type: AV.Types.DICTIONARY
+        },
+        {
+            name: 'successCallback',
+            type: AV.Types.FUNCTION,
+            optional: true,
+            nullable: true
+        },
+        {
+            name: 'errorCallback',
+            type: AV.Types.FUNCTION,
+            optional: true,
+            nullable: true
+        }
+    ]);
+
+    var service = new BluetoothGATTServerService(args.service);
+
+    var callback = function(result) {
+        if (native.isFailure(result)) {
+            native.callIfPossible(
+                args.errorCallback,
+                native.getErrorObjectAndValidate(
+                    result,
+                    BluetoothGATTServer_valid_registerService_errors,
+                    AbortError
+                )
+            );
+        } else {
+            _BluetoothGATTServerServicesRegisteredInNativeLayer[service._id] = true;
+            _BluetoothGATTServerServices.push(service);
+            native.callIfPossible(args.successCallback);
+        }
+    };
+
+    var result = native.call('BluetoothGATTServerRegisterService', service, callback);
+    if (native.isFailure(result)) {
+        throw native.getErrorObjectAndValidate(
+            result,
+            BluetoothGATTServer_valid_registerService_exceptions,
+            AbortError
+        );
+    }
+};
+
 var BluetoothGATTServer_valid_start_errors = ['InvalidStateError', 'NotSupportedError', 'AbortError'];
 var BluetoothGATTServer_valid_start_exceptions = ['InvalidStateError', 'TypeMismatchError', 'SecurityError'];
 
index b2273112256dd88a87b3b83955154503ee1c5fd7..0d131a089c6fdfc38e09fafc5f2cc7bfe6b6e453 100644 (file)
@@ -27,10 +27,14 @@ using namespace common::tools;
 namespace extension {
 namespace bluetooth {
 
-BluetoothGATTServer::BluetoothGATTServer(const BluetoothInstance& instance)
-    : instance_{instance}, initialized_{false}, running_{false}, handle_{nullptr} {
+BluetoothGATTServer::BluetoothGATTServer(const BluetoothInstance& instance,
+                                         BluetoothGATTServerService& service)
+    : instance_{instance},
+      service_{service},
+      initialized_{false},
+      running_{false},
+      handle_{nullptr} {
   ScopeLogger();
-
   /*
    * TODO: register a callback, that deinitializes a server, unregisters its
    * services, destroys handle_ and sets running_ to false
@@ -129,6 +133,55 @@ void BluetoothGATTServer::GetConnectionMtu(const picojson::value& args,
   ReportSuccess(picojson::value{static_cast<double>(mtu)}, out);
 }
 
+void BluetoothGATTServer::RegisterService(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  bt_gatt_h service_handle = nullptr;
+
+  /*
+   * Each successfully created GATT{Service, Characteristic, Descriptor} has a
+   * corresponding entry in service_.gatt_objects, mapping its _id field of its JS
+   * object to its bt_gatt_h handle.
+   * new_gatt_objects is a container for the entries, that are added to
+   * service_.gatt_objects if both CreateService() and RegisterService()
+   * succeed.
+   * Otherwise, the service is not registered and the map is not updated.
+   */
+  std::vector<std::pair<int, bt_gatt_h>> new_gatt_objects;
+  auto result = service_.CreateService(args, &service_handle, new_gatt_objects);
+  if (result.IsError()) {
+    ReportError(result, &out);
+    return;
+  }
+
+  if (!initialized_) {
+    /*
+     * Server is initialized when its services are registered.
+     * However, the case when server is uninitialized until start is
+     * also valid. It happens, when user doesn't register any services
+     * and starts the server with the default ones.
+     */
+    auto result = InitializeAndCreateHandle();
+    if (!result) {
+      result.SetMessage("Couldn't register the service");
+      ReportError(result, &out);
+      return;
+    }
+  }
+
+  result = service_.RegisterService(service_handle, this->handle_, new_gatt_objects);
+  if (result.IsError()) {
+    ReportError(result, &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+bool BluetoothGATTServer::IsRunning() {
+  return running_;
+}
+
 PlatformResult BluetoothGATTServer::Initialize() {
   ScopeLogger();
 
index e28789c865a61fd1c63bacc93a52c6efdbfb7701..82185f4f099cfd631b917528b25c622a4af25d0b 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <bluetooth.h>
 
+#include "bluetooth/bluetooth_gatt_server_service.h"
 #include "common/picojson.h"
 #include "common/platform_result.h"
 
@@ -31,12 +32,14 @@ class BluetoothInstance;
 
 class BluetoothGATTServer {
  public:
-  BluetoothGATTServer(const BluetoothInstance&);
+  BluetoothGATTServer(const BluetoothInstance& instance, BluetoothGATTServerService& service);
   ~BluetoothGATTServer();
 
   void Start(picojson::object& out);
   void Stop(picojson::object& out);
   void GetConnectionMtu(const picojson::value& args, picojson::object& out);
+  void RegisterService(const picojson::value& args, picojson::object& out);
+  bool IsRunning();
 
   static bool DestroyService(int total, int index, bt_gatt_h handle, void* user_data);
   static bool DestroyCharacteristic(int total, int index, bt_gatt_h handle, void* user_data);
@@ -44,6 +47,7 @@ class BluetoothGATTServer {
 
  private:
   const BluetoothInstance& instance_;
+  BluetoothGATTServerService& service_;
   bool initialized_;
   bool running_;
   bt_gatt_server_h handle_;
diff --git a/src/bluetooth/bluetooth_gatt_server_service.cc b/src/bluetooth/bluetooth_gatt_server_service.cc
new file mode 100644 (file)
index 0000000..dcf0e6d
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <string>
+
+#include "bluetooth/bluetooth_gatt_server.h"
+#include "bluetooth/bluetooth_gatt_server_service.h"
+#include "bluetooth/bluetooth_util.h"
+#include "bluetooth/uuid.h"
+
+#include "common/logger.h"
+#include "common/platform_result.h"
+#include "common/tools.h"
+
+using namespace extension::bluetooth::util;
+using common::PlatformResult;
+using common::ErrorCode;
+
+namespace extension {
+namespace bluetooth {
+
+namespace {
+const std::string kUuid = "uuid";
+const std::string kServiceUuid = "serviceUuid";
+const std::string kIsPrimary = "isPrimary";
+const std::string kCharacteristics = "characteristics";
+
+const std::string kServices = "services";
+const std::string kDescriptors = "descriptors";
+const std::string kIsBroadcast = "isBroadcast";
+const std::string kHasExtendedProperties = "hasExtendedProperties";
+const std::string kIsNotify = "isNotify";
+const std::string kIsIndication = "isIndication";
+const std::string kIsReadable = "isReadable";
+const std::string kIsSignedWrite = "isSignedWrite";
+const std::string kIsWritable = "isWritable";
+const std::string kIsWriteNoResponse = "isWriteNoResponse";
+const std::string kReadPermission = "readPermission";
+const std::string kWritePermission = "writePermission";
+const std::string kEncryptedReadPermission = "encryptedReadPermission";
+const std::string kEncryptedWritePermission = "encryptedWritePermission";
+const std::string kEncryptedSignedReadPermission = "encryptedSignedReadPermission";
+const std::string kEncryptedSignedWritePermission = "encryptedSignedWritePermission";
+
+const std::string kId = "_id";
+
+int GetPermissionsInt(const picojson::value& permissions) {
+  ScopeLogger("permissions: %s", permissions.serialize().c_str());
+
+  int ret = 0;
+  if (permissions.get(kReadPermission).get<bool>()) {
+    ret |= BT_GATT_PERMISSION_READ;
+  }
+  if (permissions.get(kWritePermission).get<bool>()) {
+    ret |= BT_GATT_PERMISSION_WRITE;
+  }
+  if (permissions.get(kEncryptedReadPermission).get<bool>()) {
+    ret |= BT_GATT_PERMISSION_ENCRYPT_READ;
+  }
+  if (permissions.get(kEncryptedWritePermission).get<bool>()) {
+    ret |= BT_GATT_PERMISSION_ENCRYPT_WRITE;
+  }
+  if (permissions.get(kEncryptedSignedReadPermission).get<bool>()) {
+    ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ;
+  }
+  if (permissions.get(kEncryptedSignedWritePermission).get<bool>()) {
+    ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE;
+  }
+
+  LoggerD("Permissions: %x", static_cast<unsigned int>(ret));
+  return ret;
+}
+
+int GetPropertiesInt(const picojson::value& properties) {
+  ScopeLogger("properties: %s", properties.serialize().c_str());
+
+  int ret = 0;
+  if (properties.get(kIsBroadcast).get<bool>()) {
+    ret |= BT_GATT_PROPERTY_BROADCAST;
+  }
+  if (properties.get(kIsReadable).get<bool>()) {
+    ret |= BT_GATT_PROPERTY_READ;
+  }
+  if (properties.get(kIsWriteNoResponse).get<bool>()) {
+    ret |= BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE;
+  }
+  if (properties.get(kIsWritable).get<bool>()) {
+    ret |= BT_GATT_PROPERTY_WRITE;
+  }
+  if (properties.get(kIsNotify).get<bool>()) {
+    ret |= BT_GATT_PROPERTY_NOTIFY;
+  }
+  if (properties.get(kIsIndication).get<bool>()) {
+    ret |= BT_GATT_PROPERTY_INDICATE;
+  }
+  if (properties.get(kIsSignedWrite).get<bool>()) {
+    ret |= BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES;
+  }
+  if (properties.get(kHasExtendedProperties).get<bool>()) {
+    ret |= BT_GATT_PROPERTY_EXTENDED_PROPERTIES;
+  }
+
+  LoggerD("Properties: %x", static_cast<unsigned int>(ret));
+  return ret;
+}
+
+}  // namespace
+
+bool BluetoothGATTServerService::DestroyService(int total, int index, bt_gatt_h handle, void* user_data) {
+  ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
+
+  /*
+   * Undocumented behavior of native Bluetooth API:
+   * bt_gatt_service_destroy() destroys not only the service, but also all
+   * its components (included services, characteristics, descriptors)
+   * recursively.
+   */
+  auto ret = bt_gatt_service_destroy(handle);
+  if (BT_ERROR_NONE != ret) {
+    LoggerE("bt_gatt_service_destroy(): %d (%s)", ret, get_error_message(ret));
+  }
+  LoggerD("bt_gatt_service_destroy(): success");
+
+  return true;
+}
+
+bool BluetoothGATTServerService::DestroyCharacteristic(int total, int index, bt_gatt_h handle,
+                                                void* user_data) {
+  ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
+
+  auto ret = bt_gatt_characteristic_destroy(handle);
+  if (BT_ERROR_NONE != ret) {
+    LoggerE("bt_gatt_characteristic_destroy(): %d (%s)", ret, get_error_message(ret));
+  }
+  LoggerD("bt_gatt_characteristic_destroy(): success");
+
+  return true;
+}
+
+bool BluetoothGATTServerService::DestroyDescriptor(int total, int index, bt_gatt_h handle,
+                                            void* user_data) {
+  ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
+
+  auto ret = bt_gatt_descriptor_destroy(handle);
+  if (BT_ERROR_NONE != ret) {
+    LoggerE("bt_gatt_descriptor_destroy(): %d (%s)", ret, get_error_message(ret));
+  }
+  LoggerD("bt_gatt_descriptor_destroy(): success");
+
+  return true;
+}
+BluetoothGATTServerService::BluetoothGATTServerService() {
+  ScopeLogger();
+}
+
+BluetoothGATTServerService::~BluetoothGATTServerService() {
+  ScopeLogger();
+}
+
+common::PlatformResult BluetoothGATTServerService::AddDescriptors(
+    const picojson::array& descriptors_init, bt_gatt_h characteristic_handle,
+    std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
+  ScopeLogger("descriptors_init length: %zu", descriptors_init.size());
+
+  /*
+   * This function expects valid input.
+   * If it gets descriptors missing any: uuid, permission,
+   * or with one of these with a wrong type, the application will crash.
+   */
+
+  for (const auto& descriptor_init_data : descriptors_init) {
+    const auto& uuid_str = descriptor_init_data.get(kUuid).get<std::string>();
+    /*
+     * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
+     * form to assure, it will be accepted by the native API.
+     *
+     * We assume, UUID::create() returns a valid object, because the input is valid.
+     */
+    auto uuid = UUID::create(uuid_str);
+    int permissions = GetPermissionsInt(descriptor_init_data);
+    bt_gatt_h descriptor_handle = nullptr;
+
+    int ret = bt_gatt_descriptor_create(uuid->uuid_128_bit.c_str(), permissions, nullptr, 0,
+                                        &descriptor_handle);
+    if (BT_ERROR_NONE != ret) {
+      LoggerE("bt_gatt_descriptor_create() failed: %d (%s)", ret, get_error_message(ret));
+      return BluetoothErrorToPlatformResult(ret, "Failed to create a descriptor");
+    }
+    LoggerD("bt_gatt_descriptor_create(): success");
+
+    ret = bt_gatt_characteristic_add_descriptor(characteristic_handle, descriptor_handle);
+    if (BT_ERROR_NONE != ret) {
+      LoggerE("bt_gatt_characteristic_add_descriptor() failed: %d (%s)", ret,
+              get_error_message(ret));
+      DestroyDescriptor(0, 0, descriptor_handle, nullptr);
+      return BluetoothErrorToPlatformResult(ret, "Failed to add descriptor to characteristic");
+    }
+    LoggerD("bt_gatt_characteristic_add_descriptor(): success");
+
+    const auto _id = static_cast<int>(descriptor_init_data.get(kId).get<double>());
+    new_gatt_objects.push_back({_id, descriptor_handle});
+  }
+
+  return common::PlatformResult();
+}
+
+common::PlatformResult BluetoothGATTServerService::AddCharacteristics(
+    const picojson::array& characteristics_init, bt_gatt_h service_handle,
+    std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
+  ScopeLogger("characteristics_init length: %zu", characteristics_init.size());
+
+  /*
+   * This function expects valid input.
+   * If it gets characteristics missing any: uuid, permission, property,
+   * or with any of these with a wrong type, the application will crash.
+   */
+
+  for (const auto& characteristic_init_data : characteristics_init) {
+    const auto& uuid_str = characteristic_init_data.get(kUuid).get<std::string>();
+    /*
+     * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
+     * form to assure, it will be accepted by the native API.
+     *
+     * We assume, UUID::create() returns a valid object, because the input is valid.
+     */
+    auto uuid = UUID::create(uuid_str);
+
+    int permissions = GetPermissionsInt(characteristic_init_data);
+    int properties = GetPropertiesInt(characteristic_init_data);
+    bt_gatt_h characteristic_handle = nullptr;
+
+    int ret = bt_gatt_characteristic_create(uuid->uuid_128_bit.c_str(), permissions, properties,
+                                            nullptr, 0, &characteristic_handle);
+    if (BT_ERROR_NONE != ret) {
+      LoggerE("bt_gatt_characteristic_create() failed: %d (%s)", ret, get_error_message(ret));
+      return BluetoothErrorToPlatformResult(ret, "Failed to create a characteristic");
+    }
+    LoggerD("bt_gatt_characteristic_create(): success");
+
+    if (characteristic_init_data.get(kDescriptors).is<picojson::array>()) {
+      const auto& descriptors = characteristic_init_data.get(kDescriptors).get<picojson::array>();
+      auto result = AddDescriptors(descriptors, characteristic_handle, new_gatt_objects);
+      if (!result) {
+        DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
+        return result;
+      }
+    }
+
+    ret = bt_gatt_service_add_characteristic(service_handle, characteristic_handle);
+    if (BT_ERROR_NONE != ret) {
+      LoggerE("bt_gatt_service_add_characteristic() failed: %d (%s)", ret, get_error_message(ret));
+      DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
+      return BluetoothErrorToPlatformResult(ret, "Failed to add a characteristic to a service");
+    }
+    LoggerD("bt_gatt_service_add_characteristic(): success");
+
+    const auto _id = static_cast<int>(characteristic_init_data.get(kId).get<double>());
+    new_gatt_objects.push_back({_id, characteristic_handle});
+  }
+
+  return common::PlatformResult();
+}
+
+common::PlatformResult BluetoothGATTServerService::AddIncludedServices(
+    const picojson::array& included_services_init, bt_gatt_h parent_service_handle,
+    std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
+  ScopeLogger("included_services_init length: %zu", included_services_init.size());
+
+  /*
+   * This function expects valid input.
+   * If it gets included_services missing a uuid
+   * or with any of these with a wrong type, the application will crash.
+   */
+
+  for (const auto& service_init_data : included_services_init) {
+    bt_gatt_h included_service_handle = nullptr;
+    auto result = CreateService(service_init_data, &included_service_handle, new_gatt_objects);
+    if (!result) {
+      LoggerE("Failed to create included service");
+      return result;
+    }
+
+    int ret = bt_gatt_service_add_included_service(parent_service_handle, included_service_handle);
+    if (BT_ERROR_NONE != ret) {
+      LoggerE("bt_gatt_service_add_included_service() failed: %d (%s)", ret,
+              get_error_message(ret));
+      DestroyService(0, 0, included_service_handle, nullptr);
+      return BluetoothErrorToPlatformResult(ret, "Failed to add included service");
+    }
+    LoggerD("bt_gatt_service_add_included_service(): success");
+
+    const auto _id = static_cast<int>(service_init_data.get(kId).get<double>());
+    new_gatt_objects.push_back({_id, parent_service_handle});
+  }
+
+  return common::PlatformResult();
+}
+
+common::PlatformResult BluetoothGATTServerService::CreateService(
+    const picojson::value& service_init, bt_gatt_h* new_service_handle,
+    std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
+  ScopeLogger("service_init: %s", service_init.serialize().c_str());
+  /*
+   * This function expects valid input.
+   * If it gets service_init without any of the expected members or with a member of
+   * a wrong type, the application will crash.
+   */
+
+  const auto& uuid_str = service_init.get(kServiceUuid).get<std::string>();
+  /*
+   * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
+   * form to assure, it will be accepted by the native API.
+   *
+   * We assume, UUID::create() returns a valid object, because the input is valid.
+   */
+  auto uuid = UUID::create(uuid_str);
+  bool primary = service_init.get(kIsPrimary).get<bool>();
+  bt_gatt_service_type_e type =
+      primary ? BT_GATT_SERVICE_TYPE_PRIMARY : BT_GATT_SERVICE_TYPE_SECONDARY;
+  bt_gatt_h service_handle = nullptr;
+
+  int err = bt_gatt_service_create(uuid->uuid_128_bit.c_str(), type, &service_handle);
+  if (BT_ERROR_NONE != err) {
+    LoggerE("bt_gatt_service_create error: %d (%s)", err, get_error_message(err));
+    return BluetoothErrorToPlatformResult(err, "Failed to create GATT service");
+  }
+  LoggerD("bt_gatt_service_create(): success");
+
+  if (service_init.get(kServices).is<picojson::array>()) {
+    const auto& services = service_init.get(kServices).get<picojson::array>();
+    auto result = AddIncludedServices(services, service_handle, new_gatt_objects);
+    if (!result) {
+      DestroyService(0, 0, service_handle, nullptr);
+      return result;
+    }
+  }
+
+  if (service_init.get(kCharacteristics).is<picojson::array>()) {
+    const auto& characteristics = service_init.get(kCharacteristics).get<picojson::array>();
+    auto result = AddCharacteristics(characteristics, service_handle, new_gatt_objects);
+    if (!result) {
+      DestroyService(0, 0, service_handle, nullptr);
+      return result;
+    }
+  }
+
+  const auto _id = static_cast<int>(service_init.get(kId).get<double>());
+  new_gatt_objects.push_back({_id, service_handle});
+
+  *new_service_handle = service_handle;
+
+  return common::PlatformResult();
+}
+
+common::PlatformResult BluetoothGATTServerService::RegisterService(
+    bt_gatt_h service_handle, bt_gatt_server_h server,
+    const std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
+  ScopeLogger();
+
+  int ret = bt_gatt_server_register_service(server, service_handle);
+  if (BT_ERROR_NONE != ret) {
+    LoggerE("bt_gatt_server_register_service() failed: %d (%s)", ret, get_error_message(ret));
+    return BluetoothErrorToPlatformResult(ret, "Failed to register GATT service");
+  }
+
+  gatt_objects_.insert(new_gatt_objects.begin(), new_gatt_objects.end());
+
+  return common::PlatformResult();
+}
+
+
+common::PlatformResult BluetoothGATTServerService::UnregisterService(const picojson::value& args, bt_gatt_server_h server) {
+  ScopeLogger();
+
+  auto _id = static_cast<int>(args.get(kId).get<double>());
+  LoggerD("Unregistering service with _id: %d", _id);
+
+  auto service_handle = gatt_objects_[_id];
+
+  auto ret = bt_gatt_server_unregister_service(server, service_handle);
+  if (BT_ERROR_NONE != ret) {
+    LoggerE("bt_gatt_server_unregister_service() failed: %d (%s)", ret, get_error_message(ret));
+    return BluetoothErrorToPlatformResult(ret, "Failed to unregister GATT service");
+  }
+  LoggerD("bt_gatt_server_unregister_service(): SUCCESS");
+
+  gatt_objects_.erase(_id);
+  return common::PlatformResult{};
+
+}
+
+}  // namespace bluetooth
+}  // namespace extension
diff --git a/src/bluetooth/bluetooth_gatt_server_service.h b/src/bluetooth/bluetooth_gatt_server_service.h
new file mode 100644 (file)
index 0000000..cecd9d2
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_GATT_SERVER_SERVICE_H_
+#define BLUETOOTH_BLUETOOTH_GATT_SERVER_SERVICE_H_
+
+#include <map>
+#include <vector>
+
+#include <bluetooth.h>
+
+#include "common/platform_result.h"
+
+using common::PlatformResult;
+
+namespace extension {
+
+namespace bluetooth {
+
+class BluetoothInstance;
+
+class BluetoothGATTServerService {
+ public:
+  BluetoothGATTServerService();
+  ~BluetoothGATTServerService();
+
+  PlatformResult CreateService(const picojson::value& args, bt_gatt_h* new_service_handle,
+                               std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects);
+  PlatformResult RegisterService(bt_gatt_h service_handle, bt_gatt_server_h server,
+                                 const std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects);
+  PlatformResult UnregisterService(const picojson::value& args, bt_gatt_server_h server);
+
+ private:
+  std::map<int, bt_gatt_h> gatt_objects_;
+
+  static bool DestroyService(int total, int index, bt_gatt_h handle, void* user_data);
+  static bool DestroyCharacteristic(int total, int index, bt_gatt_h handle, void* user_data);
+  static bool DestroyDescriptor(int total, int index, bt_gatt_h handle, void* user_data);
+
+  PlatformResult AddDescriptors(const picojson::array& descriptors, bt_gatt_h characteristic_handle,
+                                std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects);
+  PlatformResult AddCharacteristics(const picojson::array& characteristics,
+                                    bt_gatt_h service_handle,
+                                    std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects);
+  PlatformResult AddIncludedServices(const picojson::array& included_services,
+                                     bt_gatt_h parent_service_handle,
+                                     std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects);
+};
+
+}  // bluetooth
+}  // extension
+
+#endif  // BLUETOOTH_BLUETOOTH_GATT_SERVER_SERVICE_H_
index 2e72a9c3e30dc46269db202d77566909f113d082..a7575ea7531f90f0ee46eef263539916abe223c7 100644 (file)
@@ -37,8 +37,9 @@ BluetoothInstance::BluetoothInstance()
       bluetooth_le_adapter_(*this),
       bluetooth_gatt_client_service_(*this),
       bluetooth_le_device_(*this, bluetooth_gatt_client_service_),
+      bluetooth_gatt_server_service_(),
       worker(),
-      bluetooth_gatt_server_(*this) {
+      bluetooth_gatt_server_(*this, bluetooth_gatt_server_service_) {
   ScopeLogger();
   using std::placeholders::_1;
   using std::placeholders::_2;
@@ -103,6 +104,7 @@ BluetoothInstance::BluetoothInstance()
   REGISTER_METHOD(BluetoothGATTServerStart);
   REGISTER_METHOD(BluetoothGATTServerStop);
   REGISTER_METHOD(BluetoothGATTServerGetConnectionMtu);
+  REGISTER_METHOD(BluetoothGATTServerRegisterService);
 
 #undef REGISTER_METHOD
 }
@@ -500,5 +502,23 @@ void BluetoothInstance::BluetoothGATTServerGetConnectionMtu(const picojson::valu
   ReportSuccess(out);
 }
 
+void BluetoothInstance::BluetoothGATTServerRegisterService(const picojson::value& args,
+                                                           picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out);
+
+  worker.add_job([this, args] {
+    ScopeLogger("Async call: BluetoothGATTServerRegisterService");
+    picojson::value response = picojson::value(picojson::object());
+    picojson::object& async_out = response.get<picojson::object>();
+    double callback_id = args.get("callbackId").get<double>();
+    async_out["callbackId"] = picojson::value(callback_id);
+    this->bluetooth_gatt_server_.RegisterService(args, async_out);
+    this->PostMessage(response.serialize().c_str());
+  });
+
+  ReportSuccess(out);
+}
+
 }  // namespace bluetooth
 }  // namespace extension
index 58f9b7c0cd90f53dbca6c94e56310c485b8eeb2c..ed122272e818bcc83ab5f54f4dbf2b6d9be7cfc3 100644 (file)
@@ -23,6 +23,7 @@
 #include "bluetooth/bluetooth_device.h"
 #include "bluetooth/bluetooth_gatt_server.h"
 #include "bluetooth/bluetooth_gatt_client_service.h"
+#include "bluetooth/bluetooth_gatt_server_service.h"
 #include "bluetooth/bluetooth_health_application.h"
 #include "bluetooth/bluetooth_health_channel.h"
 #include "bluetooth/bluetooth_health_profile_handler.h"
@@ -111,6 +112,7 @@ class BluetoothInstance : public common::ParsedInstance {
   void BluetoothGATTServerStart(const picojson::value& args, picojson::object& out);
   void BluetoothGATTServerStop(const picojson::value& args, picojson::object& out);
   void BluetoothGATTServerGetConnectionMtu(const picojson::value& args, picojson::object& out);
+  void BluetoothGATTServerRegisterService(const picojson::value& args, picojson::object& out);
 
   BluetoothAdapter bluetooth_adapter_;
   BluetoothDevice bluetooth_device_;
@@ -122,6 +124,7 @@ class BluetoothInstance : public common::ParsedInstance {
   BluetoothLEAdapter bluetooth_le_adapter_;
   BluetoothGATTClientService bluetooth_gatt_client_service_;
   BluetoothLEDevice bluetooth_le_device_;
+  BluetoothGATTServerService bluetooth_gatt_server_service_;
   common::Worker worker;
   // If all operations on bluetooth_gatt_server_ will be done by the worker,
   // no mutex to prevent concurrent access of this object is needed