Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55a636bc authored by Jack He's avatar Jack He
Browse files

HCI: LeAdvertisingManager facade

* Implement LeAdvertisingManager facade to allow incoming LE connections

Bug: 140938432
Test: make
Change-Id: Id8582211109150dfa8afeeee724faa859650cbf4
parent 111c8c97
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -398,6 +398,7 @@ filegroup {
        "facade/rootservice.proto",
        "hal/facade.proto",
        "hci/facade.proto",
        "hci/facade/le_advertising_manager_facade.proto",
        "l2cap/classic/facade.proto",
    ],
}
@@ -421,6 +422,8 @@ genrule {
        "hal/facade.pb.h",
        "hci/facade.grpc.pb.h",
        "hci/facade.pb.h",
        "hci/facade/le_advertising_manager_facade.grpc.pb.h",
        "hci/facade/le_advertising_manager_facade.pb.h",
        "l2cap/classic/facade.grpc.pb.h",
        "l2cap/classic/facade.pb.h",
    ],
@@ -445,6 +448,8 @@ genrule {
        "hal/facade.pb.cc",
        "hci/facade.grpc.pb.cc",
        "hci/facade.pb.cc",
        "hci/facade/le_advertising_manager_facade.grpc.pb.cc",
        "hci/facade/le_advertising_manager_facade.pb.cc",
        "l2cap/classic/facade.grpc.pb.cc",
        "l2cap/classic/facade.pb.cc",
    ],
@@ -461,6 +466,7 @@ genrule {
        "touch $(genDir)/hal/__init__.py; " +
        "touch $(genDir)/hal/cert/__init__.py; " +
        "touch $(genDir)/hci/__init__.py; " +
        "touch $(genDir)/hci/facade/__init__.py; " +
        "touch $(genDir)/hci/cert/__init__.py; " +
        "touch $(genDir)/l2cap/classic/__init__.py; " +
        "touch $(genDir)/l2cap/classic/cert/__init__.py; ",
@@ -482,6 +488,9 @@ genrule {
        "hci/__init__.py",
        "hci/facade_pb2_grpc.py",
        "hci/facade_pb2.py",
        "hci/facade/__init__.py",
        "hci/facade/le_advertising_manager_facade_pb2_grpc.py",
        "hci/facade/le_advertising_manager_facade_pb2.py",
        "l2cap/classic/__init__.py",
        "l2cap/classic/facade_pb2_grpc.py",
        "l2cap/classic/facade_pb2.py",
+2 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ from cert.event_stream import EventStream
from facade import rootservice_pb2_grpc as facade_rootservice_pb2_grpc
from hal import facade_pb2_grpc as hal_facade_pb2_grpc
from hci import facade_pb2_grpc as hci_facade_pb2_grpc
from hci.facade import le_advertising_manager_facade_pb2_grpc
from l2cap.classic import facade_pb2_grpc as l2cap_facade_pb2_grpc

ACTS_CONTROLLER_CONFIG_NAME = "GdDevice"
@@ -71,6 +72,7 @@ class GdDevice(GdDeviceBase):
        self.hci = hci_facade_pb2_grpc.AclManagerFacadeStub(self.grpc_channel)
        self.hci_classic_security = hci_facade_pb2_grpc.ClassicSecurityManagerFacadeStub(self.grpc_channel)
        self.l2cap = l2cap_facade_pb2_grpc.L2capClassicModuleFacadeStub(self.grpc_channel)
        self.hci_le_advertising_manager = le_advertising_manager_facade_pb2_grpc.LeAdvertisingManagerFacadeStub(self.grpc_channel)

        # Event streams
        self.hal.hci_event_stream = EventStream(self.hal.FetchHciEvent)
+12 −0
Original line number Diff line number Diff line
@@ -23,3 +23,15 @@ message EventStreamRequest {
message BluetoothAddress {
  bytes address = 1;
}

enum BluetoothAddressTypeEnum {
  PUBLIC_DEVICE_ADDRESS = 0x0;
  RANDOM_DEVICE_ADDRESS = 0x1;
  PUBLIC_IDENTITY_ADDRESS = 0x2;
  RANDOM_IDENTITY_ADDRESS = 0x3;
}

enum BluetoothPeerAddressTypeEnum {
  PUBLIC_DEVICE_OR_IDENTITY_ADDRESS = 0x0;
  RANDOM_DEVICE_OR_IDENTITY_ADDRESS = 0x1;
}
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ filegroup {
    name: "BluetoothFacade_hci_layer",
    srcs: [
        "facade.cc",
        "facade/le_advertising_manager_facade.cc"
    ],
}

+220 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 The Android Open Source Project
 *
 * 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 <cstdint>
#include <unordered_map>
#include <utility>

#include "common/bidi_queue.h"
#include "common/bind.h"
#include "grpc/grpc_event_stream.h"
#include "hci/address.h"
#include "hci/address_with_type.h"
#include "hci/facade/le_advertising_manager_facade.grpc.pb.h"
#include "hci/facade/le_advertising_manager_facade.h"
#include "hci/facade/le_advertising_manager_facade.pb.h"
#include "hci/le_advertising_manager.h"
#include "os/log.h"
#include "packet/raw_builder.h"

namespace bluetooth {
namespace hci {
namespace facade {

using ::grpc::ServerAsyncResponseWriter;
using ::grpc::ServerAsyncWriter;
using ::grpc::ServerContext;
using ::grpc::ServerWriter;
using ::grpc::Status;

using ::bluetooth::facade::BluetoothAddress;
using ::bluetooth::facade::BluetoothAddressTypeEnum;
using ::bluetooth::facade::EventStreamRequest;
using ::bluetooth::grpc::GrpcEventStream;
using ::bluetooth::grpc::GrpcEventStreamCallback;

hci::GapData GapDataFromProto(const GapData& gap_data_proto) {
  hci::GapData gap_data;
  auto data_copy = std::make_shared<std::vector<uint8_t>>(gap_data_proto.data().begin(), gap_data_proto.data().end());
  packet::PacketView<packet::kLittleEndian> packet(data_copy);
  auto after = hci::GapData::Parse(&gap_data, packet.begin());
  ASSERT(after != packet.begin());
  return gap_data;
}

bool AdvertisingConfigFromProto(const AdvertisingConfig& config_proto, hci::AdvertisingConfig* config) {
  for (const auto& elem : config_proto.advertisement()) {
    config->advertisement.push_back(GapDataFromProto(elem));
  }

  for (const auto& elem : config_proto.scan_response()) {
    config->scan_response.push_back(GapDataFromProto(elem));
  }

  hci::Address::FromString(config_proto.random_address().address(), config->random_address);

  if (config_proto.interval_min() > UINT16_MAX || config_proto.interval_min() < 0) {
    LOG_WARN("Bad interval_min: %d", config_proto.interval_min());
    return false;
  }
  config->interval_min = static_cast<uint16_t>(config_proto.interval_min());

  if (config_proto.interval_max() > UINT16_MAX || config_proto.interval_max() < 0) {
    LOG_WARN("Bad interval_max: %d", config_proto.interval_max());
    return false;
  }
  config->interval_max = static_cast<uint16_t>(config_proto.interval_max());

  config->event_type = static_cast<hci::AdvertisingEventType>(config_proto.event_type());

  config->address_type = static_cast<::bluetooth::hci::AddressType>(config_proto.address_type());

  config->peer_address_type = static_cast<::bluetooth::hci::PeerAddressType>(config_proto.peer_address_type());

  hci::Address::FromString(config_proto.peer_address().address(), config->peer_address);

  if (config_proto.channel_map() > UINT8_MAX || config_proto.channel_map() < 0) {
    LOG_WARN("Bad channel_map: %d", config_proto.channel_map());
    return false;
  }
  config->channel_map = static_cast<uint8_t>(config_proto.channel_map());

  if (config_proto.tx_power() > UINT8_MAX || config_proto.tx_power() < 0) {
    LOG_WARN("Bad tx_power: %d", config_proto.tx_power());
    return false;
  }

  config->filter_policy = static_cast<hci::AdvertisingFilterPolicy>(config_proto.filter_policy());

  config->tx_power = static_cast<uint8_t>(config_proto.tx_power());
  return true;
}

class LeAdvertiser {
 public:
  LeAdvertiser(hci::AdvertisingConfig config) : config_(std::move(config)) {}

  void ScanCallback(Address address, AddressType address_type) {}

  void TerminatedCallback(ErrorCode error_code, uint8_t, uint8_t) {}

  hci::AdvertiserId GetAdvertiserId() {
    return id_;
  }

  void SetAdvertiserId(hci::AdvertiserId id) {
    id_ = id;
  }

 private:
  hci::AdvertiserId id_ = LeAdvertisingManager::kInvalidId;
  hci::AdvertisingConfig config_;
};

class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Service {
 public:
  LeAdvertisingManagerFacadeService(LeAdvertisingManager* le_advertising_manager, os::Handler* facade_handler)
      : le_advertising_manager_(le_advertising_manager), facade_handler_(facade_handler) {
    ASSERT(le_advertising_manager_ != nullptr);
    ASSERT(facade_handler_ != nullptr);
  }

  ::grpc::Status CreateAdvertiser(::grpc::ServerContext* context,
                                  const ::bluetooth::hci::facade::CreateAdvertiserRequest* request,
                                  ::bluetooth::hci::facade::CreateAdvertiserResponse* response) override {
    hci::AdvertisingConfig config = {};
    if (!AdvertisingConfigFromProto(request->config(), &config)) {
      LOG_WARN("Error parsing advertising config %s", request->SerializeAsString().c_str());
      response->set_advertiser_id(LeAdvertisingManager::kInvalidId);
      return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Error while parsing advertising config");
    }
    LeAdvertiser le_advertiser(config);
    auto advertiser_id = le_advertising_manager_->CreateAdvertiser(
        config, common::Bind(&LeAdvertiser::ScanCallback, common::Unretained(&le_advertiser)),
        common::Bind(&LeAdvertiser::TerminatedCallback, common::Unretained(&le_advertiser)), facade_handler_);
    if (advertiser_id != LeAdvertisingManager::kInvalidId) {
      le_advertiser.SetAdvertiserId(advertiser_id);
      le_advertisers_.push_back(le_advertiser);
    } else {
      LOG_WARN("Failed to create advertiser");
    }
    response->set_advertiser_id(advertiser_id);
    return ::grpc::Status::OK;
  }

  ::grpc::Status ExtendedCreateAdvertiser(
      ::grpc::ServerContext* context, const ::bluetooth::hci::facade::ExtendedCreateAdvertiserRequest* request,
      ::bluetooth::hci::facade::ExtendedCreateAdvertiserResponse* response) override {
    LOG_WARN("ExtendedCreateAdvertiser is not implemented");
    response->set_advertiser_id(LeAdvertisingManager::kInvalidId);
    return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "ExtendedCreateAdvertiser is not implemented");
  }

  ::grpc::Status GetNumberOfAdvertisingInstances(
      ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
      ::bluetooth::hci::facade::GetNumberOfAdvertisingInstancesResponse* response) override {
    response->set_num_advertising_instances(le_advertising_manager_->GetNumberOfAdvertisingInstances());
    return ::grpc::Status::OK;
  }

  ::grpc::Status RemoveAdvertiser(::grpc::ServerContext* context,
                                  const ::bluetooth::hci::facade::RemoveAdvertiserRequest* request,
                                  ::google::protobuf::Empty* response) override {
    if (request->advertiser_id() == LeAdvertisingManager::kInvalidId) {
      LOG_WARN("Invalid advertiser ID %d", request->advertiser_id());
      return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invlid advertiser ID received");
    }
    le_advertising_manager_->RemoveAdvertiser(request->advertiser_id());
    for (auto iter = le_advertisers_.begin(); iter != le_advertisers_.end();) {
      if (iter->GetAdvertiserId() == request->advertiser_id()) {
        iter = le_advertisers_.erase(iter);
      } else {
        ++iter;
      }
    }
    return ::grpc::Status::OK;
  }

  std::vector<LeAdvertiser> le_advertisers_;
  LeAdvertisingManager* le_advertising_manager_;
  os::Handler* facade_handler_;
};

void LeAdvertisingManagerFacadeModule::ListDependencies(ModuleList* list) {
  ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
  list->add<hci::LeAdvertisingManager>();
}

void LeAdvertisingManagerFacadeModule::Start() {
  ::bluetooth::grpc::GrpcFacadeModule::Start();
  service_ = new LeAdvertisingManagerFacadeService(GetDependency<hci::LeAdvertisingManager>(), GetHandler());
}

void LeAdvertisingManagerFacadeModule::Stop() {
  delete service_;
  ::bluetooth::grpc::GrpcFacadeModule::Stop();
}

::grpc::Service* LeAdvertisingManagerFacadeModule::GetService() const {
  return service_;
}

const ModuleFactory LeAdvertisingManagerFacadeModule::Factory =
    ::bluetooth::ModuleFactory([]() { return new LeAdvertisingManagerFacadeModule(); });

}  // namespace facade
}  // namespace hci
}  // namespace bluetooth
Loading