Home | History | Annotate | Download | only in service
      1 //
      2 //  Copyright 2015 Google, Inc.
      3 //
      4 //  Licensed under the Apache License, Version 2.0 (the "License");
      5 //  you may not use this file except in compliance with the License.
      6 //  You may obtain a copy of the License at:
      7 //
      8 //  http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 //  Unless required by applicable law or agreed to in writing, software
     11 //  distributed under the License is distributed on an "AS IS" BASIS,
     12 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 //  See the License for the specific language governing permissions and
     14 //  limitations under the License.
     15 //
     16 
     17 #include "service/gatt_server.h"
     18 
     19 #include <base/logging.h>
     20 
     21 #include "service/logging_helpers.h"
     22 #include "stack/include/bt_types.h"
     23 
     24 using std::lock_guard;
     25 using std::mutex;
     26 
     27 namespace bluetooth {
     28 
     29 // GattServer implementation
     30 // ========================================================
     31 
     32 GattServer::GattServer(const Uuid& uuid, int server_id)
     33     : app_identifier_(uuid), server_id_(server_id), delegate_(nullptr) {}
     34 
     35 GattServer::~GattServer() {
     36   // Automatically unregister the server.
     37   VLOG(1) << "GattServer unregistering: " << server_id_;
     38 
     39   // Unregister as observer so we no longer receive any callbacks.
     40   hal::BluetoothGattInterface::Get()->RemoveServerObserver(this);
     41 
     42   // Unregister this server, stop all services, and ignore the result.
     43   // TODO(armansito): stop and remove all services here? unregister_server
     44   // should really take care of that.
     45   hal::BluetoothGattInterface::Get()
     46       ->GetServerHALInterface()
     47       ->unregister_server(server_id_);
     48 }
     49 
     50 void GattServer::SetDelegate(Delegate* delegate) {
     51   lock_guard<mutex> lock(mutex_);
     52   delegate_ = delegate;
     53 }
     54 
     55 const Uuid& GattServer::GetAppIdentifier() const { return app_identifier_; }
     56 
     57 int GattServer::GetInstanceId() const { return server_id_; }
     58 
     59 bool GattServer::AddService(const bluetooth::Service& service,
     60                             const ResultCallback& callback) {
     61   VLOG(1) << __func__ << " server_id: " << server_id_;
     62   lock_guard<mutex> lock(mutex_);
     63 
     64   if (!callback) {
     65     LOG(ERROR) << "|callback| cannot be NULL";
     66     return false;
     67   }
     68 
     69   std::vector<btgatt_db_element_t> svc;
     70 
     71   svc.push_back({.type = (service.primary() ? BTGATT_DB_PRIMARY_SERVICE
     72                                             : BTGATT_DB_SECONDARY_SERVICE),
     73                  .uuid = service.uuid()});
     74 
     75   for (const auto& characteristic : service.characteristics()) {
     76     svc.push_back({.type = BTGATT_DB_CHARACTERISTIC,
     77                    .uuid = characteristic.uuid(),
     78                    .properties = characteristic.properties(),
     79                    .permissions = characteristic.permissions()});
     80     for (const auto& descriptor : characteristic.descriptors())
     81       svc.push_back({.type = BTGATT_DB_DESCRIPTOR,
     82                      .uuid = descriptor.uuid(),
     83                      .permissions = descriptor.permissions()});
     84   }
     85 
     86   for (const auto& incl_svc : service.included_services())
     87     svc.push_back({.type = BTGATT_DB_INCLUDED_SERVICE,
     88                    .attribute_handle = incl_svc.handle()});
     89 
     90   pending_end_decl_cb_ = callback;
     91 
     92   bt_status_t status =
     93       hal::BluetoothGattInterface::Get()->GetServerHALInterface()->add_service(
     94           server_id_, svc);
     95   if (status != BT_STATUS_SUCCESS) {
     96     LOG(ERROR) << "Failed to initiate call to populate GATT service";
     97     CleanUpPendingData();
     98     return false;
     99   }
    100 
    101   return true;
    102 }
    103 
    104 bool GattServer::SendResponse(const std::string& device_address, int request_id,
    105                               GATTError error, int offset,
    106                               const std::vector<uint8_t>& value) {
    107   VLOG(1) << __func__ << " - server_id: " << server_id_
    108           << " device_address: " << device_address
    109           << " request_id: " << request_id << " error: " << error
    110           << " offset: " << offset;
    111   lock_guard<mutex> lock(mutex_);
    112 
    113   RawAddress addr;
    114   if (!RawAddress::FromString(device_address, addr)) {
    115     LOG(ERROR) << "Invalid device address given: " << device_address;
    116     return false;
    117   }
    118 
    119   if (value.size() + offset > BTGATT_MAX_ATTR_LEN) {
    120     LOG(ERROR) << "Value is too large";
    121     return false;
    122   }
    123 
    124   // Find the correct connection ID for |device_address| and |request_id|.
    125   auto iter = conn_addr_map_.find(device_address);
    126   if (iter == conn_addr_map_.end()) {
    127     LOG(ERROR) << "No known connections for device address: " << device_address;
    128     return false;
    129   }
    130 
    131   std::shared_ptr<Connection> connection;
    132   for (const auto& tmp : iter->second) {
    133     if (tmp->request_id_to_handle.find(request_id) ==
    134         tmp->request_id_to_handle.end())
    135       continue;
    136 
    137     connection = tmp;
    138   }
    139 
    140   if (!connection) {
    141     LOG(ERROR) << "Pending request with ID " << request_id
    142                << " not found for device with BD_ADDR: " << device_address;
    143     return false;
    144   }
    145 
    146   btgatt_response_t response;
    147   memset(&response, 0, sizeof(response));
    148 
    149   // We keep -1 as the handle for "Execute Write Request". In that case,
    150   // there is no need to populate the response data. Just send zeros back.
    151   int handle = connection->request_id_to_handle[request_id];
    152   response.handle = handle;
    153   response.attr_value.handle = handle;
    154   if (handle != -1) {
    155     memcpy(response.attr_value.value, value.data(), value.size());
    156     response.attr_value.offset = offset;
    157     response.attr_value.len = value.size();
    158   }
    159 
    160   bt_status_t result =
    161       hal::BluetoothGattInterface::Get()
    162           ->GetServerHALInterface()
    163           ->send_response(connection->conn_id, request_id, error, response);
    164   if (result != BT_STATUS_SUCCESS) {
    165     LOG(ERROR) << "Failed to initiate call to send GATT response";
    166     return false;
    167   }
    168 
    169   connection->request_id_to_handle.erase(request_id);
    170 
    171   return true;
    172 }
    173 
    174 bool GattServer::SendNotification(const std::string& device_address,
    175                                   const uint16_t handle, bool confirm,
    176                                   const std::vector<uint8_t>& value,
    177                                   const GattCallback& callback) {
    178   VLOG(1) << " - server_id: " << server_id_
    179           << " device_address: " << device_address << " confirm: " << confirm;
    180   lock_guard<mutex> lock(mutex_);
    181 
    182   RawAddress addr;
    183   if (!RawAddress::FromString(device_address, addr)) {
    184     LOG(ERROR) << "Invalid device address given: " << device_address;
    185     return false;
    186   }
    187 
    188   // Get the connection IDs for which we will send this notification.
    189   auto conn_iter = conn_addr_map_.find(device_address);
    190   if (conn_iter == conn_addr_map_.end()) {
    191     LOG(ERROR) << "No known connections for device with address: "
    192                << device_address;
    193     return false;
    194   }
    195 
    196   std::shared_ptr<PendingIndication> pending_ind(
    197       new PendingIndication(callback));
    198 
    199   // Send the notification/indication on all matching connections.
    200   int send_count = 0;
    201   for (const auto& conn : conn_iter->second) {
    202     // Make sure that one isn't already pending for this connection.
    203     if (pending_indications_.find(conn->conn_id) !=
    204         pending_indications_.end()) {
    205       VLOG(1) << "A" << (confirm ? "n indication" : " notification")
    206               << " is already pending for connection: " << conn->conn_id;
    207       continue;
    208     }
    209 
    210     // The HAL API takes char* rather const char* for |value|, so we have to
    211     // cast away the const.
    212     // TODO(armansito): Make HAL accept const char*.
    213     bt_status_t status = hal::BluetoothGattInterface::Get()
    214                              ->GetServerHALInterface()
    215                              ->send_indication(server_id_, handle,
    216                                                conn->conn_id, confirm, value);
    217 
    218     // Increment the send count if this was successful. We don't immediately
    219     // fail if the HAL returned an error. It's better to report success as long
    220     // as we sent out at least one notification to this device as
    221     // multi-transport GATT connections from the same BD_ADDR will be rare
    222     // enough already.
    223     if (status != BT_STATUS_SUCCESS) continue;
    224 
    225     send_count++;
    226     pending_indications_[conn->conn_id] = pending_ind;
    227   }
    228 
    229   if (send_count == 0) {
    230     LOG(ERROR) << "Failed to send notifications/indications to device: "
    231                << device_address;
    232     return false;
    233   }
    234 
    235   return true;
    236 }
    237 
    238 void GattServer::ConnectionCallback(
    239     hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int server_id,
    240     int connected, const RawAddress& bda) {
    241   lock_guard<mutex> lock(mutex_);
    242 
    243   if (server_id != server_id_) return;
    244 
    245   std::string device_address = BtAddrString(&bda);
    246 
    247   VLOG(1) << __func__ << " conn_id: " << conn_id << " connected: " << connected
    248           << " BD_ADDR: " << device_address;
    249 
    250   if (!connected) {
    251     // Erase the entry if we were connected to it.
    252     VLOG(1) << "No longer connected: " << device_address;
    253     conn_id_map_.erase(conn_id);
    254     auto iter = conn_addr_map_.find(device_address);
    255     if (iter == conn_addr_map_.end()) return;
    256 
    257     // Remove the appropriate connection objects in the address.
    258     for (auto conn_iter = iter->second.begin(); conn_iter != iter->second.end();
    259          ++conn_iter) {
    260       if ((*conn_iter)->conn_id != conn_id) continue;
    261 
    262       iter->second.erase(conn_iter);
    263       break;
    264     }
    265 
    266     if (delegate_)
    267       delegate_->OnConnectionStateChanged(this, device_address, false);
    268 
    269     return;
    270   }
    271 
    272   if (conn_id_map_.find(conn_id) != conn_id_map_.end()) {
    273     LOG(WARNING) << "Connection entry already exists; "
    274                  << "ignoring ConnectionCallback";
    275     return;
    276   }
    277 
    278   LOG(INFO) << "Added connection entry for conn_id: " << conn_id
    279             << " device address: " << device_address;
    280   std::shared_ptr<Connection> connection(new Connection(conn_id, bda));
    281   conn_id_map_[conn_id] = connection;
    282   conn_addr_map_[device_address].push_back(connection);
    283 
    284   if (delegate_)
    285     delegate_->OnConnectionStateChanged(this, device_address, true);
    286 }
    287 
    288 void GattServer::ServiceAddedCallback(hal::BluetoothGattInterface* gatt_iface,
    289                                       int status, int server_id,
    290                                       std::vector<btgatt_db_element_t> svc) {
    291   lock_guard<mutex> lock(mutex_);
    292 
    293   if (server_id != server_id_) return;
    294 
    295   VLOG(1) << __func__ << " - status: " << status << " server_id: " << server_id
    296           << " first handle: " << svc[0].attribute_handle
    297           << " service Uuid: " << Uuid(svc[0].uuid).ToString()
    298           << " count: " << svc.size();
    299 
    300   Service service(svc[0].attribute_handle, true, Uuid(svc[0].uuid), {}, {});
    301 
    302   for (size_t i = 1; i < svc.size(); i++) {
    303     const btgatt_db_element_t& curr = svc[i];
    304     VLOG(1) << " - processing item no: " << i
    305             << " handle: " << curr.attribute_handle;
    306     if (curr.type == BTGATT_DB_CHARACTERISTIC) {
    307       service.characteristics().push_back({curr.attribute_handle,
    308                                            Uuid(curr.uuid),
    309                                            curr.properties,
    310                                            curr.permissions,
    311                                            {}});
    312     } else if (curr.type == BTGATT_DB_DESCRIPTOR) {
    313       service.characteristics().back().descriptors().push_back(
    314           {curr.attribute_handle, Uuid(curr.uuid), curr.permissions});
    315     } else if (svc[i].type == BTGATT_DB_INCLUDED_SERVICE) {
    316     }
    317   }
    318 
    319   pending_end_decl_cb_((bluetooth::BLEStatus)status, service);
    320 
    321   CleanUpPendingData();
    322 }
    323 
    324 void GattServer::ServiceStoppedCallback(
    325     hal::BluetoothGattInterface* /* gatt_iface */, int /* status */,
    326     int /* server_id */, int /* service_handle */) {
    327   // TODO(armansito): Support stopping a service.
    328 }
    329 
    330 void GattServer::RequestReadCharacteristicCallback(
    331     hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
    332     const RawAddress& bda, int attribute_handle, int offset, bool is_long) {
    333   lock_guard<mutex> lock(mutex_);
    334 
    335   // Check to see if we know about this connection. Otherwise ignore the
    336   // request.
    337   auto conn = GetConnection(conn_id, bda, trans_id);
    338   if (!conn) return;
    339 
    340   std::string device_address = BtAddrString(&bda);
    341 
    342   VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
    343           << " BD_ADDR: " << device_address
    344           << " attribute_handle: " << attribute_handle << " offset: " << offset
    345           << " is_long: " << is_long;
    346 
    347   conn->request_id_to_handle[trans_id] = attribute_handle;
    348 
    349   // If there is no delegate then there is nobody to handle request. The request
    350   // will eventually timeout and we should get a connection update that
    351   // terminates the connection.
    352   if (!delegate_) {
    353     // TODO(armansito): Require a delegate at server registration so that this
    354     // is never possible.
    355     LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
    356                  << "will time out.";
    357     return;
    358   }
    359 
    360   delegate_->OnCharacteristicReadRequest(this, device_address, trans_id, offset,
    361                                          is_long, attribute_handle);
    362 }
    363 void GattServer::RequestReadDescriptorCallback(
    364     hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
    365     const RawAddress& bda, int attribute_handle, int offset, bool is_long) {
    366   lock_guard<mutex> lock(mutex_);
    367 
    368   // Check to see if we know about this connection. Otherwise ignore the
    369   // request.
    370   auto conn = GetConnection(conn_id, bda, trans_id);
    371   if (!conn) return;
    372 
    373   std::string device_address = BtAddrString(&bda);
    374 
    375   VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
    376           << " BD_ADDR: " << device_address
    377           << " attribute_handle: " << attribute_handle << " offset: " << offset
    378           << " is_long: " << is_long;
    379 
    380   conn->request_id_to_handle[trans_id] = attribute_handle;
    381 
    382   // If there is no delegate then there is nobody to handle request. The request
    383   // will eventually timeout and we should get a connection update that
    384   // terminates the connection.
    385   if (!delegate_) {
    386     // TODO(armansito): Require a delegate at server registration so that this
    387     // is never possible.
    388     LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
    389                  << "will time out.";
    390     return;
    391   }
    392 
    393   delegate_->OnDescriptorReadRequest(this, device_address, trans_id, offset,
    394                                      is_long, attribute_handle);
    395 }
    396 
    397 void GattServer::RequestWriteCharacteristicCallback(
    398     hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
    399     const RawAddress& bda, int attr_handle, int offset, bool need_rsp,
    400     bool is_prep, std::vector<uint8_t> value) {
    401   lock_guard<mutex> lock(mutex_);
    402 
    403   // Check to see if we know about this connection. Otherwise ignore the
    404   // request.
    405   auto conn = GetConnection(conn_id, bda, trans_id);
    406   if (!conn) return;
    407 
    408   std::string device_address = BtAddrString(&bda);
    409 
    410   VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
    411           << " BD_ADDR: " << device_address << " attr_handle: " << attr_handle
    412           << " offset: " << offset << " length: " << value.size()
    413           << " need_rsp: " << need_rsp << " is_prep: " << is_prep;
    414 
    415   // Store the request ID only if this is not a write-without-response. If
    416   // another request occurs after this with the same request ID, then we'll
    417   // simply process it normally, though that shouldn't ever happen.
    418   if (need_rsp) conn->request_id_to_handle[trans_id] = attr_handle;
    419 
    420   // If there is no delegate then there is nobody to handle request. The request
    421   // will eventually timeout and we should get a connection update that
    422   // terminates the connection.
    423   if (!delegate_) {
    424     // TODO(armansito): Require a delegate at server registration so that this
    425     // is never possible.
    426     LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
    427                  << "will time out.";
    428     return;
    429   }
    430 
    431   delegate_->OnCharacteristicWriteRequest(this, device_address, trans_id,
    432                                           offset, is_prep, need_rsp,
    433                                           std::move(value), attr_handle);
    434 }
    435 
    436 void GattServer::RequestWriteDescriptorCallback(
    437     hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
    438     const RawAddress& bda, int attr_handle, int offset, bool need_rsp,
    439     bool is_prep, std::vector<uint8_t> value) {
    440   lock_guard<mutex> lock(mutex_);
    441 
    442   // Check to see if we know about this connection. Otherwise ignore the
    443   // request.
    444   auto conn = GetConnection(conn_id, bda, trans_id);
    445   if (!conn) return;
    446 
    447   std::string device_address = BtAddrString(&bda);
    448 
    449   VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
    450           << " BD_ADDR: " << device_address << " attr_handle: " << attr_handle
    451           << " offset: " << offset << " length: " << value.size()
    452           << " need_rsp: " << need_rsp << " is_prep: " << is_prep;
    453 
    454   // Store the request ID only if this is not a write-without-response. If
    455   // another request occurs after this with the same request ID, then we'll
    456   // simply process it normally, though that shouldn't ever happen.
    457   if (need_rsp) conn->request_id_to_handle[trans_id] = attr_handle;
    458 
    459   // If there is no delegate then there is nobody to handle request. The request
    460   // will eventually timeout and we should get a connection update that
    461   // terminates the connection.
    462   if (!delegate_) {
    463     // TODO(armansito): Require a delegate at server registration so that this
    464     // is never possible.
    465     LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
    466                  << "will time out.";
    467     return;
    468   }
    469 
    470   delegate_->OnDescriptorWriteRequest(this, device_address, trans_id, offset,
    471                                       is_prep, need_rsp, std::move(value),
    472                                       attr_handle);
    473 }
    474 
    475 void GattServer::RequestExecWriteCallback(
    476     hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
    477     const RawAddress& bda, int exec_write) {
    478   lock_guard<mutex> lock(mutex_);
    479 
    480   // Check to see if we know about this connection. Otherwise ignore the
    481   // request.
    482   auto conn = GetConnection(conn_id, bda, trans_id);
    483   if (!conn) return;
    484 
    485   std::string device_address = BtAddrString(&bda);
    486 
    487   VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
    488           << " BD_ADDR: " << device_address << " exec_write: " << exec_write;
    489 
    490   // Just store a dummy invalid handle as this request doesn't apply to a
    491   // specific handle.
    492   conn->request_id_to_handle[trans_id] = -1;
    493 
    494   // If there is no delegate then there is nobody to handle request. The request
    495   // will eventually timeout and we should get a connection update that
    496   // terminates the connection.
    497   if (!delegate_) {
    498     // TODO(armansito): Require a delegate at server registration so that this
    499     // is never possible.
    500     LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
    501                  << "will time out.";
    502     return;
    503   }
    504 
    505   delegate_->OnExecuteWriteRequest(this, device_address, trans_id, exec_write);
    506 }
    507 
    508 void GattServer::IndicationSentCallback(
    509     hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int status) {
    510   VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status;
    511   lock_guard<mutex> lock(mutex_);
    512 
    513   const auto& pending_ind_iter = pending_indications_.find(conn_id);
    514   if (pending_ind_iter == pending_indications_.end()) {
    515     VLOG(1) << "Unknown connection: " << conn_id;
    516     return;
    517   }
    518 
    519   std::shared_ptr<PendingIndication> pending_ind = pending_ind_iter->second;
    520   pending_indications_.erase(pending_ind_iter);
    521 
    522   if (status == BT_STATUS_SUCCESS) pending_ind->has_success = true;
    523 
    524   // Invoke it if this was the last reference to the confirmation callback.
    525   if (pending_ind.unique() && pending_ind->callback) {
    526     pending_ind->callback(pending_ind->has_success
    527                               ? GATT_ERROR_NONE
    528                               : static_cast<GATTError>(status));
    529   }
    530 }
    531 
    532 void GattServer::CleanUpPendingData() {
    533   pending_end_decl_cb_ = ResultCallback();
    534 }
    535 
    536 std::shared_ptr<GattServer::Connection> GattServer::GetConnection(
    537     int conn_id, const RawAddress& bda, int request_id) {
    538   auto iter = conn_id_map_.find(conn_id);
    539   if (iter == conn_id_map_.end()) {
    540     VLOG(1) << "Connection doesn't belong to this server";
    541     return nullptr;
    542   }
    543 
    544   auto conn = iter->second;
    545   if (conn->bdaddr != bda) {
    546     LOG(WARNING) << "BD_ADDR: " << BtAddrString(&bda) << " doesn't match "
    547                  << "connection ID: " << conn_id;
    548     return nullptr;
    549   }
    550 
    551   if (conn->request_id_to_handle.find(request_id) !=
    552       conn->request_id_to_handle.end()) {
    553     VLOG(1) << "Request with ID: " << request_id << " already exists for "
    554             << " connection: " << conn_id;
    555     return nullptr;
    556   }
    557 
    558   return conn;
    559 }
    560 
    561 // GattServerFactory implementation
    562 // ========================================================
    563 
    564 GattServerFactory::GattServerFactory() {
    565   hal::BluetoothGattInterface::Get()->AddServerObserver(this);
    566 }
    567 
    568 GattServerFactory::~GattServerFactory() {
    569   hal::BluetoothGattInterface::Get()->RemoveServerObserver(this);
    570 }
    571 
    572 bool GattServerFactory::RegisterInstance(const Uuid& uuid,
    573                                          const RegisterCallback& callback) {
    574   VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
    575   lock_guard<mutex> lock(pending_calls_lock_);
    576 
    577   if (pending_calls_.find(uuid) != pending_calls_.end()) {
    578     LOG(ERROR) << "GATT-server client with given Uuid already being registered "
    579                << " - Uuid: " << uuid.ToString();
    580     return false;
    581   }
    582 
    583   const btgatt_server_interface_t* hal_iface =
    584       hal::BluetoothGattInterface::Get()->GetServerHALInterface();
    585 
    586   if (hal_iface->register_server(uuid) != BT_STATUS_SUCCESS) return false;
    587 
    588   pending_calls_[uuid] = callback;
    589 
    590   return true;
    591 }
    592 
    593 void GattServerFactory::RegisterServerCallback(
    594     hal::BluetoothGattInterface* gatt_iface, int status, int server_id,
    595     const Uuid& app_uuid) {
    596   Uuid uuid(app_uuid);
    597 
    598   VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
    599   lock_guard<mutex> lock(pending_calls_lock_);
    600 
    601   auto iter = pending_calls_.find(uuid);
    602   if (iter == pending_calls_.end()) {
    603     VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
    604     return;
    605   }
    606 
    607   // No need to construct a server if the call wasn't successful.
    608   std::unique_ptr<GattServer> server;
    609   BLEStatus result = BLE_STATUS_FAILURE;
    610   if (status == BT_STATUS_SUCCESS) {
    611     server.reset(new GattServer(uuid, server_id));
    612 
    613     gatt_iface->AddServerObserver(server.get());
    614 
    615     result = BLE_STATUS_SUCCESS;
    616   }
    617 
    618   // Notify the result via the result callback.
    619   iter->second(result, uuid, std::move(server));
    620 
    621   pending_calls_.erase(iter);
    622 }
    623 
    624 }  // namespace bluetooth
    625