Cert stack bring up and test Inquiry with two stacks
* Add main entry point for cert stack.
* Add a test case where cert stack enables page scan and inquiry scan
and DUT starts inquiry. Verify the inquiry result.
Test: cert/run_cert.sh
Change-Id: I2deaf12b6f929301a3542c082a8f77513af8ce68
diff --git a/system/gd/Android.bp b/system/gd/Android.bp
index df5c749..40494af 100644
--- a/system/gd/Android.bp
+++ b/system/gd/Android.bp
@@ -153,6 +153,47 @@
},
}
+cc_binary {
+ name: "bluetooth_cert_stack",
+ defaults: [
+ "gd_defaults",
+ ],
+ host_supported: true,
+ srcs: [
+ "cert/stack_main.cc",
+ "grpc/grpc_module.cc",
+ ":BluetoothCertSource_hci_hal",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ "BluetoothCertStackGeneratedStub_h",
+ ],
+ generated_sources: [
+ "BluetoothCertStackGeneratedStub_cc",
+ ],
+ static_libs: [
+ "libbluetooth_gd",
+ ],
+ shared_libs: [
+ "libgrpc++_unsecure",
+ "libprotobuf-cpp-full",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhwbinder",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ ],
+ },
+ },
+ sanitize: {
+ address: true,
+ },
+}
+
cc_test {
name: "bluetooth_test_gd",
test_suites: ["device-tests"],
@@ -299,7 +340,7 @@
}
genrule {
- name: "BluetoothFacadeGeneratedStub_py",
+ name: "BluetoothFacadeAndCertGeneratedStub_py",
tools: [
"aprotoc",
"protoc-gen-grpc-python-plugin",
@@ -307,9 +348,11 @@
cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) $(in) --grpc_out=$(genDir) --python_out=$(genDir); " +
"touch $(genDir)/__init__.py; " +
"touch $(genDir)/facade/__init__.py; " +
- "touch $(genDir)/hal/__init__.py; ",
+ "touch $(genDir)/hal/__init__.py; " +
+ "touch $(genDir)/hal/cert/__init__.py; ",
srcs: [
":BluetoothFacadeProto",
+ ":BluetoothCertStackProto",
],
out: [
"__init__.py",
@@ -319,5 +362,53 @@
"hal/__init__.py",
"hal/facade_pb2_grpc.py",
"hal/facade_pb2.py",
+ "hal/cert/__init__.py",
+ "hal/cert/api_pb2_grpc.py",
+ "hal/cert/api_pb2.py",
+ ],
+}
+
+filegroup {
+ name: "BluetoothCertStackProto",
+ srcs: [
+ "hal/cert/api.proto",
+ ],
+}
+
+genrule {
+ name: "BluetoothCertStackGeneratedStub_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothCertStackProto",
+ ":BluetoothFacadeProto", // we need to use facade/common.proto
+ ],
+ out: [
+ "facade/common.grpc.pb.h",
+ "facade/common.pb.h",
+ "hal/cert/api.grpc.pb.h",
+ "hal/cert/api.pb.h",
+ ],
+}
+
+genrule {
+ name: "BluetoothCertStackGeneratedStub_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Ipackages/modules/Bluetooth/system/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothCertStackProto",
+ ":BluetoothFacadeProto", // we need to use facade/common.proto
+ ],
+ out: [
+ "facade/common.grpc.pb.cc",
+ "facade/common.pb.cc",
+ "hal/cert/api.grpc.pb.cc",
+ "hal/cert/api.pb.cc",
],
}
diff --git a/system/gd/cert/gd_base_test.py b/system/gd/cert/gd_base_test.py
index 1fdb5c4..797e3eb 100644
--- a/system/gd/cert/gd_base_test.py
+++ b/system/gd/cert/gd_base_test.py
@@ -25,7 +25,7 @@
ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP')
-sys.path.append(ANDROID_BUILD_TOP + '/out/soong/.intermediates/packages/modules/Bluetooth/system/gd/BluetoothFacadeGeneratedStub_py/gen')
+sys.path.append(ANDROID_BUILD_TOP + '/out/soong/.intermediates/packages/modules/Bluetooth/system/gd/BluetoothFacadeAndCertGeneratedStub_py/gen')
ANDROID_HOST_OUT = os.environ.get('ANDROID_HOST_OUT')
ROOTCANAL = ANDROID_HOST_OUT + "/nativetest64/root-canal/root-canal"
diff --git a/system/gd/cert/gd_device.py b/system/gd/cert/gd_device.py
index 25c2ce2..65d46d8 100755
--- a/system/gd/cert/gd_device.py
+++ b/system/gd/cert/gd_device.py
@@ -35,8 +35,11 @@
import grpc
-from hal import facade_pb2_grpc as hal_facade_pb2_grpc
from cert.event_stream import EventStream
+from hal.cert import api_pb2 as hal_cert_pb2
+from hal.cert import api_pb2_grpc as hal_cert_pb2_grpc
+from hal import facade_pb2 as hal_facade_pb2
+from hal import facade_pb2_grpc as hal_facade_pb2_grpc
ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP')
ANDROID_HOST_OUT = os.environ.get('ANDROID_HOST_OUT')
@@ -79,8 +82,10 @@
resolved_cmd = []
for entry in config["cmd"]:
resolved_cmd.append(replace_vars(entry, config))
-
- device = GdDevice(config["grpc_port"], resolved_cmd, config["label"])
+ if config["is_cert_device"] == "true":
+ device = GdCertDevice(config["grpc_port"], resolved_cmd, config["label"])
+ else:
+ device = GdDevice(config["grpc_port"], resolved_cmd, config["label"])
devices.append(device)
return devices
@@ -89,7 +94,7 @@
.replace("$(grpc_port)", config.get("grpc_port")) \
.replace("$(rootcanal_port)", config.get("rootcanal_port"))
-class GdDevice:
+class GdDeviceBase:
def __init__(self, grpc_port, cmd, label):
print(cmd)
self.label = label if label is not None else grpc_port
@@ -114,11 +119,6 @@
stderr=self.backing_process_logs)
self.grpc_channel = grpc.insecure_channel("localhost:" + grpc_port)
- self.hal = hal_facade_pb2_grpc.HciHalFacadeStub(self.grpc_channel)
- self.hal.hci_event_stream = EventStream(self.hal.FetchHciEvent)
- self.hal.hci_acl_stream = EventStream(self.hal.FetchHciAcl)
- self.hal.hci_sco_stream = EventStream(self.hal.FetchHciSco)
-
def clean_up(self):
self.grpc_channel.close()
@@ -130,6 +130,22 @@
backing_process_return_code)
return False
+
+class GdDevice(GdDeviceBase):
+ def __init__(self, grpc_port, cmd, label):
+ super().__init__(grpc_port, cmd, label)
+ self.hal = hal_facade_pb2_grpc.HciHalFacadeStub(self.grpc_channel)
+ self.hal.hci_event_stream = EventStream(self.hal.FetchHciEvent)
+ self.hal.hci_acl_stream = EventStream(self.hal.FetchHciAcl)
+ self.hal.hci_sco_stream = EventStream(self.hal.FetchHciSco)
+
+
+class GdCertDevice(GdDeviceBase):
+ def __init__(self, grpc_port, cmd, label):
+ super().__init__(grpc_port, cmd, label)
+ self.hal = hal_cert_pb2_grpc.HciHalCertStub(self.grpc_channel)
+
+
class GdDeviceLoggerAdapter(logging.LoggerAdapter):
def process(self, msg, kwargs):
msg = "[GdDevice|%s] %s" % (self.extra["device"], msg)
diff --git a/system/gd/cert/host_only_config.json b/system/gd/cert/host_only_config.json
index da14f77..7f95fd9 100644
--- a/system/gd/cert/host_only_config.json
+++ b/system/gd/cert/host_only_config.json
@@ -15,12 +15,24 @@
{
"grpc_port": "8899",
"label": "stack_under_test",
+ "is_cert_device": "false",
"cmd":
[
"$ANDROID_HOST_OUT/bin/stack_with_facade",
"--port=$(grpc_port)",
"--rootcanal-port=$(rootcanal_port)"
]
+ },
+ {
+ "grpc_port": "8898",
+ "label": "cert_stack",
+ "is_cert_device": "true",
+ "cmd":
+ [
+ "$ANDROID_HOST_OUT/bin/bluetooth_cert_stack",
+ "--port=$(grpc_port)",
+ "--rootcanal-port=$(rootcanal_port)"
+ ]
}
]
}
diff --git a/system/gd/cert/stack_main.cc b/system/gd/cert/stack_main.cc
new file mode 100644
index 0000000..edc1d62
--- /dev/null
+++ b/system/gd/cert/stack_main.cc
@@ -0,0 +1,88 @@
+/*
+ * 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 "stack_manager.h"
+
+#include <csignal>
+
+#include "grpc/grpc_module.h"
+#include "hal/cert/cert.h"
+#include "hal/hci_hal.h"
+#include "hal/hci_hal_host_rootcanal.h"
+#include "hal/snoop_logger.h"
+#include "module.h"
+#include "os/thread.h"
+
+using ::bluetooth::Module;
+using ::bluetooth::ModuleList;
+using ::bluetooth::StackManager;
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::os::Thread;
+
+namespace {
+StackManager* stack;
+
+void interrupt_handler(int) {
+ stack->GetInstance<GrpcModule>()->StopServer();
+}
+} // namespace
+
+int main(int argc, const char** argv) {
+ int port = 8898;
+
+ const std::string arg_grpc_port = "--port=";
+ const std::string arg_rootcanal_port = "--rootcanal-port=";
+ const std::string arg_btsnoop_path = "--btsnoop=";
+ std::string btsnoop_path;
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg.find(arg_grpc_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_port.size());
+ port = std::stoi(port_number);
+ }
+ if (arg.find(arg_rootcanal_port) == 0) {
+ auto port_number = arg.substr(arg_rootcanal_port.size());
+ ::bluetooth::hal::HciHalHostRootcanalConfig::Get()->SetPort(std::stoi(port_number));
+ }
+ if (arg.find(arg_btsnoop_path) == 0) {
+ btsnoop_path = arg.substr(arg_btsnoop_path.size());
+ ::bluetooth::hal::SnoopLogger::SetFilePath(btsnoop_path);
+ }
+ }
+
+ ModuleList modules;
+ modules.add<::bluetooth::hal::HciHal>();
+ modules.add<GrpcModule>();
+ modules.add<::bluetooth::hal::cert::HalCertModule>();
+
+ Thread* stack_thread = new Thread("cert_stack_thread", Thread::Priority::NORMAL);
+
+ stack = new StackManager();
+ stack->StartUp(&modules, stack_thread);
+
+ GrpcModule* grpc_module = stack->GetInstance<GrpcModule>();
+ grpc_module->StartServer("0.0.0.0", port);
+
+ signal(SIGINT, interrupt_handler);
+ auto wait_thread = std::thread([grpc_module] { grpc_module->RunGrpcLoop(); });
+ wait_thread.join();
+
+ stack->ShutDown();
+ delete stack;
+ delete stack_thread;
+
+ return 0;
+}
diff --git a/system/gd/facade/stack_with_grpc_main.cc b/system/gd/facade/stack_with_grpc_main.cc
index caa3966..1ba7d4c 100644
--- a/system/gd/facade/stack_with_grpc_main.cc
+++ b/system/gd/facade/stack_with_grpc_main.cc
@@ -80,6 +80,7 @@
stack->ShutDown();
delete stack;
+ delete stack_thread;
return 0;
}
diff --git a/system/gd/hal/Android.bp b/system/gd/hal/Android.bp
index 41b87fc..4c9fa2a 100644
--- a/system/gd/hal/Android.bp
+++ b/system/gd/hal/Android.bp
@@ -39,3 +39,10 @@
"facade.cc",
],
}
+
+filegroup {
+ name: "BluetoothCertSource_hci_hal",
+ srcs: [
+ "cert/cert.cc",
+ ],
+}
diff --git a/system/gd/hal/cert/api.proto b/system/gd/hal/cert/api.proto
new file mode 100644
index 0000000..6071dd1
--- /dev/null
+++ b/system/gd/hal/cert/api.proto
@@ -0,0 +1,38 @@
+syntax = "proto3";
+
+package bluetooth.hal.cert;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service HciHalCert {
+ rpc SendHciResetCommand(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc SetScanMode(ScanModeSettings) returns (google.protobuf.Empty) {}
+ rpc SendHciCommand(HciCommandPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciAcl(HciAclPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciSco(HciScoPacket) returns (google.protobuf.Empty) {}
+
+ rpc FetchHciEvent(bluetooth.facade.EventStreamRequest) returns (stream HciEventPacket) {}
+ rpc FetchHciAcl(bluetooth.facade.EventStreamRequest) returns (stream HciAclPacket) {}
+ rpc FetchHciSco(bluetooth.facade.EventStreamRequest) returns (stream HciScoPacket) {}
+}
+
+message ScanModeSettings {
+ uint32 mode = 1;
+}
+
+message HciEventPacket {
+ bytes payload = 1;
+}
+
+message HciCommandPacket {
+ bytes payload = 1;
+}
+
+message HciAclPacket {
+ bytes payload = 1;
+}
+
+message HciScoPacket {
+ bytes payload = 1;
+}
diff --git a/system/gd/hal/cert/cert.cc b/system/gd/hal/cert/cert.cc
new file mode 100644
index 0000000..d637f13
--- /dev/null
+++ b/system/gd/hal/cert/cert.cc
@@ -0,0 +1,203 @@
+/*
+ * 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 "hal/cert/cert.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
+#include "hal/cert/api.grpc.pb.h"
+#include "hal/hci_hal.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace hal {
+namespace cert {
+
+class HciHalCertService : public HciHalCert::Service, public ::bluetooth::hal::HciHalCallbacks {
+ public:
+ HciHalCertService(HciHal* hal)
+ : hal_(hal), hci_event_stream_(&hci_event_stream_callback_), hci_acl_stream_(&hci_acl_stream_callback_),
+ hci_sco_stream_(&hci_sco_stream_callback_) {
+ hal->registerIncomingPacketCallback(this);
+ }
+
+ ::grpc::Status SendHciResetCommand(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ auto packet = hci::ResetBuilder::Create();
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+ std::this_thread::sleep_for(std::chrono::milliseconds(300));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetScanMode(::grpc::ServerContext* context, const ScanModeSettings* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ unsigned int mode = request->mode();
+ hci::ScanEnable scan_enable;
+ switch (mode) {
+ case 0x00:
+ scan_enable = hci::ScanEnable::NO_SCANS;
+ break;
+ case 0x01:
+ scan_enable = hci::ScanEnable::INQUIRY_SCAN_ONLY;
+ break;
+ case 0x02:
+ scan_enable = hci::ScanEnable::PAGE_SCAN_ONLY;
+ break;
+ case 0x03:
+ scan_enable = hci::ScanEnable::INQUIRY_AND_PAGE_SCAN;
+ break;
+ }
+
+ auto packet = hci::WriteScanEnableBuilder::Create(scan_enable);
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciCommand(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciCommandPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ std::string req_string = request->payload();
+ hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciAcl(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciAclPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendAclData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciSco(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciScoPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendScoData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status FetchHciEvent(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciEventPacket>* writer) override {
+ return hci_event_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciAcl(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciAclPacket>* writer) override {
+ return hci_acl_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciSco(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciScoPacket>* writer) override {
+ return hci_sco_stream_.HandleRequest(context, request, writer);
+ };
+
+ void hciEventReceived(bluetooth::hal::HciPacket event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ hci_event_stream_.OnIncomingEvent(event);
+ can_send_hci_command_ = true;
+ cv_.notify_one();
+ }
+
+ void aclDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_acl_stream_.OnIncomingEvent(data);
+ }
+
+ void scoDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_sco_stream_.OnIncomingEvent(data);
+ }
+
+ private:
+ HciHal* hal_;
+ bool can_send_hci_command_ = true;
+ mutable std::mutex mutex_;
+ std::condition_variable cv_;
+
+ class HciEventStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciEventPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciEventPacket* response, const HciPacket& event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_event_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciEventPacket, HciPacket> hci_event_stream_;
+
+ class HciAclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciAclPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciAclPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_acl_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciAclPacket, HciPacket> hci_acl_stream_;
+
+ class HciScoStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciScoPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciScoPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_sco_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciScoPacket, HciPacket> hci_sco_stream_;
+};
+
+void HalCertModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<HciHal>();
+}
+
+void HalCertModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ service_ = new HciHalCertService(GetDependency<HciHal>());
+}
+
+void HalCertModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* HalCertModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory HalCertModule::Factory = ::bluetooth::ModuleFactory([]() {
+ return new HalCertModule();
+});
+
+} // namespace cert
+} // namespace hal
+} // namespace bluetooth
diff --git a/system/gd/hal/cert/cert.h b/system/gd/hal/cert/cert.h
new file mode 100644
index 0000000..7dba43d
--- /dev/null
+++ b/system/gd/hal/cert/cert.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+
+namespace bluetooth {
+namespace hal {
+namespace cert {
+
+class HciHalCertService;
+
+class HalCertModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+ void Stop() override;
+
+ ::grpc::Service* GetService() const override;
+
+ private:
+ HciHalCertService* service_;
+};
+
+} // namespace cert
+} // namespace hal
+} // namespace bluetooth
diff --git a/system/gd/hal/cert/simple_hal_test.py b/system/gd/hal/cert/simple_hal_test.py
index ed52426..99d8b13 100644
--- a/system/gd/hal/cert/simple_hal_test.py
+++ b/system/gd/hal/cert/simple_hal_test.py
@@ -18,36 +18,72 @@
import os
import sys
+import time
sys.path.append(os.environ['ANDROID_BUILD_TOP'] + '/packages/modules/Bluetooth/system/gd')
from cert.gd_base_test import GdBaseTestClass
+from cert.event_stream import EventStream
+from facade import common_pb2
+from google.protobuf import empty_pb2
+from hal.cert import api_pb2 as hal_cert_pb2
+from hal.cert import api_pb2_grpc as hal_cert_pb2_grpc
from hal import facade_pb2 as hal_facade_pb2
+from hal import facade_pb2_grpc as hal_facade_pb2_grpc
+
class SimpleHalTest(GdBaseTestClass):
+ def setup_test(self):
+ self.device_under_test = self.gd_devices[0]
+ self.cert_device = self.gd_devices[1]
+
+ self.device_under_test.hal.SendHciResetCommand(empty_pb2.Empty())
+ self.cert_device.hal.SendHciResetCommand(empty_pb2.Empty())
+
def test_none_event(self):
- self.gd_devices[0].hal.hci_event_stream.clear_event_buffer()
+ self.device_under_test.hal.hci_event_stream.clear_event_buffer()
- self.gd_devices[0].hal.hci_event_stream.subscribe()
+ self.device_under_test.hal.hci_event_stream.subscribe()
- self.gd_devices[0].hal.hci_event_stream.assert_none()
+ self.device_under_test.hal.hci_event_stream.assert_none()
- self.gd_devices[0].hal.hci_event_stream.unsubscribe()
+ self.device_under_test.hal.hci_event_stream.unsubscribe()
+
+ def test_example(self):
+ response = self.device_under_test.hal.SetLoopbackMode(
+ hal_facade_pb2.LoopbackModeSettings(enable=True)
+ )
+ print("Response " + str(response))
def test_fetch_hci_event(self):
- self.gd_devices[0].hal.SetLoopbackMode(
+ self.device_under_test.hal.SetLoopbackMode(
hal_facade_pb2.LoopbackModeSettings(enable=True)
)
- self.gd_devices[0].hal.hci_event_stream.subscribe()
+ self.device_under_test.hal.hci_event_stream.subscribe()
- self.gd_devices[0].hal.SendHciCommand(
+ self.device_under_test.hal.SendHciCommand(
hal_facade_pb2.HciCommandPacket(
payload=b'\x01\x04\x053\x8b\x9e0\x01'
)
)
- self.gd_devices[0].hal.hci_event_stream.assert_event_occurs(
+
+ self.device_under_test.hal.hci_event_stream.assert_event_occurs(
lambda packet: packet.payload == b'\x19\x08\x01\x04\x053\x8b\x9e0\x01'
)
+ self.device_under_test.hal.hci_event_stream.unsubscribe()
- self.gd_devices[0].hal.hci_event_stream.unsubscribe()
+ def test_inquiry_from_dut(self):
+ self.device_under_test.hal.hci_event_stream.subscribe()
+
+ self.cert_device.hal.SetScanMode(
+ hal_cert_pb2.ScanModeSettings(mode=3)
+ )
+ self.device_under_test.hal.SetInquiry(
+ hal_facade_pb2.InquirySettings(length=0x30, num_responses=0xff)
+ )
+ self.device_under_test.hal.hci_event_stream.assert_event_occurs(
+ lambda packet: b'\x02\x0f' in packet.payload
+ # Expecting an HCI Event (code 0x02, length 0x0f)
+ )
+ self.device_under_test.hal.hci_event_stream.unsubscribe()
diff --git a/system/gd/hal/facade.cc b/system/gd/hal/facade.cc
index ec723e1..1072d59 100644
--- a/system/gd/hal/facade.cc
+++ b/system/gd/hal/facade.cc
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include "facade.h"
+#include "hal/facade.h"
+#include <condition_variable>
#include <memory>
#include <mutex>
@@ -24,11 +25,9 @@
#include "hal/facade.grpc.pb.h"
#include "hal/hci_hal.h"
#include "hci/hci_packets.h"
-#include "os/log.h"
using ::grpc::ServerAsyncResponseWriter;
using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerCompletionQueue;
using ::grpc::ServerContext;
using ::bluetooth::facade::EventStreamRequest;
@@ -46,9 +45,26 @@
hal->registerIncomingPacketCallback(this);
}
+ ::grpc::Status SendHciResetCommand(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ auto packet = hci::ResetBuilder::Create();
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
::grpc::Status SetLoopbackMode(::grpc::ServerContext* context,
const ::bluetooth::hal::LoopbackModeSettings* request,
::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
bool enable = request->enable();
auto packet = hci::WriteLoopbackModeBuilder::Create(enable ? hci::LoopbackMode::ENABLE_LOCAL
: hci::LoopbackMode::NO_LOOPBACK);
@@ -56,13 +72,37 @@
hci::BitInserter it(*packet_bytes);
packet->Serialize(it);
hal_->sendHciCommand(*packet_bytes);
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetInquiry(::grpc::ServerContext* context, const ::bluetooth::hal::InquirySettings* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ auto packet = hci::InquiryBuilder::Create(0x33 /* LAP=0x9e8b33 */, static_cast<uint8_t>(request->length()),
+ static_cast<uint8_t>(request->num_responses()));
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ hal_->sendHciCommand(*packet_bytes);
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
return ::grpc::Status::OK;
}
::grpc::Status SendHciCommand(::grpc::ServerContext* context, const ::bluetooth::hal::HciCommandPacket* request,
::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
std::string req_string = request->payload();
hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
return ::grpc::Status::OK;
}
@@ -98,6 +138,8 @@
void hciEventReceived(bluetooth::hal::HciPacket event) override {
std::string response_str = std::string(event.begin(), event.end());
hci_event_stream_.OnIncomingEvent(event);
+ can_send_hci_command_ = true;
+ cv_.notify_one();
}
void aclDataReceived(bluetooth::hal::HciPacket data) override {
@@ -110,6 +152,9 @@
private:
HciHal* hal_;
+ bool can_send_hci_command_ = true;
+ mutable std::mutex mutex_;
+ std::condition_variable cv_;
class HciEventStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciEventPacket, HciPacket> {
public:
@@ -149,6 +194,7 @@
void HciHalFacadeModule::Stop() {
delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
}
::grpc::Service* HciHalFacadeModule::GetService() const {
diff --git a/system/gd/hal/facade.h b/system/gd/hal/facade.h
index 5763ffc..fa28d10 100644
--- a/system/gd/hal/facade.h
+++ b/system/gd/hal/facade.h
@@ -42,7 +42,6 @@
private:
HciHalFacadeService* service_;
- friend class IncomingPacketCallback;
};
} // namespace hal
diff --git a/system/gd/hal/facade.proto b/system/gd/hal/facade.proto
index 16df47a..45919fe 100644
--- a/system/gd/hal/facade.proto
+++ b/system/gd/hal/facade.proto
@@ -6,7 +6,9 @@
import "facade/common.proto";
service HciHalFacade {
+ rpc SendHciResetCommand(google.protobuf.Empty) returns (google.protobuf.Empty) {}
rpc SetLoopbackMode(LoopbackModeSettings) returns (google.protobuf.Empty) {}
+ rpc SetInquiry(InquirySettings) returns (google.protobuf.Empty) {}
rpc SendHciCommand(HciCommandPacket) returns (google.protobuf.Empty) {}
rpc SendHciAcl(HciAclPacket) returns (google.protobuf.Empty) {}
rpc SendHciSco(HciScoPacket) returns (google.protobuf.Empty) {}
@@ -20,6 +22,15 @@
bool enable = 1;
}
+message ScanModeSettings {
+ uint32 mode = 1;
+}
+
+message InquirySettings {
+ uint32 length = 1;
+ uint32 num_responses = 2;
+}
+
message HciEventPacket {
bytes payload = 1;
}
diff --git a/system/vendor_libs/test_vendor_lib/desktop/test_environment.cc b/system/vendor_libs/test_vendor_lib/desktop/test_environment.cc
index 05103c9..2822335 100644
--- a/system/vendor_libs/test_vendor_lib/desktop/test_environment.cc
+++ b/system/vendor_libs/test_vendor_lib/desktop/test_environment.cc
@@ -143,6 +143,8 @@
void TestEnvironment::SetUpTestChannel() {
int socket_fd = test_channel_transport_.SetUp(test_port_);
+ test_channel_.AddPhy({"BR_EDR"});
+ test_channel_.AddPhy({"LOW_ENERGY"});
test_channel_.SetTimerPeriod({"100"});
test_channel_.StartTimer({});