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({});