Snap for 7550740 from 9cdf080f39ba9e5781f21c0a90ed6a8e0252c728 to sdk-release

Change-Id: I88b01dfc5ba25c1002812d8bf7cb583fed63985e
diff --git a/binder/android/bluetooth/IBluetoothGatt.aidl b/binder/android/bluetooth/IBluetoothGatt.aidl
index 49bb513..201be2c 100644
--- a/binder/android/bluetooth/IBluetoothGatt.aidl
+++ b/binder/android/bluetooth/IBluetoothGatt.aidl
@@ -46,7 +46,7 @@
     void registerScanner(in IScannerCallback callback, in WorkSource workSource);
     void unregisterScanner(in int scannerId);
     void startScan(in int scannerId, in ScanSettings settings, in List<ScanFilter> filters,
-                   in List scanStorages, in String callingPackage, String callingFeatureId);
+                   in String callingPackage, String callingFeatureId);
     void startScanForIntent(in PendingIntent intent, in ScanSettings settings, in List<ScanFilter> filters,
                             in String callingPackage, String callingFeatureId);
     void stopScanForIntent(in PendingIntent intent, in String callingPackage);
@@ -86,7 +86,7 @@
     void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq);
     void readUsingCharacteristicUuid(in int clientIf, in String address, in ParcelUuid uuid,
                            in int startHandle, in int endHandle, in int authReq);
-    void writeCharacteristic(in int clientIf, in String address, in int handle,
+    int writeCharacteristic(in int clientIf, in String address, in int handle,
                             in int writeType, in int authReq, in byte[] value);
     void readDescriptor(in int clientIf, in String address, in int handle, in int authReq);
     void writeDescriptor(in int clientIf, in String address, in int handle,
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index 4636120..b108316 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -2115,7 +2115,7 @@
   }
   APPL_TRACE_ERROR(
       "%s: peer %s : Invalid peer UUID: 0x%x for bta_av_handle 0x%x",
-      peer_address.ToString().c_str(), peer_uuid, bta_av_handle);
+      __func__, peer_address.ToString().c_str(), peer_uuid, bta_av_handle);
   return A2DP_FAIL;
 }
 
diff --git a/build/Android.bp b/build/Android.bp
index 9d42342..eaa8e9a 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -76,6 +76,9 @@
     target: {
         android: {
             test_config_template: ":BluetoothTestConfigTemplate",
+            sanitize: {
+                misc_undefined: ["bounds"],
+            },
         },
     },
     defaults: ["fluoride_types_defaults_fuzzable"],
@@ -94,9 +97,6 @@
         "libcutils",
     ],
     cpp_std: "c++17",
-    sanitize: {
-        misc_undefined: ["bounds"],
-    },
 }
 
 fluoride_defaults {
@@ -111,9 +111,6 @@
         "libutils",
 
     ],
-    sanitize: {
-        misc_undefined: ["bounds"],
-    },
     static_libs: [
         "libbluetooth_gd",
         "libbluetooth_rust_interop",
@@ -132,6 +129,9 @@
             cflags: [
                 "-DOS_ANDROID",
             ],
+            sanitize: {
+                misc_undefined: ["bounds"],
+            },
         },
     },
 }
diff --git a/gd/Android.bp b/gd/Android.bp
index 17518c4..ea792b7 100644
--- a/gd/Android.bp
+++ b/gd/Android.bp
@@ -20,6 +20,9 @@
             shared_libs: [
                 "liblog",
             ],
+            sanitize: {
+                misc_undefined: ["bounds"],
+            },
         },
         host: {
             cflags: [
@@ -43,9 +46,7 @@
         "-std=c99",
     ],
     header_libs: ["jni_headers"],
-    sanitize: {
-        misc_undefined: ["bounds"],
-    },
+
 }
 
 // Enables code coverage for a set of source files. Must be combined with
diff --git a/gd/cert/matchers.py b/gd/cert/matchers.py
index 5d8fa1f..6979442 100644
--- a/gd/cert/matchers.py
+++ b/gd/cert/matchers.py
@@ -208,6 +208,19 @@
         return lambda event: data == event.payload
 
 
+class AdvertisingMatchers(object):
+
+    @staticmethod
+    def CallbackMsg(type, advertiser_id=None, status=None, data=None):
+        return lambda event: True if event.message_type == type and (advertiser_id == None or advertiser_id == event.advertiser_id) \
+            and (status == None or status == event.status) and (data == None or data == event.data) else False
+
+    @staticmethod
+    def AddressMsg(type, advertiser_id=None, address=None):
+        return lambda event: True if event.message_type == type and (advertiser_id == None or advertiser_id == event.advertiser_id) \
+            and (address == None or address == event.address) else False
+
+
 class NeighborMatchers(object):
 
     @staticmethod
diff --git a/gd/common/init_flags.cc b/gd/common/init_flags.cc
index a7569b8..c119aa6 100644
--- a/gd/common/init_flags.cc
+++ b/gd/common/init_flags.cc
@@ -18,6 +18,7 @@
 
 #include "init_flags.h"
 
+#include <cstdlib>
 #include <string>
 
 #include "common/strings.h"
@@ -27,6 +28,7 @@
 namespace common {
 
 bool InitFlags::logging_debug_enabled_for_all = false;
+int InitFlags::hci_adapter = 0;
 std::unordered_map<std::string, bool> InitFlags::logging_debug_explicit_tag_settings = {};
 
 bool ParseBoolFlag(const std::vector<std::string>& flag_pair, const std::string& flag, bool* variable) {
@@ -41,6 +43,19 @@
   return true;
 }
 
+bool ParseIntFlag(const std::vector<std::string>& flag_pair, const std::string& flag, int* variable) {
+  if (flag != flag_pair[0]) {
+    return false;
+  }
+  auto value = Int64FromString(flag_pair[1]);
+  if (!value || *value > INT32_MAX) {
+    return false;
+  }
+
+  *variable = *value;
+  return true;
+}
+
 void InitFlags::Load(const char** flags) {
   const char** flags_copy = flags;
   SetAll(false);
@@ -52,6 +67,9 @@
       continue;
     }
 
+    // Parse adapter index (defaults to 0)
+    ParseIntFlag(flag_pair, "--hci", &hci_adapter);
+
     ParseBoolFlag(flag_pair, "INIT_logging_debug_enabled_for_all", &logging_debug_enabled_for_all);
     if ("INIT_logging_debug_enabled_for_tags" == flag_pair[0]) {
       auto tags = StringSplit(flag_pair[1], ",");
diff --git a/gd/common/init_flags.h b/gd/common/init_flags.h
index 11af2a1..250e4f5 100644
--- a/gd/common/init_flags.h
+++ b/gd/common/init_flags.h
@@ -41,11 +41,16 @@
     return logging_debug_enabled_for_all;
   }
 
+  inline static int GetAdapterIndex() {
+    return hci_adapter;
+  }
+
   static void SetAllForTesting();
 
  private:
   static void SetAll(bool value);
   static bool logging_debug_enabled_for_all;
+  static int hci_adapter;
   // save both log allow list and block list in the map to save hashing time
   static std::unordered_map<std::string, bool> logging_debug_explicit_tag_settings;
 };
diff --git a/gd/grpc/grpc_event_queue.h b/gd/grpc/grpc_event_queue.h
index 9575b2d..089c3d0 100644
--- a/gd/grpc/grpc_event_queue.h
+++ b/gd/grpc/grpc_event_queue.h
@@ -50,12 +50,10 @@
   ::grpc::Status RunLoop(::grpc::ServerContext* context, ::grpc::ServerWriter<T>* writer) {
     using namespace std::chrono_literals;
     LOG_INFO("%s: Entering Loop", log_name_.c_str());
-    pending_events_.clear();
-    running_ = true;
     while (!context->IsCancelled()) {
       // Wait for 500 ms so that cancellation can be caught in amortized 250 ms latency
       if (pending_events_.wait_to_take(500ms)) {
-        LOG_INFO("%s: Got event after queue", log_name_.c_str());
+        LOG_INFO("%s: Got event from queue", log_name_.c_str());
         writer->Write(pending_events_.take());
       }
     }
@@ -73,13 +71,13 @@
       LOG_INFO("%s: Discarding an event while not running the loop", log_name_.c_str());
       return;
     }
-    LOG_INFO("%s: Got event before queue", log_name_.c_str());
+    LOG_INFO("%s: Got event, enqueuing", log_name_.c_str());
     pending_events_.push(std::move(event));
   }
 
  private:
   std::string log_name_;
-  std::atomic<bool> running_ = false;
+  std::atomic<bool> running_{true};
   common::BlockingQueue<T> pending_events_;
 };
 
diff --git a/gd/hci/cert/le_advertising_manager_test_lib.py b/gd/hci/cert/le_advertising_manager_test_lib.py
index 10e0ce6..f044316 100644
--- a/gd/hci/cert/le_advertising_manager_test_lib.py
+++ b/gd/hci/cert/le_advertising_manager_test_lib.py
@@ -18,38 +18,74 @@
 import sys
 import logging
 
+from bluetooth_packets_python3 import hci_packets
 from cert.event_stream import EventStream
-from google.protobuf import empty_pb2 as empty_proto
+from cert.closable import Closable
+from cert.closable import safeClose
+from cert.matchers import AdvertisingMatchers
+from cert.py_hci import PyHci
+from cert.truth import assertThat
+from facade import common_pb2 as common
 from facade import rootservice_pb2 as facade_rootservice
+from google.protobuf import empty_pb2 as empty_proto
 from hci.facade import hci_facade_pb2 as hci_facade
 from hci.facade import \
   le_advertising_manager_facade_pb2 as le_advertising_facade
 from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade
-from bluetooth_packets_python3 import hci_packets
-from facade import common_pb2 as common
-from cert.py_hci import PyHci
-from cert.truth import assertThat
+from hci.facade.le_advertising_manager_facade_pb2 import AdvertisingStatus
+from hci.facade.le_advertising_manager_facade_pb2 import CallbackMsgType
 
 
 class LeAdvertisingManagerTestBase():
 
     def setup_test(self, cert):
         self.cert_hci = PyHci(cert, acl_streaming=True)
+        self.dut.callback_event_stream = EventStream(
+            self.dut.hci_le_advertising_manager.FetchCallbackEvents(empty_proto.Empty()))
+        self.dut.address_event_stream = EventStream(
+            self.dut.hci_le_advertising_manager.FetchAddressEvents(empty_proto.Empty()))
 
     def teardown_test(self):
         self.cert_hci.close()
+        if self.dut.callback_event_stream is not None:
+            safeClose(self.dut.callback_event_stream)
+        else:
+            logging.info("DUT: Callback Event Stream is None!")
+        if self.dut.address_event_stream is not None:
+            safeClose(self.dut.address_event_stream)
+        else:
+            logging.info("DUT: address Event Stream is None!")
 
-    def test_le_ad_scan_dut_advertises(self):
+    def set_address_policy_with_static_address(self):
         privacy_policy = le_initiator_address_facade.PrivacyPolicy(
             address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS,
             address_with_type=common.BluetoothAddressWithType(
-                address=common.BluetoothAddress(address=bytes(b'D0:05:04:03:02:01')),
+                address=common.BluetoothAddress(address=bytes(b'd0:05:04:03:02:01')),
                 type=common.RANDOM_DEVICE_ADDRESS),
             rotation_irk=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
             minimum_rotation_time=0,
             maximum_rotation_time=0)
         self.dut.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(privacy_policy)
 
+    def create_advertiser(self):
+        gap_name = hci_packets.GapData()
+        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+        gap_name.data = list(bytes(b'Im_The_DUT'))
+        gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+        config = le_advertising_facade.AdvertisingConfig(
+            advertisement=[gap_data],
+            interval_min=512,
+            interval_max=768,
+            advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+            own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+            channel_map=7,
+            filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+        request = le_advertising_facade.CreateAdvertiserRequest(config=config)
+        create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
+        return create_response
+
+    def test_le_ad_scan_dut_advertises(self):
+        self.set_address_policy_with_static_address()
         self.cert_hci.register_for_le_events(hci_packets.SubeventCode.ADVERTISING_REPORT,
                                              hci_packets.SubeventCode.EXTENDED_ADVERTISING_REPORT)
 
@@ -67,7 +103,34 @@
             hci_packets.LeSetExtendedScanEnableBuilder(hci_packets.Enable.ENABLED,
                                                        hci_packets.FilterDuplicates.DISABLED, 0, 0))
 
-        # DUT Advertises
+        create_response = self.create_advertiser()
+
+        assertThat(self.cert_hci.get_le_event_stream()).emits(lambda packet: b'Im_The_DUT' in packet.payload)
+
+        remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id)
+        self.dut.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
+        self.cert_hci.send_command(
+            hci_packets.LeSetScanEnableBuilder(hci_packets.Enable.DISABLED, hci_packets.Enable.DISABLED))
+
+    def test_extended_create_advertises(self):
+        self.set_address_policy_with_static_address()
+        self.cert_hci.register_for_le_events(hci_packets.SubeventCode.ADVERTISING_REPORT,
+                                             hci_packets.SubeventCode.EXTENDED_ADVERTISING_REPORT)
+
+        # CERT Scans
+        self.cert_hci.send_command(hci_packets.LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
+        scan_parameters = hci_packets.PhyScanParameters()
+        scan_parameters.le_scan_type = hci_packets.LeScanType.ACTIVE
+        scan_parameters.le_scan_interval = 40
+        scan_parameters.le_scan_window = 20
+        self.cert_hci.send_command(
+            hci_packets.LeSetExtendedScanParametersBuilder(hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
+                                                           hci_packets.LeScanningFilterPolicy.ACCEPT_ALL, 1,
+                                                           [scan_parameters]))
+        self.cert_hci.send_command(
+            hci_packets.LeSetExtendedScanEnableBuilder(hci_packets.Enable.ENABLED,
+                                                       hci_packets.FilterDuplicates.DISABLED, 0, 0))
+
         gap_name = hci_packets.GapData()
         gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
         gap_name.data = list(bytes(b'Im_The_DUT'))
@@ -80,9 +143,22 @@
             own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
             channel_map=7,
             filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
-        request = le_advertising_facade.CreateAdvertiserRequest(config=config)
-
-        create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)
+        extended_config = le_advertising_facade.ExtendedAdvertisingConfig(
+            advertising_config=config,
+            connectable=True,
+            scannable=False,
+            directed=False,
+            high_duty_directed_connectable=False,
+            legacy_pdus=True,
+            anonymous=False,
+            include_tx_power=True,
+            use_le_coded_phy=False,
+            secondary_max_skip=0x00,
+            secondary_advertising_phy=0x01,
+            sid=0x00,
+            enable_scan_request_notifications=0x00)
+        request = le_advertising_facade.ExtendedCreateAdvertiserRequest(config=extended_config)
+        create_response = self.dut.hci_le_advertising_manager.ExtendedCreateAdvertiser(request)
 
         assertThat(self.cert_hci.get_le_event_stream()).emits(lambda packet: b'Im_The_DUT' in packet.payload)
 
@@ -90,3 +166,145 @@
         self.dut.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
         self.cert_hci.send_command(
             hci_packets.LeSetScanEnableBuilder(hci_packets.Enable.DISABLED, hci_packets.Enable.DISABLED))
+
+    def test_advertising_set_started_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.ADVERTISING_SET_STARTED, create_response.advertiser_id,
+                                            AdvertisingStatus.SUCCESS, 0x00))
+
+    def test_enable_advertiser_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+        enable_advertiser_request = le_advertising_facade.EnableAdvertiserRequest(
+            advertiser_id=create_response.advertiser_id, enable=True)
+        self.dut.hci_le_advertising_manager.EnableAdvertiser(enable_advertiser_request)
+
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.ADVERTISING_ENABLED, create_response.advertiser_id,
+                                            AdvertisingStatus.SUCCESS, 0x01))
+
+    def test_disable_advertiser_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+        disable_advertiser_request = le_advertising_facade.EnableAdvertiserRequest(
+            advertiser_id=create_response.advertiser_id, enable=False)
+        self.dut.hci_le_advertising_manager.EnableAdvertiser(disable_advertiser_request)
+
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.ADVERTISING_ENABLED, create_response.advertiser_id,
+                                            AdvertisingStatus.SUCCESS, 0x00))
+
+    def test_set_advertising_data_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+        gap_name = hci_packets.GapData()
+        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+        gap_name.data = list(bytes(b'Im_The_DUT2'))
+        gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+
+        set_data_request = le_advertising_facade.SetDataRequest(
+            advertiser_id=create_response.advertiser_id, set_scan_rsp=False, data=[gap_data])
+        self.dut.hci_le_advertising_manager.SetData(set_data_request)
+
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.ADVERTISING_DATA_SET, create_response.advertiser_id,
+                                            AdvertisingStatus.SUCCESS))
+
+    def test_set_scan_response_data_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+        gap_name = hci_packets.GapData()
+        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+        gap_name.data = list(bytes(b'Im_The_DUT2'))
+        gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+
+        set_data_request = le_advertising_facade.SetDataRequest(
+            advertiser_id=create_response.advertiser_id, set_scan_rsp=True, data=[gap_data])
+        self.dut.hci_le_advertising_manager.SetData(set_data_request)
+
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.SCAN_RESPONSE_DATA_SET, create_response.advertiser_id,
+                                            AdvertisingStatus.SUCCESS))
+
+    def test_set_parameters_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+
+        # The Host shall not issue set parameters command when advertising is enabled
+        disable_advertiser_request = le_advertising_facade.EnableAdvertiserRequest(
+            advertiser_id=create_response.advertiser_id, enable=False)
+        self.dut.hci_le_advertising_manager.EnableAdvertiser(disable_advertiser_request)
+
+        config = le_advertising_facade.AdvertisingConfig(
+            interval_min=512,
+            interval_max=768,
+            advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
+            own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
+            channel_map=7,
+            filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
+
+        set_parameters_request = le_advertising_facade.SetParametersRequest(
+            advertiser_id=create_response.advertiser_id, config=config)
+        self.dut.hci_le_advertising_manager.SetParameters(set_parameters_request)
+
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.ADVERTISING_PARAMETERS_UPDATED,
+                                            create_response.advertiser_id, AdvertisingStatus.SUCCESS))
+
+    def test_set_periodic_parameters_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+
+        config = le_advertising_facade.PeriodicAdvertisingParameters(
+            min_interval=512,
+            max_interval=768,
+            advertising_property=le_advertising_facade.AdvertisingProperty.INCLUDE_TX_POWER)
+
+        set_periodic_parameters_request = le_advertising_facade.SetPeriodicParametersRequest(
+            advertiser_id=create_response.advertiser_id, config=config)
+        self.dut.hci_le_advertising_manager.SetPeriodicParameters(set_periodic_parameters_request)
+
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.PERIODIC_ADVERTISING_PARAMETERS_UPDATED,
+                                            create_response.advertiser_id))
+
+    def test_set_periodic_data_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+        gap_name = hci_packets.GapData()
+        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
+        gap_name.data = list(bytes(b'Im_The_DUT2'))
+        gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
+
+        set_periodic_data_request = le_advertising_facade.SetPeriodicDataRequest(
+            advertiser_id=create_response.advertiser_id, data=[gap_data])
+        self.dut.hci_le_advertising_manager.SetPeriodicData(set_periodic_data_request)
+
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.PERIODIC_ADVERTISING_DATA_SET,
+                                            create_response.advertiser_id))
+
+    def test_enable_periodic_advertising_callback(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+        enable_periodic_advertising_request = le_advertising_facade.EnablePeriodicAdvertisingRequest(
+            advertiser_id=create_response.advertiser_id, enable=True)
+        self.dut.hci_le_advertising_manager.EnablePeriodicAdvertising(enable_periodic_advertising_request)
+
+        assertThat(self.dut.callback_event_stream).emits(
+            AdvertisingMatchers.CallbackMsg(CallbackMsgType.PERIODIC_ADVERTISING_ENABLED,
+                                            create_response.advertiser_id))
+
+    def test_get_own_address(self):
+        self.set_address_policy_with_static_address()
+        create_response = self.create_advertiser()
+        get_own_address_request = le_advertising_facade.GetOwnAddressRequest(
+            advertiser_id=create_response.advertiser_id)
+        self.dut.hci_le_advertising_manager.GetOwnAddress(get_own_address_request)
+        address_with_type = common.BluetoothAddressWithType(
+            address=common.BluetoothAddress(address=bytes(b'd0:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
+        assertThat(self.dut.address_event_stream).emits(
+            AdvertisingMatchers.AddressMsg(CallbackMsgType.OWN_ADDRESS_READ, create_response.advertiser_id,
+                                           address_with_type))
diff --git a/gd/hci/facade/le_advertising_manager_facade.cc b/gd/hci/facade/le_advertising_manager_facade.cc
index 8e017bb..7d370f8 100644
--- a/gd/hci/facade/le_advertising_manager_facade.cc
+++ b/gd/hci/facade/le_advertising_manager_facade.cc
@@ -20,6 +20,7 @@
 
 #include "common/bidi_queue.h"
 #include "common/bind.h"
+#include "grpc/grpc_event_queue.h"
 #include "hci/address.h"
 #include "hci/address_with_type.h"
 #include "hci/facade/le_advertising_manager_facade.grpc.pb.h"
@@ -50,7 +51,7 @@
   return gap_data;
 }
 
-bool AdvertisingConfigFromProto(const AdvertisingConfig& config_proto, hci::AdvertisingConfig* config) {
+bool AdvertisingConfigFromProto(const AdvertisingConfig& config_proto, hci::ExtendedAdvertisingConfig* config) {
   for (const auto& elem : config_proto.advertisement()) {
     config->advertisement.push_back(GapDataFromProto(elem));
   }
@@ -93,6 +94,47 @@
   config->filter_policy = static_cast<hci::AdvertisingFilterPolicy>(config_proto.filter_policy());
 
   config->tx_power = static_cast<uint8_t>(config_proto.tx_power());
+
+  config->legacy_pdus = true;
+  return true;
+}
+
+bool ExtendedAdvertisingConfigFromProto(
+    const ExtendedAdvertisingConfig& config_proto, hci::ExtendedAdvertisingConfig* config) {
+  if (!AdvertisingConfigFromProto(config_proto.advertising_config(), config)) {
+    LOG_WARN("Error parsing advertising config");
+    return false;
+  }
+  config->connectable = config_proto.connectable();
+  config->scannable = config_proto.scannable();
+  config->directed = config_proto.directed();
+  config->high_duty_directed_connectable = config_proto.high_duty_directed_connectable();
+  config->legacy_pdus = config_proto.legacy_pdus();
+  config->anonymous = config_proto.anonymous();
+  config->include_tx_power = config_proto.include_tx_power();
+  config->use_le_coded_phy = config_proto.use_le_coded_phy();
+  config->secondary_max_skip = static_cast<uint8_t>(config_proto.secondary_max_skip());
+  config->secondary_advertising_phy = static_cast<hci::SecondaryPhyType>(config_proto.secondary_advertising_phy());
+  config->sid = static_cast<uint8_t>(config_proto.sid());
+  config->enable_scan_request_notifications =
+      static_cast<hci::Enable>(config_proto.enable_scan_request_notifications());
+  return true;
+}
+
+bool PeriodicAdvertisingParametersFromProto(
+    const PeriodicAdvertisingParameters& config_proto, hci::PeriodicAdvertisingParameters* config) {
+  if (config_proto.min_interval() > UINT16_MAX || config_proto.min_interval() < 0) {
+    LOG_WARN("Bad interval_min: %d", config_proto.min_interval());
+    return false;
+  }
+  config->min_interval = static_cast<uint16_t>(config_proto.min_interval());
+  if (config_proto.max_interval() > UINT16_MAX || config_proto.max_interval() < 0) {
+    LOG_WARN("Bad interval_max: %d", config_proto.max_interval());
+    return false;
+  }
+  config->max_interval = static_cast<uint16_t>(config_proto.max_interval());
+  config->properties =
+      static_cast<hci::PeriodicAdvertisingParameters::AdvertisingProperty>(config_proto.advertising_property());
   return true;
 }
 
@@ -117,7 +159,7 @@
   hci::AdvertisingConfig config_;
 };
 
-class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Service {
+class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Service, AdvertisingCallback {
  public:
   LeAdvertisingManagerFacadeService(LeAdvertisingManager* le_advertising_manager, os::Handler* facade_handler)
       : le_advertising_manager_(le_advertising_manager), facade_handler_(facade_handler) {
@@ -135,7 +177,7 @@
     }
     LeAdvertiser le_advertiser(config);
     auto advertiser_id = le_advertising_manager_->ExtendedCreateAdvertiser(
-        -1,
+        0,
         config,
         common::Bind(&LeAdvertiser::ScanCallback, common::Unretained(&le_advertiser)),
         common::Bind(&LeAdvertiser::TerminatedCallback, common::Unretained(&le_advertiser)),
@@ -155,9 +197,102 @@
   ::grpc::Status ExtendedCreateAdvertiser(::grpc::ServerContext* context,
                                           const ExtendedCreateAdvertiserRequest* request,
                                           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");
+    hci::ExtendedAdvertisingConfig config = {};
+    if (!ExtendedAdvertisingConfigFromProto(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_->ExtendedCreateAdvertiser(
+        0,
+        config,
+        common::Bind(&LeAdvertiser::ScanCallback, common::Unretained(&le_advertiser)),
+        common::Bind(&LeAdvertiser::TerminatedCallback, common::Unretained(&le_advertiser)),
+        0,
+        0,
+        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 EnableAdvertiser(
+      ::grpc::ServerContext* context,
+      const EnableAdvertiserRequest* request,
+      ::google::protobuf::Empty* response) override {
+    le_advertising_manager_->EnableAdvertiser(request->advertiser_id(), request->enable(), 0, 0);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SetData(
+      ::grpc::ServerContext* context, const SetDataRequest* request, ::google::protobuf::Empty* response) override {
+    std::vector<GapData> advertising_data = {};
+    for (const auto& elem : request->data()) {
+      advertising_data.push_back(GapDataFromProto(elem));
+    }
+    le_advertising_manager_->SetData(request->advertiser_id(), request->set_scan_rsp(), advertising_data);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SetParameters(
+      ::grpc::ServerContext* context,
+      const SetParametersRequest* request,
+      ::google::protobuf::Empty* response) override {
+    hci::ExtendedAdvertisingConfig config = {};
+    if (!AdvertisingConfigFromProto(request->config(), &config)) {
+      LOG_WARN("Error parsing advertising config %s", request->SerializeAsString().c_str());
+      return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Error while parsing advertising config");
+    }
+    le_advertising_manager_->SetParameters(request->advertiser_id(), config);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SetPeriodicParameters(
+      ::grpc::ServerContext* context,
+      const SetPeriodicParametersRequest* request,
+      ::google::protobuf::Empty* response) override {
+    hci::PeriodicAdvertisingParameters config = {};
+    if (!PeriodicAdvertisingParametersFromProto(request->config(), &config)) {
+      LOG_WARN("Error parsing periodic advertising parameters %s", request->SerializeAsString().c_str());
+      return ::grpc::Status(
+          ::grpc::StatusCode::INVALID_ARGUMENT, "Error while parsing periodic advertising parameters");
+    }
+    le_advertising_manager_->SetPeriodicParameters(request->advertiser_id(), config);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SetPeriodicData(
+      ::grpc::ServerContext* context,
+      const SetPeriodicDataRequest* request,
+      ::google::protobuf::Empty* response) override {
+    std::vector<GapData> advertising_data = {};
+    for (const auto& elem : request->data()) {
+      advertising_data.push_back(GapDataFromProto(elem));
+    }
+    le_advertising_manager_->SetPeriodicData(request->advertiser_id(), advertising_data);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status EnablePeriodicAdvertising(
+      ::grpc::ServerContext* context,
+      const EnablePeriodicAdvertisingRequest* request,
+      ::google::protobuf::Empty* response) override {
+    le_advertising_manager_->EnablePeriodicAdvertising(request->advertiser_id(), request->enable());
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status GetOwnAddress(
+      ::grpc::ServerContext* context,
+      const GetOwnAddressRequest* request,
+      ::google::protobuf::Empty* response) override {
+    le_advertising_manager_->GetOwnAddress(request->advertiser_id());
+    return ::grpc::Status::OK;
   }
 
   ::grpc::Status GetNumberOfAdvertisingInstances(::grpc::ServerContext* context,
@@ -184,9 +319,104 @@
     return ::grpc::Status::OK;
   }
 
+  ::grpc::Status FetchCallbackEvents(
+      ::grpc::ServerContext* context,
+      const ::google::protobuf::Empty* request,
+      ::grpc::ServerWriter<CallbackMsg>* writer) override {
+    le_advertising_manager_->RegisterAdvertisingCallback(this);
+    return callback_events_.RunLoop(context, writer);
+  }
+
+  ::grpc::Status FetchAddressEvents(
+      ::grpc::ServerContext* context,
+      const ::google::protobuf::Empty* request,
+      ::grpc::ServerWriter<AddressMsg>* writer) override {
+    return address_events_.RunLoop(context, writer);
+  }
+
+  void OnAdvertisingSetStarted(int reg_id, uint8_t advertiser_id, int8_t tx_power, AdvertisingStatus status) {
+    CallbackMsg msg;
+    msg.set_message_type(CallbackMsgType::ADVERTISING_SET_STARTED);
+    msg.set_advertiser_id(advertiser_id);
+    msg.set_status(static_cast<facade::AdvertisingStatus>(status));
+    msg.set_data(reg_id);
+    callback_events_.OnIncomingEvent(msg);
+  };
+
+  void OnAdvertisingEnabled(uint8_t advertiser_id, bool enable, uint8_t status) {
+    CallbackMsg msg;
+    msg.set_message_type(CallbackMsgType::ADVERTISING_ENABLED);
+    msg.set_advertiser_id(advertiser_id);
+    msg.set_status(static_cast<facade::AdvertisingStatus>(status));
+    msg.set_data(enable ? 1 : 0);
+    callback_events_.OnIncomingEvent(msg);
+  };
+
+  void OnAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) {
+    CallbackMsg msg;
+    msg.set_message_type(CallbackMsgType::ADVERTISING_DATA_SET);
+    msg.set_advertiser_id(advertiser_id);
+    msg.set_status(static_cast<facade::AdvertisingStatus>(status));
+    callback_events_.OnIncomingEvent(msg);
+  };
+
+  void OnScanResponseDataSet(uint8_t advertiser_id, uint8_t status) {
+    CallbackMsg msg;
+    msg.set_message_type(CallbackMsgType::SCAN_RESPONSE_DATA_SET);
+    msg.set_advertiser_id(advertiser_id);
+    msg.set_status(static_cast<facade::AdvertisingStatus>(status));
+    callback_events_.OnIncomingEvent(msg);
+  };
+
+  void OnAdvertisingParametersUpdated(uint8_t advertiser_id, int8_t tx_power, uint8_t status) {
+    CallbackMsg msg;
+    msg.set_message_type(CallbackMsgType::ADVERTISING_PARAMETERS_UPDATED);
+    msg.set_advertiser_id(advertiser_id);
+    msg.set_status(static_cast<facade::AdvertisingStatus>(status));
+    callback_events_.OnIncomingEvent(msg);
+  };
+
+  void OnPeriodicAdvertisingParametersUpdated(uint8_t advertiser_id, uint8_t status) {
+    CallbackMsg msg;
+    msg.set_message_type(CallbackMsgType::PERIODIC_ADVERTISING_PARAMETERS_UPDATED);
+    msg.set_advertiser_id(advertiser_id);
+    msg.set_status(static_cast<facade::AdvertisingStatus>(status));
+    callback_events_.OnIncomingEvent(msg);
+  };
+
+  void OnPeriodicAdvertisingDataSet(uint8_t advertiser_id, uint8_t status) {
+    CallbackMsg msg;
+    msg.set_message_type(CallbackMsgType::PERIODIC_ADVERTISING_DATA_SET);
+    msg.set_advertiser_id(advertiser_id);
+    msg.set_status(static_cast<facade::AdvertisingStatus>(status));
+    callback_events_.OnIncomingEvent(msg);
+  };
+
+  void OnPeriodicAdvertisingEnabled(uint8_t advertiser_id, bool enable, uint8_t status) {
+    CallbackMsg msg;
+    msg.set_message_type(CallbackMsgType::PERIODIC_ADVERTISING_ENABLED);
+    msg.set_advertiser_id(advertiser_id);
+    msg.set_status(static_cast<facade::AdvertisingStatus>(status));
+    callback_events_.OnIncomingEvent(msg);
+  };
+
+  void OnOwnAddressRead(uint8_t advertiser_id, uint8_t address_type, Address address) {
+    LOG_INFO("OnOwnAddressRead Address:%s, address_type:%d", address.ToString().c_str(), address_type);
+    AddressMsg msg;
+    msg.set_message_type(CallbackMsgType::OWN_ADDRESS_READ);
+    msg.set_advertiser_id(advertiser_id);
+    bluetooth::facade::BluetoothAddressWithType facade_address;
+    facade_address.mutable_address()->set_address(address.ToString());
+    facade_address.set_type(static_cast<facade::BluetoothAddressTypeEnum>(address_type));
+    *msg.mutable_address() = facade_address;
+    address_events_.OnIncomingEvent(msg);
+  };
+
   std::vector<LeAdvertiser> le_advertisers_;
   LeAdvertisingManager* le_advertising_manager_;
   os::Handler* facade_handler_;
+  ::bluetooth::grpc::GrpcEventQueue<CallbackMsg> callback_events_{"callback events"};
+  ::bluetooth::grpc::GrpcEventQueue<AddressMsg> address_events_{"address events"};
 };
 
 void LeAdvertisingManagerFacadeModule::ListDependencies(ModuleList* list) {
diff --git a/gd/hci/facade/le_advertising_manager_facade.proto b/gd/hci/facade/le_advertising_manager_facade.proto
index edb70cf..8f258e9 100644
--- a/gd/hci/facade/le_advertising_manager_facade.proto
+++ b/gd/hci/facade/le_advertising_manager_facade.proto
@@ -8,8 +8,17 @@
 service LeAdvertisingManagerFacade {
   rpc CreateAdvertiser(CreateAdvertiserRequest) returns (CreateAdvertiserResponse) {}
   rpc ExtendedCreateAdvertiser(ExtendedCreateAdvertiserRequest) returns (ExtendedCreateAdvertiserResponse) {}
+  rpc EnableAdvertiser(EnableAdvertiserRequest) returns (google.protobuf.Empty) {}
+  rpc SetData(SetDataRequest) returns (google.protobuf.Empty) {}
+  rpc SetParameters(SetParametersRequest) returns (google.protobuf.Empty) {}
+  rpc SetPeriodicParameters(SetPeriodicParametersRequest) returns (google.protobuf.Empty) {}
+  rpc SetPeriodicData(SetPeriodicDataRequest) returns (google.protobuf.Empty) {}
+  rpc EnablePeriodicAdvertising(EnablePeriodicAdvertisingRequest) returns (google.protobuf.Empty) {}
+  rpc GetOwnAddress(GetOwnAddressRequest) returns (google.protobuf.Empty) {}
   rpc GetNumberOfAdvertisingInstances(google.protobuf.Empty) returns (GetNumberOfAdvertisingInstancesResponse) {}
   rpc RemoveAdvertiser(RemoveAdvertiserRequest) returns (google.protobuf.Empty) {}
+  rpc FetchCallbackEvents(google.protobuf.Empty) returns (stream CallbackMsg) {}
+  rpc FetchAddressEvents(google.protobuf.Empty) returns (stream AddressMsg) {}
 }
 
 message GapDataMsg {
@@ -31,6 +40,20 @@
   LISTED_SCAN_AND_CONNECT = 0x3;
 };
 
+enum AdvertisingProperty {
+  NONE = 0x00;
+  INCLUDE_TX_POWER = 0x06;
+};
+
+enum AdvertisingStatus {
+  SUCCESS = 0x00;
+  DATA_TOO_LARGE = 0x01;
+  TOO_MANY_ADVERTISERS = 0x02;
+  ALREADY_STARTED = 0x03;
+  INTERNAL_ERROR = 0x04;
+  FEATURE_UNSUPPORTED = 0x05;
+};
+
 message AdvertisingConfig {
   repeated GapDataMsg advertisement = 1;
   repeated GapDataMsg scan_response = 2;
@@ -57,10 +80,16 @@
   bool anonymous = 7;
   bool include_tx_power = 8;
   bool use_le_coded_phy = 9;
-  int32 secondary_map_skip = 10;
+  int32 secondary_max_skip = 10;
   int32 secondary_advertising_phy = 11;
   int32 sid = 12;
-  bool enable_scan_request_notification = 13;
+  bool enable_scan_request_notifications = 13;
+}
+
+message PeriodicAdvertisingParameters {
+  int32 min_interval = 1;
+  int32 max_interval = 2;
+  AdvertisingProperty advertising_property = 3;
 }
 
 message CreateAdvertiserRequest {
@@ -77,6 +106,42 @@
 }
 
 message ExtendedCreateAdvertiserResponse {
+  // -1 on error
+  int32 advertiser_id = 1;
+}
+
+message EnableAdvertiserRequest {
+  int32 advertiser_id = 1;
+  bool enable = 2;
+}
+
+message SetDataRequest {
+  int32 advertiser_id = 1;
+  bool set_scan_rsp = 2;
+  repeated GapDataMsg data = 3;
+}
+
+message SetParametersRequest {
+  int32 advertiser_id = 1;
+  AdvertisingConfig config = 2;
+}
+
+message SetPeriodicParametersRequest {
+  int32 advertiser_id = 1;
+  PeriodicAdvertisingParameters config = 2;
+}
+
+message SetPeriodicDataRequest {
+  int32 advertiser_id = 1;
+  repeated GapDataMsg data = 2;
+}
+
+message EnablePeriodicAdvertisingRequest {
+  int32 advertiser_id = 1;
+  bool enable = 2;
+}
+
+message GetOwnAddressRequest {
   int32 advertiser_id = 1;
 }
 
@@ -87,3 +152,28 @@
 message RemoveAdvertiserRequest {
   int32 advertiser_id = 1;
 }
+
+enum CallbackMsgType {
+  ADVERTISING_SET_STARTED = 0;
+  ADVERTISING_ENABLED = 1;
+  ADVERTISING_DATA_SET = 2;
+  SCAN_RESPONSE_DATA_SET = 3;
+  ADVERTISING_PARAMETERS_UPDATED = 4;
+  PERIODIC_ADVERTISING_PARAMETERS_UPDATED = 5;
+  PERIODIC_ADVERTISING_DATA_SET = 6;
+  PERIODIC_ADVERTISING_ENABLED = 7;
+  OWN_ADDRESS_READ = 8;
+}
+
+message CallbackMsg {
+  CallbackMsgType message_type = 1;
+  uint32 advertiser_id = 2;
+  AdvertisingStatus status = 3;
+  uint32 data = 4;
+}
+
+message AddressMsg {
+  CallbackMsgType message_type = 1;
+  uint32 advertiser_id = 2;
+  bluetooth.facade.BluetoothAddressWithType address = 3;
+}
diff --git a/gd/rust/common/src/time.rs b/gd/rust/common/src/time.rs
index 5e63bf8..ec6d410 100644
--- a/gd/rust/common/src/time.rs
+++ b/gd/rust/common/src/time.rs
@@ -18,7 +18,7 @@
     }
 
     /// Reset the alarm to duration, starting from now
-    pub fn reset(&mut self, duration: Duration) {
+    pub fn reset(&self, duration: Duration) {
         self.fd
             .get_ref()
             .set(Expiration::OneShot(TimeSpec::from(duration)), TimerSetTimeFlags::empty())
@@ -26,12 +26,12 @@
     }
 
     /// Stop the alarm if it is currently started
-    pub fn cancel(&mut self) {
+    pub fn cancel(&self) {
         self.reset(Duration::from_millis(0));
     }
 
     /// Completes when the alarm has expired
-    pub async fn expired(&mut self) {
+    pub async fn expired(&self) {
         let mut read_ready = self.fd.readable().await.unwrap();
         read_ready.clear_ready();
         drop(read_ready);
@@ -94,7 +94,7 @@
         let runtime = tokio::runtime::Runtime::new().unwrap();
         runtime.block_on(async {
             let timer = Instant::now();
-            let mut alarm = Alarm::new();
+            let alarm = Alarm::new();
             alarm.reset(Duration::from_millis(10));
             alarm.expired().await;
 
@@ -106,7 +106,7 @@
     fn alarm_cancel_after_expired() {
         let runtime = tokio::runtime::Runtime::new().unwrap();
         runtime.block_on(async {
-            let mut alarm = Alarm::new();
+            let alarm = Alarm::new();
             alarm.reset(Duration::from_millis(10));
             tokio::time::sleep(Duration::from_millis(30)).await;
             alarm.cancel();
@@ -131,7 +131,7 @@
         let runtime = tokio::runtime::Runtime::new().unwrap();
         runtime.block_on(async {
             let timer = Instant::now();
-            let mut alarm = Alarm::new();
+            let alarm = Alarm::new();
             alarm.reset(Duration::from_millis(10));
             alarm.expired().await;
             let ready_in_10_ms = async {
diff --git a/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager.rs b/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager.rs
index e6fa764..ed39771 100644
--- a/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager.rs
+++ b/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager.rs
@@ -1,4 +1,4 @@
-use log::error;
+use log::{error, info};
 
 use manager_service::iface_bluetooth_manager::{IBluetoothManager, IBluetoothManagerCallback};
 
@@ -12,29 +12,35 @@
 /// Implementation of IBluetoothManager.
 pub struct BluetoothManager {
     manager_context: ManagerContext,
-    callbacks: Vec<Box<dyn IBluetoothManagerCallback + Send>>,
+    callbacks: Vec<(u32, Box<dyn IBluetoothManagerCallback + Send>)>,
+    callbacks_last_id: u32,
 }
 
 impl BluetoothManager {
     pub(crate) fn new(manager_context: ManagerContext) -> BluetoothManager {
-        BluetoothManager { manager_context, callbacks: vec![] }
+        BluetoothManager { manager_context, callbacks: vec![], callbacks_last_id: 0 }
     }
 
     pub(crate) fn callback_hci_device_change(&self, hci_device: i32, present: bool) {
-        for callback in &self.callbacks {
+        for (_, callback) in &self.callbacks {
             callback.on_hci_device_changed(hci_device, present);
         }
     }
 
     pub(crate) fn callback_hci_enabled_change(&self, hci_device: i32, enabled: bool) {
-        for callback in &self.callbacks {
+        for (_, callback) in &self.callbacks {
             callback.on_hci_enabled_changed(hci_device, enabled);
         }
     }
+
+    pub(crate) fn callback_disconnected(&mut self, id: u32) {
+        self.callbacks.retain(|x| x.0 != id);
+    }
 }
 
 impl IBluetoothManager for BluetoothManager {
     fn start(&mut self, hci_interface: i32) {
+        info!("Starting {}", hci_interface);
         if !config_util::modify_hci_n_enabled(hci_interface, true) {
             error!("Config is not successfully modified");
         }
@@ -42,6 +48,7 @@
     }
 
     fn stop(&mut self, hci_interface: i32) {
+        info!("Stopping {}", hci_interface);
         if !config_util::modify_hci_n_enabled(hci_interface, false) {
             error!("Config is not successfully modified");
         }
@@ -55,9 +62,20 @@
         result
     }
 
-    fn register_callback(&mut self, callback: Box<dyn IBluetoothManagerCallback + Send>) {
-        // TODO: Handle callback disconnects.
-        self.callbacks.push(callback);
+    fn register_callback(&mut self, mut callback: Box<dyn IBluetoothManagerCallback + Send>) {
+        let tx = self.manager_context.proxy.get_tx();
+
+        self.callbacks_last_id += 1;
+        let id = self.callbacks_last_id;
+
+        callback.register_disconnect(Box::new(move || {
+            let tx = tx.clone();
+            tokio::spawn(async move {
+                let _result = tx.send(state_machine::Message::CallbackDisconnected(id)).await;
+            });
+        }));
+
+        self.callbacks.push((id, callback));
     }
 
     fn get_floss_enabled(&mut self) -> bool {
diff --git a/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs b/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs
index 9d0f736..61189cd 100644
--- a/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs
+++ b/gd/rust/linux/mgmt/src/bin/btmanagerd/state_machine.rs
@@ -5,10 +5,10 @@
 use nix::unistd::Pid;
 use regex::Regex;
 use std::process::{Child, Command, Stdio};
-use std::sync::Arc;
+use std::sync::{Arc, Mutex};
 use std::time::Duration;
 use tokio::io::unix::AsyncFd;
-use tokio::sync::{mpsc, Mutex};
+use tokio::sync::mpsc;
 
 // Directory for Bluetooth pid file
 pub const PID_DIR: &str = "/var/run/bluetooth";
@@ -32,17 +32,28 @@
     i32::from(state)
 }
 
+/// Adapter state actions
 #[derive(Debug)]
-pub enum StateMachineActions {
+pub enum AdapterStateActions {
     StartBluetooth(i32),
     StopBluetooth(i32),
     BluetoothStarted(i32, i32), // PID and HCI
     BluetoothStopped(i32),
 }
 
+/// Enum of all the messages that state machine handles.
+#[derive(Debug)]
+pub enum Message {
+    AdapterStateChange(AdapterStateActions),
+    PidChange(inotify::EventMask, Option<String>),
+    HciDeviceChange(inotify::EventMask, Option<String>),
+    CallbackDisconnected(u32),
+    CommandTimeout(),
+}
+
 pub struct StateMachineContext<PM> {
-    tx: mpsc::Sender<StateMachineActions>,
-    rx: mpsc::Receiver<StateMachineActions>,
+    tx: mpsc::Sender<Message>,
+    rx: mpsc::Receiver<Message>,
     state_machine: ManagerStateMachine<PM>,
 }
 
@@ -51,7 +62,7 @@
     where
         PM: ProcessManager + Send,
     {
-        let (tx, rx) = mpsc::channel::<StateMachineActions>(10);
+        let (tx, rx) = mpsc::channel::<Message>(10);
         StateMachineContext { tx: tx, rx: rx, state_machine: state_machine }
     }
 
@@ -66,8 +77,8 @@
 
 #[derive(Clone)]
 pub struct StateMachineProxy {
-    tx: mpsc::Sender<StateMachineActions>,
-    state: Arc<Mutex<State>>,
+    tx: mpsc::Sender<Message>,
+    state: Arc<std::sync::Mutex<State>>,
 }
 
 const TX_SEND_TIMEOUT_DURATION: Duration = Duration::from_secs(3);
@@ -77,21 +88,33 @@
     pub fn start_bluetooth(&self, hci_interface: i32) {
         let tx = self.tx.clone();
         tokio::spawn(async move {
-            let _ = tx.send(StateMachineActions::StartBluetooth(hci_interface)).await;
+            let _ = tx
+                .send(Message::AdapterStateChange(AdapterStateActions::StartBluetooth(
+                    hci_interface,
+                )))
+                .await;
         });
     }
 
     pub fn stop_bluetooth(&self, hci_interface: i32) {
         let tx = self.tx.clone();
         tokio::spawn(async move {
-            let _ = tx.send(StateMachineActions::StopBluetooth(hci_interface)).await;
+            let _ = tx
+                .send(Message::AdapterStateChange(AdapterStateActions::StopBluetooth(
+                    hci_interface,
+                )))
+                .await;
         });
     }
 
     pub fn get_state(&self) -> State {
         // This assumes that self.state is never locked for a long period, i.e. never lock() and
         // await for something else without unlocking. Otherwise this function will block.
-        return *futures::executor::block_on(self.state.lock());
+        return *self.state.lock().unwrap();
+    }
+
+    pub fn get_tx(&self) -> mpsc::Sender<Message> {
+        self.tx.clone()
     }
 }
 
@@ -103,7 +126,8 @@
     AsyncFd::new(pid_detector).expect("failed to add async fd")
 }
 
-fn get_hci_interface_from_pid_file_name(path: &str) -> Option<i32> {
+/// Given an pid path, returns the adapter index for that pid path.
+fn get_hci_index_from_pid_path(path: &str) -> Option<i32> {
     let re = Regex::new(r"bluetooth([0-9]+).pid").unwrap();
     re.captures(path)?.get(1)?.as_str().parse().ok()
 }
@@ -119,161 +143,275 @@
     AsyncFd::new(detector).expect("failed to add async fd")
 }
 
-fn get_hci_interface_from_device(path: &str) -> Option<i32> {
+/// Given an hci sysfs path, returns the index of the hci device at the path.
+fn get_hci_index_from_device(path: &str) -> Option<i32> {
     let re = Regex::new(r"hci([0-9]+)").unwrap();
     re.captures(path)?.get(1)?.as_str().parse().ok()
 }
 
+fn event_name_to_string(name: Option<&std::ffi::OsStr>) -> Option<String> {
+    if let Some(val) = &name {
+        if let Some(strval) = val.to_str() {
+            return Some(strval.to_string());
+        }
+    }
+
+    return None;
+}
+
 pub async fn mainloop<PM>(
     mut context: StateMachineContext<PM>,
     bluetooth_manager: Arc<std::sync::Mutex<Box<BluetoothManager>>>,
 ) where
     PM: ProcessManager + Send,
 {
-    let mut command_timeout = Alarm::new();
+    // Set up a command timeout listener to emit timeout messages
+    let command_timeout = Arc::new(Alarm::new());
+    let timeout_clone = command_timeout.clone();
+    let timeout_tx = context.tx.clone();
+
+    tokio::spawn(async move {
+        loop {
+            let _expired = timeout_clone.expired().await;
+            let _ = timeout_tx
+                .send_timeout(Message::CommandTimeout(), TX_SEND_TIMEOUT_DURATION)
+                .await
+                .unwrap();
+        }
+    });
+
+    // Set up a PID file listener to emit PID inotify messages
     let mut pid_async_fd = pid_inotify_async_fd();
-    let mut hci_devices_async_fd = hci_devices_inotify_async_fd();
-    loop {
-        tokio::select! {
-            Some(action) = context.rx.recv() => {
-              // Grab previous state from lock and release
-              let mut next_state;
-              let mut prev_state;
-              {
-                  prev_state = *context.state_machine.state.lock().await;
-              }
-              let mut hci = 0;
+    let pid_tx = context.tx.clone();
 
-              match action {
-                StateMachineActions::StartBluetooth(i) => {
-                    next_state = State::TurningOn;
-                    hci = i;
+    tokio::spawn(async move {
+        debug!("Spawned pid notify task");
 
-                    match context.state_machine.action_start_bluetooth(i).await {
-                        true => {
-                            command_timeout.reset(COMMAND_TIMEOUT_DURATION);
-                        },
-                        false => command_timeout.cancel(),
+        loop {
+            let r = pid_async_fd.readable_mut();
+            let mut fd_ready = r.await.unwrap();
+            let mut buffer: [u8; 1024] = [0; 1024];
+            debug!("Found new pid inotify entries. Reading them");
+            match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) {
+                Ok(Ok(events)) => {
+                    for event in events {
+                        debug!("got some events from pid {:?}", event.mask);
+                        let _ = pid_tx
+                            .send_timeout(
+                                Message::PidChange(event.mask, event_name_to_string(event.name)),
+                                TX_SEND_TIMEOUT_DURATION,
+                            )
+                            .await
+                            .unwrap();
                     }
-                },
-                StateMachineActions::StopBluetooth(i) => {
-                    next_state = State::TurningOff;
-                    hci = i;
+                }
+                Err(_) | Ok(Err(_)) => panic!("why can't we read while the asyncfd is ready?"),
+            }
+            fd_ready.clear_ready();
+            drop(fd_ready);
+        }
+    });
 
-                    match context.state_machine.action_stop_bluetooth(i).await {
-                      true => {
-                          command_timeout.reset(COMMAND_TIMEOUT_DURATION);
-                      },
-                      false => command_timeout.cancel(),
-                  }
-                },
-                StateMachineActions::BluetoothStarted(pid, i) => {
-                  next_state = State::On;
-                  hci = i;
+    // Set up an HCI device listener to emit HCI device inotify messages
+    let mut hci_devices_async_fd = hci_devices_inotify_async_fd();
+    let hci_tx = context.tx.clone();
 
-                  match context.state_machine.action_on_bluetooth_started(pid, hci).await {
-                      true => {
-                          command_timeout.cancel();
-                      }
-                      false => error!("unexpected BluetoothStarted pid{} hci{}", pid, hci),
-                  }
-                },
-                StateMachineActions::BluetoothStopped(i) => {
-                  next_state = State::Off;
-                  hci = i;
+    tokio::spawn(async move {
+        debug!("Spawned hci notify task");
+        loop {
+            let r = hci_devices_async_fd.readable_mut();
+            let mut fd_ready = r.await.unwrap();
+            let mut buffer: [u8; 1024] = [0; 1024];
+            debug!("Found new hci device entries. Reading them.");
+            match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) {
+                Ok(Ok(events)) => {
+                    for event in events {
+                        let _ = hci_tx
+                            .send_timeout(
+                                Message::HciDeviceChange(
+                                    event.mask,
+                                    event_name_to_string(event.name),
+                                ),
+                                TX_SEND_TIMEOUT_DURATION,
+                            )
+                            .await
+                            .unwrap();
+                    }
+                }
+                Err(_) | Ok(Err(_)) => panic!("why can't we read while the asyncfd is ready?"),
+            }
+            fd_ready.clear_ready();
+            drop(fd_ready);
+        }
+    });
 
-                  match context.state_machine.action_on_bluetooth_stopped().await {
-                      true => {
-                          command_timeout.cancel();
-                      }
-                      false => {
-                          command_timeout.reset(COMMAND_TIMEOUT_DURATION);
-                      }
-                  }
-                },
-              };
+    // Listen for all messages and act on them
+    loop {
+        let m = context.rx.recv().await;
 
-              // Only emit enabled event for certain transitions
-              if next_state != prev_state &&
-                 (next_state == State::On || prev_state == State::On) {
-                  bluetooth_manager.lock().unwrap().callback_hci_enabled_change(hci, next_state == State::On);
-              }
+        if m.is_none() {
+            info!("Exiting manager mainloop");
+            break;
+        }
 
+        println!("Message handler: {:?}", m);
+
+        match m.unwrap() {
+            // Adapter action has changed
+            Message::AdapterStateChange(action) => {
+                // Grab previous state from lock and release
+                let next_state;
+                let prev_state;
+                {
+                    prev_state = *context.state_machine.state.lock().unwrap();
+                }
+                let mut hci = 0;
+
+                match action {
+                    AdapterStateActions::StartBluetooth(i) => {
+                        next_state = State::TurningOn;
+                        hci = i;
+
+                        match context.state_machine.action_start_bluetooth(i) {
+                            true => {
+                                command_timeout.reset(COMMAND_TIMEOUT_DURATION);
+                            }
+                            false => command_timeout.cancel(),
+                        }
+                    }
+                    AdapterStateActions::StopBluetooth(i) => {
+                        next_state = State::TurningOff;
+                        hci = i;
+
+                        match context.state_machine.action_stop_bluetooth(i) {
+                            true => {
+                                command_timeout.reset(COMMAND_TIMEOUT_DURATION);
+                            }
+                            false => command_timeout.cancel(),
+                        }
+                    }
+                    AdapterStateActions::BluetoothStarted(pid, i) => {
+                        next_state = State::On;
+                        hci = i;
+
+                        match context.state_machine.action_on_bluetooth_started(pid, hci) {
+                            true => {
+                                command_timeout.cancel();
+                            }
+                            false => error!("unexpected BluetoothStarted pid{} hci{}", pid, hci),
+                        }
+                    }
+                    AdapterStateActions::BluetoothStopped(i) => {
+                        next_state = State::Off;
+                        hci = i;
+
+                        match context.state_machine.action_on_bluetooth_stopped() {
+                            true => {
+                                command_timeout.cancel();
+                            }
+                            false => {
+                                command_timeout.reset(COMMAND_TIMEOUT_DURATION);
+                            }
+                        }
+                    }
+                };
+
+                // Only emit enabled event for certain transitions
+                if next_state != prev_state && (next_state == State::On || prev_state == State::On)
+                {
+                    bluetooth_manager
+                        .lock()
+                        .unwrap()
+                        .callback_hci_enabled_change(hci, next_state == State::On);
+                }
+            }
+
+            // Monitored pid directory has a change
+            Message::PidChange(mask, filename) => match (mask, &filename) {
+                (inotify::EventMask::CREATE, Some(fname)) => {
+                    let path = std::path::Path::new(PID_DIR).join(&fname);
+                    match (get_hci_index_from_pid_path(&fname), tokio::fs::read(path).await.ok()) {
+                        (Some(hci), Some(s)) => {
+                            let pid = String::from_utf8(s)
+                                .expect("invalid pid file")
+                                .parse::<i32>()
+                                .unwrap_or(0);
+                            debug!("Sending bluetooth started action for pid={}, hci={}", pid, hci);
+                            let _ = context
+                                .tx
+                                .send_timeout(
+                                    Message::AdapterStateChange(
+                                        AdapterStateActions::BluetoothStarted(pid, hci),
+                                    ),
+                                    TX_SEND_TIMEOUT_DURATION,
+                                )
+                                .await
+                                .unwrap();
+                        }
+                        (hci, s) => {
+                            warn!("invalid file hci={:?} pid_file={:?}", hci, s)
+                        }
+                    }
+                }
+                (inotify::EventMask::DELETE, Some(fname)) => {
+                    if let Some(hci) = get_hci_index_from_pid_path(&fname) {
+                        debug!("Sending bluetooth stopped action for hci={}", hci);
+                        context
+                            .tx
+                            .send_timeout(
+                                Message::AdapterStateChange(AdapterStateActions::BluetoothStopped(
+                                    hci,
+                                )),
+                                TX_SEND_TIMEOUT_DURATION,
+                            )
+                            .await
+                            .unwrap();
+                    }
+                }
+                _ => debug!("Ignored event {:?} - {:?}", mask, &filename),
             },
-            _expired = command_timeout.expired() => {
-                info!("expired {:?}", *context.state_machine.state.lock().await);
-                let timeout_action = context.state_machine.action_on_command_timeout().await;
+
+            // Monitored hci directory has a change
+            Message::HciDeviceChange(mask, filename) => match (mask, &filename) {
+                (inotify::EventMask::CREATE, Some(fname)) => {
+                    match get_hci_index_from_device(&fname) {
+                        Some(hci) => {
+                            bluetooth_manager.lock().unwrap().callback_hci_device_change(hci, true);
+                        }
+                        _ => (),
+                    }
+                }
+                (inotify::EventMask::DELETE, Some(fname)) => {
+                    match get_hci_index_from_device(&fname) {
+                        Some(hci) => {
+                            bluetooth_manager
+                                .lock()
+                                .unwrap()
+                                .callback_hci_device_change(hci, false);
+                        }
+                        _ => (),
+                    }
+                }
+                _ => debug!("Ignored event {:?} - {:?}", mask, &filename),
+            },
+
+            // Callback client has disconnected
+            Message::CallbackDisconnected(id) => {
+                bluetooth_manager.lock().unwrap().callback_disconnected(id);
+            }
+
+            // Handle command timeouts
+            Message::CommandTimeout() => {
+                // Hold state lock for short duration
+                {
+                    debug!("expired {:?}", *context.state_machine.state.lock().unwrap());
+                }
+                let timeout_action = context.state_machine.action_on_command_timeout();
                 match timeout_action {
                     StateMachineTimeoutActions::Noop => (),
                     _ => command_timeout.reset(COMMAND_TIMEOUT_DURATION),
                 }
-            },
-            r = pid_async_fd.readable_mut() => {
-                let mut fd_ready = r.unwrap();
-                let mut buffer: [u8; 1024] = [0; 1024];
-                match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) {
-                    Ok(Ok(events)) => {
-                        for event in events {
-                            debug!("got some events from pid {:?}", event.mask);
-                            match (event.mask, event.name) {
-                                (inotify::EventMask::CREATE, Some(oss)) => {
-                                    let path = std::path::Path::new(PID_DIR).join(oss);
-                                    let file_name = oss.to_str().unwrap_or("invalid file");
-                                    match (get_hci_interface_from_pid_file_name(file_name), tokio::fs::read(path).await.ok()) {
-                                        (Some(hci), Some(s)) => {
-                                            let pid = String::from_utf8(s).expect("invalid pid file").parse::<i32>().unwrap_or(0);
-                                            let _ = context.tx.send_timeout(StateMachineActions::BluetoothStarted(pid, hci), TX_SEND_TIMEOUT_DURATION).await.unwrap();
-                                        },
-                                        (hci, s) => warn!("invalid file hci={:?} pid_file={:?}", hci, s),
-                                    }
-                                },
-                                (inotify::EventMask::DELETE, Some(oss)) => {
-                                    let file_name = oss.to_str().unwrap_or("invalid file");
-                                    if let Some(hci) = get_hci_interface_from_pid_file_name(file_name) {
-                                        context.tx.send_timeout(StateMachineActions::BluetoothStopped(hci), TX_SEND_TIMEOUT_DURATION).await.unwrap();
-                                    }
-                                },
-                                _ => debug!("Ignored event {:?}", event.mask)
-                            }
-                        }
-                    },
-                    Err(_) | Ok(Err(_)) => panic!("why can't we read while the asyncfd is ready?"),
-                }
-                fd_ready.clear_ready();
-                drop(fd_ready);
-            },
-            r = hci_devices_async_fd.readable_mut() => {
-                let mut fd_ready = r.unwrap();
-                let mut buffer: [u8; 1024] = [0; 1024];
-                match fd_ready.try_io(|inner| inner.get_mut().read_events(&mut buffer)) {
-                    Ok(Ok(events)) => {
-                        for event in events {
-                            match (event.mask, event.name) {
-                                (inotify::EventMask::CREATE, Some(oss)) => {
-                                    match get_hci_interface_from_device(oss.to_str().unwrap_or("invalid hci device")) {
-                                        Some(hci) => {
-                                            bluetooth_manager.lock().unwrap().callback_hci_device_change(hci, true);
-                                        },
-                                        _ => (),
-                                    }
-                                },
-                                (inotify::EventMask::DELETE, Some(oss)) => {
-                                    match get_hci_interface_from_device(oss.to_str().unwrap_or("invalid hci device")) {
-                                        Some(hci) => {
-                                            bluetooth_manager.lock().unwrap().callback_hci_device_change(hci, false);
-                                        },
-                                        _ => (),
-                                    }
-                                },
-                                _ => debug!("Ignored event {:?}", event.mask)
-                            }
-                        }
-                    },
-                    Err(_) | Ok(Err(_)) => panic!("why can't we read while the asyncfd is ready?"),
-                }
-                fd_ready.clear_ready();
-                drop(fd_ready);
-            },
+            }
         }
     }
 }
@@ -342,7 +480,7 @@
 }
 
 struct ManagerStateMachine<PM> {
-    state: Arc<Mutex<State>>,
+    state: Arc<std::sync::Mutex<State>>,
     process_manager: PM,
     hci_interface: i32,
     bluetooth_pid: i32,
@@ -373,7 +511,7 @@
 {
     pub fn new(process_manager: PM) -> ManagerStateMachine<PM> {
         ManagerStateMachine {
-            state: Arc::new(Mutex::new(State::Off)),
+            state: Arc::new(std::sync::Mutex::new(State::Off)),
             process_manager: process_manager,
             hci_interface: 0,
             bluetooth_pid: 0,
@@ -381,8 +519,8 @@
     }
 
     /// Returns true if we are starting bluetooth process.
-    pub async fn action_start_bluetooth(&mut self, hci_interface: i32) -> bool {
-        let mut state = self.state.lock().await;
+    pub fn action_start_bluetooth(&mut self, hci_interface: i32) -> bool {
+        let mut state = self.state.lock().unwrap();
         match *state {
             State::Off => {
                 *state = State::TurningOn;
@@ -396,7 +534,7 @@
     }
 
     /// Returns true if we are stopping bluetooth process.
-    pub async fn action_stop_bluetooth(&mut self, hci_interface: i32) -> bool {
+    pub fn action_stop_bluetooth(&mut self, hci_interface: i32) -> bool {
         if self.hci_interface != hci_interface {
             warn!(
                 "We are running hci{} but attempting to stop hci{}",
@@ -405,7 +543,7 @@
             return false;
         }
 
-        let mut state = self.state.lock().await;
+        let mut state = self.state.lock().unwrap();
         match *state {
             State::On => {
                 *state = State::TurningOff;
@@ -423,8 +561,8 @@
     }
 
     /// Returns true if the event is expected.
-    pub async fn action_on_bluetooth_started(&mut self, pid: i32, hci_interface: i32) -> bool {
-        let mut state = self.state.lock().await;
+    pub fn action_on_bluetooth_started(&mut self, pid: i32, hci_interface: i32) -> bool {
+        let mut state = self.state.lock().unwrap();
         if self.hci_interface != hci_interface {
             warn!(
                 "We should start hci{} but hci{} is started; capturing that process",
@@ -443,8 +581,8 @@
     /// Returns true if the event is expected.
     /// If unexpected, Bluetooth probably crashed;
     /// start the timer for restart timeout
-    pub async fn action_on_bluetooth_stopped(&mut self) -> bool {
-        let mut state = self.state.lock().await;
+    pub fn action_on_bluetooth_stopped(&mut self) -> bool {
+        let mut state = self.state.lock().unwrap();
 
         match *state {
             State::TurningOff => {
@@ -466,18 +604,18 @@
 
     /// Triggered on Bluetooth start/stop timeout.  Return the actions that the
     /// state machine has taken, for the external context to reset the timer.
-    pub async fn action_on_command_timeout(&mut self) -> StateMachineTimeoutActions {
-        let mut state = self.state.lock().await;
+    pub fn action_on_command_timeout(&mut self) -> StateMachineTimeoutActions {
+        let mut state = self.state.lock().unwrap();
         match *state {
             State::TurningOn => {
-                info!("Restarting bluetooth");
+                info!("Restarting bluetooth {}", self.hci_interface);
                 *state = State::TurningOn;
                 self.process_manager.stop(format! {"{}", self.hci_interface});
                 self.process_manager.start(format! {"{}", self.hci_interface});
                 StateMachineTimeoutActions::RetryStart
             }
             State::TurningOff => {
-                info!("Killing bluetooth");
+                info!("Killing bluetooth {}", self.hci_interface);
                 self.process_manager.stop(format! {"{}", self.hci_interface});
                 StateMachineTimeoutActions::RetryStop
             }
@@ -538,7 +676,7 @@
         tokio::runtime::Runtime::new().unwrap().block_on(async {
             let process_manager = MockProcessManager::new();
             let state_machine = ManagerStateMachine::new(process_manager);
-            assert_eq!(*state_machine.state.lock().await, State::Off);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::Off);
         })
     }
 
@@ -547,8 +685,8 @@
         tokio::runtime::Runtime::new().unwrap().block_on(async {
             let process_manager = MockProcessManager::new();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_stop_bluetooth(0).await;
-            assert_eq!(*state_machine.state.lock().await, State::Off);
+            state_machine.action_stop_bluetooth(0);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::Off);
         })
     }
 
@@ -559,8 +697,8 @@
             // Expect to send start command
             process_manager.expect_start();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
-            assert_eq!(*state_machine.state.lock().await, State::TurningOn);
+            state_machine.action_start_bluetooth(0);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::TurningOn);
         })
     }
 
@@ -571,8 +709,8 @@
             // Expect to send start command just once
             process_manager.expect_start();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
-            assert_eq!(state_machine.action_start_bluetooth(0).await, false);
+            state_machine.action_start_bluetooth(0);
+            assert_eq!(state_machine.action_start_bluetooth(0), false);
         })
     }
 
@@ -582,9 +720,9 @@
             let mut process_manager = MockProcessManager::new();
             process_manager.expect_start();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
-            state_machine.action_on_bluetooth_started(0, 0).await;
-            assert_eq!(*state_machine.state.lock().await, State::On);
+            state_machine.action_start_bluetooth(0);
+            state_machine.action_on_bluetooth_started(0, 0);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::On);
         })
     }
 
@@ -596,12 +734,12 @@
             process_manager.expect_stop();
             process_manager.expect_start(); // start bluetooth again
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
+            state_machine.action_start_bluetooth(0);
             assert_eq!(
-                state_machine.action_on_command_timeout().await,
+                state_machine.action_on_command_timeout(),
                 StateMachineTimeoutActions::RetryStart
             );
-            assert_eq!(*state_machine.state.lock().await, State::TurningOn);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::TurningOn);
         })
     }
 
@@ -613,9 +751,9 @@
             // Expect to send stop command
             process_manager.expect_stop();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
-            state_machine.action_stop_bluetooth(0).await;
-            assert_eq!(*state_machine.state.lock().await, State::Off);
+            state_machine.action_start_bluetooth(0);
+            state_machine.action_stop_bluetooth(0);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::Off);
         })
     }
 
@@ -627,10 +765,10 @@
             // Expect to send stop command
             process_manager.expect_stop();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
-            state_machine.action_on_bluetooth_started(0, 0).await;
-            state_machine.action_stop_bluetooth(0).await;
-            assert_eq!(*state_machine.state.lock().await, State::TurningOff);
+            state_machine.action_start_bluetooth(0);
+            state_machine.action_on_bluetooth_started(0, 0);
+            state_machine.action_stop_bluetooth(0);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::TurningOff);
         })
     }
 
@@ -642,10 +780,10 @@
             // Expect to start again
             process_manager.expect_start();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
-            state_machine.action_on_bluetooth_started(0, 0).await;
-            assert_eq!(state_machine.action_on_bluetooth_stopped().await, false);
-            assert_eq!(*state_machine.state.lock().await, State::TurningOn);
+            state_machine.action_start_bluetooth(0);
+            state_machine.action_on_bluetooth_started(0, 0);
+            assert_eq!(state_machine.action_on_bluetooth_stopped(), false);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::TurningOn);
         })
     }
 
@@ -656,11 +794,11 @@
             process_manager.expect_start();
             process_manager.expect_stop();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
-            state_machine.action_on_bluetooth_started(0, 0).await;
-            state_machine.action_stop_bluetooth(0).await;
-            state_machine.action_on_bluetooth_stopped().await;
-            assert_eq!(*state_machine.state.lock().await, State::Off);
+            state_machine.action_start_bluetooth(0);
+            state_machine.action_on_bluetooth_started(0, 0);
+            state_machine.action_stop_bluetooth(0);
+            state_machine.action_on_bluetooth_stopped();
+            assert_eq!(*state_machine.state.lock().unwrap(), State::Off);
         })
     }
 
@@ -672,35 +810,26 @@
             process_manager.expect_stop();
             process_manager.expect_start();
             let mut state_machine = ManagerStateMachine::new(process_manager);
-            state_machine.action_start_bluetooth(0).await;
-            state_machine.action_on_bluetooth_started(0, 0).await;
-            state_machine.action_stop_bluetooth(0).await;
-            state_machine.action_on_bluetooth_stopped().await;
-            state_machine.action_start_bluetooth(0).await;
-            state_machine.action_on_bluetooth_started(0, 0).await;
-            assert_eq!(*state_machine.state.lock().await, State::On);
+            state_machine.action_start_bluetooth(0);
+            state_machine.action_on_bluetooth_started(0, 0);
+            state_machine.action_stop_bluetooth(0);
+            state_machine.action_on_bluetooth_stopped();
+            state_machine.action_start_bluetooth(0);
+            state_machine.action_on_bluetooth_started(0, 0);
+            assert_eq!(*state_machine.state.lock().unwrap(), State::On);
         })
     }
 
     #[test]
     fn path_to_hci_interface() {
-        assert_eq!(
-            get_hci_interface_from_pid_file_name("/var/run/bluetooth/bluetooth0.pid"),
-            Some(0)
-        );
-        assert_eq!(
-            get_hci_interface_from_pid_file_name("/var/run/bluetooth/bluetooth1.pid"),
-            Some(1)
-        );
-        assert_eq!(
-            get_hci_interface_from_pid_file_name("/var/run/bluetooth/bluetooth10.pid"),
-            Some(10)
-        );
-        assert_eq!(get_hci_interface_from_pid_file_name("/var/run/bluetooth/garbage"), None);
+        assert_eq!(get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth0.pid"), Some(0));
+        assert_eq!(get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth1.pid"), Some(1));
+        assert_eq!(get_hci_index_from_pid_path("/var/run/bluetooth/bluetooth10.pid"), Some(10));
+        assert_eq!(get_hci_index_from_pid_path("/var/run/bluetooth/garbage"), None);
 
-        assert_eq!(get_hci_interface_from_device("/sys/class/bluetooth/hci0"), Some(0));
-        assert_eq!(get_hci_interface_from_device("/sys/class/bluetooth/hci1"), Some(1));
-        assert_eq!(get_hci_interface_from_device("/sys/class/bluetooth/hci10"), Some(10));
-        assert_eq!(get_hci_interface_from_device("/sys/class/bluetooth/eth0"), None);
+        assert_eq!(get_hci_index_from_device("/sys/class/bluetooth/hci0"), Some(0));
+        assert_eq!(get_hci_index_from_device("/sys/class/bluetooth/hci1"), Some(1));
+        assert_eq!(get_hci_index_from_device("/sys/class/bluetooth/hci10"), Some(10));
+        assert_eq!(get_hci_index_from_device("/sys/class/bluetooth/eth0"), None);
     }
 }
diff --git a/gd/rust/linux/service/src/iface_bluetooth_media.rs b/gd/rust/linux/service/src/iface_bluetooth_media.rs
index e375db8..233f3e5 100644
--- a/gd/rust/linux/service/src/iface_bluetooth_media.rs
+++ b/gd/rust/linux/service/src/iface_bluetooth_media.rs
@@ -16,7 +16,14 @@
 #[dbus_proxy_obj(BluetoothMediaCallback, "org.chromium.bluetooth.BluetoothMediaCallback")]
 impl IBluetoothMediaCallback for BluetoothMediaCallbackDBus {
     #[dbus_method("OnBluetoothAudioDeviceAdded")]
-    fn on_bluetooth_audio_device_added(&self, addr: String) {}
+    fn on_bluetooth_audio_device_added(
+        &self,
+        addr: String,
+        sample_rate: i32,
+        bits_per_sample: i32,
+        channel_mode: i32,
+    ) {
+    }
 
     #[dbus_method("OnBluetoothAudioDeviceRemoved")]
     fn on_bluetooth_audio_device_removed(&self, addr: String) {}
@@ -61,6 +68,9 @@
         true
     }
 
+    #[dbus_method("SetVolume")]
+    fn set_volume(&mut self, volume: i32) {}
+
     #[dbus_method("StartAudioRequest")]
     fn start_audio_request(&mut self) {}
 
diff --git a/gd/rust/linux/stack/src/bluetooth_media.rs b/gd/rust/linux/stack/src/bluetooth_media.rs
index b444307..2566dc4 100644
--- a/gd/rust/linux/stack/src/bluetooth_media.rs
+++ b/gd/rust/linux/stack/src/bluetooth_media.rs
@@ -1,13 +1,14 @@
 //! Anything related to audio and media API.
 
-use bt_topshim::btif::BluetoothInterface;
+use bt_topshim::btif::{BluetoothInterface, RawAddress};
 use bt_topshim::profiles::a2dp::{
     A2dp, A2dpCallbacks, A2dpCallbacksDispatcher, A2dpCodecBitsPerSample, A2dpCodecChannelMode,
-    A2dpCodecSampleRate, BtavConnectionState,
+    A2dpCodecConfig, A2dpCodecIndex, A2dpCodecSampleRate, BtavConnectionState,
 };
 use bt_topshim::profiles::avrcp::Avrcp;
 use bt_topshim::topstack;
 
+use std::collections::HashMap;
 use std::convert::TryFrom;
 use std::sync::Arc;
 use std::sync::Mutex;
@@ -35,13 +36,20 @@
         bits_per_sample: i32,
         channel_mode: i32,
     ) -> bool;
+    fn set_volume(&mut self, volume: i32);
     fn start_audio_request(&mut self);
     fn stop_audio_request(&mut self);
 }
 
 pub trait IBluetoothMediaCallback {
     ///
-    fn on_bluetooth_audio_device_added(&self, addr: String);
+    fn on_bluetooth_audio_device_added(
+        &self,
+        addr: String,
+        sample_rate: i32,
+        bits_per_sample: i32,
+        channel_mode: i32,
+    );
 
     ///
     fn on_bluetooth_audio_device_removed(&self, addr: String);
@@ -55,6 +63,8 @@
     tx: Sender<Message>,
     a2dp: Option<A2dp>,
     avrcp: Option<Avrcp>,
+    a2dp_states: HashMap<RawAddress, BtavConnectionState>,
+    selectable_caps: HashMap<RawAddress, Vec<A2dpCodecConfig>>,
 }
 
 impl BluetoothMedia {
@@ -67,24 +77,55 @@
             tx,
             a2dp: None,
             avrcp: None,
+            a2dp_states: HashMap::new(),
+            selectable_caps: HashMap::new(),
         }
     }
 
     pub fn dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks) {
         match cb {
-            A2dpCallbacks::ConnectionState(addr, state) => match BtavConnectionState::from(state) {
-                BtavConnectionState::Connected => {
-                    self.for_all_callbacks(|callback| {
-                        callback.on_bluetooth_audio_device_added(addr.to_string());
-                    });
+            A2dpCallbacks::ConnectionState(addr, state) => {
+                if !self.a2dp_states.get(&addr).is_none()
+                    && state == *self.a2dp_states.get(&addr).unwrap()
+                {
+                    return;
                 }
-                BtavConnectionState::Connecting => {}
-                BtavConnectionState::Disconnected => {}
-                BtavConnectionState::Disconnecting => {}
-            },
-            A2dpCallbacks::AudioState(addr, state) => {}
-            A2dpCallbacks::AudioConfig(addr, config, local_caps, selectable_caps) => {}
-            A2dpCallbacks::MandatoryCodecPreferred(addr) => {}
+                match state {
+                    BtavConnectionState::Connected => {
+                        if let Some(caps) = self.selectable_caps.get(&addr) {
+                            for cap in caps {
+                                // TODO: support codecs other than SBC.
+                                if A2dpCodecIndex::SrcSbc != A2dpCodecIndex::from(cap.codec_type) {
+                                    continue;
+                                }
+
+                                self.for_all_callbacks(|callback| {
+                                    callback.on_bluetooth_audio_device_added(
+                                        addr.to_string(),
+                                        cap.sample_rate,
+                                        cap.bits_per_sample,
+                                        cap.channel_mode,
+                                    );
+                                });
+                                return;
+                            }
+                        }
+                    }
+                    BtavConnectionState::Connecting => {}
+                    BtavConnectionState::Disconnected => {
+                        self.for_all_callbacks(|callback| {
+                            callback.on_bluetooth_audio_device_removed(addr.to_string());
+                        });
+                    }
+                    BtavConnectionState::Disconnecting => {}
+                };
+                self.a2dp_states.insert(addr, state);
+            }
+            A2dpCallbacks::AudioState(_addr, _state) => {}
+            A2dpCallbacks::AudioConfig(addr, _config, _local_caps, selectable_caps) => {
+                self.selectable_caps.insert(addr, selectable_caps);
+            }
+            A2dpCallbacks::MandatoryCodecPreferred(_addr) => {}
         }
     }
 
@@ -159,6 +200,13 @@
         true
     }
 
+    fn set_volume(&mut self, volume: i32) {
+        match i8::try_from(volume) {
+            Ok(val) => self.avrcp.as_mut().unwrap().set_volume(val),
+            _ => (),
+        };
+    }
+
     fn start_audio_request(&mut self) {
         self.a2dp.as_mut().unwrap().start_audio_request();
     }
diff --git a/gd/rust/stack/src/hci/mod.rs b/gd/rust/stack/src/hci/mod.rs
index 2fb5f6a..8f24f2a 100644
--- a/gd/rust/stack/src/hci/mod.rs
+++ b/gd/rust/stack/src/hci/mod.rs
@@ -173,7 +173,7 @@
     mut cmd_rx: Receiver<QueuedCommand>,
 ) {
     let mut pending: Option<QueuedCommand> = None;
-    let mut hci_timeout = Alarm::new();
+    let hci_timeout = Alarm::new();
     loop {
         select! {
             Some(evt) = consume(&evt_rx) => {
diff --git a/gd/rust/topshim/btav/btav_shim.cc b/gd/rust/topshim/btav/btav_shim.cc
index e867b58..c1f7a6c 100644
--- a/gd/rust/topshim/btav/btav_shim.cc
+++ b/gd/rust/topshim/btav/btav_shim.cc
@@ -255,6 +255,9 @@
   return intf_->DisconnectDevice(addr);
 }
 
+void AvrcpIntf::set_volume(int8_t volume) {
+  return mVolumeInterface.SetVolume(volume);
+}
 }  // namespace rust
 }  // namespace topshim
 }  // namespace bluetooth
diff --git a/gd/rust/topshim/btav/btav_shim.h b/gd/rust/topshim/btav/btav_shim.h
index 158d775..d2e9d0b 100644
--- a/gd/rust/topshim/btav/btav_shim.h
+++ b/gd/rust/topshim/btav/btav_shim.h
@@ -66,6 +66,9 @@
   int connect(RustRawAddress bt_addr);
   int disconnect(RustRawAddress bt_addr);
 
+  // interface for Audio server
+  void set_volume(int8_t volume);
+
  private:
   bluetooth::avrcp::ServiceInterface* intf_;
 };
diff --git a/gd/rust/topshim/src/btif.rs b/gd/rust/topshim/src/btif.rs
index 5b54147..17ce6e3 100644
--- a/gd/rust/topshim/src/btif.rs
+++ b/gd/rust/topshim/src/btif.rs
@@ -268,7 +268,7 @@
 /// A shared address structure that has the same representation as
 /// bindings::RawAddress. Macros `deref_ffi_address` and `cast_to_ffi_address`
 /// are used for transforming between bindings::RawAddress at ffi boundaries.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Hash, Eq, PartialEq)]
 #[repr(C)]
 pub struct RawAddress {
     pub val: [u8; 6],
diff --git a/gd/rust/topshim/src/profiles/a2dp.rs b/gd/rust/topshim/src/profiles/a2dp.rs
index 7a868f4..ad13ff1 100644
--- a/gd/rust/topshim/src/profiles/a2dp.rs
+++ b/gd/rust/topshim/src/profiles/a2dp.rs
@@ -57,9 +57,9 @@
     pub const MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc;
 }
 
-impl From<u32> for A2dpCodecIndex {
-    fn from(item: u32) -> Self {
-        A2dpCodecIndex::from_u32(item).unwrap_or_else(|| A2dpCodecIndex::MIN)
+impl From<i32> for A2dpCodecIndex {
+    fn from(item: i32) -> Self {
+        A2dpCodecIndex::from_i32(item).unwrap_or_else(|| A2dpCodecIndex::MIN)
     }
 }
 
diff --git a/gd/rust/topshim/src/profiles/avrcp.rs b/gd/rust/topshim/src/profiles/avrcp.rs
index 66a474d..649000b 100644
--- a/gd/rust/topshim/src/profiles/avrcp.rs
+++ b/gd/rust/topshim/src/profiles/avrcp.rs
@@ -11,6 +11,7 @@
 
         fn init(self: Pin<&mut AvrcpIntf>);
         fn cleanup(self: Pin<&mut AvrcpIntf>);
+        fn set_volume(self: Pin<&mut AvrcpIntf>, volume: i8);
 
     }
     extern "Rust" {}
@@ -43,4 +44,8 @@
         self.internal.pin_mut().cleanup();
         true
     }
+
+    pub fn set_volume(&mut self, volume: i8) {
+        self.internal.pin_mut().set_volume(volume);
+    }
 }
diff --git a/gd/stack_manager.cc b/gd/stack_manager.cc
index 3366c7b..17b6582 100644
--- a/gd/stack_manager.cc
+++ b/gd/stack_manager.cc
@@ -16,9 +16,7 @@
 
 #include "stack_manager.h"
 
-#include <fcntl.h>
 #include <stdio.h>
-#include <unistd.h>
 #include <chrono>
 #include <future>
 #include <queue>
@@ -36,9 +34,6 @@
 
 namespace bluetooth {
 
-// Assume we are hci0 for now
-constexpr char bluetooth_pid_file[] = "/var/run/bluetooth/bluetooth0.pid";
-
 void StackManager::StartUp(ModuleList* modules, Thread* stack_thread) {
   management_thread_ = new Thread("management_thread", Thread::Priority::NORMAL);
   handler_ = new Handler(management_thread_);
@@ -59,10 +54,6 @@
       "Can't start stack, last instance: %s",
       registry_.last_instance_.c_str());
 
-  pid_fd_ = open(bluetooth_pid_file, O_WRONLY | O_CREAT, 0644);
-  pid_t my_pid = getpid();
-  dprintf(pid_fd_, "%d\n", my_pid);
-
   LOG_INFO("init complete");
 }
 
@@ -92,9 +83,6 @@
   handler_->WaitUntilStopped(std::chrono::milliseconds(2000));
   delete handler_;
   delete management_thread_;
-
-  unlink(bluetooth_pid_file);
-  close(pid_fd_);
 }
 
 void StackManager::handle_shut_down(std::promise<void> promise) {
diff --git a/gd/stack_manager.h b/gd/stack_manager.h
index 985bd0b..c09a7f6 100644
--- a/gd/stack_manager.h
+++ b/gd/stack_manager.h
@@ -41,7 +41,6 @@
   os::Thread* management_thread_ = nullptr;
   os::Handler* handler_ = nullptr;
   ModuleRegistry registry_;
-  int pid_fd_ = 0;
 
   void handle_start_up(ModuleList* modules, os::Thread* stack_thread, std::promise<void> promise);
   void handle_shut_down(std::promise<void> promise);
diff --git a/hci/src/hci_layer_linux.cc b/hci/src/hci_layer_linux.cc
index e5e4fde..788abc0 100644
--- a/hci/src/hci_layer_linux.cc
+++ b/hci/src/hci_layer_linux.cc
@@ -35,6 +35,7 @@
 
 #include "buffer_allocator.h"
 #include "check.h"
+#include "gd/common/init_flags.h"
 #include "hci_internals.h"
 #include "hci_layer.h"
 #include "osi/include/compat.h"
@@ -171,23 +172,31 @@
   LOG(INFO) << __func__;
 
   char prop_value[PROPERTY_VALUE_MAX];
-  osi_property_get("bluetooth.interface", prop_value, "0");
+  int read = osi_property_get("bluetooth.interface", prop_value, nullptr);
 
-  errno = 0;
-  if (memcmp(prop_value, "hci", 3))
-    hci_interface = strtol(prop_value, NULL, 10);
-  else
-    hci_interface = strtol(prop_value + 3, NULL, 10);
-  if (errno) hci_interface = 0;
+  // If bluetooth.interface was read from properties, use it. Otherwise, default
+  // to the value read from the init flags.
+  if (read) {
+    errno = 0;
+    if (memcmp(prop_value, "hci", 3))
+      hci_interface = strtol(prop_value, NULL, 10);
+    else
+      hci_interface = strtol(prop_value + 3, NULL, 10);
+    if (errno) hci_interface = 0;
+  } else {
+    hci_interface = bluetooth::common::InitFlags::GetAdapterIndex();
+  }
 
   LOG(INFO) << "Using interface hci" << +hci_interface;
 
+#if !defined(TARGET_FLOSS)
   osi_property_get("bluetooth.rfkill", prop_value, "1");
 
   rfkill_en = atoi(prop_value);
   if (rfkill_en) {
     rfkill(0);
   }
+#endif
 
   int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
   CHECK(fd >= 0) << "socket create error" << strerror(errno);
@@ -242,7 +251,9 @@
     reader_thread = NULL;
   }
 
+#if !defined(TARGET_FLOSS)
   rfkill(1);
+#endif
 }
 
 void hci_transmit(BT_HDR* packet) {
diff --git a/main/shim/stack.cc b/main/shim/stack.cc
index e4cd6fd..9b826fc 100644
--- a/main/shim/stack.cc
+++ b/main/shim/stack.cc
@@ -18,9 +18,15 @@
 
 #include "device/include/controller.h"
 
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string>
+
 #include "gd/att/att_module.h"
 #include "gd/btaa/activity_attribution.h"
 #include "gd/common/init_flags.h"
+#include "gd/common/strings.h"
 #include "gd/hal/hci_hal.h"
 #include "gd/hci/acl_manager.h"
 #include "gd/hci/controller.h"
@@ -55,6 +61,34 @@
 namespace bluetooth {
 namespace shim {
 
+using ::bluetooth::common::InitFlags;
+using ::bluetooth::common::StringFormat;
+
+namespace {
+// PID file format
+constexpr char pid_file_format[] = "/var/run/bluetooth/bluetooth%d.pid";
+
+void CreatePidFile() {
+  std::string pid_file =
+      StringFormat(pid_file_format, InitFlags::GetAdapterIndex());
+  int pid_fd_ = open(pid_file.c_str(), O_WRONLY | O_CREAT, 0644);
+  if (!pid_fd_) return;
+
+  pid_t my_pid = getpid();
+  dprintf(pid_fd_, "%d\n", my_pid);
+  close(pid_fd_);
+
+  LOG_INFO("%s - Created pid file %s", __func__, pid_file.c_str());
+}
+
+void RemovePidFile() {
+  std::string pid_file =
+      StringFormat(pid_file_format, InitFlags::GetAdapterIndex());
+  unlink(pid_file.c_str());
+  LOG_INFO("%s - Deleted pid file %s", __func__, pid_file.c_str());
+}
+}  // namespace
+
 Stack* Stack::GetInstance() {
   static Stack instance;
   return &instance;
@@ -87,6 +121,9 @@
           rust::get_controller(**rust_stack_));
     }
     bluetooth::shim::hci_on_reset_complete();
+
+    // Create pid since we're up and running
+    CreatePidFile();
     return;
   }
 
@@ -168,6 +205,9 @@
   if (common::init_flags::btaa_hci_is_enabled()) {
     bluetooth::shim::init_activity_attribution();
   }
+
+  // Create pid since we're up and running
+  CreatePidFile();
 }
 
 void Stack::Start(ModuleList* modules) {
@@ -184,6 +224,9 @@
 }
 
 void Stack::Stop() {
+  // First remove pid file so clients no stack is going down
+  RemovePidFile();
+
   if (common::init_flags::gd_rust_is_enabled()) {
     if (rust_stack_ != nullptr) {
       rust::stack_stop(**rust_stack_);
diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc
new file mode 100644
index 0000000..2c7bebd
--- /dev/null
+++ b/stack/btm/btm_acl.cc
@@ -0,0 +1,2595 @@
+/******************************************************************************
+ *
+ *  Copyright 2000-2012 Broadcom Corporation
+ *
+ *  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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Name:          btm_acl.cc
+ *
+ *  Description:   This file contains functions that handle ACL connections.
+ *                 This includes operations such as hold and sniff modes,
+ *                 supported packet types.
+ *
+ *                 This module contains both internal and external (API)
+ *                 functions. External (API) functions are distinguishable
+ *                 by their names beginning with uppercase BTM.
+ *
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "btm_acl"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "common/metrics.h"
+#include "device/include/controller.h"
+#include "device/include/interop.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+static void btm_read_remote_features(uint16_t handle);
+static void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number);
+static void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
+                                            uint8_t num_read_pages);
+
+/* 3 seconds timeout waiting for responses */
+#define BTM_DEV_REPLY_TIMEOUT_MS (3 * 1000)
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_init
+ *
+ * Description      This function is called at BTM startup to initialize
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_acl_init(void) {
+  BTM_TRACE_DEBUG("btm_acl_init");
+  /* Initialize nonzero defaults */
+  btm_cb.btm_def_link_super_tout = HCI_DEFAULT_INACT_TOUT;
+  btm_cb.acl_disc_reason = 0xff;
+}
+
+/*******************************************************************************
+ *
+ * Function        btm_bda_to_acl
+ *
+ * Description     This function returns the FIRST acl_db entry for the passed
+ *                 BDA.
+ *
+ * Parameters      bda : BD address of the remote device
+ *                 transport : Physical transport used for ACL connection
+ *                 (BR/EDR or LE)
+ *
+ * Returns         Returns pointer to the ACL DB for the requested BDA if found.
+ *                 NULL if not found.
+ *
+ ******************************************************************************/
+tACL_CONN* btm_bda_to_acl(const RawAddress& bda, tBT_TRANSPORT transport) {
+  tACL_CONN* p = &btm_cb.acl_db[0];
+  uint16_t xx;
+  for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) {
+    if ((p->in_use) && p->remote_addr == bda && p->transport == transport) {
+      BTM_TRACE_DEBUG("btm_bda_to_acl found");
+      return (p);
+    }
+  }
+
+  /* If here, no BD Addr found */
+  return ((tACL_CONN*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_handle_to_acl_index
+ *
+ * Description      This function returns the FIRST acl_db entry for the passed
+ *                  hci_handle.
+ *
+ * Returns          index to the acl_db or MAX_L2CAP_LINKS.
+ *
+ ******************************************************************************/
+uint8_t btm_handle_to_acl_index(uint16_t hci_handle) {
+  tACL_CONN* p = &btm_cb.acl_db[0];
+  uint8_t xx;
+  BTM_TRACE_DEBUG("btm_handle_to_acl_index");
+  for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) {
+    if ((p->in_use) && (p->hci_handle == hci_handle)) {
+      break;
+    }
+  }
+
+  /* If here, no BD Addr found */
+  return (xx);
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+/*******************************************************************************
+ *
+ * Function         btm_ble_get_acl_remote_addr
+ *
+ * Description      This function reads the active remote address used for the
+ *                  connection.
+ *
+ * Returns          success return true, otherwise false.
+ *
+ ******************************************************************************/
+bool btm_ble_get_acl_remote_addr(tBTM_SEC_DEV_REC* p_dev_rec,
+                                 RawAddress& conn_addr,
+                                 tBLE_ADDR_TYPE* p_addr_type) {
+  bool st = true;
+
+  if (p_dev_rec == NULL) {
+    BTM_TRACE_ERROR("%s can not find device with matching address", __func__);
+    return false;
+  }
+
+  switch (p_dev_rec->ble.active_addr_type) {
+    case BTM_BLE_ADDR_PSEUDO:
+      conn_addr = p_dev_rec->bd_addr;
+      *p_addr_type = p_dev_rec->ble.ble_addr_type;
+      break;
+
+    case BTM_BLE_ADDR_RRA:
+      conn_addr = p_dev_rec->ble.cur_rand_addr;
+      *p_addr_type = BLE_ADDR_RANDOM;
+      break;
+
+    case BTM_BLE_ADDR_STATIC:
+      conn_addr = p_dev_rec->ble.identity_addr;
+      *p_addr_type = p_dev_rec->ble.identity_addr_type;
+      break;
+
+    default:
+      BTM_TRACE_ERROR("Unknown active address: %d",
+                      p_dev_rec->ble.active_addr_type);
+      st = false;
+      break;
+  }
+
+  return st;
+}
+#endif
+/*******************************************************************************
+ *
+ * Function         btm_acl_created
+ *
+ * Description      This function is called by L2CAP when an ACL connection
+ *                  is created.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_acl_created(const RawAddress& bda, DEV_CLASS dc, BD_NAME bdn,
+                     uint16_t hci_handle, uint8_t link_role,
+                     tBT_TRANSPORT transport) {
+  tBTM_SEC_DEV_REC* p_dev_rec = NULL;
+  tACL_CONN* p;
+  uint8_t xx;
+
+  BTM_TRACE_DEBUG("%s: peer %s hci_handle=%d link_role=%d  transport=%d",
+                  __func__, bda.ToString().c_str(), hci_handle, link_role,
+                  transport);
+  /* Ensure we don't have duplicates */
+  p = btm_bda_to_acl(bda, transport);
+  if (p != (tACL_CONN*)NULL) {
+    p->hci_handle = hci_handle;
+    p->link_role = link_role;
+    p->transport = transport;
+    VLOG(1) << "Duplicate btm_acl_created: RemBdAddr: " << bda;
+    BTM_SetLinkPolicy(p->remote_addr, &btm_cb.btm_def_link_policy);
+    return;
+  }
+
+  /* Allocate acl_db entry */
+  for (xx = 0, p = &btm_cb.acl_db[0]; xx < MAX_L2CAP_LINKS; xx++, p++) {
+    if (!p->in_use) {
+      p->in_use = true;
+      p->hci_handle = hci_handle;
+      p->link_role = link_role;
+      p->link_up_issued = false;
+      p->remote_addr = bda;
+
+      p->transport = transport;
+#if (BLE_PRIVACY_SPT == TRUE)
+      if (transport == BT_TRANSPORT_LE)
+        btm_ble_refresh_local_resolvable_private_addr(
+            bda, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr);
+#else
+      p->conn_addr_type = BLE_ADDR_PUBLIC;
+      p->conn_addr = *controller_get_interface()->get_address();
+
+#endif
+      p->switch_role_failed_attempts = 0;
+      p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+
+      btm_pm_sm_alloc(xx);
+
+      if (dc) memcpy(p->remote_dc, dc, DEV_CLASS_LEN);
+
+      if (bdn) memcpy(p->remote_name, bdn, BTM_MAX_REM_BD_NAME_LEN);
+
+      /* if BR/EDR do something more */
+      if (transport == BT_TRANSPORT_BR_EDR) {
+        btsnd_hcic_read_rmt_clk_offset(p->hci_handle);
+        btsnd_hcic_rmt_ver_req(p->hci_handle);
+      }
+      p_dev_rec = btm_find_dev_by_handle(hci_handle);
+
+      if (p_dev_rec) {
+        BTM_TRACE_DEBUG("%s: peer %s device_type=0x%x", __func__,
+                        bda.ToString().c_str(), p_dev_rec->device_type);
+      }
+
+      if (p_dev_rec && !(transport == BT_TRANSPORT_LE)) {
+        /* If remote features already known, copy them and continue connection
+         * setup */
+        if ((p_dev_rec->num_read_pages) &&
+            (p_dev_rec->num_read_pages <= (HCI_EXT_FEATURES_PAGE_MAX + 1))) {
+          memcpy(p->peer_lmp_feature_pages, p_dev_rec->feature_pages,
+                 (HCI_FEATURE_BYTES_PER_PAGE * p_dev_rec->num_read_pages));
+          p->num_read_pages = p_dev_rec->num_read_pages;
+
+          const uint8_t req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+
+          /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
+          btm_sec_set_peer_sec_caps(p, p_dev_rec);
+
+          BTM_TRACE_API("%s: pend:%d", __func__, req_pend);
+          if (req_pend) {
+            /* Request for remaining Security Features (if any) */
+            l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr);
+          }
+          btm_establish_continue(p);
+          return;
+        }
+      }
+
+      /* If here, features are not known yet */
+      if (p_dev_rec && transport == BT_TRANSPORT_LE) {
+#if (BLE_PRIVACY_SPT == TRUE)
+        btm_ble_get_acl_remote_addr(p_dev_rec, p->active_remote_addr,
+                                    &p->active_remote_addr_type);
+#endif
+
+        if (HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(
+                controller_get_interface()->get_features_ble()->as_array) ||
+            link_role == HCI_ROLE_MASTER) {
+          btsnd_hcic_ble_read_remote_feat(p->hci_handle);
+        } else {
+          btm_establish_continue(p);
+        }
+      }
+
+      /* read page 1 - on rmt feature event for buffer reasons */
+      return;
+    }
+  }
+}
+
+void btm_acl_update_conn_addr(uint16_t conn_handle, const RawAddress& address) {
+  uint8_t idx = btm_handle_to_acl_index(conn_handle);
+  if (idx != MAX_L2CAP_LINKS) {
+    btm_cb.acl_db[idx].conn_addr = address;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_report_role_change
+ *
+ * Description      This function is called when the local device is deemed
+ *                  to be down. It notifies L2CAP of the failure.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_acl_report_role_change(uint8_t hci_status, const RawAddress* bda) {
+  tBTM_ROLE_SWITCH_CMPL ref_data;
+  BTM_TRACE_DEBUG("btm_acl_report_role_change");
+  if (btm_cb.devcb.p_switch_role_cb &&
+      (bda && btm_cb.devcb.switch_role_ref_data.remote_bd_addr == *bda)) {
+    memcpy(&ref_data, &btm_cb.devcb.switch_role_ref_data,
+           sizeof(tBTM_ROLE_SWITCH_CMPL));
+    ref_data.hci_status = hci_status;
+    (*btm_cb.devcb.p_switch_role_cb)(&ref_data);
+    memset(&btm_cb.devcb.switch_role_ref_data, 0,
+           sizeof(tBTM_ROLE_SWITCH_CMPL));
+    btm_cb.devcb.p_switch_role_cb = NULL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_removed
+ *
+ * Description      This function is called by L2CAP when an ACL connection
+ *                  is removed. Since only L2CAP creates ACL links, we use
+ *                  the L2CAP link index as our index into the control blocks.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_acl_removed(const RawAddress& bda, tBT_TRANSPORT transport) {
+  tACL_CONN* p;
+  tBTM_SEC_DEV_REC* p_dev_rec = NULL;
+  BTM_TRACE_DEBUG("btm_acl_removed");
+  p = btm_bda_to_acl(bda, transport);
+  if (p != (tACL_CONN*)NULL) {
+    p->in_use = false;
+
+    /* if the disconnected channel has a pending role switch, clear it now */
+    btm_acl_report_role_change(HCI_ERR_NO_CONNECTION, &bda);
+
+    /* Only notify if link up has had a chance to be issued */
+    if (p->link_up_issued) {
+      p->link_up_issued = false;
+
+      /* If anyone cares, indicate the database changed */
+      if (btm_cb.p_bl_changed_cb) {
+        tBTM_BL_EVENT_DATA evt_data;
+        evt_data.event = BTM_BL_DISCN_EVT;
+        evt_data.discn.p_bda = &bda;
+        evt_data.discn.handle = p->hci_handle;
+        evt_data.discn.transport = p->transport;
+        (*btm_cb.p_bl_changed_cb)(&evt_data);
+      }
+
+      btm_acl_update_busy_level(BTM_BLI_ACL_DOWN_EVT);
+    }
+
+    BTM_TRACE_DEBUG(
+        "acl hci_handle=%d transport=%d connectable_mode=0x%0x link_role=%d",
+        p->hci_handle, p->transport, btm_cb.ble_ctr_cb.inq_var.connectable_mode,
+        p->link_role);
+
+    p_dev_rec = btm_find_dev(bda);
+    if (p_dev_rec) {
+      BTM_TRACE_DEBUG("before update p_dev_rec->sec_flags=0x%x",
+                      p_dev_rec->sec_flags);
+      if (p->transport == BT_TRANSPORT_LE) {
+        BTM_TRACE_DEBUG("LE link down");
+        p_dev_rec->sec_flags &= ~(BTM_SEC_LE_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+        if ((p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) == 0) {
+          BTM_TRACE_DEBUG("Not Bonded");
+          p_dev_rec->sec_flags &=
+              ~(BTM_SEC_LE_LINK_KEY_AUTHED | BTM_SEC_LE_AUTHENTICATED);
+        } else {
+          BTM_TRACE_DEBUG("Bonded");
+        }
+      } else {
+        BTM_TRACE_DEBUG("Bletooth link down");
+        p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED |
+                                  BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+      }
+      BTM_TRACE_DEBUG("after update p_dev_rec->sec_flags=0x%x",
+                      p_dev_rec->sec_flags);
+    } else {
+      BTM_TRACE_ERROR("Device not found");
+    }
+
+    /* Clear the ACL connection data */
+    memset(p, 0, sizeof(tACL_CONN));
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_device_down
+ *
+ * Description      This function is called when the local device is deemed
+ *                  to be down. It notifies L2CAP of the failure.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_acl_device_down(void) {
+  tACL_CONN* p = &btm_cb.acl_db[0];
+  uint16_t xx;
+  BTM_TRACE_DEBUG("btm_acl_device_down");
+  for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) {
+    if (p->in_use) {
+      BTM_TRACE_DEBUG("hci_handle=%d HCI_ERR_HW_FAILURE ", p->hci_handle);
+      l2c_link_hci_disc_comp(p->hci_handle, HCI_ERR_HW_FAILURE);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_update_busy_level
+ *
+ * Description      This function is called to update the busy level of the
+ *                  system.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_acl_update_busy_level(tBTM_BLI_EVENT event) {
+  bool old_inquiry_state = btm_cb.is_inquiry;
+  tBTM_BL_UPDATE_DATA evt;
+  evt.busy_level_flags = 0;
+  switch (event) {
+    case BTM_BLI_ACL_UP_EVT:
+      BTM_TRACE_DEBUG("BTM_BLI_ACL_UP_EVT");
+      break;
+    case BTM_BLI_ACL_DOWN_EVT:
+      BTM_TRACE_DEBUG("BTM_BLI_ACL_DOWN_EVT");
+      break;
+    case BTM_BLI_PAGE_EVT:
+      BTM_TRACE_DEBUG("BTM_BLI_PAGE_EVT");
+      btm_cb.is_paging = true;
+      evt.busy_level_flags = BTM_BL_PAGING_STARTED;
+      break;
+    case BTM_BLI_PAGE_DONE_EVT:
+      BTM_TRACE_DEBUG("BTM_BLI_PAGE_DONE_EVT");
+      btm_cb.is_paging = false;
+      evt.busy_level_flags = BTM_BL_PAGING_COMPLETE;
+      break;
+    case BTM_BLI_INQ_EVT:
+      BTM_TRACE_DEBUG("BTM_BLI_INQ_EVT");
+      btm_cb.is_inquiry = true;
+      evt.busy_level_flags = BTM_BL_INQUIRY_STARTED;
+      break;
+    case BTM_BLI_INQ_CANCEL_EVT:
+      BTM_TRACE_DEBUG("BTM_BLI_INQ_CANCEL_EVT");
+      btm_cb.is_inquiry = false;
+      evt.busy_level_flags = BTM_BL_INQUIRY_CANCELLED;
+      break;
+    case BTM_BLI_INQ_DONE_EVT:
+      BTM_TRACE_DEBUG("BTM_BLI_INQ_DONE_EVT");
+      btm_cb.is_inquiry = false;
+      evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
+      break;
+  }
+
+  uint8_t busy_level;
+  if (btm_cb.is_paging || btm_cb.is_inquiry)
+    busy_level = 10;
+  else
+    busy_level = BTM_GetNumAclLinks();
+
+  if ((busy_level != btm_cb.busy_level) ||
+      (old_inquiry_state != btm_cb.is_inquiry)) {
+    evt.event = BTM_BL_UPDATE_EVT;
+    evt.busy_level = busy_level;
+    btm_cb.busy_level = busy_level;
+    if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_UPDATE_MASK)) {
+      tBTM_BL_EVENT_DATA btm_bl_event_data;
+      btm_bl_event_data.update = evt;
+      (*btm_cb.p_bl_changed_cb)(&btm_bl_event_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetRole
+ *
+ * Description      This function is called to get the role of the local device
+ *                  for the ACL connection with the specified remote device
+ *
+ * Returns          BTM_SUCCESS if connection exists.
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_GetRole(const RawAddress& remote_bd_addr, uint8_t* p_role) {
+  tACL_CONN* p;
+  BTM_TRACE_DEBUG("BTM_GetRole");
+  p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR);
+  if (p == NULL) {
+    *p_role = BTM_ROLE_UNDEFINED;
+    return (BTM_UNKNOWN_ADDR);
+  }
+
+  /* Get the current role */
+  *p_role = p->link_role;
+  return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SwitchRole
+ *
+ * Description      This function is called to switch role between master and
+ *                  slave.  If role is already set it will do nothing.  If the
+ *                  command was initiated, the callback function is called upon
+ *                  completion.
+ *
+ * Returns          BTM_SUCCESS if already in specified role.
+ *                  BTM_CMD_STARTED if command issued to controller.
+ *                  BTM_NO_RESOURCES if couldn't allocate memory to issue
+ *                                   command
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *                  BTM_MODE_UNSUPPORTED if local device does not support role
+ *                                       switching
+ *                  BTM_BUSY if the previous command is not completed
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SwitchRole(const RawAddress& remote_bd_addr, uint8_t new_role,
+                           tBTM_CMPL_CB* p_cb) {
+  tACL_CONN* p;
+  tBTM_SEC_DEV_REC* p_dev_rec = NULL;
+  bool is_sco_active;
+  tBTM_STATUS status;
+  tBTM_PM_MODE pwr_mode;
+  tBTM_PM_PWR_MD settings;
+
+  LOG_INFO(LOG_TAG, "%s: peer %s new_role=0x%x p_cb=%p p_switch_role_cb=%p",
+           __func__, remote_bd_addr.ToString().c_str(), new_role, p_cb,
+           btm_cb.devcb.p_switch_role_cb);
+
+  /* Make sure the local device supports switching */
+  if (!controller_get_interface()->supports_master_slave_role_switch())
+    return (BTM_MODE_UNSUPPORTED);
+
+  if (btm_cb.devcb.p_switch_role_cb && p_cb) {
+    VLOG(2) << "Role switch on other device is in progress "
+            << btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+    return (BTM_BUSY);
+  }
+
+  p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR);
+  if (p == NULL) return (BTM_UNKNOWN_ADDR);
+
+  /* Finished if already in desired role */
+  if (p->link_role == new_role) return (BTM_SUCCESS);
+
+  if (interop_match_addr(INTEROP_DISABLE_ROLE_SWITCH, &remote_bd_addr))
+    return BTM_DEV_BLACKLISTED;
+
+  /* Check if there is any SCO Active on this BD Address */
+  is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr);
+
+  if (is_sco_active) return (BTM_NO_RESOURCES);
+
+  /* Ignore role switch request if the previous request was not completed */
+  if (p->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) {
+    BTM_TRACE_DEBUG("BTM_SwitchRole busy: %d", p->switch_role_state);
+    return (BTM_BUSY);
+  }
+
+  if (interop_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH, &remote_bd_addr)) {
+    BTM_TRACE_DEBUG("%s, Device blacklisted under INTEROP_DYNAMIC_ROLE_SWITCH.",
+                    __func__);
+    return BTM_DEV_BLACKLISTED;
+  }
+
+  status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode);
+  if (status != BTM_SUCCESS) return (status);
+
+  /* Wake up the link if in sniff or park before attempting switch */
+  if (pwr_mode == BTM_PM_MD_PARK || pwr_mode == BTM_PM_MD_SNIFF) {
+    memset((void*)&settings, 0, sizeof(settings));
+    settings.mode = BTM_PM_MD_ACTIVE;
+    status = BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p->remote_addr, &settings);
+    if (status != BTM_CMD_STARTED) return (BTM_WRONG_MODE);
+
+    p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+  }
+  /* some devices do not support switch while encryption is on */
+  else {
+    p_dev_rec = btm_find_dev(remote_bd_addr);
+    if ((p_dev_rec != NULL) &&
+        ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) &&
+        !BTM_EPR_AVAILABLE(p)) {
+      /* bypass turning off encryption if change link key is already doing it */
+      if (p->encrypt_state != BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF) {
+        btsnd_hcic_set_conn_encrypt(p->hci_handle, false);
+        p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+      }
+
+      p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+    } else {
+      btsnd_hcic_switch_role(remote_bd_addr, new_role);
+      p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+
+#if (BTM_DISC_DURING_RS == TRUE)
+      if (p_dev_rec) p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+    }
+  }
+
+  /* Initialize return structure in case request fails */
+  if (p_cb) {
+    btm_cb.devcb.switch_role_ref_data.remote_bd_addr = remote_bd_addr;
+    btm_cb.devcb.switch_role_ref_data.role = new_role;
+    /* initialized to an error code */
+    btm_cb.devcb.switch_role_ref_data.hci_status = HCI_ERR_UNSUPPORTED_VALUE;
+    btm_cb.devcb.p_switch_role_cb = p_cb;
+  }
+  return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_encrypt_change
+ *
+ * Description      This function is when encryption of the connection is
+ *                  completed by the LM.  Checks to see if a role switch or
+ *                  change of link key was active and initiates or continues
+ *                  process if needed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
+                            uint8_t encr_enable) {
+  tACL_CONN* p;
+  uint8_t xx;
+  tBTM_SEC_DEV_REC* p_dev_rec;
+
+  BTM_TRACE_DEBUG("btm_acl_encrypt_change handle=%d status=%d encr_enabl=%d",
+                  handle, status, encr_enable);
+  xx = btm_handle_to_acl_index(handle);
+  /* don't assume that we can never get a bad hci_handle */
+  if (xx < MAX_L2CAP_LINKS)
+    p = &btm_cb.acl_db[xx];
+  else
+    return;
+
+  /* Process Role Switch if active */
+  if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF) {
+    /* if encryption turn off failed we still will try to switch role */
+    if (encr_enable) {
+      p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+      p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+    } else {
+      p->switch_role_state = BTM_ACL_SWKEY_STATE_SWITCHING;
+      p->encrypt_state = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC;
+    }
+
+    btsnd_hcic_switch_role(p->remote_addr, (uint8_t)!p->link_role);
+#if (BTM_DISC_DURING_RS == TRUE)
+    p_dev_rec = btm_find_dev(p->remote_addr);
+    if (p_dev_rec != NULL) p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+
+  }
+  /* Finished enabling Encryption after role switch */
+  else if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON) {
+    p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+    p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+    btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status,
+                               &p->remote_addr);
+
+    /* if role change event is registered, report it now */
+    if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK)) {
+      tBTM_BL_ROLE_CHG_DATA evt;
+      evt.event = BTM_BL_ROLE_CHG_EVT;
+      evt.new_role = btm_cb.devcb.switch_role_ref_data.role;
+      evt.p_bda = &btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+      evt.hci_status = btm_cb.devcb.switch_role_ref_data.hci_status;
+      tBTM_BL_EVENT_DATA btm_bl_event_data;
+      btm_bl_event_data.role_chg = evt;
+      (*btm_cb.p_bl_changed_cb)(&btm_bl_event_data);
+
+      BTM_TRACE_DEBUG(
+          "%s: Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+          __func__, evt.new_role, evt.hci_status, p->switch_role_state);
+    }
+
+#if (BTM_DISC_DURING_RS == TRUE)
+    /* If a disconnect is pending, issue it now that role switch has completed
+     */
+    p_dev_rec = btm_find_dev(p->remote_addr);
+    if (p_dev_rec != NULL) {
+      if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) {
+        BTM_TRACE_WARNING(
+            "btm_acl_encrypt_change -> Issuing delayed HCI_Disconnect!!!");
+        btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+      }
+      BTM_TRACE_ERROR(
+          "btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+          PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
+      p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+    }
+#endif
+  }
+}
+/*******************************************************************************
+ *
+ * Function         BTM_SetLinkPolicy
+ *
+ * Description      Create and send HCI "Write Policy Set" command
+ *
+ * Returns          status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLinkPolicy(const RawAddress& remote_bda,
+                              uint16_t* settings) {
+  tACL_CONN* p;
+  uint8_t* localFeatures = BTM_ReadLocalFeatures();
+  BTM_TRACE_DEBUG("%s", __func__);
+  /*  BTM_TRACE_API ("%s: requested settings: 0x%04x", __func__, *settings ); */
+
+  /* First, check if hold mode is supported */
+  if (*settings != HCI_DISABLE_ALL_LM_MODES) {
+    if ((*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) &&
+        (!HCI_SWITCH_SUPPORTED(localFeatures))) {
+      *settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH);
+      BTM_TRACE_API("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)",
+                    *settings);
+    }
+    if ((*settings & HCI_ENABLE_HOLD_MODE) &&
+        (!HCI_HOLD_MODE_SUPPORTED(localFeatures))) {
+      *settings &= (~HCI_ENABLE_HOLD_MODE);
+      BTM_TRACE_API("BTM_SetLinkPolicy hold not supported (settings: 0x%04x)",
+                    *settings);
+    }
+    if ((*settings & HCI_ENABLE_SNIFF_MODE) &&
+        ((!HCI_SNIFF_MODE_SUPPORTED(localFeatures)) ||
+         interop_match_addr(INTEROP_DISABLE_SNIFF, &remote_bda))) {
+      *settings &= (~HCI_ENABLE_SNIFF_MODE);
+      BTM_TRACE_API("BTM_SetLinkPolicy sniff not supported (settings: 0x%04x)",
+                    *settings);
+    }
+    if ((*settings & HCI_ENABLE_PARK_MODE) &&
+        (!HCI_PARK_MODE_SUPPORTED(localFeatures))) {
+      *settings &= (~HCI_ENABLE_PARK_MODE);
+      BTM_TRACE_API("BTM_SetLinkPolicy park not supported (settings: 0x%04x)",
+                    *settings);
+    }
+  }
+
+  p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+  if (p != NULL) {
+    btsnd_hcic_write_policy_set(p->hci_handle, *settings);
+    return BTM_CMD_STARTED;
+  }
+
+  /* If here, no BD Addr found */
+  return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetDefaultLinkPolicy
+ *
+ * Description      Set the default value for HCI "Write Policy Set" command
+ *                  to use when an ACL link is created.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetDefaultLinkPolicy(uint16_t settings) {
+  uint8_t* localFeatures = BTM_ReadLocalFeatures();
+
+  BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy setting:0x%04x", settings);
+
+  if ((settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) &&
+      (!HCI_SWITCH_SUPPORTED(localFeatures))) {
+    settings &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+    BTM_TRACE_DEBUG(
+        "BTM_SetDefaultLinkPolicy switch not supported (settings: 0x%04x)",
+        settings);
+  }
+  if ((settings & HCI_ENABLE_HOLD_MODE) &&
+      (!HCI_HOLD_MODE_SUPPORTED(localFeatures))) {
+    settings &= ~HCI_ENABLE_HOLD_MODE;
+    BTM_TRACE_DEBUG(
+        "BTM_SetDefaultLinkPolicy hold not supported (settings: 0x%04x)",
+        settings);
+  }
+  if ((settings & HCI_ENABLE_SNIFF_MODE) &&
+      (!HCI_SNIFF_MODE_SUPPORTED(localFeatures))) {
+    settings &= ~HCI_ENABLE_SNIFF_MODE;
+    BTM_TRACE_DEBUG(
+        "BTM_SetDefaultLinkPolicy sniff not supported (settings: 0x%04x)",
+        settings);
+  }
+  if ((settings & HCI_ENABLE_PARK_MODE) &&
+      (!HCI_PARK_MODE_SUPPORTED(localFeatures))) {
+    settings &= ~HCI_ENABLE_PARK_MODE;
+    BTM_TRACE_DEBUG(
+        "BTM_SetDefaultLinkPolicy park not supported (settings: 0x%04x)",
+        settings);
+  }
+  BTM_TRACE_DEBUG("Set DefaultLinkPolicy:0x%04x", settings);
+
+  btm_cb.btm_def_link_policy = settings;
+
+  /* Set the default Link Policy of the controller */
+  btsnd_hcic_write_def_policy_set(settings);
+}
+
+void btm_use_preferred_conn_params(const RawAddress& bda) {
+  tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
+  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
+
+  /* If there are any preferred connection parameters, set them now */
+  if ((p_lcb != NULL) && (p_dev_rec != NULL) &&
+      (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN) &&
+      (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX) &&
+      (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN) &&
+      (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX) &&
+      (p_dev_rec->conn_params.slave_latency <= BTM_BLE_CONN_LATENCY_MAX) &&
+      (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) &&
+      (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) &&
+      ((p_lcb->min_interval < p_dev_rec->conn_params.min_conn_int &&
+        p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ||
+       (p_lcb->min_interval > p_dev_rec->conn_params.max_conn_int) ||
+       (p_lcb->latency > p_dev_rec->conn_params.slave_latency) ||
+       (p_lcb->timeout > p_dev_rec->conn_params.supervision_tout))) {
+    BTM_TRACE_DEBUG(
+        "%s: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d "
+        "supervision_tout=%d",
+        __func__, p_lcb->handle, p_dev_rec->conn_params.min_conn_int,
+        p_dev_rec->conn_params.max_conn_int,
+        p_dev_rec->conn_params.slave_latency,
+        p_dev_rec->conn_params.supervision_tout);
+
+    p_lcb->min_interval = p_dev_rec->conn_params.min_conn_int;
+    p_lcb->max_interval = p_dev_rec->conn_params.max_conn_int;
+    p_lcb->timeout = p_dev_rec->conn_params.supervision_tout;
+    p_lcb->latency = p_dev_rec->conn_params.slave_latency;
+
+    btsnd_hcic_ble_upd_ll_conn_params(
+        p_lcb->handle, p_dev_rec->conn_params.min_conn_int,
+        p_dev_rec->conn_params.max_conn_int,
+        p_dev_rec->conn_params.slave_latency,
+        p_dev_rec->conn_params.supervision_tout, 0, 0);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_remote_version_complete
+ *
+ * Description      This function is called when the command complete message
+ *                  is received from the HCI for the remote version info.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_remote_version_complete(uint8_t* p) {
+  tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+  uint8_t status;
+  uint16_t handle;
+  int xx;
+  BTM_TRACE_DEBUG("btm_read_remote_version_complete");
+
+  STREAM_TO_UINT8(status, p);
+  STREAM_TO_UINT16(handle, p);
+
+  /* Look up the connection by handle and copy features */
+  for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++) {
+    if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle)) {
+      if (status == HCI_SUCCESS) {
+        STREAM_TO_UINT8(p_acl_cb->lmp_version, p);
+        STREAM_TO_UINT16(p_acl_cb->manufacturer, p);
+        STREAM_TO_UINT16(p_acl_cb->lmp_subversion, p);
+
+        if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR) {
+          btm_read_remote_features(p_acl_cb->hci_handle);
+        }
+        bluetooth::common::LogRemoteVersionInfo(
+            handle, status, p_acl_cb->lmp_version, p_acl_cb->manufacturer,
+            p_acl_cb->lmp_subversion);
+      } else {
+        bluetooth::common::LogRemoteVersionInfo(handle, status, 0, 0, 0);
+      }
+
+      if (p_acl_cb->transport == BT_TRANSPORT_LE) {
+        l2cble_notify_le_connection(p_acl_cb->remote_addr);
+        btm_use_preferred_conn_params(p_acl_cb->remote_addr);
+      }
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_process_remote_ext_features
+ *
+ * Description      Local function called to process all extended features pages
+ *                  read from a remote device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
+                                     uint8_t num_read_pages) {
+  uint16_t handle = p_acl_cb->hci_handle;
+  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+  uint8_t page_idx;
+
+  BTM_TRACE_DEBUG("btm_process_remote_ext_features");
+
+  /* Make sure we have the record to save remote features information */
+  if (p_dev_rec == NULL) {
+    /* Get a new device; might be doing dedicated bonding */
+    p_dev_rec = btm_find_or_alloc_dev(p_acl_cb->remote_addr);
+  }
+
+  p_acl_cb->num_read_pages = num_read_pages;
+  p_dev_rec->num_read_pages = num_read_pages;
+
+  /* Move the pages to placeholder */
+  for (page_idx = 0; page_idx < num_read_pages; page_idx++) {
+    if (page_idx > HCI_EXT_FEATURES_PAGE_MAX) {
+      BTM_TRACE_ERROR("%s: page=%d unexpected", __func__, page_idx);
+      break;
+    }
+    memcpy(p_dev_rec->feature_pages[page_idx],
+           p_acl_cb->peer_lmp_feature_pages[page_idx],
+           HCI_FEATURE_BYTES_PER_PAGE);
+  }
+
+  if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) ||
+      p_dev_rec->is_originator) {
+    BTM_TRACE_DEBUG("%s: Calling Next Security Procedure", __func__);
+    uint8_t status = btm_sec_execute_procedure(p_dev_rec);
+    if (status != BTM_CMD_STARTED) {
+      BTM_TRACE_ERROR("%s: Security procedure not started! status %d", __func__,
+                      status);
+      btm_sec_dev_rec_cback_event(p_dev_rec, status, false);
+    }
+  }
+  const uint8_t req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+
+  /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
+  btm_sec_set_peer_sec_caps(p_acl_cb, p_dev_rec);
+
+  BTM_TRACE_API("%s: pend:%d", __func__, req_pend);
+  if (req_pend) {
+    /* Request for remaining Security Features (if any) */
+    l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_remote_features
+ *
+ * Description      Local function called to send a read remote supported
+ *                  features/remote extended features page[0].
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_remote_features(uint16_t handle) {
+  uint8_t acl_idx;
+  tACL_CONN* p_acl_cb;
+
+  BTM_TRACE_DEBUG("btm_read_remote_features() handle: %d", handle);
+
+  acl_idx = btm_handle_to_acl_index(handle);
+  if (acl_idx >= MAX_L2CAP_LINKS) {
+    BTM_TRACE_ERROR("btm_read_remote_features handle=%d invalid", handle);
+    return;
+  }
+
+  p_acl_cb = &btm_cb.acl_db[acl_idx];
+  p_acl_cb->num_read_pages = 0;
+  memset(p_acl_cb->peer_lmp_feature_pages, 0,
+         sizeof(p_acl_cb->peer_lmp_feature_pages));
+
+  /* first send read remote supported features HCI command */
+  /* because we don't know whether the remote support extended feature command
+   */
+  btsnd_hcic_rmt_features_req(handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_remote_ext_features
+ *
+ * Description      Local function called to send a read remote extended
+ *                  features
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number) {
+  BTM_TRACE_DEBUG("btm_read_remote_ext_features() handle: %d page: %d", handle,
+                  page_number);
+
+  btsnd_hcic_rmt_ext_features(handle, page_number);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_remote_features_complete
+ *
+ * Description      This function is called when the remote supported features
+ *                  complete event is received from the HCI.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_remote_features_complete(uint8_t* p) {
+  tACL_CONN* p_acl_cb;
+  uint8_t status;
+  uint16_t handle;
+  uint8_t acl_idx;
+
+  BTM_TRACE_DEBUG("btm_read_remote_features_complete");
+  STREAM_TO_UINT8(status, p);
+
+  if (status != HCI_SUCCESS) {
+    BTM_TRACE_ERROR("btm_read_remote_features_complete failed (status 0x%02x)",
+                    status);
+    return;
+  }
+
+  STREAM_TO_UINT16(handle, p);
+
+  acl_idx = btm_handle_to_acl_index(handle);
+  if (acl_idx >= MAX_L2CAP_LINKS) {
+    BTM_TRACE_ERROR("btm_read_remote_features_complete handle=%d invalid",
+                    handle);
+    return;
+  }
+
+  p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+  /* Copy the received features page */
+  STREAM_TO_ARRAY(p_acl_cb->peer_lmp_feature_pages[0], p,
+                  HCI_FEATURE_BYTES_PER_PAGE);
+
+  if ((HCI_LMP_EXTENDED_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[0])) &&
+      (controller_get_interface()
+           ->supports_reading_remote_extended_features())) {
+    /* if the remote controller has extended features and local controller
+       supports HCI_Read_Remote_Extended_Features command then start reading
+       these feature starting with extended features page 1 */
+    BTM_TRACE_DEBUG("Start reading remote extended features");
+    btm_read_remote_ext_features(handle, 1);
+    return;
+  }
+
+  /* Remote controller has no extended features. Process remote controller
+     supported features (features page 0). */
+  btm_process_remote_ext_features(p_acl_cb, 1);
+
+  /* Continue with HCI connection establishment */
+  btm_establish_continue(p_acl_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_remote_ext_features_complete
+ *
+ * Description      This function is called when the remote extended features
+ *                  complete event is received from the HCI.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_remote_ext_features_complete(uint8_t* p, uint8_t evt_len) {
+  tACL_CONN* p_acl_cb;
+  uint8_t page_num, max_page;
+  uint16_t handle;
+  uint8_t acl_idx;
+
+  BTM_TRACE_DEBUG("btm_read_remote_ext_features_complete");
+
+  if (evt_len < HCI_EXT_FEATURES_SUCCESS_EVT_LEN) {
+    android_errorWriteLog(0x534e4554, "141552859");
+    BTM_TRACE_ERROR(
+        "btm_read_remote_ext_features_complete evt length too short. length=%d",
+        evt_len);
+    return;
+  }
+
+  ++p;
+  STREAM_TO_UINT16(handle, p);
+  STREAM_TO_UINT8(page_num, p);
+  STREAM_TO_UINT8(max_page, p);
+
+  /* Validate parameters */
+  acl_idx = btm_handle_to_acl_index(handle);
+  if (acl_idx >= MAX_L2CAP_LINKS) {
+    BTM_TRACE_ERROR("btm_read_remote_ext_features_complete handle=%d invalid",
+                    handle);
+    return;
+  }
+
+  if (max_page > HCI_EXT_FEATURES_PAGE_MAX) {
+    BTM_TRACE_ERROR("btm_read_remote_ext_features_complete page=%d unknown",
+                    max_page);
+    return;
+  }
+
+  if (page_num > HCI_EXT_FEATURES_PAGE_MAX) {
+    android_errorWriteLog(0x534e4554, "141552859");
+    BTM_TRACE_ERROR("btm_read_remote_ext_features_complete num_page=%d invalid",
+                    page_num);
+    return;
+  }
+
+  if (page_num > max_page) {
+    BTM_TRACE_WARNING(
+        "btm_read_remote_ext_features_complete num_page=%d, max_page=%d "
+        "invalid", page_num, max_page);
+  }
+
+  p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+  /* Copy the received features page */
+  STREAM_TO_ARRAY(p_acl_cb->peer_lmp_feature_pages[page_num], p,
+                  HCI_FEATURE_BYTES_PER_PAGE);
+
+  /* If there is the next remote features page and
+   * we have space to keep this page data - read this page */
+  if ((page_num < max_page) && (page_num < HCI_EXT_FEATURES_PAGE_MAX)) {
+    page_num++;
+    BTM_TRACE_DEBUG("BTM reads next remote extended features page (%d)",
+                    page_num);
+    btm_read_remote_ext_features(handle, page_num);
+    return;
+  }
+
+  /* Reading of remote feature pages is complete */
+  BTM_TRACE_DEBUG("BTM reached last remote extended features page (%d)",
+                  page_num);
+
+  /* Process the pages */
+  btm_process_remote_ext_features(p_acl_cb, (uint8_t)(page_num + 1));
+
+  /* Continue with HCI connection establishment */
+  btm_establish_continue(p_acl_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_remote_ext_features_failed
+ *
+ * Description      This function is called when the remote extended features
+ *                  complete event returns a failed status.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_remote_ext_features_failed(uint8_t status, uint16_t handle) {
+  tACL_CONN* p_acl_cb;
+  uint8_t acl_idx;
+
+  BTM_TRACE_WARNING(
+      "btm_read_remote_ext_features_failed (status 0x%02x) for handle %d",
+      status, handle);
+
+  acl_idx = btm_handle_to_acl_index(handle);
+  if (acl_idx >= MAX_L2CAP_LINKS) {
+    BTM_TRACE_ERROR("btm_read_remote_ext_features_failed handle=%d invalid",
+                    handle);
+    return;
+  }
+
+  p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+  /* Process supported features only */
+  btm_process_remote_ext_features(p_acl_cb, 1);
+
+  /* Continue HCI connection establishment */
+  btm_establish_continue(p_acl_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_establish_continue
+ *
+ * Description      This function is called when the command complete message
+ *                  is received from the HCI for the read local link policy
+ *                  request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_establish_continue(tACL_CONN* p_acl_cb) {
+  tBTM_BL_EVENT_DATA evt_data;
+  BTM_TRACE_DEBUG("btm_establish_continue");
+#if (BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+  if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR) {
+    /* For now there are a some devices that do not like sending */
+    /* commands events and data at the same time. */
+    /* Set the packet types to the default allowed by the device */
+    btm_set_packet_types(p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+    if (btm_cb.btm_def_link_policy)
+      BTM_SetLinkPolicy(p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+  }
+#endif
+  if (p_acl_cb->link_up_issued) {
+    BTM_TRACE_ERROR("%s: Already link is up ", __func__);
+    return;
+  }
+  p_acl_cb->link_up_issued = true;
+
+  /* If anyone cares, tell him database changed */
+  if (btm_cb.p_bl_changed_cb) {
+    evt_data.event = BTM_BL_CONN_EVT;
+    evt_data.conn.p_bda = &p_acl_cb->remote_addr;
+    evt_data.conn.p_bdn = p_acl_cb->remote_name;
+    evt_data.conn.p_dc = p_acl_cb->remote_dc;
+    evt_data.conn.p_features = p_acl_cb->peer_lmp_feature_pages[0];
+    evt_data.conn.handle = p_acl_cb->hci_handle;
+    evt_data.conn.transport = p_acl_cb->transport;
+
+    (*btm_cb.p_bl_changed_cb)(&evt_data);
+  }
+  btm_acl_update_busy_level(BTM_BLI_ACL_UP_EVT);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetDefaultLinkSuperTout
+ *
+ * Description      Set the default value for HCI "Write Link Supervision
+ *                                                 Timeout"
+ *                  command to use when an ACL link is created.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetDefaultLinkSuperTout(uint16_t timeout) {
+  BTM_TRACE_DEBUG("BTM_SetDefaultLinkSuperTout");
+  btm_cb.btm_def_link_super_tout = timeout;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetLinkSuperTout
+ *
+ * Description      Read the link supervision timeout value of the connection
+ *
+ * Returns          status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_GetLinkSuperTout(const RawAddress& remote_bda,
+                                 uint16_t* p_timeout) {
+  tACL_CONN* p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+  BTM_TRACE_DEBUG("BTM_GetLinkSuperTout");
+  if (p != (tACL_CONN*)NULL) {
+    *p_timeout = p->link_super_tout;
+    return (BTM_SUCCESS);
+  }
+  /* If here, no BD Addr found */
+  return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetLinkSuperTout
+ *
+ * Description      Create and send HCI "Write Link Supervision Timeout" command
+ *
+ * Returns          status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLinkSuperTout(const RawAddress& remote_bda,
+                                 uint16_t timeout) {
+  tACL_CONN* p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+  BTM_TRACE_DEBUG("BTM_SetLinkSuperTout");
+  if (p != (tACL_CONN*)NULL) {
+    p->link_super_tout = timeout;
+
+    /* Only send if current role is Master; 2.0 spec requires this */
+    if (p->link_role == BTM_ROLE_MASTER) {
+      btsnd_hcic_write_link_super_tout(LOCAL_BR_EDR_CONTROLLER_ID,
+                                       p->hci_handle, timeout);
+      return (BTM_CMD_STARTED);
+    } else {
+      return (BTM_SUCCESS);
+    }
+  }
+
+  /* If here, no BD Addr found */
+  return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_IsAclConnectionUp
+ *
+ * Description      This function is called to check if an ACL connection exists
+ *                  to a specific remote BD Address.
+ *
+ * Returns          true if connection is up, else false.
+ *
+ ******************************************************************************/
+bool BTM_IsAclConnectionUp(const RawAddress& remote_bda,
+                           tBT_TRANSPORT transport) {
+  tACL_CONN* p;
+
+  VLOG(2) << __func__ << " RemBdAddr: " << remote_bda;
+
+  p = btm_bda_to_acl(remote_bda, transport);
+  if (p != (tACL_CONN*)NULL) {
+    return (true);
+  }
+
+  /* If here, no BD Addr found */
+  return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetNumAclLinks
+ *
+ * Description      This function is called to count the number of
+ *                  ACL links that are active.
+ *
+ * Returns          uint16_t Number of active ACL links
+ *
+ ******************************************************************************/
+uint16_t BTM_GetNumAclLinks(void) {
+  uint16_t num_acl = 0;
+
+  for (uint16_t i = 0; i < MAX_L2CAP_LINKS; ++i) {
+    if (btm_cb.acl_db[i].in_use) ++num_acl;
+  }
+
+  return num_acl;
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_get_acl_disc_reason_code
+ *
+ * Description      This function is called to get the disconnection reason code
+ *                  returned by the HCI at disconnection complete event.
+ *
+ * Returns          true if connection is up, else false.
+ *
+ ******************************************************************************/
+uint16_t btm_get_acl_disc_reason_code(void) {
+  uint8_t res = btm_cb.acl_disc_reason;
+  BTM_TRACE_DEBUG("btm_get_acl_disc_reason_code");
+  return (res);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetHCIConnHandle
+ *
+ * Description      This function is called to get the handle for an ACL
+ *                  connection to a specific remote BD Address.
+ *
+ * Returns          the handle of the connection, or 0xFFFF if none.
+ *
+ ******************************************************************************/
+uint16_t BTM_GetHCIConnHandle(const RawAddress& remote_bda,
+                              tBT_TRANSPORT transport) {
+  tACL_CONN* p;
+  BTM_TRACE_DEBUG("BTM_GetHCIConnHandle");
+  p = btm_bda_to_acl(remote_bda, transport);
+  if (p != (tACL_CONN*)NULL) {
+    return (p->hci_handle);
+  }
+
+  /* If here, no BD Addr found */
+  return (0xFFFF);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_process_clk_off_comp_evt
+ *
+ * Description      This function is called when clock offset command completes.
+ *
+ * Input Parms      hci_handle - connection handle associated with the change
+ *                  clock offset
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_process_clk_off_comp_evt(uint16_t hci_handle, uint16_t clock_offset) {
+  uint8_t xx;
+  BTM_TRACE_DEBUG("btm_process_clk_off_comp_evt");
+  /* Look up the connection by handle and set the current mode */
+  xx = btm_handle_to_acl_index(hci_handle);
+  if (xx < MAX_L2CAP_LINKS) btm_cb.acl_db[xx].clock_offset = clock_offset;
+}
+
+/*******************************************************************************
+*
+* Function         btm_blacklist_role_change_device
+*
+* Description      This function is used to blacklist the device if the role
+*                  switch fails for maximum number of times. It also removes
+*                  the device from the black list if the role switch succeeds.
+*
+* Input Parms      bd_addr - remote BD addr
+*                  hci_status - role switch status
+*
+* Returns          void
+*
+*******************************************************************************/
+void btm_blacklist_role_change_device(const RawAddress& bd_addr,
+                                      uint8_t hci_status) {
+  tACL_CONN* p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
+  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+  if (!p || !p_dev_rec) {
+    return;
+  }
+  if (hci_status == HCI_SUCCESS) {
+    p->switch_role_failed_attempts = 0;
+    return;
+  }
+
+  /* check for carkits */
+  const uint32_t cod_audio_device =
+      (BTM_COD_SERVICE_AUDIO | BTM_COD_MAJOR_AUDIO) << 8;
+  const uint32_t cod =
+      ((p_dev_rec->dev_class[0] << 16) | (p_dev_rec->dev_class[1] << 8) |
+       p_dev_rec->dev_class[2]) &
+      0xffffff;
+  if ((hci_status != HCI_SUCCESS) &&
+      ((p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING) ||
+       (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS)) &&
+      ((cod & cod_audio_device) == cod_audio_device) &&
+      (!interop_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH, &bd_addr))) {
+    p->switch_role_failed_attempts++;
+    if (p->switch_role_failed_attempts == BTM_MAX_SW_ROLE_FAILED_ATTEMPTS) {
+      BTM_TRACE_WARNING(
+          "%s: Device %s blacklisted for role switching - "
+          "multiple role switch failed attempts: %u",
+          __func__, bd_addr.ToString().c_str(), p->switch_role_failed_attempts);
+      interop_database_add(INTEROP_DYNAMIC_ROLE_SWITCH, &bd_addr, 3);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_role_changed
+ *
+ * Description      This function is called whan a link's master/slave role
+ *                  change event or command status event (with error) is
+ *                  received. It updates the link control block, and calls the
+ *                  registered callback with status and role (if registered).
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_acl_role_changed(uint8_t hci_status, const RawAddress* bd_addr,
+                          uint8_t new_role) {
+  const RawAddress* p_bda =
+      (bd_addr) ? bd_addr : &btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+  tACL_CONN* p = btm_bda_to_acl(*p_bda, BT_TRANSPORT_BR_EDR);
+  tBTM_ROLE_SWITCH_CMPL* p_data = &btm_cb.devcb.switch_role_ref_data;
+  tBTM_SEC_DEV_REC* p_dev_rec;
+
+  BTM_TRACE_DEBUG("%s: peer %s hci_status:0x%x new_role:%d", __func__,
+                  (p_bda != nullptr) ? bd_addr->ToString().c_str() : "nullptr",
+                  hci_status, new_role);
+  /* Ignore any stray events */
+  if (p == NULL) {
+    /* it could be a failure */
+    if (hci_status != HCI_SUCCESS)
+      btm_acl_report_role_change(hci_status, bd_addr);
+    return;
+  }
+
+  p_data->hci_status = hci_status;
+
+  if (hci_status == HCI_SUCCESS) {
+    p_data->role = new_role;
+    p_data->remote_bd_addr = *p_bda;
+
+    /* Update cached value */
+    p->link_role = new_role;
+
+    /* Reload LSTO: link supervision timeout is reset in the LM after a role
+     * switch */
+    if (new_role == BTM_ROLE_MASTER) {
+      BTM_SetLinkSuperTout(p->remote_addr, p->link_super_tout);
+    }
+  } else {
+    /* so the BTM_BL_ROLE_CHG_EVT uses the old role */
+    new_role = p->link_role;
+  }
+
+  /* Check if any SCO req is pending for role change */
+  btm_sco_chk_pend_rolechange(p->hci_handle);
+
+  /* if switching state is switching we need to turn encryption on */
+  /* if idle, we did not change encryption */
+  if (p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING) {
+    btsnd_hcic_set_conn_encrypt(p->hci_handle, true);
+    p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON;
+    p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+    return;
+  }
+
+  /* Set the switch_role_state to IDLE since the reply received from HCI */
+  /* regardless of its result either success or failed. */
+  if (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS) {
+    p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+    p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+  }
+
+  /* if role switch complete is needed, report it now */
+  btm_acl_report_role_change(hci_status, bd_addr);
+
+  /* if role change event is registered, report it now */
+  if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK)) {
+    tBTM_BL_ROLE_CHG_DATA evt;
+    evt.event = BTM_BL_ROLE_CHG_EVT;
+    evt.new_role = new_role;
+    evt.p_bda = p_bda;
+    evt.hci_status = hci_status;
+    tBTM_BL_EVENT_DATA btm_bl_event_data;
+    btm_bl_event_data.role_chg = evt;
+    (*btm_cb.p_bl_changed_cb)(&btm_bl_event_data);
+  }
+
+  BTM_TRACE_DEBUG(
+      "%s: peer %s Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, "
+      "rs_st:%d",
+      __func__, (p_bda != nullptr) ? p_bda->ToString().c_str() : "nullptr",
+      p_data->role, p_data->hci_status, p->switch_role_state);
+
+#if (BTM_DISC_DURING_RS == TRUE)
+  /* If a disconnect is pending, issue it now that role switch has completed */
+  p_dev_rec = btm_find_dev(*p_bda);
+  if (p_dev_rec != NULL) {
+    if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) {
+      BTM_TRACE_WARNING(
+          "%s peer %s Issuing delayed HCI_Disconnect!!!", __func__,
+          (p_bda != nullptr) ? p_bda->ToString().c_str() : "nullptr");
+      btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+    }
+    BTM_TRACE_ERROR("%s: peer %s tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+                    __func__,
+                    (p_bda != nullptr) ? p_bda->ToString().c_str() : "nullptr",
+                    PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
+    p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+  }
+
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_AllocateSCN
+ *
+ * Description      Look through the Server Channel Numbers for a free one.
+ *
+ * Returns          Allocated SCN number or 0 if none.
+ *
+ ******************************************************************************/
+
+uint8_t BTM_AllocateSCN(void) {
+  uint8_t x;
+  BTM_TRACE_DEBUG("BTM_AllocateSCN");
+
+  // stack reserves scn 1 for HFP, HSP we still do the correct way
+  for (x = 1; x < BTM_MAX_SCN; x++) {
+    if (!btm_cb.btm_scn[x]) {
+      btm_cb.btm_scn[x] = true;
+      return (x + 1);
+    }
+  }
+
+  return (0); /* No free ports */
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_TryAllocateSCN
+ *
+ * Description      Try to allocate a fixed server channel
+ *
+ * Returns          Returns true if server channel was available
+ *
+ ******************************************************************************/
+
+bool BTM_TryAllocateSCN(uint8_t scn) {
+  /* Make sure we don't exceed max port range.
+   * Stack reserves scn 1 for HFP, HSP we still do the correct way.
+   */
+  if ((scn >= BTM_MAX_SCN) || (scn == 1) || (scn == 0)) return false;
+
+  /* check if this port is available */
+  if (!btm_cb.btm_scn[scn - 1]) {
+    btm_cb.btm_scn[scn - 1] = true;
+    return true;
+  }
+
+  return (false); /* Port was busy */
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_FreeSCN
+ *
+ * Description      Free the specified SCN.
+ *
+ * Returns          true or false
+ *
+ ******************************************************************************/
+bool BTM_FreeSCN(uint8_t scn) {
+  BTM_TRACE_DEBUG("BTM_FreeSCN ");
+  if (scn <= BTM_MAX_SCN && scn > 0) {
+    btm_cb.btm_scn[scn - 1] = false;
+    return (true);
+  } else {
+    return (false); /* Illegal SCN passed in */
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_set_packet_types
+ *
+ * Description      This function sets the packet types used for a specific
+ *                  ACL connection. It is called internally by btm_acl_created
+ *                  or by an application/profile by BTM_SetPacketTypes.
+ *
+ * Returns          status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_set_packet_types(tACL_CONN* p, uint16_t pkt_types) {
+  uint16_t temp_pkt_types;
+  BTM_TRACE_DEBUG("btm_set_packet_types");
+  /* Save in the ACL control blocks, types that we support */
+  temp_pkt_types = (pkt_types & BTM_ACL_SUPPORTED_PKTS_MASK &
+                    btm_cb.btm_acl_pkt_types_supported);
+
+  /* OR in any exception packet types if at least 2.0 version of spec */
+  temp_pkt_types |=
+      ((pkt_types & BTM_ACL_EXCEPTION_PKTS_MASK) |
+       (btm_cb.btm_acl_pkt_types_supported & BTM_ACL_EXCEPTION_PKTS_MASK));
+
+  /* Exclude packet types not supported by the peer */
+  btm_acl_chk_peer_pkt_type_support(p, &temp_pkt_types);
+
+  BTM_TRACE_DEBUG("SetPacketType Mask -> 0x%04x", temp_pkt_types);
+
+  btsnd_hcic_change_conn_type(p->hci_handle, temp_pkt_types);
+  p->pkt_types_mask = temp_pkt_types;
+
+  return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_get_max_packet_size
+ *
+ * Returns          Returns maximum packet size that can be used for current
+ *                  connection, 0 if connection is not established
+ *
+ ******************************************************************************/
+uint16_t btm_get_max_packet_size(const RawAddress& addr) {
+  tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+  uint16_t pkt_types = 0;
+  uint16_t pkt_size = 0;
+  BTM_TRACE_DEBUG("btm_get_max_packet_size");
+  if (p != NULL) {
+    pkt_types = p->pkt_types_mask;
+  } else {
+    /* Special case for when info for the local device is requested */
+    if (addr == *controller_get_interface()->get_address()) {
+      pkt_types = btm_cb.btm_acl_pkt_types_supported;
+    }
+  }
+
+  if (pkt_types) {
+    if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH5))
+      pkt_size = HCI_EDR3_DH5_PACKET_SIZE;
+    else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH5))
+      pkt_size = HCI_EDR2_DH5_PACKET_SIZE;
+    else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH3))
+      pkt_size = HCI_EDR3_DH3_PACKET_SIZE;
+    else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH5)
+      pkt_size = HCI_DH5_PACKET_SIZE;
+    else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH3))
+      pkt_size = HCI_EDR2_DH3_PACKET_SIZE;
+    else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM5)
+      pkt_size = HCI_DM5_PACKET_SIZE;
+    else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH3)
+      pkt_size = HCI_DH3_PACKET_SIZE;
+    else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM3)
+      pkt_size = HCI_DM3_PACKET_SIZE;
+    else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH1))
+      pkt_size = HCI_EDR3_DH1_PACKET_SIZE;
+    else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH1))
+      pkt_size = HCI_EDR2_DH1_PACKET_SIZE;
+    else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH1)
+      pkt_size = HCI_DH1_PACKET_SIZE;
+    else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM1)
+      pkt_size = HCI_DM1_PACKET_SIZE;
+  }
+
+  return (pkt_size);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRemoteVersion
+ *
+ * Returns          If connected report peer device info
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version,
+                                  uint16_t* manufacturer,
+                                  uint16_t* lmp_sub_version) {
+  tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+  BTM_TRACE_DEBUG("BTM_ReadRemoteVersion");
+  if (p == NULL) return (BTM_UNKNOWN_ADDR);
+
+  if (lmp_version) *lmp_version = p->lmp_version;
+
+  if (manufacturer) *manufacturer = p->manufacturer;
+
+  if (lmp_sub_version) *lmp_sub_version = p->lmp_subversion;
+
+  return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRemoteFeatures
+ *
+ * Returns          pointer to the remote supported features mask (8 bytes)
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadRemoteFeatures(const RawAddress& addr) {
+  tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+  BTM_TRACE_DEBUG("BTM_ReadRemoteFeatures");
+  if (p == NULL) {
+    return (NULL);
+  }
+
+  return (p->peer_lmp_feature_pages[0]);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_RegBusyLevelNotif
+ *
+ * Description      This function is called to register a callback to receive
+ *                  busy level change events.
+ *
+ * Returns          BTM_SUCCESS if successfully registered, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegBusyLevelNotif(tBTM_BL_CHANGE_CB* p_cb, uint8_t* p_level,
+                                  tBTM_BL_EVENT_MASK evt_mask) {
+  BTM_TRACE_DEBUG("BTM_RegBusyLevelNotif");
+  if (p_level) *p_level = btm_cb.busy_level;
+
+  btm_cb.bl_evt_mask = evt_mask;
+
+  if (!p_cb)
+    btm_cb.p_bl_changed_cb = NULL;
+  else if (btm_cb.p_bl_changed_cb)
+    return (BTM_BUSY);
+  else
+    btm_cb.p_bl_changed_cb = p_cb;
+
+  return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_qos_setup_timeout
+ *
+ * Description      Callback when QoS setup times out.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_qos_setup_timeout(UNUSED_ATTR void* data) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_qos_setup_cmpl_cb;
+  btm_cb.devcb.p_qos_setup_cmpl_cb = NULL;
+  if (p_cb) (*p_cb)((void*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_qos_setup_complete
+ *
+ * Description      This function is called when the command complete message
+ *                  is received from the HCI for the qos setup request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_qos_setup_complete(uint8_t status, uint16_t handle,
+                            FLOW_SPEC* p_flow) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_qos_setup_cmpl_cb;
+  tBTM_QOS_SETUP_CMPL qossu;
+
+  BTM_TRACE_DEBUG("%s", __func__);
+  alarm_cancel(btm_cb.devcb.qos_setup_timer);
+  btm_cb.devcb.p_qos_setup_cmpl_cb = NULL;
+
+  /* If there was a registered callback, call it */
+  if (p_cb) {
+    memset(&qossu, 0, sizeof(tBTM_QOS_SETUP_CMPL));
+    qossu.status = status;
+    qossu.handle = handle;
+    if (p_flow != NULL) {
+      qossu.flow.qos_flags = p_flow->qos_flags;
+      qossu.flow.service_type = p_flow->service_type;
+      qossu.flow.token_rate = p_flow->token_rate;
+      qossu.flow.peak_bandwidth = p_flow->peak_bandwidth;
+      qossu.flow.latency = p_flow->latency;
+      qossu.flow.delay_variation = p_flow->delay_variation;
+    }
+    BTM_TRACE_DEBUG("BTM: p_flow->delay_variation: 0x%02x",
+                    qossu.flow.delay_variation);
+    (*p_cb)(&qossu);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRSSI
+ *
+ * Description      This function is called to read the link policy settings.
+ *                  The address of link policy results are returned in the
+ *                  callback.
+ *                  (tBTM_RSSI_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated or error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRSSI(const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb) {
+  tACL_CONN* p = NULL;
+  tBT_DEVICE_TYPE dev_type;
+  tBLE_ADDR_TYPE addr_type;
+
+  /* If someone already waiting on the version, do not allow another */
+  if (btm_cb.devcb.p_rssi_cmpl_cb) return (BTM_BUSY);
+
+  BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+
+  if (dev_type & BT_DEVICE_TYPE_BLE) {
+    p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE);
+  }
+
+  if (p == NULL && dev_type & BT_DEVICE_TYPE_BREDR) {
+    p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+  }
+
+  if (p) {
+    btm_cb.devcb.p_rssi_cmpl_cb = p_cb;
+    alarm_set_on_mloop(btm_cb.devcb.read_rssi_timer, BTM_DEV_REPLY_TIMEOUT_MS,
+                       btm_read_rssi_timeout, NULL);
+
+    btsnd_hcic_read_rssi(p->hci_handle);
+    return (BTM_CMD_STARTED);
+  }
+
+  /* If here, no BD Addr found */
+  return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadFailedContactCounter
+ *
+ * Description      This function is called to read the failed contact counter.
+ *                  The result is returned in the callback.
+ *                  (tBTM_FAILED_CONTACT_COUNTER_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated or error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadFailedContactCounter(const RawAddress& remote_bda,
+                                         tBTM_CMPL_CB* p_cb) {
+  tACL_CONN* p;
+  tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+  tBT_DEVICE_TYPE dev_type;
+  tBLE_ADDR_TYPE addr_type;
+
+  /* If someone already waiting on the result, do not allow another */
+  if (btm_cb.devcb.p_failed_contact_counter_cmpl_cb) return (BTM_BUSY);
+
+  BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+  if (dev_type == BT_DEVICE_TYPE_BLE) transport = BT_TRANSPORT_LE;
+
+  p = btm_bda_to_acl(remote_bda, transport);
+  if (p != (tACL_CONN*)NULL) {
+    btm_cb.devcb.p_failed_contact_counter_cmpl_cb = p_cb;
+    alarm_set_on_mloop(btm_cb.devcb.read_failed_contact_counter_timer,
+                       BTM_DEV_REPLY_TIMEOUT_MS,
+                       btm_read_failed_contact_counter_timeout, NULL);
+
+    btsnd_hcic_read_failed_contact_counter(p->hci_handle);
+    return (BTM_CMD_STARTED);
+  }
+
+  /* If here, no BD Addr found */
+  return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadAutomaticFlushTimeout
+ *
+ * Description      This function is called to read the automatic flush timeout.
+ *                  The result is returned in the callback.
+ *                  (tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated or error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadAutomaticFlushTimeout(const RawAddress& remote_bda,
+                                          tBTM_CMPL_CB* p_cb) {
+  tACL_CONN* p;
+  tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+  tBT_DEVICE_TYPE dev_type;
+  tBLE_ADDR_TYPE addr_type;
+
+  /* If someone already waiting on the result, do not allow another */
+  if (btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb) return (BTM_BUSY);
+
+  BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+  if (dev_type == BT_DEVICE_TYPE_BLE) transport = BT_TRANSPORT_LE;
+
+  p = btm_bda_to_acl(remote_bda, transport);
+  if (!p) return BTM_UNKNOWN_ADDR;
+
+  btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb = p_cb;
+  alarm_set_on_mloop(btm_cb.devcb.read_automatic_flush_timeout_timer,
+                     BTM_DEV_REPLY_TIMEOUT_MS,
+                     btm_read_automatic_flush_timeout_timeout, nullptr);
+
+  btsnd_hcic_read_automatic_flush_timeout(p->hci_handle);
+  return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadTxPower
+ *
+ * Description      This function is called to read the current
+ *                  TX power of the connection. The tx power level results
+ *                  are returned in the callback.
+ *                  (tBTM_RSSI_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated or error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadTxPower(const RawAddress& remote_bda,
+                            tBT_TRANSPORT transport, tBTM_CMPL_CB* p_cb) {
+  tACL_CONN* p;
+#define BTM_READ_RSSI_TYPE_CUR 0x00
+#define BTM_READ_RSSI_TYPE_MAX 0X01
+
+  VLOG(2) << __func__ << ": RemBdAddr: " << remote_bda;
+
+  /* If someone already waiting on the version, do not allow another */
+  if (btm_cb.devcb.p_tx_power_cmpl_cb) return (BTM_BUSY);
+
+  p = btm_bda_to_acl(remote_bda, transport);
+  if (p != (tACL_CONN*)NULL) {
+    btm_cb.devcb.p_tx_power_cmpl_cb = p_cb;
+    alarm_set_on_mloop(btm_cb.devcb.read_tx_power_timer,
+                       BTM_DEV_REPLY_TIMEOUT_MS, btm_read_tx_power_timeout,
+                       NULL);
+
+    if (p->transport == BT_TRANSPORT_LE) {
+      btm_cb.devcb.read_tx_pwr_addr = remote_bda;
+      btsnd_hcic_ble_read_adv_chnl_tx_power();
+    } else {
+      btsnd_hcic_read_tx_power(p->hci_handle, BTM_READ_RSSI_TYPE_CUR);
+    }
+
+    return (BTM_CMD_STARTED);
+  }
+
+  /* If here, no BD Addr found */
+  return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_tx_power_timeout
+ *
+ * Description      Callback when reading the tx power times out.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_tx_power_timeout(UNUSED_ATTR void* data) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_tx_power_cmpl_cb;
+  btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+  if (p_cb) (*p_cb)((void*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_tx_power_complete
+ *
+ * Description      This function is called when the command complete message
+ *                  is received from the HCI for the read tx power request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_tx_power_complete(uint8_t* p, bool is_ble) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_tx_power_cmpl_cb;
+  tBTM_TX_POWER_RESULT result;
+  tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+
+  BTM_TRACE_DEBUG("%s", __func__);
+  alarm_cancel(btm_cb.devcb.read_tx_power_timer);
+  btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+
+  /* If there was a registered callback, call it */
+  if (p_cb) {
+    STREAM_TO_UINT8(result.hci_status, p);
+
+    if (result.hci_status == HCI_SUCCESS) {
+      result.status = BTM_SUCCESS;
+
+      if (!is_ble) {
+        uint16_t handle;
+        STREAM_TO_UINT16(handle, p);
+        STREAM_TO_UINT8(result.tx_power, p);
+
+        /* Search through the list of active channels for the correct BD Addr */
+        for (uint16_t index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) {
+          if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) {
+            result.rem_bda = p_acl_cb->remote_addr;
+            break;
+          }
+        }
+      } else {
+        STREAM_TO_UINT8(result.tx_power, p);
+        result.rem_bda = btm_cb.devcb.read_tx_pwr_addr;
+      }
+      BTM_TRACE_DEBUG("BTM TX power Complete: tx_power %d, hci status 0x%02x",
+                      result.tx_power, result.hci_status);
+    } else {
+      result.status = BTM_ERR_PROCESSING;
+    }
+
+    (*p_cb)(&result);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_rssi_timeout
+ *
+ * Description      Callback when reading the RSSI times out.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_rssi_timeout(UNUSED_ATTR void* data) {
+  tBTM_RSSI_RESULT result;
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+  btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+  result.status = BTM_DEVICE_TIMEOUT;
+  if (p_cb) (*p_cb)(&result);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_rssi_complete
+ *
+ * Description      This function is called when the command complete message
+ *                  is received from the HCI for the read rssi request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_rssi_complete(uint8_t* p) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+  tBTM_RSSI_RESULT result;
+  tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+
+  BTM_TRACE_DEBUG("%s", __func__);
+  alarm_cancel(btm_cb.devcb.read_rssi_timer);
+  btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+  /* If there was a registered callback, call it */
+  if (p_cb) {
+    STREAM_TO_UINT8(result.hci_status, p);
+
+    if (result.hci_status == HCI_SUCCESS) {
+      uint16_t handle;
+      result.status = BTM_SUCCESS;
+
+      STREAM_TO_UINT16(handle, p);
+
+      STREAM_TO_UINT8(result.rssi, p);
+      BTM_TRACE_DEBUG("BTM RSSI Complete: rssi %d, hci status 0x%02x",
+                      result.rssi, result.hci_status);
+
+      /* Search through the list of active channels for the correct BD Addr */
+      for (uint16_t index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) {
+        if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) {
+          result.rem_bda = p_acl_cb->remote_addr;
+          break;
+        }
+      }
+    } else {
+      result.status = BTM_ERR_PROCESSING;
+    }
+
+    (*p_cb)(&result);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_failed_contact_counter_timeout
+ *
+ * Description      Callback when reading the failed contact counter times out.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_failed_contact_counter_timeout(UNUSED_ATTR void* data) {
+  tBTM_FAILED_CONTACT_COUNTER_RESULT result;
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_failed_contact_counter_cmpl_cb;
+  btm_cb.devcb.p_failed_contact_counter_cmpl_cb = NULL;
+  result.status = BTM_DEVICE_TIMEOUT;
+  if (p_cb) (*p_cb)(&result);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_failed_contact_counter_complete
+ *
+ * Description      This function is called when the command complete message
+ *                  is received from the HCI for the read failed contact
+ *                  counter request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_failed_contact_counter_complete(uint8_t* p) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_failed_contact_counter_cmpl_cb;
+  tBTM_FAILED_CONTACT_COUNTER_RESULT result;
+  tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+
+  BTM_TRACE_DEBUG("%s", __func__);
+  alarm_cancel(btm_cb.devcb.read_failed_contact_counter_timer);
+  btm_cb.devcb.p_failed_contact_counter_cmpl_cb = NULL;
+
+  /* If there was a registered callback, call it */
+  if (p_cb) {
+    uint16_t handle;
+    STREAM_TO_UINT8(result.hci_status, p);
+
+    if (result.hci_status == HCI_SUCCESS) {
+      result.status = BTM_SUCCESS;
+
+      STREAM_TO_UINT16(handle, p);
+
+      STREAM_TO_UINT16(result.failed_contact_counter, p);
+      BTM_TRACE_DEBUG(
+          "BTM Failed Contact Counter Complete: counter %u, hci status 0x%02x",
+          result.failed_contact_counter, result.hci_status);
+
+      /* Search through the list of active channels for the correct BD Addr */
+      for (uint16_t index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) {
+        if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) {
+          result.rem_bda = p_acl_cb->remote_addr;
+          break;
+        }
+      }
+    } else {
+      result.status = BTM_ERR_PROCESSING;
+    }
+
+    (*p_cb)(&result);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_automatic_flush_timeout_timeout
+ *
+ * Description      Callback when reading the automatic flush timeout times out.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_automatic_flush_timeout_timeout(UNUSED_ATTR void* data) {
+  tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT result;
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb;
+  btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb = nullptr;
+  result.status = BTM_DEVICE_TIMEOUT;
+  if (p_cb) (*p_cb)(&result);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_automatic_flush_timeout_complete
+ *
+ * Description      This function is called when the command complete message
+ *                  is received from the HCI for the read automatic flush
+ *                  timeout request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_automatic_flush_timeout_complete(uint8_t* p) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb;
+  tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT result;
+  tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+
+  BTM_TRACE_DEBUG("%s", __func__);
+  alarm_cancel(btm_cb.devcb.read_automatic_flush_timeout_timer);
+  btm_cb.devcb.p_automatic_flush_timeout_cmpl_cb = nullptr;
+
+  /* If there was a registered callback, call it */
+  if (p_cb) {
+    uint16_t handle;
+    STREAM_TO_UINT8(result.hci_status, p);
+
+    if (result.hci_status == HCI_SUCCESS) {
+      result.status = BTM_SUCCESS;
+
+      STREAM_TO_UINT16(handle, p);
+
+      STREAM_TO_UINT16(result.automatic_flush_timeout, p);
+      BTM_TRACE_DEBUG(
+          "BTM Automatic Flush Timeout Complete: timeout %u, hci status 0x%02x",
+          result.automatic_flush_timeout, result.hci_status);
+
+      /* Search through the list of active channels for the correct BD Addr */
+      for (uint16_t index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) {
+        if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) {
+          result.rem_bda = p_acl_cb->remote_addr;
+          break;
+        }
+      }
+    } else {
+      result.status = BTM_ERR_PROCESSING;
+    }
+
+    (*p_cb)(&result);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_link_quality_timeout
+ *
+ * Description      Callback when reading the link quality times out.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_link_quality_timeout(UNUSED_ATTR void* data) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_link_qual_cmpl_cb;
+  btm_cb.devcb.p_link_qual_cmpl_cb = NULL;
+  if (p_cb) (*p_cb)((void*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_read_link_quality_complete
+ *
+ * Description      This function is called when the command complete message
+ *                  is received from the HCI for the read link quality.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_read_link_quality_complete(uint8_t* p) {
+  tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_link_qual_cmpl_cb;
+  tBTM_LINK_QUALITY_RESULT result;
+  tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+
+  BTM_TRACE_DEBUG("%s", __func__);
+  alarm_cancel(btm_cb.devcb.read_link_quality_timer);
+  btm_cb.devcb.p_link_qual_cmpl_cb = NULL;
+
+  /* If there was a registered callback, call it */
+  if (p_cb) {
+    STREAM_TO_UINT8(result.hci_status, p);
+
+    if (result.hci_status == HCI_SUCCESS) {
+      uint16_t handle;
+      result.status = BTM_SUCCESS;
+
+      STREAM_TO_UINT16(handle, p);
+
+      STREAM_TO_UINT8(result.link_quality, p);
+      BTM_TRACE_DEBUG(
+          "BTM Link Quality Complete: Link Quality %d, hci status 0x%02x",
+          result.link_quality, result.hci_status);
+
+      /* Search through the list of active channels for the correct BD Addr */
+      for (uint16_t index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) {
+        if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) {
+          result.rem_bda = p_acl_cb->remote_addr;
+          break;
+        }
+      }
+    } else {
+      result.status = BTM_ERR_PROCESSING;
+    }
+
+    (*p_cb)(&result);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_remove_acl
+ *
+ * Description      This function is called to disconnect an ACL connection
+ *
+ * Returns          BTM_SUCCESS if successfully initiated, otherwise
+ *                  BTM_NO_RESOURCES.
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_remove_acl(const RawAddress& bd_addr, tBT_TRANSPORT transport) {
+  uint16_t hci_handle = BTM_GetHCIConnHandle(bd_addr, transport);
+  tBTM_STATUS status = BTM_SUCCESS;
+
+  BTM_TRACE_DEBUG("btm_remove_acl");
+#if (BTM_DISC_DURING_RS == TRUE)
+  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+  /* Role Switch is pending, postpone until completed */
+  if (p_dev_rec && (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING)) {
+    p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+  } else /* otherwise can disconnect right away */
+#endif
+  {
+    if (hci_handle != 0xFFFF && p_dev_rec &&
+        p_dev_rec->sec_state != BTM_SEC_STATE_DISCONNECTING) {
+      btsnd_hcic_disconnect(hci_handle, HCI_ERR_PEER_USER);
+    } else {
+      status = BTM_UNKNOWN_ADDR;
+    }
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetTraceLevel
+ *
+ * Description      This function sets the trace level for BTM.  If called with
+ *                  a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns          The new or current trace level
+ *
+ ******************************************************************************/
+uint8_t BTM_SetTraceLevel(uint8_t new_level) {
+  BTM_TRACE_DEBUG("BTM_SetTraceLevel");
+  if (new_level != 0xFF) btm_cb.trace_level = new_level;
+
+  return (btm_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_cont_rswitch
+ *
+ * Description      This function is called to continue processing an active
+ *                  role switch. It first disables encryption if enabled and
+ *                  EPR is not supported
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btm_cont_rswitch(tACL_CONN* p, tBTM_SEC_DEV_REC* p_dev_rec,
+                      uint8_t hci_status) {
+  BTM_TRACE_DEBUG("btm_cont_rswitch");
+  /* Check to see if encryption needs to be turned off if pending
+     change of link key or role switch */
+  if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) {
+    /* Must turn off Encryption first if necessary */
+    /* Some devices do not support switch or change of link key while encryption
+     * is on */
+    if (p_dev_rec != NULL &&
+        ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) &&
+        !BTM_EPR_AVAILABLE(p)) {
+      btsnd_hcic_set_conn_encrypt(p->hci_handle, false);
+      p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+      if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+        p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+    } else /* Encryption not used or EPR supported, continue with switch
+              and/or change of link key */
+    {
+      if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) {
+        p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+#if (BTM_DISC_DURING_RS == TRUE)
+        if (p_dev_rec) p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+        btsnd_hcic_switch_role(p->remote_addr, (uint8_t)!p->link_role);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_resubmit_page
+ *
+ * Description      send pending page request
+ *
+ ******************************************************************************/
+void btm_acl_resubmit_page(void) {
+  tBTM_SEC_DEV_REC* p_dev_rec;
+  BT_HDR* p_buf;
+  uint8_t* pp;
+  BTM_TRACE_DEBUG("btm_acl_resubmit_page");
+  /* If there were other page request schedule can start the next one */
+  p_buf = (BT_HDR*)fixed_queue_try_dequeue(btm_cb.page_queue);
+  if (p_buf != NULL) {
+    /* skip 3 (2 bytes opcode and 1 byte len) to get to the bd_addr
+     * for both create_conn and rmt_name */
+    pp = (uint8_t*)(p_buf + 1) + p_buf->offset + 3;
+
+    RawAddress bda;
+    STREAM_TO_BDADDR(bda, pp);
+
+    p_dev_rec = btm_find_or_alloc_dev(bda);
+
+    btm_cb.connecting_bda = p_dev_rec->bd_addr;
+    memcpy(btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+    btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p_buf);
+  } else {
+    btm_cb.paging = false;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_reset_paging
+ *
+ * Description      set paging to false and free the page queue - called at
+ *                  hci_reset
+ *
+ ******************************************************************************/
+void btm_acl_reset_paging(void) {
+  BT_HDR* p;
+  BTM_TRACE_DEBUG("btm_acl_reset_paging");
+  /* If we sent reset we are definitely not paging any more */
+  while ((p = (BT_HDR*)fixed_queue_try_dequeue(btm_cb.page_queue)) != NULL)
+    osi_free(p);
+
+  btm_cb.paging = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_paging
+ *
+ * Description      send a paging command or queue it in btm_cb
+ *
+ ******************************************************************************/
+void btm_acl_paging(BT_HDR* p, const RawAddress& bda) {
+  tBTM_SEC_DEV_REC* p_dev_rec;
+
+  VLOG(2) << __func__ << ":" << btm_cb.discing << " , paging:" << btm_cb.paging
+          << " BDA: " << bda;
+
+  if (btm_cb.discing) {
+    btm_cb.paging = true;
+    fixed_queue_enqueue(btm_cb.page_queue, p);
+  } else {
+    if (!BTM_ACL_IS_CONNECTED(bda)) {
+      VLOG(1) << "connecting_bda: " << btm_cb.connecting_bda;
+      if (btm_cb.paging && bda == btm_cb.connecting_bda) {
+        fixed_queue_enqueue(btm_cb.page_queue, p);
+      } else {
+        p_dev_rec = btm_find_or_alloc_dev(bda);
+        btm_cb.connecting_bda = p_dev_rec->bd_addr;
+        memcpy(btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+        btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+      }
+
+      btm_cb.paging = true;
+    } else /* ACL is already up */
+    {
+      btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_notif_conn_collision
+ *
+ * Description      Send connection collision event to upper layer if registered
+ *
+ * Returns          true if sent out to upper layer,
+ *                  false if no one needs the notification.
+ *
+ ******************************************************************************/
+bool btm_acl_notif_conn_collision(const RawAddress& bda) {
+  /* Report possible collision to the upper layer. */
+  if (btm_cb.p_bl_changed_cb) {
+    VLOG(1) << __func__ << " RemBdAddr: " << bda;
+
+    tBTM_BL_EVENT_DATA evt_data;
+    evt_data.event = BTM_BL_COLLISION_EVT;
+    evt_data.conn.p_bda = &bda;
+    evt_data.conn.transport = BT_TRANSPORT_BR_EDR;
+    evt_data.conn.handle = BTM_INVALID_HCI_HANDLE;
+    (*btm_cb.p_bl_changed_cb)(&evt_data);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_acl_chk_peer_pkt_type_support
+ *
+ * Description      Check if peer supports requested packets
+ *
+ ******************************************************************************/
+void btm_acl_chk_peer_pkt_type_support(tACL_CONN* p, uint16_t* p_pkt_type) {
+  /* 3 and 5 slot packets? */
+  if (!HCI_3_SLOT_PACKETS_SUPPORTED(p->peer_lmp_feature_pages[0]))
+    *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3);
+
+  if (!HCI_5_SLOT_PACKETS_SUPPORTED(p->peer_lmp_feature_pages[0]))
+    *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5);
+
+  /* 2 and 3 MPS support? */
+  if (!HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_feature_pages[0]))
+    /* Not supported. Add 'not_supported' mask for all 2MPS packet types */
+    *p_pkt_type |=
+        (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+         BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+
+  if (!HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_feature_pages[0]))
+    /* Not supported. Add 'not_supported' mask for all 3MPS packet types */
+    *p_pkt_type |=
+        (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
+         BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+
+  /* EDR 3 and 5 slot support? */
+  if (HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_feature_pages[0]) ||
+      HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_feature_pages[0])) {
+    if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_feature_pages[0]))
+      /* Not supported. Add 'not_supported' mask for all 3-slot EDR packet types
+       */
+      *p_pkt_type |=
+          (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+
+    if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_feature_pages[0]))
+      /* Not supported. Add 'not_supported' mask for all 5-slot EDR packet types
+       */
+      *p_pkt_type |=
+          (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+  }
+}
diff --git a/vendor_libs/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp
index 0358a23..ae19638 100644
--- a/vendor_libs/test_vendor_lib/Android.bp
+++ b/vendor_libs/test_vendor_lib/Android.bp
@@ -133,6 +133,11 @@
         "-fvisibility=hidden",
         "-DLOG_NDEBUG=1",
     ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 // Linux RootCanal Executable
@@ -190,6 +195,9 @@
                 all_undefined: false,
             },
         },
+        darwin: {
+            enabled: false,
+        },
     },
 }