Merge "Trigger gd legacy from legacy dumpsys"
diff --git a/system/gd/Android.bp b/system/gd/Android.bp
index b2bff30..60e1030 100644
--- a/system/gd/Android.bp
+++ b/system/gd/Android.bp
@@ -114,11 +114,17 @@
             srcs: [
                 ":BluetoothOsSources_linux_generic",
             ],
+            shared_libs: [
+                "libprotobuf-cpp-full",
+            ],
         },
         host: {
             srcs: [
                 ":BluetoothHalSources_hci_rootcanal",
             ],
+            shared_libs: [
+                "libprotobuf-cpp-full",
+            ],
         },
         android: {
             srcs: [
@@ -153,6 +159,9 @@
         "libchrome",
         "libcrypto",
     ],
+    static_libs: [
+        "libbluetooth-protos",
+    ]
 }
 
 cc_library {
@@ -205,6 +214,7 @@
     ],
     static_libs: [
         "libbluetooth_gd",
+        "libbluetooth-protos",
     ],
     shared_libs: [
         "libchrome",
@@ -279,12 +289,14 @@
         "BluetoothGeneratedPackets_h",
     ],
     static_libs: [
+        "libbluetooth-protos",
         "libbluetooth_gd",
         "libgmock",
     ],
     shared_libs: [
         "libchrome",
         "libcrypto",
+        "libprotobuf-cpp-full",
     ],
     sanitize: {
         address: true,
@@ -320,6 +332,7 @@
         ":BluetoothHciFuzzHelperSources",
     ],
     static_libs: [
+        "libbluetooth-protos",
         "libbluetooth_gd_fuzzing",
         "libchrome",
         "libgmock",
@@ -331,6 +344,7 @@
     ],
     shared_libs: [
         "libcrypto",
+        "libprotobuf-cpp-full",
     ],
     cflags: [
         "-DFUZZ_TARGET",
diff --git a/system/gd/hci/hci_layer.cc b/system/gd/hci/hci_layer.cc
index 74ac026..ecceb71 100644
--- a/system/gd/hci/hci_layer.cc
+++ b/system/gd/hci/hci_layer.cc
@@ -45,6 +45,8 @@
 using hci::ResetCompleteView;
 using os::Alarm;
 using os::Handler;
+using std::move;
+using std::unique_ptr;
 
 static void fail_if_reset_complete_not_success(CommandCompleteView complete) {
   auto reset_complete = ResetCompleteView::Create(complete);
@@ -58,18 +60,33 @@
 
 class CommandQueueEntry {
  public:
-  CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+  CommandQueueEntry(unique_ptr<CommandPacketBuilder> command_packet,
                     ContextualOnceCallback<void(CommandCompleteView)> on_complete_function)
-      : command(std::move(command_packet)), waiting_for_status_(false), on_complete(std::move(on_complete_function)) {}
+      : command(move(command_packet)), waiting_for_status_(false), on_complete(move(on_complete_function)) {}
 
-  CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+  CommandQueueEntry(unique_ptr<CommandPacketBuilder> command_packet,
                     ContextualOnceCallback<void(CommandStatusView)> on_status_function)
-      : command(std::move(command_packet)), waiting_for_status_(true), on_status(std::move(on_status_function)) {}
+      : command(move(command_packet)), waiting_for_status_(true), on_status(move(on_status_function)) {}
 
-  std::unique_ptr<CommandPacketBuilder> command;
+  unique_ptr<CommandPacketBuilder> command;
   bool waiting_for_status_;
   ContextualOnceCallback<void(CommandStatusView)> on_status;
   ContextualOnceCallback<void(CommandCompleteView)> on_complete;
+
+  template <typename TView>
+  ContextualOnceCallback<void(TView)>* GetCallback() {
+    return nullptr;
+  }
+
+  template <>
+  ContextualOnceCallback<void(CommandStatusView)>* GetCallback<CommandStatusView>() {
+    return &on_status;
+  }
+
+  template <>
+  ContextualOnceCallback<void(CommandCompleteView)>* GetCallback<CommandCompleteView>() {
+    return &on_complete;
+  }
 };
 
 template <typename T>
@@ -78,37 +95,25 @@
   explicit CommandInterfaceImpl(HciLayer& hci) : hci_(hci) {}
   ~CommandInterfaceImpl() override = default;
 
-  void EnqueueCommand(std::unique_ptr<T> command,
-                      ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
-    hci_.EnqueueCommand(std::move(command), std::move(on_complete));
+  void EnqueueCommand(unique_ptr<T> command, ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
+    hci_.EnqueueCommand(move(command), move(on_complete));
   }
 
-  void EnqueueCommand(std::unique_ptr<T> command, ContextualOnceCallback<void(CommandStatusView)> on_status) override {
-    hci_.EnqueueCommand(std::move(command), std::move(on_status));
+  void EnqueueCommand(unique_ptr<T> command, ContextualOnceCallback<void(CommandStatusView)> on_status) override {
+    hci_.EnqueueCommand(move(command), move(on_status));
   }
   HciLayer& hci_;
 };
 
 struct HciLayer::impl {
-  impl(HciLayer& module) : hal_(nullptr), module_(module) {}
+  impl(hal::HciHal* hal, HciLayer& module) : hal_(hal), module_(module) {
+    hci_timeout_alarm_ = new Alarm(module.GetHandler());
+  }
 
-  void Start(hal::HciHal* hal) {
-    hal_ = hal;
-    hci_timeout_alarm_ = new Alarm(module_.GetHandler());
-
-    auto queue_end = acl_queue_.GetDownEnd();
-    Handler* handler = module_.GetHandler();
-    queue_end->RegisterDequeue(handler, BindOn(this, &impl::on_outbound_acl_ready));
-    module_.RegisterEventHandler(EventCode::COMMAND_COMPLETE, handler->BindOn(this, &impl::on_command_complete));
-    module_.RegisterEventHandler(EventCode::COMMAND_STATUS, handler->BindOn(this, &impl::on_command_status));
-    module_.RegisterEventHandler(EventCode::LE_META_EVENT, handler->BindOn(this, &impl::on_le_meta_event));
-    // TODO find the right place
-    auto drop_packet = handler->BindOn(this, &impl::drop);
-    module_.RegisterEventHandler(EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE, drop_packet);
-    module_.RegisterEventHandler(EventCode::MAX_SLOTS_CHANGE, drop_packet);
-    module_.RegisterEventHandler(EventCode::VENDOR_SPECIFIC, drop_packet);
-
-    module_.EnqueueCommand(ResetBuilder::Create(), handler->BindOnce(&fail_if_reset_complete_not_success));
+  ~impl() {
+    incoming_acl_buffer_.Clear();
+    delete hci_timeout_alarm_;
+    command_queue_.clear();
   }
 
   void drop(EventPacketView) {}
@@ -121,54 +126,34 @@
     hal_->sendAclData(bytes);
   }
 
-  void Stop() {
-    acl_queue_.GetDownEnd()->UnregisterDequeue();
-    incoming_acl_packet_buffer_.Clear();
-    delete hci_timeout_alarm_;
-    command_queue_.clear();
-    hal_ = nullptr;
-  }
-
   void on_command_status(EventPacketView event) {
-    CommandStatusView status_view = CommandStatusView::Create(event);
-    ASSERT(status_view.IsValid());
-    command_credits_ = status_view.GetNumHciCommandPackets();
-    OpCode op_code = status_view.GetCommandOpCode();
-    if (op_code == OpCode::NONE) {
-      send_next_command();
-      return;
-    }
-    ASSERT_LOG(!command_queue_.empty(), "Unexpected status event with OpCode 0x%02hx (%s)", op_code,
-               OpCodeText(op_code).c_str());
-    ASSERT_LOG(waiting_command_ == op_code, "Waiting for 0x%02hx (%s), got 0x%02hx (%s)", waiting_command_,
-               OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
-    ASSERT_LOG(command_queue_.front().waiting_for_status_,
-               "Waiting for command complete 0x%02hx (%s), got command status for 0x%02hx (%s)", waiting_command_,
-               OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
-    command_queue_.front().on_status.Invoke(std::move(status_view));
-    command_queue_.pop_front();
-    waiting_command_ = OpCode::NONE;
-    hci_timeout_alarm_->Cancel();
-    send_next_command();
+    handle_command_response<CommandStatusView>(event, "status");
   }
 
   void on_command_complete(EventPacketView event) {
-    CommandCompleteView complete_view = CommandCompleteView::Create(event);
-    ASSERT(complete_view.IsValid());
-    command_credits_ = complete_view.GetNumHciCommandPackets();
-    OpCode op_code = complete_view.GetCommandOpCode();
+    handle_command_response<CommandCompleteView>(event, "complete");
+  }
+
+  template <typename TResponse>
+  void handle_command_response(EventPacketView event, std::string logging_id) {
+    TResponse response_view = TResponse::Create(event);
+    ASSERT(response_view.IsValid());
+    command_credits_ = response_view.GetNumHciCommandPackets();
+    OpCode op_code = response_view.GetCommandOpCode();
     if (op_code == OpCode::NONE) {
       send_next_command();
       return;
     }
-    ASSERT_LOG(command_queue_.size() > 0, "Unexpected command complete with OpCode 0x%02hx (%s)", op_code,
+    bool is_status = logging_id == "status";
+
+    ASSERT_LOG(!command_queue_.empty(), "Unexpected %s event with OpCode 0x%02hx (%s)", logging_id.c_str(), op_code,
                OpCodeText(op_code).c_str());
     ASSERT_LOG(waiting_command_ == op_code, "Waiting for 0x%02hx (%s), got 0x%02hx (%s)", waiting_command_,
                OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
-    ASSERT_LOG(!command_queue_.front().waiting_for_status_,
-               "Waiting for command status 0x%02hx (%s), got command complete for 0x%02hx (%s)", waiting_command_,
-               OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
-    command_queue_.front().on_complete.Invoke(std::move(complete_view));
+    ASSERT_LOG(command_queue_.front().waiting_for_status_ == is_status, "0x%02hx (%s) was not expecting %s event",
+               op_code, OpCodeText(op_code).c_str(), logging_id.c_str());
+
+    command_queue_.front().GetCallback<TResponse>()->Invoke(move(response_view));
     command_queue_.pop_front();
     waiting_command_ = OpCode::NONE;
     hci_timeout_alarm_->Cancel();
@@ -185,6 +170,7 @@
   }
 
   void on_hci_event(EventPacketView event) {
+    ASSERT(event.IsValid());
     EventCode event_code = event.GetEventCode();
     if (event_handlers_.find(event_code) == event_handlers_.end()) {
       LOG_DEBUG("Dropping unregistered event of type 0x%02hhx (%s)", event_code, EventCodeText(event_code).c_str());
@@ -193,17 +179,9 @@
     event_handlers_[event_code].Invoke(event);
   }
 
-  void handle_enqueue_command_with_complete(std::unique_ptr<CommandPacketBuilder> command,
-                                            ContextualOnceCallback<void(CommandCompleteView)> on_complete) {
-    command_queue_.emplace_back(std::move(command), std::move(on_complete));
-
-    send_next_command();
-  }
-
-  void handle_enqueue_command_with_status(std::unique_ptr<CommandPacketBuilder> command,
-                                          ContextualOnceCallback<void(CommandStatusView)> on_status) {
-    command_queue_.emplace_back(std::move(command), std::move(on_status));
-
+  template <typename TResponse>
+  void enqueue_command(unique_ptr<CommandPacketBuilder> command, ContextualOnceCallback<void(TResponse)> on_response) {
+    command_queue_.emplace_back(move(command), move(on_response));
     send_next_command();
   }
 
@@ -221,6 +199,7 @@
     BitInserter bi(*bytes);
     command_queue_.front().command->Serialize(bi);
     hal_->sendHciCommand(*bytes);
+
     auto cmd_view = CommandPacketView::Create(bytes);
     ASSERT(cmd_view.IsValid());
     OpCode op_code = cmd_view.GetOpCode();
@@ -229,32 +208,27 @@
     hci_timeout_alarm_->Schedule(BindOnce(&on_hci_timeout, op_code), kHciTimeoutMs);
   }
 
-  void handle_register_event_handler(EventCode event_code, ContextualCallback<void(EventPacketView)> event_handler) {
-    ASSERT_LOG(event_handlers_.count(event_code) == 0, "Can not register a second handler for event_code %02hhx (%s)",
-               event_code, EventCodeText(event_code).c_str());
-    event_handlers_[event_code] = event_handler;
+  void register_event(EventCode event, ContextualCallback<void(EventPacketView)> handler) {
+    ASSERT_LOG(event_handlers_.count(event) == 0, "Can not register a second handler for %02hhx (%s)", event,
+               EventCodeText(event).c_str());
+    event_handlers_[event] = handler;
   }
 
-  void handle_unregister_event_handler(EventCode event_code) {
-    event_handlers_.erase(event_handlers_.find(event_code));
+  void unregister_event(EventCode event) {
+    event_handlers_.erase(event_handlers_.find(event));
   }
 
-  void handle_register_le_event_handler(SubeventCode subevent_code,
-                                        ContextualCallback<void(LeMetaEventView)> subevent_handler) {
-    ASSERT_LOG(subevent_handlers_.count(subevent_code) == 0,
-               "Can not register a second handler for subevent_code %02hhx (%s)", subevent_code,
-               SubeventCodeText(subevent_code).c_str());
-    subevent_handlers_[subevent_code] = subevent_handler;
+  void register_le_event(SubeventCode event, ContextualCallback<void(LeMetaEventView)> handler) {
+    ASSERT_LOG(subevent_handlers_.count(event) == 0, "Can not register a second handler for %02hhx (%s)", event,
+               SubeventCodeText(event).c_str());
+    subevent_handlers_[event] = handler;
   }
 
-  void handle_unregister_le_event_handler(SubeventCode subevent_code) {
-    subevent_handlers_.erase(subevent_handlers_.find(subevent_code));
+  void unregister_le_event(SubeventCode event) {
+    subevent_handlers_.erase(subevent_handlers_.find(event));
   }
 
-  // The HAL
   hal::HciHal* hal_;
-
-  // A reference to the HciLayer module
   HciLayer& module_;
 
   // Interfaces
@@ -276,7 +250,7 @@
 
   // Acl packets
   BidiQueue<AclPacketView, AclPacketBuilder> acl_queue_{3 /* TODO: Set queue depth */};
-  os::EnqueueBuffer<AclPacketView> incoming_acl_packet_buffer_{acl_queue_.GetDownEnd()};
+  os::EnqueueBuffer<AclPacketView> incoming_acl_buffer_{acl_queue_.GetDownEnd()};
 };
 
 // All functions here are running on the HAL thread
@@ -286,15 +260,13 @@
   void hciEventReceived(hal::HciPacket event_bytes) override {
     auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(event_bytes));
     EventPacketView event = EventPacketView::Create(packet);
-    ASSERT(event.IsValid());
-    module_.CallOn(module_.impl_, &impl::on_hci_event, std::move(event));
+    module_.CallOn(module_.impl_, &impl::on_hci_event, move(event));
   }
 
   void aclDataReceived(hal::HciPacket data_bytes) override {
-    auto packet =
-        packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(std::move(data_bytes)));
-    AclPacketView acl = AclPacketView::Create(packet);
-    module_.impl_->incoming_acl_packet_buffer_.Enqueue(std::make_unique<AclPacketView>(acl), module_.GetHandler());
+    auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(move(data_bytes)));
+    auto acl = std::make_unique<AclPacketView>(AclPacketView::Create(packet));
+    module_.impl_->incoming_acl_buffer_.Enqueue(move(acl), module_.GetHandler());
   }
 
   void scoDataReceived(hal::HciPacket data_bytes) override {
@@ -304,42 +276,39 @@
   HciLayer& module_;
 };
 
-HciLayer::HciLayer() : impl_(new impl(*this)), hal_callbacks_(new hal_callbacks(*this)) {}
+HciLayer::HciLayer() : impl_(nullptr), hal_callbacks_(nullptr) {}
 
 HciLayer::~HciLayer() {
-  delete impl_;
-  delete hal_callbacks_;
 }
 
-void HciLayer::EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+void HciLayer::EnqueueCommand(unique_ptr<CommandPacketBuilder> command,
                               common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) {
-  CallOn(impl_, &impl::handle_enqueue_command_with_complete, std::move(command), std::move(on_complete));
+  CallOn(impl_, &impl::enqueue_command<CommandCompleteView>, move(command), move(on_complete));
 }
 
-void HciLayer::EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+void HciLayer::EnqueueCommand(unique_ptr<CommandPacketBuilder> command,
                               common::ContextualOnceCallback<void(CommandStatusView)> on_status) {
-  CallOn(impl_, &impl::handle_enqueue_command_with_status, std::move(command), std::move(on_status));
+  CallOn(impl_, &impl::enqueue_command<CommandStatusView>, move(command), move(on_status));
 }
 
 common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* HciLayer::GetAclQueueEnd() {
   return impl_->acl_queue_.GetUpEnd();
 }
 
-void HciLayer::RegisterEventHandler(EventCode event_code, ContextualCallback<void(EventPacketView)> event_handler) {
-  CallOn(impl_, &impl::handle_register_event_handler, event_code, event_handler);
+void HciLayer::RegisterEventHandler(EventCode event, ContextualCallback<void(EventPacketView)> handler) {
+  CallOn(impl_, &impl::register_event, event, handler);
 }
 
-void HciLayer::UnregisterEventHandler(EventCode event_code) {
-  CallOn(impl_, &impl::handle_unregister_event_handler, event_code);
+void HciLayer::UnregisterEventHandler(EventCode event) {
+  CallOn(impl_, &impl::unregister_event, event);
 }
 
-void HciLayer::RegisterLeEventHandler(SubeventCode subevent_code,
-                                      ContextualCallback<void(LeMetaEventView)> event_handler) {
-  CallOn(impl_, &impl::handle_register_le_event_handler, subevent_code, event_handler);
+void HciLayer::RegisterLeEventHandler(SubeventCode event, ContextualCallback<void(LeMetaEventView)> handler) {
+  CallOn(impl_, &impl::register_le_event, event, handler);
 }
 
-void HciLayer::UnregisterLeEventHandler(SubeventCode subevent_code) {
-  CallOn(impl_, &impl::handle_unregister_le_event_handler, subevent_code);
+void HciLayer::UnregisterLeEventHandler(SubeventCode event) {
+  CallOn(impl_, &impl::unregister_le_event, event);
 }
 
 AclConnectionInterface* HciLayer::GetAclConnectionInterface(
@@ -396,14 +365,31 @@
 
 void HciLayer::Start() {
   auto hal = GetDependency<hal::HciHal>();
-  impl_->Start(hal);
+  impl_ = new impl(hal, *this);
+  hal_callbacks_ = new hal_callbacks(*this);
+
+  Handler* handler = GetHandler();
+  impl_->acl_queue_.GetDownEnd()->RegisterDequeue(handler, BindOn(impl_, &impl::on_outbound_acl_ready));
+  RegisterEventHandler(EventCode::COMMAND_COMPLETE, handler->BindOn(impl_, &impl::on_command_complete));
+  RegisterEventHandler(EventCode::COMMAND_STATUS, handler->BindOn(impl_, &impl::on_command_status));
+  RegisterEventHandler(EventCode::LE_META_EVENT, handler->BindOn(impl_, &impl::on_le_meta_event));
+  // TODO find the right place
+  auto drop_packet = handler->BindOn(impl_, &impl::drop);
+  RegisterEventHandler(EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE, drop_packet);
+  RegisterEventHandler(EventCode::MAX_SLOTS_CHANGE, drop_packet);
+  RegisterEventHandler(EventCode::VENDOR_SPECIFIC, drop_packet);
+
+  EnqueueCommand(ResetBuilder::Create(), handler->BindOnce(&fail_if_reset_complete_not_success));
   hal->registerIncomingPacketCallback(hal_callbacks_);
 }
 
 void HciLayer::Stop() {
   auto hal = GetDependency<hal::HciHal>();
   hal->unregisterIncomingPacketCallback();
-  impl_->Stop();
+  delete hal_callbacks_;
+
+  impl_->acl_queue_.GetDownEnd()->UnregisterDequeue();
+  delete impl_;
 }
 
 }  // namespace hci
diff --git a/system/gd/module.cc b/system/gd/module.cc
index a9599b9..8ec1bbd 100644
--- a/system/gd/module.cc
+++ b/system/gd/module.cc
@@ -15,6 +15,7 @@
  */
 
 #include "module.h"
+#include "bluetooth/dumpmod.pb.h"
 
 using ::bluetooth::os::Handler;
 using ::bluetooth::os::Thread;
@@ -126,6 +127,8 @@
 }
 
 void ModuleDumper::DumpState() const {
+  Dumpmod dumpmod;
+
   for (auto it = module_registry_.start_order_.rbegin(); it != module_registry_.start_order_.rend(); it++) {
     auto instance = module_registry_.started_modules_.find(*it);
     ASSERT(instance != module_registry_.started_modules_.end());
@@ -133,7 +136,10 @@
     if (message == nullptr) {
       continue;
     }
-    // TODO(cmanton) Process module message into master proto
+    ModuleDumpState dump_state;
+    dump_state.set_name(instance->second->ToString());
+    dump_state.mutable_data()->PackFrom(*message);
+    dumpmod.mutable_module_dump_states()->insert({dump_state.name(), dump_state});
   }
 }
 
diff --git a/system/gd/proto/Android.bp b/system/gd/proto/Android.bp
index ef5c78e..ea3620d 100644
--- a/system/gd/proto/Android.bp
+++ b/system/gd/proto/Android.bp
@@ -22,10 +22,15 @@
     host_supported: true,
     proto: {
         export_proto_headers: true,
+        type: "lite",
         include_dirs: ["external/protobuf/src"],
     },
     srcs: [
         "bluetooth/dumpmod.proto",
         "bluetooth/metrics/bluetooth.proto"
     ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth.updatable",
+    ],
 }
diff --git a/system/gd/security/cert/cert_security.py b/system/gd/security/cert/cert_security.py
new file mode 100644
index 0000000..e862699
--- /dev/null
+++ b/system/gd/security/cert/cert_security.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python3
+#
+#   Copyright 2020 - 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.
+
+import logging
+
+from bluetooth_packets_python3 import hci_packets
+from cert.closable import safeClose
+from cert.event_stream import EventStream
+from cert.py_hci import PyHci
+from cert.py_security import PySecurity
+from datetime import datetime
+from google.protobuf import empty_pb2 as empty_proto
+from hci.facade import facade_pb2 as hci_facade
+from l2cap.classic import facade_pb2 as l2cap_facade
+from security.facade_pb2 import IoCapabilities
+from security.facade_pb2 import AuthenticationRequirements
+from security.facade_pb2 import OobDataPresent
+
+
+class CertSecurity(PySecurity):
+    """
+        Contain all of the certification stack logic for sending and receiving
+        HCI commands following the Classic Pairing flows.
+    """
+    _io_cap_lookup = {
+        IoCapabilities.DISPLAY_ONLY:
+        hci_packets.IoCapability.DISPLAY_ONLY,
+        IoCapabilities.DISPLAY_YES_NO_IO_CAP:
+        hci_packets.IoCapability.DISPLAY_YES_NO,
+        IoCapabilities.KEYBOARD_ONLY:
+        hci_packets.IoCapability.KEYBOARD_ONLY,
+        IoCapabilities.NO_INPUT_NO_OUTPUT:
+        hci_packets.IoCapability.NO_INPUT_NO_OUTPUT,
+    }
+
+    _auth_req_lookup = {
+        AuthenticationRequirements.NO_BONDING:
+        hci_packets.AuthenticationRequirements.NO_BONDING,
+        AuthenticationRequirements.NO_BONDING_MITM_PROTECTION:
+        hci_packets.AuthenticationRequirements.NO_BONDING_MITM_PROTECTION,
+        AuthenticationRequirements.DEDICATED_BONDING:
+        hci_packets.AuthenticationRequirements.DEDICATED_BONDING,
+        AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION:
+        hci_packets.AuthenticationRequirements.
+        DEDICATED_BONDING_MITM_PROTECTION,
+        AuthenticationRequirements.GENERAL_BONDING:
+        hci_packets.AuthenticationRequirements.GENERAL_BONDING,
+        AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION:
+        hci_packets.AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION,
+    }
+
+    _oob_present_lookup = {
+        OobDataPresent.NOT_PRESENT:
+        hci_packets.OobDataPresent.NOT_PRESENT,
+        OobDataPresent.P192_PRESENT:
+        hci_packets.OobDataPresent.P_192_PRESENT,
+        OobDataPresent.P256_PRESENT:
+        hci_packets.OobDataPresent.P_256_PRESENT,
+        OobDataPresent.P192_AND_256_PRESENT:
+        hci_packets.OobDataPresent.P_192_AND_256_PRESENT,
+    }
+
+    _hci_event_stream = None
+    _io_caps = hci_packets.IoCapability.DISPLAY_ONLY
+    _oob_data = hci_packets.OobDataPresent.NOT_PRESENT
+    _auth_reqs = hci_packets.AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
+
+    _hci = None
+
+    def _enqueue_hci_command(self, command, expect_complete):
+        if (expect_complete):
+            self._hci.send_command_with_complete(command)
+        else:
+            self._hci.send_command_with_status(command)
+
+    def __init__(self, device):
+        """
+            Don't call super b/c the gRPC stream setup will crash test
+        """
+        logging.info("Cert: Init")
+        self._device = device
+        self._device.wait_channel_ready()
+        self._hci = PyHci(device)
+        self._hci.register_for_events(
+            hci_packets.EventCode.LINK_KEY_REQUEST,
+            hci_packets.EventCode.IO_CAPABILITY_REQUEST,
+            hci_packets.EventCode.IO_CAPABILITY_RESPONSE,
+            hci_packets.EventCode.USER_PASSKEY_NOTIFICATION,
+            hci_packets.EventCode.USER_PASSKEY_REQUEST,
+            hci_packets.EventCode.USER_CONFIRMATION_REQUEST,
+            hci_packets.EventCode.REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION,
+            hci_packets.EventCode.LINK_KEY_NOTIFICATION,
+            hci_packets.EventCode.SIMPLE_PAIRING_COMPLETE)
+        self._hci_event_stream = self._hci.get_event_stream()
+
+    def create_bond(self, address, type):
+        """
+            Creates a bond from the cert perspective
+        """
+        logging.info("Cert: Creating bond to '%s' from '%s'" %
+                     (str(address), str(self._device.address)))
+        # TODO(optedoblivion): Trigger connection to Send AuthenticationRequested
+
+    def remove_bond(self, address):
+        """
+            We store the link key locally in the test and pretend
+            So to remove_bond we need to Remove the "stored" data
+        """
+        pass
+
+    def set_io_capabilities(self, io_capabilities):
+        """
+            Set the IO Capabilities used for the cert
+        """
+        logging.info(
+            "Cert: setting IO Capabilities data to '%s'" % io_capabilities)
+        self._io_caps = self._io_cap_lookup.get(
+            io_capabilities, hci_packets.IoCapability.DISPLAY_YES_NO)
+
+    def set_authentication_requirements(self, auth_reqs):
+        """
+            Establish authentication requirements for the stack
+        """
+        logging.info("Cert: setting Authentication Requirements data to '%s'" %
+                     auth_reqs)
+        self._auth_reqs = self._auth_req_lookup.get(
+            auth_reqs, hci_packets.AuthenticationRequirements.GENERAL_BONDING)
+
+    def set_oob_data(self, data):
+        """
+            Set the Out-of-band data for SSP pairing
+        """
+        logging.info("Cert: setting OOB data present to '%s'" % data)
+        self._oob_data = self._oob_present_lookup.get(
+            data, hci_packets.OobDataPresent.NOT_PRESENT)
+
+    def send_ui_callback(self, address, callback_type, b, uid):
+        """
+            Pretend to answer the pairing dailog as a user
+        """
+        logging.info(
+            "Cert: Send user input callback uid:%d; response: %s" % (uid, b))
+        # TODO(optedoblivion): Make callback and set it to the module
+
+    def enable_secure_simple_pairing(self):
+        """
+            This is called when you want to enable SSP for testing
+        """
+        logging.info("Cert: Sending WRITE_SIMPLE_PAIRING_MODE [True]")
+        self._enqueue_hci_command(
+            hci_packets.WriteSimplePairingModeBuilder(
+                hci_packets.Enable.ENABLED), True)
+        logging.info("Cert: Waiting for controller response")
+        self._hci_event_stream.assert_event_occurs(
+            lambda msg: b'\x0e\x04\x01\x56\x0c' in msg.event)
+
+    def accept_pairing(self, dut_address, reply_boolean):
+        """
+            Here we handle the pairing events at the HCI level
+        """
+        logging.info("Cert: Waiting for LINK_KEY_REQUEST")
+        self._hci_event_stream.assert_event_occurs(
+            lambda event: logging.debug(event.event) or hci_packets.EventCode.LINK_KEY_REQUEST in event.event
+        )
+        logging.info("Cert: Sending LINK_KEY_REQUEST_NEGATIVE_REPLY")
+        self._enqueue_hci_command(
+            hci_packets.LinkKeyRequestNegativeReplyBuilder(
+                dut_address.decode('utf8')), True)
+        logging.info("Cert: Waiting for IO_CAPABILITY_REQUEST")
+        self._hci_event_stream.assert_event_occurs(
+            lambda event: logging.debug(event.event) or hci_packets.EventCode.IO_CAPABILITY_REQUEST in event.event
+        )
+        logging.info("Cert: Sending IO_CAPABILITY_REQUEST_REPLY")
+
+        self._enqueue_hci_command(
+            hci_packets.IoCapabilityRequestReplyBuilder(
+                dut_address.decode('utf8'), self._io_caps, self._oob_data,
+                self._auth_reqs), True)
+
+        logging.info("Cert: Waiting for USER_CONFIRMATION_REQUEST")
+        self._hci_event_stream.assert_event_occurs(
+            lambda event: logging.debug(event.event) or hci_packets.EventCode.USER_CONFIRMATION_REQUEST in event.event
+        )
+        logging.info(
+            "Cert: Sending Simulated User Response '%s'" % reply_boolean)
+        if reply_boolean:
+            logging.info("Cert: Sending USER_CONFIRMATION_REQUEST_REPLY")
+            self._enqueue_hci_command(
+                hci_packets.UserConfirmationRequestReplyBuilder(
+                    dut_address.decode('utf8')), True)
+            logging.info("Cert: Waiting for LINK_KEY_NOTIFICATION")
+            self._hci_event_stream.assert_event_occurs(
+                lambda event: logging.debug(event.event) or hci_packets.EventCode.LINK_KEY_NOTIFICATION in event.event
+            )
+            logging.info("Cert: Waiting for SIMPLE_PAIRING_COMPLETE")
+            self._hci_event_stream.assert_event_occurs(
+                lambda event: logging.debug(event.event) or hci_packets.EventCode.SIMPLE_PAIRING_COMPLETE in event.event
+            )
+        else:
+            logging.info(
+                "Cert: Sending USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY")
+            self._enqueue_hci_command(
+                hci_packets.UserConfirmationRequestNegativeReplyBuilder(
+                    dut_address.decode('utf8')), True)
+            logging.info("Cert: Waiting for SIMPLE_PAIRING_COMPLETE")
+            self._hci_event_stream.assert_event_occurs(
+                lambda event: logging.debug(event.event) or hci_packets.EventCode.SIMPLE_PAIRING_COMPLETE in event.event
+            )
+
+    def on_user_input(self, dut_address, reply_boolean, expected_ui_event):
+        """
+            Cert doesn't need the test to respond to the ui event
+            Cert responds in accept pairing
+        """
+        pass
+
+    def wait_for_bond_event(self, expected_bond_event):
+        """
+            A bond event will be triggered once the bond process
+            is complete.  For the DUT we need to wait for it,
+            for Cert it isn't needed.
+        """
+        pass
+
+    def close(self):
+        safeClose(self._hci)