Snap for 9640974 from 3958f204af9c774049a800e84158783f17eedec2 to mainline-permission-release

Change-Id: I0c770ae00241d5257fcf6df90773e4adf6d6f503
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d398fd8..c1b9e29 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,119 +1,220 @@
 {
-  "postsubmit" : [
+  "presubmit": [
+    // android_test targets
     {
-      "name" : "bluetooth_test_common"
+      "name": "CtsBluetoothTestCases"
     },
     {
-      "name" : "bluetoothtbd_test"
+      "name": "BluetoothInstrumentationTests"
     },
     {
-      "name" : "net_test_audio_a2dp_hw"
+      "name": "GoogleBluetoothInstrumentationTests"
     },
     {
-      "name" : "net_test_avrcp"
+      "name": "FrameworkBluetoothTests"
     },
     {
-      "name" : "net_test_btcore"
+      "name": "ServiceBluetoothTests"
+    },
+    // device only tests
+    // Broken
+    //{
+    //  "name": "bluetooth-test-audio-hal-interface"
+    //},
+    {
+      "name": "net_test_audio_a2dp_hw"
     },
     {
-      "name" : "net_test_btif"
+      "name": "net_test_audio_hearing_aid_hw"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "net_test_bluetooth"
+    // },
+    // {
+    //   "name": "net_test_bta"
+    // },
+    // {
+    //   "name": "net_test_btif"
+    // },
+    {
+      "name": "net_test_btif_hf_client_service"
     },
     {
-      "name" : "net_test_btif_profile_queue"
+      "name": "net_test_btif_profile_queue"
     },
     {
-      "name" : "net_test_btpackets"
+      "name": "net_test_device"
     },
     {
-      "name" : "net_test_device"
+      "name": "net_test_gatt_conn_multiplexing"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "net_test_hci"
+    // },
+    {
+      "name": "net_test_hf_client_add_record"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "net_test_stack"
+    // },
+    {
+      "name": "net_test_stack_ad_parser"
     },
     {
-      "name" : "net_test_eatt"
+      "name": "net_test_stack_multi_adv"
+    },
+    // go/a-unit-tests tests (unit_test: true)
+    // Thoses test run on the host in the CI automatically.
+    // Run the one that are available on the device on the
+    // device as well
+    // TODO (b/267212763)
+    // {
+    //   "name": "bluetooth_csis_test"
+    // },
+    {
+      "name": "bluetooth_flatbuffer_tests"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "bluetooth_groups_test"
+    // },
+    // {
+    //   "name": "bluetooth_has_test"
+    // },
+    {
+      "name": "bluetooth_hh_test"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "bluetooth_le_audio_client_test"
+    // },
+    {
+      "name": "bluetooth_le_audio_test"
     },
     {
-      "name" : "net_test_hci"
+      "name": "bluetooth_packet_parser_test"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "bluetooth_test_broadcaster"
+    // },
+    // {
+    //   "name": "bluetooth_test_broadcaster_state_machine"
+    // },
+    {
+      "name": "bluetooth_test_common"
     },
     {
-      "name" : "net_test_performance"
+      "name": "bluetooth_test_gd_unit"
     },
     {
-      "name" : "net_test_stack"
+      "name": "bluetooth_test_sdp"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "bluetooth_vc_test"
+    // },
+    // {
+    //   "name": "bluetoothtbd_test"
+    // },
+    // {
+    //   "name": "bt_host_test_bta"
+    // },
+    {
+      "name": "libaptx_enc_tests"
     },
     {
-      "name" : "net_test_stack_ad_parser"
+      "name": "libaptxhd_enc_tests"
     },
     {
-      "name" : "net_test_stack_multi_adv"
+      "name": "net_test_avrcp"
     },
     {
-      "name" : "net_test_stack_rfcomm"
+      "name": "net_test_btcore"
     },
     {
-      "name" : "net_test_stack_smp"
+      "name": "net_test_btif_config_cache"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "net_test_btif_hh"
+    // },
+    {
+      "name": "net_test_btif_rc"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "net_test_btif_stack"
+    // },
+    {
+      "name": "net_test_btm_iso"
     },
     {
-      "name" : "net_test_types"
-    }
-  ],
-  "presubmit" : [
-    {
-      "name" : "net_test_hf_client_add_record"
+      "name": "net_test_btpackets"
     },
     {
-      "name" : "net_test_btif_hf_client_service"
+      "name": "net_test_eatt"
     },
     {
-      "name" : "libaptx_enc_tests"
+      "name": "net_test_hci_fragmenter_native"
     },
     {
-      "name" : "libaptxhd_enc_tests"
+      "name": "net_test_main_shim"
     },
     {
-      "name" : "net_test_stack_btm"
+      "name": "net_test_osi"
     },
     {
-      "name" : "BluetoothInstrumentationTests",
-      "options" : [{
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_MSG_CONNECT_TIMEOUT"
-      }, {
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_MSG_SHARE_INTERRUPTED_batchFailed"
-      }, {
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_TRANSPORT_ERROR_connectThreadIsNull"
-      }, {
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#onBatchCanceled_checkStatus"
-      }, {
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppUtilityTest#openReceivedFile_fileNotExist"
-      }]
+      "name": "net_test_performance"
     },
     {
-      "name" : "GoogleBluetoothInstrumentationTests",
-      "options" : [{
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_MSG_CONNECT_TIMEOUT"
-      }, {
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_MSG_SHARE_INTERRUPTED_batchFailed"
-      }, {
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#eventHandler_handleMessage_TRANSPORT_ERROR_connectThreadIsNull"
-      }, {
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppTransferTest#onBatchCanceled_checkStatus"
-      }, {
-        // b/259422308
-        "exclude-filter" : "com.android.bluetooth.opp.BluetoothOppUtilityTest#openReceivedFile_fileNotExist"
-      }]
+      "name": "net_test_stack_a2dp_native"
     },
     {
-      "name" : "FrameworkBluetoothTests"
+      "name": "net_test_stack_acl"
     },
     {
-      "name" : "ServiceBluetoothTests"
+      "name": "net_test_stack_avdtp"
+    },
+    // TODO (b/267212763)
+    // {
+    //   "name": "net_test_stack_btm"
+    // },
+    {
+      "name": "net_test_stack_btu"
+    },
+    {
+      "name": "net_test_stack_gatt"
+    },
+    {
+      "name": "net_test_stack_gatt_native"
+    },
+    {
+      "name": "net_test_stack_gatt_sr_hash_native"
+    },
+    {
+      "name": "net_test_stack_hci"
+    },
+    {
+      "name": "net_test_stack_hid"
+    },
+    {
+      "name": "net_test_stack_l2cap"
+    },
+    {
+      "name": "net_test_stack_rfcomm"
+    },
+    {
+      "name": "net_test_stack_sdp"
+    },
+    {
+      "name": "net_test_stack_smp"
+    },
+    {
+      "name": "net_test_types"
     }
   ]
 }
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
index 9bc4fad..7ca6166 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -106,7 +106,6 @@
     boolean mA2dpOffloadEnabled = false;
 
     private BroadcastReceiver mBondStateChangedReceiver;
-    private BroadcastReceiver mConnectionStateChangedReceiver;
 
     public static boolean isEnabled() {
         return BluetoothProperties.isProfileA2dpSourceEnabled().orElse(false);
@@ -169,10 +168,6 @@
         filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         mBondStateChangedReceiver = new BondStateChangedReceiver();
         registerReceiver(mBondStateChangedReceiver, filter);
-        filter = new IntentFilter();
-        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
-        mConnectionStateChangedReceiver = new ConnectionStateChangedReceiver();
-        registerReceiver(mConnectionStateChangedReceiver, filter);
 
         // Step 8: Mark service as started
         setA2dpService(this);
@@ -208,8 +203,6 @@
         setA2dpService(null);
 
         // Step 7: Unregister broadcast receivers
-        unregisterReceiver(mConnectionStateChangedReceiver);
-        mConnectionStateChangedReceiver = null;
         unregisterReceiver(mBondStateChangedReceiver);
         mBondStateChangedReceiver = null;
 
@@ -1242,7 +1235,7 @@
         }
     }
 
-    private void connectionStateChanged(BluetoothDevice device, int fromState, int toState) {
+    void connectionStateChanged(BluetoothDevice device, int fromState, int toState) {
         if ((device == null) || (fromState == toState)) {
             return;
         }
@@ -1269,27 +1262,6 @@
     }
 
     /**
-     * Receiver for processing device connection state changes.
-     *
-     * <ul>
-     * <li> Update codec support per device when device is (re)connected
-     * <li> Delete the state machine instance if the device is disconnected and unbond
-     * </ul>
-     */
-    private class ConnectionStateChangedReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (!BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
-                return;
-            }
-            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-            int toState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
-            int fromState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
-            connectionStateChanged(device, fromState, toState);
-        }
-    }
-
-    /**
      * Retrieves the most recently connected device in the A2DP connected devices list.
      */
     public BluetoothDevice getFallbackDevice() {
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index 9e7323f..11d33ad 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -701,6 +701,7 @@
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                         | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        mA2dpService.connectionStateChanged(mDevice, prevState, newState);
         mA2dpService.sendBroadcast(intent, BLUETOOTH_CONNECT,
                 Utils.getTempAllowlistBroadcastOptions());
     }
diff --git a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
index 127fa31..03160d4 100644
--- a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
+++ b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
@@ -20,13 +20,13 @@
 import android.annotation.SuppressLint;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHapClient;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -690,9 +690,9 @@
         if (headsetService == null) {
             return;
         }
-        BluetoothAudioPolicy audioPolicy = headsetService.getHfpCallAudioPolicy(device);
-        if (audioPolicy == null || audioPolicy.getConnectingTimePolicy()
-                != BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
+        BluetoothSinkAudioPolicy audioPolicy = headsetService.getHfpCallAudioPolicy(device);
+        if (audioPolicy == null || audioPolicy.getActiveDevicePolicyAfterConnection()
+                != BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
             if (!headsetService.setActiveDevice(device)) {
                 return;
             }
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
index 9d9f887..7e36914 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
@@ -42,7 +42,6 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothAdapter.ActiveDeviceProfile;
 import android.bluetooth.BluetoothAdapter.ActiveDeviceUse;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothFrameworkInitializer;
@@ -51,6 +50,7 @@
 import android.bluetooth.BluetoothProtoEnums;
 import android.bluetooth.BluetoothSap;
 import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothSocket;
 import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.BluetoothUuid;
@@ -3671,70 +3671,73 @@
         }
 
         @Override
-        public void getAudioPolicyRemoteSupported(BluetoothDevice device,
+        public void isRequestAudioPolicyAsSinkSupported(BluetoothDevice device,
                 AttributionSource source, SynchronousResultReceiver receiver) {
             try {
-                receiver.send(getAudioPolicyRemoteSupported(device, source));
+                receiver.send(isRequestAudioPolicyAsSinkSupported(device, source));
             } catch (RuntimeException e) {
                 receiver.propagateException(e);
             }
         }
-        private int getAudioPolicyRemoteSupported(BluetoothDevice device,
+        private int isRequestAudioPolicyAsSinkSupported(BluetoothDevice device,
                 AttributionSource source) {
             AdapterService service = getService();
             if (service == null
                     || !callerIsSystemOrActiveOrManagedUser(service, TAG,
-                        "getAudioPolicyRemoteSupported")
+                        "isRequestAudioPolicyAsSinkSupported")
                     || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) {
-                return BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
+                return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
             }
             enforceBluetoothPrivilegedPermission(service);
-            return service.getAudioPolicyRemoteSupported(device);
+            return service.isRequestAudioPolicyAsSinkSupported(device);
         }
 
         @Override
-        public void setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies,
-                AttributionSource source, SynchronousResultReceiver receiver) {
+        public void requestAudioPolicyAsSink(BluetoothDevice device,
+                BluetoothSinkAudioPolicy policies, AttributionSource source,
+                SynchronousResultReceiver receiver) {
             try {
-                receiver.send(setAudioPolicy(device, policies, source));
+                receiver.send(requestAudioPolicyAsSink(device, policies, source));
             } catch (RuntimeException e) {
                 receiver.propagateException(e);
             }
         }
-        private int setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies,
-                AttributionSource source) {
+        private int requestAudioPolicyAsSink(BluetoothDevice device,
+                BluetoothSinkAudioPolicy policies, AttributionSource source) {
             AdapterService service = getService();
             if (service == null) {
                 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
-            } else if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "setAudioPolicy")) {
+            } else if (!callerIsSystemOrActiveOrManagedUser(service,
+                    TAG, "requestAudioPolicyAsSink")) {
                 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
             } else if (!Utils.checkConnectPermissionForDataDelivery(
                     service, source, TAG)) {
                 return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
             }
             enforceBluetoothPrivilegedPermission(service);
-            return service.setAudioPolicy(device, policies);
+            return service.requestAudioPolicyAsSink(device, policies);
         }
 
         @Override
-        public void getAudioPolicy(BluetoothDevice device,
+        public void getRequestedAudioPolicyAsSink(BluetoothDevice device,
                 AttributionSource source, SynchronousResultReceiver receiver) {
             try {
-                receiver.send(getAudioPolicy(device, source));
+                receiver.send(getRequestedAudioPolicyAsSink(device, source));
             } catch (RuntimeException e) {
                 receiver.propagateException(e);
             }
         }
-        private BluetoothAudioPolicy getAudioPolicy(BluetoothDevice device,
+        private BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink(BluetoothDevice device,
                 AttributionSource source) {
             AdapterService service = getService();
             if (service == null
-                    || !callerIsSystemOrActiveOrManagedUser(service, TAG, "getAudioPolicy")
+                    || !callerIsSystemOrActiveOrManagedUser(service,
+                            TAG, "getRequestedAudioPolicyAsSink")
                     || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) {
                 return null;
             }
             enforceBluetoothPrivilegedPermission(service);
-            return service.getAudioPolicy(device);
+            return service.getRequestedAudioPolicyAsSink(device);
         }
 
         @Override
@@ -5582,12 +5585,12 @@
      * @param device Bluetooth device to be checked for audio policy support
      * @return int status of the remote support for audio policy feature
      */
-    public int getAudioPolicyRemoteSupported(BluetoothDevice device) {
+    public int isRequestAudioPolicyAsSinkSupported(BluetoothDevice device) {
         if (mHeadsetClientService != null) {
             return mHeadsetClientService.getAudioPolicyRemoteSupported(device);
         } else {
             Log.e(TAG, "No audio transport connected");
-            return BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
+            return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
         }
     }
 
@@ -5595,19 +5598,19 @@
      * Set audio policy for remote device
      *
      * @param device Bluetooth device to be set policy for
-     * @return int result status for setAudioPolicy API
+     * @return int result status for requestAudioPolicyAsSink API
      */
-    public int setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies) {
+    public int requestAudioPolicyAsSink(BluetoothDevice device, BluetoothSinkAudioPolicy policies) {
         DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
         if (deviceProp == null) {
             return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED;
         }
 
         if (mHeadsetClientService != null) {
-            if (getAudioPolicyRemoteSupported(device)
-                    != BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE) {
-                Log.w(TAG, "Audio Policy feature not supported by AG");
-                return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
+            if (isRequestAudioPolicyAsSinkSupported(device)
+                    != BluetoothStatusCodes.FEATURE_SUPPORTED) {
+                throw new UnsupportedOperationException(
+                        "Request Audio Policy As Sink not supported");
             }
             deviceProp.setHfAudioPolicyForRemoteAg(policies);
             mHeadsetClientService.setAudioPolicy(device, policies);
@@ -5622,9 +5625,9 @@
      * Get audio policy for remote device
      *
      * @param device Bluetooth device to be set policy for
-     * @return {@link BluetoothAudioPolicy} policy stored for the device
+     * @return {@link BluetoothSinkAudioPolicy} policy stored for the device
      */
-    public BluetoothAudioPolicy getAudioPolicy(BluetoothDevice device) {
+    public BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink(BluetoothDevice device) {
         DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
         if (deviceProp == null) {
             return null;
diff --git a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
index 163a3cd..6d2e838 100644
--- a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -355,10 +355,12 @@
                     BluetoothProfile.PAN, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
         }
 
+        boolean isLeAudioProfileAllowed = false;
         if ((leAudioService != null) && Utils.arrayContains(uuids,
                 BluetoothUuid.LE_AUDIO) && (leAudioService.getConnectionPolicy(device)
                 == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
             debugLog("setting le audio profile priority for device " + device);
+            isLeAudioProfileAllowed = true;
             mAdapterService.getDatabase().setProfileConnectionPolicy(device,
                     BluetoothProfile.LE_AUDIO, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
             if (mPreferLeAudioOnlyMode) {
@@ -384,9 +386,13 @@
         if ((hearingAidService != null) && Utils.arrayContains(uuids,
                 BluetoothUuid.HEARING_AID) && (hearingAidService.getConnectionPolicy(device)
                 == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
-            debugLog("setting hearing aid profile priority for device " + device);
-            mAdapterService.getDatabase().setProfileConnectionPolicy(device,
-                    BluetoothProfile.HEARING_AID, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+            if (isLeAudioProfileAllowed) {
+                debugLog("LE Audio preferred over ASHA for device " + device);
+            } else {
+                debugLog("setting hearing aid profile priority for device " + device);
+                mAdapterService.getDatabase().setProfileConnectionPolicy(device,
+                        BluetoothProfile.HEARING_AID, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+            }
         }
 
         if ((volumeControlService != null) && Utils.arrayContains(uuids,
diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
index dd1297c..d18cafc 100644
--- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -22,12 +22,12 @@
 import android.app.admin.SecurityLog;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothAssignedNumbers;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHeadsetClient;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.IBluetoothConnectionCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -313,7 +313,7 @@
         @VisibleForTesting int mBondState;
         @VisibleForTesting int mDeviceType;
         @VisibleForTesting ParcelUuid[] mUuids;
-        private BluetoothAudioPolicy mAudioPolicy;
+        private BluetoothSinkAudioPolicy mAudioPolicy;
 
         DeviceProperties() {
             mBondState = BluetoothDevice.BOND_NONE;
@@ -502,11 +502,11 @@
             }
         }
 
-        public void setHfAudioPolicyForRemoteAg(BluetoothAudioPolicy policies) {
+        public void setHfAudioPolicyForRemoteAg(BluetoothSinkAudioPolicy policies) {
             mAudioPolicy = policies;
         }
 
-        public BluetoothAudioPolicy getHfAudioPolicyForRemoteAg() {
+        public BluetoothSinkAudioPolicy getHfAudioPolicyForRemoteAg() {
             return mAudioPolicy;
         }
     }
diff --git a/android/app/src/com/android/bluetooth/btservice/storage/AudioPolicyEntity.java b/android/app/src/com/android/bluetooth/btservice/storage/AudioPolicyEntity.java
index 8a302ff..d5ec422 100644
--- a/android/app/src/com/android/bluetooth/btservice/storage/AudioPolicyEntity.java
+++ b/android/app/src/com/android/bluetooth/btservice/storage/AudioPolicyEntity.java
@@ -16,7 +16,7 @@
 
 package com.android.bluetooth.btservice.storage;
 
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 
 import androidx.room.ColumnInfo;
 import androidx.room.Entity;
@@ -31,9 +31,9 @@
     public int inBandRingtoneAudioPolicy;
 
     AudioPolicyEntity() {
-        callEstablishAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
-        connectingTimeAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
-        inBandRingtoneAudioPolicy = BluetoothAudioPolicy.POLICY_UNCONFIGURED;
+        callEstablishAudioPolicy = BluetoothSinkAudioPolicy.POLICY_UNCONFIGURED;
+        connectingTimeAudioPolicy = BluetoothSinkAudioPolicy.POLICY_UNCONFIGURED;
+        inBandRingtoneAudioPolicy = BluetoothSinkAudioPolicy.POLICY_UNCONFIGURED;
     }
 
     AudioPolicyEntity(int callEstablishAudioPolicy, int connectingTimeAudioPolicy,
diff --git a/android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java b/android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
index df8505e..cd81c9d 100644
--- a/android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
+++ b/android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java
@@ -20,10 +20,10 @@
 import android.bluetooth.BluetoothA2dp.OptionalCodecsPreferenceStatus;
 import android.bluetooth.BluetoothA2dp.OptionalCodecsSupportStatus;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProtoEnums;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -288,7 +288,8 @@
      * Set audio policy metadata to database with requested key
      */
     @VisibleForTesting
-    public boolean setAudioPolicyMetadata(BluetoothDevice device, BluetoothAudioPolicy policies) {
+    public boolean setAudioPolicyMetadata(BluetoothDevice device,
+            BluetoothSinkAudioPolicy policies) {
         synchronized (mMetadataCache) {
             if (device == null) {
                 Log.e(TAG, "setAudioPolicyMetadata: device is null");
@@ -302,7 +303,7 @@
             Metadata data = mMetadataCache.get(address);
             AudioPolicyEntity entity = data.audioPolicyMetadata;
             entity.callEstablishAudioPolicy = policies.getCallEstablishPolicy();
-            entity.connectingTimeAudioPolicy = policies.getConnectingTimePolicy();
+            entity.connectingTimeAudioPolicy = policies.getActiveDevicePolicyAfterConnection();
             entity.inBandRingtoneAudioPolicy = policies.getInBandRingtonePolicy();
 
             updateDatabase(data);
@@ -314,7 +315,7 @@
      * Get audio policy metadata from database with requested key
      */
     @VisibleForTesting
-    public BluetoothAudioPolicy getAudioPolicyMetadata(BluetoothDevice device) {
+    public BluetoothSinkAudioPolicy getAudioPolicyMetadata(BluetoothDevice device) {
         synchronized (mMetadataCache) {
             if (device == null) {
                 Log.e(TAG, "getAudioPolicyMetadata: device is null");
@@ -329,9 +330,9 @@
             }
 
             AudioPolicyEntity entity = mMetadataCache.get(address).audioPolicyMetadata;
-            return new BluetoothAudioPolicy.Builder()
+            return new BluetoothSinkAudioPolicy.Builder()
                     .setCallEstablishPolicy(entity.callEstablishAudioPolicy)
-                    .setConnectingTimePolicy(entity.connectingTimeAudioPolicy)
+                    .setActiveDevicePolicyAfterConnection(entity.connectingTimeAudioPolicy)
                     .setInBandRingtonePolicy(entity.inBandRingtoneAudioPolicy)
                     .build();
         }
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
index 536c054..856f7dd 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -23,11 +23,11 @@
 
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothHeadset;
@@ -58,6 +58,7 @@
 import com.android.bluetooth.btservice.ProfileService;
 import com.android.bluetooth.btservice.ServiceFactory;
 import com.android.bluetooth.btservice.storage.DatabaseManager;
+import com.android.bluetooth.hfpclient.HeadsetClientService;
 import com.android.bluetooth.le_audio.LeAudioService;
 import com.android.bluetooth.telephony.BluetoothInCallService;
 import com.android.internal.annotations.VisibleForTesting;
@@ -1368,9 +1369,9 @@
      * Get the Bluetooth Audio Policy stored in the state machine
      *
      * @param device the device to change silence mode
-     * @return a {@link BluetoothAudioPolicy} object
+     * @return a {@link BluetoothSinkAudioPolicy} object
      */
-    public BluetoothAudioPolicy getHfpCallAudioPolicy(BluetoothDevice device) {
+    public BluetoothSinkAudioPolicy getHfpCallAudioPolicy(BluetoothDevice device) {
         synchronized (mStateMachines) {
             final HeadsetStateMachine stateMachine = mStateMachines.get(device);
             if (stateMachine == null) {
@@ -1915,9 +1916,9 @@
             if (stateMachine == null) {
                 Log.d(TAG, "phoneStateChanged: CALL_STATE_IDLE, mActiveDevice is Null");
             } else {
-                BluetoothAudioPolicy currentPolicy = stateMachine.getHfpCallAudioPolicy();
-                if (currentPolicy != null && currentPolicy.getConnectingTimePolicy()
-                        == BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
+                BluetoothSinkAudioPolicy currentPolicy = stateMachine.getHfpCallAudioPolicy();
+                if (currentPolicy != null && currentPolicy.getActiveDevicePolicyAfterConnection()
+                        == BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
                     /**
                      * If the active device was set because of the pick up audio policy
                      * and the connecting policy is NOT_ALLOWED, then after the call is
@@ -1981,10 +1982,10 @@
         List<BluetoothDevice> audioConnectableDevices = getConnectedDevices();
         if (audioConnectableDevices.size() == 1) {
             BluetoothDevice connectedDevice = audioConnectableDevices.get(0);
-            BluetoothAudioPolicy callAudioPolicy =
+            BluetoothSinkAudioPolicy callAudioPolicy =
                     getHfpCallAudioPolicy(connectedDevice);
             if (callAudioPolicy != null && callAudioPolicy.getInBandRingtonePolicy()
-                    == BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
+                    == BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
                 inbandRingtoneAllowedByPolicy = false;
             }
         }
@@ -1992,7 +1993,16 @@
         return isInbandRingingSupported && !SystemProperties.getBoolean(
                 DISABLE_INBAND_RINGING_PROPERTY, false)
                 && !mInbandRingingRuntimeDisable
-                && inbandRingtoneAllowedByPolicy;
+                && inbandRingtoneAllowedByPolicy
+                && !isHeadsetClientConnected();
+    }
+
+    private boolean isHeadsetClientConnected() {
+        HeadsetClientService headsetClientService = HeadsetClientService.getHeadsetClientService();
+        if (headsetClientService == null) {
+            return false;
+        }
+        return !(headsetClientService.getConnectedDevices().isEmpty());
     }
 
     /**
@@ -2007,30 +2017,53 @@
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void onConnectionStateChangedFromStateMachine(BluetoothDevice device, int fromState,
             int toState) {
-        synchronized (mStateMachines) {
-            List<BluetoothDevice> audioConnectableDevices =
-                    getDevicesMatchingConnectionStates(CONNECTING_CONNECTED_STATES);
-            if (fromState != BluetoothProfile.STATE_CONNECTED
-                    && toState == BluetoothProfile.STATE_CONNECTED) {
-                if (audioConnectableDevices.size() > 1) {
-                    mInbandRingingRuntimeDisable = true;
-                    doForEachConnectedStateMachine(
-                            stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.SEND_BSIR,
-                                    0));
-                }
-                MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HEADSET);
+        if (fromState != BluetoothProfile.STATE_CONNECTED
+                && toState == BluetoothProfile.STATE_CONNECTED) {
+            updateInbandRinging(device, true);
+            MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HEADSET);
+        }
+        if (fromState != BluetoothProfile.STATE_DISCONNECTED
+                && toState == BluetoothProfile.STATE_DISCONNECTED) {
+            updateInbandRinging(device, false);
+            if (device.equals(mActiveDevice)) {
+                setActiveDevice(null);
             }
-            if (fromState != BluetoothProfile.STATE_DISCONNECTED
-                    && toState == BluetoothProfile.STATE_DISCONNECTED) {
-                if (audioConnectableDevices.size() <= 1) {
-                    mInbandRingingRuntimeDisable = false;
-                    doForEachConnectedStateMachine(
-                            stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.SEND_BSIR,
-                                    1));
-                }
-                if (device.equals(mActiveDevice)) {
-                    setActiveDevice(null);
-                }
+        }
+    }
+
+    /**
+     * Called from {@link HeadsetClientStateMachine} to update inband ringing status.
+     */
+    public void updateInbandRinging(BluetoothDevice device, boolean connected) {
+        synchronized (mStateMachines) {
+            List<BluetoothDevice> audioConnectableDevices = getConnectedDevices();
+            final int enabled;
+            final boolean inbandRingingRuntimeDisable = mInbandRingingRuntimeDisable;
+
+            if (audioConnectableDevices.size() > 1 || isHeadsetClientConnected()) {
+                mInbandRingingRuntimeDisable = true;
+                enabled = 0;
+            } else {
+                mInbandRingingRuntimeDisable = false;
+                enabled = 1;
+            }
+
+            final boolean updateAll = inbandRingingRuntimeDisable != mInbandRingingRuntimeDisable;
+
+            Log.i(TAG, "updateInbandRinging():"
+                    + " Device=" + device
+                    + " enabled=" + enabled
+                    + " connected=" + connected
+                    + " Update all=" + updateAll);
+
+            StateMachineTask sendBsirTask = stateMachine -> stateMachine
+                            .sendMessage(HeadsetStateMachine.SEND_BSIR, enabled);
+
+            if (updateAll) {
+                doForEachConnectedStateMachine(sendBsirTask);
+            } else if (connected) {
+                // Same Inband ringing status, send +BSIR only to the new connected device
+                doForStateMachine(device, sendBsirTask);
             }
         }
     }
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index cec0a39..03ea3fa 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -21,11 +21,11 @@
 import android.annotation.RequiresPermission;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothAssignedNumbers;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProtoEnums;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.hfp.BluetoothHfpProtoEnums;
 import android.content.Intent;
@@ -160,7 +160,7 @@
 
     static final int HFP_SET_AUDIO_POLICY = 1;
 
-    private BluetoothAudioPolicy mHsClientAudioPolicy;
+    private BluetoothSinkAudioPolicy mHsClientAudioPolicy;
 
     // Keys are AT commands, and values are the company IDs.
     private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID;
@@ -199,10 +199,11 @@
             "DatabaseManager cannot be null when HeadsetClientStateMachine is created");
         mDeviceSilenced = false;
 
-        BluetoothAudioPolicy storedAudioPolicy = mDatabaseManager.getAudioPolicyMetadata(device);
+        BluetoothSinkAudioPolicy storedAudioPolicy =
+                mDatabaseManager.getAudioPolicyMetadata(device);
         if (storedAudioPolicy == null) {
             Log.w(TAG, "Audio Policy not created in database! Creating...");
-            mHsClientAudioPolicy = new BluetoothAudioPolicy.Builder().build();
+            mHsClientAudioPolicy = new BluetoothSinkAudioPolicy.Builder().build();
             mDatabaseManager.setAudioPolicyMetadata(device, mHsClientAudioPolicy);
         } else {
             Log.i(TAG, "Audio Policy found in database!");
@@ -2019,9 +2020,9 @@
         int connectingTimePolicy = (Integer) args[2];
         int inbandPolicy = (Integer) args[3];
 
-        setHfpCallAudioPolicy(new BluetoothAudioPolicy.Builder()
+        setHfpCallAudioPolicy(new BluetoothSinkAudioPolicy.Builder()
                 .setCallEstablishPolicy(callEstablishPolicy)
-                .setConnectingTimePolicy(connectingTimePolicy)
+                .setActiveDevicePolicyAfterConnection(connectingTimePolicy)
                 .setInBandRingtonePolicy(inbandPolicy)
                 .build());
     }
@@ -2031,7 +2032,7 @@
      *
      * @param policies policies to be set and stored
      */
-    public void setHfpCallAudioPolicy(BluetoothAudioPolicy policies) {
+    public void setHfpCallAudioPolicy(BluetoothSinkAudioPolicy policies) {
         mHsClientAudioPolicy = policies;
         mDatabaseManager.setAudioPolicyMetadata(mDevice, policies);
     }
@@ -2040,7 +2041,7 @@
      * get the audio policy of the client device
      *
      */
-    public BluetoothAudioPolicy getHfpCallAudioPolicy() {
+    public BluetoothSinkAudioPolicy getHfpCallAudioPolicy() {
         return mHsClientAudioPolicy;
     }
 
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java b/android/app/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
index 0820544..bbf4e36 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
@@ -19,9 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -163,10 +163,10 @@
         }
         BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
         if (bluetoothInCallService != null) {
-            BluetoothAudioPolicy callAudioPolicy =
+            BluetoothSinkAudioPolicy callAudioPolicy =
                     mHeadsetService.getHfpCallAudioPolicy(device);
             if (callAudioPolicy == null || callAudioPolicy.getCallEstablishPolicy()
-                    != BluetoothAudioPolicy.POLICY_NOT_ALLOWED) {
+                    != BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
                 mHeadsetService.setActiveDevice(device);
             }
             bluetoothInCallService.answerCall();
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
index bce1c79..9221d98 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
@@ -17,11 +17,12 @@
 package com.android.bluetooth.hfpclient;
 
 import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadsetClient;
 import android.bluetooth.BluetoothHeadsetClientCall;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
+import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.IBluetoothHeadsetClient;
 import android.content.AttributionSource;
 import android.content.BroadcastReceiver;
@@ -33,6 +34,7 @@
 import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.sysprop.BluetoothProperties;
 import android.util.Log;
 
@@ -927,13 +929,13 @@
     }
 
     /**
-     * sends the {@link BluetoothAudioPolicy} object to the state machine of the corresponding
+     * sends the {@link BluetoothSinkAudioPolicy} object to the state machine of the corresponding
      * device to store and send to the remote device using Android specific AT commands.
      *
      * @param device for whom the policies to be set
      * @param policies to be set policies
      */
-    public void setAudioPolicy(BluetoothDevice device, BluetoothAudioPolicy policies) {
+    public void setAudioPolicy(BluetoothDevice device, BluetoothSinkAudioPolicy policies) {
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         Log.i(TAG, "setAudioPolicy: device=" + device + ", " + policies.toString() + ", "
                 + Utils.getUidPidString());
@@ -970,7 +972,7 @@
         if (sm != null) {
             return sm.getAudioPolicyRemoteSupported();
         }
-        return BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
+        return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
     }
 
     public boolean connectAudio(BluetoothDevice device) {
@@ -1128,6 +1130,14 @@
             return null;
         }
 
+        // Some platform does not support three way calling (ex: watch)
+        final boolean support_three_way_calling = SystemProperties
+                .getBoolean("bluetooth.headset_client.three_way_calling.enabled", true);
+        if (!support_three_way_calling && !getCurrentCalls(device).isEmpty()) {
+            Log.e(TAG, String.format("dial(%s): Line is busy, reject dialing", device));
+            return null;
+        }
+
         HfpClientCall call = new HfpClientCall(device,
                 HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID,
                 HfpClientCall.CALL_STATE_DIALING, number, false  /* multiparty */,
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index 581b258..804dadd 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -37,11 +37,12 @@
 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
 
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadsetClient;
 import android.bluetooth.BluetoothHeadsetClient.NetworkServiceState;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
+import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.hfp.BluetoothHfpProtoEnums;
 import android.content.Intent;
@@ -64,6 +65,7 @@
 import com.android.bluetooth.btservice.AdapterService;
 import com.android.bluetooth.btservice.MetricsLogger;
 import com.android.bluetooth.btservice.ProfileService;
+import com.android.bluetooth.hfp.HeadsetService;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IState;
 import com.android.internal.util.State;
@@ -148,6 +150,7 @@
     private long mClccTimer = 0;
 
     private final HeadsetClientService mService;
+    private final HeadsetService mHeadsetService;
 
     // Set of calls that represent the accurate state of calls that exists on AG and the calls that
     // are currently in process of being notified to the AG from HF.
@@ -186,7 +189,7 @@
     private static final int CALL_AUDIO_POLICY_FEATURE_ID = 1;
 
     public int mAudioPolicyRemoteSupported;
-    private BluetoothAudioPolicy mHsClientAudioPolicy;
+    private BluetoothSinkAudioPolicy mHsClientAudioPolicy;
 
     private boolean mAudioWbs;
     private int mVoiceRecognitionActive;
@@ -860,12 +863,13 @@
         return (bitfield & mask) == mask;
     }
 
-    HeadsetClientStateMachine(HeadsetClientService context, Looper looper,
-                              NativeInterface nativeInterface) {
+    HeadsetClientStateMachine(HeadsetClientService context, HeadsetService headsetService,
+                              Looper looper, NativeInterface nativeInterface) {
         super(TAG, looper);
         mService = context;
         mNativeInterface = nativeInterface;
         mAudioManager = mService.getAudioManager();
+        mHeadsetService = headsetService;
 
         mVendorProcessor = new VendorCommandResponseProcessor(mService, mNativeInterface);
 
@@ -877,7 +881,7 @@
         mAudioRouteAllowed = context.getResources().getBoolean(
             R.bool.headset_client_initial_audio_route_allowed);
 
-        mHsClientAudioPolicy = new BluetoothAudioPolicy.Builder().build();
+        mHsClientAudioPolicy = new BluetoothSinkAudioPolicy.Builder().build();
 
         mIndicatorNetworkState = HeadsetClientHalConstants.NETWORK_STATE_NOT_AVAILABLE;
         mIndicatorNetworkType = HeadsetClientHalConstants.SERVICE_TYPE_HOME;
@@ -909,11 +913,12 @@
         setInitialState(mDisconnected);
     }
 
-    static HeadsetClientStateMachine make(HeadsetClientService context, Looper looper,
-                                          NativeInterface nativeInterface) {
+    static HeadsetClientStateMachine make(HeadsetClientService context,
+                                          HeadsetService headsetService,
+                                          Looper looper, NativeInterface nativeInterface) {
         logD("make");
-        HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, looper,
-                                                                        nativeInterface);
+        HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, headsetService,
+                                                                        looper, nativeInterface);
         hfcsm.start();
         return hfcsm;
     }
@@ -1022,6 +1027,9 @@
                 Log.e(TAG, "Disconnected: Illegal state transition from " + mPrevState.getName()
                         + " to Disconnected, mCurrentDevice=" + mCurrentDevice);
             }
+            if (mHeadsetService != null && mCurrentDevice != null) {
+                mHeadsetService.updateInbandRinging(mCurrentDevice, false);
+            }
             mCurrentDevice = null;
         }
 
@@ -1309,6 +1317,9 @@
             if (mPrevState == mConnecting) {
                 broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED,
                         BluetoothProfile.STATE_CONNECTING);
+                if (mHeadsetService != null) {
+                    mHeadsetService.updateInbandRinging(mCurrentDevice, true);
+                }
                 MetricsLogger.logProfileConnectionEvent(
                         BluetoothMetricsProto.ProfileId.HEADSET_CLIENT);
             } else if (mPrevState != mAudioOn) {
@@ -2152,13 +2163,13 @@
         mAudioRouteAllowed = allowed;
 
         int establishPolicy = allowed
-                ? BluetoothAudioPolicy.POLICY_ALLOWED :
-                BluetoothAudioPolicy.POLICY_NOT_ALLOWED;
+                ? BluetoothSinkAudioPolicy.POLICY_ALLOWED :
+                BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED;
 
         /*
          * Backward compatibility for mAudioRouteAllowed
          */
-        setAudioPolicy(new BluetoothAudioPolicy.Builder(mHsClientAudioPolicy)
+        setAudioPolicy(new BluetoothSinkAudioPolicy.Builder(mHsClientAudioPolicy)
                 .setCallEstablishPolicy(establishPolicy).build());
     }
 
@@ -2166,26 +2177,26 @@
         return mAudioRouteAllowed;
     }
 
-    private String createMaskString(BluetoothAudioPolicy policies) {
+    private String createMaskString(BluetoothSinkAudioPolicy policies) {
         StringBuilder mask = new StringBuilder();
         mask.append(Integer.toString(CALL_AUDIO_POLICY_FEATURE_ID));
         mask.append("," + policies.getCallEstablishPolicy());
-        mask.append("," + policies.getConnectingTimePolicy());
+        mask.append("," + policies.getActiveDevicePolicyAfterConnection());
         mask.append("," + policies.getInBandRingtonePolicy());
         return mask.toString();
     }
 
     /**
-     * sets the {@link BluetoothAudioPolicy} object device and send to the remote
+     * sets the {@link BluetoothSinkAudioPolicy} object device and send to the remote
      * device using Android specific AT commands.
      *
      * @param policies to be set policies
      */
-    public void setAudioPolicy(BluetoothAudioPolicy policies) {
+    public void setAudioPolicy(BluetoothSinkAudioPolicy policies) {
         logD("setAudioPolicy: " + policies);
         mHsClientAudioPolicy = policies;
 
-        if (mAudioPolicyRemoteSupported != BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE) {
+        if (mAudioPolicyRemoteSupported != BluetoothStatusCodes.FEATURE_SUPPORTED) {
             Log.e(TAG, "Audio Policy feature not supported!");
             return;
         }
@@ -2213,9 +2224,9 @@
      */
     public void setAudioPolicyRemoteSupported(boolean supported) {
         if (supported) {
-            mAudioPolicyRemoteSupported = BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE;
+            mAudioPolicyRemoteSupported = BluetoothStatusCodes.FEATURE_SUPPORTED;
         } else {
-            mAudioPolicyRemoteSupported = BluetoothAudioPolicy.FEATURE_NOT_SUPPORTED_BY_REMOTE;
+            mAudioPolicyRemoteSupported = BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
         }
     }
 
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java
index b0c7265..b21f537 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java
@@ -18,6 +18,8 @@
 
 import android.os.HandlerThread;
 
+import com.android.bluetooth.hfp.HeadsetService;
+
 // Factory so that StateMachine objected can be mocked
 public class HeadsetClientStateMachineFactory {
     /**
@@ -26,6 +28,7 @@
      */
     public HeadsetClientStateMachine make(HeadsetClientService context, HandlerThread t,
             NativeInterface nativeInterface) {
-        return HeadsetClientStateMachine.make(context, t.getLooper(), nativeInterface);
+        return HeadsetClientStateMachine.make(context, HeadsetService.getHeadsetService(),
+                t.getLooper(), nativeInterface);
     }
 }
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
index 8eab0d5..9921c33 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -77,7 +77,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Provides Bluetooth LeAudio profile, as a service in the Bluetooth application.
@@ -91,7 +90,7 @@
     private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000;
 
     // Upper limit of all LeAudio devices: Bonded or Connected
-    private static final int MAX_LE_AUDIO_STATE_MACHINES = 10;
+    private static final int MAX_LE_AUDIO_DEVICES = 10;
     private static LeAudioService sLeAudioService;
 
     /**
@@ -156,16 +155,27 @@
         BluetoothDevice mLostLeadDeviceWhileStreaming;
     }
 
+    private static class LeAudioDeviceDescriptor {
+        LeAudioDeviceDescriptor() {
+            mStateMachine = null;
+            mGroupId = LE_AUDIO_GROUP_ID_INVALID;
+            mSinkAudioLocation = BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+            mDirection = AUDIO_DIRECTION_NONE;
+        }
+
+        public LeAudioStateMachine mStateMachine;
+        public Integer mGroupId;
+        public Integer mSinkAudioLocation;
+        public Integer mDirection;
+    }
+
     List<BluetoothLeAudioCodecConfig> mInputLocalCodecCapabilities = new ArrayList<>();
     List<BluetoothLeAudioCodecConfig> mOutputLocalCodecCapabilities = new ArrayList<>();
 
     @GuardedBy("mGroupLock")
     private final Map<Integer, LeAudioGroupDescriptor> mGroupDescriptors = new LinkedHashMap<>();
-    private final Map<BluetoothDevice, LeAudioStateMachine> mStateMachines = new LinkedHashMap<>();
-
-    @GuardedBy("mGroupLock")
-    private final Map<BluetoothDevice, Integer> mDeviceGroupIdMap = new ConcurrentHashMap<>();
-    private final Map<BluetoothDevice, Integer> mDeviceAudioLocationMap = new ConcurrentHashMap<>();
+    private final Map<BluetoothDevice, LeAudioDeviceDescriptor> mDeviceDescriptors =
+            new LinkedHashMap<>();
 
     private BroadcastReceiver mBondStateChangedReceiver;
     private BroadcastReceiver mConnectionStateChangedReceiver;
@@ -219,17 +229,15 @@
                 "AudioManager cannot be null when LeAudioService starts");
 
         // Start handler thread for state machines
-        mStateMachines.clear();
         mStateMachinesThread = new HandlerThread("LeAudioService.StateMachines");
         mStateMachinesThread.start();
 
-        mDeviceAudioLocationMap.clear();
         mBroadcastStateMap.clear();
         mBroadcastMetadataList.clear();
         mBroadcastsPlaybackMap.clear();
 
         synchronized (mGroupLock) {
-            mDeviceGroupIdMap.clear();
+            mDeviceDescriptors.clear();
             mGroupDescriptors.clear();
         }
 
@@ -326,7 +334,18 @@
                     break;
                 }
             }
-            mDeviceGroupIdMap.clear();
+
+            // Destroy state machines and stop handler thread
+            for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+                LeAudioStateMachine sm = descriptor.mStateMachine;
+                if (sm == null) {
+                    continue;
+                }
+                sm.doQuit();
+                sm.cleanup();
+            }
+
+            mDeviceDescriptors.clear();
             mGroupDescriptors.clear();
         }
 
@@ -352,16 +371,6 @@
         unregisterReceiver(mMuteStateChangedReceiver);
         mMuteStateChangedReceiver = null;
 
-        // Destroy state machines and stop handler thread
-        synchronized (mStateMachines) {
-            for (LeAudioStateMachine sm : mStateMachines.values()) {
-                sm.doQuit();
-                sm.cleanup();
-            }
-            mStateMachines.clear();
-        }
-
-        mDeviceAudioLocationMap.clear();
 
         if (mBroadcastCallbacks != null) {
             mBroadcastCallbacks.kill();
@@ -439,6 +448,27 @@
         return mVolumeControlService.getAudioDeviceGroupVolume(groupId);
     }
 
+    LeAudioDeviceDescriptor createDeviceDescriptor(BluetoothDevice device) {
+        LeAudioDeviceDescriptor descriptor = mDeviceDescriptors.get(device);
+        if (descriptor == null) {
+
+            // Limit the maximum number of devices to avoid DoS attack
+            if (mDeviceDescriptors.size() >= MAX_LE_AUDIO_DEVICES) {
+                Log.e(TAG, "Maximum number of LeAudio state machines reached: "
+                        + MAX_LE_AUDIO_DEVICES);
+                return null;
+            }
+
+            mDeviceDescriptors.put(device, new LeAudioDeviceDescriptor());
+            descriptor = mDeviceDescriptors.get(device);
+            Log.d(TAG, "Created descriptor for device: " + device);
+        } else {
+            Log.w(TAG, "Device: " + device + ", already exists");
+        }
+
+        return descriptor;
+    }
+
     public boolean connect(BluetoothDevice device) {
         if (DBG) {
             Log.d(TAG, "connect(): " + device);
@@ -454,7 +484,11 @@
             return false;
         }
 
-        synchronized (mStateMachines) {
+        synchronized (mGroupLock) {
+            if (createDeviceDescriptor(device) == null) {
+                return false;
+            }
+
             LeAudioStateMachine sm = getOrCreateStateMachine(device);
             if (sm == null) {
                 Log.e(TAG, "Ignored connect request for " + device + " : no state machine");
@@ -477,9 +511,14 @@
             Log.d(TAG, "disconnect(): " + device);
         }
 
-        // Disconnect this device
-        synchronized (mStateMachines) {
-            LeAudioStateMachine sm = mStateMachines.get(device);
+        synchronized (mGroupLock) {
+            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+            if (descriptor == null) {
+                Log.e(TAG, "disconnect: No valid descriptor for device: " + device);
+                return false;
+            }
+
+            LeAudioStateMachine sm = descriptor.mStateMachine;
             if (sm == null) {
                 Log.e(TAG, "Ignored disconnect request for " + device
                         + " : no state machine");
@@ -492,10 +531,11 @@
     }
 
     public List<BluetoothDevice> getConnectedDevices() {
-        synchronized (mStateMachines) {
+        synchronized (mGroupLock) {
             List<BluetoothDevice> devices = new ArrayList<>();
-            for (LeAudioStateMachine sm : mStateMachines.values()) {
-                if (sm.isConnected()) {
+            for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+                LeAudioStateMachine sm = descriptor.mStateMachine;
+                if (sm != null && sm.isConnected()) {
                     devices.add(sm.getDevice());
                 }
             }
@@ -504,11 +544,31 @@
     }
 
     BluetoothDevice getConnectedGroupLeadDevice(int groupId) {
+        BluetoothDevice device = null;
+
         if (mActiveAudioOutDevice != null
                 && getGroupId(mActiveAudioOutDevice) == groupId) {
-            return mActiveAudioOutDevice;
+            device = mActiveAudioOutDevice;
+        } else {
+            device = getFirstDeviceFromGroup(groupId);
         }
-        return getFirstDeviceFromGroup(groupId);
+
+        if (device == null) {
+            return device;
+        }
+
+        LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+        if (descriptor == null) {
+            Log.e(TAG, "getConnectedGroupLeadDevice: No valid descriptor for device: " + device);
+            return null;
+        }
+
+        LeAudioStateMachine sm = descriptor.mStateMachine;
+        if (sm != null && sm.getConnectionState() == BluetoothProfile.STATE_CONNECTED) {
+            return device;
+        }
+
+        return null;
     }
 
     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
@@ -520,14 +580,21 @@
         if (bondedDevices == null) {
             return devices;
         }
-        synchronized (mStateMachines) {
+        synchronized (mGroupLock) {
             for (BluetoothDevice device : bondedDevices) {
                 final ParcelUuid[] featureUuids = device.getUuids();
                 if (!Utils.arrayContains(featureUuids, BluetoothUuid.LE_AUDIO)) {
                     continue;
                 }
                 int connectionState = BluetoothProfile.STATE_DISCONNECTED;
-                LeAudioStateMachine sm = mStateMachines.get(device);
+                LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+                if (descriptor == null) {
+                    Log.e(TAG, "getDevicesMatchingConnectionStates: "
+                            + "No valid descriptor for device: " + device);
+                    return null;
+                }
+
+                LeAudioStateMachine sm = descriptor.mStateMachine;
                 if (sm != null) {
                     connectionState = sm.getConnectionState();
                 }
@@ -550,9 +617,11 @@
     @VisibleForTesting
     List<BluetoothDevice> getDevices() {
         List<BluetoothDevice> devices = new ArrayList<>();
-        synchronized (mStateMachines) {
-            for (LeAudioStateMachine sm : mStateMachines.values()) {
-                devices.add(sm.getDevice());
+        synchronized (mGroupLock) {
+            for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+                if (descriptor.mStateMachine != null) {
+                    devices.add(descriptor.mStateMachine.getDevice());
+                }
             }
             return devices;
         }
@@ -568,8 +637,13 @@
      * {@link BluetoothProfile#STATE_DISCONNECTING} if this profile is being disconnected
      */
     public int getConnectionState(BluetoothDevice device) {
-        synchronized (mStateMachines) {
-            LeAudioStateMachine sm = mStateMachines.get(device);
+        synchronized (mGroupLock) {
+            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+            if (descriptor == null) {
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+
+            LeAudioStateMachine sm = descriptor.mStateMachine;
             if (sm == null) {
                 return BluetoothProfile.STATE_DISCONNECTED;
             }
@@ -610,8 +684,10 @@
      * @param group_id group Id to verify
      * @return true given group exists, otherwise false
      */
-    public boolean isValidDeviceGroup(int group_id) {
-        return group_id != LE_AUDIO_GROUP_ID_INVALID && mDeviceGroupIdMap.containsValue(group_id);
+    public boolean isValidDeviceGroup(int groupId) {
+        synchronized (mGroupLock) {
+            return groupId != LE_AUDIO_GROUP_ID_INVALID && mGroupDescriptors.containsKey(groupId);
+        }
     }
 
     /**
@@ -627,8 +703,9 @@
         }
 
         synchronized (mGroupLock) {
-            for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
-                if (entry.getValue() == groupId) {
+            for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
+                    : mDeviceDescriptors.entrySet()) {
+                if (entry.getValue().mGroupId == groupId) {
                     result.add(entry.getKey());
                 }
             }
@@ -772,15 +849,16 @@
             return null;
         }
         synchronized (mGroupLock) {
-            for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
-                if (entry.getValue() != groupId) {
+            for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+                if (!descriptor.mGroupId.equals(groupId)) {
                     continue;
                 }
-                LeAudioStateMachine sm = mStateMachines.get(entry.getKey());
+
+                LeAudioStateMachine sm = descriptor.mStateMachine;
                 if (sm == null || sm.getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
                     continue;
                 }
-                return entry.getKey();
+                return sm.getDevice();
             }
         }
         return null;
@@ -802,8 +880,13 @@
         }
 
         if (device != null && mActiveAudioInDevice != null) {
-            int previousGroupId = getGroupId(mActiveAudioInDevice);
-            if (previousGroupId == groupId) {
+            LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+            if (deviceDescriptor == null) {
+                Log.e(TAG, "updateActiveInDevice: No valid descriptor for device: " + device);
+                return false;
+            }
+
+            if (deviceDescriptor.mGroupId.equals(groupId)) {
                 /* This is thes same group as aleady notified to the system.
                  * Therefore do not change the device we have connected to the group,
                  * unless, previous one is disconnected now
@@ -811,9 +894,9 @@
                 if (mActiveAudioInDevice.isConnected()) {
                     device = mActiveAudioInDevice;
                 }
-            } else if (previousGroupId != LE_AUDIO_GROUP_ID_INVALID) {
+            } else if (deviceDescriptor.mGroupId != LE_AUDIO_GROUP_ID_INVALID) {
                 /* Mark old group as no active */
-                LeAudioGroupDescriptor descriptor = getGroupDescriptor(previousGroupId);
+                LeAudioGroupDescriptor descriptor = getGroupDescriptor(deviceDescriptor.mGroupId);
                 if (descriptor != null) {
                     descriptor.mIsActive = false;
                 }
@@ -859,8 +942,13 @@
         }
 
         if (device != null && mActiveAudioOutDevice != null) {
-            int previousGroupId = getGroupId(mActiveAudioOutDevice);
-            if (previousGroupId == groupId) {
+            LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+            if (deviceDescriptor == null) {
+                Log.e(TAG, "updateActiveOutDevice: No valid descriptor for device: " + device);
+                return false;
+            }
+
+            if (deviceDescriptor.mGroupId.equals(groupId)) {
                 /* This is the same group as already notified to the system.
                  * Therefore do not change the device we have connected to the group,
                  * unless, previous one is disconnected now
@@ -868,10 +956,11 @@
                 if (mActiveAudioOutDevice.isConnected()) {
                     device = mActiveAudioOutDevice;
                 }
-            } else if (previousGroupId != LE_AUDIO_GROUP_ID_INVALID) {
-                Log.i(TAG, " Switching active group from " + previousGroupId + " to " + groupId);
+            } else if (deviceDescriptor.mGroupId != LE_AUDIO_GROUP_ID_INVALID) {
+                Log.i(TAG, " Switching active group from " + deviceDescriptor.mGroupId + " to "
+                        + groupId);
                 /* Mark old group as no active */
-                LeAudioGroupDescriptor descriptor = getGroupDescriptor(previousGroupId);
+                LeAudioGroupDescriptor descriptor = getGroupDescriptor(deviceDescriptor.mGroupId);
                 if (descriptor != null) {
                     descriptor.mIsActive = false;
                 }
@@ -1033,7 +1122,13 @@
         int groupId = LE_AUDIO_GROUP_ID_INVALID;
 
         if (device != null) {
-            groupId = mDeviceGroupIdMap.getOrDefault(device, LE_AUDIO_GROUP_ID_INVALID);
+            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+            if (descriptor == null) {
+                Log.e(TAG, "setActiveGroupWithDevice: No valid descriptor for device: " + device);
+                return;
+            }
+
+            groupId = descriptor.mGroupId;
         }
 
         int currentlyActiveGroupId = getActiveGroupId();
@@ -1128,21 +1223,30 @@
     }
 
     void connectSet(BluetoothDevice device) {
-        int groupId = getGroupId(device);
-        if (groupId == LE_AUDIO_GROUP_ID_INVALID) {
+        LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+        if (descriptor == null) {
+            Log.e(TAG, "connectSet: No valid descriptor for device: " + device);
+            return;
+        }
+        if (descriptor.mGroupId == LE_AUDIO_GROUP_ID_INVALID) {
             return;
         }
 
         if (DBG) {
-            Log.d(TAG, "connect() others from group id: " + groupId);
+            Log.d(TAG, "connect() others from group id: " + descriptor.mGroupId);
         }
 
-        for (BluetoothDevice storedDevice : mDeviceGroupIdMap.keySet()) {
+        Integer setGroupId = descriptor.mGroupId;
+
+        for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
+                : mDeviceDescriptors.entrySet()) {
+            BluetoothDevice storedDevice = entry.getKey();
+            descriptor = entry.getValue();
             if (device.equals(storedDevice)) {
                 continue;
             }
 
-            if (getGroupId(storedDevice) != groupId) {
+            if (!descriptor.mGroupId.equals(setGroupId)) {
                 continue;
             }
 
@@ -1150,7 +1254,7 @@
                 Log.d(TAG, "connect(): " + storedDevice);
             }
 
-            synchronized (mStateMachines) {
+            synchronized (mGroupLock) {
                 LeAudioStateMachine sm = getOrCreateStateMachine(storedDevice);
                 if (sm == null) {
                     Log.e(TAG, "Ignored connect request for " + storedDevice
@@ -1198,8 +1302,15 @@
                 Log.d(TAG, "Clearing lost dev: " + descriptor.mLostLeadDeviceWhileStreaming);
             }
 
-            LeAudioStateMachine sm =
-                    mStateMachines.get(descriptor.mLostLeadDeviceWhileStreaming);
+            LeAudioDeviceDescriptor deviceDescriptor =
+                    getDeviceDescriptor(descriptor.mLostLeadDeviceWhileStreaming);
+            if (deviceDescriptor == null) {
+                Log.e(TAG, "clearLostDevicesWhileStreaming: No valid descriptor for device: "
+                        + descriptor.mLostLeadDeviceWhileStreaming);
+                return;
+            }
+
+            LeAudioStateMachine sm = deviceDescriptor.mStateMachine;
             if (sm != null) {
                 LeAudioStackEvent stackEvent =
                         new LeAudioStackEvent(
@@ -1283,12 +1394,17 @@
     void messageFromNative(LeAudioStackEvent stackEvent) {
         Log.d(TAG, "Message from native: " + stackEvent);
         BluetoothDevice device = stackEvent.device;
-        Intent intent = null;
 
         if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
             // Some events require device state machine
-            synchronized (mStateMachines) {
-                LeAudioStateMachine sm = mStateMachines.get(device);
+            synchronized (mGroupLock) {
+                LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+                if (deviceDescriptor == null) {
+                    Log.e(TAG, "messageFromNative: No valid descriptor for device: " + device);
+                    return;
+                }
+
+                LeAudioStateMachine sm = deviceDescriptor.mStateMachine;
                 if (sm != null) {
                     /*
                      * To improve scenario when lead Le Audio device is disconnected for the
@@ -1298,41 +1414,39 @@
                      * the hood and keep using lead device as a audio device indetifier in
                      * the audio framework in order to not stop the stream.
                      */
-                    int groupId = getGroupId(device);
-                    synchronized (mGroupLock) {
-                        LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
-                        switch (stackEvent.valueInt1) {
-                            case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTING:
-                            case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTED:
-                                boolean disconnectDueToUnbond =
-                                        (BluetoothDevice.BOND_NONE
-                                                == mAdapterService.getBondState(device));
-                                if (descriptor != null && (Objects.equals(device,
-                                        mActiveAudioOutDevice)
-                                        || Objects.equals(device, mActiveAudioInDevice))
-                                        && (getConnectedPeerDevices(groupId).size() > 1)
-                                        && !disconnectDueToUnbond) {
+                    int groupId = deviceDescriptor.mGroupId;
+                    LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
+                    switch (stackEvent.valueInt1) {
+                        case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTING:
+                        case LeAudioStackEvent.CONNECTION_STATE_DISCONNECTED:
+                            boolean disconnectDueToUnbond =
+                                    (BluetoothDevice.BOND_NONE
+                                            == mAdapterService.getBondState(device));
+                            if (descriptor != null && (Objects.equals(device,
+                                    mActiveAudioOutDevice)
+                                    || Objects.equals(device, mActiveAudioInDevice))
+                                    && (getConnectedPeerDevices(groupId).size() > 1)
+                                    && !disconnectDueToUnbond) {
 
-                                    if (DBG) Log.d(TAG, "Adding to lost devices : " + device);
-                                    descriptor.mLostLeadDeviceWhileStreaming = device;
-                                    return;
+                                if (DBG) Log.d(TAG, "Adding to lost devices : " + device);
+                                descriptor.mLostLeadDeviceWhileStreaming = device;
+                                return;
+                            }
+                            break;
+                        case LeAudioStackEvent.CONNECTION_STATE_CONNECTED:
+                        case LeAudioStackEvent.CONNECTION_STATE_CONNECTING:
+                            if (descriptor != null
+                                    && Objects.equals(
+                                            descriptor.mLostLeadDeviceWhileStreaming,
+                                            device)) {
+                                if (DBG) {
+                                    Log.d(TAG, "Removing from lost devices : " + device);
                                 }
-                                break;
-                            case LeAudioStackEvent.CONNECTION_STATE_CONNECTED:
-                            case LeAudioStackEvent.CONNECTION_STATE_CONNECTING:
-                                if (descriptor != null
-                                        && Objects.equals(
-                                                descriptor.mLostLeadDeviceWhileStreaming,
-                                                device)) {
-                                    if (DBG) {
-                                        Log.d(TAG, "Removing from lost devices : " + device);
-                                    }
-                                    descriptor.mLostLeadDeviceWhileStreaming = null;
-                                    /* Try to connect other devices from the group */
-                                    connectSet(device);
-                                }
-                                break;
-                        }
+                                descriptor.mLostLeadDeviceWhileStreaming = null;
+                                /* Try to connect other devices from the group */
+                                connectSet(device);
+                            }
+                            break;
                     }
                 } else {
                     /* state machine does not exist yet */
@@ -1410,26 +1524,36 @@
             int src_audio_location = stackEvent.valueInt4;
             int available_contexts = stackEvent.valueInt5;
 
-            LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
-            if (descriptor != null) {
-                if (descriptor.mIsActive) {
-                    descriptor.mIsActive =
-                            updateActiveDevices(groupId, descriptor.mDirection, direction,
-                            descriptor.mIsActive);
-                    if (!descriptor.mIsActive) {
-                        notifyGroupStatusChanged(groupId, BluetoothLeAudio.GROUP_STATUS_INACTIVE);
+            synchronized (mGroupLock) {
+                LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
+                if (descriptor != null) {
+                    if (descriptor.mIsActive) {
+                        descriptor.mIsActive =
+                                updateActiveDevices(groupId, descriptor.mDirection, direction,
+                                descriptor.mIsActive);
+                        if (!descriptor.mIsActive) {
+                            notifyGroupStatusChanged(groupId,
+                                    BluetoothLeAudio.GROUP_STATUS_INACTIVE);
+                        }
                     }
+                    descriptor.mDirection = direction;
+                } else {
+                    Log.e(TAG, "no descriptors for group: " + groupId);
                 }
-                descriptor.mDirection = direction;
-            } else {
-                Log.e(TAG, "no descriptors for group: " + groupId);
             }
         } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE) {
             Objects.requireNonNull(stackEvent.device,
                     "Device should never be null, event: " + stackEvent);
 
             int sink_audio_location = stackEvent.valueInt1;
-            mDeviceAudioLocationMap.put(device, sink_audio_location);
+
+            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+            if (descriptor == null) {
+                Log.e(TAG, "messageFromNative: No valid descriptor for device: " + device);
+                return;
+            }
+
+            descriptor.mSinkAudioLocation = sink_audio_location;
 
             if (DBG) {
                 Log.i(TAG, "EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE:" + device
@@ -1557,10 +1681,6 @@
                 setCcidInformation(userUuid, ccidInformation.first, ccidInformation.second);
             }
         }
-
-        if (intent != null) {
-            sendBroadcast(intent, BLUETOOTH_CONNECT);
-        }
     }
 
     private LeAudioStateMachine getOrCreateStateMachine(BluetoothDevice device) {
@@ -1568,25 +1688,26 @@
             Log.e(TAG, "getOrCreateStateMachine failed: device cannot be null");
             return null;
         }
-        synchronized (mStateMachines) {
-            LeAudioStateMachine sm = mStateMachines.get(device);
-            if (sm != null) {
-                return sm;
-            }
-            // Limit the maximum number of state machines to avoid DoS attack
-            if (mStateMachines.size() >= MAX_LE_AUDIO_STATE_MACHINES) {
-                Log.e(TAG, "Maximum number of LeAudio state machines reached: "
-                        + MAX_LE_AUDIO_STATE_MACHINES);
-                return null;
-            }
-            if (DBG) {
-                Log.d(TAG, "Creating a new state machine for " + device);
-            }
-            sm = LeAudioStateMachine.make(device, this,
-                    mLeAudioNativeInterface, mStateMachinesThread.getLooper());
-            mStateMachines.put(device, sm);
+
+        LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+        if (descriptor == null) {
+            Log.e(TAG, "getOrCreateStateMachine: No valid descriptor for device: " + device);
+            return null;
+        }
+
+        LeAudioStateMachine sm = descriptor.mStateMachine;
+        if (sm != null) {
             return sm;
         }
+
+        if (DBG) {
+            Log.d(TAG, "Creating a new state machine for " + device);
+        }
+
+        sm = LeAudioStateMachine.make(device, this,
+                mLeAudioNativeInterface, mStateMachinesThread.getLooper());
+        descriptor.mStateMachine = sm;
+        return sm;
     }
 
     // Remove state machine if the bonding for a device is removed
@@ -1623,16 +1744,23 @@
             return;
         }
 
-        int groupId = getGroupId(device);
-        if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
-            /* In case device is still in the group, let's remove it */
-            mLeAudioNativeInterface.groupRemoveNode(groupId, device);
-        }
+        synchronized (mGroupLock) {
+            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+            if (descriptor == null) {
+                Log.e(TAG, "bondStateChanged: No valid descriptor for device: " + device);
+                return;
+            }
 
-        mDeviceGroupIdMap.remove(device);
-        mDeviceAudioLocationMap.remove(device);
-        synchronized (mStateMachines) {
-            LeAudioStateMachine sm = mStateMachines.get(device);
+            if (descriptor.mGroupId != LE_AUDIO_GROUP_ID_INVALID) {
+                /* In case device is still in the group, let's remove it */
+                mLeAudioNativeInterface.groupRemoveNode(descriptor.mGroupId, device);
+            }
+
+            descriptor.mGroupId = LE_AUDIO_GROUP_ID_INVALID;
+            descriptor.mSinkAudioLocation = BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+            descriptor.mDirection = AUDIO_DIRECTION_NONE;
+
+            LeAudioStateMachine sm = descriptor.mStateMachine;
             if (sm == null) {
                 return;
             }
@@ -1642,12 +1770,19 @@
                 return;
             }
             removeStateMachine(device);
+            mDeviceDescriptors.remove(device);
         }
     }
 
     private void removeStateMachine(BluetoothDevice device) {
-        synchronized (mStateMachines) {
-            LeAudioStateMachine sm = mStateMachines.get(device);
+        synchronized (mGroupLock) {
+            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+            if (descriptor == null) {
+                Log.e(TAG, "removeStateMachine: No valid descriptor for device: " + device);
+                return;
+            }
+
+            LeAudioStateMachine sm = descriptor.mStateMachine;
             if (sm == null) {
                 Log.w(TAG, "removeStateMachine: device " + device
                         + " does not have a state machine");
@@ -1656,7 +1791,7 @@
             Log.i(TAG, "removeStateMachine: removing state machine for device: " + device);
             sm.doQuit();
             sm.cleanup();
-            mStateMachines.remove(device);
+            descriptor.mStateMachine = null;
         }
     }
 
@@ -1678,21 +1813,27 @@
                     + " fromState=" + fromState + " toState=" + toState);
             return;
         }
+
+        LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+        if (deviceDescriptor == null) {
+            Log.e(TAG, "connectionStateChanged: No valid descriptor for device: " + device);
+            return;
+        }
+
         if (toState == BluetoothProfile.STATE_CONNECTED) {
-            int myGroupId = getGroupId(device);
-            if (myGroupId == LE_AUDIO_GROUP_ID_INVALID
-                    || getConnectedPeerDevices(myGroupId).size() == 1) {
+            if (deviceDescriptor.mGroupId == LE_AUDIO_GROUP_ID_INVALID
+                    || getConnectedPeerDevices(deviceDescriptor.mGroupId).size() == 1) {
                 // Log LE Audio connection event if we are the first device in a set
                 // Or when the GroupId has not been found
                 // MetricsLogger.logProfileConnectionEvent(
                 //         BluetoothMetricsProto.ProfileId.LE_AUDIO);
             }
 
-            LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
+            LeAudioGroupDescriptor descriptor = getGroupDescriptor(deviceDescriptor.mGroupId);
             if (descriptor != null) {
                 descriptor.mIsConnected = true;
             } else {
-                Log.e(TAG, "no descriptors for group: " + myGroupId);
+                Log.e(TAG, "no descriptors for group: " + deviceDescriptor.mGroupId);
             }
         }
         // Check if the device is disconnected - if unbond, remove the state machine
@@ -1705,14 +1846,14 @@
                 removeStateMachine(device);
             }
 
-            int myGroupId = getGroupId(device);
-            LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
+            LeAudioGroupDescriptor descriptor = getGroupDescriptor(deviceDescriptor.mGroupId);
             if (descriptor == null) {
-                Log.e(TAG, "no descriptors for group: " + myGroupId);
+                Log.e(TAG, "no descriptors for group: " + deviceDescriptor.mGroupId);
                 return;
             }
 
-            List<BluetoothDevice> connectedDevices = getConnectedPeerDevices(myGroupId);
+            List<BluetoothDevice> connectedDevices =
+                    getConnectedPeerDevices(deviceDescriptor.mGroupId);
             /* Let's check if the last connected device is really connected */
             if (connectedDevices.size() == 1 && Objects.equals(
                     connectedDevices.get(0), descriptor.mLostLeadDeviceWhileStreaming)) {
@@ -1720,14 +1861,14 @@
                 return;
             }
 
-            if (getConnectedPeerDevices(myGroupId).isEmpty()) {
+            if (getConnectedPeerDevices(deviceDescriptor.mGroupId).isEmpty()) {
                 descriptor.mIsConnected = false;
                 if (descriptor.mIsActive) {
                     /* Notify Native layer */
                     setActiveDevice(null);
                     descriptor.mIsActive = false;
                     /* Update audio framework */
-                    updateActiveDevices(myGroupId,
+                    updateActiveDevices(deviceDescriptor.mGroupId,
                             descriptor.mDirection,
                             descriptor.mDirection,
                             descriptor.mIsActive);
@@ -1736,7 +1877,7 @@
             }
 
             if (descriptor.mIsActive) {
-                updateActiveDevices(myGroupId,
+                updateActiveDevices(deviceDescriptor.mGroupId,
                         descriptor.mDirection,
                         descriptor.mDirection,
                         descriptor.mIsActive);
@@ -1833,8 +1974,14 @@
         if (device == null) {
             return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
         }
-        return mDeviceAudioLocationMap.getOrDefault(device,
-                BluetoothLeAudio.AUDIO_LOCATION_INVALID);
+
+        LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+        if (descriptor == null) {
+            Log.e(TAG, "getAudioLocation: No valid descriptor for device: " + device);
+            return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+        }
+
+        return descriptor.mSinkAudioLocation;
     }
 
     /**
@@ -1925,8 +2072,15 @@
         if (device == null) {
             return LE_AUDIO_GROUP_ID_INVALID;
         }
+
         synchronized (mGroupLock) {
-            return mDeviceGroupIdMap.getOrDefault(device, LE_AUDIO_GROUP_ID_INVALID);
+            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+            if (descriptor == null) {
+                Log.e(TAG, "getGroupId: No valid descriptor for device: " + device);
+                return LE_AUDIO_GROUP_ID_INVALID;
+            }
+
+            return descriptor.mGroupId;
         }
     }
 
@@ -1998,7 +2152,7 @@
         mBluetoothEnabled = true;
 
         synchronized (mGroupLock) {
-            if (mDeviceGroupIdMap.isEmpty()) {
+            if (mDeviceDescriptors.isEmpty()) {
                 return;
             }
         }
@@ -2010,7 +2164,12 @@
         }
 
         synchronized (mGroupLock) {
-            for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
+            for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
+                    : mDeviceDescriptors.entrySet()) {
+                if (entry.getValue().mGroupId == LE_AUDIO_GROUP_ID_INVALID) {
+                    continue;
+                }
+
                 mcpService.setDeviceAuthorized(entry.getKey(), true);
             }
         }
@@ -2022,13 +2181,35 @@
         }
     }
 
+    private LeAudioDeviceDescriptor getDeviceDescriptor(BluetoothDevice device) {
+        synchronized (mGroupLock) {
+            return mDeviceDescriptors.get(device);
+        }
+    }
+
     private void handleGroupNodeAdded(BluetoothDevice device, int groupId) {
         synchronized (mGroupLock) {
             if (DBG) {
                 Log.d(TAG, "Device " + device + " added to group " + groupId);
             }
 
-            mDeviceGroupIdMap.put(device, groupId);
+            LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+            if (deviceDescriptor == null) {
+                deviceDescriptor = createDeviceDescriptor(device);
+                if (deviceDescriptor == null) {
+                    Log.e(TAG, "handleGroupNodeAdded: Can't create descriptor for added from"
+                            + " storage device: " + device);
+                    return;
+                }
+
+                LeAudioStateMachine sm = getOrCreateStateMachine(device);
+                if (getOrCreateStateMachine(device) == null) {
+                    Log.e(TAG, "Can't get state machine for device: " + device);
+                    return;
+                }
+            }
+            deviceDescriptor.mGroupId = groupId;
+
             LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
             if (descriptor == null) {
                 mGroupDescriptors.put(groupId, new LeAudioGroupDescriptor());
@@ -2070,17 +2251,39 @@
             Log.d(TAG, "Removing device " + device + " grom group " + groupId);
         }
 
-        LeAudioGroupDescriptor descriptor = getGroupDescriptor(groupId);
-        if (DBG) {
-            Log.d(TAG, "Lost lead device is " + descriptor.mLostLeadDeviceWhileStreaming);
-        }
-        if (Objects.equals(device, descriptor.mLostLeadDeviceWhileStreaming)) {
-            clearLostDevicesWhileStreaming(descriptor);
-        }
-
         synchronized (mGroupLock) {
-            mDeviceGroupIdMap.remove(device);
-            if (!mDeviceGroupIdMap.containsValue(groupId)) {
+            LeAudioGroupDescriptor groupDescriptor = getGroupDescriptor(groupId);
+            if (DBG) {
+                Log.d(TAG, "Lost lead device is " + groupDescriptor.mLostLeadDeviceWhileStreaming);
+            }
+            if (Objects.equals(device, groupDescriptor.mLostLeadDeviceWhileStreaming)) {
+                clearLostDevicesWhileStreaming(groupDescriptor);
+            }
+
+            LeAudioDeviceDescriptor deviceDescriptor = getDeviceDescriptor(device);
+            if (deviceDescriptor == null) {
+                Log.e(TAG, "handleGroupNodeRemoved: No valid descriptor for device: " + device);
+                return;
+            }
+            deviceDescriptor.mGroupId = LE_AUDIO_GROUP_ID_INVALID;
+
+            boolean isGroupEmpty = true;
+
+            for (LeAudioDeviceDescriptor descriptor : mDeviceDescriptors.values()) {
+                if (descriptor.mGroupId == groupId) {
+                    isGroupEmpty = false;
+                    break;
+                }
+            }
+
+            if (isGroupEmpty) {
+                /* Device is currently an active device. Group needs to be inactivated before
+                 * removing
+                 */
+                if (Objects.equals(device, mActiveAudioOutDevice)
+                        || Objects.equals(device, mActiveAudioInDevice)) {
+                    handleGroupTransitToInactive(groupId);
+                }
                 mGroupDescriptors.remove(groupId);
             }
             notifyGroupNodeRemoved(device, groupId);
@@ -2910,16 +3113,22 @@
     @Override
     public void dump(StringBuilder sb) {
         super.dump(sb);
-        ProfileService.println(sb, "State machines: ");
-        for (LeAudioStateMachine sm : mStateMachines.values()) {
-            sm.dump(sb);
-        }
         ProfileService.println(sb, "Active Groups information: ");
         ProfileService.println(sb, "  currentlyActiveGroupId: " + getActiveGroupId());
         ProfileService.println(sb, "  mActiveAudioOutDevice: " + mActiveAudioOutDevice);
         ProfileService.println(sb, "  mActiveAudioInDevice: " + mActiveAudioInDevice);
         ProfileService.println(sb, "  mHfpHandoverDevice:" + mHfpHandoverDevice);
 
+        for (Map.Entry<BluetoothDevice, LeAudioDeviceDescriptor> entry
+                : mDeviceDescriptors.entrySet()) {
+            LeAudioDeviceDescriptor descriptor = entry.getValue();
+
+            descriptor.mStateMachine.dump(sb);
+            ProfileService.println(sb, "    mGroupId: " + descriptor.mGroupId);
+            ProfileService.println(sb, "    mSinkAudioLocation: " + descriptor.mSinkAudioLocation);
+            ProfileService.println(sb, "    mDirection: " + descriptor.mDirection);
+        }
+
         for (Map.Entry<Integer, LeAudioGroupDescriptor> entry : mGroupDescriptors.entrySet()) {
             LeAudioGroupDescriptor descriptor = entry.getValue();
             Integer groupId = entry.getKey();
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java
index a838cbb..95c4e0f 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioStateMachine.java
@@ -55,8 +55,6 @@
 import android.util.Log;
 import static android.Manifest.permission.BLUETOOTH_CONNECT;
 
-import android.annotation.RequiresPermission;
-
 import com.android.bluetooth.Utils;
 import com.android.bluetooth.btservice.ProfileService;
 import com.android.internal.annotations.VisibleForTesting;
diff --git a/android/app/src/com/android/bluetooth/mapclient/MapClientContent.java b/android/app/src/com/android/bluetooth/mapclient/MapClientContent.java
index 36d4535..aa60b5b 100644
--- a/android/app/src/com/android/bluetooth/mapclient/MapClientContent.java
+++ b/android/app/src/com/android/bluetooth/mapclient/MapClientContent.java
@@ -137,6 +137,10 @@
         SubscriptionManager subscriptionManager =
                 context.getSystemService(SubscriptionManager.class);
         List<SubscriptionInfo> subscriptions = subscriptionManager.getActiveSubscriptionInfoList();
+        if (subscriptions == null) {
+            Log.w(TAG, "Active subscription list is missing");
+            return;
+        }
         for (SubscriptionInfo info : subscriptions) {
             if (info.getSubscriptionType() == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) {
                 clearMessages(context, info.getSubscriptionId());
diff --git a/android/app/src/com/android/bluetooth/mapclient/MapClientService.java b/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
index ff38353..25a8a2f 100644
--- a/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
+++ b/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
@@ -166,9 +166,6 @@
     }
 
     private synchronized void addDeviceToMapAndConnect(BluetoothDevice device) {
-        if (Utils.isInstrumentationTestMode()) {
-            Log.d(TAG, "addDeviceToMapAndConnect: device=" + device, new Exception());
-        }
         // When creating a new statemachine, its state is set to CONNECTING - which will trigger
         // connect.
         MceStateMachine mapStateMachine = new MceStateMachine(this, device);
@@ -358,6 +355,7 @@
             }
             stateMachine.doQuit();
         }
+        mMapInstanceMap.clear();
         return true;
     }
 
@@ -367,10 +365,6 @@
             Log.d(TAG, "in Cleanup");
         }
         removeUncleanAccounts();
-        mMapInstanceMap.clear();
-        if (Utils.isInstrumentationTestMode()) {
-            Log.d(TAG, "cleanup() called.", new Exception());
-        }
         // TODO(b/72948646): should be moved to stop()
         setMapClientService(null);
     }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
index 5574b87..c6ed3c1 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
@@ -26,13 +26,13 @@
 
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHapClient;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.content.Context;
 import android.content.Intent;
 import android.media.AudioManager;
@@ -125,7 +125,7 @@
 
         when(mA2dpService.setActiveDevice(any())).thenReturn(true);
         when(mHeadsetService.getHfpCallAudioPolicy(any())).thenReturn(
-                new BluetoothAudioPolicy.Builder().build());
+                new BluetoothSinkAudioPolicy.Builder().build());
         when(mHeadsetService.setActiveDevice(any())).thenReturn(true);
         when(mHearingAidService.setActiveDevice(any())).thenReturn(true);
         when(mLeAudioService.setActiveDevice(any())).thenReturn(true);
@@ -319,10 +319,11 @@
     public void notAllowedConnectingPolicyHeadsetConnected_noSetActiveDevice() {
         // setting connecting policy to NOT ALLOWED
         when(mHeadsetService.getHfpCallAudioPolicy(mHeadsetDevice))
-                .thenReturn(new BluetoothAudioPolicy.Builder()
-                        .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                        .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_NOT_ALLOWED)
-                        .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+                .thenReturn(new BluetoothSinkAudioPolicy.Builder()
+                        .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                        .setActiveDevicePolicyAfterConnection(
+                                BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED)
+                        .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
                         .build());
 
         headsetConnected(mHeadsetDevice);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java
new file mode 100644
index 0000000..6acc5a0
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceFactoryResetTest.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.btservice;
+
+import static android.Manifest.permission.BLUETOOTH_SCAN;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import android.app.AlarmManager;
+import android.app.admin.DevicePolicyManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.IBluetoothCallback;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.AsyncTask;
+import android.os.BatteryStatsManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.permission.PermissionCheckerManager;
+import android.permission.PermissionManager;
+import android.provider.Settings;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.TestUtils;
+import com.android.bluetooth.Utils;
+import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.a2dpsink.A2dpSinkService;
+import com.android.bluetooth.avrcp.AvrcpTargetService;
+import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
+import com.android.bluetooth.bas.BatteryService;
+import com.android.bluetooth.bass_client.BassClientService;
+import com.android.bluetooth.csip.CsipSetCoordinatorService;
+import com.android.bluetooth.gatt.GattService;
+import com.android.bluetooth.hap.HapClientService;
+import com.android.bluetooth.hearingaid.HearingAidService;
+import com.android.bluetooth.hfp.HeadsetService;
+import com.android.bluetooth.hfpclient.HeadsetClientService;
+import com.android.bluetooth.hid.HidDeviceService;
+import com.android.bluetooth.hid.HidHostService;
+import com.android.bluetooth.le_audio.LeAudioService;
+import com.android.bluetooth.map.BluetoothMapService;
+import com.android.bluetooth.mapclient.MapClientService;
+import com.android.bluetooth.mcp.McpService;
+import com.android.bluetooth.opp.BluetoothOppService;
+import com.android.bluetooth.pan.PanService;
+import com.android.bluetooth.pbap.BluetoothPbapService;
+import com.android.bluetooth.pbapclient.PbapClientService;
+import com.android.bluetooth.sap.SapService;
+import com.android.bluetooth.tbs.TbsService;
+import com.android.bluetooth.vc.VolumeControlService;
+import com.android.internal.app.IBatteryStats;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AdapterServiceFactoryResetTest {
+    private static final String TAG = AdapterServiceFactoryResetTest.class.getSimpleName();
+
+    private AdapterService mAdapterService;
+    private AdapterService.AdapterServiceBinder mServiceBinder;
+
+    private @Mock Context mMockContext;
+    private @Mock ApplicationInfo mMockApplicationInfo;
+    private @Mock AlarmManager mMockAlarmManager;
+    private @Mock Resources mMockResources;
+    private @Mock UserManager mMockUserManager;
+    private @Mock DevicePolicyManager mMockDevicePolicyManager;
+    private @Mock ProfileService mMockGattService;
+    private @Mock ProfileService mMockService;
+    private @Mock ProfileService mMockService2;
+    private @Mock IBluetoothCallback mIBluetoothCallback;
+    private @Mock Binder mBinder;
+    private @Mock AudioManager mAudioManager;
+    private @Mock android.app.Application mApplication;
+    private @Mock MetricsLogger mMockMetricsLogger;
+
+    // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
+    // underlying binder calls.
+    final BatteryStatsManager mBatteryStatsManager =
+            new BatteryStatsManager(mock(IBatteryStats.class));
+
+    private static final int CONTEXT_SWITCH_MS = 100;
+    private static final int PROFILE_SERVICE_TOGGLE_TIME_MS = 200;
+    private static final int GATT_START_TIME_MS = 1000;
+    private static final int ONE_SECOND_MS = 1000;
+    private static final int NATIVE_INIT_MS = 8000;
+
+    private final AttributionSource mAttributionSource = new AttributionSource.Builder(
+            Process.myUid()).build();
+
+    private BluetoothManager mBluetoothManager;
+    private PowerManager mPowerManager;
+    private PermissionCheckerManager mPermissionCheckerManager;
+    private PermissionManager mPermissionManager;
+    private PackageManager mMockPackageManager;
+    private MockContentResolver mMockContentResolver;
+    private HashMap<String, HashMap<String, String>> mAdapterConfig;
+    private int mForegroundUserId;
+
+    private void configureEnabledProfiles() {
+        Log.e(TAG, "configureEnabledProfiles");
+        Config.setProfileEnabled(PanService.class, true);
+        Config.setProfileEnabled(BluetoothPbapService.class, true);
+        Config.setProfileEnabled(GattService.class, true);
+
+        Config.setProfileEnabled(A2dpService.class, false);
+        Config.setProfileEnabled(A2dpSinkService.class, false);
+        Config.setProfileEnabled(AvrcpTargetService.class, false);
+        Config.setProfileEnabled(AvrcpControllerService.class, false);
+        Config.setProfileEnabled(BassClientService.class, false);
+        Config.setProfileEnabled(BatteryService.class, false);
+        Config.setProfileEnabled(CsipSetCoordinatorService.class, false);
+        Config.setProfileEnabled(HapClientService.class, false);
+        Config.setProfileEnabled(HeadsetService.class, false);
+        Config.setProfileEnabled(HeadsetClientService.class, false);
+        Config.setProfileEnabled(HearingAidService.class, false);
+        Config.setProfileEnabled(HidDeviceService.class, false);
+        Config.setProfileEnabled(HidHostService.class, false);
+        Config.setProfileEnabled(LeAudioService.class, false);
+        Config.setProfileEnabled(TbsService.class, false);
+        Config.setProfileEnabled(BluetoothMapService.class, false);
+        Config.setProfileEnabled(MapClientService.class, false);
+        Config.setProfileEnabled(McpService.class, false);
+        Config.setProfileEnabled(BluetoothOppService.class, false);
+        Config.setProfileEnabled(PbapClientService.class, false);
+        Config.setProfileEnabled(SapService.class, false);
+        Config.setProfileEnabled(VolumeControlService.class, false);
+    }
+
+    @BeforeClass
+    public static void setupClass() {
+        Log.e(TAG, "setupClass");
+        // Bring native layer up and down to make sure config files are properly loaded
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        Assert.assertNotNull(Looper.myLooper());
+        AdapterService adapterService = new AdapterService();
+        adapterService.initNative(false /* is_restricted */, false /* is_common_criteria_mode */,
+                0 /* config_compare_result */, new String[0], false, "");
+        adapterService.cleanupNative();
+        HashMap<String, HashMap<String, String>> adapterConfig = TestUtils.readAdapterConfig();
+        Assert.assertNotNull(adapterConfig);
+        Assert.assertNotNull("metrics salt is null: " + adapterConfig.toString(),
+                AdapterServiceTest.getMetricsSalt(adapterConfig));
+    }
+
+    @Before
+    public void setUp() throws PackageManager.NameNotFoundException {
+        Log.e(TAG, "setUp()");
+        MockitoAnnotations.initMocks(this);
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        Assert.assertNotNull(Looper.myLooper());
+
+        // Dispatch all async work through instrumentation so we can wait until
+        // it's drained below
+        AsyncTask.setDefaultExecutor((r) -> {
+            androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
+                    .runOnMainSync(r);
+        });
+        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity();
+
+        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                () -> mAdapterService = new AdapterService());
+        mServiceBinder = new AdapterService.AdapterServiceBinder(mAdapterService);
+        mMockPackageManager = mock(PackageManager.class);
+        when(mMockPackageManager.getPermissionInfo(any(), anyInt()))
+                .thenReturn(new PermissionInfo());
+
+        mMockContentResolver = new MockContentResolver(InstrumentationRegistry.getTargetContext());
+        mMockContentResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() {
+            @Override
+            public Bundle call(String method, String request, Bundle args) {
+                return Bundle.EMPTY;
+            }
+        });
+
+        mPowerManager = InstrumentationRegistry.getTargetContext()
+                .getSystemService(PowerManager.class);
+        mPermissionCheckerManager = InstrumentationRegistry.getTargetContext()
+                .getSystemService(PermissionCheckerManager.class);
+
+        mPermissionManager = InstrumentationRegistry.getTargetContext()
+                .getSystemService(PermissionManager.class);
+
+        mBluetoothManager = InstrumentationRegistry.getTargetContext()
+                .getSystemService(BluetoothManager.class);
+
+        when(mMockContext.getCacheDir()).thenReturn(InstrumentationRegistry.getTargetContext()
+                .getCacheDir());
+        when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo);
+        when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+        when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+        when(mMockContext.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0)).thenReturn(
+                mMockContext);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
+        when(mMockContext.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE);
+        when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+                mMockDevicePolicyManager);
+        when(mMockContext.getSystemServiceName(DevicePolicyManager.class))
+                .thenReturn(Context.DEVICE_POLICY_SERVICE);
+        when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager);
+        when(mMockContext.getSystemServiceName(PowerManager.class))
+                .thenReturn(Context.POWER_SERVICE);
+        when(mMockContext.getSystemServiceName(PermissionCheckerManager.class))
+                .thenReturn(Context.PERMISSION_CHECKER_SERVICE);
+        when(mMockContext.getSystemService(Context.PERMISSION_CHECKER_SERVICE))
+                .thenReturn(mPermissionCheckerManager);
+        when(mMockContext.getSystemServiceName(PermissionManager.class))
+                .thenReturn(Context.PERMISSION_SERVICE);
+        when(mMockContext.getSystemService(Context.PERMISSION_SERVICE))
+                .thenReturn(mPermissionManager);
+        when(mMockContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mMockAlarmManager);
+        when(mMockContext.getSystemServiceName(AlarmManager.class))
+                .thenReturn(Context.ALARM_SERVICE);
+        when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
+        when(mMockContext.getSystemServiceName(AudioManager.class))
+                .thenReturn(Context.AUDIO_SERVICE);
+        when(mMockContext.getSystemService(Context.BATTERY_STATS_SERVICE))
+                .thenReturn(mBatteryStatsManager);
+        when(mMockContext.getSystemServiceName(BatteryStatsManager.class))
+                .thenReturn(Context.BATTERY_STATS_SERVICE);
+        when(mMockContext.getSystemService(Context.BLUETOOTH_SERVICE))
+                .thenReturn(mBluetoothManager);
+        when(mMockContext.getSystemServiceName(BluetoothManager.class))
+                .thenReturn(Context.BLUETOOTH_SERVICE);
+        when(mMockContext.getSharedPreferences(anyString(), anyInt()))
+                .thenReturn(InstrumentationRegistry.getTargetContext()
+                        .getSharedPreferences("AdapterServiceTestPrefs", Context.MODE_PRIVATE));
+
+        when(mMockContext.getAttributionSource()).thenReturn(mAttributionSource);
+        doAnswer(invocation -> {
+            Object[] args = invocation.getArguments();
+            return InstrumentationRegistry.getTargetContext().getDatabasePath((String) args[0]);
+        }).when(mMockContext).getDatabasePath(anyString());
+
+        // Sets the foreground user id to match that of the tests (restored in tearDown)
+        mForegroundUserId = Utils.getForegroundUserId();
+        int callingUid = Binder.getCallingUid();
+        UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
+        Utils.setForegroundUserId(callingUser.getIdentifier());
+
+        when(mMockDevicePolicyManager.isCommonCriteriaModeEnabled(any())).thenReturn(false);
+
+        when(mIBluetoothCallback.asBinder()).thenReturn(mBinder);
+
+        doReturn(Process.BLUETOOTH_UID).when(mMockPackageManager)
+                .getPackageUidAsUser(any(), anyInt(), anyInt());
+
+        when(mMockGattService.getName()).thenReturn("GattService");
+        when(mMockService.getName()).thenReturn("Service1");
+        when(mMockService2.getName()).thenReturn("Service2");
+
+        when(mMockMetricsLogger.init(any())).thenReturn(true);
+        when(mMockMetricsLogger.close()).thenReturn(true);
+
+        configureEnabledProfiles();
+        Config.init(mMockContext);
+
+        mAdapterService.setMetricsLogger(mMockMetricsLogger);
+
+        // Attach a context to the service for permission checks.
+        mAdapterService.attach(mMockContext, null, null, null, mApplication, null);
+        mAdapterService.onCreate();
+
+        // Wait for any async events to drain
+        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        mServiceBinder.registerCallback(mIBluetoothCallback, mAttributionSource);
+
+        mAdapterConfig = TestUtils.readAdapterConfig();
+        Assert.assertNotNull(mAdapterConfig);
+    }
+
+    @After
+    public void tearDown() {
+        Log.e(TAG, "tearDown()");
+
+        // Enable the stack to re-create the config. Next tests rely on it.
+        doEnable(0, false);
+
+        // Restores the foregroundUserId to the ID prior to the test setup
+        Utils.setForegroundUserId(mForegroundUserId);
+
+        mServiceBinder.unregisterCallback(mIBluetoothCallback, mAttributionSource);
+        mAdapterService.cleanup();
+    }
+
+    @AfterClass
+    public static void tearDownOnce() {
+        AsyncTask.setDefaultExecutor(AsyncTask.SERIAL_EXECUTOR);
+    }
+
+    private void verifyStateChange(int prevState, int currState, int callNumber, int timeoutMs) {
+        try {
+            verify(mIBluetoothCallback, timeout(timeoutMs).times(callNumber))
+                .onBluetoothStateChange(prevState, currState);
+        } catch (RemoteException e) {
+            // the mocked onBluetoothStateChange doesn't throw RemoteException
+        }
+    }
+
+    private void doEnable(int invocationNumber, boolean onlyGatt) {
+        Log.e(TAG, "doEnable() start");
+        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+
+        int startServiceCalls;
+        startServiceCalls = 2 * (onlyGatt ? 1 : 3); // Start and stop GATT + 2
+
+        mAdapterService.enable(false);
+
+        verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON,
+                invocationNumber + 1, CONTEXT_SWITCH_MS);
+
+        // Start GATT
+        verify(mMockContext, timeout(GATT_START_TIME_MS).times(
+                startServiceCalls * invocationNumber + 1)).startService(any());
+        mAdapterService.addProfile(mMockGattService);
+        mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_ON);
+
+        verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, BluetoothAdapter.STATE_BLE_ON,
+                invocationNumber + 1, NATIVE_INIT_MS);
+
+        mServiceBinder.onLeServiceUp(mAttributionSource);
+
+        verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_TURNING_ON,
+                invocationNumber + 1, CONTEXT_SWITCH_MS);
+
+        if (!onlyGatt) {
+            // Start Mock PBAP and PAN services
+            verify(mMockContext, timeout(ONE_SECOND_MS).times(
+                    startServiceCalls * invocationNumber + 3)).startService(any());
+
+            mAdapterService.addProfile(mMockService);
+            mAdapterService.addProfile(mMockService2);
+            mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_ON);
+            mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_ON);
+        }
+
+        verifyStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_ON,
+                invocationNumber + 1, PROFILE_SERVICE_TOGGLE_TIME_MS);
+
+        verify(mMockContext, timeout(CONTEXT_SWITCH_MS).times(2 * invocationNumber + 2))
+                .sendBroadcast(any(), eq(BLUETOOTH_SCAN),
+                        any(Bundle.class));
+        final int scanMode = mServiceBinder.getScanMode(mAttributionSource);
+        Assert.assertTrue(scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
+                || scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+        Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+
+        Log.e(TAG, "doEnable() complete success");
+    }
+
+    /**
+     * Test: Verify that obfuscated Bluetooth address changes after factory reset
+     *
+     * There are 4 types of factory reset that we are talking about:
+     * 1. Factory reset all user data from Settings -> Will restart phone
+     * 2. Factory reset WiFi and Bluetooth from Settings -> Will only restart WiFi and BT
+     * 3. Call BluetoothAdapter.factoryReset() -> Will disable Bluetooth and reset config in
+     * memory and disk
+     * 4. Call AdapterService.factoryReset() -> Will only reset config in memory
+     *
+     * We can only use No. 4 here
+     */
+    @Ignore("AdapterService.factoryReset() does not reload config into memory and hence old salt"
+            + " is still used until next time Bluetooth library is initialized. However Bluetooth"
+            + " cannot be used until Bluetooth process restart any way. Thus it is almost"
+            + " guaranteed that user has to re-enable Bluetooth and hence re-generate new salt"
+            + " after factory reset")
+    @Test
+    public void testObfuscateBluetoothAddress_FactoryReset() {
+        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+        BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
+        byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
+        Assert.assertTrue(obfuscatedAddress1.length > 0);
+        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress1));
+        mServiceBinder.factoryReset(mAttributionSource);
+        byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
+        Assert.assertTrue(obfuscatedAddress2.length > 0);
+        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress2));
+        Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
+                obfuscatedAddress1));
+        doEnable(0, false);
+        byte[] obfuscatedAddress3 = mAdapterService.obfuscateAddress(device);
+        Assert.assertTrue(obfuscatedAddress3.length > 0);
+        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress3));
+        Assert.assertArrayEquals(obfuscatedAddress3,
+                obfuscatedAddress2);
+        mServiceBinder.factoryReset(mAttributionSource);
+        byte[] obfuscatedAddress4 = mAdapterService.obfuscateAddress(device);
+        Assert.assertTrue(obfuscatedAddress4.length > 0);
+        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress4));
+        Assert.assertFalse(Arrays.equals(obfuscatedAddress4,
+                obfuscatedAddress3));
+    }
+
+    /**
+     * Test: Verify that obfuscated Bluetooth address changes after factory reset and reloading
+     *       native layer
+     */
+    @Test
+    public void testObfuscateBluetoothAddress_FactoryResetAndReloadNativeLayer() throws
+            PackageManager.NameNotFoundException {
+        byte[] metricsSalt1 = AdapterServiceTest.getMetricsSalt(mAdapterConfig);
+        Assert.assertNotNull(metricsSalt1);
+        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+        BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
+        byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
+        Assert.assertTrue(obfuscatedAddress1.length > 0);
+        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress1));
+        Assert.assertArrayEquals(AdapterServiceTest.obfuscateInJava(metricsSalt1, device),
+                obfuscatedAddress1);
+        mServiceBinder.factoryReset(mAttributionSource);
+        tearDown();
+        setUp();
+        // Cannot verify metrics salt since it is not written to disk until native cleanup
+        byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
+        Assert.assertTrue(obfuscatedAddress2.length > 0);
+        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress2));
+        Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
+                obfuscatedAddress1));
+    }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java
new file mode 100644
index 0000000..c93837b
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceRestartTest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.btservice;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import android.app.AlarmManager;
+import android.app.admin.DevicePolicyManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.IBluetoothCallback;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.AsyncTask;
+import android.os.BatteryStatsManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.permission.PermissionCheckerManager;
+import android.permission.PermissionManager;
+import android.provider.Settings;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.TestUtils;
+import com.android.bluetooth.Utils;
+import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.a2dpsink.A2dpSinkService;
+import com.android.bluetooth.avrcp.AvrcpTargetService;
+import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
+import com.android.bluetooth.bas.BatteryService;
+import com.android.bluetooth.bass_client.BassClientService;
+import com.android.bluetooth.csip.CsipSetCoordinatorService;
+import com.android.bluetooth.gatt.GattService;
+import com.android.bluetooth.hap.HapClientService;
+import com.android.bluetooth.hearingaid.HearingAidService;
+import com.android.bluetooth.hfp.HeadsetService;
+import com.android.bluetooth.hfpclient.HeadsetClientService;
+import com.android.bluetooth.hid.HidDeviceService;
+import com.android.bluetooth.hid.HidHostService;
+import com.android.bluetooth.le_audio.LeAudioService;
+import com.android.bluetooth.map.BluetoothMapService;
+import com.android.bluetooth.mapclient.MapClientService;
+import com.android.bluetooth.mcp.McpService;
+import com.android.bluetooth.opp.BluetoothOppService;
+import com.android.bluetooth.pan.PanService;
+import com.android.bluetooth.pbap.BluetoothPbapService;
+import com.android.bluetooth.pbapclient.PbapClientService;
+import com.android.bluetooth.sap.SapService;
+import com.android.bluetooth.tbs.TbsService;
+import com.android.bluetooth.vc.VolumeControlService;
+import com.android.internal.app.IBatteryStats;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AdapterServiceRestartTest {
+    private static final String TAG = AdapterServiceTest.class.getSimpleName();
+
+    private AdapterService mAdapterService;
+    private AdapterService.AdapterServiceBinder mServiceBinder;
+
+    private @Mock Context mMockContext;
+    private @Mock ApplicationInfo mMockApplicationInfo;
+    private @Mock AlarmManager mMockAlarmManager;
+    private @Mock Resources mMockResources;
+    private @Mock UserManager mMockUserManager;
+    private @Mock DevicePolicyManager mMockDevicePolicyManager;
+    private @Mock IBluetoothCallback mIBluetoothCallback;
+    private @Mock Binder mBinder;
+    private @Mock AudioManager mAudioManager;
+    private @Mock android.app.Application mApplication;
+    private @Mock MetricsLogger mMockMetricsLogger;
+
+    // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
+    // underlying binder calls.
+    final BatteryStatsManager mBatteryStatsManager =
+            new BatteryStatsManager(mock(IBatteryStats.class));
+
+    private final AttributionSource mAttributionSource = new AttributionSource.Builder(
+            Process.myUid()).build();
+
+    private BluetoothManager mBluetoothManager;
+    private PowerManager mPowerManager;
+    private PermissionCheckerManager mPermissionCheckerManager;
+    private PermissionManager mPermissionManager;
+    private PackageManager mMockPackageManager;
+    private MockContentResolver mMockContentResolver;
+    private HashMap<String, HashMap<String, String>> mAdapterConfig;
+    private int mForegroundUserId;
+
+    private void configureEnabledProfiles() {
+        Log.e(TAG, "configureEnabledProfiles");
+        Config.setProfileEnabled(PanService.class, true);
+        Config.setProfileEnabled(BluetoothPbapService.class, true);
+        Config.setProfileEnabled(GattService.class, true);
+
+        Config.setProfileEnabled(A2dpService.class, false);
+        Config.setProfileEnabled(A2dpSinkService.class, false);
+        Config.setProfileEnabled(AvrcpTargetService.class, false);
+        Config.setProfileEnabled(AvrcpControllerService.class, false);
+        Config.setProfileEnabled(BassClientService.class, false);
+        Config.setProfileEnabled(BatteryService.class, false);
+        Config.setProfileEnabled(CsipSetCoordinatorService.class, false);
+        Config.setProfileEnabled(HapClientService.class, false);
+        Config.setProfileEnabled(HeadsetService.class, false);
+        Config.setProfileEnabled(HeadsetClientService.class, false);
+        Config.setProfileEnabled(HearingAidService.class, false);
+        Config.setProfileEnabled(HidDeviceService.class, false);
+        Config.setProfileEnabled(HidHostService.class, false);
+        Config.setProfileEnabled(LeAudioService.class, false);
+        Config.setProfileEnabled(TbsService.class, false);
+        Config.setProfileEnabled(BluetoothMapService.class, false);
+        Config.setProfileEnabled(MapClientService.class, false);
+        Config.setProfileEnabled(McpService.class, false);
+        Config.setProfileEnabled(BluetoothOppService.class, false);
+        Config.setProfileEnabled(PbapClientService.class, false);
+        Config.setProfileEnabled(SapService.class, false);
+        Config.setProfileEnabled(VolumeControlService.class, false);
+    }
+
+    @BeforeClass
+    public static void setupClass() {
+        Log.e(TAG, "setupClass");
+        // Bring native layer up and down to make sure config files are properly loaded
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        Assert.assertNotNull(Looper.myLooper());
+        AdapterService adapterService = new AdapterService();
+        adapterService.initNative(false /* is_restricted */, false /* is_common_criteria_mode */,
+                0 /* config_compare_result */, new String[0], false, "");
+        adapterService.cleanupNative();
+        HashMap<String, HashMap<String, String>> adapterConfig = TestUtils.readAdapterConfig();
+        Assert.assertNotNull(adapterConfig);
+        Assert.assertNotNull("metrics salt is null: " + adapterConfig.toString(),
+                AdapterServiceTest.getMetricsSalt(adapterConfig));
+    }
+
+    @Before
+    public void setUp() throws PackageManager.NameNotFoundException {
+        Log.e(TAG, "setUp()");
+        MockitoAnnotations.initMocks(this);
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        Assert.assertNotNull(Looper.myLooper());
+
+        // Dispatch all async work through instrumentation so we can wait until
+        // it's drained below
+        AsyncTask.setDefaultExecutor((r) -> {
+            androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
+                    .runOnMainSync(r);
+        });
+        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity();
+
+        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                () -> mAdapterService = new AdapterService());
+        mServiceBinder = new AdapterService.AdapterServiceBinder(mAdapterService);
+        mMockPackageManager = mock(PackageManager.class);
+        when(mMockPackageManager.getPermissionInfo(any(), anyInt()))
+                .thenReturn(new PermissionInfo());
+
+        mMockContentResolver = new MockContentResolver(InstrumentationRegistry.getTargetContext());
+        mMockContentResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() {
+            @Override
+            public Bundle call(String method, String request, Bundle args) {
+                return Bundle.EMPTY;
+            }
+        });
+
+        mPowerManager = InstrumentationRegistry.getTargetContext()
+                .getSystemService(PowerManager.class);
+        mPermissionCheckerManager = InstrumentationRegistry.getTargetContext()
+                .getSystemService(PermissionCheckerManager.class);
+
+        mPermissionManager = InstrumentationRegistry.getTargetContext()
+                .getSystemService(PermissionManager.class);
+
+        mBluetoothManager = InstrumentationRegistry.getTargetContext()
+                .getSystemService(BluetoothManager.class);
+
+        when(mMockContext.getCacheDir()).thenReturn(InstrumentationRegistry.getTargetContext()
+                .getCacheDir());
+        when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo);
+        when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+        when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+        when(mMockContext.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0)).thenReturn(
+                mMockContext);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
+        when(mMockContext.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE);
+        when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+                mMockDevicePolicyManager);
+        when(mMockContext.getSystemServiceName(DevicePolicyManager.class))
+                .thenReturn(Context.DEVICE_POLICY_SERVICE);
+        when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager);
+        when(mMockContext.getSystemServiceName(PowerManager.class))
+                .thenReturn(Context.POWER_SERVICE);
+        when(mMockContext.getSystemServiceName(PermissionCheckerManager.class))
+                .thenReturn(Context.PERMISSION_CHECKER_SERVICE);
+        when(mMockContext.getSystemService(Context.PERMISSION_CHECKER_SERVICE))
+                .thenReturn(mPermissionCheckerManager);
+        when(mMockContext.getSystemServiceName(PermissionManager.class))
+                .thenReturn(Context.PERMISSION_SERVICE);
+        when(mMockContext.getSystemService(Context.PERMISSION_SERVICE))
+                .thenReturn(mPermissionManager);
+        when(mMockContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mMockAlarmManager);
+        when(mMockContext.getSystemServiceName(AlarmManager.class))
+                .thenReturn(Context.ALARM_SERVICE);
+        when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
+        when(mMockContext.getSystemServiceName(AudioManager.class))
+                .thenReturn(Context.AUDIO_SERVICE);
+        when(mMockContext.getSystemService(Context.BATTERY_STATS_SERVICE))
+                .thenReturn(mBatteryStatsManager);
+        when(mMockContext.getSystemServiceName(BatteryStatsManager.class))
+                .thenReturn(Context.BATTERY_STATS_SERVICE);
+        when(mMockContext.getSystemService(Context.BLUETOOTH_SERVICE))
+                .thenReturn(mBluetoothManager);
+        when(mMockContext.getSystemServiceName(BluetoothManager.class))
+                .thenReturn(Context.BLUETOOTH_SERVICE);
+        when(mMockContext.getSharedPreferences(anyString(), anyInt()))
+                .thenReturn(InstrumentationRegistry.getTargetContext()
+                        .getSharedPreferences("AdapterServiceTestPrefs", Context.MODE_PRIVATE));
+
+        when(mMockContext.getAttributionSource()).thenReturn(mAttributionSource);
+        doAnswer(invocation -> {
+            Object[] args = invocation.getArguments();
+            return InstrumentationRegistry.getTargetContext().getDatabasePath((String) args[0]);
+        }).when(mMockContext).getDatabasePath(anyString());
+
+        // Sets the foreground user id to match that of the tests (restored in tearDown)
+        mForegroundUserId = Utils.getForegroundUserId();
+        int callingUid = Binder.getCallingUid();
+        UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
+        Utils.setForegroundUserId(callingUser.getIdentifier());
+
+        when(mMockDevicePolicyManager.isCommonCriteriaModeEnabled(any())).thenReturn(false);
+
+        when(mIBluetoothCallback.asBinder()).thenReturn(mBinder);
+
+        doReturn(Process.BLUETOOTH_UID).when(mMockPackageManager)
+                .getPackageUidAsUser(any(), anyInt(), anyInt());
+
+        when(mMockMetricsLogger.init(any())).thenReturn(true);
+        when(mMockMetricsLogger.close()).thenReturn(true);
+
+        configureEnabledProfiles();
+        Config.init(mMockContext);
+
+        mAdapterService.setMetricsLogger(mMockMetricsLogger);
+
+        // Attach a context to the service for permission checks.
+        mAdapterService.attach(mMockContext, null, null, null, mApplication, null);
+        mAdapterService.onCreate();
+
+        // Wait for any async events to drain
+        androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        mServiceBinder.registerCallback(mIBluetoothCallback, mAttributionSource);
+
+        mAdapterConfig = TestUtils.readAdapterConfig();
+        Assert.assertNotNull(mAdapterConfig);
+    }
+
+    @After
+    public void tearDown() {
+        Log.e(TAG, "tearDown()");
+
+        // Restores the foregroundUserId to the ID prior to the test setup
+        Utils.setForegroundUserId(mForegroundUserId);
+
+        mServiceBinder.unregisterCallback(mIBluetoothCallback, mAttributionSource);
+        mAdapterService.cleanup();
+    }
+
+    @AfterClass
+    public static void tearDownOnce() {
+        AsyncTask.setDefaultExecutor(AsyncTask.SERIAL_EXECUTOR);
+    }
+
+    /**
+     * Test: Check if obfuscated Bluetooth address stays the same after re-initializing
+     *       {@link AdapterService}
+     */
+    @Test
+    public void testObfuscateBluetoothAddress_PersistentBetweenAdapterServiceInitialization() throws
+            PackageManager.NameNotFoundException {
+        byte[] metricsSalt = AdapterServiceTest.getMetricsSalt(mAdapterConfig);
+        Assert.assertNotNull(metricsSalt);
+        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+        BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
+        byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
+        Assert.assertTrue(obfuscatedAddress1.length > 0);
+        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress1));
+        Assert.assertArrayEquals(AdapterServiceTest.obfuscateInJava(metricsSalt, device),
+                obfuscatedAddress1);
+        tearDown();
+        setUp();
+
+        byte[] metricsSalt2 = AdapterServiceTest.getMetricsSalt(mAdapterConfig);
+        Assert.assertNotNull(metricsSalt2);
+        Assert.assertArrayEquals(metricsSalt, metricsSalt2);
+
+        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+        byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
+        Assert.assertTrue(obfuscatedAddress2.length > 0);
+        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress2));
+        Assert.assertArrayEquals(obfuscatedAddress2,
+                obfuscatedAddress1);
+    }
+
+    /**
+     * Test: Check if id gotten stays the same after re-initializing
+     *       {@link AdapterService}
+     */
+    @Test
+    public void testgetMetricId_PersistentBetweenAdapterServiceInitialization() throws
+            PackageManager.NameNotFoundException {
+        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+        BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
+        int id1 = mAdapterService.getMetricId(device);
+        Assert.assertTrue(id1 > 0);
+        tearDown();
+        setUp();
+        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
+        int id2 = mAdapterService.getMetricId(device);
+        Assert.assertEquals(id2, id1);
+    }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
index a229499..c320b35 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java
@@ -101,7 +101,6 @@
 import java.io.PrintWriter;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
 import java.util.HashMap;
 
 import javax.crypto.Mac;
@@ -742,7 +741,6 @@
     /**
      * Test: Check if obfuscated Bluetooth address stays the same after toggling Bluetooth
      */
-    @Ignore("b/265588558")
     @Test
     public void testObfuscateBluetoothAddress_PersistentBetweenToggle() {
         Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
@@ -772,103 +770,6 @@
                 obfuscatedAddress1);
     }
 
-    /**
-     * Test: Check if obfuscated Bluetooth address stays the same after re-initializing
-     *       {@link AdapterService}
-     */
-    @Test
-    public void testObfuscateBluetoothAddress_PersistentBetweenAdapterServiceInitialization() throws
-            PackageManager.NameNotFoundException {
-        byte[] metricsSalt = getMetricsSalt(mAdapterConfig);
-        Assert.assertNotNull(metricsSalt);
-        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
-        BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
-        byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
-        Assert.assertTrue(obfuscatedAddress1.length > 0);
-        Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1));
-        Assert.assertArrayEquals(obfuscateInJava(metricsSalt, device),
-                obfuscatedAddress1);
-        tearDown();
-        setUp();
-        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
-        byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
-        Assert.assertTrue(obfuscatedAddress2.length > 0);
-        Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2));
-        Assert.assertArrayEquals(obfuscatedAddress2,
-                obfuscatedAddress1);
-    }
-
-    /**
-     * Test: Verify that obfuscated Bluetooth address changes after factory reset
-     *
-     * There are 4 types of factory reset that we are talking about:
-     * 1. Factory reset all user data from Settings -> Will restart phone
-     * 2. Factory reset WiFi and Bluetooth from Settings -> Will only restart WiFi and BT
-     * 3. Call BluetoothAdapter.factoryReset() -> Will disable Bluetooth and reset config in
-     * memory and disk
-     * 4. Call AdapterService.factoryReset() -> Will only reset config in memory
-     *
-     * We can only use No. 4 here
-     */
-    @Ignore("AdapterService.factoryReset() does not reload config into memory and hence old salt"
-            + " is still used until next time Bluetooth library is initialized. However Bluetooth"
-            + " cannot be used until Bluetooth process restart any way. Thus it is almost"
-            + " guaranteed that user has to re-enable Bluetooth and hence re-generate new salt"
-            + " after factory reset")
-    @Test
-    public void testObfuscateBluetoothAddress_FactoryReset() {
-        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
-        BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
-        byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
-        Assert.assertTrue(obfuscatedAddress1.length > 0);
-        Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1));
-        mServiceBinder.factoryReset(mAttributionSource);
-        byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
-        Assert.assertTrue(obfuscatedAddress2.length > 0);
-        Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2));
-        Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
-                obfuscatedAddress1));
-        doEnable(0, false);
-        byte[] obfuscatedAddress3 = mAdapterService.obfuscateAddress(device);
-        Assert.assertTrue(obfuscatedAddress3.length > 0);
-        Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress3));
-        Assert.assertArrayEquals(obfuscatedAddress3,
-                obfuscatedAddress2);
-        mServiceBinder.factoryReset(mAttributionSource);
-        byte[] obfuscatedAddress4 = mAdapterService.obfuscateAddress(device);
-        Assert.assertTrue(obfuscatedAddress4.length > 0);
-        Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress4));
-        Assert.assertFalse(Arrays.equals(obfuscatedAddress4,
-                obfuscatedAddress3));
-    }
-
-    /**
-     * Test: Verify that obfuscated Bluetooth address changes after factory reset and reloading
-     *       native layer
-     */
-    @Test
-    public void testObfuscateBluetoothAddress_FactoryResetAndReloadNativeLayer() throws
-            PackageManager.NameNotFoundException {
-        byte[] metricsSalt1 = getMetricsSalt(mAdapterConfig);
-        Assert.assertNotNull(metricsSalt1);
-        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
-        BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
-        byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device);
-        Assert.assertTrue(obfuscatedAddress1.length > 0);
-        Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1));
-        Assert.assertArrayEquals(obfuscateInJava(metricsSalt1, device),
-                obfuscatedAddress1);
-        mServiceBinder.factoryReset(mAttributionSource);
-        tearDown();
-        setUp();
-        // Cannot verify metrics salt since it is not written to disk until native cleanup
-        byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device);
-        Assert.assertTrue(obfuscatedAddress2.length > 0);
-        Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2));
-        Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
-                obfuscatedAddress1));
-    }
-
     @Test
     public void testAddressConsolidation() {
         // Create device properties
@@ -886,7 +787,7 @@
         Assert.assertEquals(identityAddress, TEST_BT_ADDR_2);
     }
 
-    private static byte[] getMetricsSalt(HashMap<String, HashMap<String, String>> adapterConfig) {
+    public static byte[] getMetricsSalt(HashMap<String, HashMap<String, String>> adapterConfig) {
         HashMap<String, String> metricsSection = adapterConfig.get("Metrics");
         if (metricsSection == null) {
             Log.e(TAG, "Metrics section is null: " + adapterConfig.toString());
@@ -905,7 +806,7 @@
         return metricsSalt;
     }
 
-    private static byte[] obfuscateInJava(byte[] key, BluetoothDevice device) {
+    public static byte[] obfuscateInJava(byte[] key, BluetoothDevice device) {
         String algorithm = "HmacSHA256";
         try {
             Mac hmac256 = Mac.getInstance(algorithm);
@@ -917,7 +818,7 @@
         }
     }
 
-    private static boolean isByteArrayAllZero(byte[] byteArray) {
+    public static boolean isByteArrayAllZero(byte[] byteArray) {
         for (byte i : byteArray) {
             if (i != 0) {
                 return false;
@@ -985,24 +886,6 @@
         Assert.assertEquals(id3, id1);
     }
 
-    /**
-     * Test: Check if id gotten stays the same after re-initializing
-     *       {@link AdapterService}
-     */
-    @Test
-    public void testgetMetricId_PersistentBetweenAdapterServiceInitialization() throws
-            PackageManager.NameNotFoundException {
-        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
-        BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0);
-        int id1 = mAdapterService.getMetricId(device);
-        Assert.assertTrue(id1 > 0);
-        tearDown();
-        setUp();
-        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);
-        int id2 = mAdapterService.getMetricId(device);
-        Assert.assertEquals(id2, id1);
-    }
-
     @Test
     public void testDump_doesNotCrash() {
         FileDescriptor fd = new FileDescriptor();
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
index 22df72c..86875f2 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java
@@ -6,11 +6,11 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothAssignedNumbers;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHeadsetClient;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.HandlerThread;
@@ -527,10 +527,10 @@
         mRemoteDevices.addDeviceProperties(Utils.getBytesFromAddress(TEST_BT_ADDR_1));
 
         DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(mDevice1);
-        BluetoothAudioPolicy policies = new BluetoothAudioPolicy.Builder()
-                .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+        BluetoothSinkAudioPolicy policies = new BluetoothSinkAudioPolicy.Builder()
+                .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                .setActiveDevicePolicyAfterConnection(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
                 .build();
         deviceProp.setHfAudioPolicyForRemoteAg(policies);
 
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
index 2bf7302..cd306f4 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
@@ -28,9 +28,9 @@
 
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
@@ -460,10 +460,10 @@
     @Test
     public void testSetGetAudioPolicyMetaData() {
         int badKey = 100;
-        BluetoothAudioPolicy value = new BluetoothAudioPolicy.Builder()
-                .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_NOT_ALLOWED)
-                .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+        BluetoothSinkAudioPolicy value = new BluetoothSinkAudioPolicy.Builder()
+                .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                .setActiveDevicePolicyAfterConnection(BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED)
+                .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
                 .build();
 
         // Device is not in database
@@ -1481,8 +1481,8 @@
     }
 
     void testSetGetAudioPolicyMetadataCase(boolean stored,
-                BluetoothAudioPolicy policy, boolean expectedResult) {
-        BluetoothAudioPolicy testPolicy = new BluetoothAudioPolicy.Builder().build();
+                BluetoothSinkAudioPolicy policy, boolean expectedResult) {
+        BluetoothSinkAudioPolicy testPolicy = new BluetoothSinkAudioPolicy.Builder().build();
         if (stored) {
             Metadata data = new Metadata(TEST_BT_ADDR);
             mDatabaseManager.mMetadataCache.put(TEST_BT_ADDR, data);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
index fb27a2a..c41cbce 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
@@ -26,7 +26,7 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
@@ -67,6 +67,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
+import org.mockito.InOrder;
 
 import java.lang.reflect.Method;
 import java.util.Collections;
@@ -182,8 +183,8 @@
                 .getBondState(any(BluetoothDevice.class));
         doAnswer(invocation -> mBondedDevices.toArray(new BluetoothDevice[]{})).when(
                 mAdapterService).getBondedDevices();
-        doReturn(new BluetoothAudioPolicy.Builder().build()).when(mAdapterService)
-                .getAudioPolicy(any(BluetoothDevice.class));
+        doReturn(new BluetoothSinkAudioPolicy.Builder().build()).when(mAdapterService)
+                .getRequestedAudioPolicyAsSink(any(BluetoothDevice.class));
         // Mock system interface
         doNothing().when(mSystemInterface).stop();
         when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState);
@@ -666,6 +667,7 @@
         Assert.assertTrue(mHeadsetService.setActiveDevice(device));
         verify(mNativeInterface).setActiveDevice(device);
         Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+        verify(mNativeInterface).sendBsir(eq(device), eq(true));
         // Start voice recognition
         startVoiceRecognitionFromHf(device);
     }
@@ -689,6 +691,7 @@
         Assert.assertTrue(mHeadsetService.setActiveDevice(device));
         verify(mNativeInterface).setActiveDevice(device);
         Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+        verify(mNativeInterface).sendBsir(eq(device), eq(true));
         // Start voice recognition
         startVoiceRecognitionFromHf(device);
         // Stop voice recognition
@@ -723,6 +726,7 @@
         Assert.assertTrue(mHeadsetService.setActiveDevice(device));
         verify(mNativeInterface).setActiveDevice(device);
         Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+        verify(mNativeInterface).sendBsir(eq(device), eq(true));
         // Start voice recognition
         HeadsetStackEvent startVrEvent =
                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED,
@@ -755,6 +759,7 @@
         Assert.assertTrue(mHeadsetService.setActiveDevice(device));
         verify(mNativeInterface).setActiveDevice(device);
         Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+        verify(mNativeInterface).sendBsir(eq(device), eq(true));
         // Start voice recognition
         HeadsetStackEvent startVrEvent =
                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED,
@@ -787,6 +792,7 @@
         Assert.assertTrue(mHeadsetService.setActiveDevice(device));
         verify(mNativeInterface).setActiveDevice(device);
         Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+        verify(mNativeInterface).sendBsir(eq(device), eq(true));
         // Start voice recognition
         startVoiceRecognitionFromAg();
     }
@@ -860,6 +866,7 @@
         Assert.assertTrue(mHeadsetService.setActiveDevice(device));
         verify(mNativeInterface).setActiveDevice(device);
         Assert.assertEquals(device, mHeadsetService.getActiveDevice());
+        verify(mNativeInterface).sendBsir(eq(device), eq(true));
         // Start voice recognition
         startVoiceRecognitionFromAg();
         // Stop voice recognition
@@ -908,8 +915,10 @@
         connectTestDevice(deviceA);
         BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);
         connectTestDevice(deviceB);
-        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false);
-        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false);
+        InOrder inOrder = inOrder(mNativeInterface);
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true));
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false));
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false));
         // Set active device to device B
         Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB));
         verify(mNativeInterface).setActiveDevice(deviceB);
@@ -960,8 +969,10 @@
         connectTestDevice(deviceA);
         BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);
         connectTestDevice(deviceB);
-        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false);
-        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false);
+        InOrder inOrder = inOrder(mNativeInterface);
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true));
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false));
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false));
         // Set active device to device B
         Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB));
         verify(mNativeInterface).setActiveDevice(deviceB);
@@ -1012,8 +1023,10 @@
         connectTestDevice(deviceA);
         BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);
         connectTestDevice(deviceB);
-        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false);
-        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false);
+        InOrder inOrder = inOrder(mNativeInterface);
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true));
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false));
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false));
         // Set active device to device B
         Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB));
         verify(mNativeInterface).setActiveDevice(deviceB);
@@ -1051,8 +1064,10 @@
         connectTestDevice(deviceA);
         BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);
         connectTestDevice(deviceB);
-        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false);
-        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false);
+        InOrder inOrder = inOrder(mNativeInterface);
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true));
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false));
+        inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false));
         // Set active device to device B
         Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB));
         verify(mNativeInterface).setActiveDevice(deviceB);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
index 817ea8b..09fe7cc 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
@@ -19,7 +19,7 @@
 import static org.mockito.Mockito.*;
 
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
@@ -117,8 +117,8 @@
             Set<BluetoothDevice> keys = mStateMachines.keySet();
             return keys.toArray(new BluetoothDevice[keys.size()]);
         }).when(mAdapterService).getBondedDevices();
-        doReturn(new BluetoothAudioPolicy.Builder().build()).when(mAdapterService)
-                .getAudioPolicy(any(BluetoothDevice.class));
+        doReturn(new BluetoothSinkAudioPolicy.Builder().build()).when(mAdapterService)
+                .getRequestedAudioPolicyAsSink(any(BluetoothDevice.class));
         // Mock system interface
         doNothing().when(mSystemInterface).stop();
         when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState);
@@ -1012,19 +1012,21 @@
                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED);
 
         when(mStateMachines.get(mCurrentDevice).getHfpCallAudioPolicy()).thenReturn(
-                new BluetoothAudioPolicy.Builder()
-                        .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                        .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                        .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+                new BluetoothSinkAudioPolicy.Builder()
+                        .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                        .setActiveDevicePolicyAfterConnection(
+                                BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                        .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
                         .build()
         );
         Assert.assertEquals(true, mHeadsetService.isInbandRingingEnabled());
 
         when(mStateMachines.get(mCurrentDevice).getHfpCallAudioPolicy()).thenReturn(
-                new BluetoothAudioPolicy.Builder()
-                        .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                        .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                        .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_NOT_ALLOWED)
+                new BluetoothSinkAudioPolicy.Builder()
+                        .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                        .setActiveDevicePolicyAfterConnection(
+                                BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                        .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED)
                         .build()
         );
         Assert.assertEquals(false, mHeadsetService.isInbandRingingEnabled());
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
index bc335a5..be9df4b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientServiceTest.java
@@ -27,7 +27,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothManager;
 import android.content.Context;
 import android.content.Intent;
@@ -159,9 +159,9 @@
                 BluetoothAdapter.getDefaultAdapter().getRemoteDevice("00:01:02:03:04:05");
         mService.getStateMachineMap().put(device, mStateMachine);
 
-        mService.setAudioPolicy(device, new BluetoothAudioPolicy.Builder().build());
+        mService.setAudioPolicy(device, new BluetoothSinkAudioPolicy.Builder().build());
 
         verify(mStateMachine, timeout(STANDARD_WAIT_MILLIS).times(1))
-                .setAudioPolicy(any(BluetoothAudioPolicy.class));
+                .setAudioPolicy(any(BluetoothSinkAudioPolicy.class));
     }
 }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
index f64cda7..dc8683d 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
@@ -1,5 +1,26 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.bluetooth.hfpclient;
 
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
+import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
+import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING;
+
 import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.AT_OK;
 import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.ENTER_PRIVATE_MODE;
 import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER;
@@ -13,7 +34,7 @@
 import android.bluetooth.BluetoothAssignedNumbers;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadsetClient;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.content.Intent;
@@ -21,6 +42,7 @@
 import android.media.AudioManager;
 import android.os.Bundle;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.Message;
 import android.util.Pair;
 
@@ -36,6 +58,8 @@
 import com.android.bluetooth.TestUtils;
 import com.android.bluetooth.Utils;
 import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.hfp.HeadsetService;
+import com.android.bluetooth.hfp.HeadsetStackEvent;
 
 import org.hamcrest.core.AllOf;
 import org.hamcrest.core.IsInstanceOf;
@@ -47,18 +71,22 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.hamcrest.MockitoHamcrest;
 
 import java.util.List;
 import java.util.Set;
 
+/**
+ * Test cases for {@link HeadsetClientStateMachine}.
+ */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class HeadsetClientStateMachineTest {
     private BluetoothAdapter mAdapter;
     private HandlerThread mHandlerThread;
-    private HeadsetClientStateMachine mHeadsetClientStateMachine;
+    private TestHeadsetClientStateMachine mHeadsetClientStateMachine;
     private BluetoothDevice mTestDevice;
     private Context mTargetContext;
 
@@ -67,6 +95,8 @@
     @Mock
     private Resources mMockHfpResources;
     @Mock
+    private HeadsetService mHeadsetService;
+    @Mock
     private HeadsetClientService mHeadsetClientService;
     @Mock
     private AudioManager mAudioManager;
@@ -77,6 +107,7 @@
     private static final int QUERY_CURRENT_CALLS_WAIT_MILLIS = 2000;
     private static final int QUERY_CURRENT_CALLS_TEST_WAIT_MILLIS = QUERY_CURRENT_CALLS_WAIT_MILLIS
             * 3 / 2;
+    private static final int TIMEOUT_MS = 1000;
 
     @Before
     public void setUp() throws Exception {
@@ -109,9 +140,8 @@
         mHandlerThread = new HandlerThread("HeadsetClientStateMachineTestHandlerThread");
         mHandlerThread.start();
         // Manage looper execution in main test thread explicitly to guarantee timing consistency
-        mHeadsetClientStateMachine =
-                new HeadsetClientStateMachine(mHeadsetClientService, mHandlerThread.getLooper(),
-                                              mNativeInterface);
+        mHeadsetClientStateMachine = new TestHeadsetClientStateMachine(mHeadsetClientService,
+                mHeadsetService, mHandlerThread.getLooper(), mNativeInterface);
         mHeadsetClientStateMachine.start();
         TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
     }
@@ -122,9 +152,12 @@
             return;
         }
         TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
-        TestUtils.clearAdapterService(mAdapterService);
+        mHeadsetClientStateMachine.allowConnect = null;
         mHeadsetClientStateMachine.doQuit();
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
         mHandlerThread.quit();
+        TestUtils.clearAdapterService(mAdapterService);
+        verifyNoMoreInteractions(mHeadsetService);
     }
 
     /**
@@ -217,6 +250,7 @@
         // Check we are in connecting state now.
         Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
                 IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
     }
 
     /**
@@ -259,6 +293,7 @@
         // Check we are in connecting state now.
         Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
                 IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class));
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
     }
 
     /**
@@ -310,6 +345,8 @@
         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
                 intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
 
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
+
         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_IN_BAND_RINGTONE);
         event.valueInt = 0;
         event.device = mTestDevice;
@@ -427,6 +464,7 @@
                 intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
         Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
                 IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
 
         startBroadcastIndex++;
         return startBroadcastIndex;
@@ -1047,7 +1085,7 @@
         expectedBroadcastIndex = setUpHfpClientConnection(expectedBroadcastIndex);
         expectedBroadcastIndex = setUpServiceLevelConnection(expectedBroadcastIndex);
 
-        BluetoothAudioPolicy dummyAudioPolicy = new BluetoothAudioPolicy.Builder().build();
+        BluetoothSinkAudioPolicy dummyAudioPolicy = new BluetoothSinkAudioPolicy.Builder().build();
         mHeadsetClientStateMachine.setAudioPolicy(dummyAudioPolicy);
         verify(mNativeInterface, never()).sendAndroidAt(mTestDevice, "+ANDROID:1,0,0,0");
     }
@@ -1064,13 +1102,330 @@
         expectedBroadcastIndex = setUpHfpClientConnection(expectedBroadcastIndex);
         expectedBroadcastIndex = setUpServiceLevelConnection(expectedBroadcastIndex, true);
 
-        BluetoothAudioPolicy dummyAudioPolicy = new BluetoothAudioPolicy.Builder()
-                .setCallEstablishPolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
-                .setConnectingTimePolicy(BluetoothAudioPolicy.POLICY_NOT_ALLOWED)
-                .setInBandRingtonePolicy(BluetoothAudioPolicy.POLICY_ALLOWED)
+        BluetoothSinkAudioPolicy dummyAudioPolicy = new BluetoothSinkAudioPolicy.Builder()
+                .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
+                .setActiveDevicePolicyAfterConnection(BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED)
+                .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED)
                 .build();
 
         mHeadsetClientStateMachine.setAudioPolicy(dummyAudioPolicy);
         verify(mNativeInterface).sendAndroidAt(mTestDevice, "+ANDROID=1,1,2,1");
     }
+
+    @Test
+    public void testDumpDoesNotCrash() {
+        mHeadsetClientStateMachine.dump(new StringBuilder());
+    }
+
+    @Test
+    public void testProcessDisconnectMessage_onDisconnectedState() {
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertEquals(STATE_DISCONNECTED,
+                mHeadsetClientStateMachine.getConnectionState(mTestDevice));
+    }
+
+    @Test
+    public void testProcessConnectMessage_onDisconnectedState() {
+        doReturn(true).when(mNativeInterface).connect(any(BluetoothDevice.class));
+        sendMessageAndVerifyTransition(
+                mHeadsetClientStateMachine
+                        .obtainMessage(HeadsetClientStateMachine.CONNECT, mTestDevice),
+                HeadsetClientStateMachine.Connecting.class);
+    }
+
+    @Test
+    public void testStackEvent_toConnectingState_onDisconnectedState() {
+        allowConnection(true);
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+        event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
+        event.device = mTestDevice;
+        sendMessageAndVerifyTransition(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event),
+                HeadsetClientStateMachine.Connecting.class);
+    }
+
+    @Test
+    public void testStackEvent_toConnectingState_disallowConnection_onDisconnectedState() {
+        allowConnection(false);
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+        event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
+        event.device = mTestDevice;
+        sendMessageAndVerifyTransition(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event),
+                HeadsetClientStateMachine.Disconnected.class);
+    }
+
+    @Test
+    public void testProcessConnectMessage_onConnectingState() {
+        initToConnectingState();
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertTrue(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+                HeadsetClientStateMachine.CONNECT));
+    }
+
+    @Test
+    public void testProcessStackEvent_ConnectionStateChanged_Disconnected_onConnectingState() {
+        initToConnectingState();
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+        event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED;
+        event.device = mTestDevice;
+        sendMessageAndVerifyTransition(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event),
+                HeadsetClientStateMachine.Disconnected.class);
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+    }
+
+    @Test
+    public void testProcessStackEvent_ConnectionStateChanged_Connected_onConnectingState() {
+        initToConnectingState();
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+        event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+    }
+
+    @Test
+    public void testProcessStackEvent_ConnectionStateChanged_Connecting_onConnectingState() {
+        initToConnectingState();
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+        event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTING;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+    }
+
+    @Test
+    public void testProcessStackEvent_Call_onConnectingState() {
+        initToConnectingState();
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALL);
+        event.valueInt = StackEvent.EVENT_TYPE_CALL;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertTrue(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+                StackEvent.STACK_EVENT));
+    }
+
+    @Test
+    public void testProcessStackEvent_CmdResultWithEmptyQueuedActions_onConnectingState() {
+        initToConnectingState();
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
+        event.valueInt = StackEvent.CMD_RESULT_TYPE_OK;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+    }
+
+    @Test
+    public void testProcessStackEvent_Unknown_onConnectingState() {
+        String atCommand = "+ANDROID: 1";
+
+        initToConnectingState();
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
+        event.valueString = atCommand;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
+    }
+
+    @Test
+    public void testProcessConnectTimeoutMessage_onConnectingState() {
+        initToConnectingState();
+        Message msg = mHeadsetClientStateMachine
+                .obtainMessage(HeadsetClientStateMachine.CONNECTING_TIMEOUT);
+        sendMessageAndVerifyTransition(msg, HeadsetClientStateMachine.Disconnected.class);
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+    }
+
+    @Test
+    public void testProcessConnectMessage_onConnectedState() {
+        initToConnectedState();
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+    }
+
+    @Test
+    public void testProcessDisconnectMessage_onConnectedState() {
+        initToConnectedState();
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        verify(mNativeInterface).disconnect(any(BluetoothDevice.class));
+    }
+
+    @Test
+    public void testProcessConnectAudioMessage_onConnectedState() {
+        initToConnectedState();
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        verify(mNativeInterface).connectAudio(any(BluetoothDevice.class));
+    }
+
+    @Test
+    public void testProcessDisconnectAudioMessage_onConnectedState() {
+        initToConnectedState();
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        verify(mNativeInterface).disconnectAudio(any(BluetoothDevice.class));
+    }
+
+    @Test
+    public void testProcessVoiceRecognitionStartMessage_onConnectedState() {
+        initToConnectedState();
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_START);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        verify(mNativeInterface).startVoiceRecognition(any(BluetoothDevice.class));
+    }
+
+    @Test
+    public void testProcessDisconnectMessage_onAudioOnState() {
+        initToAudioOnState();
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertTrue(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+                HeadsetClientStateMachine.DISCONNECT));
+    }
+
+    @Test
+    public void testProcessDisconnectAudioMessage_onAudioOnState() {
+        initToAudioOnState();
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO,
+                mTestDevice);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        verify(mNativeInterface).disconnectAudio(any(BluetoothDevice.class));
+    }
+
+    @Test
+    public void testProcessHoldCall_onAudioOnState() {
+        initToAudioOnState();
+        HfpClientCall call = new HfpClientCall(mTestDevice, 0, HfpClientCall.CALL_STATE_ACTIVE,
+                "1", true, false, false);
+        mHeadsetClientStateMachine.mCalls.put(0, call);
+        int[] states = new int[1];
+        states[0] = HfpClientCall.CALL_STATE_ACTIVE;
+        mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.HOLD_CALL,
+                mTestDevice);
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        verify(mNativeInterface).handleCallAction(any(BluetoothDevice.class), anyInt(), eq(0));
+    }
+
+    @Test
+    public void testProcessStackEvent_ConnectionStateChanged_onAudioOnState() {
+        initToAudioOnState();
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+        event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class));
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+    }
+
+    @Test
+    public void testProcessStackEvent_AudioStateChanged_onAudioOnState() {
+        initToAudioOnState();
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
+        event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+    }
+
+    /**
+     * Allow/disallow connection to any device
+     *
+     * @param allow if true, connection is allowed
+     */
+    private void allowConnection(boolean allow) {
+        mHeadsetClientStateMachine.allowConnect = allow;
+    }
+
+    private void initToConnectingState() {
+        doReturn(true).when(mNativeInterface).connect(any(BluetoothDevice.class));
+        sendMessageAndVerifyTransition(
+                mHeadsetClientStateMachine
+                        .obtainMessage(HeadsetClientStateMachine.CONNECT, mTestDevice),
+                HeadsetClientStateMachine.Connecting.class);
+    }
+
+    private void initToConnectedState() {
+        String atCommand = "+ANDROID: 1";
+        initToConnectingState();
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
+        event.valueString = atCommand;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+        verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
+    }
+
+    private void initToAudioOnState() {
+        mHeadsetClientStateMachine.setAudioRouteAllowed(true);
+        initToConnectedState();
+        StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
+        event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_CONNECTED;
+        event.device = mTestDevice;
+        mHeadsetClientStateMachine.sendMessage(
+                mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
+        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+    }
+
+    private <T> void sendMessageAndVerifyTransition(Message msg, Class<T> type) {
+        Mockito.clearInvocations(mHeadsetClientService);
+        mHeadsetClientStateMachine.sendMessage(msg);
+        // Verify that one connection state broadcast is executed
+        verify(mHeadsetClientService, timeout(TIMEOUT_MS)).sendBroadcastMultiplePermissions(
+                any(Intent.class), any(String[].class), any(BroadcastOptions.class)
+        );
+        Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(),
+                IsInstanceOf.instanceOf(type));
+    }
+
+    public static class TestHeadsetClientStateMachine extends HeadsetClientStateMachine {
+
+        Boolean allowConnect = null;
+
+        TestHeadsetClientStateMachine(HeadsetClientService context, HeadsetService headsetService,
+                Looper looper, NativeInterface nativeInterface) {
+            super(context, headsetService, looper, nativeInterface);
+        }
+
+        public boolean doesSuperHaveDeferredMessages(int what) {
+            return super.hasDeferredMessages(what);
+        }
+
+        @Override
+        public boolean okToConnect(BluetoothDevice device) {
+            return allowConnect != null ? allowConnect : super.okToConnect(device);
+        }
+    }
 }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
index d2c7cd1..d1d1727 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
@@ -643,6 +643,9 @@
         doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
         doReturn(true).when(mNativeInterface).disconnectLeAudio(any(BluetoothDevice.class));
 
+        // Create device descriptor with connect request
+        assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();
+
         // Le Audio stack event: CONNECTION_STATE_CONNECTING - state machine should be created
         generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING,
                 BluetoothProfile.STATE_DISCONNECTED);
@@ -710,6 +713,9 @@
         doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
         doReturn(true).when(mNativeInterface).disconnectLeAudio(any(BluetoothDevice.class));
 
+        // Create device descriptor with connect request
+        assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();
+
         // LeAudio stack event: CONNECTION_STATE_CONNECTING - state machine should be created
         generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING,
                 BluetoothProfile.STATE_DISCONNECTED);
@@ -777,6 +783,9 @@
         doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
         doReturn(true).when(mNativeInterface).disconnectLeAudio(any(BluetoothDevice.class));
 
+        // Create device descriptor with connect request
+        assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();
+
         // LeAudio stack event: CONNECTION_STATE_CONNECTING - state machine should be created
         generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING,
                 BluetoothProfile.STATE_DISCONNECTED);
@@ -1514,6 +1523,9 @@
 
     @Test
     public void testGetAudioLocation() {
+        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
+        connectTestDevice(mSingleDevice, testGroupId);
+
         assertThat(mService.getAudioLocation(null))
                 .isEqualTo(BluetoothLeAudio.AUDIO_LOCATION_INVALID);
 
@@ -1619,6 +1631,10 @@
     public void testAuthorizeMcpServiceOnBluetoothEnableAndNodeRemoval() {
         int groupId = 1;
 
+        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
+        connectTestDevice(mLeftDevice, groupId);
+        connectTestDevice(mRightDevice, groupId);
+
         generateGroupNodeAdded(mLeftDevice, groupId);
         generateGroupNodeAdded(mRightDevice, groupId);
 
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
index 3249a42..7c80bff 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientTest.java
@@ -24,7 +24,6 @@
 import android.bluetooth.IBluetoothMapClient;
 import android.content.Context;
 import android.os.UserHandle;
-import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.MediumTest;
@@ -123,7 +122,6 @@
 
         // is the statemachine created
         Map<BluetoothDevice, MceStateMachine> map = mService.getInstanceMap();
-        Log.d("MapClientTest", "map=" + map);
 
         Assert.assertEquals(1, map.size());
         Assert.assertNotNull(map.get(device));
diff --git a/android/pandora/server/configs/PtsBotTestMts.xml b/android/pandora/server/configs/PtsBotTestMts.xml
index a5953e2..d301e42 100644
--- a/android/pandora/server/configs/PtsBotTestMts.xml
+++ b/android/pandora/server/configs/PtsBotTestMts.xml
@@ -14,6 +14,7 @@
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.PythonVirtualenvPreparer">
+        <!-- TODO(b/267785204): Import python dependencies -->
         <option name="dep-module" value="grpcio" />
         <option name="dep-module" value="protobuf==3.20.1" />
         <option name="dep-module" value="scipy" />
@@ -23,8 +24,8 @@
         <!-- Creates a randomized temp dir for pts-bot binaries and avoid
              conflicts when running multiple pts-bot on the same machine -->
         <option name="create-bin-temp-dir" value="true"/>
-        <!-- mmi2grpc is contained inside testcases folder -->
-        <option name="mmi2grpc" value="testcases" />
+        <!-- mmi2grpc is contained inside pts-bot-mts folder -->
+        <option name="mmi2grpc" value="pts-bot-mts" />
         <option name="tests-config-file" value="pts_bot_tests_config.json" />
         <option name="max-flaky-tests" value="3" />
         <option name="max-retries-per-test" value="3" />
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java
index 5646efb..58895ef 100644
--- a/framework/java/android/bluetooth/BluetoothDevice.java
+++ b/framework/java/android/bluetooth/BluetoothDevice.java
@@ -3248,14 +3248,14 @@
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(
-        prefix = { "REMOTE_STATUS_" },
+        prefix = { "FEATURE_" },
         value = {
             /** Remote support status of audio policy feature is unknown/unconfigured **/
-            BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE,
+            BluetoothStatusCodes.FEATURE_NOT_CONFIGURED,
             /** Remote support status of audio policy feature is supported **/
-            BluetoothAudioPolicy.FEATURE_SUPPORTED_BY_REMOTE,
+            BluetoothStatusCodes.FEATURE_SUPPORTED,
             /** Remote support status of audio policy feature is not supported **/
-            BluetoothAudioPolicy.FEATURE_NOT_SUPPORTED_BY_REMOTE,
+            BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
         }
     )
 
@@ -3269,24 +3269,29 @@
             BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
             BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED,
             BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
-            BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
             BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED,
     })
     public @interface AudioPolicyReturnValues{}
 
     /**
-     * Returns whether the audio policy feature is supported by the remote.
-     * This requires a vendor specific command, so the API returns
-     * {@link BluetoothAudioPolicy#FEATURE_UNCONFIGURED_BY_REMOTE} to indicate the remote
+     * Returns whether the audio policy feature is supported by
+     * both the local and the remote device.
+     * This is configured during initiating the connection between the devices through
+     * one of the transport protocols (e.g. HFP Vendor specific protocol). So if the API
+     * is invoked before this initial configuration is completed, it returns
+     * {@link BluetoothStatusCodes#FEATURE_NOT_CONFIGURED} to indicate the remote
      * device has not yet relayed this information. After the internal configuration,
      * the support status will be set to either
-     * {@link BluetoothAudioPolicy#FEATURE_NOT_SUPPORTED_BY_REMOTE} or
-     * {@link BluetoothAudioPolicy#FEATURE_SUPPORTED_BY_REMOTE}.
+     * {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} or
+     * {@link BluetoothStatusCodes#FEATURE_SUPPORTED}.
      * The rest of the APIs related to this feature in both {@link BluetoothDevice}
-     * and {@link BluetoothAudioPolicy} should be invoked  only after getting a
-     * {@link BluetoothAudioPolicy#FEATURE_SUPPORTED_BY_REMOTE} response from this API.
+     * and {@link BluetoothSinkAudioPolicy} should be invoked  only after getting a
+     * {@link BluetoothStatusCodes#FEATURE_SUPPORTED} response from this API.
+     * <p>Note that this API is intended to be used by a client device to send these requests
+     * to the server represented by this BluetoothDevice object.
      *
-     * @return if call audio policy feature is supported or not
+     * @return if call audio policy feature is supported by both local and remote
+     * device or not
      *
      * @hide
      */
@@ -3295,17 +3300,17 @@
             android.Manifest.permission.BLUETOOTH_CONNECT,
             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
     })
-    public @AudioPolicyRemoteSupport int getAudioPolicyRemoteSupported() {
-        if (DBG) log("getAudioPolicyRemoteSupported()");
+    public @AudioPolicyRemoteSupport int isRequestAudioPolicyAsSinkSupported() {
+        if (DBG) log("isRequestAudioPolicyAsSinkSupported()");
         final IBluetooth service = getService();
-        final int defaultValue = BluetoothAudioPolicy.FEATURE_UNCONFIGURED_BY_REMOTE;
+        final int defaultValue = BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
         if (service == null || !isBluetoothEnabled()) {
             Log.e(TAG, "BT not enabled. Cannot retrieve audio policy support status.");
             if (DBG) log(Log.getStackTraceString(new Throwable()));
         } else {
             try {
                 final SynchronousResultReceiver<Integer> recv = SynchronousResultReceiver.get();
-                service.getAudioPolicyRemoteSupported(this, mAttributionSource, recv);
+                service.isRequestAudioPolicyAsSinkSupported(this, mAttributionSource, recv);
                 return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
@@ -3319,9 +3324,15 @@
 
     /**
      * Sets call audio preferences and sends them to the remote device.
+     * <p>Note that the caller should check if the feature is supported by
+     * invoking {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported} first.
+     * <p>This API will throw an exception if the feature is not supported but still
+     * invoked.
+     * <p>Note that this API is intended to be used by a client device to send these requests
+     * to the server represented by this BluetoothDevice object.
      *
      * @param policies call audio policy preferences
-     * @return whether audio policy was set successfully or not
+     * @return whether audio policy was requested successfully or not
      *
      * @hide
      */
@@ -3330,8 +3341,9 @@
             android.Manifest.permission.BLUETOOTH_CONNECT,
             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
     })
-    public @AudioPolicyReturnValues int setAudioPolicy(@NonNull BluetoothAudioPolicy policies) {
-        if (DBG) log("setAudioPolicy");
+    public @AudioPolicyReturnValues int requestAudioPolicyAsSink(
+            @NonNull BluetoothSinkAudioPolicy policies) {
+        if (DBG) log("requestAudioPolicyAsSink");
         final IBluetooth service = getService();
         final int defaultValue = BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
         if (service == null || !isBluetoothEnabled()) {
@@ -3340,7 +3352,7 @@
         } else {
             try {
                 final SynchronousResultReceiver<Integer> recv = SynchronousResultReceiver.get();
-                service.setAudioPolicy(this, policies, mAttributionSource, recv);
+                service.requestAudioPolicyAsSink(this, policies, mAttributionSource, recv);
                 return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
@@ -3352,14 +3364,18 @@
     /**
      * Gets the call audio preferences for the remote device.
      * <p>Note that the caller should check if the feature is supported by
-     * invoking {@link BluetoothDevice#getAudioPolicyRemoteSupported} first.
+     * invoking {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported} first.
+     * <p>This API will throw an exception if the feature is not supported but still
+     * invoked.
      * <p>This API will return null if
      * 1. The bleutooth service is not started yet,
      * 2. It is invoked for a device which is not bonded, or
      * 3. The used transport, for example, HFP Client profile is not enabled or
      * connected yet.
+     * <p>Note that this API is intended to be used by a client device to send these requests
+     * to the server represented by this BluetoothDevice object.
      *
-     * @return call audio policy as {@link BluetoothAudioPolicy} object
+     * @return call audio policy as {@link BluetoothSinkAudioPolicy} object
      *
      * @hide
      */
@@ -3368,17 +3384,17 @@
             android.Manifest.permission.BLUETOOTH_CONNECT,
             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
     })
-    public @Nullable BluetoothAudioPolicy getAudioPolicy() {
-        if (DBG) log("getAudioPolicy");
+    public @Nullable BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink() {
+        if (DBG) log("getRequestedAudioPolicyAsSink");
         final IBluetooth service = getService();
         if (service == null || !isBluetoothEnabled()) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot get Audio Policy.");
             if (DBG) log(Log.getStackTraceString(new Throwable()));
         } else {
             try {
-                final SynchronousResultReceiver<BluetoothAudioPolicy>
+                final SynchronousResultReceiver<BluetoothSinkAudioPolicy>
                         recv = SynchronousResultReceiver.get();
-                service.getAudioPolicy(this, mAttributionSource, recv);
+                service.getRequestedAudioPolicyAsSink(this, mAttributionSource, recv);
                 return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
             } catch (RemoteException | TimeoutException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
diff --git a/framework/java/android/bluetooth/BluetoothServerSocket.java b/framework/java/android/bluetooth/BluetoothServerSocket.java
index bb4e354..5a23f7e3 100644
--- a/framework/java/android/bluetooth/BluetoothServerSocket.java
+++ b/framework/java/android/bluetooth/BluetoothServerSocket.java
@@ -75,7 +75,7 @@
 public final class BluetoothServerSocket implements Closeable {
 
     private static final String TAG = "BluetoothServerSocket";
-    private static final boolean DBG = false;
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     @UnsupportedAppUsage(publicAlternatives = "Use public {@link BluetoothServerSocket} API "
             + "instead.")
     /*package*/ final BluetoothSocket mSocket;
diff --git a/framework/java/android/bluetooth/BluetoothAudioPolicy.java b/framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java
similarity index 70%
rename from framework/java/android/bluetooth/BluetoothAudioPolicy.java
rename to framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java
index 873abcd..8641e51 100644
--- a/framework/java/android/bluetooth/BluetoothAudioPolicy.java
+++ b/framework/java/android/bluetooth/BluetoothSinkAudioPolicy.java
@@ -33,29 +33,29 @@
  * devices shall send objects of this class to send its preference to the AG/CG
  * devices.
  *
- * <p>HF/CT side applications on can use {@link BluetoothDevice#setAudioPolicy}
- * API to set and send a {@link BluetoothAudioPolicy} object containing the
+ * <p>HF/CT side applications on can use {@link BluetoothDevice#requestAudioPolicyAsSink}
+ * API to set and send a {@link BluetoothSinkAudioPolicy} object containing the
  * preference/policy values. This object will be stored in the memory of HF/CT
  * side, will be send to the AG/CG side using Android Specific AT Commands and will
  * be stored in the AG side memory and database.
  *
- * <p>HF/CT side API {@link BluetoothDevice#getAudioPolicy} can be used to retrieve
+ * <p>HF/CT side API {@link BluetoothDevice#getRequestedAudioPolicyAsSink} can be used to retrieve
  * the stored audio policies currently.
  *
  * <p>Note that the setter APIs of this class will only set the values of the
- * object. To actually set the policies, API {@link BluetoothDevice#setAudioPolicy}
- * must need to be invoked with the {@link BluetoothAudioPolicy} object.
+ * object. To actually set the policies, API {@link BluetoothDevice#requestAudioPolicyAsSink}
+ * must need to be invoked with the {@link BluetoothSinkAudioPolicy} object.
  *
  * <p>Note that any API related to this feature should be used after configuring
  * the support of the AG device and after checking whether the AG device supports
- * this feature or not by invoking {@link BluetoothDevice#getAudioPolicyRemoteSupported}.
- * Only after getting a {@link BluetoothAudioPolicy#FEATURE_SUPPORTED_BY_REMOTE} response
+ * this feature or not by invoking {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported}.
+ * Only after getting a {@link BluetoothStatusCodes#FEATURE_SUPPORTED} response
  * from the API should the APIs related to this feature be used.
  *
  *
  * @hide
  */
-public final class BluetoothAudioPolicy implements Parcelable {
+public final class BluetoothSinkAudioPolicy implements Parcelable {
 
     /**
      * @hide
@@ -102,28 +102,6 @@
      */
     public static final int POLICY_NOT_ALLOWED = 2;
 
-    /**
-     * Remote support status of audio policy feature is unknown/unconfigured.
-     *
-     * @hide
-     */
-    public static final int FEATURE_UNCONFIGURED_BY_REMOTE = 0;
-
-    /**
-     * Remote support status of audio policy feature is supported.
-     *
-     * @hide
-     */
-    public static final int FEATURE_SUPPORTED_BY_REMOTE = 1;
-
-    /**
-     * Remote support status of audio policy feature is not supported.
-     *
-     * @hide
-     */
-    public static final int FEATURE_NOT_SUPPORTED_BY_REMOTE = 2;
-
-
     @AudioPolicyValues private final int mCallEstablishPolicy;
     @AudioPolicyValues private final int mConnectingTimePolicy;
     @AudioPolicyValues private final int mInBandRingtonePolicy;
@@ -131,7 +109,7 @@
     /**
      * @hide
      */
-    public BluetoothAudioPolicy(int callEstablishPolicy,
+    public BluetoothSinkAudioPolicy(int callEstablishPolicy,
             int connectingTimePolicy, int inBandRingtonePolicy) {
         mCallEstablishPolicy = callEstablishPolicy;
         mConnectingTimePolicy = connectingTimePolicy;
@@ -139,10 +117,14 @@
     }
 
     /**
-     * Get Call pick up audio policy.
+     * Get Call establishment policy audio policy.
+     * <p>This policy is used to determine the audio preference when the
+     * HF device makes or answers a call. That is, if this device
+     * makes or answers a call, is the audio preferred by HF.
      *
      * @return the call pick up audio policy value
      *
+     * @hide
      */
     public @AudioPolicyValues int getCallEstablishPolicy() {
         return mCallEstablishPolicy;
@@ -150,19 +132,30 @@
 
     /**
      * Get during connection audio up policy.
+     * <p>This policy is used to determine the audio preference when the
+     * HF device connects with the AG device. That is, when the
+     * HF device gets connected, should the HF become active and get audio
+     * is decided by this policy. This also covers the case of during a call.
+     * If the HF connects with the AG during an ongoing call, should the call
+     * audio be routed to the HF will be decided by this policy.
      *
      * @return the during connection audio policy value
      *
+     * @hide
      */
-    public @AudioPolicyValues int getConnectingTimePolicy() {
+    public @AudioPolicyValues int getActiveDevicePolicyAfterConnection() {
         return mConnectingTimePolicy;
     }
 
     /**
      * Get In band ringtone audio up policy.
+     * <p>This policy is used to determine the audio preference of the
+     * in band ringtone. That is, if there is an incoming call, should the
+     * inband ringtone audio be routed to the HF will be decided by this policy.
      *
      * @return the in band ringtone audio policy value
      *
+     * @hide
      */
     public @AudioPolicyValues int getInBandRingtonePolicy() {
         return mInBandRingtonePolicy;
@@ -170,7 +163,7 @@
 
     @Override
     public String toString() {
-        StringBuilder builder = new StringBuilder("BluetoothAudioPolicy{");
+        StringBuilder builder = new StringBuilder("BluetoothSinkAudioPolicy{");
         builder.append("mCallEstablishPolicy: ");
         builder.append(mCallEstablishPolicy);
         builder.append(", mConnectingTimePolicy: ");
@@ -184,17 +177,17 @@
     /**
      * {@link Parcelable.Creator} interface implementation.
      */
-    public static final @android.annotation.NonNull Parcelable.Creator<BluetoothAudioPolicy>
-            CREATOR = new Parcelable.Creator<BluetoothAudioPolicy>() {
+    public static final @android.annotation.NonNull Parcelable.Creator<BluetoothSinkAudioPolicy>
+            CREATOR = new Parcelable.Creator<BluetoothSinkAudioPolicy>() {
                 @Override
-                public BluetoothAudioPolicy createFromParcel(@NonNull Parcel in) {
-                    return new BluetoothAudioPolicy(
+                public BluetoothSinkAudioPolicy createFromParcel(@NonNull Parcel in) {
+                    return new BluetoothSinkAudioPolicy(
                             in.readInt(), in.readInt(), in.readInt());
                 }
 
                 @Override
-                public BluetoothAudioPolicy[] newArray(int size) {
-                    return new BluetoothAudioPolicy[size];
+                public BluetoothSinkAudioPolicy[] newArray(int size) {
+                    return new BluetoothSinkAudioPolicy[size];
                 }
             };
 
@@ -215,8 +208,8 @@
 
     @Override
     public boolean equals(@Nullable Object o) {
-        if (o instanceof BluetoothAudioPolicy) {
-            BluetoothAudioPolicy other = (BluetoothAudioPolicy) o;
+        if (o instanceof BluetoothSinkAudioPolicy) {
+            BluetoothSinkAudioPolicy other = (BluetoothSinkAudioPolicy) o;
             return (other.mCallEstablishPolicy == mCallEstablishPolicy
                     && other.mConnectingTimePolicy == mConnectingTimePolicy
                     && other.mInBandRingtonePolicy == mInBandRingtonePolicy);
@@ -236,9 +229,9 @@
     }
 
     /**
-     * Builder for {@link BluetoothAudioPolicy}.
+     * Builder for {@link BluetoothSinkAudioPolicy}.
      * <p> By default, the audio policy values will be set to
-     * {@link BluetoothAudioPolicy#POLICY_UNCONFIGURED}.
+     * {@link BluetoothSinkAudioPolicy#POLICY_UNCONFIGURED}.
      */
     public static final class Builder {
         private int mCallEstablishPolicy = POLICY_UNCONFIGURED;
@@ -249,7 +242,7 @@
 
         }
 
-        public Builder(@NonNull BluetoothAudioPolicy policies) {
+        public Builder(@NonNull BluetoothSinkAudioPolicy policies) {
             mCallEstablishPolicy = policies.mCallEstablishPolicy;
             mConnectingTimePolicy = policies.mConnectingTimePolicy;
             mInBandRingtonePolicy = policies.mInBandRingtonePolicy;
@@ -259,10 +252,15 @@
          * Set Call Establish (pick up and answer) policy.
          * <p>This policy is used to determine the audio preference when the
          * HF device makes or answers a call. That is, if this device
-         * makes or answers a call, is the audio preferred by HF should be decided
-         * by this policy.
+         * makes or answers a call, is the audio preferred by HF.
+         * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, answering or making
+         * a call from the HF device will route the call audio to it.
+         * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, answering or making
+         * a call from the HF device will NOT route the call audio to it.
          *
          * @return reference to the current object
+         *
+         * @hide
          */
         public @NonNull Builder setCallEstablishPolicy(
                 @AudioPolicyValues int callEstablishPolicy) {
@@ -278,10 +276,16 @@
          * is decided by this policy. This also covers the case of during a call.
          * If the HF connects with the AG during an ongoing call, should the call
          * audio be routed to the HF will be decided by this policy.
+         * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, connecting HF
+         * during a call will route the call audio to it.
+         * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, connecting HF
+         * during a call will NOT route the call audio to it.
          *
          * @return reference to the current object
+         *
+         * @hide
          */
-        public @NonNull Builder setConnectingTimePolicy(
+        public @NonNull Builder setActiveDevicePolicyAfterConnection(
                 @AudioPolicyValues int connectingTimePolicy) {
             mConnectingTimePolicy = connectingTimePolicy;
             return this;
@@ -292,9 +296,14 @@
          * <p>This policy is used to determine the audio preference of the
          * in band ringtone. That is, if there is an incoming call, should the
          * inband ringtone audio be routed to the HF will be decided by this policy.
+         * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, there will be
+         * in band ringtone in the HF device during an incoming call.
+         * If set to {@link BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, there will NOT
+         * be in band ringtone in the HF device during an incoming call.
          *
          * @return reference to the current object
          *
+         * @hide
          */
         public @NonNull Builder setInBandRingtonePolicy(
                 @AudioPolicyValues int inBandRingtonePolicy) {
@@ -303,11 +312,13 @@
         }
 
         /**
-         * Build {@link BluetoothAudioPolicy}.
-         * @return new BluetoothAudioPolicy object
+         * Build {@link BluetoothSinkAudioPolicy}.
+         * @return new BluetoothSinkAudioPolicy object
+         *
+         * @hide
          */
-        public @NonNull BluetoothAudioPolicy build() {
-            return new BluetoothAudioPolicy(
+        public @NonNull BluetoothSinkAudioPolicy build() {
+            return new BluetoothSinkAudioPolicy(
                     mCallEstablishPolicy, mConnectingTimePolicy, mInBandRingtonePolicy);
         }
     }
diff --git a/framework/java/android/bluetooth/BluetoothSocket.java b/framework/java/android/bluetooth/BluetoothSocket.java
index ef2f7b8..b57bfca 100644
--- a/framework/java/android/bluetooth/BluetoothSocket.java
+++ b/framework/java/android/bluetooth/BluetoothSocket.java
@@ -285,7 +285,7 @@
         BluetoothSocket as = new BluetoothSocket(this);
         as.mSocketState = SocketState.CONNECTED;
         FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
-        if (DBG) Log.d(TAG, "socket fd passed by stack fds: " + Arrays.toString(fds));
+        if (DBG) Log.d(TAG, "acceptSocket: socket fd passed by stack fds:" + Arrays.toString(fds));
         if (fds == null || fds.length != 1) {
             Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds));
             as.close();
@@ -450,6 +450,7 @@
                     throw new IOException("bt socket closed");
                 }
                 mSocketState = SocketState.CONNECTED;
+                if (DBG) Log.d(TAG, "connect(), socket connected");
             }
         } catch (RemoteException e) {
             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
@@ -536,8 +537,8 @@
         if (mSocketState != SocketState.LISTENING) {
             throw new IOException("bt socket is not in listen state");
         }
+        Log.d(TAG, "accept(), timeout (ms):" + timeout);
         if (timeout > 0) {
-            Log.d(TAG, "accept() set timeout (ms):" + timeout);
             mSocket.setSoTimeout(timeout);
         }
         String RemoteAddr = waitSocketSignal(mSocketIS);
diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java
index 35e03f5..24be7fc 100644
--- a/framework/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java
@@ -216,6 +216,12 @@
     public static final int ERROR_REMOTE_OPERATION_NOT_SUPPORTED = 27;
 
     /**
+     * Indicates that the feature status is not configured yet.
+     * @hide
+     */
+    public static final int FEATURE_NOT_CONFIGURED = 30;
+
+    /**
      * A GATT writeCharacteristic request is not permitted on the remote device.
      */
     public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200;
diff --git a/system/audio_hal_interface/aidl/client_interface_aidl.cc b/system/audio_hal_interface/aidl/client_interface_aidl.cc
index efdc469..9af2803 100644
--- a/system/audio_hal_interface/aidl/client_interface_aidl.cc
+++ b/system/audio_hal_interface/aidl/client_interface_aidl.cc
@@ -55,9 +55,8 @@
 }
 
 bool BluetoothAudioClientInterface::is_aidl_available() {
-  auto service = AServiceManager_checkService(
+  return AServiceManager_isDeclared(
       kDefaultAudioProviderFactoryInterface.c_str());
-  return (service != nullptr);
 }
 
 std::vector<AudioCapabilities>
@@ -72,7 +71,7 @@
     return capabilities;
   }
   auto provider_factory = IBluetoothAudioProviderFactory::fromBinder(
-      ::ndk::SpAIBinder(AServiceManager_getService(
+      ::ndk::SpAIBinder(AServiceManager_waitForService(
           kDefaultAudioProviderFactoryInterface.c_str())));
 
   if (provider_factory == nullptr) {
@@ -91,16 +90,15 @@
 }
 
 void BluetoothAudioClientInterface::FetchAudioProvider() {
-  if (provider_ != nullptr) {
-    LOG(WARNING) << __func__ << ": refetch";
-  } else if (!is_aidl_available()) {
-    // AIDL availability should only be checked at the beginning.
-    // When refetching, AIDL may not be ready *yet* but it's expected to be
-    // available later.
+  if (!is_aidl_available()) {
+    LOG(ERROR) << __func__ << ": aidl is not supported on this platform.";
     return;
   }
+  if (provider_ != nullptr) {
+    LOG(WARNING) << __func__ << ": refetch";
+  }
   auto provider_factory = IBluetoothAudioProviderFactory::fromBinder(
-      ::ndk::SpAIBinder(AServiceManager_getService(
+      ::ndk::SpAIBinder(AServiceManager_waitForService(
           kDefaultAudioProviderFactoryInterface.c_str())));
 
   if (provider_factory == nullptr) {
diff --git a/system/binder/android/bluetooth/BluetoothAudioPolicy.aidl b/system/binder/android/bluetooth/BluetoothSinkAudioPolicy.aidl
similarity index 94%
rename from system/binder/android/bluetooth/BluetoothAudioPolicy.aidl
rename to system/binder/android/bluetooth/BluetoothSinkAudioPolicy.aidl
index d06c286..740249c 100644
--- a/system/binder/android/bluetooth/BluetoothAudioPolicy.aidl
+++ b/system/binder/android/bluetooth/BluetoothSinkAudioPolicy.aidl
@@ -16,4 +16,4 @@
 
 package android.bluetooth;
 
-parcelable BluetoothAudioPolicy;
+parcelable BluetoothSinkAudioPolicy;
diff --git a/system/binder/android/bluetooth/IBluetooth.aidl b/system/binder/android/bluetooth/IBluetooth.aidl
index d55dbc1..360220c 100644
--- a/system/binder/android/bluetooth/IBluetooth.aidl
+++ b/system/binder/android/bluetooth/IBluetooth.aidl
@@ -25,7 +25,7 @@
 import android.bluetooth.IBluetoothSocketManager;
 import android.bluetooth.IBluetoothStateChangeCallback;
 import android.bluetooth.BluetoothActivityEnergyInfo;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.IncomingRfcommSocketInfo;
@@ -268,11 +268,11 @@
     oneway void allowLowLatencyAudio(in boolean allowed, in BluetoothDevice device, in SynchronousResultReceiver receiver);
 
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
-    void getAudioPolicyRemoteSupported(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+    void isRequestAudioPolicyAsSinkSupported(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
-    void setAudioPolicy(in BluetoothDevice device, in BluetoothAudioPolicy policies, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+    void requestAudioPolicyAsSink(in BluetoothDevice device, in BluetoothSinkAudioPolicy policies, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
-    void getAudioPolicy(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+    void getRequestedAudioPolicyAsSink(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
 
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
     oneway void startRfcommListener(String name, in ParcelUuid uuid, in PendingIntent intent, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
diff --git a/system/binder/android/bluetooth/IBluetoothHeadsetClient.aidl b/system/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
index d0adfdf..ad3316c 100644
--- a/system/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
+++ b/system/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -17,7 +17,7 @@
 package android.bluetooth;
 
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothAudioPolicy;
+import android.bluetooth.BluetoothSinkAudioPolicy;
 import android.bluetooth.BluetoothHeadsetClientCall;
 import android.content.AttributionSource;
 
diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc
index 48aa7b9..faa1bb1 100644
--- a/system/bta/gatt/bta_gattc_act.cc
+++ b/system/bta/gatt/bta_gattc_act.cc
@@ -34,6 +34,7 @@
 #include "bta/hh/bta_hh_int.h"
 #include "btif/include/btif_debug_conn.h"
 #include "device/include/controller.h"
+#include "device/include/interop.h"
 #include "main/shim/dumpsys.h"
 #include "osi/include/allocator.h"
 #include "osi/include/log.h"
@@ -802,6 +803,18 @@
         p_clcb->p_srcb->srvc_hdl_db_hash = false;
       }
 
+      // Some LMP 5.2 devices also don't support robust caching. This workaround
+      // conditionally disables the feature based on a combination of LMP
+      // version and OUI prefix.
+      if (lmp_version < 0x0c &&
+          interop_match_addr(INTEROP_DISABLE_ROBUST_CACHING, &p_clcb->bda)) {
+        LOG_WARN(
+            "Device LMP version 0x%02x <= Bluetooth 5.2 and MAC addr on "
+            "interop list, skipping robust caching",
+            lmp_version);
+        p_clcb->p_srcb->srvc_hdl_db_hash = false;
+      }
+
       /* read db hash if db hash characteristic exists */
       if (bta_gattc_is_robust_caching_enabled() &&
           p_clcb->p_srcb->srvc_hdl_db_hash &&
diff --git a/system/bta/gatt/bta_gatts_act.cc b/system/bta/gatt/bta_gatts_act.cc
index 7f2457e..800fbf0 100644
--- a/system/bta/gatt/bta_gatts_act.cc
+++ b/system/bta/gatt/bta_gatts_act.cc
@@ -120,6 +120,8 @@
 
     p_cb->enabled = true;
 
+    gatt_load_bonded();
+
     if (!GATTS_NVRegister(&bta_gatts_nv_cback)) {
       LOG(ERROR) << "BTA GATTS NV register failed.";
     }
diff --git a/system/bta/gatt/bta_gatts_api.cc b/system/bta/gatt/bta_gatts_api.cc
index d0e4f44..5c69ab4 100644
--- a/system/bta/gatt/bta_gatts_api.cc
+++ b/system/bta/gatt/bta_gatts_api.cc
@@ -374,3 +374,11 @@
 
   bta_sys_sendmsg(p_buf);
 }
+
+void BTA_GATTS_InitBonded(void) {
+  LOG(INFO) << __func__;
+
+  BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
+  p_buf->event = BTA_GATTS_API_INIT_BONDED_EVT;
+  bta_sys_sendmsg(p_buf);
+}
diff --git a/system/bta/gatt/bta_gatts_int.h b/system/bta/gatt/bta_gatts_int.h
index f989e09..7672130 100644
--- a/system/bta/gatt/bta_gatts_int.h
+++ b/system/bta/gatt/bta_gatts_int.h
@@ -51,7 +51,9 @@
   BTA_GATTS_API_OPEN_EVT,
   BTA_GATTS_API_CANCEL_OPEN_EVT,
   BTA_GATTS_API_CLOSE_EVT,
-  BTA_GATTS_API_DISABLE_EVT
+  BTA_GATTS_API_DISABLE_EVT,
+
+  BTA_GATTS_API_INIT_BONDED_EVT,
 };
 typedef uint16_t tBTA_GATTS_INT_EVT;
 
diff --git a/system/bta/gatt/bta_gatts_main.cc b/system/bta/gatt/bta_gatts_main.cc
index 97e9a3d..458f5e2 100644
--- a/system/bta/gatt/bta_gatts_main.cc
+++ b/system/bta/gatt/bta_gatts_main.cc
@@ -105,6 +105,10 @@
       break;
     }
 
+    case BTA_GATTS_API_INIT_BONDED_EVT:
+      gatt_load_bonded();
+      break;
+
     default:
       break;
   }
diff --git a/system/bta/hd/bta_hd_api.cc b/system/bta/hd/bta_hd_api.cc
index a0d4802..93a9155 100644
--- a/system/bta/hd/bta_hd_api.cc
+++ b/system/bta/hd/bta_hd_api.cc
@@ -79,7 +79,10 @@
 void BTA_HdDisable(void) {
   APPL_TRACE_API("%s", __func__);
 
-  bta_sys_deregister(BTA_ID_HD);
+  if (!bluetooth::common::init_flags::
+          delay_hidh_cleanup_until_hidh_ready_start_is_enabled()) {
+    bta_sys_deregister(BTA_ID_HD);
+  }
 
   BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
   p_buf->event = BTA_HD_API_DISABLE_EVT;
diff --git a/system/bta/hearing_aid/hearing_aid.cc b/system/bta/hearing_aid/hearing_aid.cc
index d79e33d..8637f89 100644
--- a/system/bta/hearing_aid/hearing_aid.cc
+++ b/system/bta/hearing_aid/hearing_aid.cc
@@ -182,7 +182,8 @@
     int read_rssi_start_interval_count = 0;
 
     for (auto& d : devices) {
-      VLOG(1) << __func__ << ": device=" << d.address << ", read_rssi_count=" << d.read_rssi_count;
+      LOG_DEBUG("device=%s, read_rssi_count=%d",
+                d.address.ToStringForLogging().c_str(), d.read_rssi_count);
 
       // Reset the count
       if (d.read_rssi_count <= 0) {
@@ -211,9 +212,8 @@
                                  uint16_t handle, uint16_t len,
                                  const uint8_t* value, void* data) {
   if (status != GATT_SUCCESS) {
-    LOG(ERROR) << __func__ << ": handle=" << handle << ", conn_id=" << conn_id
-               << ", status=" << loghex(static_cast<uint8_t>(status))
-               << ", length=" << len;
+    LOG_ERROR("handle= %hu, conn_id=%hu, status= %s, length=%u", handle,
+              conn_id, loghex(static_cast<uint8_t>(status)).c_str(), len);
   }
 }
 
@@ -222,7 +222,7 @@
 
 inline void encoder_state_init() {
   if (encoder_state_left != nullptr) {
-    LOG(WARNING) << __func__ << ": encoder already initialized";
+    LOG_WARN("encoder already initialized");
     return;
   }
   encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
@@ -261,19 +261,16 @@
         "persist.bluetooth.hearingaid.interval", (int32_t)HA_INTERVAL_20_MS);
     if ((default_data_interval_ms != HA_INTERVAL_10_MS) &&
         (default_data_interval_ms != HA_INTERVAL_20_MS)) {
-      LOG(ERROR) << __func__
-                 << ": invalid interval=" << default_data_interval_ms
-                 << "ms. Overwriting back to default";
+      LOG_ERROR("invalid interval= %ums. Overwrriting back to default",
+                default_data_interval_ms);
       default_data_interval_ms = HA_INTERVAL_20_MS;
     }
-    VLOG(2) << __func__
-            << ", default_data_interval_ms=" << default_data_interval_ms;
+    LOG_DEBUG("default_data_interval_ms=%u", default_data_interval_ms);
 
     overwrite_min_ce_len = (uint16_t)osi_property_get_int32(
         "persist.bluetooth.hearingaidmincelen", 0);
     if (overwrite_min_ce_len) {
-      LOG(INFO) << __func__
-                << ": Overwrites MIN_CE_LEN=" << overwrite_min_ce_len;
+      LOG_INFO("Overwrites MIN_CE_LEN=%u", overwrite_min_ce_len);
     }
 
     BTA_GATTC_AppRegister(
@@ -281,14 +278,15 @@
         base::Bind(
             [](Closure initCb, uint8_t client_id, uint8_t status) {
               if (status != GATT_SUCCESS) {
-                LOG(ERROR) << "Can't start Hearing Aid profile - no gatt "
-                              "clients left!";
+                LOG_ERROR(
+                    "Can't start Hearing Aid profile - no gatt clients left!");
                 return;
               }
               instance->gatt_if = client_id;
               initCb.Run();
             },
-            initCb), false);
+            initCb),
+        false);
   }
 
   uint16_t UpdateBleConnParams(const RawAddress& address) {
@@ -306,15 +304,15 @@
         connection_interval = CONNECTION_INTERVAL_20MS_PARAM;
         break;
       default:
-        LOG(ERROR) << __func__ << ":Error: invalid default_data_interval_ms="
-                   << default_data_interval_ms;
+        LOG_ERROR("invalid default_data_interval_ms=%u",
+                  default_data_interval_ms);
         min_ce_len = MIN_CE_LEN_10MS_CI;
         connection_interval = CONNECTION_INTERVAL_10MS_PARAM;
     }
 
     if (overwrite_min_ce_len != 0) {
-      VLOG(2) << __func__ << ": min_ce_len=" << min_ce_len
-              << " is overwritten to " << overwrite_min_ce_len;
+      LOG_DEBUG("min_ce_len=%u is overwritten to %u", min_ce_len,
+                overwrite_min_ce_len);
       min_ce_len = overwrite_min_ce_len;
     }
 
@@ -323,22 +321,22 @@
     return connection_interval;
   }
 
-  void Connect(const RawAddress& address) override {
-    DVLOG(2) << __func__ << " " << address;
+  void Connect(const RawAddress& address) {
+    LOG_DEBUG("%s", address.ToStringForLogging().c_str());
     hearingDevices.Add(HearingDevice(address, true));
     BTA_GATTC_Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, false);
   }
 
-  void AddToAcceptlist(const RawAddress& address) override {
-    VLOG(2) << __func__ << " address: " << address;
+  void AddToAcceptlist(const RawAddress& address) {
+    LOG_DEBUG("%s", address.ToStringForLogging().c_str());
     hearingDevices.Add(HearingDevice(address, true));
     BTA_GATTC_Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false);
   }
 
   void AddFromStorage(const HearingDevice& dev_info, uint16_t is_acceptlisted) {
-    DVLOG(2) << __func__ << " " << dev_info.address
-             << ", hiSyncId=" << loghex(dev_info.hi_sync_id)
-             << ", isAcceptlisted=" << is_acceptlisted;
+    LOG_DEBUG("%s, hiSyncId=%s, isAcceptlisted=%u",
+              dev_info.address.ToStringForLogging().c_str(),
+              loghex(dev_info.hi_sync_id).c_str(), is_acceptlisted);
     if (is_acceptlisted) {
       hearingDevices.Add(dev_info);
 
@@ -364,13 +362,14 @@
     if (!hearingDevice) {
       /* When Hearing Aid is quickly disabled and enabled in settings, this case
        * might happen */
-      LOG(WARNING) << "Closing connection to non hearing-aid device, address="
-                   << address;
+      LOG_WARN("Closing connection to non hearing-aid device, address=%s",
+               address.ToStringForLogging().c_str());
       BTA_GATTC_Close(conn_id);
       return;
     }
 
-    LOG(INFO) << __func__ << ": address=" << address << ", conn_id=" << conn_id;
+    LOG_INFO("address=%s, conn_id=%u", address.ToStringForLogging().c_str(),
+             conn_id);
 
     if (status != GATT_SUCCESS) {
       if (!hearingDevice->connecting_actively) {
@@ -378,7 +377,7 @@
         return;
       }
 
-      LOG(INFO) << "Failed to connect to Hearing Aid device";
+      LOG_INFO("Failed to connect to Hearing Aid device");
       hearingDevices.Remove(address);
       callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
       return;
@@ -404,7 +403,7 @@
     }
 
     if (controller_get_interface()->supports_ble_2m_phy()) {
-      LOG(INFO) << address << " set preferred 2M PHY";
+      LOG_INFO("%s set preferred 2M PHY", address.ToStringForLogging().c_str());
       BTM_BleSetPhy(address, PHY_LE_2M, PHY_LE_2M, 0);
     }
 
@@ -439,7 +438,7 @@
   void OnConnectionUpdateComplete(uint16_t conn_id, tBTA_GATTC* p_data) {
     HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
     if (!hearingDevice) {
-      DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+      LOG_DEBUG("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
       return;
     }
 
@@ -452,31 +451,29 @@
         switch (hearingDevice->connection_update_status) {
           case COMPLETED:
             if (!same_conn_interval) {
-              LOG(WARNING) << __func__
-                           << ": Unexpected change. Redo. connection interval="
-                           << p_data->conn_update.interval << ", expected="
-                           << hearingDevice->requested_connection_interval
-                           << ", conn_id=" << conn_id
-                           << ", connection_update_status="
-                           << hearingDevice->connection_update_status;
+              LOG_WARN(
+                  "Unexpected change. Redo. connection interval=%u, "
+                  "expected=%u, conn_id=%u, connection_update_status=%u",
+                  p_data->conn_update.interval,
+                  hearingDevice->requested_connection_interval, conn_id,
+                  hearingDevice->connection_update_status);
               // Redo this connection interval change.
               hearingDevice->connection_update_status = AWAITING;
             }
             break;
           case STARTED:
             if (same_conn_interval) {
-              LOG(INFO) << __func__
-                        << ": Connection update completed. conn_id=" << conn_id
-                        << ", device=" << hearingDevice->address;
+              LOG_INFO("Connection update completed. conn_id=%u, device=%s",
+                       conn_id,
+                       hearingDevice->address.ToStringForLogging().c_str());
               hearingDevice->connection_update_status = COMPLETED;
             } else {
-              LOG(WARNING) << __func__
-                           << ": Ignored. Different connection interval="
-                           << p_data->conn_update.interval << ", expected="
-                           << hearingDevice->requested_connection_interval
-                           << ", conn_id=" << conn_id
-                           << ", connection_update_status="
-                           << hearingDevice->connection_update_status;
+              LOG_WARN(
+                  "Ignored. Different connection interval=%u, expected=%u, "
+                  "conn_id=%u, connection_update_status=%u",
+                  p_data->conn_update.interval,
+                  hearingDevice->requested_connection_interval, conn_id,
+                  hearingDevice->connection_update_status);
               // Wait for the right Connection Update Completion.
               return;
             }
@@ -494,16 +491,15 @@
         send_state_change_to_other_side(hearingDevice, conn_update);
         send_state_change(hearingDevice, conn_update);
       } else {
-        LOG(INFO) << __func__ << ": error status="
-                  << loghex(static_cast<uint8_t>(p_data->conn_update.status))
-                  << ", conn_id=" << conn_id
-                  << ", device=" << hearingDevice->address
-                  << ", connection_update_status="
-                  << hearingDevice->connection_update_status;
-
+        LOG_INFO(
+            "error status=%s, conn_id=%u,device=%s, "
+            "connection_update_status=%u",
+            loghex(static_cast<uint8_t>(p_data->conn_update.status)).c_str(),
+            conn_id, hearingDevice->address.ToStringForLogging().c_str(),
+            hearingDevice->connection_update_status);
         if (hearingDevice->connection_update_status == STARTED) {
           // Redo this connection interval change.
-          LOG(ERROR) << __func__ << ": Redo Connection Interval change";
+          LOG_ERROR("Redo Connection Interval change");
           hearingDevice->connection_update_status = AWAITING;
         }
       }
@@ -531,15 +527,18 @@
   void OnReadRssiComplete(const RawAddress& address, int8_t rssi_value) {
     HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
     if (!hearingDevice) {
-      LOG(INFO) << "Skipping unknown device" << address;
+      LOG_INFO("Skipping unknown device %s",
+               address.ToStringForLogging().c_str());
       return;
     }
 
-    VLOG(1) << __func__ << ": device=" << address << ", rssi=" << (int)rssi_value;
+    LOG_DEBUG("device=%s, rss=%d", address.ToStringForLogging().c_str(),
+              (int)rssi_value);
 
     if (hearingDevice->read_rssi_count <= 0) {
-      LOG(ERROR) << __func__ << ": device=" << address
-                 << ", invalid read_rssi_count=" << hearingDevice->read_rssi_count;
+      LOG_ERROR(" device=%s, invalid read_rssi_count=%d",
+                address.ToStringForLogging().c_str(),
+                hearingDevice->read_rssi_count);
       return;
     }
 
@@ -548,7 +547,8 @@
     if (hearingDevice->read_rssi_count == READ_RSSI_NUM_TRIES) {
       // Store the timestamp only for the first one after packet flush
       clock_gettime(CLOCK_REALTIME, &last_log_set.timestamp);
-      LOG(INFO) << __func__ << ": store time. device=" << address << ", rssi=" << (int)rssi_value;
+      LOG_INFO("store time, device=%s, rssi=%d",
+               address.ToStringForLogging().c_str(), (int)rssi_value);
     }
 
     last_log_set.rssi.emplace_back(rssi_value);
@@ -558,12 +558,13 @@
   void OnEncryptionComplete(const RawAddress& address, bool success) {
     HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
     if (!hearingDevice) {
-      DVLOG(2) << "Skipping unknown device" << address;
+      LOG_DEBUG("Skipping unknown device %s",
+                address.ToStringForLogging().c_str());
       return;
     }
 
     if (!success) {
-      LOG(ERROR) << "encryption failed";
+      LOG_ERROR("encryption failed");
       BTA_GATTC_Close(hearingDevice->conn_id);
       if (hearingDevice->first_connection) {
         callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
@@ -571,7 +572,7 @@
       return;
     }
 
-    LOG(INFO) << __func__ << ": " << address;
+    LOG_INFO("%s", address.ToStringForLogging().c_str());
 
     if (hearingDevice->audio_control_point_handle &&
         hearingDevice->audio_status_handle &&
@@ -580,8 +581,8 @@
       // Use cached data, jump to read PSM
       ReadPSM(hearingDevice);
     } else {
-      LOG(INFO) << __func__ << ": " << address
-                << ": do BTA_GATTC_ServiceSearchRequest";
+      LOG_INFO("%s: do BTA_GATTC_ServiceSearchRequest",
+               address.ToStringForLogging().c_str());
       hearingDevice->first_connection = true;
       BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
     }
@@ -592,32 +593,34 @@
                         tGATT_STATUS status) {
     HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
     if (!hearingDevice) {
-      DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+      LOG_DEBUG("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
       return;
     }
     if (status != GATT_SUCCESS) {
-      LOG(WARNING) << hearingDevice->address
-                   << " phy update fail with status: " << status;
+      LOG_WARN("%s phy update fail with status: %hu",
+               hearingDevice->address.ToStringForLogging().c_str(), status);
       return;
     }
     if (tx_phys == PHY_LE_2M && rx_phys == PHY_LE_2M) {
-      LOG(INFO) << hearingDevice->address << " phy update to 2M successful";
+      LOG_INFO("%s phy update to 2M successful",
+               hearingDevice->address.ToStringForLogging().c_str());
       return;
     }
-    LOG(INFO)
-        << hearingDevice->address
-        << " phy update successful but not target phy, try again. tx_phys: "
-        << tx_phys << ", rx_phys: " << rx_phys;
+    LOG_INFO(
+        "%s phy update successful but not target phy, try again. tx_phys: "
+        "%u,rx_phys: %u",
+        hearingDevice->address.ToStringForLogging().c_str(), tx_phys, rx_phys);
     BTM_BleSetPhy(hearingDevice->address, PHY_LE_2M, PHY_LE_2M, 0);
   }
 
   void OnServiceChangeEvent(const RawAddress& address) {
     HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
     if (!hearingDevice) {
-      VLOG(2) << "Skipping unknown device" << address;
+      LOG_DEBUG("Skipping unknown device %s",
+                address.ToStringForLogging().c_str());
       return;
     }
-    LOG(INFO) << __func__ << ": address=" << address;
+    LOG_INFO("address=%s", address.ToStringForLogging().c_str());
     hearingDevice->first_connection = true;
     hearingDevice->service_changed_rcvd = true;
     BtaGattQueue::Clean(hearingDevice->conn_id);
@@ -630,17 +633,18 @@
   void OnServiceDiscDoneEvent(const RawAddress& address) {
     HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
     if (!hearingDevice) {
-      VLOG(2) << "Skipping unknown device" << address;
+      LOG_DEBUG("Skipping unknown device %s",
+                address.ToStringForLogging().c_str());
       return;
     }
-    LOG(INFO) << __func__ << ": " << address;
+    LOG_INFO("%s", address.ToStringForLogging().c_str());
     if (hearingDevice->service_changed_rcvd ||
         !(hearingDevice->audio_control_point_handle &&
           hearingDevice->audio_status_handle &&
           hearingDevice->audio_status_ccc_handle &&
           hearingDevice->volume_handle && hearingDevice->read_psm_handle)) {
-      LOG(INFO) << __func__ << ": " << address
-                << ": do BTA_GATTC_ServiceSearchRequest";
+      LOG_INFO("%s: do BTA_GATTC_ServiceSearchRequest",
+               address.ToStringForLogging().c_str());
       BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
     }
   }
@@ -648,7 +652,7 @@
   void OnServiceSearchComplete(uint16_t conn_id, tGATT_STATUS status) {
     HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
     if (!hearingDevice) {
-      DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+      LOG_DEBUG("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
       return;
     }
 
@@ -657,7 +661,7 @@
 
     if (status != GATT_SUCCESS) {
       /* close connection and report service discovery complete with error */
-      LOG(ERROR) << "Service discovery failed";
+      LOG_ERROR("Service discovery failed");
       if (hearingDevice->first_connection) {
         callbacks->OnConnectionState(ConnectionState::DISCONNECTED,
                                      hearingDevice->address);
@@ -670,18 +674,19 @@
     const gatt::Service* service = nullptr;
     for (const gatt::Service& tmp : *services) {
       if (tmp.uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) {
-        LOG(INFO) << "Found UUID_SERVCLASS_GATT_SERVER, handle="
-                  << loghex(tmp.handle);
+        LOG_INFO("Found UUID_SERVCLASS_GATT_SERVER, handle=%s",
+                 loghex(tmp.handle).c_str());
         const gatt::Service* service_changed_service = &tmp;
         find_server_changed_ccc_handle(conn_id, service_changed_service);
       } else if (tmp.uuid == HEARING_AID_UUID) {
-        LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle);
+        LOG_INFO("Found Hearing Aid service, handle=%s",
+                 loghex(tmp.handle).c_str());
         service = &tmp;
       }
     }
 
     if (!service) {
-      LOG(ERROR) << "No Hearing Aid service found";
+      LOG_ERROR("No Hearing Aid service found");
       callbacks->OnConnectionState(ConnectionState::DISCONNECTED,
                                    hearingDevice->address);
       return;
@@ -693,8 +698,8 @@
                 hearingDevice->address, &hearingDevice->capabilities,
                 &hearingDevice->hi_sync_id, &hearingDevice->render_delay,
                 &hearingDevice->preparation_delay, &hearingDevice->codecs)) {
-          VLOG(2) << "Reading read only properties "
-                  << loghex(charac.value_handle);
+          LOG_DEBUG("Reading read only properties %s",
+                    loghex(charac.value_handle).c_str());
           BtaGattQueue::ReadCharacteristic(
               conn_id, charac.value_handle,
               HearingAidImpl::OnReadOnlyPropertiesReadStatic, nullptr);
@@ -708,19 +713,20 @@
         hearingDevice->audio_status_ccc_handle =
             find_ccc_handle(conn_id, charac.value_handle);
         if (!hearingDevice->audio_status_ccc_handle) {
-          LOG(ERROR) << __func__ << ": cannot find Audio Status CCC descriptor";
+          LOG_ERROR("cannot find Audio Status CCC descriptor");
           continue;
         }
 
-        LOG(INFO) << __func__
-                  << ": audio_status_handle=" << loghex(charac.value_handle)
-                  << ", ccc=" << loghex(hearingDevice->audio_status_ccc_handle);
+        LOG_INFO("audio_status_handle=%s, ccc=%s",
+                 loghex(charac.value_handle).c_str(),
+                 loghex(hearingDevice->audio_status_ccc_handle).c_str());
       } else if (charac.uuid == VOLUME_UUID) {
         hearingDevice->volume_handle = charac.value_handle;
       } else if (charac.uuid == LE_PSM_UUID) {
         hearingDevice->read_psm_handle = charac.value_handle;
       } else {
-        LOG(WARNING) << "Unknown characteristic found:" << charac.uuid;
+        LOG_WARN("Unknown characteristic found:%s",
+                 charac.uuid.ToString().c_str());
       }
     }
 
@@ -733,8 +739,9 @@
 
   void ReadPSM(HearingDevice* hearingDevice) {
     if (hearingDevice->read_psm_handle) {
-      LOG(INFO) << "Reading PSM " << loghex(hearingDevice->read_psm_handle)
-                << ", device=" << hearingDevice->address;
+      LOG_INFO("Reading PSM %s, device=%s",
+               loghex(hearingDevice->read_psm_handle).c_str(),
+               hearingDevice->address.ToStringForLogging().c_str());
       BtaGattQueue::ReadCharacteristic(
           hearingDevice->conn_id, hearingDevice->read_psm_handle,
           HearingAidImpl::OnPsmReadStatic, nullptr);
@@ -745,33 +752,29 @@
                            uint8_t* value) {
     HearingDevice* device = hearingDevices.FindByConnId(conn_id);
     if (!device) {
-      LOG(INFO) << __func__
-                << ": Skipping unknown device, conn_id=" << loghex(conn_id);
+      LOG_INFO("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
       return;
     }
 
     if (device->audio_status_handle != handle) {
-      LOG(INFO) << __func__ << ": Mismatched handle, "
-                << loghex(device->audio_status_handle)
-                << "!=" << loghex(handle);
+      LOG_INFO("Mismatched handle, %s!=%s",
+               loghex(device->audio_status_handle).c_str(),
+               loghex(handle).c_str());
       return;
     }
 
     if (len < 1) {
-      LOG(ERROR) << __func__ << ": Data Length too small, len=" << len
-                 << ", expecting at least 1";
+      LOG_ERROR("Data Length too small, len=%u, expecting at least 1", len);
       return;
     }
 
     if (value[0] != 0) {
-      LOG(INFO) << __func__
-                << ": Invalid returned status. data=" << loghex(value[0]);
+      LOG_INFO("Invalid returned status. data=%s", loghex(value[0]).c_str());
       return;
     }
 
-    LOG(INFO) << __func__
-              << ": audio status success notification. command_acked="
-              << device->command_acked;
+    LOG_INFO("audio status success notification. command_acked=%u",
+             device->command_acked);
     device->command_acked = true;
   }
 
@@ -780,11 +783,11 @@
                                 void* data) {
     HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
     if (!hearingDevice) {
-      DVLOG(2) << __func__ << "unknown conn_id=" << loghex(conn_id);
+      LOG_DEBUG("unknown conn_id=%s", loghex(conn_id).c_str());
       return;
     }
 
-    VLOG(2) << __func__ << " " << base::HexEncode(value, len);
+    LOG_DEBUG("%s", base::HexEncode(value, len).c_str());
 
     uint8_t* p = value;
 
@@ -792,13 +795,13 @@
     STREAM_TO_UINT8(version, p);
 
     if (version != 0x01) {
-      LOG(WARNING) << "Unknown version: " << loghex(version);
+      LOG_WARN("Unknown version: %s", loghex(version).c_str());
       return;
     }
 
     // version 0x01 of read only properties:
     if (len < 17) {
-      LOG(WARNING) << "Read only properties too short: " << loghex(len);
+      LOG_WARN("Read only properties too short: %s", loghex(len).c_str());
       return;
     }
     uint8_t capabilities;
@@ -806,35 +809,34 @@
     hearingDevice->capabilities = capabilities;
     bool side = capabilities & CAPABILITY_SIDE;
     bool standalone = capabilities & CAPABILITY_BINAURAL;
-    VLOG(2) << __func__ << " capabilities: " << (side ? "right" : "left")
-            << ", " << (standalone ? "binaural" : "monaural");
+    LOG_DEBUG("capabilities: %s, %s", (side ? "right" : "left"),
+              (standalone ? "binaural" : "monaural"));
 
     if (capabilities & CAPABILITY_RESERVED) {
-      LOG(WARNING) << __func__ << " reserved capabilities are set";
+      LOG_WARN("reserved capabilities are set");
     }
 
     STREAM_TO_UINT64(hearingDevice->hi_sync_id, p);
-    VLOG(2) << __func__ << " hiSyncId: " << loghex(hearingDevice->hi_sync_id);
+    LOG_DEBUG("hiSyncId: %s", loghex(hearingDevice->hi_sync_id).c_str());
     uint8_t feature_map;
     STREAM_TO_UINT8(feature_map, p);
 
     STREAM_TO_UINT16(hearingDevice->render_delay, p);
-    VLOG(2) << __func__
-            << " render delay: " << loghex(hearingDevice->render_delay);
+    LOG_DEBUG("render delay: %s", loghex(hearingDevice->render_delay).c_str());
 
     STREAM_TO_UINT16(hearingDevice->preparation_delay, p);
-    VLOG(2) << __func__ << " preparation delay: "
-            << loghex(hearingDevice->preparation_delay);
+    LOG_DEBUG("preparation delay: %s",
+              loghex(hearingDevice->preparation_delay).c_str());
 
     uint16_t codecs;
     STREAM_TO_UINT16(codecs, p);
     hearingDevice->codecs = codecs;
-    VLOG(2) << __func__ << " supported codecs: " << loghex(codecs);
-    if (codecs & (1 << CODEC_G722_16KHZ)) VLOG(2) << "\tG722@16kHz";
-    if (codecs & (1 << CODEC_G722_24KHZ)) VLOG(2) << "\tG722@24kHz";
+    LOG_DEBUG("supported codecs: %s", loghex(codecs).c_str());
+    if (codecs & (1 << CODEC_G722_16KHZ)) LOG_INFO("%s\tG722@16kHz", __func__);
+    if (codecs & (1 << CODEC_G722_24KHZ)) LOG_INFO("%s\tG722@24kHz", __func__);
 
     if (!(codecs & (1 << CODEC_G722_16KHZ))) {
-      LOG(WARNING) << __func__ << " Mandatory codec, G722@16kHz not supported";
+      LOG_WARN("Mandatory codec, G722@16kHz not supported");
     }
   }
 
@@ -883,29 +885,31 @@
 
   void OnAudioStatus(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
                      uint16_t len, uint8_t* value, void* data) {
-    LOG(INFO) << __func__ << " " << base::HexEncode(value, len);
+    LOG_INFO("%s", base::HexEncode(value, len).c_str());
   }
 
   void OnPsmRead(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
                  uint16_t len, uint8_t* value, void* data) {
     HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
     if (!hearingDevice) {
-      DVLOG(2) << "Skipping unknown read event, conn_id=" << loghex(conn_id);
+      LOG_DEBUG("Skipping unknown read event, conn_id=%s",
+                loghex(conn_id).c_str());
       return;
     }
 
     if (status != GATT_SUCCESS) {
-      LOG(ERROR) << "Error reading PSM for device" << hearingDevice->address;
+      LOG_ERROR("Error reading PSM for device %s",
+                hearingDevice->address.ToStringForLogging().c_str());
       return;
     }
 
     if (len > 2) {
-      LOG(ERROR) << "Bad PSM length";
+      LOG_ERROR("Bad PSM Lengh");
       return;
     }
 
     uint16_t psm = *((uint16_t*)value);
-    VLOG(2) << "read psm:" << loghex(psm);
+    LOG_DEBUG("read psm:%s", loghex(psm).c_str());
 
     if (hearingDevice->gap_handle == GAP_INVALID_HANDLE &&
         BTM_IsEncrypted(hearingDevice->address, BT_TRANSPORT_LE)) {
@@ -926,12 +930,12 @@
         &cfg_info, nullptr, BTM_SEC_NONE /* TODO: request security ? */,
         HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE);
     if (gap_handle == GAP_INVALID_HANDLE) {
-      LOG(ERROR) << "UNABLE TO GET gap_handle";
+      LOG_ERROR("UNABLE TO GET gap_handle");
       return;
     }
 
     hearingDevice->gap_handle = gap_handle;
-    LOG(INFO) << "Successfully sent GAP connect request";
+    LOG_INFO("Successfully sent GAP connect request");
   }
 
   static void OnReadOnlyPropertiesReadStatic(uint16_t conn_id,
@@ -960,7 +964,8 @@
   void OnDeviceReady(const RawAddress& address) {
     HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
     if (!hearingDevice) {
-      LOG(INFO) << "Device not connected to profile" << address;
+      LOG_INFO("Device not connected to profile %s",
+               address.ToStringForLogging().c_str());
       return;
     }
 
@@ -970,19 +975,17 @@
       hearingDevice->first_connection = false;
     }
 
-    LOG(INFO) << __func__ << ": audio_status_handle="
-              << loghex(hearingDevice->audio_status_handle)
-              << ", audio_status_ccc_handle="
-              << loghex(hearingDevice->audio_status_ccc_handle);
+    LOG_INFO("audio_status_handle=%s, audio_status_ccc_handle=%s",
+             loghex(hearingDevice->audio_status_handle).c_str(),
+             loghex(hearingDevice->audio_status_ccc_handle).c_str());
 
     /* Register and enable the Audio Status Notification */
     tGATT_STATUS register_status;
     register_status = BTA_GATTC_RegisterForNotifications(
         gatt_if, address, hearingDevice->audio_status_handle);
     if (register_status != GATT_SUCCESS) {
-      LOG(ERROR) << __func__
-                 << ": BTA_GATTC_RegisterForNotifications failed, status="
-                 << loghex(static_cast<uint8_t>(register_status));
+      LOG_ERROR("BTA_GATTC_RegisterForNotifications failed, status=%s",
+                loghex(static_cast<uint8_t>(register_status)).c_str());
       return;
     }
     std::vector<uint8_t> value(2);
@@ -1005,10 +1008,10 @@
 
     hearingDevice->connecting_actively = false;
     hearingDevice->accepting_audio = true;
-    LOG(INFO) << __func__ << ": address=" << address
-              << ", hi_sync_id=" << loghex(hearingDevice->hi_sync_id)
-              << ", codec_in_use=" << loghex(codec_in_use)
-              << ", audio_running=" << audio_running;
+    LOG_INFO("address=%s, hi_sync_id=%s, codec_in_use=%s, audio_running=%i",
+             address.ToStringForLogging().c_str(),
+             loghex(hearingDevice->hi_sync_id).c_str(),
+             loghex(codec_in_use).c_str(), audio_running);
 
     StartSendingAudio(*hearingDevice);
 
@@ -1018,7 +1021,7 @@
   }
 
   void StartSendingAudio(const HearingDevice& hearingDevice) {
-    VLOG(0) << __func__ << ": device=" << hearingDevice.address;
+    LOG_DEBUG("device=%s", hearingDevice.address.ToStringForLogging().c_str());
 
     if (encoder_state_left == nullptr) {
       encoder_state_init();
@@ -1048,9 +1051,9 @@
     CHECK(stop_audio_ticks) << "stop_audio_ticks is empty";
 
     if (!audio_running) {
-      LOG(WARNING) << __func__ << ": Unexpected audio suspend";
+      LOG_WARN("Unexpected audio suspend");
     } else {
-      LOG(INFO) << __func__ << ": audio_running=" << audio_running;
+      LOG_INFO("audio_running=%i", audio_running);
     }
     audio_running = false;
     stop_audio_ticks();
@@ -1060,11 +1063,11 @@
       if (!device.accepting_audio) continue;
 
       if (!device.playback_started) {
-        LOG(WARNING) << __func__
-                     << ": Playback not started, skip send Stop cmd, device="
-                     << device.address;
+        LOG_WARN("Playback not started, skip send Stop cmd, device=%s",
+                 device.address.ToStringForLogging().c_str());
       } else {
-        LOG(INFO) << __func__ << ": send Stop cmd, device=" << device.address;
+        LOG_INFO("send Stop cmd, device=%s",
+                 device.address.ToStringForLogging().c_str());
         device.playback_started = false;
         device.command_acked = false;
         BtaGattQueue::WriteCharacteristic(device.conn_id,
@@ -1078,9 +1081,9 @@
     CHECK(start_audio_ticks) << "start_audio_ticks is empty";
 
     if (audio_running) {
-      LOG(ERROR) << __func__ << ": Unexpected Audio Resume";
+      LOG_ERROR("Unexpected Audio Resume");
     } else {
-      LOG(INFO) << __func__ << ": audio_running=" << audio_running;
+      LOG_INFO("audio_running=%i", audio_running);
     }
 
     for (auto& device : hearingDevices.devices) {
@@ -1090,8 +1093,7 @@
     }
 
     if (!audio_running) {
-      LOG(INFO) << __func__ << ": No device (0/" << GetDeviceCount()
-                << ") ready to start";
+      LOG_INFO("No device (0/%d) ready to start", GetDeviceCount());
       return;
     }
 
@@ -1119,8 +1121,8 @@
   }
 
   void SendEnableServiceChangedInd(HearingDevice* device) {
-    VLOG(2) << __func__ << " Enable " << device->address
-            << "service changed ind.";
+    LOG_DEBUG("Enable service changed ind.%s",
+              device->address.ToStringForLogging().c_str());
     std::vector<uint8_t> value(2);
     uint8_t* ptr = value.data();
     UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_INDICTION);
@@ -1136,13 +1138,11 @@
 
     if (!audio_running) {
       if (!device->playback_started) {
-        LOG(INFO) << __func__
-                  << ": Skip Send Start since audio is not running, device="
-                  << device->address;
+        LOG_INFO("Skip Send Start since audio is not running, device=%s",
+                 device->address.ToStringForLogging().c_str());
       } else {
-        LOG(ERROR) << __func__
-                   << ": Audio not running but Playback has started, device="
-                   << device->address;
+        LOG_ERROR("Audio not running but Playback has started, device=%s",
+                  device->address.ToStringForLogging().c_str());
       }
       return;
     }
@@ -1150,15 +1150,16 @@
     if (current_volume == VOLUME_UNKNOWN) start[3] = (uint8_t)VOLUME_MIN;
 
     if (device->playback_started) {
-      LOG(ERROR) << __func__
-                 << ": Playback already started, skip send Start cmd, device="
-                 << device->address;
+      LOG_ERROR("Playback already started, skip send Start cmd, device=%s",
+                device->address.ToStringForLogging().c_str());
     } else {
       start[4] = GetOtherSideStreamStatus(device);
-      LOG(INFO) << __func__ << ": send Start cmd, volume=" << loghex(start[3])
-                << ", audio type=" << loghex(start[2])
-                << ", device=" << device->address
-                << ", other side streaming=" << loghex(start[4]);
+      LOG_INFO(
+          "send Start cmd, volume=%s, audio type=%s, device=%s, other side "
+          "streaming=%s",
+          loghex(start[3]).c_str(), loghex(start[2]).c_str(),
+          device->address.ToStringForLogging().c_str(),
+          loghex(start[4]).c_str());
       device->command_acked = false;
       BtaGattQueue::WriteCharacteristic(
           device->conn_id, device->audio_control_point_handle, start,
@@ -1171,12 +1172,12 @@
                                            uint16_t len, const uint8_t* value,
                                            void* data) {
     if (status != GATT_SUCCESS) {
-      LOG(ERROR) << __func__ << ": handle=" << handle << ", conn_id=" << conn_id
-                 << ", status=" << loghex(static_cast<uint8_t>(status));
+      LOG_ERROR("handle=%u, conn_id=%u, status=%s", handle, conn_id,
+                loghex(static_cast<uint8_t>(status)).c_str());
       return;
     }
     if (!instance) {
-      LOG(ERROR) << __func__ << ": instance is null.";
+      LOG_ERROR("instance is null");
       return;
     }
     instance->StartAudioCtrlCallback(conn_id);
@@ -1185,10 +1186,10 @@
   void StartAudioCtrlCallback(uint16_t conn_id) {
     HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
     if (!hearingDevice) {
-      LOG(ERROR) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+      LOG_ERROR("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
       return;
     }
-    LOG(INFO) << __func__ << ": device: " << hearingDevice->address;
+    LOG_INFO("device: %s", hearingDevice->address.ToStringForLogging().c_str());
     hearingDevice->playback_started = true;
   }
 
@@ -1203,7 +1204,7 @@
   bool NeedToDropPacket(HearingDevice* target_side, HearingDevice* other_side) {
     // Just drop packet if the other side does not exist.
     if (!other_side) {
-      VLOG(2) << __func__ << ": other side not connected to profile";
+      LOG_DEBUG("other side not connected to profile");
       return true;
     }
 
@@ -1212,14 +1213,14 @@
     uint16_t target_current_credit = L2CA_GetPeerLECocCredit(
         target_side->address, GAP_ConnGetL2CAPCid(target_side->gap_handle));
     if (target_current_credit == L2CAP_LE_CREDIT_MAX) {
-      LOG(ERROR) << __func__ << ": Get target side credit value fail.";
+      LOG_ERROR("Get target side credit value fail.");
       return true;
     }
 
     uint16_t other_current_credit = L2CA_GetPeerLECocCredit(
         other_side->address, GAP_ConnGetL2CAPCid(other_side->gap_handle));
     if (other_current_credit == L2CAP_LE_CREDIT_MAX) {
-      LOG(ERROR) << __func__ << ": Get other side credit value fail.";
+      LOG_ERROR("Get other side credit value fail.");
       return true;
     }
 
@@ -1228,24 +1229,23 @@
     } else {
       diff_credit = other_current_credit - target_current_credit;
     }
-    VLOG(2) << __func__ << ": Target(" << target_side->address
-            << ") Credit: " << target_current_credit << ", Other("
-            << other_side->address << ") Credit: " << other_current_credit
-            << ", Init Credit: " << init_credit;
+    LOG_DEBUG("Target(%s) Credit: %u, Other(%s) Credit: %u, Init Credit: %u",
+              target_side->address.ToStringForLogging().c_str(),
+              target_current_credit,
+              other_side->address.ToStringForLogging().c_str(),
+              other_current_credit, init_credit);
     return diff_credit < (init_credit / 2 - 1);
   }
 
   void OnAudioDataReady(const std::vector<uint8_t>& data) {
     /* For now we assume data comes in as 16bit per sample 16kHz PCM stereo */
-    DVLOG(2) << __func__;
-
     bool need_drop = false;
     int num_samples =
         data.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/);
 
     // The G.722 codec accept only even number of samples for encoding
     if (num_samples % 2 != 0)
-      LOG(FATAL) << "num_samples is not even: " << num_samples;
+      LOG_ALWAYS_FATAL("num_samples is not even: %d", num_samples);
 
     // TODO: we should cache left/right and current state, instad of recomputing
     // it for each packet, 100 times a second.
@@ -1261,8 +1261,7 @@
     }
 
     if (left == nullptr && right == nullptr) {
-      LOG(WARNING) << __func__ << ": No more (0/" << GetDeviceCount()
-                   << ") devices ready";
+      LOG_WARN("No more (0/%d) devices ready", GetDeviceCount());
       DoDisconnectAudioStop();
       return;
     }
@@ -1318,13 +1317,15 @@
         // Compare the two sides LE CoC credit value to confirm need to drop or
         // skip audio packet.
         if (NeedToDropPacket(left, right)) {
-          LOG(INFO) << left->address << " triggers dropping, "
-                    << packets_in_chans << " packets in channel";
+          LOG_INFO("%s triggers dropping, %u packets in channel",
+                   left->address.ToStringForLogging().c_str(),
+                   packets_in_chans);
           need_drop = true;
           left->audio_stats.trigger_drop_count++;
         } else {
-          LOG(INFO) << left->address << " skipping " << packets_in_chans
-                    << " packets";
+          LOG_INFO("%s skipping %u packets",
+                   left->address.ToStringForLogging().c_str(),
+                   packets_in_chans);
           left->audio_stats.packet_flush_count += packets_in_chans;
           left->audio_stats.frame_flush_count++;
           L2CA_FlushChannel(cid, 0xffff);
@@ -1350,13 +1351,15 @@
         // Compare the two sides LE CoC credit value to confirm need to drop or
         // skip audio packet.
         if (NeedToDropPacket(right, left)) {
-          LOG(INFO) << right->address << " triggers dropping, "
-                    << packets_in_chans << " packets in channel";
+          LOG_INFO("%s triggers dropping, %u packets in channel",
+                   right->address.ToStringForLogging().c_str(),
+                   packets_in_chans);
           need_drop = true;
           right->audio_stats.trigger_drop_count++;
         } else {
-          LOG(INFO) << right->address << " skipping " << packets_in_chans
-                    << " packets";
+          LOG_INFO("%s skipping %u packets",
+                   right->address.ToStringForLogging().c_str(),
+                   packets_in_chans);
           right->audio_stats.packet_flush_count += packets_in_chans;
           right->audio_stats.frame_flush_count++;
           L2CA_FlushChannel(cid, 0xffff);
@@ -1400,10 +1403,9 @@
   void SendAudio(uint8_t* encoded_data, uint16_t packet_size,
                  HearingDevice* hearingAid) {
     if (!hearingAid->playback_started || !hearingAid->command_acked) {
-      VLOG(2) << __func__
-              << ": Playback stalled, device=" << hearingAid->address
-              << ", cmd send=" << hearingAid->playback_started
-              << ", cmd acked=" << hearingAid->command_acked;
+      LOG_DEBUG("Playback stalled, device=%s,cmd send=%i, cmd acked=%i",
+                hearingAid->address.ToStringForLogging().c_str(),
+                hearingAid->playback_started, hearingAid->command_acked);
       return;
     }
 
@@ -1413,19 +1415,20 @@
     p++;
     memcpy(p, encoded_data, packet_size);
 
-    DVLOG(2) << hearingAid->address << " : " << base::HexEncode(p, packet_size);
+    LOG_DEBUG("%s : %s", hearingAid->address.ToStringForLogging().c_str(),
+              base::HexEncode(p, packet_size).c_str());
 
     uint16_t result = GAP_ConnWriteData(hearingAid->gap_handle, audio_packet);
 
     if (result != BT_PASS) {
-      LOG(ERROR) << " Error sending data: " << loghex(result);
+      LOG_ERROR("Error sending data: %s", loghex(result).c_str());
     }
   }
 
   void GapCallback(uint16_t gap_handle, uint16_t event, tGAP_CB_DATA* data) {
     HearingDevice* hearingDevice = hearingDevices.FindByGapHandle(gap_handle);
     if (!hearingDevice) {
-      LOG(INFO) << "Skipping unknown device, gap_handle=" << gap_handle;
+      LOG_INFO("Skipping unknown device, gap_handle=%u", gap_handle);
       return;
     }
 
@@ -1437,12 +1440,13 @@
         init_credit =
             L2CA_GetPeerLECocCredit(address, GAP_ConnGetL2CAPCid(gap_handle));
 
-        LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu
-                  << ", init_credit=" << init_credit;
+        LOG_INFO("GAP_EVT_CONN_OPENED %s, tx_mtu=%u, init_credit=%u",
+                 address.ToStringForLogging().c_str(), tx_mtu, init_credit);
 
         HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
         if (!hearingDevice) {
-          LOG(INFO) << "Skipping unknown device" << address;
+          LOG_INFO("Skipping unknown device %s",
+                   address.ToStringForLogging().c_str());
           return;
         }
         hearingDevice->gap_opened = true;
@@ -1453,10 +1457,11 @@
       }
 
       case GAP_EVT_CONN_CLOSED:
-        LOG(INFO) << __func__
-                  << ": GAP_EVT_CONN_CLOSED: " << hearingDevice->address
-                  << ", playback_started=" << hearingDevice->playback_started
-                  << ", accepting_audio=" << hearingDevice->accepting_audio;
+        LOG_INFO(
+            "GAP_EVT_CONN_CLOSED: %s, playback_started=%i, "
+            "accepting_audio=%i",
+            hearingDevice->address.ToStringForLogging().c_str(),
+            hearingDevice->playback_started, hearingDevice->accepting_audio);
         if (!hearingDevice->accepting_audio) {
           /* Disconnect connection when data channel is not available */
           BTA_GATTC_Close(hearingDevice->conn_id);
@@ -1471,7 +1476,7 @@
         }
         break;
       case GAP_EVT_CONN_DATA_AVAIL: {
-        DVLOG(2) << "GAP_EVT_CONN_DATA_AVAIL";
+        LOG_DEBUG("GAP_EVT_CONN_DATA_AVAIL");
 
         // only data we receive back from hearing aids are some stats, not
         // really important, but useful now for debugging.
@@ -1484,28 +1489,28 @@
         GAP_ConnReadData(gap_handle, buffer.data(), buffer.size(), &bytes_read);
 
         if (bytes_read < 4) {
-          LOG(WARNING) << " Wrong data length";
+          LOG_WARN("Wrong data length");
           return;
         }
 
         uint8_t* p = buffer.data();
 
-        DVLOG(1) << "stats from the hearing aid:";
+        LOG_DEBUG("stats from the hearing aid:");
         for (size_t i = 0; i + 4 <= buffer.size(); i += 4) {
           uint16_t event_counter, frame_index;
           STREAM_TO_UINT16(event_counter, p);
           STREAM_TO_UINT16(frame_index, p);
-          DVLOG(1) << "event_counter=" << event_counter
-                   << " frame_index: " << frame_index;
+          LOG_DEBUG("event_counter=%u frame_index: %u", event_counter,
+                    frame_index);
         }
         break;
       }
 
       case GAP_EVT_TX_EMPTY:
-        DVLOG(2) << "GAP_EVT_TX_EMPTY";
+        LOG_DEBUG("GAP_EVT_TX_EMPTY");
         break;
       case GAP_EVT_CONN_CONGESTED:
-        DVLOG(2) << "GAP_EVT_CONN_CONGESTED";
+        LOG_DEBUG("GAP_EVT_CONN_CONGESTED");
 
         // TODO: make it into function
         HearingAidAudioSource::Stop();
@@ -1515,7 +1520,7 @@
         // encoder_state_right = nulllptr;
         break;
       case GAP_EVT_CONN_UNCONGESTED:
-        DVLOG(2) << "GAP_EVT_CONN_UNCONGESTED";
+        LOG_DEBUG("GAP_EVT_CONN_UNCONGESTED");
         break;
     }
   }
@@ -1544,8 +1549,8 @@
       char temptime[20];
       struct tm* tstamp = localtime(&rssi_logs.timestamp.tv_sec);
       if (!strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp)) {
-        LOG(ERROR) << __func__ << ": strftime fails. tm_sec=" << tstamp->tm_sec << ", tm_min=" << tstamp->tm_min
-                   << ", tm_hour=" << tstamp->tm_hour;
+        LOG_ERROR("strftime fails. tm_sec=%d, tm_min=%d, tm_hour=%d",
+                  tstamp->tm_sec, tstamp->tm_min, tstamp->tm_hour);
         strlcpy(temptime, "UNKNOWN TIME", sizeof(temptime));
       }
       snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime, rssi_logs.timestamp.tv_nsec / 1000000);
@@ -1586,22 +1591,22 @@
     dprintf(fd, "%s", stream.str().c_str());
   }
 
-  void Disconnect(const RawAddress& address) override {
-    DVLOG(2) << __func__;
+  void Disconnect(const RawAddress& address) {
     HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
     if (!hearingDevice) {
-      LOG(INFO) << "Device not connected to profile" << address;
+      LOG_INFO("Device not connected to profile %s",
+               address.ToStringForLogging().c_str());
       return;
     }
 
-    VLOG(2) << __func__ << ": " << address;
+    LOG_DEBUG("%s", address.ToStringForLogging().c_str());
 
     bool connected = hearingDevice->accepting_audio;
     bool connecting_by_user = hearingDevice->connecting_actively;
 
-    LOG(INFO) << __func__ << ": " << hearingDevice->address
-              << ", playback_started=" << hearingDevice->playback_started
-              << ", accepting_audio=" << hearingDevice->accepting_audio;
+    LOG_INFO("%s, playback_started=%i, accepting_audio=%i",
+             hearingDevice->address.ToStringForLogging().c_str(),
+             hearingDevice->playback_started, hearingDevice->accepting_audio);
 
     if (hearingDevice->connecting_actively) {
       // cancel pending direct connect
@@ -1634,8 +1639,7 @@
     for (const auto& device : hearingDevices.devices) {
       if (device.accepting_audio) return;
     }
-    LOG(INFO) << __func__ << ": No more (0/" << GetDeviceCount()
-              << ") devices ready";
+    LOG_INFO("No more (0/%d) devices ready", GetDeviceCount());
     DoDisconnectAudioStop();
   }
 
@@ -1643,12 +1647,12 @@
                           RawAddress remote_bda) {
     HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
     if (!hearingDevice) {
-      VLOG(2) << "Skipping unknown device disconnect, conn_id="
-              << loghex(conn_id);
+      LOG_DEBUG("Skipping unknown device disconnect, conn_id=%s",
+                loghex(conn_id).c_str());
       return;
     }
-    VLOG(2) << __func__ << ": conn_id=" << loghex(conn_id)
-            << ", remote_bda=" << remote_bda;
+    LOG_DEBUG("conn_id=%s, remote_bda=%s", loghex(conn_id).c_str(),
+              remote_bda.ToStringForLogging().c_str());
 
     // Inform the other side (if any) of this disconnection
     std::vector<uint8_t> inform_disconn_state(
@@ -1667,16 +1671,15 @@
     for (const auto& device : hearingDevices.devices) {
       if (device.accepting_audio) return;
     }
-    LOG(INFO) << __func__ << ": No more (0/" << GetDeviceCount()
-              << ") devices ready";
+    LOG_INFO("No more (0/%d) devices ready", GetDeviceCount());
     DoDisconnectAudioStop();
   }
 
   void DoDisconnectCleanUp(HearingDevice* hearingDevice) {
     if (hearingDevice->connection_update_status != COMPLETED) {
-      LOG(INFO) << __func__ << ": connection update not completed. Current="
-                << hearingDevice->connection_update_status
-                << ", device=" << hearingDevice->address;
+      LOG_INFO("connection update not completed. Current=%u, device=%s",
+               hearingDevice->connection_update_status,
+               hearingDevice->address.ToStringForLogging().c_str());
 
       if (hearingDevice->connection_update_status == STARTED) {
         OnConnectionUpdateComplete(hearingDevice->conn_id, NULL);
@@ -1697,8 +1700,9 @@
     }
 
     hearingDevice->accepting_audio = false;
-    LOG(INFO) << __func__ << ": device=" << hearingDevice->address
-              << ", playback_started=" << hearingDevice->playback_started;
+    LOG_INFO("device=%s, playback_started=%i",
+             hearingDevice->address.ToStringForLogging().c_str(),
+             hearingDevice->playback_started);
     hearingDevice->playback_started = false;
     hearingDevice->command_acked = false;
   }
@@ -1710,8 +1714,8 @@
     current_volume = VOLUME_UNKNOWN;
   }
 
-  void SetVolume(int8_t volume) override {
-    VLOG(2) << __func__ << ": " << +volume;
+  void SetVolume(int8_t volume) {
+    LOG_DEBUG("%d", volume);
     current_volume = volume;
     for (HearingDevice& device : hearingDevices.devices) {
       if (!device.accepting_audio) continue;
@@ -1754,7 +1758,7 @@
                                       const gatt::Service* service) {
     HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
     if (!hearingDevice) {
-      DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id);
+      LOG_DEBUG("Skipping unknown device, conn_id=%s", loghex(conn_id).c_str());
       return;
     }
     for (const gatt::Characteristic& charac : service->characteristics) {
@@ -1762,12 +1766,11 @@
         hearingDevice->service_changed_ccc_handle =
             find_ccc_handle(conn_id, charac.value_handle);
         if (!hearingDevice->service_changed_ccc_handle) {
-          LOG(ERROR) << __func__
-                     << ": cannot find service changed CCC descriptor";
+          LOG_ERROR("cannot find service changed CCC descriptor");
           continue;
         }
-        LOG(INFO) << __func__ << " service_changed_ccc="
-                  << loghex(hearingDevice->service_changed_ccc_handle);
+        LOG_INFO("service_changed_ccc=%s",
+                 loghex(hearingDevice->service_changed_ccc_handle).c_str());
         break;
       }
     }
@@ -1780,7 +1783,7 @@
         BTA_GATTC_GetCharacteristic(conn_id, char_handle);
 
     if (!p_char) {
-      LOG(WARNING) << __func__ << ": No such characteristic: " << char_handle;
+      LOG_WARN("No such characteristic: %u", char_handle);
       return 0;
     }
 
@@ -1795,14 +1798,14 @@
   void send_state_change(HearingDevice* device, std::vector<uint8_t> payload) {
     if (device->conn_id != 0) {
       if (device->service_changed_rcvd) {
-        LOG(INFO)
-            << __func__
-            << ": service discover is in progress, skip send State Change cmd.";
+        LOG_INFO(
+            "service discover is in progress, skip send State Change cmd.");
         return;
       }
       // Send the data packet
-      LOG(INFO) << __func__ << ": Send State Change. device=" << device->address
-                << ", status=" << loghex(payload[1]);
+      LOG_INFO("Send State Change. device=%s, status=%s",
+               device->address.ToStringForLogging().c_str(),
+               loghex(payload[1]).c_str());
       BtaGattQueue::WriteCharacteristic(
           device->conn_id, device->audio_control_point_handle, payload,
           GATT_WRITE_NO_RSP, nullptr, nullptr);
@@ -1825,7 +1828,7 @@
       device->num_intervals_since_last_rssi_read++;
       if (device->num_intervals_since_last_rssi_read >= PERIOD_TO_READ_RSSI_IN_INTERVALS) {
         device->num_intervals_since_last_rssi_read = 0;
-        VLOG(1) << __func__ << ": device=" << device->address;
+        LOG_DEBUG("device=%s", device->address.ToStringForLogging().c_str());
         BTM_ReadRSSI(device->address, read_rssi_cb);
       }
     }
@@ -1843,7 +1846,7 @@
 }
 
 void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
-  VLOG(2) << __func__ << " event = " << +event;
+  LOG_DEBUG("event = %u", event);
 
   if (p_data == nullptr) return;
 
@@ -1874,9 +1877,8 @@
     case BTA_GATTC_NOTIF_EVT:
       if (!instance) return;
       if (!p_data->notify.is_notify || p_data->notify.len > GATT_MAX_ATTR_LEN) {
-        LOG(ERROR) << __func__ << ": rejected BTA_GATTC_NOTIF_EVT. is_notify="
-                   << p_data->notify.is_notify
-                   << ", len=" << p_data->notify.len;
+        LOG_ERROR("rejected BTA_GATTC_NOTIF_EVT. is_notify=%i, len=%u",
+                  p_data->notify.is_notify, p_data->notify.len);
         break;
       }
       instance->OnNotificationEvent(p_data->notify.conn_id,
@@ -1945,7 +1947,8 @@
 void HearingAid::Initialize(
     bluetooth::hearing_aid::HearingAidCallbacks* callbacks, Closure initCb) {
   if (instance) {
-    LOG(ERROR) << "Already initialized!";
+    LOG_ERROR("Already initialized!");
+    return;
   }
 
   audioReceiver = &audioReceiverImpl;
@@ -1955,15 +1958,42 @@
 
 bool HearingAid::IsHearingAidRunning() { return instance; }
 
-HearingAid* HearingAid::Get() {
-  CHECK(instance);
-  return instance;
-};
+void HearingAid::Connect(const RawAddress& address) {
+  if (!instance) {
+    LOG_ERROR("Hearing Aid instance is not available");
+    return;
+  }
+  instance->Connect(address);
+}
+
+void HearingAid::Disconnect(const RawAddress& address) {
+  if (!instance) {
+    LOG_ERROR("Hearing Aid instance is not available");
+    return;
+  }
+  instance->Disconnect(address);
+}
+
+void HearingAid::AddToAcceptlist(const RawAddress& address) {
+  if (!instance) {
+    LOG_ERROR("Hearing Aid instance is not available");
+    return;
+  }
+  instance->AddToAcceptlist(address);
+}
+
+void HearingAid::SetVolume(int8_t volume) {
+  if (!instance) {
+    LOG_ERROR("Hearing Aid instance is not available");
+    return;
+  }
+  instance->SetVolume(volume);
+}
 
 void HearingAid::AddFromStorage(const HearingDevice& dev_info,
                                 uint16_t is_acceptlisted) {
   if (!instance) {
-    LOG(ERROR) << "Not initialized yet";
+    LOG_ERROR("Not initialized yet");
   }
 
   instance->AddFromStorage(dev_info, is_acceptlisted);
@@ -1971,7 +2001,7 @@
 
 int HearingAid::GetDeviceCount() {
   if (!instance) {
-    LOG(INFO) << __func__ << ": Not initialized yet";
+    LOG_INFO("Not initialized yet");
     return 0;
   }
 
diff --git a/system/bta/hearing_aid/hearing_aid_audio_source.cc b/system/bta/hearing_aid/hearing_aid_audio_source.cc
index c7dc6ae..e347f87 100644
--- a/system/bta/hearing_aid/hearing_aid_audio_source.cc
+++ b/system/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -18,6 +18,7 @@
 
 #include <base/files/file_util.h>
 #include <base/logging.h>
+
 #include <cstdint>
 #include <memory>
 #include <sstream>
@@ -28,6 +29,7 @@
 #include "bta/include/bta_hearing_aid_api.h"
 #include "common/repeating_timer.h"
 #include "common/time_util.h"
+#include "osi/include/log.h"
 #include "osi/include/wakelock.h"
 #include "stack/include/btu.h"  // get_main_thread
 #include "udrv/include/uipc.h"
@@ -98,7 +100,7 @@
                            bytes_per_tick);
   }
 
-  VLOG(2) << "bytes_read: " << bytes_read;
+  LOG_DEBUG("bytes_read: %u", bytes_read);
   if (bytes_read < bytes_per_tick) {
     stats.media_read_total_underflow_bytes += bytes_per_tick - bytes_read;
     stats.media_read_total_underflow_count++;
@@ -115,14 +117,14 @@
 
 void hearing_aid_send_ack(tHEARING_AID_CTRL_ACK status) {
   uint8_t ack = status;
-  DVLOG(2) << "Hearing Aid audio ctrl ack: " << status;
+  LOG_DEBUG("Hearing Aid audio ctrl ack: %u", status);
   UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
 }
 
 void start_audio_ticks() {
   if (data_interval_ms != HA_INTERVAL_10_MS &&
       data_interval_ms != HA_INTERVAL_20_MS) {
-    LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
+    LOG_ALWAYS_FATAL("Unsupported data interval: %d", data_interval_ms);
   }
 
   wakelock_acquire();
@@ -133,20 +135,20 @@
 #else
       base::Milliseconds(data_interval_ms));
 #endif
-  LOG(INFO) << __func__ << ": running with data interval: " << data_interval_ms;
+  LOG_INFO("running with data interval: %d", data_interval_ms);
 }
 
 void stop_audio_ticks() {
-  LOG(INFO) << __func__ << ": stopped";
+  LOG_INFO("stopped");
   audio_timer.CancelAndWait();
   wakelock_release();
 }
 
 void hearing_aid_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
-  DVLOG(2) << "Hearing Aid audio data event: " << event;
+  LOG_DEBUG("Hearing Aid audio data event: %u", event);
   switch (event) {
     case UIPC_OPEN_EVT:
-      LOG(INFO) << __func__ << ": UIPC_OPEN_EVT";
+      LOG_INFO("UIPC_OPEN_EVT");
       /*
        * Read directly from media task from here on (keep callback for
        * connection events.
@@ -159,12 +161,12 @@
       do_in_main_thread(FROM_HERE, base::BindOnce(start_audio_ticks));
       break;
     case UIPC_CLOSE_EVT:
-      LOG(INFO) << __func__ << ": UIPC_CLOSE_EVT";
+      LOG_INFO("UIPC_CLOSE_EVT");
       hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
       do_in_main_thread(FROM_HERE, base::BindOnce(stop_audio_ticks));
       break;
     default:
-      LOG(ERROR) << "Hearing Aid audio data event not recognized:" << event;
+      LOG_ERROR("Hearing Aid audio data event not recognized: %u", event);
   }
 }
 
@@ -178,12 +180,12 @@
 
   /* detach on ctrl channel means audioflinger process was terminated */
   if (n == 0) {
-    LOG(WARNING) << __func__ << "CTRL CH DETACHED";
+    LOG_WARN("CTRL CH DETACHED");
     UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL);
     return;
   }
 
-  LOG(INFO) << __func__ << " " << audio_ha_hw_dump_ctrl_event(cmd);
+  LOG_INFO("%s", audio_ha_hw_dump_ctrl_event(cmd));
   //  a2dp_cmd_pending = cmd;
 
   tHEARING_AID_CTRL_ACK ctrl_ack_status;
@@ -207,7 +209,9 @@
 
     case HEARING_AID_CTRL_CMD_STOP:
       if (!hearing_aid_on_suspend_req()) {
-        LOG(INFO) << __func__ << ":HEARING_AID_CTRL_CMD_STOP: hearing_aid_on_suspend_req() errs, but ignored.";
+        LOG_INFO(
+            "HEARING_AID_CTRL_CMD_STOP: hearing_aid_on_suspend_req() errs, but "
+            "ignored.");
       }
       hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
       break;
@@ -230,7 +234,7 @@
         codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000;
         codec_capability.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000;
       } else {
-        LOG(FATAL) << "unsupported sample rate: " << sample_rate;
+        LOG_ALWAYS_FATAL("unsupported sample rate: %d", sample_rate);
       }
 
       codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
@@ -278,15 +282,14 @@
                     reinterpret_cast<uint8_t*>(&codec_config.sample_rate),
                     sizeof(btav_a2dp_codec_sample_rate_t)) !=
           sizeof(btav_a2dp_codec_sample_rate_t)) {
-        LOG(ERROR) << __func__ << "Error reading sample rate from audio HAL";
+        LOG_ERROR("Error reading sample rate from audio HAL");
         break;
       }
       if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL,
                     reinterpret_cast<uint8_t*>(&codec_config.bits_per_sample),
                     sizeof(btav_a2dp_codec_bits_per_sample_t)) !=
           sizeof(btav_a2dp_codec_bits_per_sample_t)) {
-        LOG(ERROR) << __func__
-                   << "Error reading bits per sample from audio HAL";
+        LOG_ERROR("Error reading bits per sample from audio HAL");
 
         break;
       }
@@ -294,29 +297,28 @@
                     reinterpret_cast<uint8_t*>(&codec_config.channel_mode),
                     sizeof(btav_a2dp_codec_channel_mode_t)) !=
           sizeof(btav_a2dp_codec_channel_mode_t)) {
-        LOG(ERROR) << __func__ << "Error reading channel mode from audio HAL";
+        LOG_ERROR("Error reading channel mode from audio HAL");
 
         break;
       }
-      LOG(INFO) << __func__ << " HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: "
-                << "sample_rate=" << codec_config.sample_rate
-                << "bits_per_sample=" << codec_config.bits_per_sample
-                << "channel_mode=" << codec_config.channel_mode;
+      LOG_INFO(
+          "HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: sample_rate=%u, "
+          "bits_per_sample=%u,channel_mode=%u",
+          codec_config.sample_rate, codec_config.bits_per_sample,
+          codec_config.channel_mode);
       break;
     }
 
     default:
-      LOG(ERROR) << __func__ << "UNSUPPORTED CMD: " << cmd;
+      LOG_ERROR("UNSUPPORTED CMD: %u", cmd);
       hearing_aid_send_ack(HEARING_AID_CTRL_ACK_FAILURE);
       break;
   }
-  LOG(INFO) << __func__
-            << " a2dp-ctrl-cmd : " << audio_ha_hw_dump_ctrl_event(cmd)
-            << " DONE";
+  LOG_INFO("a2dp-ctrl-cmd : %s DONE", audio_ha_hw_dump_ctrl_event(cmd));
 }
 
 void hearing_aid_ctrl_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
-  VLOG(2) << "Hearing Aid audio ctrl event: " << event;
+  LOG_DEBUG("Hearing Aid audio ctrl event: %u", event);
   switch (event) {
     case UIPC_OPEN_EVT:
       break;
@@ -331,14 +333,13 @@
       hearing_aid_recv_ctrl_data();
       break;
     default:
-      LOG(ERROR) << "Hearing Aid audio ctrl unrecognized event: " << event;
+      LOG_ERROR("Hearing Aid audio ctrl unrecognized event: %u", event);
   }
 }
 
 bool hearing_aid_on_resume_req(bool start_media_task) {
   if (localAudioReceiver == nullptr) {
-    LOG(ERROR) << __func__
-               << ": HEARING_AID_CTRL_CMD_START: audio receiver not started";
+    LOG_ERROR("HEARING_AID_CTRL_CMD_START: audio receiver not started");
     return false;
   }
   bt_status_t status;
@@ -349,7 +350,7 @@
                                   start_audio_ticks));
   } else {
     auto start_dummy_ticks = []() {
-      LOG(INFO) << "start_audio_ticks: waiting for data path opened";
+      LOG_INFO("start_audio_ticks: waiting for data path opened");
     };
     status = do_in_main_thread(
         FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
@@ -357,9 +358,7 @@
                                   start_dummy_ticks));
   }
   if (status != BT_STATUS_SUCCESS) {
-    LOG(ERROR) << __func__
-               << ": HEARING_AID_CTRL_CMD_START: do_in_main_thread err="
-               << status;
+    LOG_ERROR("HEARING_AID_CTRL_CMD_START: do_in_main_thread err=%u", status);
     return false;
   }
   return true;
@@ -367,8 +366,7 @@
 
 bool hearing_aid_on_suspend_req() {
   if (localAudioReceiver == nullptr) {
-    LOG(ERROR) << __func__
-               << ": HEARING_AID_CTRL_CMD_SUSPEND: audio receiver not started";
+    LOG_ERROR("HEARING_AID_CTRL_CMD_SUSPEND: audio receiver not started");
     return false;
   }
   bt_status_t status = do_in_main_thread(
@@ -376,9 +374,7 @@
       base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
                      base::Unretained(localAudioReceiver), stop_audio_ticks));
   if (status != BT_STATUS_SUCCESS) {
-    LOG(ERROR) << __func__
-               << ": HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err="
-               << status;
+    LOG_ERROR("HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err=%u", status);
     return false;
   }
   return true;
@@ -388,7 +384,7 @@
 void HearingAidAudioSource::Start(const CodecConfiguration& codecConfiguration,
                                   HearingAidAudioReceiver* audioReceiver,
                                   uint16_t remote_delay_ms) {
-  LOG(INFO) << __func__ << ": Hearing Aid Source Open";
+  LOG_INFO("Hearing Aid Source Open");
 
   bit_rate = codecConfiguration.bit_rate;
   sample_rate = codecConfiguration.sample_rate;
@@ -404,7 +400,7 @@
 }
 
 void HearingAidAudioSource::Stop() {
-  LOG(INFO) << __func__ << ": Hearing Aid Source Close";
+  LOG_INFO("Hearing Aid Source Close");
 
   localAudioReceiver = nullptr;
   if (bluetooth::audio::hearing_aid::is_hal_enabled()) {
@@ -420,7 +416,7 @@
       .on_suspend_ = hearing_aid_on_suspend_req,
   };
   if (!bluetooth::audio::hearing_aid::init(stream_cb, get_main_thread())) {
-    LOG(WARNING) << __func__ << ": Using legacy HAL";
+    LOG_WARN("Using legacy HAL");
     uipc_hearing_aid = UIPC_Init();
     UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb, HEARING_AID_CTRL_PATH);
   }
diff --git a/system/bta/hf_client/bta_hf_client_at.cc b/system/bta/hf_client/bta_hf_client_at.cc
index 7a710bf..97fcb97 100644
--- a/system/bta/hf_client/bta_hf_client_at.cc
+++ b/system/bta/hf_client/bta_hf_client_at.cc
@@ -2149,7 +2149,7 @@
   at_len = snprintf(buf, sizeof(buf), "AT+BIA=");
 
   const int32_t position = osi_property_get_int32(
-      "bluetooth.headsetclient.disable_indicator.position", -1);
+      "bluetooth.headset_client.disable_indicator.position", -1);
 
   for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) {
     int sup = client_cb->at_cb.indicator_lookup[i] == -1 ? 0 : 1;
diff --git a/system/bta/hh/bta_hh_le.cc b/system/bta/hh/bta_hh_le.cc
index ffcbf7f..776a5a3 100644
--- a/system/bta/hh/bta_hh_le.cc
+++ b/system/bta/hh/bta_hh_le.cc
@@ -1015,7 +1015,8 @@
               bta_hh_status_text(p_cb->status).c_str(),
               btm_status_text(p_cb->btm_status).c_str());
     if (!(p_cb->status == BTA_HH_ERR_SEC &&
-          p_cb->btm_status == BTM_ERR_PROCESSING))
+          (p_cb->btm_status == BTM_ERR_PROCESSING ||
+           p_cb->btm_status == BTM_FAILED_ON_SECURITY)))
       bta_hh_le_api_disc_act(p_cb);
     }
 }
diff --git a/system/bta/include/bta_gatt_api.h b/system/bta/include/bta_gatt_api.h
index d334bcc..9fd4db8 100644
--- a/system/bta/include/bta_gatt_api.h
+++ b/system/bta/include/bta_gatt_api.h
@@ -999,4 +999,7 @@
  ******************************************************************************/
 extern void BTA_GATTS_Close(uint16_t conn_id);
 
+// Adds bonded device for GATT server tracking service changes
+extern void BTA_GATTS_InitBonded(void);
+
 #endif /* BTA_GATT_API_H */
diff --git a/system/bta/include/bta_hearing_aid_api.h b/system/bta/include/bta_hearing_aid_api.h
index 90803c5..d1b930b 100644
--- a/system/bta/include/bta_hearing_aid_api.h
+++ b/system/bta/include/bta_hearing_aid_api.h
@@ -228,7 +228,6 @@
                          base::Closure initCb);
   static void CleanUp();
   static bool IsHearingAidRunning();
-  static HearingAid* Get();
   static void DebugDump(int fd);
 
   static void AddFromStorage(const HearingDevice& dev_info,
@@ -236,10 +235,10 @@
 
   static int GetDeviceCount();
 
-  virtual void Connect(const RawAddress& address) = 0;
-  virtual void Disconnect(const RawAddress& address) = 0;
-  virtual void AddToAcceptlist(const RawAddress& address) = 0;
-  virtual void SetVolume(int8_t volume) = 0;
+  static void Connect(const RawAddress& address);
+  static void Disconnect(const RawAddress& address);
+  static void AddToAcceptlist(const RawAddress& address);
+  static void SetVolume(int8_t volume);
 };
 
 /* Represents configuration of audio codec, as exchanged between hearing aid and
diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc
index c9a89bc..1d3cb3f 100644
--- a/system/bta/le_audio/client.cc
+++ b/system/bta/le_audio/client.cc
@@ -1350,15 +1350,15 @@
 
     leAudioDevice->SetConnectionState(DeviceConnectState::DISCONNECTING);
 
-    if (acl_force_disconnect) {
-      leAudioDevice->DisconnectAcl();
-      return;
-    }
-
     BtaGattQueue::Clean(leAudioDevice->conn_id_);
     BTA_GATTC_Close(leAudioDevice->conn_id_);
     leAudioDevice->conn_id_ = GATT_INVALID_CONN_ID;
     leAudioDevice->mtu_ = 0;
+
+    /* Remote in bad state, force ACL Disconnection. */
+    if (acl_force_disconnect) {
+      leAudioDevice->DisconnectAcl();
+    }
   }
 
   void DeregisterNotifications(LeAudioDevice* leAudioDevice) {
diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc
index 49f80f5..9b91b43 100644
--- a/system/bta/le_audio/state_machine.cc
+++ b/system/bta/le_audio/state_machine.cc
@@ -681,8 +681,6 @@
       LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice,
       const bluetooth::hci::iso_manager::cis_establish_cmpl_evt* event)
       override {
-    std::vector<uint8_t> value;
-
     auto ases_pair = leAudioDevice->GetAsesByCisConnHdl(event->cis_conn_hdl);
 
     if (event->status) {
@@ -734,11 +732,17 @@
     }
 
     if (!leAudioDevice->HaveAllActiveAsesCisEst()) {
-      /* More cis established event has to come */
+      /* More cis established events has to come */
       return;
     }
 
-    std::vector<uint8_t> ids;
+    if (!leAudioDevice->IsReadyToCreateStream()) {
+      /* Device still remains in ready to create stream state. It means that
+       * more enabling status notifications has to come. This may only happen
+       * for reconnection scenario for bi-directional CIS.
+       */
+      return;
+    }
 
     /* All CISes created. Send start ready for source ASE before we can go
      * to streaming state.
@@ -749,21 +753,8 @@
                "id: %d, cis handle 0x%04x",
                leAudioDevice->address_.ToString().c_str(), event->cig_id,
                event->cis_conn_hdl);
-    do {
-      if (ase->direction == le_audio::types::kLeAudioDirectionSource)
-        ids.push_back(ase->id);
-    } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
 
-    if (ids.size() > 0) {
-      le_audio::client_parser::ascs::PrepareAseCtpAudioReceiverStartReady(
-          ids, value);
-
-      BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_,
-                                        leAudioDevice->ctp_hdls_.val_hdl, value,
-                                        GATT_WRITE_NO_RSP, NULL, NULL);
-
-      return;
-    }
+    PrepareAndSendReceiverStartReady(leAudioDevice, ase);
 
     /* Cis establishment may came after setting group state to streaming, e.g.
      * for autonomous scenario when ase is sink */
@@ -850,6 +841,7 @@
         }
 
         LOG_INFO("Lost all members from the group %d", group->group_id_);
+        group->cises_.clear();
         RemoveCigForGroup(group);
 
         group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE);
@@ -2187,6 +2179,28 @@
     }
   }
 
+  void PrepareAndSendReceiverStartReady(LeAudioDevice* leAudioDevice,
+                                        struct ase* ase) {
+    std::vector<uint8_t> ids;
+    std::vector<uint8_t> value;
+
+    do {
+      if (ase->direction == le_audio::types::kLeAudioDirectionSource)
+        ids.push_back(ase->id);
+    } while ((ase = leAudioDevice->GetNextActiveAse(ase)));
+
+    if (ids.size() > 0) {
+      le_audio::client_parser::ascs::PrepareAseCtpAudioReceiverStartReady(
+          ids, value);
+
+      BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_,
+                                        leAudioDevice->ctp_hdls_.val_hdl, value,
+                                        GATT_WRITE_NO_RSP, NULL, NULL);
+
+      return;
+    }
+  }
+
   void AseStateMachineProcessEnabling(
       struct le_audio::client_parser::ascs::ase_rsp_hdr& arh, struct ase* ase,
       LeAudioDeviceGroup* group, LeAudioDevice* leAudioDevice) {
@@ -2200,8 +2214,32 @@
         ase->state = AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING;
 
         if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
-          /* We are here because of the reconnection of the single device. */
-          CisCreateForDevice(leAudioDevice);
+          if (ase->data_path_state < AudioStreamDataPathState::CIS_PENDING) {
+            /* We are here because of the reconnection of the single device. */
+            CisCreateForDevice(leAudioDevice);
+          }
+
+          if (!leAudioDevice->HaveAllActiveAsesCisEst()) {
+            /* More cis established events has to come */
+            return;
+          }
+
+          if (!leAudioDevice->IsReadyToCreateStream()) {
+            /* Device still remains in ready to create stream state. It means
+             * that more enabling status notifications has to come.
+             */
+            return;
+          }
+
+          /* All CISes created. Send start ready for source ASE before we can go
+           * to streaming state.
+           */
+          struct ase* ase = leAudioDevice->GetFirstActiveAse();
+          ASSERT_LOG(ase != nullptr,
+                     "shouldn't be called without an active ASE, device %s",
+                     leAudioDevice->address_.ToString().c_str());
+          PrepareAndSendReceiverStartReady(leAudioDevice, ase);
+
           return;
         }
 
diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc
index 1cafe06..dc5cfe9 100644
--- a/system/bta/le_audio/state_machine_test.cc
+++ b/system/bta/le_audio/state_machine_test.cc
@@ -3100,6 +3100,118 @@
   ASSERT_NE(ase->retrans_nb, 0);
 }
 
+TEST_F(StateMachineTest, testAttachDeviceToTheConversationalStream) {
+  const auto context_type = kContextTypeConversational;
+  const auto leaudio_group_id = 6;
+  const auto num_devices = 2;
+
+  ContentControlIdKeeper::GetInstance()->SetCcid(call_context, call_ccid);
+
+  // Prepare multiple fake connected devices in a group
+  auto* group =
+      PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices);
+  ASSERT_EQ(group->Size(), num_devices);
+
+  PrepareConfigureCodecHandler(group);
+  PrepareConfigureQosHandler(group);
+  PrepareEnableHandler(group);
+  PrepareReceiverStartReady(group);
+  PrepareDisableHandler(group);
+  PrepareReleaseHandler(group);
+
+  auto* leAudioDevice = group->GetFirstDevice();
+  LeAudioDevice* lastDevice;
+  LeAudioDevice* fistDevice = leAudioDevice;
+
+  auto expected_devices_written = 0;
+  while (leAudioDevice) {
+    /* Three Writes:
+     * 1: Codec Config
+     * 2: Codec QoS
+     * 3: Enabling
+     */
+    lastDevice = leAudioDevice;
+    EXPECT_CALL(gatt_queue,
+                WriteCharacteristic(leAudioDevice->conn_id_,
+                                    leAudioDevice->ctp_hdls_.val_hdl, _,
+                                    GATT_WRITE_NO_RSP, _, _))
+        .Times(AtLeast(3));
+    expected_devices_written++;
+    leAudioDevice = group->GetNextDevice(leAudioDevice);
+  }
+  ASSERT_EQ(expected_devices_written, num_devices);
+
+  EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(4);
+
+  InjectInitialIdleNotification(group);
+
+  // Start the configuration and stream Conversational content
+  LeAudioGroupStateMachine::Get()->StartStream(
+      group, static_cast<LeAudioContextType>(context_type),
+      types::AudioContexts(context_type));
+
+  // Check if group has transitioned to a proper state
+  ASSERT_EQ(group->GetState(),
+            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+  testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
+
+  // Inject CIS and ACL disconnection of first device
+  InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT);
+  InjectAclDisconnected(group, lastDevice);
+
+  // Check if group keeps streaming
+  ASSERT_EQ(group->GetState(),
+            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+
+  lastDevice->conn_id_ = 3;
+  group->UpdateAudioContextTypeAvailability();
+
+  // Make sure ASE with disconnected CIS are not left in STREAMING
+  ASSERT_EQ(lastDevice->GetFirstAseWithState(
+                ::le_audio::types::kLeAudioDirectionSink,
+                types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
+            nullptr);
+  ASSERT_EQ(lastDevice->GetFirstAseWithState(
+                ::le_audio::types::kLeAudioDirectionSource,
+                types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING),
+            nullptr);
+
+  EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_,
+                                              lastDevice->ctp_hdls_.val_hdl, _,
+                                              GATT_WRITE_NO_RSP, _, _))
+      .Times(AtLeast(3));
+
+  EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2);
+  LeAudioGroupStateMachine::Get()->AttachToStream(group, lastDevice);
+
+  // Check if group keeps streaming
+  ASSERT_EQ(group->GetState(),
+            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+
+  // Verify that the joining device receives the right CCID list
+  auto lastMeta = lastDevice->GetFirstActiveAse()->metadata;
+  bool parsedOk = false;
+  auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(),
+                                                   lastMeta.size(), parsedOk);
+  ASSERT_TRUE(parsedOk);
+
+  auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList);
+  ASSERT_TRUE(ccids.has_value());
+  ASSERT_NE(std::find(ccids->begin(), ccids->end(), call_ccid), ccids->end());
+
+  /* Verify that ASE of first device are still good*/
+  auto ase = fistDevice->GetFirstActiveAse();
+  ASSERT_NE(ase->max_transport_latency, 0);
+  ASSERT_NE(ase->retrans_nb, 0);
+
+  // Make sure ASEs with reconnected CIS are in STREAMING state
+  ASSERT_TRUE(lastDevice->HaveAllActiveAsesSameState(
+      types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING));
+}
+
 TEST_F(StateMachineTest, StartStreamAfterConfigure) {
   const auto context_type = kContextTypeMedia;
   const auto leaudio_group_id = 6;
@@ -3705,5 +3817,135 @@
   testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
   ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
 }
+
+TEST_F(StateMachineTest, StreamReconfigureAfterCisLostTwoDevices) {
+  auto context_type = kContextTypeConversational;
+  const auto leaudio_group_id = 4;
+  const auto num_devices = 2;
+
+  // Prepare multiple fake connected devices in a group
+  auto* group = PrepareSingleTestDeviceGroup(
+      leaudio_group_id, context_type, num_devices,
+      kContextTypeConversational | kContextTypeMedia);
+  ASSERT_EQ(group->Size(), num_devices);
+
+  PrepareConfigureCodecHandler(group);
+  PrepareConfigureQosHandler(group);
+  PrepareEnableHandler(group);
+  PrepareReceiverStartReady(group);
+
+  /* Prepare DisconnectCis mock to not symulate CisDisconnection */
+  ON_CALL(*mock_iso_manager_, DisconnectCis).WillByDefault(Return());
+
+  EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(2);
+  EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(2);
+  EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(6);
+  EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0);
+  EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0);
+  EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(1);
+
+  InjectInitialIdleNotification(group);
+
+  auto* leAudioDevice = group->GetFirstDevice();
+  auto expected_devices_written = 0;
+  while (leAudioDevice) {
+    EXPECT_CALL(gatt_queue,
+                WriteCharacteristic(leAudioDevice->conn_id_,
+                                    leAudioDevice->ctp_hdls_.val_hdl, _,
+                                    GATT_WRITE_NO_RSP, _, _))
+        .Times(3);
+    expected_devices_written++;
+    leAudioDevice = group->GetNextDevice(leAudioDevice);
+  }
+  ASSERT_EQ(expected_devices_written, num_devices);
+
+  // Validate GroupStreamStatus
+  EXPECT_CALL(
+      mock_callbacks_,
+      StatusReportCb(leaudio_group_id,
+                     bluetooth::le_audio::GroupStreamStatus::STREAMING));
+
+  // Start the configuration and stream Media content
+  context_type = kContextTypeMedia;
+  ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
+      group, static_cast<LeAudioContextType>(context_type),
+      types::AudioContexts(context_type)));
+
+  // Check if group has transitioned to a proper state
+  ASSERT_EQ(group->GetState(),
+            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+  ASSERT_EQ(1, mock_function_count_map["alarm_cancel"]);
+  testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
+  testing::Mock::VerifyAndClearExpectations(&gatt_queue);
+  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+
+  // Device disconnects due to timeout of CIS
+  leAudioDevice = group->GetFirstDevice();
+  while (leAudioDevice) {
+    InjectCisDisconnected(group, leAudioDevice, HCI_ERR_CONN_CAUSE_LOCAL_HOST);
+    // Disconnect device
+    LeAudioGroupStateMachine::Get()->ProcessHciNotifAclDisconnected(
+        group, leAudioDevice);
+
+    leAudioDevice = group->GetNextDevice(leAudioDevice);
+  }
+
+  LOG(INFO) << "GK A1";
+  group->ReloadAudioLocations();
+  group->ReloadAudioDirections();
+  group->UpdateAudioContextTypeAvailability();
+
+  // Start conversational scenario
+  leAudioDevice = group->GetFirstDevice();
+  int device_cnt = num_devices;
+  while (leAudioDevice) {
+    LOG(INFO) << "GK A11";
+    leAudioDevice->conn_id_ = device_cnt--;
+    leAudioDevice->SetConnectionState(DeviceConnectState::CONNECTED);
+    leAudioDevice = group->GetNextDevice(leAudioDevice);
+  }
+
+  LOG(INFO) << "GK A2";
+  InjectInitialIdleNotification(group);
+
+  group->ReloadAudioLocations();
+  group->ReloadAudioDirections();
+  group->UpdateAudioContextTypeAvailability(kContextTypeConversational |
+                                            kContextTypeMedia);
+
+  leAudioDevice = group->GetFirstDevice();
+  expected_devices_written = 0;
+  while (leAudioDevice) {
+    EXPECT_CALL(gatt_queue,
+                WriteCharacteristic(leAudioDevice->conn_id_,
+                                    leAudioDevice->ctp_hdls_.val_hdl, _,
+                                    GATT_WRITE_NO_RSP, _, _))
+        .Times(4);
+    expected_devices_written++;
+    leAudioDevice = group->GetNextDevice(leAudioDevice);
+  }
+  ASSERT_EQ(expected_devices_written, num_devices);
+
+  // Validate GroupStreamStatus
+  EXPECT_CALL(
+      mock_callbacks_,
+      StatusReportCb(leaudio_group_id,
+                     bluetooth::le_audio::GroupStreamStatus::STREAMING));
+
+  // Start the configuration and stream Conversational content
+  context_type = kContextTypeConversational;
+  ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream(
+      group, static_cast<LeAudioContextType>(context_type),
+      types::AudioContexts(context_type)));
+
+  // Check if group has transitioned to a proper state
+  ASSERT_EQ(group->GetState(),
+            types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
+  ASSERT_EQ(2, mock_function_count_map["alarm_cancel"]);
+  testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_);
+  testing::Mock::VerifyAndClearExpectations(&gatt_queue);
+  testing::Mock::VerifyAndClearExpectations(&mock_callbacks_);
+}
+
 }  // namespace internal
 }  // namespace le_audio
diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index 6299237..b86486f 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -389,6 +389,124 @@
     cflags: ["-DBUILDCFG"],
 }
 
+cc_test {
+    name: "net_test_btif_hh",
+    host_supported: true,
+    defaults: [
+        "fluoride_defaults",
+        "mts_defaults",
+    ],
+    test_suites: ["device-tests"],
+    include_dirs: [
+        "frameworks/av/media/libaaudio/include",
+        "packages/modules/Bluetooth/system",
+        "packages/modules/Bluetooth/system/bta/dm",
+        "packages/modules/Bluetooth/system/bta/include",
+        "packages/modules/Bluetooth/system/bta/sys",
+        "packages/modules/Bluetooth/system/btif/avrcp",
+        "packages/modules/Bluetooth/system/btif/co",
+        "packages/modules/Bluetooth/system/btif/include",
+        "packages/modules/Bluetooth/system/device/include",
+        "packages/modules/Bluetooth/system/embdrv/sbc/decoder/include",
+        "packages/modules/Bluetooth/system/embdrv/sbc/encoder/include",
+        "packages/modules/Bluetooth/system/gd",
+        "packages/modules/Bluetooth/system/include",
+        "packages/modules/Bluetooth/system/internal_include",
+        "packages/modules/Bluetooth/system/stack/a2dp",
+        "packages/modules/Bluetooth/system/stack/avdt",
+        "packages/modules/Bluetooth/system/stack/btm",
+        "packages/modules/Bluetooth/system/stack/include",
+        "packages/modules/Bluetooth/system/stack/l2cap",
+        "packages/modules/Bluetooth/system/udrv/include",
+        "packages/modules/Bluetooth/system/utils/include",
+        "packages/modules/Bluetooth/system/vnd/include",
+        "system/libfmq/include",
+        "system/libhwbinder/include",
+        ],
+      srcs: [
+          ":LibBluetoothSources",
+          ":TestCommonMainHandler",
+          ":TestCommonMockFunctions",
+          ":TestMockAndroidHardware",
+          ":BtaDmSources",
+          ":TestMockBtaAg",
+          ":TestMockBtaAr",
+          ":TestMockBtaAv",
+          ":TestMockBtaCsis",
+          ":TestMockBtaGatt",
+          ":TestMockBtaGroups",
+          ":TestMockBtaHas",
+          ":TestMockBtaHd",
+          ":TestMockBtaHearingAid",
+          ":TestMockBtaHf",
+          ":TestMockBtaHh",
+          ":TestMockBtaJv",
+          ":TestMockBtaLeAudio",
+          ":TestMockBtaLeAudioHalVerifier",
+          ":TestMockBtaPan",
+          ":TestMockBtaSdp",
+          ":TestMockBtaSys",
+          ":TestMockBtaVc",
+          ":TestMockBtu",
+          ":TestMockBtcore",
+          ":TestMockCommon",
+          ":TestMockFrameworks",
+          ":TestMockHci",
+          ":TestMockMainShim",
+          ":TestMockOsi",
+          ":TestMockStack",
+          ":TestMockSystemLibfmq",
+          ":TestMockUdrv",
+          ":TestMockUtils",
+          "test/btif_hh_test.cc",
+      ],
+      generated_headers: [
+        "BluetoothGeneratedDumpsysDataSchema_h",
+        "BluetoothGeneratedPackets_h",
+      ],
+      header_libs: ["libbluetooth_headers"],
+      shared_libs: [
+          "android.hardware.bluetooth.audio@2.0",
+          "android.hardware.bluetooth.audio@2.1",
+          "libcrypto",
+          "libcutils",
+          "libhidlbase",
+          "liblog",
+          "libtinyxml2",
+      ],
+      whole_static_libs: [
+          "libbtif",
+      ],
+      static_libs: [
+          "android.hardware.bluetooth.a2dp@1.0",
+          "avrcp-target-service",
+          "libaudio-a2dp-hw-utils",
+          "libbluetooth-types",
+          "libbt-audio-hal-interface",
+          "libbt-stack",
+          "libbtdevice",
+          "lib-bt-packets",
+          "lib-bt-packets-avrcp",
+          "lib-bt-packets-base",
+          "libc++fs",
+          "libflatbuffers-cpp",
+          "libgmock",
+      ],
+      cflags: ["-DBUILDCFG"],
+      target: {
+          android: {
+              shared_libs: [
+                  "libbinder_ndk",
+                  "android.hardware.bluetooth.audio-V2-ndk",
+              ],
+          },
+      },
+      sanitize: {
+        address: true,
+        cfi: true,
+        misc_undefined: ["bounds"],
+    },
+}
 // Cycle stack test
 cc_test {
     name: "net_test_btif_stack",
diff --git a/system/btif/include/btif_sock.h b/system/btif/include/btif_sock.h
index cb0378e..494782e 100644
--- a/system/btif/include/btif_sock.h
+++ b/system/btif/include/btif_sock.h
@@ -18,11 +18,35 @@
 
 #pragma once
 
-#include "btif_uid.h"
-
 #include <hardware/bt_sock.h>
 
+#include "btif_uid.h"
+#include "types/raw_address.h"
+
+enum {
+  SOCKET_CONNECTION_STATE_UNKNOWN,
+  // Socket acts as a server waiting for connection
+  SOCKET_CONNECTION_STATE_LISTENING,
+  // Socket acts as a client trying to connect
+  SOCKET_CONNECTION_STATE_CONNECTING,
+  // Socket is connected
+  SOCKET_CONNECTION_STATE_CONNECTED,
+  // Socket tries to disconnect from remote
+  SOCKET_CONNECTION_STATE_DISCONNECTING,
+  // This socket is closed
+  SOCKET_CONNECTION_STATE_DISCONNECTED,
+};
+
+enum {
+  SOCKET_ROLE_UNKNOWN,
+  SOCKET_ROLE_LISTEN,
+  SOCKET_ROLE_CONNECTION,
+};
+
 const btsock_interface_t* btif_sock_get_interface(void);
 
 bt_status_t btif_sock_init(uid_set_t* uid_set);
 void btif_sock_cleanup(void);
+
+void btif_sock_connection_logger(int state, int role, const RawAddress& addr);
+void btif_sock_dump(int fd);
diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc
index 9a16712..9e089f7 100644
--- a/system/btif/src/bluetooth.cc
+++ b/system/btif/src/bluetooth.cc
@@ -58,6 +58,7 @@
 #include "bta/include/bta_le_audio_broadcaster_api.h"
 #include "bta/include/bta_vc_api.h"
 #include "btif/avrcp/avrcp_service.h"
+#include "btif/include/btif_sock.h"
 #include "btif/include/stack_manager.h"
 #include "btif_a2dp.h"
 #include "btif_activity_attribution.h"
@@ -434,6 +435,7 @@
   btif_debug_av_dump(fd);
   bta_debug_av_dump(fd);
   stack_debug_avdtp_api_dump(fd);
+  btif_sock_dump(fd);
   bluetooth::avrcp::AvrcpService::DebugDump(fd);
   btif_debug_config_dump(fd);
   BTA_HfClientDumpStatistics(fd);
diff --git a/system/btif/src/btif_config.cc b/system/btif/src/btif_config.cc
index 4b99365..a777ba8 100644
--- a/system/btif/src/btif_config.cc
+++ b/system/btif/src/btif_config.cc
@@ -112,7 +112,7 @@
     metrics_salt.fill(0);
   }
   if (!AddressObfuscator::IsSaltValid(metrics_salt)) {
-    LOG(INFO) << __func__ << ": Metrics salt is not invalid, creating new one";
+    LOG(INFO) << __func__ << ": Metrics salt is invalid, creating new one";
     if (RAND_bytes(metrics_salt.data(), metrics_salt.size()) != 1) {
       LOG(FATAL) << __func__ << "Failed to generate salt for metrics";
     }
diff --git a/system/btif/src/btif_gatt.cc b/system/btif/src/btif_gatt.cc
index d8076b0..2d0944f 100644
--- a/system/btif/src/btif_gatt.cc
+++ b/system/btif/src/btif_gatt.cc
@@ -55,6 +55,7 @@
  ******************************************************************************/
 static bt_status_t btif_gatt_init(const btgatt_callbacks_t* callbacks) {
   bt_gatt_callbacks = callbacks;
+  BTA_GATTS_InitBonded();
   return BT_STATUS_SUCCESS;
 }
 
diff --git a/system/btif/src/btif_gatt_util.cc b/system/btif/src/btif_gatt_util.cc
index 290c431..55788b0 100644
--- a/system/btif/src/btif_gatt_util.cc
+++ b/system/btif/src/btif_gatt_util.cc
@@ -36,6 +36,7 @@
 #include "btif_gatt.h"
 #include "btif_storage.h"
 #include "btif_util.h"
+#include "gd/os/system_properties.h"
 #include "osi/include/allocator.h"
 #include "osi/include/osi.h"
 #include "stack/btm/btm_sec.h"
@@ -75,6 +76,12 @@
 
 void btif_gatt_check_encrypted_link(RawAddress bd_addr,
                                     tBT_TRANSPORT transport_link) {
+  static const bool check_encrypted = bluetooth::os::GetSystemPropertyBool(
+      "bluetooth.gatt.check_encrypted_link.enabled", true);
+  if (!check_encrypted) {
+    LOG_DEBUG("Check skipped due to system config");
+    return;
+  }
   tBTM_LE_PENC_KEYS key;
   if ((btif_storage_get_ble_bonding_key(
            bd_addr, BTM_LE_KEY_PENC, (uint8_t*)&key,
diff --git a/system/btif/src/btif_hd.cc b/system/btif/src/btif_hd.cc
index 0d5b365..c41713a 100644
--- a/system/btif/src/btif_hd.cc
+++ b/system/btif/src/btif_hd.cc
@@ -32,10 +32,12 @@
 #include "bt_target.h"  // Must be first to define build configuration
 
 #include "bta/include/bta_hd_api.h"
+#include "bta/sys/bta_sys.h"
 #include "btif/include/btif_common.h"
 #include "btif/include/btif_hd.h"
 #include "btif/include/btif_storage.h"
 #include "btif/include/btif_util.h"
+#include "gd/common/init_flags.h"
 #include "include/hardware/bt_hd.h"
 #include "osi/include/allocator.h"
 #include "osi/include/compat.h"
@@ -162,6 +164,7 @@
       BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
       btif_hd_cb.status = BTIF_HD_DISABLED;
       if (btif_hd_cb.service_dereg_active) {
+        bta_sys_deregister(BTA_ID_HD);
         BTIF_TRACE_WARNING("registering hid host now");
         btif_hh_service_registration(TRUE);
         btif_hd_cb.service_dereg_active = FALSE;
@@ -181,6 +184,7 @@
         addr = NULL;
       }
 
+      LOG_INFO("Registering HID device app");
       btif_hd_cb.app_registered = TRUE;
       HAL_CBACK(bt_hd_callbacks, application_state_cb, addr,
                 BTHD_APP_STATE_REGISTERED);
@@ -192,7 +196,10 @@
                 BTHD_APP_STATE_NOT_REGISTERED);
       if (btif_hd_cb.service_dereg_active) {
         BTIF_TRACE_WARNING("disabling hid device service now");
-        btif_hd_free_buf();
+        if (!bluetooth::common::init_flags::
+                delay_hidh_cleanup_until_hidh_ready_start_is_enabled()) {
+          btif_hd_free_buf();
+        }
         BTA_HdDisable();
       }
       break;
diff --git a/system/btif/src/btif_hearing_aid.cc b/system/btif/src/btif_hearing_aid.cc
index 3b51ede..7820f42 100644
--- a/system/btif/src/btif_hearing_aid.cc
+++ b/system/btif/src/btif_hearing_aid.cc
@@ -85,30 +85,26 @@
 
   void Connect(const RawAddress& address) override {
     DVLOG(2) << __func__ << " address: " << address;
-    do_in_main_thread(FROM_HERE, Bind(&HearingAid::Connect,
-                                      Unretained(HearingAid::Get()), address));
+    do_in_main_thread(FROM_HERE, Bind(&HearingAid::Connect, address));
   }
 
   void Disconnect(const RawAddress& address) override {
     DVLOG(2) << __func__ << " address: " << address;
-    do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect,
-                                      Unretained(HearingAid::Get()), address));
+    do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect, address));
     do_in_jni_thread(FROM_HERE, Bind(&btif_storage_set_hearing_aid_acceptlist,
                                      address, false));
   }
 
   void AddToAcceptlist(const RawAddress& address) override {
     VLOG(2) << __func__ << " address: " << address;
-    do_in_main_thread(FROM_HERE, Bind(&HearingAid::AddToAcceptlist,
-                                      Unretained(HearingAid::Get()), address));
+    do_in_main_thread(FROM_HERE, Bind(&HearingAid::AddToAcceptlist, address));
     do_in_jni_thread(FROM_HERE, Bind(&btif_storage_set_hearing_aid_acceptlist,
                                      address, true));
   }
 
   void SetVolume(int8_t volume) override {
     DVLOG(2) << __func__ << " volume: " << +volume;
-    do_in_main_thread(FROM_HERE, Bind(&HearingAid::SetVolume,
-                                      Unretained(HearingAid::Get()), volume));
+    do_in_main_thread(FROM_HERE, Bind(&HearingAid::SetVolume, volume));
   }
 
   void RemoveDevice(const RawAddress& address) override {
@@ -116,9 +112,7 @@
 
     // RemoveDevice can be called on devices that don't have HA enabled
     if (HearingAid::IsHearingAidRunning()) {
-      do_in_main_thread(FROM_HERE,
-                        Bind(&HearingAid::Disconnect,
-                             Unretained(HearingAid::Get()), address));
+      do_in_main_thread(FROM_HERE, Bind(&HearingAid::Disconnect, address));
     }
 
     do_in_jni_thread(FROM_HERE,
diff --git a/system/btif/src/btif_hf_client.cc b/system/btif/src/btif_hf_client.cc
index 177ea7c..6ea3178 100644
--- a/system/btif/src/btif_hf_client.cc
+++ b/system/btif/src/btif_hf_client.cc
@@ -872,6 +872,7 @@
         cb->state = BTHF_CLIENT_CONNECTION_STATE_CONNECTED;
         cb->peer_feat = 0;
         cb->chld_feat = 0;
+        cb->handle = p_data->open.handle;
       } else if (cb->state == BTHF_CLIENT_CONNECTION_STATE_CONNECTING) {
         cb->state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
       } else {
@@ -917,6 +918,22 @@
       cb->peer_bda = RawAddress::kAny;
       cb->peer_feat = 0;
       cb->chld_feat = 0;
+      cb->handle = 0;
+
+      /* Clean up any btif_hf_client_cb for the same disconnected bd_addr.
+       * when there is an Incoming hf_client connection is in progress and
+       * at the same time, outgoing hf_client connection is initiated then
+       * due to race condition two btif_hf_client_cb is created. This creates
+       * problem for successive connections
+       */
+      while ((cb = btif_hf_client_get_cb_by_bda(p_data->bd_addr)) != NULL) {
+        cb->state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+        cb->peer_bda = RawAddress::kAny;
+        cb->peer_feat = 0;
+        cb->chld_feat = 0;
+        cb->handle = 0;
+      }
+
       btif_queue_advance();
       break;
 
diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc
index 3280a95..38986b9 100644
--- a/system/btif/src/btif_hh.cc
+++ b/system/btif/src/btif_hh.cc
@@ -538,6 +538,15 @@
        (btif_hh_cb.status == BTIF_HH_DEV_CONNECTING)) {
           btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
           btif_hh_cb.pending_conn_address = RawAddress::kEmpty;
+
+      /* need to notify up-layer device is disconnected to avoid
+       * state out of sync with up-layer */
+      do_in_jni_thread(base::Bind(
+            [](RawAddress bd_addrcb) {
+              HAL_CBACK(bt_hh_callbacks, connection_state_cb, &bd_addrcb,
+                        BTHH_CONN_STATE_DISCONNECTED);
+            },
+           *bd_addr));
     }
     return BT_STATUS_FAIL;
   }
diff --git a/system/btif/src/btif_rc.cc b/system/btif/src/btif_rc.cc
index 1b68326..937cb15 100644
--- a/system/btif/src/btif_rc.cc
+++ b/system/btif/src/btif_rc.cc
@@ -1959,6 +1959,11 @@
                    dump_rc_notification_event_id(event_id));
   std::unique_lock<std::mutex> lock(btif_rc_cb.lock);
 
+  if (event_id > MAX_RC_NOTIFICATIONS) {
+    BTIF_TRACE_ERROR("Invalid event id");
+    return BT_STATUS_PARM_INVALID;
+  }
+
   memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
 
   avrc_rsp.reg_notif.event_id = event_id;
diff --git a/system/btif/src/btif_sdp_server.cc b/system/btif/src/btif_sdp_server.cc
index 5bfd3e8..64dab16 100644
--- a/system/btif/src/btif_sdp_server.cc
+++ b/system/btif/src/btif_sdp_server.cc
@@ -287,6 +287,10 @@
 bt_status_t remove_sdp_record(int record_id) {
   int handle;
 
+  if (record_id >= MAX_SDP_SLOTS) {
+    return BT_STATUS_PARM_INVALID;
+  }
+
   bluetooth_sdp_record* record;
   bluetooth_sdp_types sdp_type = SDP_TYPE_RAW;
   {
@@ -349,9 +353,9 @@
   BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
   const sdp_slot_t* sdp_slot = start_create_sdp(id);
   tBTA_SERVICE_ID service_id = -1;
+  bluetooth_sdp_record* record;
   /* In the case we are shutting down, sdp_slot is NULL */
-  if (sdp_slot != NULL) {
-    bluetooth_sdp_record* record = sdp_slot->record_data;
+  if (sdp_slot != nullptr && (record = sdp_slot->record_data) != nullptr) {
     int handle = -1;
     switch (record->hdr.type) {
       case SDP_TYPE_MAP_MAS:
diff --git a/system/btif/src/btif_sock.cc b/system/btif/src/btif_sock.cc
index b945f4b..bcbce01 100644
--- a/system/btif/src/btif_sock.cc
+++ b/system/btif/src/btif_sock.cc
@@ -18,10 +18,13 @@
 
 #define LOG_TAG "bt_btif_sock"
 
+#include "btif/include/btif_sock.h"
+
 #include <base/logging.h>
 #include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
 #include <hardware/bluetooth.h>
 #include <hardware/bt_sock.h>
+#include <time.h>
 
 #include <atomic>
 
@@ -60,6 +63,22 @@
 static std::atomic_int thread_handle{-1};
 static thread_t* thread;
 
+#define SOCK_LOGGER_SIZE_MAX 16
+
+struct SockConnectionEvent {
+  bool used;
+  RawAddress addr;
+  int state;
+  int role;
+  struct timespec timestamp;
+
+  void dump(const int fd);
+};
+
+static std::atomic<uint8_t> logger_index;
+
+static SockConnectionEvent connection_logger[SOCK_LOGGER_SIZE_MAX];
+
 const btsock_interface_t* btif_sock_get_interface(void) {
   static btsock_interface_t interface = {
       sizeof(interface), btsock_listen, /* listen */
@@ -131,6 +150,88 @@
   thread = NULL;
 }
 
+void btif_sock_connection_logger(int state, int role, const RawAddress& addr) {
+  LOG_INFO("address=%s, role=%d, state=%d", addr.ToString().c_str(), state,
+           role);
+
+  uint8_t index = logger_index++ % SOCK_LOGGER_SIZE_MAX;
+
+  connection_logger[index] = {
+      .used = true,
+      .addr = addr,
+      .state = state,
+      .role = role,
+  };
+  clock_gettime(CLOCK_REALTIME, &connection_logger[index].timestamp);
+}
+
+void btif_sock_dump(int fd) {
+  dprintf(fd, "\nSocket Events: \n");
+  dprintf(fd, "  Time        \tAddress          \tState             \tRole\n");
+
+  const uint8_t head = logger_index.load() % SOCK_LOGGER_SIZE_MAX;
+
+  uint8_t index = head;
+  do {
+    connection_logger[index].dump(fd);
+
+    index++;
+    index %= SOCK_LOGGER_SIZE_MAX;
+  } while (index != head);
+  dprintf(fd, "\n");
+}
+
+void SockConnectionEvent::dump(const int fd) {
+  if (!used) {
+    return;
+  }
+
+  char eventtime[20];
+  char temptime[20];
+  struct tm* tstamp = localtime(&timestamp.tv_sec);
+  strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp);
+  snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime,
+           timestamp.tv_nsec / 1000000);
+
+  const char* str_state;
+  switch (state) {
+    case SOCKET_CONNECTION_STATE_LISTENING:
+      str_state = "STATE_LISTENING";
+      break;
+    case SOCKET_CONNECTION_STATE_CONNECTING:
+      str_state = "STATE_CONNECTING";
+      break;
+    case SOCKET_CONNECTION_STATE_CONNECTED:
+      str_state = "STATE_CONNECTED";
+      break;
+    case SOCKET_CONNECTION_STATE_DISCONNECTING:
+      str_state = "STATE_DISCONNECTING";
+      break;
+    case SOCKET_CONNECTION_STATE_DISCONNECTED:
+      str_state = "STATE_DISCONNECTED";
+      break;
+    default:
+      str_state = "STATE_UNKNOWN";
+      break;
+  }
+
+  const char* str_role;
+  switch (role) {
+    case SOCKET_ROLE_LISTEN:
+      str_role = "ROLE_LISTEN";
+      break;
+    case SOCKET_ROLE_CONNECTION:
+      str_role = "ROLE_CONNECTION";
+      break;
+    default:
+      str_role = "ROLE_UNKNOWN";
+      break;
+  }
+
+  dprintf(fd, "  %s\t%s\t%s   \t%s\n", eventtime,
+          addr.ToString().c_str(), str_state, str_role);
+}
+
 static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
                                  const Uuid* service_uuid, int channel,
                                  int* sock_fd, int flags, int app_uid) {
@@ -142,6 +243,8 @@
   bt_status_t status = BT_STATUS_FAIL;
   int original_channel = channel;
 
+  btif_sock_connection_logger(SOCKET_CONNECTION_STATE_LISTENING,
+                              SOCKET_ROLE_LISTEN, RawAddress::kEmpty);
   log_socket_connection_state(RawAddress::kEmpty, 0, type,
                               android::bluetooth::SocketConnectionstateEnum::
                                   SOCKET_CONNECTION_STATE_LISTENING,
@@ -183,6 +286,8 @@
       break;
   }
   if (status != BT_STATUS_SUCCESS) {
+    btif_sock_connection_logger(SOCKET_CONNECTION_STATE_DISCONNECTED,
+                                SOCKET_ROLE_LISTEN, RawAddress::kEmpty);
     log_socket_connection_state(RawAddress::kEmpty, 0, type,
                                 android::bluetooth::SocketConnectionstateEnum::
                                     SOCKET_CONNECTION_STATE_DISCONNECTED,
@@ -198,9 +303,13 @@
   CHECK(bd_addr != NULL);
   CHECK(sock_fd != NULL);
 
+  LOG_INFO("%s", __func__);
+
   *sock_fd = INVALID_FD;
   bt_status_t status = BT_STATUS_FAIL;
 
+  btif_sock_connection_logger(SOCKET_CONNECTION_STATE_CONNECTING,
+                              SOCKET_ROLE_CONNECTION, *bd_addr);
   log_socket_connection_state(*bd_addr, 0, type,
                               android::bluetooth::SocketConnectionstateEnum::
                                   SOCKET_CONNECTION_STATE_CONNECTING,
@@ -245,6 +354,8 @@
       break;
   }
   if (status != BT_STATUS_SUCCESS) {
+    btif_sock_connection_logger(SOCKET_CONNECTION_STATE_DISCONNECTED,
+                                SOCKET_ROLE_CONNECTION, *bd_addr);
     log_socket_connection_state(*bd_addr, 0, type,
                                 android::bluetooth::SocketConnectionstateEnum::
                                     SOCKET_CONNECTION_STATE_DISCONNECTED,
diff --git a/system/btif/src/btif_sock_l2cap.cc b/system/btif/src/btif_sock_l2cap.cc
index 9d5a5bd..8f42316 100644
--- a/system/btif/src/btif_sock_l2cap.cc
+++ b/system/btif/src/btif_sock_l2cap.cc
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+#include <base/logging.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/types.h>
@@ -24,6 +25,7 @@
 
 #include "bta/include/bta_jv_api.h"
 #include "btif/include/btif_metrics_logging.h"
+#include "btif/include/btif_sock.h"
 #include "btif/include/btif_sock_thread.h"
 #include "btif/include/btif_sock_util.h"
 #include "btif/include/btif_uid.h"
@@ -37,8 +39,6 @@
 #include "stack/include/bt_types.h"
 #include "types/raw_address.h"
 
-#include <base/logging.h>
-
 struct packet {
   struct packet *next, *prev;
   uint32_t len;
@@ -206,6 +206,10 @@
   if (!t) /* prever double-frees */
     return;
 
+  btif_sock_connection_logger(
+      SOCKET_CONNECTION_STATE_DISCONNECTED,
+      sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr);
+
   // Whenever a socket is freed, the connection must be dropped
   log_socket_connection_state(
       sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
@@ -389,6 +393,10 @@
 
   sock->handle = p_start->handle;
 
+  btif_sock_connection_logger(
+      SOCKET_CONNECTION_STATE_LISTENING,
+      sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr);
+
   log_socket_connection_state(
       sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
       android::bluetooth::SocketConnectionstateEnum::
@@ -452,6 +460,11 @@
   accept_rs->id = sock->id;
   sock->id = new_listen_id;
 
+  btif_sock_connection_logger(
+      SOCKET_CONNECTION_STATE_CONNECTED,
+      accept_rs->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+      accept_rs->addr);
+
   log_socket_connection_state(
       accept_rs->addr, accept_rs->id,
       accept_rs->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
@@ -492,6 +505,10 @@
     return;
   }
 
+  btif_sock_connection_logger(
+      SOCKET_CONNECTION_STATE_CONNECTED,
+      sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr);
+
   log_socket_connection_state(
       sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
       android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
@@ -544,6 +561,10 @@
     return;
   }
 
+  btif_sock_connection_logger(
+      SOCKET_CONNECTION_STATE_DISCONNECTING,
+      sock->server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, sock->addr);
+
   log_socket_connection_state(
       sock->addr, sock->id, sock->is_le_coc ? BTSOCK_L2CAP_LE : BTSOCK_L2CAP,
       android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTING, 0, 0,
diff --git a/system/btif/src/btif_sock_rfc.cc b/system/btif/src/btif_sock_rfc.cc
index 7452f86..0a6a26e 100644
--- a/system/btif/src/btif_sock_rfc.cc
+++ b/system/btif/src/btif_sock_rfc.cc
@@ -31,6 +31,7 @@
 #include "btif/include/btif_metrics_logging.h"
 /* The JV interface can have only one user, hence we need to call a few
  * L2CAP functions from this file. */
+#include "btif/include/btif_sock.h"
 #include "btif/include/btif_sock_l2cap.h"
 #include "btif/include/btif_sock_sdp.h"
 #include "btif/include/btif_sock_thread.h"
@@ -404,6 +405,10 @@
   if (slot->fd != INVALID_FD) {
     shutdown(slot->fd, SHUT_RDWR);
     close(slot->fd);
+    btif_sock_connection_logger(
+        SOCKET_CONNECTION_STATE_DISCONNECTED,
+        slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+        slot->addr);
     log_socket_connection_state(
         slot->addr, slot->id, BTSOCK_RFCOMM,
         android::bluetooth::SOCKET_CONNECTION_STATE_DISCONNECTED,
@@ -485,6 +490,10 @@
 
   if (p_start->status == BTA_JV_SUCCESS) {
     slot->rfc_handle = p_start->handle;
+    btif_sock_connection_logger(
+        SOCKET_CONNECTION_STATE_LISTENING,
+        slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+        slot->addr);
     log_socket_connection_state(
         slot->addr, slot->id, BTSOCK_RFCOMM,
         android::bluetooth::SocketConnectionstateEnum::
@@ -508,6 +517,10 @@
       srv_rs, &p_open->rem_bda, p_open->handle, p_open->new_listen_handle);
   if (!accept_rs) return 0;
 
+  btif_sock_connection_logger(
+      SOCKET_CONNECTION_STATE_CONNECTED,
+      accept_rs->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION,
+      accept_rs->addr);
   log_socket_connection_state(
       accept_rs->addr, accept_rs->id, BTSOCK_RFCOMM,
       android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
@@ -540,6 +553,9 @@
   slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
   slot->addr = p_open->rem_bda;
 
+  btif_sock_connection_logger(
+      SOCKET_CONNECTION_STATE_CONNECTED,
+      slot->f.server ? SOCKET_ROLE_LISTEN : SOCKET_ROLE_CONNECTION, slot->addr);
   log_socket_connection_state(
       slot->addr, slot->id, BTSOCK_RFCOMM,
       android::bluetooth::SOCKET_CONNECTION_STATE_CONNECTED, 0, 0,
diff --git a/system/btif/test/btif_hh_test.cc b/system/btif/test/btif_hh_test.cc
new file mode 100644
index 0000000..9c1fc9d
--- /dev/null
+++ b/system/btif/test/btif_hh_test.cc
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "btif/include/btif_hh.h"
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <array>
+#include <future>
+#include <vector>
+
+#include "bta/hh/bta_hh_int.h"
+#include "bta/include/bta_ag_api.h"
+#include "bta/include/bta_hh_api.h"
+#include "btcore/include/module.h"
+#include "btif/include/btif_api.h"
+#include "btif/include/stack_manager.h"
+#include "include/hardware/bt_hh.h"
+#include "test/common/mock_functions.h"
+#include "test/mock/mock_osi_allocator.h"
+
+using namespace std::chrono_literals;
+
+void set_hal_cbacks(bt_callbacks_t* callbacks);
+
+uint8_t appl_trace_level = BT_TRACE_LEVEL_DEBUG;
+uint8_t btif_trace_level = BT_TRACE_LEVEL_DEBUG;
+uint8_t btu_trace_level = BT_TRACE_LEVEL_DEBUG;
+
+module_t bt_utils_module;
+module_t gd_controller_module;
+module_t gd_idle_module;
+module_t gd_shim_module;
+module_t osi_module;
+
+const tBTA_AG_RES_DATA tBTA_AG_RES_DATA::kEmpty = {};
+
+extern void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data);
+extern const bthh_interface_t* btif_hh_get_interface();
+
+namespace test {
+namespace mock {
+extern bool bluetooth_shim_is_gd_stack_started_up;
+}
+}  // namespace test
+
+#if __GLIBC__
+size_t strlcpy(char* dst, const char* src, size_t siz) {
+  char* d = dst;
+  const char* s = src;
+  size_t n = siz;
+
+  /* Copy as many bytes as will fit */
+  if (n != 0) {
+    while (--n != 0) {
+      if ((*d++ = *s++) == '\0') break;
+    }
+  }
+
+  /* Not enough room in dst, add NUL and traverse rest of src */
+  if (n == 0) {
+    if (siz != 0) *d = '\0'; /* NUL-terminate dst */
+    while (*s++)
+      ;
+  }
+
+  return (s - src - 1); /* count does not include NUL */
+}
+
+pid_t gettid(void) throw() { return syscall(SYS_gettid); }
+#endif
+
+namespace {
+std::array<uint8_t, 32> data32 = {
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+    0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+    0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+};
+
+const RawAddress kDeviceAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
+const uint16_t kHhHandle = 123;
+
+// Callback parameters grouped into a structure
+struct get_report_cb_t {
+  RawAddress raw_address;
+  bthh_status_t status;
+  std::vector<uint8_t> data;
+} get_report_cb_;
+
+// Globals allow usage within function pointers
+std::promise<bt_cb_thread_evt> g_thread_evt_promise;
+std::promise<bt_status_t> g_status_promise;
+std::promise<get_report_cb_t> g_bthh_callbacks_get_report_promise;
+
+}  // namespace
+
+bt_callbacks_t bt_callbacks = {
+    .size = sizeof(bt_callbacks_t),
+    .adapter_state_changed_cb = nullptr,  // adapter_state_changed_callback
+    .adapter_properties_cb = nullptr,     // adapter_properties_callback
+    .remote_device_properties_cb =
+        nullptr,                            // remote_device_properties_callback
+    .device_found_cb = nullptr,             // device_found_callback
+    .discovery_state_changed_cb = nullptr,  // discovery_state_changed_callback
+    .pin_request_cb = nullptr,              // pin_request_callback
+    .ssp_request_cb = nullptr,              // ssp_request_callback
+    .bond_state_changed_cb = nullptr,       // bond_state_changed_callback
+    .address_consolidate_cb = nullptr,      // address_consolidate_callback
+    .le_address_associate_cb = nullptr,     // le_address_associate_callback
+    .acl_state_changed_cb = nullptr,        // acl_state_changed_callback
+    .thread_evt_cb = nullptr,               // callback_thread_event
+    .dut_mode_recv_cb = nullptr,            // dut_mode_recv_callback
+    .le_test_mode_cb = nullptr,             // le_test_mode_callback
+    .energy_info_cb = nullptr,              // energy_info_callback
+    .link_quality_report_cb = nullptr,      // link_quality_report_callback
+    .generate_local_oob_data_cb = nullptr,  // generate_local_oob_data_callback
+    .switch_buffer_size_cb = nullptr,       // switch_buffer_size_callback
+    .switch_codec_cb = nullptr,             // switch_codec_callback
+};
+
+bthh_callbacks_t bthh_callbacks = {
+    .size = sizeof(bthh_callbacks_t),
+    .connection_state_cb = nullptr,  // bthh_connection_state_callback
+    .hid_info_cb = nullptr,          // bthh_hid_info_callback
+    .protocol_mode_cb = nullptr,     // bthh_protocol_mode_callback
+    .idle_time_cb = nullptr,         // bthh_idle_time_callback
+    .get_report_cb = nullptr,        // bthh_get_report_callback
+    .virtual_unplug_cb = nullptr,    // bthh_virtual_unplug_callback
+    .handshake_cb = nullptr,         // bthh_handshake_callback
+};
+
+class BtifHhWithMockTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    reset_mock_function_count_map();
+    test::mock::osi_allocator::osi_malloc.body = [](size_t size) {
+      return malloc(size);
+    };
+    test::mock::osi_allocator::osi_calloc.body = [](size_t size) {
+      return calloc(1UL, size);
+    };
+    test::mock::osi_allocator::osi_free.body = [](void* ptr) { free(ptr); };
+    test::mock::osi_allocator::osi_free_and_reset.body = [](void** ptr) {
+      free(*ptr);
+      *ptr = nullptr;
+    };
+  }
+
+  void TearDown() override {
+    test::mock::osi_allocator::osi_malloc = {};
+    test::mock::osi_allocator::osi_calloc = {};
+    test::mock::osi_allocator::osi_free = {};
+    test::mock::osi_allocator::osi_free_and_reset = {};
+  }
+};
+
+class BtifHhWithHalCallbacksTest : public BtifHhWithMockTest {
+ protected:
+  void SetUp() override {
+    bluetooth::common::InitFlags::SetAllForTesting();
+    BtifHhWithMockTest::SetUp();
+    g_thread_evt_promise = std::promise<bt_cb_thread_evt>();
+    auto future = g_thread_evt_promise.get_future();
+    bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) {
+      g_thread_evt_promise.set_value(evt);
+    };
+    set_hal_cbacks(&bt_callbacks);
+    // Start the jni callback thread
+    ASSERT_EQ(BT_STATUS_SUCCESS, btif_init_bluetooth());
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+    ASSERT_EQ(ASSOCIATE_JVM, future.get());
+
+    bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) {};
+  }
+
+  void TearDown() override {
+    g_thread_evt_promise = std::promise<bt_cb_thread_evt>();
+    auto future = g_thread_evt_promise.get_future();
+    bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) {
+      g_thread_evt_promise.set_value(evt);
+    };
+    // Shutdown the jni callback thread
+    ASSERT_EQ(BT_STATUS_SUCCESS, btif_cleanup_bluetooth());
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+    ASSERT_EQ(DISASSOCIATE_JVM, future.get());
+
+    bt_callbacks.thread_evt_cb = [](bt_cb_thread_evt evt) {};
+    BtifHhWithMockTest::TearDown();
+  }
+};
+
+class BtifHhAdapterReady : public BtifHhWithHalCallbacksTest {
+ protected:
+  void SetUp() override {
+    BtifHhWithHalCallbacksTest::SetUp();
+    test::mock::bluetooth_shim_is_gd_stack_started_up = true;
+    ASSERT_EQ(BT_STATUS_SUCCESS,
+              btif_hh_get_interface()->init(&bthh_callbacks));
+  }
+
+  void TearDown() override {
+    test::mock::bluetooth_shim_is_gd_stack_started_up = false;
+    BtifHhWithHalCallbacksTest::TearDown();
+  }
+};
+
+class BtifHhWithDevice : public BtifHhAdapterReady {
+ protected:
+  void SetUp() override {
+    BtifHhAdapterReady::SetUp();
+
+    // Short circuit a connected device
+    btif_hh_cb.devices[0].bd_addr = kDeviceAddress;
+    btif_hh_cb.devices[0].dev_status = BTHH_CONN_STATE_CONNECTED;
+    btif_hh_cb.devices[0].dev_handle = kHhHandle;
+  }
+
+  void TearDown() override { BtifHhAdapterReady::TearDown(); }
+};
+
+TEST_F(BtifHhAdapterReady, lifecycle) {}
+
+TEST_F(BtifHhWithDevice, BTA_HH_GET_RPT_EVT) {
+  tBTA_HH data = {
+      .hs_data =
+          {
+              .status = BTA_HH_OK,
+              .handle = kHhHandle,
+              .rsp_data =
+                  {
+                      .p_rpt_data = static_cast<BT_HDR*>(
+                          osi_calloc(data32.size() + sizeof(BT_HDR))),
+                  },
+          },
+  };
+
+  // Fill out the deep copy data
+  data.hs_data.rsp_data.p_rpt_data->len = static_cast<uint16_t>(data32.size());
+  std::copy(data32.begin(), data32.begin() + data32.size(),
+            reinterpret_cast<uint8_t*>((data.hs_data.rsp_data.p_rpt_data + 1)));
+
+  g_bthh_callbacks_get_report_promise = std::promise<get_report_cb_t>();
+  auto future = g_bthh_callbacks_get_report_promise.get_future();
+  bthh_callbacks.get_report_cb = [](RawAddress* bd_addr,
+                                    bthh_status_t hh_status, uint8_t* rpt_data,
+                                    int rpt_size) {
+    get_report_cb_t report = {
+        .raw_address = *bd_addr,
+        .status = hh_status,
+        .data = std::vector<uint8_t>(),
+    };
+    report.data.assign(rpt_data, rpt_data + rpt_size),
+        g_bthh_callbacks_get_report_promise.set_value(report);
+  };
+
+  bte_hh_evt(BTA_HH_GET_RPT_EVT, &data);
+  osi_free(data.hs_data.rsp_data.p_rpt_data);
+
+  ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+  auto report = future.get();
+
+  // Verify data was delivered
+  ASSERT_STREQ(kDeviceAddress.ToString().c_str(),
+               report.raw_address.ToString().c_str());
+  ASSERT_EQ(BTHH_OK, report.status);
+  int i = 0;
+  for (const auto& data : data32) {
+    ASSERT_EQ(data, report.data[i++]);
+  }
+}
diff --git a/system/device/include/interop.h b/system/device/include/interop.h
index 0f1ff22..7b8eb1a 100644
--- a/system/device/include/interop.h
+++ b/system/device/include/interop.h
@@ -118,7 +118,14 @@
   INTEROP_SLC_SKIP_BIND_COMMAND,
 
   // Respond AVRCP profile version only 1.3 for some device.
-  INTEROP_AVRCP_1_3_ONLY
+  INTEROP_AVRCP_1_3_ONLY,
+
+  // Some remote devices have LMP version in[5.0, 5.2] but do not support
+  // robust
+  // caching or correctly response with an error. We disable the
+  // database hash
+  // lookup for such devices.
+  INTEROP_DISABLE_ROBUST_CACHING,
 } interop_feature_t;
 
 // Check if a given |addr| matches a known interoperability workaround as
diff --git a/system/device/include/interop_database.h b/system/device/include/interop_database.h
index 6f127e0..e055f43 100644
--- a/system/device/include/interop_database.h
+++ b/system/device/include/interop_database.h
@@ -195,6 +195,39 @@
 
     // BMW Carkit
     {{{0x00, 0x0a, 0x08, 0, 0, 0}}, 3, INTEROP_AVRCP_1_3_ONLY},
+
+    // Eero Wi-Fi Router
+    {{{0x08, 0x9b, 0xf1, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x20, 0xbe, 0xcd, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x30, 0x34, 0x22, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x3c, 0x5c, 0xf1, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x40, 0x47, 0x5e, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x50, 0x27, 0xa9, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x64, 0x97, 0x14, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x64, 0xc2, 0x69, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x68, 0x4a, 0x76, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x6c, 0xae, 0xf6, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x78, 0x76, 0x89, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x78, 0xd6, 0xd6, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x84, 0x70, 0xd7, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x98, 0xed, 0x7e, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x9c, 0x0b, 0x05, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x9c, 0x57, 0xbc, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0x9c, 0xa5, 0x70, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xa0, 0x8e, 0x24, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xac, 0xec, 0x85, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xb4, 0x20, 0x46, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xb4, 0xb9, 0xe6, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xc0, 0x36, 0x53, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xc4, 0xf1, 0x74, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xc8, 0xb8, 0x2f, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xc8, 0xe3, 0x06, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xd4, 0x05, 0xde, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xd4, 0x3f, 0x32, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xec, 0x74, 0x27, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xf0, 0x21, 0xe0, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xf0, 0xb6, 0x61, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
+    {{{0xfc, 0x3f, 0xa6, 0, 0, 0}}, 3, INTEROP_DISABLE_ROBUST_CACHING},
 };
 
 typedef struct {
diff --git a/system/device/src/interop.cc b/system/device/src/interop.cc
index 5cde30d..2024d7a 100644
--- a/system/device/src/interop.cc
+++ b/system/device/src/interop.cc
@@ -138,7 +138,8 @@
     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF)
     CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_SUSPEND)
     CASE_RETURN_STR(INTEROP_SLC_SKIP_BIND_COMMAND)
-    CASE_RETURN_STR(INTEROP_AVRCP_1_3_ONLY);
+    CASE_RETURN_STR(INTEROP_AVRCP_1_3_ONLY)
+    CASE_RETURN_STR(INTEROP_DISABLE_ROBUST_CACHING);
   }
 
   return "UNKNOWN";
diff --git a/system/gd/common/circular_buffer_test.cc b/system/gd/common/circular_buffer_test.cc
index dc238c2..9a2ef4e 100644
--- a/system/gd/common/circular_buffer_test.cc
+++ b/system/gd/common/circular_buffer_test.cc
@@ -68,6 +68,7 @@
 }
 
 TEST(CircularBufferTest, test_timestamps) {
+  timestamp_ = 0;
   bluetooth::common::TimestampedCircularBuffer<std::string> buffer(10, std::make_unique<TestTimestamper>());
 
   buffer.Push(std::string("One"));
diff --git a/system/gd/common/init_flags.fbs b/system/gd/common/init_flags.fbs
index b6dbe0a..0953465 100644
--- a/system/gd/common/init_flags.fbs
+++ b/system/gd/common/init_flags.fbs
@@ -16,7 +16,8 @@
     btaa_hci_is_enabled:bool (privacy:"Any");
     bta_dm_clear_conn_id_on_client_close_is_enabled:bool (privacy:"Any");
     btm_dm_flush_discovery_queue_on_search_cancel_is_enabled:bool (privacy:"Any");
-    finite_att_timeout_is_enabled:bool (privacy:"Any");
+    clear_hidd_interrupt_cid_on_disconnect_is_enabled:bool (privacy:"Any");
+    delay_hidh_cleanup_until_hidh_ready_start_is_enabled:bool (privacy:"Any");
     gatt_robust_caching_client_is_enabled:bool (privacy:"Any");
     gatt_robust_caching_server_is_enabled:bool (privacy:"Any");
     gd_core_is_enabled:bool (privacy:"Any");
diff --git a/system/gd/common/interfaces/ILoggable.h b/system/gd/common/interfaces/ILoggable.h
new file mode 100644
index 0000000..ad2b8ab
--- /dev/null
+++ b/system/gd/common/interfaces/ILoggable.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright 2022 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <string>
+
+namespace bluetooth {
+namespace common {
+
+class ILoggable {
+ public:
+  // the interface for
+  // converting an object to a string for feeding to loggers
+  // e.g.. logcat
+  virtual std::string ToStringForLogging() const = 0;
+  virtual ~ILoggable() = default;
+};
+
+class IRedactableLoggable : public ILoggable {
+ public:
+  // the interface for
+  // converting an object to a string with sensitive info redacted
+  // to avoid violating privacy
+  virtual std::string ToRedactedStringForLogging() const = 0;
+  virtual ~IRedactableLoggable() = default;
+};
+
+}  // namespace common
+}  // namespace bluetooth
diff --git a/system/gd/common/testing/host/log_capture_test.cc b/system/gd/common/testing/host/log_capture_test.cc
index cbd6a1c..320b4fe 100644
--- a/system/gd/common/testing/host/log_capture_test.cc
+++ b/system/gd/common/testing/host/log_capture_test.cc
@@ -62,7 +62,8 @@
   ASSERT_TRUE(log_capture->Size() == 0);
 }
 
-TEST_F(LogCaptureTest, truncate) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_truncate) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   CalibrateOneLine(kLogError);
@@ -76,7 +77,8 @@
   ASSERT_EQ(size, log_capture->Size());
 }
 
-TEST_F(LogCaptureTest, log_size) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_log_size) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   CalibrateOneLine(kEmptyLine);
@@ -101,7 +103,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find(kLogInfo));
 }
 
-TEST_F(LogCaptureTest, typical) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_typical) {
   bluetooth::common::InitFlags::Load(nullptr);
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
@@ -118,7 +121,8 @@
   ASSERT_FALSE(log_capture->Rewind()->Find(kLogVerbose));
 }
 
-TEST_F(LogCaptureTest, with_logging_debug_enabled_for_all) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_with_logging_debug_enabled_for_all) {
   bluetooth::common::InitFlags::Load(test_flags);
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
@@ -136,7 +140,8 @@
   bluetooth::common::InitFlags::Load(nullptr);
 }
 
-TEST_F(LogCaptureTest, wait_until_log_contains) {
+// b/260917913
+TEST_F(LogCaptureTest, DISABLED_wait_until_log_contains) {
   bluetooth::common::InitFlags::Load(test_flags);
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
diff --git a/system/gd/dumpsys/bundler/Android.bp b/system/gd/dumpsys/bundler/Android.bp
index 3754611..41f5549 100644
--- a/system/gd/dumpsys/bundler/Android.bp
+++ b/system/gd/dumpsys/bundler/Android.bp
@@ -69,9 +69,8 @@
     ],
 }
 
-cc_test {
+cc_test_host {
     name: "bluetooth_flatbuffer_bundler_test",
-    host_supported: true,
     srcs: [
         ":BluetoothFlatbufferBundlerTestSources",
     ],
diff --git a/system/gd/dumpsys/init_flags.cc b/system/gd/dumpsys/init_flags.cc
index 08d3bf9..0bf3cd0 100644
--- a/system/gd/dumpsys/init_flags.cc
+++ b/system/gd/dumpsys/init_flags.cc
@@ -39,8 +39,10 @@
       initFlags::bta_dm_clear_conn_id_on_client_close_is_enabled());
   builder.add_btm_dm_flush_discovery_queue_on_search_cancel_is_enabled(
       initFlags::btm_dm_flush_discovery_queue_on_search_cancel_is_enabled());
-  builder.add_finite_att_timeout_is_enabled(initFlags::finite_att_timeout_is_enabled());
-  builder.add_gatt_robust_caching_client_is_enabled(initFlags::gatt_robust_caching_client_is_enabled());
+  builder.add_clear_hidd_interrupt_cid_on_disconnect_is_enabled(
+      initFlags::clear_hidd_interrupt_cid_on_disconnect_is_enabled());
+  builder.add_delay_hidh_cleanup_until_hidh_ready_start_is_enabled(
+      initFlags::delay_hidh_cleanup_until_hidh_ready_start_is_enabled());
   builder.add_gatt_robust_caching_server_is_enabled(initFlags::gatt_robust_caching_server_is_enabled());
   builder.add_gd_core_is_enabled(initFlags::gd_core_is_enabled());
   builder.add_gd_l2cap_is_enabled(initFlags::gd_l2cap_is_enabled());
diff --git a/system/gd/hal/snoop_logger.cc b/system/gd/hal/snoop_logger.cc
index 1b03033..e3b585c 100644
--- a/system/gd/hal/snoop_logger.cc
+++ b/system/gd/hal/snoop_logger.cc
@@ -193,6 +193,7 @@
 }  // namespace
 
 const std::string SnoopLogger::kBtSnoopLogModeDisabled = "disabled";
+const std::string SnoopLogger::kBtSnoopLogModeTruncated = "truncated";
 const std::string SnoopLogger::kBtSnoopLogModeFiltered = "filtered";
 const std::string SnoopLogger::kBtSnoopLogModeFull = "full";
 const std::string SnoopLogger::kSoCManufacturerQualcomm = "Qualcomm";
@@ -203,6 +204,10 @@
 const std::string SnoopLogger::kBtSnoopDefaultLogModeProperty = "persist.bluetooth.btsnoopdefaultmode";
 const std::string SnoopLogger::kSoCManufacturerProperty = "ro.soc.manufacturer";
 
+// The max ACL packet size (in bytes) in truncated logging mode. All information
+// past this point is truncated from a packet.
+static constexpr uint32_t kMaxTruncatedAclPacketSize = 100;
+
 SnoopLogger::SnoopLogger(
     std::string snoop_log_path,
     std::string snooz_log_path,
@@ -236,6 +241,15 @@
     delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, true));
     // delete snooz logs
     delete_btsnoop_files(snooz_log_path_);
+  } else if (btsnoop_mode == kBtSnoopLogModeTruncated) {
+    LOG_INFO("Snoop Logs truncated. Limiting to %u", kMaxTruncatedAclPacketSize);
+    is_enabled_ = true;
+    is_truncated_ = true;
+    is_filtered_ = false;
+    // delete filtered logs
+    delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, true));
+    // delete snooz logs
+    delete_btsnoop_files(snooz_log_path_);
   } else {
     LOG_INFO("Snoop Logs disabled");
     is_enabled_ = false;
@@ -320,6 +334,9 @@
                              .dropped_packets = 0,
                              .timestamp = htonll(timestamp_us + kBtSnoopEpochDelta),
                              .type = static_cast<uint8_t>(type)};
+  if (is_truncated_ && type == PacketType::ACL) {
+    header.length_captured = htonl(std::min(length, kMaxTruncatedAclPacketSize));
+  }
   {
     std::lock_guard<std::recursive_mutex> lock(file_mutex_);
     if (!is_enabled_) {
@@ -445,9 +462,8 @@
 size_t SnoopLogger::GetMaxPacketsPerBuffer() {
   // We want to use at most 256 KB memory for btsnooz log for release builds
   // and 512 KB memory for userdebug/eng builds
-  auto is_debuggable = os::GetSystemProperty(kIsDebuggableProperty);
-  size_t btsnooz_max_memory_usage_bytes =
-      ((is_debuggable.has_value() && common::StringTrim(is_debuggable.value()) == "1") ? 1024 : 256) * 1024;
+  auto is_debuggable = os::GetSystemPropertyBool(kIsDebuggableProperty, false);
+  size_t btsnooz_max_memory_usage_bytes = (is_debuggable ? 1024 : 256) * 1024;
   // Calculate max number of packets based on max memory usage and max packet size
   return btsnooz_max_memory_usage_bytes / kDefaultBtSnoozMaxBytesPerPacket;
 }
@@ -457,8 +473,8 @@
   // In userdebug/eng build, it can also be overwritten by modifying the global setting
   std::string default_mode = kBtSnoopLogModeDisabled;
   {
-    auto is_debuggable = os::GetSystemProperty(kIsDebuggableProperty);
-    if (is_debuggable.has_value() && common::StringTrim(is_debuggable.value()) == "1") {
+    auto is_debuggable = os::GetSystemPropertyBool(kIsDebuggableProperty, false);
+    if (is_debuggable) {
       auto default_mode_property = os::GetSystemProperty(kBtSnoopDefaultLogModeProperty);
       if (default_mode_property) {
         default_mode = std::move(default_mode_property.value());
diff --git a/system/gd/hal/snoop_logger.h b/system/gd/hal/snoop_logger.h
index 7fa65aa..f879798 100644
--- a/system/gd/hal/snoop_logger.h
+++ b/system/gd/hal/snoop_logger.h
@@ -38,6 +38,7 @@
   static const ModuleFactory Factory;
 
   static const std::string kBtSnoopLogModeDisabled;
+  static const std::string kBtSnoopLogModeTruncated;
   static const std::string kBtSnoopLogModeFiltered;
   static const std::string kBtSnoopLogModeFull;
   static const std::string kSoCManufacturerQualcomm;
@@ -124,6 +125,7 @@
   std::ofstream btsnoop_ostream_;
   bool is_enabled_ = false;
   bool is_filtered_ = false;
+  bool is_truncated_ = false;
   size_t max_packets_per_file_;
   common::CircularBuffer<std::string> btsnooz_buffer_;
   bool qualcomm_debug_log_enabled_ = false;
diff --git a/system/gd/hci/Android.bp b/system/gd/hci/Android.bp
index ae026fc..3dad0d6 100644
--- a/system/gd/hci/Android.bp
+++ b/system/gd/hci/Android.bp
@@ -33,32 +33,25 @@
 filegroup {
     name: "BluetoothHciUnitTestSources",
     srcs: [
-        "acl_manager/le_impl_test.cc",
         "acl_builder_test.cc",
+        "acl_manager_test.cc",
         "acl_manager_unittest.cc",
+        "acl_manager/classic_acl_connection_test.cc",
+        "acl_manager/le_impl_test.cc",
+        "acl_manager/round_robin_scheduler_test.cc",
         "address_unittest.cc",
         "address_with_type_test.cc",
         "class_of_device_unittest.cc",
         "controller_test.cc",
         "hci_layer_fake.cc",
+        "hci_layer_test.cc",
         "hci_layer_unittest.cc",
         "hci_packets_test.cc",
         "uuid_unittest.cc",
         "le_periodic_sync_manager_test.cc",
         "le_scanning_manager_test.cc",
         "le_advertising_manager_test.cc",
-    ],
-}
-
-filegroup {
-    name: "BluetoothHciTestSources",
-    srcs: [
-        "acl_manager/round_robin_scheduler_test.cc",
-        "acl_manager_test.cc",
-        "hci_layer_test.cc",
         "le_address_manager_test.cc",
-        "le_advertising_manager_test.cc",
-        "le_scanning_manager_test.cc",
     ],
 }
 
diff --git a/system/gd/hci/acl_manager/classic_acl_connection_test.cc b/system/gd/hci/acl_manager/classic_acl_connection_test.cc
new file mode 100644
index 0000000..9ba38c9
--- /dev/null
+++ b/system/gd/hci/acl_manager/classic_acl_connection_test.cc
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hci/acl_manager/classic_acl_connection.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <cstdint>
+#include <future>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <vector>
+
+#include "hci/acl_connection_interface.h"
+#include "hci/acl_manager/connection_management_callbacks.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "os/thread.h"
+
+using namespace bluetooth;
+using namespace std::chrono_literals;
+
+namespace {
+constexpr char kAddress[] = "00:11:22:33:44:55";
+constexpr uint16_t kConnectionHandle = 123;
+constexpr size_t kQueueSize = 10;
+
+std::vector<hci::DisconnectReason> disconnect_reason_vector = {
+    hci::DisconnectReason::AUTHENTICATION_FAILURE,
+    hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION,
+    hci::DisconnectReason::REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES,
+    hci::DisconnectReason::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF,
+    hci::DisconnectReason::UNSUPPORTED_REMOTE_FEATURE,
+    hci::DisconnectReason::PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED,
+    hci::DisconnectReason::UNACCEPTABLE_CONNECTION_PARAMETERS,
+};
+
+std::vector<hci::ErrorCode> error_code_vector = {
+    hci::ErrorCode::SUCCESS,
+    hci::ErrorCode::UNKNOWN_HCI_COMMAND,
+    hci::ErrorCode::UNKNOWN_CONNECTION,
+    hci::ErrorCode::HARDWARE_FAILURE,
+    hci::ErrorCode::PAGE_TIMEOUT,
+    hci::ErrorCode::AUTHENTICATION_FAILURE,
+    hci::ErrorCode::PIN_OR_KEY_MISSING,
+    hci::ErrorCode::MEMORY_CAPACITY_EXCEEDED,
+    hci::ErrorCode::CONNECTION_TIMEOUT,
+    hci::ErrorCode::CONNECTION_LIMIT_EXCEEDED,
+    hci::ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED,
+    hci::ErrorCode::CONNECTION_ALREADY_EXISTS,
+    hci::ErrorCode::COMMAND_DISALLOWED,
+    hci::ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES,
+    hci::ErrorCode::CONNECTION_REJECTED_SECURITY_REASONS,
+    hci::ErrorCode::CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR,
+    hci::ErrorCode::CONNECTION_ACCEPT_TIMEOUT,
+    hci::ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE,
+    hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS,
+    hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION,
+    hci::ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES,
+    hci::ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF,
+    hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST,
+    hci::ErrorCode::REPEATED_ATTEMPTS,
+    hci::ErrorCode::PAIRING_NOT_ALLOWED,
+    hci::ErrorCode::UNKNOWN_LMP_PDU,
+    hci::ErrorCode::UNSUPPORTED_REMOTE_OR_LMP_FEATURE,
+    hci::ErrorCode::SCO_OFFSET_REJECTED,
+    hci::ErrorCode::SCO_INTERVAL_REJECTED,
+    hci::ErrorCode::SCO_AIR_MODE_REJECTED,
+    hci::ErrorCode::INVALID_LMP_OR_LL_PARAMETERS,
+    hci::ErrorCode::UNSPECIFIED_ERROR,
+    hci::ErrorCode::UNSUPPORTED_LMP_OR_LL_PARAMETER,
+    hci::ErrorCode::ROLE_CHANGE_NOT_ALLOWED,
+    hci::ErrorCode::TRANSACTION_RESPONSE_TIMEOUT,
+    hci::ErrorCode::LINK_LAYER_COLLISION,
+    hci::ErrorCode::ENCRYPTION_MODE_NOT_ACCEPTABLE,
+    hci::ErrorCode::ROLE_SWITCH_FAILED,
+    hci::ErrorCode::CONTROLLER_BUSY,
+    hci::ErrorCode::ADVERTISING_TIMEOUT,
+    hci::ErrorCode::CONNECTION_FAILED_ESTABLISHMENT,
+    hci::ErrorCode::LIMIT_REACHED,
+    hci::ErrorCode::STATUS_UNKNOWN,
+};
+
+// Generic template for all commands
+template <typename T, typename U>
+T CreateCommand(U u) {
+  T command;
+  return command;
+}
+
+template <>
+hci::DisconnectView CreateCommand(std::shared_ptr<std::vector<uint8_t>> bytes) {
+  return hci::DisconnectView::Create(
+      hci::AclCommandView::Create(hci::CommandView::Create(hci::PacketView<hci::kLittleEndian>(bytes))));
+}
+
+}  // namespace
+
+class TestAclConnectionInterface : public hci::AclConnectionInterface {
+ private:
+  void EnqueueCommand(
+      std::unique_ptr<hci::AclCommandBuilder> command,
+      common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) override {
+    const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+    command_queue_.push(std::move(command));
+    command_status_callbacks.push_back(std::move(on_status));
+    if (command_promise_ != nullptr) {
+      std::promise<void>* prom = command_promise_.release();
+      prom->set_value();
+      delete prom;
+    }
+  }
+
+  void EnqueueCommand(
+      std::unique_ptr<hci::AclCommandBuilder> command,
+      common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) override {
+    const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+    command_queue_.push(std::move(command));
+    command_complete_callbacks.push_back(std::move(on_complete));
+    if (command_promise_ != nullptr) {
+      std::promise<void>* prom = command_promise_.release();
+      prom->set_value();
+      delete prom;
+    }
+  }
+
+ public:
+  virtual ~TestAclConnectionInterface() = default;
+
+  std::unique_ptr<hci::CommandBuilder> DequeueCommand() {
+    const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+    auto packet = std::move(command_queue_.front());
+    command_queue_.pop();
+    return std::move(packet);
+  }
+
+  std::shared_ptr<std::vector<uint8_t>> DequeueCommandBytes() {
+    auto command = DequeueCommand();
+    auto bytes = std::make_shared<std::vector<uint8_t>>();
+    packet::BitInserter bi(*bytes);
+    command->Serialize(bi);
+    return bytes;
+  }
+
+  bool IsPacketQueueEmpty() const {
+    const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+    return command_queue_.empty();
+  }
+
+  size_t NumberOfQueuedCommands() const {
+    const std::lock_guard<std::mutex> lock(command_queue_mutex_);
+    return command_queue_.size();
+  }
+
+ private:
+  std::list<common::ContextualOnceCallback<void(hci::CommandCompleteView)>> command_complete_callbacks;
+  std::list<common::ContextualOnceCallback<void(hci::CommandStatusView)>> command_status_callbacks;
+  std::queue<std::unique_ptr<hci::CommandBuilder>> command_queue_;
+  mutable std::mutex command_queue_mutex_;
+  std::unique_ptr<std::promise<void>> command_promise_;
+  std::unique_ptr<std::future<void>> command_future_;
+};
+
+class TestConnectionManagementCallbacks : public hci::acl_manager::ConnectionManagementCallbacks {
+ public:
+  ~TestConnectionManagementCallbacks() = default;
+  void OnConnectionPacketTypeChanged(uint16_t packet_type) override {}
+  void OnAuthenticationComplete(hci::ErrorCode hci_status) override {}
+  void OnEncryptionChange(hci::EncryptionEnabled enabled) override {}
+  void OnChangeConnectionLinkKeyComplete() override {}
+  void OnReadClockOffsetComplete(uint16_t clock_offset) override {}
+  void OnModeChange(hci::ErrorCode status, hci::Mode current_mode, uint16_t interval) override {}
+  void OnSniffSubrating(
+      hci::ErrorCode hci_status,
+      uint16_t maximum_transmit_latency,
+      uint16_t maximum_receive_latency,
+      uint16_t minimum_remote_timeout,
+      uint16_t minimum_local_timeout) override {}
+  void OnQosSetupComplete(
+      hci::ServiceType service_type,
+      uint32_t token_rate,
+      uint32_t peak_bandwidth,
+      uint32_t latency,
+      uint32_t delay_variation) override {}
+  void OnFlowSpecificationComplete(
+      hci::FlowDirection flow_direction,
+      hci::ServiceType service_type,
+      uint32_t token_rate,
+      uint32_t token_bucket_size,
+      uint32_t peak_bandwidth,
+      uint32_t access_latency) override {}
+  void OnFlushOccurred() override {}
+  void OnRoleDiscoveryComplete(hci::Role current_role) override {}
+  void OnReadLinkPolicySettingsComplete(uint16_t link_policy_settings) override {}
+  void OnReadAutomaticFlushTimeoutComplete(uint16_t flush_timeout) override {}
+  void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) override {}
+  void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) override {}
+  void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) override {}
+  void OnReadLinkQualityComplete(uint8_t link_quality) override {}
+  void OnReadAfhChannelMapComplete(hci::AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map) override {}
+  void OnReadRssiComplete(uint8_t rssi) override {}
+  void OnReadClockComplete(uint32_t clock, uint16_t accuracy) override {}
+  void OnCentralLinkKeyComplete(hci::KeyFlag key_flag) override {}
+  void OnRoleChange(hci::ErrorCode hci_status, hci::Role new_role) override {}
+  void OnDisconnection(hci::ErrorCode reason) override {
+    on_disconnection_error_code_queue_.push(reason);
+  }
+  void OnReadRemoteVersionInformationComplete(
+      hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override {}
+  void OnReadRemoteSupportedFeaturesComplete(uint64_t features) override {}
+  void OnReadRemoteExtendedFeaturesComplete(uint8_t page_number, uint8_t max_page_number, uint64_t features) override {}
+
+  std::queue<hci::ErrorCode> on_disconnection_error_code_queue_;
+};
+
+namespace bluetooth {
+namespace hci {
+namespace acl_manager {
+
+class ClassicAclConnectionTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_TRUE(hci::Address::FromString(kAddress, address_));
+    thread_ = new os::Thread("thread", os::Thread::Priority::NORMAL);
+    handler_ = new os::Handler(thread_);
+    queue_ = std::make_shared<hci::acl_manager::AclConnection::Queue>(kQueueSize);
+    sync_handler();
+  }
+
+  void TearDown() override {
+    handler_->Clear();
+    delete handler_;
+    delete thread_;
+  }
+
+  void sync_handler() {
+    ASSERT(handler_ != nullptr);
+
+    auto promise = std::promise<void>();
+    auto future = promise.get_future();
+    handler_->BindOnceOn(&promise, &std::promise<void>::set_value).Invoke();
+    auto status = future.wait_for(2s);
+    ASSERT_EQ(status, std::future_status::ready);
+  }
+
+  Address address_;
+  os::Handler* handler_{nullptr};
+  os::Thread* thread_{nullptr};
+  std::shared_ptr<hci::acl_manager::AclConnection::Queue> queue_;
+
+  TestAclConnectionInterface acl_connection_interface_;
+  TestConnectionManagementCallbacks callbacks_;
+};
+
+TEST_F(ClassicAclConnectionTest, simple) {
+  AclConnectionInterface* acl_connection_interface = nullptr;
+  ClassicAclConnection* connection =
+      new ClassicAclConnection(queue_, acl_connection_interface, kConnectionHandle, address_);
+  connection->RegisterCallbacks(&callbacks_, handler_);
+
+  delete connection;
+}
+
+class ClassicAclConnectionWithCallbacksTest : public ClassicAclConnectionTest {
+ protected:
+  void SetUp() override {
+    ClassicAclConnectionTest::SetUp();
+    connection_ =
+        std::make_unique<ClassicAclConnection>(queue_, &acl_connection_interface_, kConnectionHandle, address_);
+    connection_->RegisterCallbacks(&callbacks_, handler_);
+    is_callbacks_registered_ = true;
+    connection_management_callbacks_ =
+        connection_->GetEventCallbacks([this](uint16_t hci_handle) { is_callbacks_invalidated_ = true; });
+    is_callbacks_invalidated_ = false;
+  }
+
+  void TearDown() override {
+    connection_.reset();
+    ASSERT_TRUE(is_callbacks_invalidated_);
+    ClassicAclConnectionTest::TearDown();
+  }
+
+ protected:
+  std::unique_ptr<ClassicAclConnection> connection_;
+  ConnectionManagementCallbacks* connection_management_callbacks_;
+  bool is_callbacks_registered_{false};
+  bool is_callbacks_invalidated_{false};
+};
+
+TEST_F(ClassicAclConnectionWithCallbacksTest, Disconnect) {
+  for (const auto& reason : disconnect_reason_vector) {
+    ASSERT_TRUE(connection_->Disconnect(reason));
+  }
+
+  for (const auto& reason : disconnect_reason_vector) {
+    ASSERT_FALSE(acl_connection_interface_.IsPacketQueueEmpty());
+    auto command = CreateCommand<DisconnectView>(acl_connection_interface_.DequeueCommandBytes());
+    ASSERT_TRUE(command.IsValid());
+    ASSERT_EQ(reason, command.GetReason());
+    ASSERT_EQ(kConnectionHandle, command.GetConnectionHandle());
+  }
+  ASSERT_TRUE(acl_connection_interface_.IsPacketQueueEmpty());
+}
+
+TEST_F(ClassicAclConnectionWithCallbacksTest, OnDisconnection) {
+  for (const auto& error_code : error_code_vector) {
+    connection_management_callbacks_->OnDisconnection(error_code);
+  }
+
+  sync_handler();
+  ASSERT_TRUE(!callbacks_.on_disconnection_error_code_queue_.empty());
+
+  for (const auto& error_code : error_code_vector) {
+    ASSERT_EQ(error_code, callbacks_.on_disconnection_error_code_queue_.front());
+    callbacks_.on_disconnection_error_code_queue_.pop();
+  }
+}
+
+}  // namespace acl_manager
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/system/gd/hci/acl_manager/le_impl_test.cc b/system/gd/hci/acl_manager/le_impl_test.cc
index ca9d022..d84f95b 100644
--- a/system/gd/hci/acl_manager/le_impl_test.cc
+++ b/system/gd/hci/acl_manager/le_impl_test.cc
@@ -62,12 +62,14 @@
 [[maybe_unused]] constexpr bool kSkipFilterAcceptList = !kAddToFilterAcceptList;
 [[maybe_unused]] constexpr bool kIsDirectConnection = true;
 [[maybe_unused]] constexpr bool kIsBackgroundConnection = !kIsDirectConnection;
-constexpr ::bluetooth::crypto_toolbox::Octet16 kRotationIrk = {};
+constexpr crypto_toolbox::Octet16 kRotationIrk = {};
 constexpr std::chrono::milliseconds kMinimumRotationTime(14 * 1000);
 constexpr std::chrono::milliseconds kMaximumRotationTime(16 * 1000);
-constexpr uint16_t kIntervalMin = 0x20;
 constexpr uint16_t kIntervalMax = 0x40;
+constexpr uint16_t kIntervalMin = 0x20;
 constexpr uint16_t kLatency = 0x60;
+constexpr uint16_t kLength = 0x5678;
+constexpr uint16_t kTime = 0x1234;
 constexpr uint16_t kTimeout = 0x80;
 constexpr std::array<uint8_t, 16> kPeerIdentityResolvingKey({
     0x00,
@@ -106,11 +108,12 @@
     0x8f,
 });
 
-// Generic template for all commands
-template <typename T, typename U>
-T CreateCommand(U u) {
-  T command;
-  return command;
+template <typename B>
+std::shared_ptr<std::vector<uint8_t>> Serialize(std::unique_ptr<B> build) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter bi(*bytes);
+  build->Serialize(bi);
+  return bytes;
 }
 
 template <typename T>
@@ -140,20 +143,16 @@
 
 [[maybe_unused]] hci::CommandCompleteView ReturnCommandComplete(hci::OpCode op_code, hci::ErrorCode error_code) {
   std::vector<uint8_t> success_vector{static_cast<uint8_t>(error_code)};
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter bi(*bytes);
   auto builder = hci::CommandCompleteBuilder::Create(uint8_t{1}, op_code, std::make_unique<RawBuilder>(success_vector));
-  builder->Serialize(bi);
+  auto bytes = Serialize<hci::CommandCompleteBuilder>(std::move(builder));
   return hci::CommandCompleteView::Create(hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
 }
 
 [[maybe_unused]] hci::CommandStatusView ReturnCommandStatus(hci::OpCode op_code, hci::ErrorCode error_code) {
   std::vector<uint8_t> success_vector{static_cast<uint8_t>(error_code)};
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter bi(*bytes);
   auto builder = hci::CommandStatusBuilder::Create(
       hci::ErrorCode::SUCCESS, uint8_t{1}, op_code, std::make_unique<RawBuilder>(success_vector));
-  builder->Serialize(bi);
+  auto bytes = Serialize<hci::CommandStatusBuilder>(std::move(builder));
   return hci::CommandStatusView::Create(hci::EventView::Create(hci::PacketView<hci::kLittleEndian>(bytes)));
 }
 
@@ -256,8 +255,9 @@
     command_queue_.push(std::move(command));
     command_status_callbacks.push_back(std::move(on_status));
     if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
+      std::promise<void>* prom = command_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
@@ -268,8 +268,9 @@
     command_queue_.push(std::move(command));
     command_complete_callbacks.push_back(std::move(on_complete));
     if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
+      std::promise<void>* prom = command_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
@@ -300,7 +301,7 @@
   }
 
   void SetCommandFuture() {
-    ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
+    ASSERT_EQ(command_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
     command_promise_ = std::make_unique<std::promise<void>>();
     command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
   }
@@ -425,6 +426,7 @@
 class LeImplTest : public ::testing::Test {
  protected:
   void SetUp() override {
+    bluetooth::common::InitFlags::SetAllForTesting();
     thread_ = new Thread("thread", Thread::Priority::NORMAL);
     handler_ = new Handler(thread_);
     controller_ = new TestController();
@@ -449,7 +451,7 @@
 
   void set_random_device_address_policy() {
     // Set address policy
-    hci_layer_->SetCommandFuture();
+    ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
     hci::Address address;
     Address::FromString("D0:05:04:03:02:01", address);
     hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
@@ -571,6 +573,7 @@
  protected:
   void SetUp() override {
     LeImplTest::SetUp();
+    set_random_device_address_policy();
 
     EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _))
         .WillOnce([&](AddressWithType addr, std::unique_ptr<LeAclConnection> conn) {
@@ -579,8 +582,6 @@
           connection_->RegisterCallbacks(&connection_management_callbacks_, handler_);
         });
 
-    auto bytes = std::make_shared<std::vector<uint8_t>>();
-    BitInserter bi(*bytes);
     auto command = LeEnhancedConnectionCompleteBuilder::Create(
         ErrorCode::SUCCESS,
         kHciHandle,
@@ -593,7 +594,7 @@
         0x0000,
         0x0011,
         ClockAccuracy::PPM_30);
-    command->Serialize(bi);
+    auto bytes = Serialize<LeEnhancedConnectionCompleteBuilder>(std::move(command));
     auto view = CreateLeEventView<hci::LeEnhancedConnectionCompleteView>(bytes);
     ASSERT_TRUE(view.IsValid());
     le_impl_->on_le_event(view);
@@ -603,6 +604,7 @@
   }
 
   void TearDown() override {
+    connection_.reset();
     LeImplTest::TearDown();
   }
 
@@ -652,11 +654,11 @@
   set_random_device_address_policy();
 
   // Create connection
-  hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
   le_impl_->create_le_connection(
       {{0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, AddressType::PUBLIC_DEVICE_ADDRESS}, true, false);
   hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
-  hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
   hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
   hci_layer_->CommandStatusCallback(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
@@ -669,7 +671,7 @@
   hci::Address remote_address;
   Address::FromString("D0:05:04:03:02:01", remote_address);
   hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
-  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, ::testing::_));
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _));
   hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       0x0041,
@@ -691,11 +693,11 @@
 
   controller_->AddSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION);
   // Create connection
-  hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
   le_impl_->create_le_connection(
       {{0x21, 0x22, 0x23, 0x24, 0x25, 0x26}, AddressType::PUBLIC_DEVICE_ADDRESS}, true, false);
   hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
-  hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
   hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION);
   hci_layer_->CommandStatusCallback(LeExtendedCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
@@ -708,7 +710,7 @@
   hci::Address remote_address;
   Address::FromString("D0:05:04:03:02:01", remote_address);
   hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
-  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, ::testing::_));
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _));
   hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       0x0041,
@@ -734,10 +736,10 @@
   Address::FromString("D0:05:04:03:02:01", remote_address);
   hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
   // Create connection
-  hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
   le_impl_->create_le_connection(address_with_type, true, false);
   hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
-  hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
   hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
   hci_layer_->CommandStatusCallback(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
@@ -747,7 +749,7 @@
   ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
 
   // Receive connection complete of outgoing connection (Role::CENTRAL)
-  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, ::testing::_));
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _));
   hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       0x0041,
@@ -772,10 +774,10 @@
   Address::FromString("D0:05:04:03:02:01", remote_address);
   hci::AddressWithType address_with_type(remote_address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
   // Create connection
-  hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
   le_impl_->create_le_connection(address_with_type, true, false);
   hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
-  hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(hci_layer_->SetCommandFuture());
   hci_layer_->CommandCompleteCallback(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   hci_layer_->GetCommand(OpCode::LE_EXTENDED_CREATE_CONNECTION);
   hci_layer_->CommandStatusCallback(LeExtendedCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
@@ -785,7 +787,7 @@
   ASSERT_EQ(ConnectabilityState::ARMED, le_impl_->connectability_state_);
 
   // Receive connection complete of outgoing connection (Role::CENTRAL)
-  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, ::testing::_));
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(address_with_type, _));
   hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       0x0041,
@@ -804,8 +806,8 @@
   ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
 }
 
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyNotSet) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyNotSet) {
   auto log_capture = std::make_unique<LogCapture>();
 
   std::promise<void> promise;
@@ -857,8 +859,8 @@
       std::move(log_capture)));
 }
 
-TEST_F(LeImplTest, disarm_connectability_DISARMED) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_DISARMED) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   le_impl_->connectability_state_ = ConnectabilityState::DISARMED;
@@ -871,8 +873,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMED"));
 }
 
-TEST_F(LeImplTest, disarm_connectability_DISARMED_extended) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_DISARMED_extended) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   le_impl_->connectability_state_ = ConnectabilityState::DISARMED;
@@ -886,8 +888,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMED"));
 }
 
-TEST_F(LeImplTest, disarm_connectability_ARMING) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_ARMING) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   le_impl_->connectability_state_ = ConnectabilityState::ARMING;
@@ -899,8 +901,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("Le connection state machine armed state"));
 }
 
-TEST_F(LeImplTest, disarm_connectability_ARMING_extended) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_ARMING_extended) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   le_impl_->connectability_state_ = ConnectabilityState::ARMING;
@@ -914,8 +916,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("Le connection state machine armed state"));
 }
 
-TEST_F(LeImplTest, disarm_connectability_ARMED) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_ARMED) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   le_impl_->connectability_state_ = ConnectabilityState::ARMED;
@@ -928,8 +930,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("Disarming LE connection state machine with create connection"));
 }
 
-TEST_F(LeImplTest, disarm_connectability_ARMED_extended) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_ARMED_extended) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   le_impl_->connectability_state_ = ConnectabilityState::ARMED;
@@ -943,8 +945,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("Disarming LE connection state machine with create connection"));
 }
 
-TEST_F(LeImplTest, disarm_connectability_DISARMING) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_DISARMING) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   le_impl_->connectability_state_ = ConnectabilityState::DISARMING;
@@ -957,8 +959,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMING"));
 }
 
-TEST_F(LeImplTest, disarm_connectability_DISARMING_extended) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_disarm_connectability_DISARMING_extended) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   le_impl_->connectability_state_ = ConnectabilityState::DISARMING;
@@ -972,8 +974,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("in unexpected state:ConnectabilityState::DISARMING"));
 }
 
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyPublicAddress) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyPublicAddress) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_PUBLIC_ADDRESS);
@@ -994,8 +996,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("Client unregistered"));
 }
 
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyStaticAddress) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyStaticAddress) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS);
@@ -1016,8 +1018,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("Client unregistered"));
 }
 
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyNonResolvableAddress) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyNonResolvableAddress) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS);
@@ -1038,8 +1040,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("Client unregistered"));
 }
 
-TEST_F(LeImplTest, register_with_address_manager__AddressPolicyResolvableAddress) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+// b/260917913
+TEST_F(LeImplTest, DISABLED_register_with_address_manager__AddressPolicyResolvableAddress) {
   std::unique_ptr<LogCapture> log_capture = std::make_unique<LogCapture>();
 
   set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS);
@@ -1060,9 +1062,8 @@
   ASSERT_TRUE(log_capture->Rewind()->Find("Client unregistered"));
 }
 
-TEST_F(LeImplTest, add_device_to_resolving_list) {
-  bluetooth::common::InitFlags::SetAllForTesting();
-
+// b/260920739
+TEST_F(LeImplTest, DISABLED_add_device_to_resolving_list) {
   // Some kind of privacy policy must be set for LeAddressManager to operate properly
   set_privacy_policy_for_initiator_address(fixed_address_, LeAddressManager::AddressPolicy::USE_PUBLIC_ADDRESS);
   // Let LeAddressManager::resume_registered_clients execute
@@ -1133,8 +1134,6 @@
 }
 
 TEST_F(LeImplTest, add_device_to_resolving_list__SupportsBlePrivacy) {
-  bluetooth::common::InitFlags::SetAllForTesting();
-
   controller_->supports_ble_privacy_ = true;
 
   // Some kind of privacy policy must be set for LeAddressManager to operate properly
@@ -1228,11 +1227,8 @@
 }
 
 TEST_F(LeImplTest, on_le_event__CONNECTION_COMPLETE_CENTRAL) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _)).Times(1);
   set_random_device_address_policy();
-
-  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(::testing::_, ::testing::_)).Times(1);
-
   auto command = LeConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       kHciHandle,
@@ -1243,22 +1239,15 @@
       0x0000,
       0x0011,
       ClockAccuracy::PPM_30);
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter bi(*bytes);
-  command->Serialize(bi);
+  auto bytes = Serialize<LeConnectionCompleteBuilder>(std::move(command));
   auto view = CreateLeEventView<hci::LeConnectionCompleteView>(bytes);
   ASSERT_TRUE(view.IsValid());
   le_impl_->on_le_event(view);
 }
 
 TEST_F(LeImplTest, on_le_event__CONNECTION_COMPLETE_PERIPHERAL) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _)).Times(1);
   set_random_device_address_policy();
-
-  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(::testing::_, ::testing::_)).Times(1);
-
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter bi(*bytes);
   auto command = LeConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       kHciHandle,
@@ -1269,18 +1258,15 @@
       0x0000,
       0x0011,
       ClockAccuracy::PPM_30);
-  command->Serialize(bi);
+  auto bytes = Serialize<LeConnectionCompleteBuilder>(std::move(command));
   auto view = CreateLeEventView<hci::LeConnectionCompleteView>(bytes);
   ASSERT_TRUE(view.IsValid());
   le_impl_->on_le_event(view);
 }
 
 TEST_F(LeImplTest, on_le_event__ENHANCED_CONNECTION_COMPLETE_CENTRAL) {
-  bluetooth::common::InitFlags::SetAllForTesting();
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _)).Times(1);
   set_random_device_address_policy();
-
-  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(::testing::_, ::testing::_)).Times(1);
-
   auto command = LeEnhancedConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       kHciHandle,
@@ -1293,20 +1279,15 @@
       0x0000,
       0x0011,
       ClockAccuracy::PPM_30);
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter bi(*bytes);
-  command->Serialize(bi);
+  auto bytes = Serialize<LeEnhancedConnectionCompleteBuilder>(std::move(command));
   auto view = CreateLeEventView<hci::LeEnhancedConnectionCompleteView>(bytes);
   ASSERT_TRUE(view.IsValid());
   le_impl_->on_le_event(view);
 }
 
 TEST_F(LeImplTest, on_le_event__ENHANCED_CONNECTION_COMPLETE_PERIPHERAL) {
-  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(::testing::_, ::testing::_)).Times(1);
-
-  bluetooth::common::InitFlags::SetAllForTesting();
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectSuccess(_, _)).Times(1);
   set_random_device_address_policy();
-
   auto command = LeEnhancedConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       kHciHandle,
@@ -1319,9 +1300,7 @@
       0x0000,
       0x0011,
       ClockAccuracy::PPM_30);
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter bi(*bytes);
-  command->Serialize(bi);
+  auto bytes = Serialize<LeEnhancedConnectionCompleteBuilder>(std::move(command));
   auto view = CreateLeEventView<hci::LeEnhancedConnectionCompleteView>(bytes);
   ASSERT_TRUE(view.IsValid());
   le_impl_->on_le_event(view);
@@ -1340,11 +1319,9 @@
 }
 
 TEST_F(LeImplWithConnectionTest, on_le_event__PHY_UPDATE_COMPLETE) {
-  bluetooth::common::InitFlags::SetAllForTesting();
-  set_random_device_address_policy();
-  hci::ErrorCode hci_status;
-  hci::PhyType tx_phy;
-  hci::PhyType rx_phy;
+  hci::ErrorCode hci_status{ErrorCode::STATUS_UNKNOWN};
+  hci::PhyType tx_phy{0};
+  hci::PhyType rx_phy{0};
 
   // Send a phy update
   {
@@ -1354,10 +1331,8 @@
           tx_phy = static_cast<PhyType>(_tx_phy);
           rx_phy = static_cast<PhyType>(_rx_phy);
         });
-    auto command = LePhyUpdateCompleteBuilder::Create(ErrorCode::SUCCESS, kHciHandle, 0x01, 0x01);
-    auto bytes = std::make_shared<std::vector<uint8_t>>();
-    BitInserter bi(*bytes);
-    command->Serialize(bi);
+    auto command = LePhyUpdateCompleteBuilder::Create(ErrorCode::SUCCESS, kHciHandle, 0x01, 0x02);
+    auto bytes = Serialize<LePhyUpdateCompleteBuilder>(std::move(command));
     auto view = CreateLeEventView<hci::LePhyUpdateCompleteView>(bytes);
     ASSERT_TRUE(view.IsValid());
     le_impl_->on_le_event(view);
@@ -1366,12 +1341,10 @@
   sync_handler();
   ASSERT_EQ(ErrorCode::SUCCESS, hci_status);
   ASSERT_EQ(PhyType::LE_1M, tx_phy);
+  ASSERT_EQ(PhyType::LE_2M, rx_phy);
 }
 
 TEST_F(LeImplWithConnectionTest, on_le_event__DATA_LENGTH_CHANGE) {
-  bluetooth::common::InitFlags::SetAllForTesting();
-  set_random_device_address_policy();
-
   uint16_t tx_octets{0};
   uint16_t tx_time{0};
   uint16_t rx_octets{0};
@@ -1387,9 +1360,7 @@
           rx_time = _rx_time;
         });
     auto command = LeDataLengthChangeBuilder::Create(kHciHandle, 0x1234, 0x5678, 0x9abc, 0xdef0);
-    auto bytes = std::make_shared<std::vector<uint8_t>>();
-    BitInserter bi(*bytes);
-    command->Serialize(bi);
+    auto bytes = Serialize<LeDataLengthChangeBuilder>(std::move(command));
     auto view = CreateLeEventView<hci::LeDataLengthChangeView>(bytes);
     ASSERT_TRUE(view.IsValid());
     le_impl_->on_le_event(view);
@@ -1403,15 +1374,10 @@
 }
 
 TEST_F(LeImplWithConnectionTest, on_le_event__REMOTE_CONNECTION_PARAMETER_REQUEST) {
-  bluetooth::common::InitFlags::SetAllForTesting();
-  set_random_device_address_policy();
-
   // Send a remote connection parameter request
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter bi(*bytes);
   auto command = hci::LeRemoteConnectionParameterRequestBuilder::Create(
       kHciHandle, kIntervalMin, kIntervalMax, kLatency, kTimeout);
-  command->Serialize(bi);
+  auto bytes = Serialize<LeRemoteConnectionParameterRequestBuilder>(std::move(command));
   {
     auto view = CreateLeEventView<hci::LeRemoteConnectionParameterRequestView>(bytes);
     ASSERT_TRUE(view.IsValid());
@@ -1432,6 +1398,99 @@
   ASSERT_EQ(kTimeout, view.GetTimeout());
 }
 
+// b/260920739
+TEST_F(LeImplRegisteredWithAddressManagerTest, DISABLED_clear_resolving_list) {
+  le_impl_->clear_resolving_list();
+  ASSERT_EQ(3UL, le_impl_->le_address_manager_->NumberCachedCommands());
+
+  sync_handler();  // Allow |LeAddressManager::pause_registered_clients| to complete
+  sync_handler();  // Allow |LeAddressManager::handle_next_command| to complete
+
+  ASSERT_EQ(1UL, hci_layer_->NumberOfQueuedCommands());
+  {
+    auto view = CreateLeSecurityCommandView<LeSetAddressResolutionEnableView>(hci_layer_->DequeueCommandBytes());
+    ASSERT_TRUE(view.IsValid());
+    ASSERT_EQ(Enable::DISABLED, view.GetAddressResolutionEnable());
+    le_impl_->le_address_manager_->OnCommandComplete(
+        ReturnCommandComplete(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE, ErrorCode::SUCCESS));
+  }
+
+  sync_handler();  // Allow |LeAddressManager::check_cached_commands| to complete
+  ASSERT_EQ(1UL, hci_layer_->NumberOfQueuedCommands());
+  {
+    auto view = CreateLeSecurityCommandView<LeClearResolvingListView>(hci_layer_->DequeueCommandBytes());
+    ASSERT_TRUE(view.IsValid());
+    le_impl_->le_address_manager_->OnCommandComplete(
+        ReturnCommandComplete(OpCode::LE_CLEAR_RESOLVING_LIST, ErrorCode::SUCCESS));
+  }
+
+  sync_handler();  // Allow |LeAddressManager::handle_next_command| to complete
+  ASSERT_EQ(1UL, hci_layer_->NumberOfQueuedCommands());
+  {
+    auto view = CreateLeSecurityCommandView<LeSetAddressResolutionEnableView>(hci_layer_->DequeueCommandBytes());
+    ASSERT_TRUE(view.IsValid());
+    ASSERT_EQ(Enable::ENABLED, view.GetAddressResolutionEnable());
+    le_impl_->le_address_manager_->OnCommandComplete(
+        ReturnCommandComplete(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE, ErrorCode::SUCCESS));
+  }
+  ASSERT_TRUE(hci_layer_->IsPacketQueueEmpty());
+}
+
+TEST_F(LeImplWithConnectionTest, HACK_get_handle) {
+  sync_handler();
+
+  ASSERT_EQ(kHciHandle, le_impl_->HACK_get_handle(remote_address_));
+}
+
+TEST_F(LeImplTest, on_le_connection_canceled_on_pause) {
+  set_random_device_address_policy();
+  le_impl_->pause_connection = true;
+  le_impl_->on_le_connection_canceled_on_pause();
+  ASSERT_TRUE(le_impl_->arm_on_resume_);
+  ASSERT_EQ(ConnectabilityState::DISARMED, le_impl_->connectability_state_);
+}
+
+TEST_F(LeImplTest, on_create_connection_timeout) {
+  EXPECT_CALL(mock_le_connection_callbacks_, OnLeConnectFail(_, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)).Times(1);
+  le_impl_->create_connection_timeout_alarms_.emplace(
+      std::piecewise_construct,
+      std::forward_as_tuple(
+          remote_public_address_with_type_.GetAddress(), remote_public_address_with_type_.GetAddressType()),
+      std::forward_as_tuple(handler_));
+  le_impl_->on_create_connection_timeout(remote_public_address_with_type_);
+  sync_handler();
+  ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty());
+}
+
+// b/260917913
+TEST_F(LeImplTest, DISABLED_on_common_le_connection_complete__NoPriorConnection) {
+  auto log_capture = std::make_unique<LogCapture>();
+  le_impl_->on_common_le_connection_complete(remote_public_address_with_type_);
+  ASSERT_TRUE(le_impl_->connecting_le_.empty());
+  ASSERT_TRUE(log_capture->Rewind()->Find("No prior connection request for"));
+}
+
+TEST_F(LeImplTest, cancel_connect) {
+  le_impl_->create_connection_timeout_alarms_.emplace(
+      std::piecewise_construct,
+      std::forward_as_tuple(
+          remote_public_address_with_type_.GetAddress(), remote_public_address_with_type_.GetAddressType()),
+      std::forward_as_tuple(handler_));
+  le_impl_->cancel_connect(remote_public_address_with_type_);
+  sync_handler();
+  ASSERT_TRUE(le_impl_->create_connection_timeout_alarms_.empty());
+}
+
+TEST_F(LeImplTest, set_le_suggested_default_data_parameters) {
+  le_impl_->set_le_suggested_default_data_parameters(kLength, kTime);
+  sync_handler();
+  auto view =
+      CreateLeConnectionManagementCommandView<LeWriteSuggestedDefaultDataLengthView>(hci_layer_->DequeueCommandBytes());
+  ASSERT_TRUE(view.IsValid());
+  ASSERT_EQ(kLength, view.GetTxOctets());
+  ASSERT_EQ(kTime, view.GetTxTime());
+}
+
 }  // namespace acl_manager
 }  // namespace hci
 }  // namespace bluetooth
diff --git a/system/gd/hci/acl_manager/round_robin_scheduler_test.cc b/system/gd/hci/acl_manager/round_robin_scheduler_test.cc
index e27ff7c..a8bd3d7 100644
--- a/system/gd/hci/acl_manager/round_robin_scheduler_test.cc
+++ b/system/gd/hci/acl_manager/round_robin_scheduler_test.cc
@@ -35,6 +35,7 @@
 namespace bluetooth {
 namespace hci {
 namespace acl_manager {
+namespace {
 
 class TestController : public Controller {
  public:
@@ -153,7 +154,7 @@
   }
 
   void SetPacketFuture(uint16_t count) {
-    ASSERT_LOG(packet_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
+    ASSERT_EQ(packet_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
     packet_count_ = count;
     packet_promise_ = std::make_unique<std::promise<void>>();
     packet_future_ = std::make_unique<std::future<void>>(packet_promise_->get_future());
@@ -186,7 +187,7 @@
   auto connection_queue = std::make_shared<AclConnection::Queue>(10);
   round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
 
-  SetPacketFuture(2);
+  ASSERT_NO_FATAL_FAILURE(SetPacketFuture(2));
   AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
   std::vector<uint8_t> packet1 = {0x01, 0x02, 0x03};
   std::vector<uint8_t> packet2 = {0x04, 0x05, 0x06};
@@ -210,7 +211,7 @@
   round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
   round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue);
 
-  SetPacketFuture(2);
+  ASSERT_NO_FATAL_FAILURE(SetPacketFuture(2));
   AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
   AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
   std::vector<uint8_t> packet = {0x01, 0x02, 0x03};
@@ -233,7 +234,7 @@
   auto connection_queue = std::make_shared<AclConnection::Queue>(15);
   round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
 
-  SetPacketFuture(10);
+  ASSERT_NO_FATAL_FAILURE(SetPacketFuture(10));
   AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
   for (uint8_t i = 0; i < 15; i++) {
     std::vector<uint8_t> packet = {0x01, 0x02, 0x03, i};
@@ -247,7 +248,7 @@
   }
   ASSERT_EQ(round_robin_scheduler_->GetCredits(), 0);
 
-  SetPacketFuture(5);
+  ASSERT_NO_FATAL_FAILURE(SetPacketFuture(5));
   controller_->SendCompletedAclPacketsCallback(0x01, 10);
   sync_handler();
   packet_future_->wait();
@@ -277,7 +278,7 @@
   auto le_connection_queue1 = std::make_shared<AclConnection::Queue>(10);
   auto le_connection_queue2 = std::make_shared<AclConnection::Queue>(10);
 
-  SetPacketFuture(18);
+  ASSERT_NO_FATAL_FAILURE(SetPacketFuture(18));
   AclConnection::QueueUpEnd* queue_up_end1 = connection_queue1->GetUpEnd();
   AclConnection::QueueUpEnd* queue_up_end2 = connection_queue2->GetUpEnd();
   AclConnection::QueueUpEnd* le_queue_up_end1 = le_connection_queue1->GetUpEnd();
@@ -334,7 +335,7 @@
   round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
   round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue);
 
-  SetPacketFuture(5);
+  ASSERT_NO_FATAL_FAILURE(SetPacketFuture(5));
   AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
   AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
   std::vector<uint8_t> packet(controller_->hci_mtu_, 0xff);
@@ -380,7 +381,8 @@
   round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
   round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue);
 
-  SetPacketFuture(controller_->le_max_acl_packet_credits_ + controller_->max_acl_packet_credits_);
+  ASSERT_NO_FATAL_FAILURE(
+      SetPacketFuture(controller_->le_max_acl_packet_credits_ + controller_->max_acl_packet_credits_));
   AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
   AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
   std::vector<uint8_t> huge_packet(2000);
@@ -411,6 +413,7 @@
   round_robin_scheduler_->Unregister(le_handle);
 }
 
+}  // namespace
 }  // namespace acl_manager
 }  // namespace hci
 }  // namespace bluetooth
diff --git a/system/gd/hci/acl_manager_test.cc b/system/gd/hci/acl_manager_test.cc
index 73e3228..e4cdcae 100644
--- a/system/gd/hci/acl_manager_test.cc
+++ b/system/gd/hci/acl_manager_test.cc
@@ -16,19 +16,20 @@
 
 #include "hci/acl_manager.h"
 
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
 #include <algorithm>
 #include <chrono>
 #include <future>
 #include <map>
 
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
 #include "common/bind.h"
 #include "hci/address.h"
 #include "hci/class_of_device.h"
 #include "hci/controller.h"
 #include "hci/hci_layer.h"
+#include "hci/hci_layer_fake.h"
 #include "os/thread.h"
 #include "packet/raw_builder.h"
 
@@ -43,37 +44,14 @@
 using packet::PacketView;
 using packet::RawBuilder;
 
-constexpr std::chrono::seconds kTimeout = std::chrono::seconds(2);
+constexpr auto kTimeout = std::chrono::seconds(2);
+constexpr auto kShortTimeout = std::chrono::milliseconds(100);
 constexpr uint16_t kScanIntervalFast = 0x0060;
 constexpr uint16_t kScanWindowFast = 0x0030;
 constexpr uint16_t kScanIntervalSlow = 0x0800;
 constexpr uint16_t kScanWindowSlow = 0x0030;
 const AddressWithType empty_address_with_type = hci::AddressWithType();
 
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter i(*bytes);
-  bytes->reserve(packet->size());
-  packet->Serialize(i);
-  return packet::PacketView<packet::kLittleEndian>(bytes);
-}
-
-std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle) {
-  static uint32_t packet_number = 1;
-  auto payload = std::make_unique<RawBuilder>();
-  payload->AddOctets2(6);  // L2CAP PDU size
-  payload->AddOctets2(2);  // L2CAP CID
-  payload->AddOctets2(handle);
-  payload->AddOctets4(packet_number++);
-  return std::move(payload);
-}
-
-std::unique_ptr<AclBuilder> NextAclPacket(uint16_t handle) {
-  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
-  BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
-  return AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle));
-}
-
 class TestController : public Controller {
  public:
   void RegisterCompletedAclPacketsCallback(
@@ -118,200 +96,6 @@
   void ListDependencies(ModuleList* list) const {}
 };
 
-class TestHciLayer : public HciLayer {
- public:
-  void EnqueueCommand(
-      std::unique_ptr<CommandBuilder> command,
-      common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
-    command_queue_.push(std::move(command));
-    command_status_callbacks.push_back(std::move(on_status));
-    if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
-    }
-  }
-
-  void EnqueueCommand(
-      std::unique_ptr<CommandBuilder> command,
-      common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
-    command_queue_.push(std::move(command));
-    command_complete_callbacks.push_back(std::move(on_complete));
-    if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
-    }
-  }
-
-  void SetCommandFuture() {
-    ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
-    command_promise_ = std::make_unique<std::promise<void>>();
-    command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
-  }
-
-  CommandView GetLastCommand() {
-    if (command_queue_.size() == 0) {
-      return CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
-    }
-    auto last = std::move(command_queue_.front());
-    command_queue_.pop();
-    return CommandView::Create(GetPacketView(std::move(last)));
-  }
-
-  ConnectionManagementCommandView GetCommand(OpCode op_code) {
-    if (command_future_ != nullptr) {
-      auto result = command_future_->wait_for(std::chrono::milliseconds(1000));
-      EXPECT_NE(std::future_status::timeout, result);
-    }
-    if (command_queue_.empty()) {
-      return ConnectionManagementCommandView::Create(AclCommandView::Create(
-          CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()))));
-    }
-    CommandView command_packet_view = GetLastCommand();
-    ConnectionManagementCommandView command =
-        ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
-    EXPECT_TRUE(command.IsValid());
-    EXPECT_EQ(command.GetOpCode(), op_code);
-
-    return command;
-  }
-
-  ConnectionManagementCommandView GetLastCommand(OpCode op_code) {
-    if (!command_queue_.empty() && command_future_ != nullptr) {
-      command_future_.reset();
-      command_promise_.reset();
-    } else if (command_future_ != nullptr) {
-      auto result = command_future_->wait_for(std::chrono::milliseconds(1000));
-      EXPECT_NE(std::future_status::timeout, result);
-    }
-    if (command_queue_.empty()) {
-      return ConnectionManagementCommandView::Create(AclCommandView::Create(
-          CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()))));
-    }
-    CommandView command_packet_view = GetLastCommand();
-    ConnectionManagementCommandView command =
-        ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
-    EXPECT_TRUE(command.IsValid());
-    EXPECT_EQ(command.GetOpCode(), op_code);
-
-    return command;
-  }
-
-  void RegisterEventHandler(EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) override {
-    registered_events_[event_code] = event_handler;
-  }
-
-  void UnregisterEventHandler(EventCode event_code) override {
-    registered_events_.erase(event_code);
-  }
-
-  void RegisterLeEventHandler(SubeventCode subevent_code,
-                              common::ContextualCallback<void(LeMetaEventView)> event_handler) override {
-    registered_le_events_[subevent_code] = event_handler;
-  }
-
-  void UnregisterLeEventHandler(SubeventCode subevent_code) override {
-    registered_le_events_.erase(subevent_code);
-  }
-
-  void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
-    auto packet = GetPacketView(std::move(event_builder));
-    EventView event = EventView::Create(packet);
-    ASSERT_TRUE(event.IsValid());
-    EventCode event_code = event.GetEventCode();
-    ASSERT_NE(registered_events_.find(event_code), registered_events_.end()) << EventCodeText(event_code);
-    registered_events_[event_code].Invoke(event);
-  }
-
-  void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
-    auto packet = GetPacketView(std::move(event_builder));
-    EventView event = EventView::Create(packet);
-    LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
-    EXPECT_TRUE(meta_event_view.IsValid());
-    SubeventCode subevent_code = meta_event_view.GetSubeventCode();
-    EXPECT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end());
-    registered_le_events_[subevent_code].Invoke(meta_event_view);
-  }
-
-  void IncomingAclData(uint16_t handle) {
-    os::Handler* hci_handler = GetHandler();
-    auto* queue_end = acl_queue_.GetDownEnd();
-    std::promise<void> promise;
-    auto future = promise.get_future();
-    queue_end->RegisterEnqueue(hci_handler,
-                               common::Bind(
-                                   [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) {
-                                     auto packet = GetPacketView(NextAclPacket(handle));
-                                     AclView acl2 = AclView::Create(packet);
-                                     queue_end->UnregisterEnqueue();
-                                     promise.set_value();
-                                     return std::make_unique<AclView>(acl2);
-                                   },
-                                   queue_end, handle, common::Passed(std::move(promise))));
-    auto status = future.wait_for(kTimeout);
-    ASSERT_EQ(status, std::future_status::ready);
-  }
-
-  void AssertNoOutgoingAclData() {
-    auto queue_end = acl_queue_.GetDownEnd();
-    EXPECT_EQ(queue_end->TryDequeue(), nullptr);
-  }
-
-  void CommandCompleteCallback(EventView event) {
-    CommandCompleteView complete_view = CommandCompleteView::Create(event);
-    ASSERT_TRUE(complete_view.IsValid());
-    std::move(command_complete_callbacks.front()).Invoke(complete_view);
-    command_complete_callbacks.pop_front();
-  }
-
-  void CommandStatusCallback(EventView event) {
-    CommandStatusView status_view = CommandStatusView::Create(event);
-    ASSERT_TRUE(status_view.IsValid());
-    std::move(command_status_callbacks.front()).Invoke(status_view);
-    command_status_callbacks.pop_front();
-  }
-
-  PacketView<kLittleEndian> OutgoingAclData() {
-    auto queue_end = acl_queue_.GetDownEnd();
-    std::unique_ptr<AclBuilder> received;
-    do {
-      received = queue_end->TryDequeue();
-    } while (received == nullptr);
-
-    return GetPacketView(std::move(received));
-  }
-
-  BidiQueueEnd<AclBuilder, AclView>* GetAclQueueEnd() override {
-    return acl_queue_.GetUpEnd();
-  }
-
-  void ListDependencies(ModuleList* list) const {}
-  void Start() override {
-    RegisterEventHandler(EventCode::COMMAND_COMPLETE,
-                         GetHandler()->BindOn(this, &TestHciLayer::CommandCompleteCallback));
-    RegisterEventHandler(EventCode::COMMAND_STATUS, GetHandler()->BindOn(this, &TestHciLayer::CommandStatusCallback));
-  }
-  void Stop() override {}
-
-  void Disconnect(uint16_t handle, ErrorCode reason) override {
-    GetHandler()->Post(common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason));
-  }
-
- private:
-  std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
-  std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
-  std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
-  std::list<common::ContextualOnceCallback<void(CommandStatusView)>> command_status_callbacks;
-  BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
-
-  std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
-  std::unique_ptr<std::promise<void>> command_promise_;
-  std::unique_ptr<std::future<void>> command_future_;
-
-  void do_disconnect(uint16_t handle, ErrorCode reason) {
-    HciLayer::Disconnect(handle, reason);
-  }
-};
-
 class AclManagerNoCallbacksTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -321,7 +105,6 @@
     fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
     client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
     ASSERT_NE(client_handler_, nullptr);
-    test_hci_layer_->SetCommandFuture();
     fake_registry_.Start<AclManager>(&thread_);
     acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
     Address::FromString("A1:A2:A3:A4:A5:A6", remote);
@@ -337,21 +120,29 @@
         minimum_rotation_time,
         maximum_rotation_time);
 
-    auto set_random_address_packet = LeSetRandomAddressView::Create(
-        LeAdvertisingCommandView::Create(test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS)));
+    auto set_random_address_packet =
+        LeSetRandomAddressView::Create(LeAdvertisingCommandView::Create(
+            GetConnectionManagementCommand(OpCode::LE_SET_RANDOM_ADDRESS)));
     ASSERT_TRUE(set_random_address_packet.IsValid());
-    my_initiating_address =
-        AddressWithType(set_random_address_packet.GetRandomAddress(), AddressType::RANDOM_DEVICE_ADDRESS);
-    // Verify LE Set Random Address was sent during setup
-    test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
+    my_initiating_address = AddressWithType(
+        set_random_address_packet.GetRandomAddress(), AddressType::RANDOM_DEVICE_ADDRESS);
     test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   }
 
   void TearDown() override {
+    // Invalid mutex exception is raised if the connections
+    // are cleared after the AclConnectionInterface is deleted
+    // through fake_registry_.
+    mock_connection_callback_.Clear();
+    mock_le_connection_callbacks_.Clear();
     fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
     fake_registry_.StopAll();
   }
 
+  void sync_client_handler() {
+    ASSERT(thread_.GetReactor()->WaitForIdle(std::chrono::seconds(2)));
+  }
+
   TestModuleRegistry fake_registry_;
   TestHciLayer* test_hci_layer_ = nullptr;
   TestController* test_controller_ = nullptr;
@@ -398,6 +189,15 @@
     ASSERT_EQ(status, std::future_status::ready);
   }
 
+  ConnectionManagementCommandView GetConnectionManagementCommand(OpCode op_code) {
+    auto base_command = test_hci_layer_->GetCommand();
+    ConnectionManagementCommandView command =
+        ConnectionManagementCommandView::Create(AclCommandView::Create(base_command));
+    EXPECT_TRUE(command.IsValid());
+    EXPECT_EQ(command.GetOpCode(), op_code);
+    return command;
+  }
+
   class MockConnectionCallback : public ConnectionCallbacks {
    public:
     void OnConnectSuccess(std::unique_ptr<ClassicAclConnection> connection) override {
@@ -408,6 +208,11 @@
         connection_promise_.reset();
       }
     }
+
+    void Clear() {
+      connections_.clear();
+    }
+
     MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
 
     MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override));
@@ -426,6 +231,11 @@
         le_connection_promise_.reset();
       }
     }
+
+    void Clear() {
+      le_connections_.clear();
+    }
+
     MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
 
     std::list<std::shared_ptr<LeAclConnection>> le_connections_;
@@ -451,9 +261,9 @@
     acl_manager_->CreateConnection(remote);
 
     // Wait for the connection request
-    auto last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+    auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
     while (!last_command.IsValid()) {
-      last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+      last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
     }
 
     EXPECT_CALL(mock_connection_management_callbacks_, OnRoleChange(hci::ErrorCode::SUCCESS, Role::CENTRAL));
@@ -470,19 +280,17 @@
   }
 
   void TearDown() override {
+    // Invalid mutex exception is raised if the connection
+    // is cleared after the AclConnectionInterface is deleted
+    // through fake_registry_.
+    mock_connection_callback_.Clear();
+    mock_le_connection_callbacks_.Clear();
+    connection_.reset();
     fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
     fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
     fake_registry_.StopAll();
   }
 
-  void sync_client_handler() {
-    std::promise<void> promise;
-    auto future = promise.get_future();
-    client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
-    auto future_status = future.wait_for(std::chrono::seconds(1));
-    EXPECT_EQ(future_status, std::future_status::ready);
-  }
-
   uint16_t handle_;
   std::shared_ptr<ClassicAclConnection> connection_;
 
@@ -532,30 +340,15 @@
 
 TEST_F(AclManagerTest, startup_teardown) {}
 
-TEST_F(AclManagerNoCallbacksTest, acl_connection_before_registered_callbacks) {
-  ClassOfDevice class_of_device;
-
-  test_hci_layer_->IncomingEvent(
-      ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
-  fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
-  fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
-  fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
-  CommandView command = CommandView::Create(test_hci_layer_->GetLastCommand());
-  EXPECT_TRUE(command.IsValid());
-  OpCode op_code = command.GetOpCode();
-  EXPECT_EQ(op_code, OpCode::REJECT_CONNECTION_REQUEST);
-}
-
 TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_success) {
   uint16_t handle = 1;
 
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateConnection(remote);
 
   // Wait for the connection request
-  auto last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+  auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
   while (!last_command.IsValid()) {
-    last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+    last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
   }
 
   auto first_connection = GetConnectionFuture();
@@ -573,13 +366,12 @@
 TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_fail) {
   uint16_t handle = 0x123;
 
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateConnection(remote);
 
   // Wait for the connection request
-  auto last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+  auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
   while (!last_command.IsValid()) {
-    last_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+    last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
   }
 
   EXPECT_CALL(mock_connection_callback_, OnConnectFail(remote, ErrorCode::PAGE_TIMEOUT));
@@ -596,12 +388,10 @@
     AclManagerTest::SetUp();
 
     remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-    test_hci_layer_->SetCommandFuture();
     acl_manager_->CreateLeConnection(remote_with_type_, true);
-    test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+    GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
     test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
-    test_hci_layer_->SetCommandFuture();
-    auto packet = test_hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
+    auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
     auto le_connection_management_command_view =
         LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
     auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
@@ -621,7 +411,7 @@
     test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
         ErrorCode::SUCCESS,
         handle_,
-        Role::PERIPHERAL,
+        Role::CENTRAL,
         AddressType::PUBLIC_DEVICE_ADDRESS,
         remote,
         0x0100,
@@ -629,8 +419,7 @@
         0x0C80,
         ClockAccuracy::PPM_30));
 
-    test_hci_layer_->SetCommandFuture();
-    test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+    GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
     test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
     auto first_connection_status = first_connection.wait_for(kTimeout);
@@ -640,19 +429,17 @@
   }
 
   void TearDown() override {
+    // Invalid mutex exception is raised if the connection
+    // is cleared after the AclConnectionInterface is deleted
+    // through fake_registry_.
+    mock_connection_callback_.Clear();
+    mock_le_connection_callbacks_.Clear();
+    connection_.reset();
     fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
     fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
     fake_registry_.StopAll();
   }
 
-  void sync_client_handler() {
-    std::promise<void> promise;
-    auto future = promise.get_future();
-    client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
-    auto future_status = future.wait_for(std::chrono::seconds(1));
-    EXPECT_EQ(future_status, std::future_status::ready);
-  }
-
   uint16_t handle_ = 0x123;
   std::shared_ptr<LeAclConnection> connection_;
   AddressWithType remote_with_type_;
@@ -686,12 +473,10 @@
 
 TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_fail) {
   AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateLeConnection(remote_with_type, true);
-  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+  GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
-  test_hci_layer_->SetCommandFuture();
-  auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+  auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
   auto le_connection_management_command_view =
       LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
   auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
@@ -707,10 +492,11 @@
 
   EXPECT_CALL(mock_le_connection_callbacks_,
               OnLeConnectFail(remote_with_type, ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES));
+
   test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
       ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES,
       0x123,
-      Role::PERIPHERAL,
+      Role::CENTRAL,
       AddressType::PUBLIC_DEVICE_ADDRESS,
       remote,
       0x0100,
@@ -718,8 +504,7 @@
       0x0011,
       ClockAccuracy::PPM_30));
 
-  test_hci_layer_->SetCommandFuture();
-  packet = test_hci_layer_->GetLastCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+  packet = GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
   le_connection_management_command_view = LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
   auto remove_command_view = LeRemoveDeviceFromFilterAcceptListView::Create(le_connection_management_command_view);
   ASSERT_TRUE(remove_command_view.IsValid());
@@ -728,16 +513,14 @@
 
 TEST_F(AclManagerTest, cancel_le_connection) {
   AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateLeConnection(remote_with_type, true);
-  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+  GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+  GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
+  test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
 
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CancelLeConnect(remote_with_type);
-  auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
+  auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
   auto le_connection_management_command_view =
       LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
   auto command_view = LeCreateConnectionCancelView::Create(le_connection_management_command_view);
@@ -747,7 +530,7 @@
   test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
       ErrorCode::UNKNOWN_CONNECTION,
       0x123,
-      Role::PERIPHERAL,
+      Role::CENTRAL,
       AddressType::PUBLIC_DEVICE_ADDRESS,
       remote,
       0x0100,
@@ -755,8 +538,7 @@
       0x0011,
       ClockAccuracy::PPM_30));
 
-  test_hci_layer_->SetCommandFuture();
-  packet = test_hci_layer_->GetLastCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+  packet = GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
   le_connection_management_command_view = LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
   auto remove_command_view = LeRemoveDeviceFromFilterAcceptListView::Create(le_connection_management_command_view);
   ASSERT_TRUE(remove_command_view.IsValid());
@@ -766,31 +548,32 @@
 
 TEST_F(AclManagerTest, create_connection_with_fast_mode) {
   AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateLeConnection(remote_with_type, true);
-  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
-  test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
-  test_hci_layer_->SetCommandFuture();
-  auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+  GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+  test_hci_layer_->IncomingEvent(
+      LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+
+  auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
   auto command_view =
       LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetLeScanInterval(), kScanIntervalFast);
   ASSERT_EQ(command_view.GetLeScanWindow(), kScanWindowFast);
   test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
+
   auto first_connection = GetLeConnectionFuture();
   test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       0x00,
-      Role::PERIPHERAL,
+      Role::CENTRAL,
       AddressType::PUBLIC_DEVICE_ADDRESS,
       remote,
       0x0100,
       0x0010,
       0x0C80,
       ClockAccuracy::PPM_30));
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+
+  GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   auto first_connection_status = first_connection.wait_for(kTimeout);
   ASSERT_EQ(first_connection_status, std::future_status::ready);
@@ -798,12 +581,10 @@
 
 TEST_F(AclManagerTest, create_connection_with_slow_mode) {
   AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateLeConnection(remote_with_type, false);
-  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+  GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
-  test_hci_layer_->SetCommandFuture();
-  auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+  auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
   auto command_view =
       LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
   ASSERT_TRUE(command_view.IsValid());
@@ -814,15 +595,14 @@
   test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
       ErrorCode::SUCCESS,
       0x00,
-      Role::PERIPHERAL,
+      Role::CENTRAL,
       AddressType::PUBLIC_DEVICE_ADDRESS,
       remote,
       0x0100,
       0x0010,
       0x0C80,
       ClockAccuracy::PPM_30));
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
+  GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   auto first_connection_status = first_connection.wait_for(kTimeout);
   ASSERT_EQ(first_connection_status, std::future_status::ready);
@@ -867,19 +647,25 @@
   uint16_t connection_interval = (connection_interval_max + connection_interval_min) / 2;
   uint16_t connection_latency = 0x0001;
   uint16_t supervision_timeout = 0x0A00;
-  test_hci_layer_->SetCommandFuture();
-  connection_->LeConnectionUpdate(connection_interval_min, connection_interval_max, connection_latency,
-                                  supervision_timeout, 0x10, 0x20);
-  auto update_packet = test_hci_layer_->GetCommand(OpCode::LE_CONNECTION_UPDATE);
+  connection_->LeConnectionUpdate(
+      connection_interval_min,
+      connection_interval_max,
+      connection_latency,
+      supervision_timeout,
+      0x10,
+      0x20);
+  auto update_packet = GetConnectionManagementCommand(OpCode::LE_CONNECTION_UPDATE);
   auto update_view =
       LeConnectionUpdateView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(update_packet)));
   ASSERT_TRUE(update_view.IsValid());
   EXPECT_EQ(update_view.GetConnectionHandle(), handle_);
+  test_hci_layer_->IncomingEvent(LeConnectionUpdateStatusBuilder::Create(ErrorCode::SUCCESS, 0x1));
   EXPECT_CALL(
       mock_le_connection_management_callbacks_,
       OnConnectionUpdate(hci_status, connection_interval, connection_latency, supervision_timeout));
   test_hci_layer_->IncomingLeMetaEvent(LeConnectionUpdateCompleteBuilder::Create(
       ErrorCode::SUCCESS, handle_, connection_interval, connection_latency, supervision_timeout));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_disconnect) {
@@ -890,9 +676,10 @@
   auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
   EXPECT_CALL(mock_le_connection_management_callbacks_, OnDisconnection(reason));
   test_hci_layer_->Disconnect(handle_, reason);
+  sync_client_handler();
 }
 
-TEST_F(AclManagerWithLeConnectionTest, DISABLED_invoke_registered_callback_le_disconnect_data_race) {
+TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_disconnect_data_race) {
   ASSERT_EQ(connection_->GetRemoteAddress(), remote_with_type_);
   ASSERT_EQ(connection_->GetHandle(), handle_);
   connection_->RegisterCallbacks(&mock_le_connection_management_callbacks_, client_handler_);
@@ -901,6 +688,7 @@
   auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
   EXPECT_CALL(mock_le_connection_management_callbacks_, OnDisconnection(reason));
   test_hci_layer_->Disconnect(handle_, reason);
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_queue_disconnect) {
@@ -918,6 +706,7 @@
   auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
   EXPECT_CALL(mock_connection_management_callbacks_, OnDisconnection(reason));
   test_hci_layer_->Disconnect(handle_, reason);
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, acl_send_data_one_connection) {
@@ -941,15 +730,15 @@
   SendAclData(handle_, connection_->GetAclQueueEnd());
 
   sent_packet = test_hci_layer_->OutgoingAclData();
-  test_hci_layer_->SetCommandFuture();
   auto reason = ErrorCode::AUTHENTICATION_FAILURE;
   EXPECT_CALL(mock_connection_management_callbacks_, OnDisconnection(reason));
   connection_->Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
-  auto packet = test_hci_layer_->GetCommand(OpCode::DISCONNECT);
+  auto packet = GetConnectionManagementCommand(OpCode::DISCONNECT);
   auto command_view = DisconnectView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetConnectionHandle(), handle_);
   test_hci_layer_->Disconnect(handle_, reason);
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, acl_send_data_credits) {
@@ -969,12 +758,12 @@
   test_controller_->CompletePackets(handle_, 1);
 
   auto after_credits_sent_packet = test_hci_layer_->OutgoingAclData();
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_switch_role) {
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->SwitchRole(connection_->GetAddress(), Role::PERIPHERAL);
-  auto packet = test_hci_layer_->GetCommand(OpCode::SWITCH_ROLE);
+  auto packet = GetConnectionManagementCommand(OpCode::SWITCH_ROLE);
   auto command_view = SwitchRoleView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetBdAddr(), connection_->GetAddress());
@@ -983,13 +772,13 @@
   EXPECT_CALL(mock_connection_management_callbacks_, OnRoleChange(hci::ErrorCode::SUCCESS, Role::PERIPHERAL));
   test_hci_layer_->IncomingEvent(
       RoleChangeBuilder::Create(ErrorCode::SUCCESS, connection_->GetAddress(), Role::PERIPHERAL));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_write_default_link_policy_settings) {
-  test_hci_layer_->SetCommandFuture();
   uint16_t link_policy_settings = 0x05;
   acl_manager_->WriteDefaultLinkPolicySettings(link_policy_settings);
-  auto packet = test_hci_layer_->GetCommand(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
+  auto packet = GetConnectionManagementCommand(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
   auto command_view = WriteDefaultLinkPolicySettingsView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetDefaultLinkPolicySettings(), 0x05);
@@ -997,49 +786,52 @@
   uint8_t num_packets = 1;
   test_hci_layer_->IncomingEvent(
       WriteDefaultLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS));
+  sync_client_handler();
 
   ASSERT_EQ(link_policy_settings, acl_manager_->ReadDefaultLinkPolicySettings());
 }
 
 TEST_F(AclManagerWithConnectionTest, send_authentication_requested) {
-  test_hci_layer_->SetCommandFuture();
   connection_->AuthenticationRequested();
-  auto packet = test_hci_layer_->GetCommand(OpCode::AUTHENTICATION_REQUESTED);
+  auto packet = GetConnectionManagementCommand(OpCode::AUTHENTICATION_REQUESTED);
   auto command_view = AuthenticationRequestedView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnAuthenticationComplete);
-  test_hci_layer_->IncomingEvent(AuthenticationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_));
+  test_hci_layer_->IncomingEvent(
+      AuthenticationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_clock_offset) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadClockOffset();
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_CLOCK_OFFSET);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_CLOCK_OFFSET);
   auto command_view = ReadClockOffsetView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockOffsetComplete(0x0123));
-  test_hci_layer_->IncomingEvent(ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, 0x0123));
+  test_hci_layer_->IncomingEvent(
+      ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, 0x0123));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_hold_mode) {
-  test_hci_layer_->SetCommandFuture();
   connection_->HoldMode(0x0500, 0x0020);
-  auto packet = test_hci_layer_->GetCommand(OpCode::HOLD_MODE);
+  auto packet = GetConnectionManagementCommand(OpCode::HOLD_MODE);
   auto command_view = HoldModeView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetHoldModeMaxInterval(), 0x0500);
   ASSERT_EQ(command_view.GetHoldModeMinInterval(), 0x0020);
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::HOLD, 0x0020));
-  test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::HOLD, 0x0020));
+  test_hci_layer_->IncomingEvent(
+      ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::HOLD, 0x0020));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_sniff_mode) {
-  test_hci_layer_->SetCommandFuture();
   connection_->SniffMode(0x0500, 0x0020, 0x0040, 0x0014);
-  auto packet = test_hci_layer_->GetCommand(OpCode::SNIFF_MODE);
+  auto packet = GetConnectionManagementCommand(OpCode::SNIFF_MODE);
   auto command_view = SniffModeView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetSniffMaxInterval(), 0x0500);
@@ -1048,101 +840,109 @@
   ASSERT_EQ(command_view.GetSniffTimeout(), 0x0014);
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::SNIFF, 0x0028));
-  test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::SNIFF, 0x0028));
+  test_hci_layer_->IncomingEvent(
+      ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::SNIFF, 0x0028));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_exit_sniff_mode) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ExitSniffMode();
-  auto packet = test_hci_layer_->GetCommand(OpCode::EXIT_SNIFF_MODE);
+  auto packet = GetConnectionManagementCommand(OpCode::EXIT_SNIFF_MODE);
   auto command_view = ExitSniffModeView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::ACTIVE, 0x00));
-  test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::ACTIVE, 0x00));
+  test_hci_layer_->IncomingEvent(
+      ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::ACTIVE, 0x00));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_qos_setup) {
-  test_hci_layer_->SetCommandFuture();
   connection_->QosSetup(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
-  auto packet = test_hci_layer_->GetCommand(OpCode::QOS_SETUP);
+  auto packet = GetConnectionManagementCommand(OpCode::QOS_SETUP);
   auto command_view = QosSetupView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
-  ASSERT_EQ(command_view.GetTokenRate(), 0x1234);
-  ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1233);
-  ASSERT_EQ(command_view.GetLatency(), 0x1232);
-  ASSERT_EQ(command_view.GetDelayVariation(), 0x1231);
+  ASSERT_EQ(command_view.GetTokenRate(), 0x1234u);
+  ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1233u);
+  ASSERT_EQ(command_view.GetLatency(), 0x1232u);
+  ASSERT_EQ(command_view.GetDelayVariation(), 0x1231u);
 
   EXPECT_CALL(mock_connection_management_callbacks_,
               OnQosSetupComplete(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
-  test_hci_layer_->IncomingEvent(QosSetupCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, ServiceType::BEST_EFFORT,
-                                                                 0x1234, 0x1233, 0x1232, 0x1231));
+  test_hci_layer_->IncomingEvent(QosSetupCompleteBuilder::Create(
+      ErrorCode::SUCCESS, handle_, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_flow_specification) {
-  test_hci_layer_->SetCommandFuture();
-  connection_->FlowSpecification(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232,
-                                 0x1231);
-  auto packet = test_hci_layer_->GetCommand(OpCode::FLOW_SPECIFICATION);
+  connection_->FlowSpecification(
+      FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
+  auto packet = GetConnectionManagementCommand(OpCode::FLOW_SPECIFICATION);
   auto command_view = FlowSpecificationView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetFlowDirection(), FlowDirection::OUTGOING_FLOW);
   ASSERT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
-  ASSERT_EQ(command_view.GetTokenRate(), 0x1234);
-  ASSERT_EQ(command_view.GetTokenBucketSize(), 0x1233);
-  ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1232);
-  ASSERT_EQ(command_view.GetAccessLatency(), 0x1231);
+  ASSERT_EQ(command_view.GetTokenRate(), 0x1234u);
+  ASSERT_EQ(command_view.GetTokenBucketSize(), 0x1233u);
+  ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1232u);
+  ASSERT_EQ(command_view.GetAccessLatency(), 0x1231u);
 
   EXPECT_CALL(mock_connection_management_callbacks_,
               OnFlowSpecificationComplete(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233,
                                           0x1232, 0x1231));
-  test_hci_layer_->IncomingEvent(
-      FlowSpecificationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, FlowDirection::OUTGOING_FLOW,
-                                               ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
+  test_hci_layer_->IncomingEvent(FlowSpecificationCompleteBuilder::Create(
+      ErrorCode::SUCCESS,
+      handle_,
+      FlowDirection::OUTGOING_FLOW,
+      ServiceType::BEST_EFFORT,
+      0x1234,
+      0x1233,
+      0x1232,
+      0x1231));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_flush) {
-  test_hci_layer_->SetCommandFuture();
   connection_->Flush();
-  auto packet = test_hci_layer_->GetCommand(OpCode::FLUSH);
+  auto packet = GetConnectionManagementCommand(OpCode::FLUSH);
   auto command_view = FlushView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnFlushOccurred());
   test_hci_layer_->IncomingEvent(FlushOccurredBuilder::Create(handle_));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_role_discovery) {
-  test_hci_layer_->SetCommandFuture();
   connection_->RoleDiscovery();
-  auto packet = test_hci_layer_->GetCommand(OpCode::ROLE_DISCOVERY);
+  auto packet = GetConnectionManagementCommand(OpCode::ROLE_DISCOVERY);
   auto command_view = RoleDiscoveryView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnRoleDiscoveryComplete(Role::CENTRAL));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(
-      RoleDiscoveryCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, Role::CENTRAL));
+  test_hci_layer_->IncomingEvent(RoleDiscoveryCompleteBuilder::Create(
+      num_packets, ErrorCode::SUCCESS, handle_, Role::CENTRAL));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_link_policy_settings) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadLinkPolicySettings();
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_LINK_POLICY_SETTINGS);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_POLICY_SETTINGS);
   auto command_view = ReadLinkPolicySettingsView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkPolicySettingsComplete(0x07));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(
-      ReadLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+  test_hci_layer_->IncomingEvent(ReadLinkPolicySettingsCompleteBuilder::Create(
+      num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_write_link_policy_settings) {
-  test_hci_layer_->SetCommandFuture();
   connection_->WriteLinkPolicySettings(0x05);
-  auto packet = test_hci_layer_->GetCommand(OpCode::WRITE_LINK_POLICY_SETTINGS);
+  auto packet = GetConnectionManagementCommand(OpCode::WRITE_LINK_POLICY_SETTINGS);
   auto command_view = WriteLinkPolicySettingsView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetLinkPolicySettings(), 0x05);
@@ -1150,12 +950,12 @@
   uint8_t num_packets = 1;
   test_hci_layer_->IncomingEvent(
       WriteLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_sniff_subrating) {
-  test_hci_layer_->SetCommandFuture();
   connection_->SniffSubrating(0x1234, 0x1235, 0x1236);
-  auto packet = test_hci_layer_->GetCommand(OpCode::SNIFF_SUBRATING);
+  auto packet = GetConnectionManagementCommand(OpCode::SNIFF_SUBRATING);
   auto command_view = SniffSubratingView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetMaximumLatency(), 0x1234);
@@ -1163,26 +963,27 @@
   ASSERT_EQ(command_view.GetMinimumLocalTimeout(), 0x1236);
 
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(SniffSubratingCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+  test_hci_layer_->IncomingEvent(
+      SniffSubratingCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_automatic_flush_timeout) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadAutomaticFlushTimeout();
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT);
   auto command_view = ReadAutomaticFlushTimeoutView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnReadAutomaticFlushTimeoutComplete(0x07ff));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(
-      ReadAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07ff));
+  test_hci_layer_->IncomingEvent(ReadAutomaticFlushTimeoutCompleteBuilder::Create(
+      num_packets, ErrorCode::SUCCESS, handle_, 0x07ff));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_write_automatic_flush_timeout) {
-  test_hci_layer_->SetCommandFuture();
   connection_->WriteAutomaticFlushTimeout(0x07FF);
-  auto packet = test_hci_layer_->GetCommand(OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT);
+  auto packet = GetConnectionManagementCommand(OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT);
   auto command_view = WriteAutomaticFlushTimeoutView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetFlushTimeout(), 0x07FF);
@@ -1190,39 +991,39 @@
   uint8_t num_packets = 1;
   test_hci_layer_->IncomingEvent(
       WriteAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_transmit_power_level) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadTransmitPowerLevel(TransmitPowerLevelType::CURRENT);
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_TRANSMIT_POWER_LEVEL);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_TRANSMIT_POWER_LEVEL);
   auto command_view = ReadTransmitPowerLevelView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetTransmitPowerLevelType(), TransmitPowerLevelType::CURRENT);
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnReadTransmitPowerLevelComplete(0x07));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(
-      ReadTransmitPowerLevelCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+  test_hci_layer_->IncomingEvent(ReadTransmitPowerLevelCompleteBuilder::Create(
+      num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_link_supervision_timeout) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadLinkSupervisionTimeout();
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_LINK_SUPERVISION_TIMEOUT);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_SUPERVISION_TIMEOUT);
   auto command_view = ReadLinkSupervisionTimeoutView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkSupervisionTimeoutComplete(0x5677));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(
-      ReadLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x5677));
+  test_hci_layer_->IncomingEvent(ReadLinkSupervisionTimeoutCompleteBuilder::Create(
+      num_packets, ErrorCode::SUCCESS, handle_, 0x5677));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_write_link_supervision_timeout) {
-  test_hci_layer_->SetCommandFuture();
   connection_->WriteLinkSupervisionTimeout(0x5678);
-  auto packet = test_hci_layer_->GetCommand(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT);
+  auto packet = GetConnectionManagementCommand(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT);
   auto command_view = WriteLinkSupervisionTimeoutView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetLinkSupervisionTimeout(), 0x5678);
@@ -1230,37 +1031,37 @@
   uint8_t num_packets = 1;
   test_hci_layer_->IncomingEvent(
       WriteLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_failed_contact_counter) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadFailedContactCounter();
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_FAILED_CONTACT_COUNTER);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_FAILED_CONTACT_COUNTER);
   auto command_view = ReadFailedContactCounterView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnReadFailedContactCounterComplete(0x00));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(
-      ReadFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+  test_hci_layer_->IncomingEvent(ReadFailedContactCounterCompleteBuilder::Create(
+      num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_reset_failed_contact_counter) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ResetFailedContactCounter();
-  auto packet = test_hci_layer_->GetCommand(OpCode::RESET_FAILED_CONTACT_COUNTER);
+  auto packet = GetConnectionManagementCommand(OpCode::RESET_FAILED_CONTACT_COUNTER);
   auto command_view = ResetFailedContactCounterView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
   uint8_t num_packets = 1;
   test_hci_layer_->IncomingEvent(
       ResetFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_link_quality) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadLinkQuality();
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_LINK_QUALITY);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_QUALITY);
   auto command_view = ReadLinkQualityView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
 
@@ -1268,12 +1069,12 @@
   uint8_t num_packets = 1;
   test_hci_layer_->IncomingEvent(
       ReadLinkQualityCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0xa9));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_afh_channel_map) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadAfhChannelMap();
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_AFH_CHANNEL_MAP);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_AFH_CHANNEL_MAP);
   auto command_view = ReadAfhChannelMapView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   std::array<uint8_t, 10> afh_channel_map = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
@@ -1281,34 +1082,36 @@
   EXPECT_CALL(mock_connection_management_callbacks_,
               OnReadAfhChannelMapComplete(AfhMode::AFH_ENABLED, afh_channel_map));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(ReadAfhChannelMapCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_,
-                                                                          AfhMode::AFH_ENABLED, afh_channel_map));
+  test_hci_layer_->IncomingEvent(ReadAfhChannelMapCompleteBuilder::Create(
+      num_packets, ErrorCode::SUCCESS, handle_, AfhMode::AFH_ENABLED, afh_channel_map));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_rssi) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadRssi();
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_RSSI);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_RSSI);
   auto command_view = ReadRssiView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   sync_client_handler();
   EXPECT_CALL(mock_connection_management_callbacks_, OnReadRssiComplete(0x00));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(ReadRssiCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+  test_hci_layer_->IncomingEvent(
+      ReadRssiCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+  sync_client_handler();
 }
 
 TEST_F(AclManagerWithConnectionTest, send_read_clock) {
-  test_hci_layer_->SetCommandFuture();
   connection_->ReadClock(WhichClock::LOCAL);
-  auto packet = test_hci_layer_->GetCommand(OpCode::READ_CLOCK);
+  auto packet = GetConnectionManagementCommand(OpCode::READ_CLOCK);
   auto command_view = ReadClockView::Create(packet);
   ASSERT_TRUE(command_view.IsValid());
   ASSERT_EQ(command_view.GetWhichClock(), WhichClock::LOCAL);
 
   EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockComplete(0x00002e6a, 0x0000));
   uint8_t num_packets = 1;
-  test_hci_layer_->IncomingEvent(
-      ReadClockCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00002e6a, 0x0000));
+  test_hci_layer_->IncomingEvent(ReadClockCompleteBuilder::Create(
+      num_packets, ErrorCode::SUCCESS, handle_, 0x00002e6a, 0x0000));
+  sync_client_handler();
 }
 
 class AclManagerWithResolvableAddressTest : public AclManagerNoCallbacksTest {
@@ -1320,7 +1123,6 @@
     fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
     client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
     ASSERT_NE(client_handler_, nullptr);
-    test_hci_layer_->SetCommandFuture();
     fake_registry_.Start<AclManager>(&thread_);
     acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
     Address::FromString("A1:A2:A3:A4:A5:A6", remote);
@@ -1338,28 +1140,22 @@
         minimum_rotation_time,
         maximum_rotation_time);
 
-    test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
+    GetConnectionManagementCommand(OpCode::LE_SET_RANDOM_ADDRESS);
     test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   }
 };
 
 TEST_F(AclManagerWithResolvableAddressTest, create_connection_cancel_fail) {
   auto remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateLeConnection(remote_with_type_, true);
 
-  // Set random address
-  test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
-
   // Add device to connect list
-  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+  test_hci_layer_->IncomingEvent(
+      LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
   // send create connection command
-  test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+  GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
   test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
 
   fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
@@ -1370,11 +1166,10 @@
   auto remote_with_type2 = AddressWithType(remote2, AddressType::PUBLIC_DEVICE_ADDRESS);
 
   // create another connection
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateLeConnection(remote_with_type2, true);
 
   // cancel previous connection
-  test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
+  GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
 
   // receive connection complete of first device
   test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
@@ -1389,13 +1184,14 @@
       ClockAccuracy::PPM_30));
 
   // receive create connection cancel complete with ErrorCode::CONNECTION_ALREADY_EXISTS
-  test_hci_layer_->SetCommandFuture();
   test_hci_layer_->IncomingEvent(
       LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::CONNECTION_ALREADY_EXISTS));
 
   // Add another device to connect list
-  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+  GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+
+  // Sync events.
 }
 
 class AclManagerLifeCycleTest : public AclManagerNoCallbacksTest {
@@ -1412,9 +1208,8 @@
 
 TEST_F(AclManagerLifeCycleTest, unregister_classic_after_create_connection) {
   // Inject create connection
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateConnection(remote);
-  auto connection_command = test_hci_layer_->GetCommand(OpCode::CREATE_CONNECTION);
+  auto connection_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
 
   // Unregister callbacks after sending connection request
   auto promise = std::promise<void>();
@@ -1426,38 +1221,19 @@
   auto connection_future = GetConnectionFuture();
   test_hci_layer_->IncomingEvent(
       ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
-  auto connection_future_status = connection_future.wait_for(kTimeout);
+
+  sync_client_handler();
+  auto connection_future_status = connection_future.wait_for(kShortTimeout);
   ASSERT_NE(connection_future_status, std::future_status::ready);
 }
 
-TEST_F(AclManagerLifeCycleTest, unregister_classic_before_connection_request) {
-  ClassOfDevice class_of_device;
-
-  // Unregister callbacks before receiving connection request
-  auto promise = std::promise<void>();
-  auto future = promise.get_future();
-  acl_manager_->UnregisterCallbacks(&mock_connection_callback_, std::move(promise));
-  future.get();
-
-  // Inject peer sending connection request
-  auto connection_future = GetConnectionFuture();
-  test_hci_layer_->IncomingEvent(
-      ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
-  auto connection_future_status = connection_future.wait_for(kTimeout);
-  ASSERT_NE(connection_future_status, std::future_status::ready);
-
-  test_hci_layer_->GetLastCommand(OpCode::REJECT_CONNECTION_REQUEST);
-}
-
 TEST_F(AclManagerLifeCycleTest, unregister_le_before_connection_complete) {
   AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateLeConnection(remote_with_type, true);
-  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+  GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
-  test_hci_layer_->SetCommandFuture();
-  auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+  auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
   auto le_connection_management_command_view =
       LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
   auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
@@ -1487,19 +1263,18 @@
       0x0500,
       ClockAccuracy::PPM_30));
 
-  auto connection_future_status = connection_future.wait_for(kTimeout);
+  sync_client_handler();
+  auto connection_future_status = connection_future.wait_for(kShortTimeout);
   ASSERT_NE(connection_future_status, std::future_status::ready);
 }
 
 TEST_F(AclManagerLifeCycleTest, unregister_le_before_enhanced_connection_complete) {
   AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-  test_hci_layer_->SetCommandFuture();
   acl_manager_->CreateLeConnection(remote_with_type, true);
-  test_hci_layer_->GetLastCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
+  GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
-  test_hci_layer_->SetCommandFuture();
-  auto packet = test_hci_layer_->GetLastCommand(OpCode::LE_CREATE_CONNECTION);
+  auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
   auto le_connection_management_command_view =
       LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
   auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
@@ -1531,7 +1306,8 @@
       0x0500,
       ClockAccuracy::PPM_30));
 
-  auto connection_future_status = connection_future.wait_for(kTimeout);
+  sync_client_handler();
+  auto connection_future_status = connection_future.wait_for(kShortTimeout);
   ASSERT_NE(connection_future_status, std::future_status::ready);
 }
 
diff --git a/system/gd/hci/acl_manager_unittest.cc b/system/gd/hci/acl_manager_unittest.cc
index 37d96db..31c71eb 100644
--- a/system/gd/hci/acl_manager_unittest.cc
+++ b/system/gd/hci/acl_manager_unittest.cc
@@ -21,11 +21,15 @@
 
 #include <algorithm>
 #include <chrono>
+#include <deque>
 #include <future>
+#include <list>
 #include <map>
 
 #include "common/bind.h"
+#include "common/init_flags.h"
 #include "hci/address.h"
+#include "hci/address_with_type.h"
 #include "hci/class_of_device.h"
 #include "hci/controller.h"
 #include "hci/hci_layer.h"
@@ -45,9 +49,28 @@
 using packet::PacketView;
 using packet::RawBuilder;
 
-constexpr std::chrono::seconds kTimeout = std::chrono::seconds(2);
+namespace {
+constexpr char kLocalRandomAddressString[] = "D0:05:04:03:02:01";
+constexpr char kRemotePublicDeviceStringA[] = "11:A2:A3:A4:A5:A6";
+constexpr char kRemotePublicDeviceStringB[] = "11:B2:B3:B4:B5:B6";
+constexpr uint16_t kHciHandleA = 123;
+constexpr uint16_t kHciHandleB = 456;
+
+constexpr auto kMinimumRotationTime = std::chrono::milliseconds(7 * 60 * 1000);
+constexpr auto kMaximumRotationTime = std::chrono::milliseconds(15 * 60 * 1000);
+
 const AddressWithType empty_address_with_type = hci::AddressWithType();
 
+struct {
+  Address address;
+  ClassOfDevice class_of_device;
+  const uint16_t handle;
+} remote_device[2] = {
+    {.address = {}, .class_of_device = {}, .handle = kHciHandleA},
+    {.address = {}, .class_of_device = {}, .handle = kHciHandleB},
+};
+}  // namespace
+
 PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
   auto bytes = std::make_shared<std::vector<uint8_t>>();
   BitInserter i(*bytes);
@@ -74,15 +97,6 @@
 
 class TestController : public Controller {
  public:
-  void RegisterCompletedAclPacketsCallback(
-      common::ContextualCallback<void(uint16_t /* handle */, uint16_t /* packets */)> cb) override {
-    acl_cb_ = cb;
-  }
-
-  void UnregisterCompletedAclPacketsCallback() override {
-    acl_cb_ = {};
-  }
-
   uint16_t GetAclPacketLength() const override {
     return acl_buffer_length_;
   }
@@ -102,18 +116,15 @@
     return le_buffer_size;
   }
 
-  void CompletePackets(uint16_t handle, uint16_t packets) {
-    acl_cb_.Invoke(handle, packets);
-  }
-
-  uint16_t acl_buffer_length_ = 1024;
-  uint16_t total_acl_buffers_ = 2;
-  common::ContextualCallback<void(uint16_t /* handle */, uint16_t /* packets */)> acl_cb_;
-
  protected:
   void Start() override {}
   void Stop() override {}
   void ListDependencies(ModuleList* list) const {}
+
+ private:
+  uint16_t acl_buffer_length_ = 1024;
+  uint16_t total_acl_buffers_ = 2;
+  common::ContextualCallback<void(uint16_t /* handle */, uint16_t /* packets */)> acl_cb_;
 };
 
 class TestHciLayer : public HciLayer {
@@ -123,10 +134,7 @@
       common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
     command_queue_.push(std::move(command));
     command_status_callbacks.push_back(std::move(on_status));
-    if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
-    }
+    Notify();
   }
 
   void EnqueueCommand(
@@ -134,16 +142,18 @@
       common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
     command_queue_.push(std::move(command));
     command_complete_callbacks.push_back(std::move(on_complete));
-    if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
-    }
+    Notify();
   }
 
   void SetCommandFuture() {
-    ASSERT_TRUE(command_promise_ == nullptr) << "Promises, Promises, ... Only one at a time.";
-    command_promise_ = std::make_unique<std::promise<void>>();
-    command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
+    ASSERT_EQ(hci_command_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
+    hci_command_promise_ = std::make_unique<std::promise<void>>();
+    command_future_ = std::make_unique<std::future<void>>(hci_command_promise_->get_future());
+  }
+
+  std::future<void> GetOutgoingCommandFuture() {
+    hci_command_promise_ = std::make_unique<std::promise<void>>();
+    return hci_command_promise_->get_future();
   }
 
   CommandView GetLastCommand() {
@@ -173,9 +183,10 @@
   ConnectionManagementCommandView GetLastCommand(OpCode op_code) {
     if (!command_queue_.empty() && command_future_ != nullptr) {
       command_future_.reset();
-      command_promise_.reset();
+      hci_command_promise_.reset();
     } else if (command_future_ != nullptr) {
       command_future_->wait_for(std::chrono::milliseconds(1000));
+      hci_command_promise_.reset();
     }
     if (command_queue_.empty()) {
       return ConnectionManagementCommandView::Create(AclCommandView::Create(
@@ -188,6 +199,19 @@
     return command;
   }
 
+  ConnectionManagementCommandView GetLastOutgoingCommand() {
+    if (command_queue_.empty()) {
+      // An empty packet will force a failure on |IsValid()| required by all packets before usage
+      return ConnectionManagementCommandView::Create(AclCommandView::Create(
+          CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()))));
+    } else {
+      CommandView command_packet_view = GetLastCommand();
+      ConnectionManagementCommandView command =
+          ConnectionManagementCommandView::Create(AclCommandView::Create(command_packet_view));
+      return command;
+    }
+  }
+
   void RegisterEventHandler(EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) override {
     registered_events_[event_code] = event_handler;
   }
@@ -205,7 +229,7 @@
     registered_le_events_.erase(subevent_code);
   }
 
-  void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
+  void SendIncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
     auto packet = GetPacketView(std::move(event_builder));
     EventView event = EventView::Create(packet);
     ASSERT_TRUE(event.IsValid());
@@ -242,7 +266,7 @@
             queue_end,
             handle,
             common::Passed(std::move(promise))));
-    auto status = future.wait_for(kTimeout);
+    auto status = future.wait_for(2s);
     ASSERT_EQ(status, std::future_status::ready);
   }
 
@@ -291,7 +315,17 @@
     GetHandler()->Post(common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason));
   }
 
+  std::unique_ptr<std::promise<void>> hci_command_promise_;
+
  private:
+  void Notify() {
+    if (hci_command_promise_ != nullptr) {
+      std::promise<void>* prom = hci_command_promise_.release();
+      prom->set_value();
+      delete prom;
+    }
+  }
+
   std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
   std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
   std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
@@ -299,7 +333,6 @@
   BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
 
   std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
-  std::unique_ptr<std::promise<void>> command_promise_;
   std::unique_ptr<std::future<void>> command_future_;
 
   void do_disconnect(uint16_t handle, ErrorCode reason) {
@@ -307,90 +340,122 @@
   }
 };
 
-class AclManagerNoCallbacksTest : public ::testing::Test {
+class MockConnectionCallback : public ConnectionCallbacks {
+ public:
+  void OnConnectSuccess(std::unique_ptr<ClassicAclConnection> connection) override {
+    // Convert to std::shared_ptr during push_back()
+    connections_.push_back(std::move(connection));
+    if (is_promise_set_) {
+      is_promise_set_ = false;
+      connection_promise_.set_value(connections_.back());
+    }
+  }
+  MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
+
+  MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override));
+  MOCK_METHOD(void, HACK_OnScoConnectRequest, (Address, ClassOfDevice), (override));
+
+  size_t NumberOfConnections() const {
+    return connections_.size();
+  }
+
+ private:
+  friend class AclManagerWithCallbacksTest;
+  friend class AclManagerNoCallbacksTest;
+
+  std::deque<std::shared_ptr<ClassicAclConnection>> connections_;
+  std::promise<std::shared_ptr<ClassicAclConnection>> connection_promise_;
+  bool is_promise_set_{false};
+};
+
+class MockLeConnectionCallbacks : public LeConnectionCallbacks {
+ public:
+  void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection) override {
+    le_connections_.push_back(std::move(connection));
+    if (le_connection_promise_ != nullptr) {
+      std::promise<void>* prom = le_connection_promise_.release();
+      prom->set_value();
+      delete prom;
+    }
+  }
+  MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
+
+  std::deque<std::shared_ptr<LeAclConnection>> le_connections_;
+  std::unique_ptr<std::promise<void>> le_connection_promise_;
+};
+
+class AclManagerBaseTest : public ::testing::Test {
  protected:
   void SetUp() override {
+    common::InitFlags::SetAllForTesting();
     test_hci_layer_ = new TestHciLayer;  // Ownership is transferred to registry
+    ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
     test_controller_ = new TestController;
     fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
     fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
     client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
     ASSERT_NE(client_handler_, nullptr);
-    test_hci_layer_->SetCommandFuture();
     fake_registry_.Start<AclManager>(&thread_);
-    acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
-    Address::FromString("A1:A2:A3:A4:A5:A6", remote);
-
-    hci::Address address;
-    Address::FromString("D0:05:04:03:02:01", address);
-    hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
-    auto minimum_rotation_time = std::chrono::milliseconds(7 * 60 * 1000);
-    auto maximum_rotation_time = std::chrono::milliseconds(15 * 60 * 1000);
-    acl_manager_->SetPrivacyPolicyForInitiatorAddress(
-        LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS,
-        address_with_type,
-        minimum_rotation_time,
-        maximum_rotation_time);
-
-    auto set_random_address_packet = LeSetRandomAddressView::Create(
-        LeAdvertisingCommandView::Create(test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS)));
-    ASSERT_TRUE(set_random_address_packet.IsValid());
-    my_initiating_address =
-        AddressWithType(set_random_address_packet.GetRandomAddress(), AddressType::RANDOM_DEVICE_ADDRESS);
-    // Verify LE Set Random Address was sent during setup
-    test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
-    test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+    ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
   }
 
   void TearDown() override {
-    mock_connection_callbacks_.connections_.clear();
-    mock_le_connection_callbacks_.le_connections_.clear();
-
     fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
     fake_registry_.StopAll();
   }
 
-  TestModuleRegistry fake_registry_;
+  void sync_client_handler() {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    auto future_status = future.wait_for(std::chrono::seconds(1));
+    ASSERT_EQ(future_status, std::future_status::ready);
+  }
+
   TestHciLayer* test_hci_layer_ = nullptr;
   TestController* test_controller_ = nullptr;
+
+  TestModuleRegistry fake_registry_;
   os::Thread& thread_ = fake_registry_.GetTestThread();
   AclManager* acl_manager_ = nullptr;
   os::Handler* client_handler_ = nullptr;
-  Address remote;
-  AddressWithType my_initiating_address;
+};
+
+class AclManagerNoCallbacksTest : public AclManagerBaseTest {
+ protected:
+  void SetUp() override {
+    AclManagerBaseTest::SetUp();
+    ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
+
+    acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
+
+    local_address_with_type_ = AddressWithType(
+        Address::FromString(kLocalRandomAddressString).value(), hci::AddressType::RANDOM_DEVICE_ADDRESS);
+
+    ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
+    auto future = test_hci_layer_->GetOutgoingCommandFuture();
+
+    acl_manager_->SetPrivacyPolicyForInitiatorAddress(
+        LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS,
+        local_address_with_type_,
+        kMinimumRotationTime,
+        kMaximumRotationTime);
+
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+    sync_client_handler();
+    ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
+    auto command = test_hci_layer_->GetLastOutgoingCommand();
+    ASSERT_TRUE(command.IsValid());
+    ASSERT_EQ(OpCode::LE_SET_RANDOM_ADDRESS, command.GetOpCode());
+  }
+
+  void TearDown() override {
+    AclManagerBaseTest::TearDown();
+  }
+
+  AddressWithType local_address_with_type_;
   const bool use_connect_list_ = true;  // gd currently only supports connect list
 
-  void check_connection_promise_not_null() {
-    ASSERT_TRUE(mock_connection_callbacks_.connection_promise_ == nullptr)
-        << "Promises promises ... Only one at a time";
-  }
-
-  std::future<void> GetConnectionFuture() {
-    check_connection_promise_not_null();
-    mock_connection_callbacks_.connection_promise_ = std::make_unique<std::promise<void>>();
-    return mock_connection_callbacks_.connection_promise_->get_future();
-  }
-
-  std::future<void> GetLeConnectionFuture() {
-    check_connection_promise_not_null();
-    mock_le_connection_callbacks_.le_connection_promise_ = std::make_unique<std::promise<void>>();
-    return mock_le_connection_callbacks_.le_connection_promise_->get_future();
-  }
-
-  void check_connections_not_empty() {
-    ASSERT_TRUE(!mock_connection_callbacks_.connections_.empty()) << "There are no classic ACL connections";
-  }
-
-  std::shared_ptr<ClassicAclConnection> GetLastConnection() {
-    check_connections_not_empty();
-    return mock_connection_callbacks_.connections_.back();
-  }
-
-  std::shared_ptr<LeAclConnection> GetLastLeConnection() {
-    check_connections_not_empty();
-    return mock_le_connection_callbacks_.le_connections_.back();
-  }
-
   void SendAclData(uint16_t handle, AclConnection::QueueUpEnd* queue_end) {
     std::promise<void> promise;
     auto future = promise.get_future();
@@ -405,51 +470,18 @@
             queue_end,
             handle,
             common::Passed(std::move(promise))));
-    auto status = future.wait_for(kTimeout);
+    auto status = future.wait_for(2s);
     ASSERT_EQ(status, std::future_status::ready);
   }
-
-  class MockConnectionCallback : public ConnectionCallbacks {
-   public:
-    void OnConnectSuccess(std::unique_ptr<ClassicAclConnection> connection) override {
-      // Convert to std::shared_ptr during push_back()
-      connections_.push_back(std::move(connection));
-      if (connection_promise_ != nullptr) {
-        connection_promise_->set_value();
-        connection_promise_.reset();
-      }
-    }
-    MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
-
-    MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override));
-    MOCK_METHOD(void, HACK_OnScoConnectRequest, (Address, ClassOfDevice), (override));
-
-    std::list<std::shared_ptr<ClassicAclConnection>> connections_;
-    std::unique_ptr<std::promise<void>> connection_promise_;
-  } mock_connection_callbacks_;
-
-  class MockLeConnectionCallbacks : public LeConnectionCallbacks {
-   public:
-    void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection) override {
-      le_connections_.push_back(std::move(connection));
-      if (le_connection_promise_ != nullptr) {
-        le_connection_promise_->set_value();
-        le_connection_promise_.reset();
-      }
-    }
-    MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
-
-    std::list<std::shared_ptr<LeAclConnection>> le_connections_;
-    std::unique_ptr<std::promise<void>> le_connection_promise_;
-  } mock_le_connection_callbacks_;
 };
 
-class AclManagerTest : public AclManagerNoCallbacksTest {
+class AclManagerWithCallbacksTest : public AclManagerNoCallbacksTest {
  protected:
   void SetUp() override {
     AclManagerNoCallbacksTest::SetUp();
     acl_manager_->RegisterCallbacks(&mock_connection_callbacks_, client_handler_);
     acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
+    ASSERT_TRUE(test_hci_layer_->hci_command_promise_ == nullptr) << "hci command is nullptr";
   }
 
   void TearDown() override {
@@ -468,16 +500,53 @@
       acl_manager_->UnregisterCallbacks(&mock_connection_callbacks_, std::move(promise));
       future.wait_for(2s);
     }
+
+    mock_connection_callbacks_.connections_.clear();
+    mock_le_connection_callbacks_.le_connections_.clear();
+
     AclManagerNoCallbacksTest::TearDown();
   }
+
+  std::future<std::shared_ptr<ClassicAclConnection>> GetConnectionFuture() {
+    // Run on main thread
+    mock_connection_callbacks_.connection_promise_ = std::promise<std::shared_ptr<ClassicAclConnection>>();
+    mock_connection_callbacks_.is_promise_set_ = true;
+    return mock_connection_callbacks_.connection_promise_.get_future();
+  }
+
+  std::future<void> GetLeConnectionFuture() {
+    mock_le_connection_callbacks_.le_connection_promise_ = std::make_unique<std::promise<void>>();
+    return mock_le_connection_callbacks_.le_connection_promise_->get_future();
+  }
+
+  std::shared_ptr<ClassicAclConnection> GetLastConnection() {
+    return mock_connection_callbacks_.connections_.back();
+  }
+
+  size_t NumberOfConnections() {
+    return mock_connection_callbacks_.connections_.size();
+  }
+
+  std::shared_ptr<LeAclConnection> GetLastLeConnection() {
+    return mock_le_connection_callbacks_.le_connections_.back();
+  }
+
+  size_t NumberOfLeConnections() {
+    return mock_le_connection_callbacks_.le_connections_.size();
+  }
+
+  MockConnectionCallback mock_connection_callbacks_;
+  MockLeConnectionCallbacks mock_le_connection_callbacks_;
 };
 
-class AclManagerWithConnectionTest : public AclManagerTest {
+class AclManagerWithConnectionTest : public AclManagerWithCallbacksTest {
  protected:
   void SetUp() override {
-    AclManagerTest::SetUp();
+    AclManagerWithCallbacksTest::SetUp();
 
     handle_ = 0x123;
+    Address::FromString("A1:A2:A3:A4:A5:A6", remote);
+
     acl_manager_->CreateConnection(remote);
 
     // Wait for the connection request
@@ -489,10 +558,10 @@
     EXPECT_CALL(mock_connection_management_callbacks_, OnRoleChange(hci::ErrorCode::SUCCESS, Role::CENTRAL));
 
     auto first_connection = GetConnectionFuture();
-    test_hci_layer_->IncomingEvent(
+    test_hci_layer_->SendIncomingEvent(
         ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
 
-    auto first_connection_status = first_connection.wait_for(kTimeout);
+    auto first_connection_status = first_connection.wait_for(2s);
     ASSERT_EQ(first_connection_status, std::future_status::ready);
 
     connection_ = GetLastConnection();
@@ -505,15 +574,8 @@
     fake_registry_.StopAll();
   }
 
-  void sync_client_handler() {
-    std::promise<void> promise;
-    auto future = promise.get_future();
-    client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
-    auto future_status = future.wait_for(std::chrono::seconds(1));
-    ASSERT_EQ(future_status, std::future_status::ready);
-  }
-
   uint16_t handle_;
+  Address remote;
   std::shared_ptr<ClassicAclConnection> connection_;
 
   class MockConnectionManagementCallbacks : public ConnectionManagementCallbacks {
@@ -572,19 +634,20 @@
   } mock_connection_management_callbacks_;
 };
 
-TEST_F(AclManagerTest, startup_teardown) {}
+TEST_F(AclManagerWithCallbacksTest, startup_teardown) {}
 
-class AclManagerWithLeConnectionTest : public AclManagerTest {
+class AclManagerWithLeConnectionTest : public AclManagerWithCallbacksTest {
  protected:
   void SetUp() override {
-    AclManagerTest::SetUp();
+    AclManagerWithCallbacksTest::SetUp();
 
-    remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
-    test_hci_layer_->SetCommandFuture();
+    Address remote_public_address = Address::FromString(kRemotePublicDeviceStringA).value();
+    remote_with_type_ = AddressWithType(remote_public_address, AddressType::PUBLIC_DEVICE_ADDRESS);
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
     acl_manager_->CreateLeConnection(remote_with_type_, true);
     test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
-    test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
-    test_hci_layer_->SetCommandFuture();
+    test_hci_layer_->SendIncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
     auto packet = test_hci_layer_->GetCommand(OpCode::LE_CREATE_CONNECTION);
     auto le_connection_management_command_view =
         LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
@@ -594,11 +657,11 @@
       ASSERT_EQ(command_view.GetPeerAddress(), empty_address_with_type.GetAddress());
       ASSERT_EQ(command_view.GetPeerAddressType(), empty_address_with_type.GetAddressType());
     } else {
-      ASSERT_EQ(command_view.GetPeerAddress(), remote);
+      ASSERT_EQ(command_view.GetPeerAddress(), remote_public_address);
       ASSERT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
     }
 
-    test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
+    test_hci_layer_->SendIncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
 
     auto first_connection = GetLeConnectionFuture();
 
@@ -607,17 +670,18 @@
         handle_,
         Role::PERIPHERAL,
         AddressType::PUBLIC_DEVICE_ADDRESS,
-        remote,
+        remote_public_address,
         0x0100,
         0x0010,
         0x0C80,
         ClockAccuracy::PPM_30));
 
-    test_hci_layer_->SetCommandFuture();
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
     test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
-    test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+    test_hci_layer_->SendIncomingEvent(
+        LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
-    auto first_connection_status = first_connection.wait_for(kTimeout);
+    auto first_connection_status = first_connection.wait_for(2s);
     ASSERT_EQ(first_connection_status, std::future_status::ready);
 
     connection_ = GetLastLeConnection();
@@ -661,7 +725,7 @@
   } mock_le_connection_management_callbacks_;
 };
 
-class AclManagerWithResolvableAddressTest : public AclManagerNoCallbacksTest {
+class AclManagerWithResolvableAddressTest : public AclManagerWithCallbacksTest {
  protected:
   void SetUp() override {
     test_hci_layer_ = new TestHciLayer;  // Ownership is transferred to registry
@@ -670,11 +734,9 @@
     fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
     client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
     ASSERT_NE(client_handler_, nullptr);
-    test_hci_layer_->SetCommandFuture();
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
     fake_registry_.Start<AclManager>(&thread_);
     acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
-    Address::FromString("A1:A2:A3:A4:A5:A6", remote);
-
     hci::Address address;
     Address::FromString("D0:05:04:03:02:01", address);
     hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
@@ -689,25 +751,17 @@
         maximum_rotation_time);
 
     test_hci_layer_->GetLastCommand(OpCode::LE_SET_RANDOM_ADDRESS);
-    test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+    test_hci_layer_->SendIncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   }
 };
 
-class AclManagerLifeCycleTest : public AclManagerNoCallbacksTest {
- protected:
-  void SetUp() override {
-    AclManagerNoCallbacksTest::SetUp();
-    acl_manager_->RegisterCallbacks(&mock_connection_callbacks_, client_handler_);
-    acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
-  }
-
-  AddressWithType remote_with_type_;
-  uint16_t handle_{0x123};
-};
-
-TEST_F(AclManagerLifeCycleTest, unregister_classic_before_connection_request) {
+TEST_F(AclManagerNoCallbacksTest, unregister_classic_before_connection_request) {
   ClassOfDevice class_of_device;
 
+  MockConnectionCallback mock_connection_callbacks_;
+
+  acl_manager_->RegisterCallbacks(&mock_connection_callbacks_, client_handler_);
+
   // Unregister callbacks before receiving connection request
   auto promise = std::promise<void>();
   auto future = promise.get_future();
@@ -715,103 +769,126 @@
   future.get();
 
   // Inject peer sending connection request
-  auto connection_future = GetConnectionFuture();
-  test_hci_layer_->IncomingEvent(
-      ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
-  auto connection_future_status = connection_future.wait_for(kTimeout);
-  ASSERT_NE(connection_future_status, std::future_status::ready);
+  test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+      local_address_with_type_.GetAddress(), class_of_device, ConnectionRequestLinkType::ACL));
+  sync_client_handler();
 
-  test_hci_layer_->GetLastCommand(OpCode::REJECT_CONNECTION_REQUEST);
+  // There should be no connections
+  ASSERT_EQ(0UL, mock_connection_callbacks_.NumberOfConnections());
+
+  auto command = test_hci_layer_->GetLastOutgoingCommand();
+  ASSERT_TRUE(command.IsValid());
+  ASSERT_EQ(OpCode::REJECT_CONNECTION_REQUEST, command.GetOpCode());
 }
 
-TEST_F(AclManagerTest, two_remote_connection_requests_ABAB) {
-  struct {
-    Address address;
-    ClassOfDevice class_of_device;
-    const uint16_t handle;
-  } remote[2] = {
-      {
-          .address = {},
-          .class_of_device = {},
-          .handle = 123,
-      },
-      {.address = {}, .class_of_device = {}, .handle = 456},
-  };
-  Address::FromString("A1:A2:A3:A4:A5:A6", remote[0].address);
-  Address::FromString("B1:B2:B3:B4:B5:B6", remote[1].address);
-
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->IncomingEvent(
-      ConnectionRequestBuilder::Create(remote[0].address, remote[0].class_of_device, ConnectionRequestLinkType::ACL));
-  test_hci_layer_->GetLastCommand(OpCode::ACCEPT_CONNECTION_REQUEST);
-
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->IncomingEvent(
-      ConnectionRequestBuilder::Create(remote[1].address, remote[1].class_of_device, ConnectionRequestLinkType::ACL));
-  test_hci_layer_->GetLastCommand(OpCode::ACCEPT_CONNECTION_REQUEST);
+TEST_F(AclManagerWithCallbacksTest, two_remote_connection_requests_ABAB) {
+  Address::FromString(kRemotePublicDeviceStringA, remote_device[0].address);
+  Address::FromString(kRemotePublicDeviceStringB, remote_device[1].address);
 
   {
-    auto first_connection = GetConnectionFuture();
-    test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create(
-        ErrorCode::SUCCESS, remote[0].handle, remote[0].address, LinkType::ACL, Enable::DISABLED));
-    auto first_connection_status = first_connection.wait_for(kTimeout);
-    ASSERT_EQ(first_connection_status, std::future_status::ready);
+    // Device A sends connection request
+    auto future = test_hci_layer_->GetOutgoingCommandFuture();
+    test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+        remote_device[0].address, remote_device[0].class_of_device, ConnectionRequestLinkType::ACL));
+    sync_client_handler();
+    // Verify we accept this connection
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+    auto command = test_hci_layer_->GetLastOutgoingCommand();
+    ASSERT_TRUE(command.IsValid());
+    ASSERT_EQ(OpCode::ACCEPT_CONNECTION_REQUEST, command.GetOpCode());
   }
-  ASSERT_EQ(GetLastConnection()->GetAddress(), remote[0].address);
 
   {
-    auto first_connection = GetConnectionFuture();
-    test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create(
-        ErrorCode::SUCCESS, remote[1].handle, remote[1].address, LinkType::ACL, Enable::DISABLED));
-    auto first_connection_status = first_connection.wait_for(2s);
-    ASSERT_EQ(first_connection_status, std::future_status::ready);
+    // Device B sends connection request
+    auto future = test_hci_layer_->GetOutgoingCommandFuture();
+    test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+        remote_device[1].address, remote_device[1].class_of_device, ConnectionRequestLinkType::ACL));
+    sync_client_handler();
+    // Verify we accept this connection
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+    auto command = test_hci_layer_->GetLastOutgoingCommand();
+    ASSERT_TRUE(command.IsValid());
+    ASSERT_EQ(OpCode::ACCEPT_CONNECTION_REQUEST, command.GetOpCode());
   }
-  ASSERT_EQ(GetLastConnection()->GetAddress(), remote[1].address);
+
+  ASSERT_EQ(0UL, NumberOfConnections());
+
+  {
+    // Device A completes first connection
+    auto future = GetConnectionFuture();
+    test_hci_layer_->SendIncomingEvent(ConnectionCompleteBuilder::Create(
+        ErrorCode::SUCCESS, remote_device[0].handle, remote_device[0].address, LinkType::ACL, Enable::DISABLED));
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s)) << "Timeout waiting for first connection complete";
+    ASSERT_EQ(1UL, NumberOfConnections());
+    auto connection = future.get();
+    ASSERT_EQ(connection->GetAddress(), remote_device[0].address) << "First connection remote address mismatch";
+  }
+
+  {
+    // Device B completes second connection
+    auto future = GetConnectionFuture();
+    test_hci_layer_->SendIncomingEvent(ConnectionCompleteBuilder::Create(
+        ErrorCode::SUCCESS, remote_device[1].handle, remote_device[1].address, LinkType::ACL, Enable::DISABLED));
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s)) << "Timeout waiting for second connection complete";
+    ASSERT_EQ(2UL, NumberOfConnections());
+    auto connection = future.get();
+    ASSERT_EQ(connection->GetAddress(), remote_device[1].address) << "Second connection remote address mismatch";
+  }
 }
 
-TEST_F(AclManagerTest, two_remote_connection_requests_ABBA) {
-  struct {
-    Address address;
-    ClassOfDevice class_of_device;
-    const uint16_t handle;
-  } remote[2] = {
-      {
-          .address = {},
-          .class_of_device = {},
-          .handle = 123,
-      },
-      {.address = {}, .class_of_device = {}, .handle = 456},
-  };
-  Address::FromString("A1:A2:A3:A4:A5:A6", remote[0].address);
-  Address::FromString("B1:B2:B3:B4:B5:B6", remote[1].address);
-
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->IncomingEvent(
-      ConnectionRequestBuilder::Create(remote[0].address, remote[0].class_of_device, ConnectionRequestLinkType::ACL));
-  test_hci_layer_->GetLastCommand(OpCode::ACCEPT_CONNECTION_REQUEST);
-
-  test_hci_layer_->SetCommandFuture();
-  test_hci_layer_->IncomingEvent(
-      ConnectionRequestBuilder::Create(remote[1].address, remote[1].class_of_device, ConnectionRequestLinkType::ACL));
-  test_hci_layer_->GetLastCommand(OpCode::ACCEPT_CONNECTION_REQUEST);
+TEST_F(AclManagerWithCallbacksTest, two_remote_connection_requests_ABBA) {
+  Address::FromString(kRemotePublicDeviceStringA, remote_device[0].address);
+  Address::FromString(kRemotePublicDeviceStringB, remote_device[1].address);
 
   {
-    auto first_connection = GetConnectionFuture();
-    test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create(
-        ErrorCode::SUCCESS, remote[1].handle, remote[1].address, LinkType::ACL, Enable::DISABLED));
-    auto first_connection_status = first_connection.wait_for(2s);
-    ASSERT_EQ(first_connection_status, std::future_status::ready);
+    // Device A sends connection request
+    auto future = test_hci_layer_->GetOutgoingCommandFuture();
+    test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+        remote_device[0].address, remote_device[0].class_of_device, ConnectionRequestLinkType::ACL));
+    sync_client_handler();
+    // Verify we accept this connection
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+    auto command = test_hci_layer_->GetLastOutgoingCommand();
+    ASSERT_TRUE(command.IsValid());
+    ASSERT_EQ(OpCode::ACCEPT_CONNECTION_REQUEST, command.GetOpCode());
   }
-  ASSERT_EQ(GetLastConnection()->GetAddress(), remote[1].address);
 
   {
-    auto first_connection = GetConnectionFuture();
-    test_hci_layer_->IncomingEvent(ConnectionCompleteBuilder::Create(
-        ErrorCode::SUCCESS, remote[0].handle, remote[0].address, LinkType::ACL, Enable::DISABLED));
-    auto first_connection_status = first_connection.wait_for(kTimeout);
-    ASSERT_EQ(first_connection_status, std::future_status::ready);
+    // Device B sends connection request
+    auto future = test_hci_layer_->GetOutgoingCommandFuture();
+    test_hci_layer_->SendIncomingEvent(ConnectionRequestBuilder::Create(
+        remote_device[1].address, remote_device[1].class_of_device, ConnectionRequestLinkType::ACL));
+    sync_client_handler();
+    // Verify we accept this connection
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s));
+    auto command = test_hci_layer_->GetLastOutgoingCommand();
+    ASSERT_TRUE(command.IsValid());
+    ASSERT_EQ(OpCode::ACCEPT_CONNECTION_REQUEST, command.GetOpCode());
   }
-  ASSERT_EQ(GetLastConnection()->GetAddress(), remote[0].address);
+
+  ASSERT_EQ(0UL, NumberOfConnections());
+
+  {
+    // Device B completes first connection
+    auto future = GetConnectionFuture();
+    test_hci_layer_->SendIncomingEvent(ConnectionCompleteBuilder::Create(
+        ErrorCode::SUCCESS, remote_device[1].handle, remote_device[1].address, LinkType::ACL, Enable::DISABLED));
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s)) << "Timeout waiting for first connection complete";
+    ASSERT_EQ(1UL, NumberOfConnections());
+    auto connection = future.get();
+    ASSERT_EQ(connection->GetAddress(), remote_device[1].address) << "First connection remote address mismatch";
+  }
+
+  {
+    // Device A completes second connection
+    auto future = GetConnectionFuture();
+    test_hci_layer_->SendIncomingEvent(ConnectionCompleteBuilder::Create(
+        ErrorCode::SUCCESS, remote_device[0].handle, remote_device[0].address, LinkType::ACL, Enable::DISABLED));
+    ASSERT_EQ(std::future_status::ready, future.wait_for(2s)) << "Timeout waiting for second connection complete";
+    ASSERT_EQ(2UL, NumberOfConnections());
+    auto connection = future.get();
+    ASSERT_EQ(connection->GetAddress(), remote_device[0].address) << "Second connection remote address mismatch";
+  }
 }
 
 }  // namespace
diff --git a/system/gd/hci/address.cc b/system/gd/hci/address.cc
index 3dc013f..7409418 100644
--- a/system/gd/hci/address.cc
+++ b/system/gd/hci/address.cc
@@ -42,10 +42,15 @@
   std::copy(l.begin(), std::min(l.begin() + kLength, l.end()), data());
 }
 
-std::string Address::ToString() const {
+std::string Address::_ToMaskedColonSepHexString(int bytes_to_mask) const {
   std::stringstream ss;
+  int count = 0;
   for (auto it = address.rbegin(); it != address.rend(); it++) {
-    ss << std::nouppercase << std::hex << std::setw(2) << std::setfill('0') << +*it;
+    if (count++ < bytes_to_mask) {
+      ss << "xx";
+    } else {
+      ss << std::nouppercase << std::hex << std::setw(2) << std::setfill('0') << +*it;
+    }
     if (std::next(it) != address.rend()) {
       ss << ':';
     }
@@ -53,6 +58,22 @@
   return ss.str();
 }
 
+std::string Address::ToString() const {
+  return _ToMaskedColonSepHexString(0);
+}
+
+std::string Address::ToColonSepHexString() const {
+  return _ToMaskedColonSepHexString(0);
+}
+
+std::string Address::ToStringForLogging() const {
+  return _ToMaskedColonSepHexString(0);
+}
+
+std::string Address::ToRedactedStringForLogging() const {
+  return _ToMaskedColonSepHexString(4);
+}
+
 std::string Address::ToLegacyConfigString() const {
   return ToString();
 }
diff --git a/system/gd/hci/address.h b/system/gd/hci/address.h
index c5e43d4..2c1dfff 100644
--- a/system/gd/hci/address.h
+++ b/system/gd/hci/address.h
@@ -25,13 +25,16 @@
 #include <ostream>
 #include <string>
 
+#include "common/interfaces/ILoggable.h"
 #include "packet/custom_field_fixed_size_interface.h"
 #include "storage/serializable.h"
 
 namespace bluetooth {
 namespace hci {
 
-class Address final : public packet::CustomFieldFixedSizeInterface<Address>, public storage::Serializable<Address> {
+class Address final : public packet::CustomFieldFixedSizeInterface<Address>,
+                      public storage::Serializable<Address>,
+                      public bluetooth::common::IRedactableLoggable {
  public:
   static constexpr size_t kLength = 6;
 
@@ -51,6 +54,10 @@
 
   // storage::Serializable methods
   std::string ToString() const override;
+  std::string ToColonSepHexString() const;
+  std::string ToStringForLogging() const override;
+  std::string ToRedactedStringForLogging() const override;
+
   static std::optional<Address> FromString(const std::string& from);
   std::string ToLegacyConfigString() const override;
   static std::optional<Address> FromLegacyConfigString(const std::string& str);
@@ -91,8 +98,12 @@
 
   static const Address kEmpty;  // 00:00:00:00:00:00
   static const Address kAny;    // FF:FF:FF:FF:FF:FF
+ private:
+  std::string _ToMaskedColonSepHexString(int bytes_to_mask) const;
 };
 
+// TODO: to fine-tune this.
+// we need an interface between the logger and ILoggable
 inline std::ostream& operator<<(std::ostream& os, const Address& a) {
   os << a.ToString();
   return os;
diff --git a/system/gd/hci/address_unittest.cc b/system/gd/hci/address_unittest.cc
index ae2c2e7..a675682 100644
--- a/system/gd/hci/address_unittest.cc
+++ b/system/gd/hci/address_unittest.cc
@@ -16,12 +16,14 @@
  *
  ******************************************************************************/
 
-#include <unordered_map>
+#include "hci/address.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "hci/address.h"
+#include <cstdint>
+#include <string>
+#include <unordered_map>
 
 using bluetooth::hci::Address;
 
@@ -233,3 +235,14 @@
   struct std::hash<Address> hasher;
   ASSERT_NE(hasher(Address::kEmpty), hasher(Address::kAny));
 }
+
+TEST(AddressTest, ToStringForLoggingTestOutputUnderDebuggablePropAndInitFlag) {
+  Address addr{{0xab, 0x55, 0x44, 0x33, 0x22, 0x11}};
+  const std::string redacted_loggable_str = "xx:xx:xx:xx:55:ab";
+  const std::string loggable_str = "11:22:33:44:55:ab";
+
+  std::string ret1 = addr.ToStringForLogging();
+  ASSERT_STREQ(ret1.c_str(), loggable_str.c_str());
+  std::string ret2 = addr.ToRedactedStringForLogging();
+  ASSERT_STREQ(ret2.c_str(), redacted_loggable_str.c_str());
+}
diff --git a/system/gd/hci/address_with_type.h b/system/gd/hci/address_with_type.h
index ec4d40c..75a0b3c 100644
--- a/system/gd/hci/address_with_type.h
+++ b/system/gd/hci/address_with_type.h
@@ -22,6 +22,7 @@
 #include <string>
 #include <utility>
 
+#include "common/interfaces/ILoggable.h"
 #include "crypto_toolbox/crypto_toolbox.h"
 #include "hci/address.h"
 #include "hci/hci_packets.h"
@@ -29,7 +30,7 @@
 namespace bluetooth {
 namespace hci {
 
-class AddressWithType final {
+class AddressWithType final : public bluetooth::common::IRedactableLoggable {
  public:
   AddressWithType(Address address, AddressType address_type)
       : address_(std::move(address)), address_type_(address_type) {}
@@ -119,6 +120,14 @@
     return ss.str();
   }
 
+  std::string ToStringForLogging() const override {
+    return address_.ToStringForLogging() + "[" + AddressTypeText(address_type_) + "]";
+  }
+
+  std::string ToRedactedStringForLogging() const override {
+    return address_.ToStringForLogging() + "[" + AddressTypeText(address_type_) + "]";
+  }
+
  private:
   Address address_;
   AddressType address_type_;
diff --git a/system/gd/hci/controller.cc b/system/gd/hci/controller.cc
index 3c8b69d..9dac2b6 100644
--- a/system/gd/hci/controller.cc
+++ b/system/gd/hci/controller.cc
@@ -870,27 +870,27 @@
 
   CompletedAclPacketsCallback acl_credits_callback_{};
   CompletedAclPacketsCallback acl_monitor_credits_callback_{};
-  LocalVersionInformation local_version_information_;
-  std::array<uint8_t, 64> local_supported_commands_;
-  std::vector<uint64_t> extended_lmp_features_array_;
-  uint16_t acl_buffer_length_ = 0;
-  uint16_t acl_buffers_ = 0;
-  uint8_t sco_buffer_length_ = 0;
-  uint16_t sco_buffers_ = 0;
-  Address mac_address_;
-  std::string local_name_;
-  LeBufferSize le_buffer_size_;
-  LeBufferSize iso_buffer_size_;
-  uint64_t le_local_supported_features_;
-  uint64_t le_supported_states_;
-  uint8_t le_connect_list_size_;
-  uint8_t le_resolving_list_size_;
-  LeMaximumDataLength le_maximum_data_length_;
-  uint16_t le_maximum_advertising_data_length_;
-  uint16_t le_suggested_default_data_length_;
-  uint8_t le_number_supported_advertising_sets_;
-  uint8_t le_periodic_advertiser_list_size_;
-  VendorCapabilities vendor_capabilities_;
+  LocalVersionInformation local_version_information_{};
+  std::array<uint8_t, 64> local_supported_commands_{};
+  std::vector<uint64_t> extended_lmp_features_array_{};
+  uint16_t acl_buffer_length_{};
+  uint16_t acl_buffers_{};
+  uint8_t sco_buffer_length_{};
+  uint16_t sco_buffers_{};
+  Address mac_address_{};
+  std::string local_name_{};
+  LeBufferSize le_buffer_size_{};
+  LeBufferSize iso_buffer_size_{};
+  uint64_t le_local_supported_features_{};
+  uint64_t le_supported_states_{};
+  uint8_t le_connect_list_size_{};
+  uint8_t le_resolving_list_size_{};
+  LeMaximumDataLength le_maximum_data_length_{};
+  uint16_t le_maximum_advertising_data_length_{};
+  uint16_t le_suggested_default_data_length_{};
+  uint8_t le_number_supported_advertising_sets_{};
+  uint8_t le_periodic_advertiser_list_size_{};
+  VendorCapabilities vendor_capabilities_{};
 };  // namespace hci
 
 Controller::Controller() : impl_(std::make_unique<impl>(*this)) {}
diff --git a/system/gd/hci/controller_test.cc b/system/gd/hci/controller_test.cc
index dacdef7..6353482 100644
--- a/system/gd/hci/controller_test.cc
+++ b/system/gd/hci/controller_test.cc
@@ -54,7 +54,6 @@
 uint16_t feature_spec_version = 55;
 constexpr char title[] = "hci_controller_test";
 
-
 PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
   auto bytes = std::make_shared<std::vector<uint8_t>>();
   BitInserter i(*bytes);
@@ -65,6 +64,8 @@
 
 }  // namespace
 
+namespace {
+
 class TestHciLayer : public HciLayer {
  public:
   void EnqueueCommand(
@@ -281,9 +282,11 @@
   std::condition_variable not_empty_;
 };
 
+}  // namespace
 class ControllerTest : public ::testing::Test {
  protected:
   void SetUp() override {
+    feature_spec_version = feature_spec_version_;
     bluetooth::common::InitFlags::SetAllForTesting();
     test_hci_layer_ = new TestHciLayer;
     fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
@@ -301,6 +304,31 @@
   os::Thread& thread_ = fake_registry_.GetTestThread();
   Controller* controller_ = nullptr;
   os::Handler* client_handler_ = nullptr;
+  uint16_t feature_spec_version_ = 98;
+};
+
+class Controller055Test : public ControllerTest {
+ protected:
+  void SetUp() override {
+    feature_spec_version_ = 55;
+    ControllerTest::SetUp();
+  }
+};
+
+class Controller095Test : public ControllerTest {
+ protected:
+  void SetUp() override {
+    feature_spec_version_ = 95;
+    ControllerTest::SetUp();
+  }
+};
+
+class Controller096Test : public ControllerTest {
+ protected:
+  void SetUp() override {
+    feature_spec_version_ = 96;
+    ControllerTest::SetUp();
+  }
 };
 
 TEST_F(ControllerTest, startup_teardown) {}
@@ -407,28 +435,25 @@
   ASSERT_FALSE(controller_->IsSupported(OpCode::LE_SET_PERIODIC_ADVERTISING_PARAM));
 }
 
-TEST_F(ControllerTest, feature_spec_version_055_test) {
+TEST_F(Controller055Test, feature_spec_version_055_test) {
   ASSERT_EQ(controller_->GetVendorCapabilities().version_supported_, 55);
   ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
   ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
   ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
-  feature_spec_version = 95;
 }
 
-TEST_F(ControllerTest, feature_spec_version_095_test) {
+TEST_F(Controller095Test, feature_spec_version_095_test) {
   ASSERT_EQ(controller_->GetVendorCapabilities().version_supported_, 95);
   ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
   ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
   ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
-  feature_spec_version = 96;
 }
 
-TEST_F(ControllerTest, feature_spec_version_096_test) {
+TEST_F(Controller096Test, feature_spec_version_096_test) {
   ASSERT_EQ(controller_->GetVendorCapabilities().version_supported_, 96);
   ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
   ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
   ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
-  feature_spec_version = 98;
 }
 
 TEST_F(ControllerTest, feature_spec_version_098_test) {
@@ -436,7 +461,6 @@
   ASSERT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
   ASSERT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
   ASSERT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
-  feature_spec_version = 55;
 }
 
 std::promise<void> credits1_set;
diff --git a/system/gd/hci/hci_layer_fake.cc b/system/gd/hci/hci_layer_fake.cc
index 65ef988..3000c56 100644
--- a/system/gd/hci/hci_layer_fake.cc
+++ b/system/gd/hci/hci_layer_fake.cc
@@ -25,6 +25,8 @@
 namespace bluetooth {
 namespace hci {
 
+using common::BidiQueue;
+using common::BidiQueueEnd;
 using packet::kLittleEndian;
 using packet::PacketView;
 using packet::RawBuilder;
@@ -37,6 +39,22 @@
   return packet::PacketView<packet::kLittleEndian>(bytes);
 }
 
+std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle) {
+  static uint32_t packet_number = 1;
+  auto payload = std::make_unique<RawBuilder>();
+  payload->AddOctets2(6);  // L2CAP PDU size
+  payload->AddOctets2(2);  // L2CAP CID
+  payload->AddOctets2(handle);
+  payload->AddOctets4(packet_number++);
+  return std::move(payload);
+}
+
+static std::unique_ptr<AclBuilder> NextAclPacket(uint16_t handle) {
+  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+  BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+  return AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle));
+}
+
 void TestHciLayer::EnqueueCommand(
     std::unique_ptr<CommandBuilder> command, common::ContextualOnceCallback<void(CommandStatusView)> on_status) {
   std::lock_guard<std::mutex> lock(mutex_);
@@ -150,10 +168,59 @@
   ASSERT_TRUE(empty_command_view_.IsValid());
 }
 
+void TestHciLayer::IncomingAclData(uint16_t handle) {
+  os::Handler* hci_handler = GetHandler();
+  auto* queue_end = acl_queue_.GetDownEnd();
+  std::promise<void> promise;
+  auto future = promise.get_future();
+  queue_end->RegisterEnqueue(
+      hci_handler,
+      common::Bind(
+          [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) {
+            auto packet = GetPacketView(NextAclPacket(handle));
+            AclView acl2 = AclView::Create(packet);
+            queue_end->UnregisterEnqueue();
+            promise.set_value();
+            return std::make_unique<AclView>(acl2);
+          },
+          queue_end,
+          handle,
+          common::Passed(std::move(promise))));
+  auto status = future.wait_for(std::chrono::milliseconds(1000));
+  ASSERT_EQ(status, std::future_status::ready);
+}
+
+void TestHciLayer::AssertNoOutgoingAclData() {
+  auto queue_end = acl_queue_.GetDownEnd();
+  EXPECT_EQ(queue_end->TryDequeue(), nullptr);
+}
+
+PacketView<kLittleEndian> TestHciLayer::OutgoingAclData() {
+  auto queue_end = acl_queue_.GetDownEnd();
+  std::unique_ptr<AclBuilder> received;
+  do {
+    received = queue_end->TryDequeue();
+  } while (received == nullptr);
+
+  return GetPacketView(std::move(received));
+}
+
+BidiQueueEnd<AclBuilder, AclView>* TestHciLayer::GetAclQueueEnd() {
+  return acl_queue_.GetUpEnd();
+}
+
+void TestHciLayer::Disconnect(uint16_t handle, ErrorCode reason) {
+  GetHandler()->Post(
+      common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason));
+}
+
+void TestHciLayer::do_disconnect(uint16_t handle, ErrorCode reason) {
+  HciLayer::Disconnect(handle, reason);
+}
+
 void TestHciLayer::ListDependencies(ModuleList* list) const {}
 void TestHciLayer::Start() {
   std::lock_guard<std::mutex> lock(mutex_);
-
   InitEmptyCommand();
 }
 void TestHciLayer::Stop() {}
diff --git a/system/gd/hci/hci_layer_fake.h b/system/gd/hci/hci_layer_fake.h
index a944286..a2c3ea1 100644
--- a/system/gd/hci/hci_layer_fake.h
+++ b/system/gd/hci/hci_layer_fake.h
@@ -25,10 +25,10 @@
 namespace bluetooth {
 namespace hci {
 
-using packet::kLittleEndian;
-using packet::PacketView;
+packet::PacketView<packet::kLittleEndian> GetPacketView(
+    std::unique_ptr<packet::BasePacketBuilder> packet);
 
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet);
+std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle);
 
 class TestHciLayer : public HciLayer {
  public:
@@ -59,6 +59,16 @@
 
   void CommandStatusCallback(EventView event);
 
+  void IncomingAclData(uint16_t handle);
+
+  void AssertNoOutgoingAclData();
+
+  packet::PacketView<packet::kLittleEndian> OutgoingAclData();
+
+  common::BidiQueueEnd<AclBuilder, AclView>* GetAclQueueEnd() override;
+
+  void Disconnect(uint16_t handle, ErrorCode reason) override;
+
  protected:
   void ListDependencies(ModuleList* list) const override;
   void Start() override;
@@ -66,6 +76,7 @@
 
  private:
   void InitEmptyCommand();
+  void do_disconnect(uint16_t handle, ErrorCode reason);
 
   // Handler-only state. Mutexes are not needed when accessing these fields.
   std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
@@ -73,9 +84,12 @@
   std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
   std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
 
-  // Most operations must acquire this mutex before manipulating shared state. The ONLY exception is blocking on a
-  // promise, IF your thread is the only one mutating it. Note that SETTING a promise REQUIRES a lock, since another
-  // thread may replace the promise while you are doing so.
+  // thread-safe
+  common::BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
+
+  // Most operations must acquire this mutex before manipulating shared state. The ONLY exception
+  // is blocking on a promise, IF your thread is the only one mutating it. Note that SETTING a
+  // promise REQUIRES a lock, since another thread may replace the promise while you are doing so.
   mutable std::mutex mutex_{};
 
   // Shared state between the test and stack threads
@@ -83,13 +97,14 @@
 
   // We start with Consumed=Set, Command=Unset.
   // When a command is enqueued, we set Command=set
-  // When a command is popped, we block until Command=Set, then (if the queue is now empty) we reset Command=Unset and
-  // set Consumed=Set. This way we emulate a blocking queue.
-  std::promise<void> command_promise_{};                              // Set when at least one command is in the queue
-  std::future<void> command_future_ = command_promise_.get_future();  // GetCommand() blocks until this is fulfilled
+  // When a command is popped, we block until Command=Set, then (if the queue is now empty) we
+  // reset Command=Unset and set Consumed=Set. This way we emulate a blocking queue.
+  std::promise<void> command_promise_{};  // Set when at least one command is in the queue
+  std::future<void> command_future_ =
+      command_promise_.get_future();  // GetCommand() blocks until this is fulfilled
 
-  CommandView empty_command_view_ =
-      CommandView::Create(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
+  CommandView empty_command_view_ = CommandView::Create(
+      PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
 };
 
 }  // namespace hci
diff --git a/system/gd/hci/hci_layer_test.cc b/system/gd/hci/hci_layer_test.cc
index b0aaeaa..8735dcb 100644
--- a/system/gd/hci/hci_layer_test.cc
+++ b/system/gd/hci/hci_layer_test.cc
@@ -60,6 +60,7 @@
 
 namespace bluetooth {
 namespace hci {
+namespace {
 
 constexpr std::chrono::milliseconds kTimeout = HciLayer::kHciTimeoutMs / 2;
 constexpr std::chrono::milliseconds kAclTimeout = std::chrono::milliseconds(1000);
@@ -83,18 +84,18 @@
   void sendHciCommand(hal::HciPacket command) override {
     outgoing_commands_.push_back(std::move(command));
     if (sent_command_promise_ != nullptr) {
-      auto promise = std::move(sent_command_promise_);
-      sent_command_promise_.reset();
-      promise->set_value();
+      std::promise<void>* prom = sent_command_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
   void sendAclData(hal::HciPacket data) override {
     outgoing_acl_.push_back(std::move(data));
     if (sent_acl_promise_ != nullptr) {
-      auto promise = std::move(sent_acl_promise_);
-      sent_acl_promise_.reset();
-      promise->set_value();
+      std::promise<void>* prom = sent_acl_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
@@ -105,9 +106,9 @@
   void sendIsoData(hal::HciPacket data) override {
     outgoing_iso_.push_back(std::move(data));
     if (sent_iso_promise_ != nullptr) {
-      auto promise = std::move(sent_iso_promise_);
-      sent_iso_promise_.reset();
-      promise->set_value();
+      std::promise<void>* prom = sent_iso_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
@@ -290,7 +291,7 @@
     hci_->GetIsoQueueEnd()->UnregisterDequeue();
   }
 
-  void ListDependencies(ModuleList* list) {
+  void ListDependencies(ModuleList* list) const {
     list->add<HciLayer>();
   }
 
@@ -390,14 +391,14 @@
     ASSERT_EQ(reset_sent_status, std::future_status::ready);
 
     // Verify that reset was received
-    ASSERT_EQ(1, hal->GetNumSentCommands());
+    ASSERT_EQ(1u, hal->GetNumSentCommands());
 
     auto sent_command = hal->GetSentCommand();
     auto reset_view = ResetView::Create(CommandView::Create(sent_command));
     ASSERT_TRUE(reset_view.IsValid());
 
     // Verify that only one was sent
-    ASSERT_EQ(0, hal->GetNumSentCommands());
+    ASSERT_EQ(0u, hal->GetNumSentCommands());
 
     // Send the response event
     uint8_t num_packets = 1;
@@ -457,7 +458,7 @@
   ASSERT_TRUE(LeConnectionCompleteView::Create(LeMetaEventView::Create(EventView::Create(event))).IsValid());
 }
 
-TEST_F(HciTest, hciTimeOut) {
+TEST_F(HciTest, DISABLED_hciTimeOut) {
   auto event_future = upper->GetReceivedEventFuture();
   auto reset_command_future = hal->GetSentCommandFuture();
   upper->SendHciCommandExpectingComplete(ResetBuilder::Create());
@@ -478,7 +479,7 @@
 }
 
 TEST_F(HciTest, noOpCredits) {
-  ASSERT_EQ(0, hal->GetNumSentCommands());
+  ASSERT_EQ(0u, hal->GetNumSentCommands());
 
   // Send 0 credits
   uint8_t num_packets = 0;
@@ -488,7 +489,7 @@
   upper->SendHciCommandExpectingComplete(ReadLocalVersionInformationBuilder::Create());
 
   // Verify that nothing was sent
-  ASSERT_EQ(0, hal->GetNumSentCommands());
+  ASSERT_EQ(0u, hal->GetNumSentCommands());
 
   num_packets = 1;
   hal->callbacks->hciEventReceived(GetPacketBytes(NoCommandCompleteBuilder::Create(num_packets)));
@@ -497,7 +498,7 @@
   ASSERT_EQ(command_sent_status, std::future_status::ready);
 
   // Verify that one was sent
-  ASSERT_EQ(1, hal->GetNumSentCommands());
+  ASSERT_EQ(1u, hal->GetNumSentCommands());
 
   auto event_future = upper->GetReceivedEventFuture();
 
@@ -522,7 +523,7 @@
 }
 
 TEST_F(HciTest, creditsTest) {
-  ASSERT_EQ(0, hal->GetNumSentCommands());
+  ASSERT_EQ(0u, hal->GetNumSentCommands());
 
   auto command_future = hal->GetSentCommandFuture();
 
@@ -535,14 +536,14 @@
   ASSERT_EQ(command_sent_status, std::future_status::ready);
 
   // Verify that the first one is sent
-  ASSERT_EQ(1, hal->GetNumSentCommands());
+  ASSERT_EQ(1u, hal->GetNumSentCommands());
 
   auto sent_command = hal->GetSentCommand();
   auto version_view = ReadLocalVersionInformationView::Create(CommandView::Create(sent_command));
   ASSERT_TRUE(version_view.IsValid());
 
   // Verify that only one was sent
-  ASSERT_EQ(0, hal->GetNumSentCommands());
+  ASSERT_EQ(0u, hal->GetNumSentCommands());
 
   // Get a new future
   auto event_future = upper->GetReceivedEventFuture();
@@ -570,14 +571,14 @@
   // Verify that the second one is sent
   command_sent_status = command_future.wait_for(kTimeout);
   ASSERT_EQ(command_sent_status, std::future_status::ready);
-  ASSERT_EQ(1, hal->GetNumSentCommands());
+  ASSERT_EQ(1u, hal->GetNumSentCommands());
 
   sent_command = hal->GetSentCommand();
   auto supported_commands_view = ReadLocalSupportedCommandsView::Create(CommandView::Create(sent_command));
   ASSERT_TRUE(supported_commands_view.IsValid());
 
   // Verify that only one was sent
-  ASSERT_EQ(0, hal->GetNumSentCommands());
+  ASSERT_EQ(0u, hal->GetNumSentCommands());
   event_future = upper->GetReceivedEventFuture();
   command_future = hal->GetSentCommandFuture();
 
@@ -598,14 +599,14 @@
   // Verify that the third one is sent
   command_sent_status = command_future.wait_for(kTimeout);
   ASSERT_EQ(command_sent_status, std::future_status::ready);
-  ASSERT_EQ(1, hal->GetNumSentCommands());
+  ASSERT_EQ(1u, hal->GetNumSentCommands());
 
   sent_command = hal->GetSentCommand();
   auto supported_features_view = ReadLocalSupportedFeaturesView::Create(CommandView::Create(sent_command));
   ASSERT_TRUE(supported_features_view.IsValid());
 
   // Verify that only one was sent
-  ASSERT_EQ(0, hal->GetNumSentCommands());
+  ASSERT_EQ(0u, hal->GetNumSentCommands());
   event_future = upper->GetReceivedEventFuture();
 
   // Send the response event
@@ -631,7 +632,7 @@
 
   // Check the command
   auto sent_command = hal->GetSentCommand();
-  ASSERT_LT(0, sent_command.size());
+  ASSERT_LT(0u, sent_command.size());
   LeRandView view = LeRandView::Create(LeSecurityCommandView::Create(CommandView::Create(sent_command)));
   ASSERT_TRUE(view.IsValid());
 
@@ -662,7 +663,7 @@
 
   // Check the command
   auto sent_command = hal->GetSentCommand();
-  ASSERT_LT(0, sent_command.size());
+  ASSERT_LT(0u, sent_command.size());
   auto view = WriteSimplePairingModeView::Create(SecurityCommandView::Create(CommandView::Create(sent_command)));
   ASSERT_TRUE(view.IsValid());
 
@@ -699,7 +700,7 @@
 
   // Check the command
   auto sent_command = hal->GetSentCommand();
-  ASSERT_LT(0, sent_command.size());
+  ASSERT_LT(0u, sent_command.size());
   CreateConnectionView view = CreateConnectionView::Create(
       ConnectionManagementCommandView::Create(AclCommandView::Create(CommandView::Create(sent_command))));
   ASSERT_TRUE(view.IsValid());
@@ -776,7 +777,7 @@
   auto sent_acl_status = sent_acl_future.wait_for(kAclTimeout);
   ASSERT_EQ(sent_acl_status, std::future_status::ready);
   auto sent_acl = hal->GetSentAcl();
-  ASSERT_LT(0, sent_acl.size());
+  ASSERT_LT(0u, sent_acl.size());
   AclView sent_acl_view = AclView::Create(sent_acl);
   ASSERT_TRUE(sent_acl_view.IsValid());
   ASSERT_EQ(bd_addr.length() + sizeof(handle), sent_acl_view.GetPayload().size());
@@ -904,5 +905,7 @@
   ASSERT_EQ(handle, itr.extract<uint16_t>());
   ASSERT_EQ(received_packets, itr.extract<uint16_t>());
 }
+
+}  // namespace
 }  // namespace hci
 }  // namespace bluetooth
diff --git a/system/gd/hci/hci_layer_unittest.cc b/system/gd/hci/hci_layer_unittest.cc
index 3d88f06..d4c2423 100644
--- a/system/gd/hci/hci_layer_unittest.cc
+++ b/system/gd/hci/hci_layer_unittest.cc
@@ -168,11 +168,13 @@
 
 TEST_F(HciLayerTest, setup_teardown) {}
 
-TEST_F(HciLayerTest, reset_command_sent_on_start) {
+// b/260915548
+TEST_F(HciLayerTest, DISABLED_reset_command_sent_on_start) {
   FailIfResetNotSent();
 }
 
-TEST_F(HciLayerTest, controller_debug_info_requested_on_hci_timeout) {
+// b/260915548
+TEST_F(HciLayerTest, DISABLED_controller_debug_info_requested_on_hci_timeout) {
   FailIfResetNotSent();
   FakeTimerAdvance(HciLayer::kHciTimeoutMs.count());
 
@@ -183,7 +185,8 @@
   ASSERT_TRUE(debug_info_view.IsValid());
 }
 
-TEST_F(HciLayerTest, abort_after_hci_restart_timeout) {
+// b/260915548
+TEST_F(HciLayerTest, DISABLED_abort_after_hci_restart_timeout) {
   FailIfResetNotSent();
   FakeTimerAdvance(HciLayer::kHciTimeoutMs.count());
 
@@ -202,7 +205,8 @@
       "");
 }
 
-TEST_F(HciLayerTest, abort_on_root_inflammation_event) {
+// b/260915548
+TEST_F(HciLayerTest, DISABLED_abort_on_root_inflammation_event) {
   FailIfResetNotSent();
 
   auto payload = CreatePayload({'0'});
diff --git a/system/gd/hci/le_address_manager_test.cc b/system/gd/hci/le_address_manager_test.cc
index 5008db5..7f698f0 100644
--- a/system/gd/hci/le_address_manager_test.cc
+++ b/system/gd/hci/le_address_manager_test.cc
@@ -26,22 +26,28 @@
 using ::bluetooth::os::Handler;
 using ::bluetooth::os::Thread;
 
-namespace bluetooth {
-namespace hci {
-
 namespace {
-using packet::kLittleEndian;
-using packet::PacketView;
-using packet::RawBuilder;
 
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+using namespace bluetooth;
+
+packet::PacketView<packet::kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
   auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter i(*bytes);
+  packet::BitInserter i(*bytes);
   bytes->reserve(packet->size());
   packet->Serialize(i);
   return packet::PacketView<packet::kLittleEndian>(bytes);
 }
 
+}  // namespace
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using packet::kLittleEndian;
+using packet::PacketView;
+using packet::RawBuilder;
+
 class TestHciLayer : public HciLayer {
  public:
   void EnqueueCommand(
@@ -51,13 +57,14 @@
     command_queue_.push(std::move(command));
     command_complete_callbacks.push_back(std::move(on_complete));
     if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
+      std::promise<void>* prom = command_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
   void SetCommandFuture() {
-    ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
+    ASSERT_EQ(command_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
     command_promise_ = std::make_unique<std::promise<void>>();
     command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
   }
@@ -130,8 +137,9 @@
     paused = false;
     le_address_manager_->AckResume(this);
     if (resume_promise_ != nullptr) {
-      resume_promise_->set_value();
-      resume_promise_.reset();
+      std::promise<void>* prom = resume_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
@@ -217,10 +225,11 @@
       LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
       remote_address,
       irk,
+      false,
       minimum_rotation_time,
       maximum_rotation_time);
 
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->Register(clients[0].get());
   sync_handler(handler_);
   test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
@@ -239,10 +248,11 @@
       LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS,
       remote_address,
       irk,
+      false,
       minimum_rotation_time,
       maximum_rotation_time);
 
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->Register(clients[0].get());
   sync_handler(handler_);
   test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
@@ -263,6 +273,7 @@
       LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
       remote_address,
       irk,
+      false,
       minimum_rotation_time,
       maximum_rotation_time);
   le_address_manager_->Register(clients[0].get());
@@ -300,10 +311,11 @@
         LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
         remote_address,
         irk,
+        false,
         minimum_rotation_time,
         maximum_rotation_time);
 
-    test_hci_layer_->SetCommandFuture();
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
     le_address_manager_->Register(clients[0].get());
     sync_handler(handler_);
     test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
@@ -330,7 +342,7 @@
 TEST_F(LeAddressManagerWithSingleClientTest, add_device_to_connect_list) {
   Address address;
   Address::FromString("01:02:03:04:05:06", address);
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->AddDeviceToFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
   auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   auto packet_view = LeAddDeviceToFilterAcceptListView::Create(
@@ -346,12 +358,12 @@
 TEST_F(LeAddressManagerWithSingleClientTest, remove_device_from_connect_list) {
   Address address;
   Address::FromString("01:02:03:04:05:06", address);
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->AddDeviceToFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
   test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->RemoveDeviceFromFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
   auto packet = test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
   auto packet_view = LeRemoveDeviceFromFilterAcceptListView::Create(
@@ -366,84 +378,154 @@
 TEST_F(LeAddressManagerWithSingleClientTest, clear_connect_list) {
   Address address;
   Address::FromString("01:02:03:04:05:06", address);
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->AddDeviceToFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
   test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->ClearFilterAcceptList();
   test_hci_layer_->GetCommand(OpCode::LE_CLEAR_FILTER_ACCEPT_LIST);
   test_hci_layer_->IncomingEvent(LeClearFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
   clients[0].get()->WaitForResume();
 }
 
-TEST_F(LeAddressManagerWithSingleClientTest, add_device_to_resolving_list) {
+// b/260916288
+TEST_F(LeAddressManagerWithSingleClientTest, DISABLED_add_device_to_resolving_list) {
   Address address;
   Address::FromString("01:02:03:04:05:06", address);
   Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
   Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
-  test_hci_layer_->SetCommandFuture();
+
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->AddDeviceToResolvingList(
       PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
-  auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
-  auto packet_view = LeAddDeviceToResolvingListView::Create(LeSecurityCommandView::Create(packet));
-  ASSERT_TRUE(packet_view.IsValid());
-  ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
-  ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
-  ASSERT_EQ(peer_irk, packet_view.GetPeerIrk());
-  ASSERT_EQ(local_irk, packet_view.GetLocalIrk());
-
-  test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  {
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+    auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    ASSERT_EQ(Enable::DISABLED, packet_view.GetAddressResolutionEnable());
+    test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
+  {
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
+    auto packet_view = LeAddDeviceToResolvingListView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
+    ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
+    ASSERT_EQ(peer_irk, packet_view.GetPeerIrk());
+    ASSERT_EQ(local_irk, packet_view.GetLocalIrk());
+    test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
+  {
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+    auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    ASSERT_EQ(Enable::ENABLED, packet_view.GetAddressResolutionEnable());
+    test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
   clients[0].get()->WaitForResume();
 }
 
-TEST_F(LeAddressManagerWithSingleClientTest, remove_device_from_resolving_list) {
+// b/260916288
+TEST_F(LeAddressManagerWithSingleClientTest, DISABLED_remove_device_from_resolving_list) {
   Address address;
   Address::FromString("01:02:03:04:05:06", address);
   Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
   Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->AddDeviceToResolvingList(
       PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
+  test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+  test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+  test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+  test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->RemoveDeviceFromResolvingList(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address);
-  auto packet = test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST);
-  auto packet_view = LeRemoveDeviceFromResolvingListView::Create(LeSecurityCommandView::Create(packet));
-  ASSERT_TRUE(packet_view.IsValid());
-  ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
-  ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
-  test_hci_layer_->IncomingEvent(LeRemoveDeviceFromResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  {
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+    auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    ASSERT_EQ(Enable::DISABLED, packet_view.GetAddressResolutionEnable());
+    test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
+  {
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST);
+    auto packet_view = LeRemoveDeviceFromResolvingListView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
+    ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
+    test_hci_layer_->IncomingEvent(LeRemoveDeviceFromResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
+  {
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+    auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    ASSERT_EQ(Enable::ENABLED, packet_view.GetAddressResolutionEnable());
+    test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
   clients[0].get()->WaitForResume();
 }
 
-TEST_F(LeAddressManagerWithSingleClientTest, clear_resolving_list) {
+// b/260916288
+TEST_F(LeAddressManagerWithSingleClientTest, DISABLED_clear_resolving_list) {
   Address address;
   Address::FromString("01:02:03:04:05:06", address);
   Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
   Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->AddDeviceToResolvingList(
       PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
+  test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+  test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
   test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+  test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+  test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->ClearResolvingList();
-  auto packet = test_hci_layer_->GetCommand(OpCode::LE_CLEAR_RESOLVING_LIST);
-  auto packet_view = LeClearResolvingListView::Create(LeSecurityCommandView::Create(packet));
-  ASSERT_TRUE(packet_view.IsValid());
-  test_hci_layer_->IncomingEvent(LeClearResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  {
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+    auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    ASSERT_EQ(Enable::DISABLED, packet_view.GetAddressResolutionEnable());
+    test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
+  {
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_CLEAR_RESOLVING_LIST);
+    auto packet_view = LeClearResolvingListView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    test_hci_layer_->IncomingEvent(LeClearResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
+  {
+    ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
+    auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE);
+    auto packet_view = LeSetAddressResolutionEnableView::Create(LeSecurityCommandView::Create(packet));
+    ASSERT_TRUE(packet_view.IsValid());
+    ASSERT_EQ(Enable::ENABLED, packet_view.GetAddressResolutionEnable());
+    test_hci_layer_->IncomingEvent(LeSetAddressResolutionEnableCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
+  }
+
   clients[0].get()->WaitForResume();
 }
 
 TEST_F(LeAddressManagerWithSingleClientTest, register_during_command_complete) {
   Address address;
   Address::FromString("01:02:03:04:05:06", address);
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->AddDeviceToFilterAcceptList(FilterAcceptListAddressType::RANDOM, address);
   auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
   auto packet_view = LeAddDeviceToFilterAcceptListView::Create(
@@ -454,7 +536,7 @@
   test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
 
   AllocateClients(1);
-  test_hci_layer_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_hci_layer_->SetCommandFuture());
   le_address_manager_->Register(clients[1].get());
   clients[0].get()->WaitForResume();
   clients[1].get()->WaitForResume();
diff --git a/system/gd/hci/le_periodic_sync_manager_test.cc b/system/gd/hci/le_periodic_sync_manager_test.cc
index 3bb9e42..da77d18 100644
--- a/system/gd/hci/le_periodic_sync_manager_test.cc
+++ b/system/gd/hci/le_periodic_sync_manager_test.cc
@@ -45,8 +45,9 @@
     command_queue_.push(std::move(command));
     command_complete_callbacks.push_back(std::move(on_complete));
     if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
+      std::promise<void>* prom = command_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
@@ -56,13 +57,14 @@
     command_queue_.push(std::move(command));
     command_status_callbacks.push_back(std::move(on_status));
     if (command_promise_ != nullptr) {
-      command_promise_->set_value();
-      command_promise_.reset();
+      std::promise<void>* prom = command_promise_.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
   void SetCommandFuture() {
-    ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
+    ASSERT_EQ(command_promise_, nullptr) << "Promises, Promises, ... Only one at a time.";
     command_promise_ = std::make_unique<std::promise<void>>();
     command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
   }
@@ -224,7 +226,7 @@
   };
   uint16_t skip = 0x04;
   uint16_t sync_timeout = 0x0A;
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->StartSync(request, skip, sync_timeout);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
   auto packet_view = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -251,7 +253,7 @@
       .sync_handle = sync_handle,
       .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
   };
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
   auto temp_view = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -293,7 +295,7 @@
       .sync_handle = sync_handle,
       .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
   };
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
   auto temp_view = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -335,7 +337,7 @@
       .sync_handle = sync_handle,
       .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
   };
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
   auto temp_veiw = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -362,7 +364,7 @@
   periodic_sync_manager_->HandleLePeriodicAdvertisingSyncEstablished(event_view);
 
   // StopSync
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->StopSync(sync_handle);
   packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_TERMINATE_SYNC);
   auto packet_view = LePeriodicAdvertisingTerminateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -385,7 +387,7 @@
       .sync_handle = sync_handle,
       .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
   };
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
   auto temp_veiw = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -396,7 +398,7 @@
       LePeriodicAdvertisingCreateSyncStatusBuilder::Create(ErrorCode::SUCCESS, 0x00));
 
   // Cancel crate sync
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->CancelCreateSync(advertiser_sid, address_with_type.GetAddress());
   packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL);
   auto packet_view = LePeriodicAdvertisingCreateSyncCancelView::Create(LeScanningCommandView::Create(packet));
@@ -411,7 +413,7 @@
   uint16_t sync_handle = 0x11;
   uint16_t connection_handle = 0x12;
   int pa_source = 0x01;
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->TransferSync(address, service_data, sync_handle, pa_source, connection_handle);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER);
   auto packet_view = LePeriodicAdvertisingSyncTransferView::Create(LeScanningCommandView::Create(packet));
@@ -436,7 +438,7 @@
   uint16_t advertising_handle = 0x11;
   uint16_t connection_handle = 0x12;
   int pa_source = 0x01;
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->SyncSetInfo(address, service_data, advertising_handle, pa_source, connection_handle);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER);
   auto packet_view = LePeriodicAdvertisingSetInfoTransferView::Create(LeScanningCommandView::Create(packet));
@@ -461,7 +463,7 @@
   uint16_t skip = 0x11;
   uint16_t timout = 0x12;
   int reg_id = 0x01;
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->SyncTxParameters(address, mode, skip, timout, reg_id);
   auto packet =
       test_le_scanning_interface_->GetCommand(OpCode::LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS);
@@ -490,7 +492,7 @@
       .sync_handle = sync_handle,
       .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
   };
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
   auto temp_veiw = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
@@ -542,7 +544,7 @@
       .sync_handle = sync_handle,
       .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
   };
-  test_le_scanning_interface_->SetCommandFuture();
+  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
   periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
   auto packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
   auto temp_veiw = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
diff --git a/system/gd/hci/le_scanning_manager_test.cc b/system/gd/hci/le_scanning_manager_test.cc
index 88eb3be..e59c725 100644
--- a/system/gd/hci/le_scanning_manager_test.cc
+++ b/system/gd/hci/le_scanning_manager_test.cc
@@ -29,6 +29,7 @@
 #include <queue>
 #include <vector>
 
+#include "hci/hci_layer_fake.h"
 #include "common/bind.h"
 #include "hci/acl_manager.h"
 #include "hci/address.h"
@@ -109,14 +110,6 @@
 namespace hci {
 namespace {
 
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter i(*bytes);
-  bytes->reserve(packet->size());
-  packet->Serialize(i);
-  return packet::PacketView<packet::kLittleEndian>(bytes);
-}
-
 class TestController : public Controller {
  public:
   bool IsSupported(OpCode op_code) const override {
@@ -127,6 +120,14 @@
     supported_opcodes_.insert(op_code);
   }
 
+  bool SupportsBleExtendedAdvertising() const override {
+    return support_ble_extended_advertising_;
+  }
+
+  void SetBleExtendedAdvertisingSupport(bool support) {
+    support_ble_extended_advertising_ = support;
+  }
+
  protected:
   void Start() override {}
   void Stop() override {}
@@ -134,156 +135,7 @@
 
  private:
   std::set<OpCode> supported_opcodes_{};
-};
-
-class TestHciLayer : public HciLayer {
- public:
-  void EnqueueCommand(
-      std::unique_ptr<CommandBuilder> command,
-      common::ContextualOnceCallback<void(CommandStatusView)> on_status) override {
-    std::lock_guard<std::mutex> lock(mutex_);
-    command_queue_.push(std::move(command));
-    command_status_callbacks.push_back(std::move(on_status));
-    command_count_--;
-    if (command_promise_ != nullptr && command_count_ == 0) {
-      command_promise_->set_value();
-      command_promise_.reset();
-    }
-  }
-
-  void EnqueueCommand(
-      std::unique_ptr<CommandBuilder> command,
-      common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
-    std::lock_guard<std::mutex> lock(mutex_);
-    command_queue_.push(std::move(command));
-    command_complete_callbacks.push_back(std::move(on_complete));
-    command_count_--;
-    if (command_promise_ != nullptr && command_count_ == 0) {
-      command_promise_->set_value();
-      command_promise_.reset();
-    }
-  }
-
-  // Set command future for 'num_command' commands are expected
-  void SetCommandFuture(uint16_t num_command = 1) {
-    ASSERT_TRUE(command_promise_ == nullptr) << "Promises, Promises, ... Only one at a time.";
-    command_count_ = num_command;
-    command_promise_ = std::make_unique<std::promise<void>>();
-    command_future_ = command_promise_->get_future();
-  }
-
-  CommandView GetCommand() {
-    // Wait for EnqueueCommand if command_queue_ is empty
-    if (command_promise_ != nullptr) {
-      if (command_queue_.empty()) {
-        LOG_ERROR("Waiting for command queue to fill ");
-        command_future_.wait_for(1s);
-      }
-      command_promise_.reset();
-    }
-
-    std::lock_guard<std::mutex> lock(mutex_);
-    if (command_queue_.empty()) {
-      LOG_ERROR("Command queue is empty");
-      return empty_command_view_;
-    }
-
-    auto last = std::move(command_queue_.front());
-    command_queue_.pop();
-    CommandView command_packet_view = CommandView::Create(GetPacketView(std::move(last)));
-    if (!command_packet_view.IsValid()) {
-      LOG_ERROR("Got invalid command");
-      return empty_command_view_;
-    }
-    return command_packet_view;
-  }
-
-  void RegisterEventHandler(EventCode event_code, common::ContextualCallback<void(EventView)> event_handler) override {
-    registered_events_[event_code] = event_handler;
-  }
-
-  void UnregisterEventHandler(EventCode event_code) override {
-    registered_events_.erase(event_code);
-  }
-
-  void RegisterLeEventHandler(
-      SubeventCode subevent_code, common::ContextualCallback<void(LeMetaEventView)> event_handler) override {
-    registered_le_events_[subevent_code] = event_handler;
-  }
-
-  void UnregisterLeEventHandler(SubeventCode subevent_code) override {
-    registered_le_events_.erase(subevent_code);
-  }
-
-  void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
-    auto packet = GetPacketView(std::move(event_builder));
-    EventView event = EventView::Create(packet);
-    ASSERT_TRUE(event.IsValid());
-    EventCode event_code = event.GetEventCode();
-    ASSERT_NE(registered_events_.find(event_code), registered_events_.end()) << EventCodeText(event_code);
-    registered_events_[event_code].Invoke(event);
-  }
-
-  void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
-    auto packet = GetPacketView(std::move(event_builder));
-    EventView event = EventView::Create(packet);
-    LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
-    ASSERT_TRUE(meta_event_view.IsValid());
-    SubeventCode subevent_code = meta_event_view.GetSubeventCode();
-    ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end());
-    registered_le_events_[subevent_code].Invoke(meta_event_view);
-  }
-
-  void CommandCompleteCallback(EventView event) {
-    CommandCompleteView complete_view = CommandCompleteView::Create(event);
-    ASSERT_TRUE(complete_view.IsValid());
-    ASSERT_TRUE(!command_complete_callbacks.empty());
-    std::move(command_complete_callbacks.front()).Invoke(complete_view);
-    command_complete_callbacks.pop_front();
-  }
-
-  void CommandStatusCallback(EventView event) {
-    CommandStatusView status_view = CommandStatusView::Create(event);
-    ASSERT_TRUE(status_view.IsValid());
-    std::move(command_status_callbacks.front()).Invoke(status_view);
-    command_status_callbacks.pop_front();
-  }
-
-  void InitEmptyCommand() {
-    auto payload = std::make_unique<bluetooth::packet::RawBuilder>();
-    auto command_builder = CommandBuilder::Create(OpCode::NONE, std::move(payload));
-    empty_command_view_ = CommandView::Create(GetPacketView(std::move(command_builder)));
-    ASSERT_TRUE(empty_command_view_.IsValid());
-  }
-
-  void ListDependencies(ModuleList* list) const {}
-  void Start() override {
-    InitEmptyCommand();
-    RegisterEventHandler(
-        EventCode::COMMAND_COMPLETE, GetHandler()->BindOn(this, &TestHciLayer::CommandCompleteCallback));
-    RegisterEventHandler(EventCode::COMMAND_STATUS, GetHandler()->BindOn(this, &TestHciLayer::CommandStatusCallback));
-  }
-  void Stop() override {
-    UnregisterEventHandler(EventCode::COMMAND_STATUS);
-    UnregisterEventHandler(EventCode::COMMAND_COMPLETE);
-  }
-
-  size_t CommandQueueSize() const {
-    return command_queue_.size();
-  }
-
- private:
-  std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
-  std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;
-  std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
-  std::list<common::ContextualOnceCallback<void(CommandStatusView)>> command_status_callbacks;
-  std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
-  std::unique_ptr<std::promise<void>> command_promise_;
-  std::future<void> command_future_;
-  mutable std::mutex mutex_;
-  uint16_t command_count_ = 0;
-  CommandView empty_command_view_ =
-      CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
+  bool support_ble_extended_advertising_ = false;
 };
 
 class TestLeAddressManager : public LeAddressManager {
@@ -438,11 +290,7 @@
   }
 
   void sync_client_handler() {
-    std::promise<void> promise;
-    auto future = promise.get_future();
-    client_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
-    auto future_status = future.wait_for(std::chrono::seconds(1));
-    ASSERT_EQ(future_status, std::future_status::ready);
+    ASSERT(thread_.GetReactor()->WaitForIdle(std::chrono::seconds(2)));
   }
 
   TestModuleRegistry fake_registry_;
@@ -466,10 +314,13 @@
     start_le_scanning_manager();
     ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory));
 
-    test_hci_layer_->SetCommandFuture();
     ASSERT_EQ(OpCode::LE_ADV_FILTER, test_hci_layer_->GetCommand().GetOpCode());
-    ASSERT_EQ(0UL, test_hci_layer_->CommandQueueSize());
     test_hci_layer_->IncomingEvent(LeAdvFilterReadExtendedFeaturesCompleteBuilder::Create(1, ErrorCode::SUCCESS, 0x01));
+
+    // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc
+    // Fixed on aosp/2242078 but not present on older branches
+    EXPECT_EQ(OpCode::LE_EXTENDED_SCAN_PARAMS, test_hci_layer_->GetCommand().GetOpCode());
+    test_hci_layer_->IncomingEvent(LeExtendedScanParamsCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
   }
 
   void TearDown() override {
@@ -483,7 +334,12 @@
     LeScanningManagerTest::SetUp();
     test_controller_->AddSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS);
     test_controller_->AddSupported(OpCode::LE_SET_EXTENDED_SCAN_ENABLE);
+    test_controller_->SetBleExtendedAdvertisingSupport(true);
     start_le_scanning_manager();
+    // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc
+    // Fixed on aosp/2242078 but not present on older branches
+    EXPECT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
+    test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
   }
 };
 
@@ -492,12 +348,17 @@
 TEST_F(LeScanningManagerTest, start_scan_test) {
   start_le_scanning_manager();
 
-  test_hci_layer_->SetCommandFuture(2);
+  // Get the command a second time as the configure_scan is called twice in le_scanning_manager.cc
+  // Fixed on aosp/2242078 but not present on older branches
+  EXPECT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
+  test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
   // Enable scan
   le_scanning_manager->Scan(true);
-  ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
+  EXPECT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
   test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
-  ASSERT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
+
+  EXPECT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
   test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
 
   LeAdvertisingResponse report = make_advertising_report();
@@ -515,7 +376,7 @@
 TEST_F(LeScanningManagerTest, scan_filter_add_ad_type_not_supported_test) {
   start_le_scanning_manager();
   ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory));
-  test_hci_layer_->SetCommandFuture();
+
   std::vector<AdvertisingPacketContentFilterCommand> filters = {};
   filters.push_back(make_filter(hci::ApcfFilterType::AD_TYPE));
   le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -524,7 +385,6 @@
 TEST_F(LeScanningManagerAndroidHciTest, startup_teardown) {}
 
 TEST_F(LeScanningManagerAndroidHciTest, start_scan_test) {
-  test_hci_layer_->SetCommandFuture(2);
   // Enable scan
   le_scanning_manager->Scan(true);
   ASSERT_EQ(OpCode::LE_EXTENDED_SCAN_PARAMS, test_hci_layer_->GetCommand().GetOpCode());
@@ -545,14 +405,16 @@
 
 TEST_F(LeScanningManagerAndroidHciTest, scan_filter_enable_test) {
   le_scanning_manager->ScanFilterEnable(true);
+  sync_client_handler();
 
   EXPECT_CALL(mock_callbacks_, OnFilterEnable);
   test_hci_layer_->IncomingEvent(
       LeAdvFilterEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, Enable::ENABLED));
+  sync_client_handler();
 }
 
 TEST_F(LeScanningManagerAndroidHciTest, scan_filter_parameter_test) {
-  test_hci_layer_->SetCommandFuture();
+
   AdvertisingFilterParameter advertising_filter_parameter{};
   advertising_filter_parameter.delivery_mode = DeliveryMode::IMMEDIATE;
   le_scanning_manager->ScanFilterParameterSetup(ApcfAction::ADD, 0x01, advertising_filter_parameter);
@@ -566,10 +428,11 @@
   EXPECT_CALL(mock_callbacks_, OnFilterParamSetup);
   test_hci_layer_->IncomingEvent(
       LeAdvFilterSetFilteringParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS, ApcfAction::ADD, 0x0a));
+  sync_client_handler();
 }
 
 TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_broadcaster_address_test) {
-  test_hci_layer_->SetCommandFuture();
+
   std::vector<AdvertisingPacketContentFilterCommand> filters = {};
   filters.push_back(make_filter(ApcfFilterType::BROADCASTER_ADDRESS));
   le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -586,7 +449,7 @@
 }
 
 TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_service_uuid_test) {
-  test_hci_layer_->SetCommandFuture();
+
   std::vector<AdvertisingPacketContentFilterCommand> filters = {};
   filters.push_back(make_filter(ApcfFilterType::SERVICE_UUID));
   le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -603,7 +466,7 @@
 }
 
 TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_local_name_test) {
-  test_hci_layer_->SetCommandFuture();
+
   std::vector<AdvertisingPacketContentFilterCommand> filters = {};
   filters.push_back(make_filter(ApcfFilterType::LOCAL_NAME));
   le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -620,7 +483,7 @@
 }
 
 TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_manufacturer_data_test) {
-  test_hci_layer_->SetCommandFuture();
+
   std::vector<AdvertisingPacketContentFilterCommand> filters = {};
   filters.push_back(make_filter(ApcfFilterType::MANUFACTURER_DATA));
   le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -637,7 +500,7 @@
 }
 
 TEST_F(LeScanningManagerAndroidHciTest, scan_filter_add_service_data_test) {
-  test_hci_layer_->SetCommandFuture();
+
   std::vector<AdvertisingPacketContentFilterCommand> filters = {};
   filters.push_back(make_filter(hci::ApcfFilterType::SERVICE_DATA));
   le_scanning_manager->ScanFilterAdd(0x01, filters);
@@ -680,20 +543,20 @@
       LeBatchScanSetStorageParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
 
   // Enable batch scan
-  test_hci_layer_->SetCommandFuture();
+
   le_scanning_manager->BatchScanEnable(BatchScanMode::FULL, 2400, 2400, BatchScanDiscardRule::OLDEST);
   ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode());
   test_hci_layer_->IncomingEvent(LeBatchScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
 
   // Read batch scan data
-  test_hci_layer_->SetCommandFuture();
+
   le_scanning_manager->BatchScanReadReport(0x01, BatchScanMode::FULL);
   ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode());
 
   // We will send read command while num_of_record != 0
   std::vector<uint8_t> raw_data = {0x5c, 0x1f, 0xa2, 0xc3, 0x63, 0x5d, 0x01, 0xf5, 0xb3, 0x5e, 0x00, 0x0c, 0x02,
                                    0x01, 0x02, 0x05, 0x09, 0x6d, 0x76, 0x38, 0x76, 0x02, 0x0a, 0xf5, 0x00};
-  test_hci_layer_->SetCommandFuture();
+
   test_hci_layer_->IncomingEvent(LeBatchScanReadResultParametersCompleteRawBuilder::Create(
       uint8_t{1}, ErrorCode::SUCCESS, BatchScanDataRead::FULL_MODE_DATA, 1, raw_data));
   ASSERT_EQ(OpCode::LE_BATCH_SCAN, test_hci_layer_->GetCommand().GetOpCode());
@@ -708,7 +571,6 @@
 
 TEST_F(LeScanningManagerExtendedTest, start_scan_test) {
   // Enable scan
-  test_hci_layer_->SetCommandFuture(2);
   le_scanning_manager->Scan(true);
   ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
   test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
@@ -742,7 +604,6 @@
   test_le_address_manager->ignore_unregister_for_testing = true;
 
   // Register LeAddressManager
-  test_hci_layer_->SetCommandFuture(2);
   le_scanning_manager->Scan(true);
   ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
   test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
@@ -751,7 +612,6 @@
   sync_client_handler();
 
   // Unregister LeAddressManager
-  test_hci_layer_->SetCommandFuture(1);
   le_scanning_manager->Scan(false);
   ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
   test_hci_layer_->IncomingEvent(LeSetExtendedScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
@@ -768,7 +628,6 @@
 
 TEST_F(LeScanningManagerExtendedTest, drop_insignificant_bytes_test) {
   // Enable scan
-  test_hci_layer_->SetCommandFuture(2);
   le_scanning_manager->Scan(true);
   ASSERT_EQ(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
   test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
diff --git a/system/gd/os/Android.bp b/system/gd/os/Android.bp
index 7431f15..292da06 100644
--- a/system/gd/os/Android.bp
+++ b/system/gd/os/Android.bp
@@ -17,6 +17,7 @@
 filegroup {
     name: "BluetoothOsSources_android",
     srcs: [
+        "system_properties_common.cc",
         "android/metrics.cc",
         "android/parameter_provider.cc",
         "android/system_properties.cc",
@@ -35,6 +36,7 @@
 filegroup {
     name: "BluetoothOsSources_host",
     srcs: [
+        "system_properties_common.cc",
         "host/metrics.cc",
         "host/parameter_provider.cc",
         "host/system_properties.cc",
diff --git a/system/gd/os/BUILD.gn b/system/gd/os/BUILD.gn
index 48337e1..7204ccd 100644
--- a/system/gd/os/BUILD.gn
+++ b/system/gd/os/BUILD.gn
@@ -18,6 +18,7 @@
     "linux/parameter_provider.cc",
     "linux/system_properties.cc",
     "linux/wakelock_native.cc",
+    "system_properties_common.cc",
     "syslog.cc",
   ]
 
diff --git a/system/gd/os/android/metrics.cc b/system/gd/os/android/metrics.cc
index db42fc5a..eacaa72 100644
--- a/system/gd/os/android/metrics.cc
+++ b/system/gd/os/android/metrics.cc
@@ -236,7 +236,7 @@
 }
 
 void LogMetricSmpPairingEvent(
-    const Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {
+    const Address& address, uint16_t smp_cmd, android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {
   int metric_id = 0;
   if (!address.IsEmpty()) {
     metric_id = MetricIdManager::GetInstance().AllocateId(address);
diff --git a/system/gd/os/android/wakelock_native_test.cc b/system/gd/os/android/wakelock_native_test.cc
index 66be722..36f8af8 100644
--- a/system/gd/os/android/wakelock_native_test.cc
+++ b/system/gd/os/android/wakelock_native_test.cc
@@ -53,8 +53,9 @@
   static void FulfilPromise(std::unique_ptr<std::promise<void>>& promise) {
     std::lock_guard<std::recursive_mutex> lock_guard(mutex);
     if (promise != nullptr) {
-      promise->set_value();
-      promise = nullptr;
+      std::promise<void>* prom = promise.release();
+      prom->set_value();
+      delete prom;
     }
   }
 
diff --git a/system/gd/os/host/metrics.cc b/system/gd/os/host/metrics.cc
index 955d22e..2e85e73 100644
--- a/system/gd/os/host/metrics.cc
+++ b/system/gd/os/host/metrics.cc
@@ -96,7 +96,7 @@
     const char* attribute_value) {}
 
 void LogMetricSmpPairingEvent(
-    const Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {}
+    const Address& address, uint16_t smp_cmd, android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {}
 
 void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int audio_coding_mode) {}
 
diff --git a/system/gd/os/linux/metrics.cc b/system/gd/os/linux/metrics.cc
index 65fb181..3941f77 100644
--- a/system/gd/os/linux/metrics.cc
+++ b/system/gd/os/linux/metrics.cc
@@ -96,7 +96,7 @@
     const char* attribute_value) {}
 
 void LogMetricSmpPairingEvent(
-    const Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {}
+    const Address& address, uint16_t smp_cmd, android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {}
 
 void LogMetricA2dpPlaybackEvent(const Address& address, int playback_state, int audio_coding_mode) {}
 
diff --git a/system/gd/os/linux_generic/queue_unittest.cc b/system/gd/os/linux_generic/queue_unittest.cc
index 7994aba..706fcd2 100644
--- a/system/gd/os/linux_generic/queue_unittest.cc
+++ b/system/gd/os/linux_generic/queue_unittest.cc
@@ -19,6 +19,7 @@
 #include <sys/eventfd.h>
 
 #include <atomic>
+#include <chrono>
 #include <future>
 #include <unordered_map>
 
@@ -26,6 +27,8 @@
 #include "gtest/gtest.h"
 #include "os/reactor.h"
 
+using namespace std::chrono_literals;
+
 namespace bluetooth {
 namespace os {
 namespace {
@@ -60,6 +63,11 @@
   Handler* enqueue_handler_;
   Thread* dequeue_thread_;
   Handler* dequeue_handler_;
+
+  void sync_enqueue_handler() {
+    ASSERT(enqueue_thread_ != nullptr);
+    ASSERT(enqueue_thread_->GetReactor()->WaitForIdle(2s));
+  }
 };
 
 class TestEnqueueEnd {
@@ -338,6 +346,7 @@
   test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
   enqueue_future.wait();
   EXPECT_EQ(enqueue_future.get(), 0);
+  sync_enqueue_handler();
 }
 
 // Enqueue end level : 1
diff --git a/system/gd/os/metrics.h b/system/gd/os/metrics.h
index 339a2cf..cb35d68 100644
--- a/system/gd/os/metrics.h
+++ b/system/gd/os/metrics.h
@@ -166,7 +166,10 @@
  * @param smp_fail_reason SMP pairing failure reason code from SMP spec
  */
 void LogMetricSmpPairingEvent(
-    const hci::Address& address, uint8_t smp_cmd, android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason);
+    const hci::Address& address,
+    uint16_t smp_cmd,
+    android::bluetooth::DirectionEnum direction,
+    uint16_t smp_fail_reason);
 
 /**
  * Logs there is an event related Bluetooth classic pairing
diff --git a/system/gd/os/system_properties.h b/system/gd/os/system_properties.h
index f5a82b8..42ea4e7 100644
--- a/system/gd/os/system_properties.h
+++ b/system/gd/os/system_properties.h
@@ -26,6 +26,21 @@
 // or if the platform does not support system property
 std::optional<std::string> GetSystemProperty(const std::string& property);
 
+// Get |property| keyed system property as uint32_t from supported platform, return |default_value| if the property
+// does not exist or if the platform does not support system property
+uint32_t GetSystemPropertyUint32(const std::string& property, uint32_t default_value);
+
+// Get |property| keyed system property as uint32_t from supported platform, return |default_value|
+// if the property does not exist or if the platform does not support system property if property is
+// found it will call stoul with |base|
+uint32_t GetSystemPropertyUint32Base(
+    const std::string& property, uint32_t default_value, int base = 0);
+
+// Get |property| keyed property as bool from supported platform, return
+// |default_value| if the property does not exist or if the platform
+// does not support system property
+bool GetSystemPropertyBool(const std::string& property, bool default_value);
+
 // Set |property| keyed system property to |value|, return true if the set was successful and false if the set failed
 // Replace existing value if property already exists
 bool SetSystemProperty(const std::string& property, const std::string& value);
diff --git a/system/gd/os/system_properties_common.cc b/system/gd/os/system_properties_common.cc
new file mode 100644
index 0000000..f59560c
--- /dev/null
+++ b/system/gd/os/system_properties_common.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include "common/strings.h"
+#include "os/system_properties.h"
+
+namespace bluetooth {
+namespace os {
+
+uint32_t GetSystemPropertyUint32(const std::string& property, uint32_t default_value) {
+  return GetSystemPropertyUint32Base(property, default_value, 10);
+}
+
+uint32_t GetSystemPropertyUint32Base(
+    const std::string& property, uint32_t default_value, int base) {
+  std::optional<std::string> result = GetSystemProperty(property);
+  if (result.has_value()) {
+    return static_cast<uint32_t>(std::stoul(*result, nullptr, base));
+  }
+  return default_value;
+}
+
+bool GetSystemPropertyBool(const std::string& property, bool default_value) {
+  std::optional<std::string> result = GetSystemProperty(property);
+  if (result.has_value()) {
+    std::string trimmed_val = common::StringTrim(result.value());
+    if (trimmed_val == "true" || trimmed_val == "1") {
+      return true;
+    }
+    if (trimmed_val == "false" || trimmed_val == "0") {
+      return false;
+    }
+  }
+  return default_value;
+}
+
+}  // namespace os
+}  // namespace bluetooth
diff --git a/system/gd/rust/common/src/init_flags.rs b/system/gd/rust/common/src/init_flags.rs
index 8e06df7..2beb2b5 100644
--- a/system/gd/rust/common/src/init_flags.rs
+++ b/system/gd/rust/common/src/init_flags.rs
@@ -209,6 +209,8 @@
         btaa_hci = true,
         bta_dm_clear_conn_id_on_client_close = true,
         btm_dm_flush_discovery_queue_on_search_cancel,
+        clear_hidd_interrupt_cid_on_disconnect = true,
+        delay_hidh_cleanup_until_hidh_ready_start = true,
         finite_att_timeout = true,
         gatt_robust_caching_client = true,
         gatt_robust_caching_server,
diff --git a/system/gd/rust/shim/src/init_flags.rs b/system/gd/rust/shim/src/init_flags.rs
index 46c379f..5c1e29d 100644
--- a/system/gd/rust/shim/src/init_flags.rs
+++ b/system/gd/rust/shim/src/init_flags.rs
@@ -8,6 +8,8 @@
         fn btaa_hci_is_enabled() -> bool;
         fn bta_dm_clear_conn_id_on_client_close_is_enabled() -> bool;
         fn btm_dm_flush_discovery_queue_on_search_cancel_is_enabled() -> bool;
+        fn delay_hidh_cleanup_until_hidh_ready_start_is_enabled() -> bool;
+        fn clear_hidd_interrupt_cid_on_disconnect_is_enabled() -> bool;
         fn finite_att_timeout_is_enabled() -> bool;
         fn gatt_robust_caching_client_is_enabled() -> bool;
         fn gatt_robust_caching_server_is_enabled() -> bool;
diff --git a/system/gd/stack_manager_unittest.cc b/system/gd/stack_manager_unittest.cc
index 824675e..51645ea 100644
--- a/system/gd/stack_manager_unittest.cc
+++ b/system/gd/stack_manager_unittest.cc
@@ -22,7 +22,7 @@
 namespace bluetooth {
 namespace {
 
-TEST(StackManagerTest, start_and_shutdown_no_module) {
+TEST(StackManagerTest, DISABLED_start_and_shutdown_no_module) {
   StackManager stack_manager;
   ModuleList module_list;
   os::Thread thread{"test_thread", os::Thread::Priority::NORMAL};
@@ -45,7 +45,7 @@
 
 const ModuleFactory TestModuleNoDependency::Factory = ModuleFactory([]() { return new TestModuleNoDependency(); });
 
-TEST(StackManagerTest, get_module_instance) {
+TEST(StackManagerTest, DISABLED_get_module_instance) {
   StackManager stack_manager;
   ModuleList module_list;
   module_list.add<TestModuleNoDependency>();
diff --git a/system/hci/Android.bp b/system/hci/Android.bp
index d9f9542..1553c25 100644
--- a/system/hci/Android.bp
+++ b/system/hci/Android.bp
@@ -91,28 +91,6 @@
     ],
 }
 
-// HCI native unit tests for target
-cc_test {
-    name: "net_test_hci_native",
-    test_suites: ["device-tests"],
-    defaults: [
-        "fluoride_unit_test_defaults",
-        "mts_defaults",
-    ],
-    local_include_dirs: [
-        "include",
-    ],
-    include_dirs: [
-        "packages/modules/Bluetooth/system",
-        "packages/modules/Bluetooth/system/gd",
-        "packages/modules/Bluetooth/system/stack/include",
-    ],
-    srcs: [
-        "test/hci_layer_test.cc",
-        "test/other_stack_stub.cc",
-    ],
-}
-
 cc_test {
     name: "net_test_hci_fragmenter_native",
     test_suites: ["device-tests"],
diff --git a/system/hci/test/hci_layer_test.cc b/system/hci/test/hci_layer_test.cc
deleted file mode 100644
index e69de29..0000000
--- a/system/hci/test/hci_layer_test.cc
+++ /dev/null
diff --git a/system/hci/test/other_stack_stub.cc b/system/hci/test/other_stack_stub.cc
deleted file mode 100644
index e69de29..0000000
--- a/system/hci/test/other_stack_stub.cc
+++ /dev/null
diff --git a/system/internal_include/bt_target.h b/system/internal_include/bt_target.h
index 98787a3..89478dc 100644
--- a/system/internal_include/bt_target.h
+++ b/system/internal_include/bt_target.h
@@ -1026,12 +1026,4 @@
 
 #include "bt_trace.h"
 
-#ifndef BTM_DELAY_AUTH_MS
-#define BTM_DELAY_AUTH_MS 0
-#endif
-
-#ifndef BTM_DISABLE_CONCURRENT_PEER_AUTH
-#define BTM_DISABLE_CONCURRENT_PEER_AUTH FALSE
-#endif
-
 #endif /* BT_TARGET_H */
diff --git a/system/main/shim/metrics_api.cc b/system/main/shim/metrics_api.cc
index 99832be..82ad3c1 100644
--- a/system/main/shim/metrics_api.cc
+++ b/system/main/shim/metrics_api.cc
@@ -89,9 +89,9 @@
                                                  transmit_power_level);
 }
 
-void LogMetricSmpPairingEvent(const RawAddress& raw_address, uint8_t smp_cmd,
+void LogMetricSmpPairingEvent(const RawAddress& raw_address, uint16_t smp_cmd,
                               android::bluetooth::DirectionEnum direction,
-                              uint8_t smp_fail_reason) {
+                              uint16_t smp_fail_reason) {
   Address address = bluetooth::ToGdAddress(raw_address);
   bluetooth::os::LogMetricSmpPairingEvent(address, smp_cmd, direction,
                                           smp_fail_reason);
diff --git a/system/main/shim/metrics_api.h b/system/main/shim/metrics_api.h
index ce13876..f838908 100644
--- a/system/main/shim/metrics_api.h
+++ b/system/main/shim/metrics_api.h
@@ -134,9 +134,9 @@
  * @param direction direction of this SMP command
  * @param smp_fail_reason SMP pairing failure reason code from SMP spec
  */
-void LogMetricSmpPairingEvent(const RawAddress& address, uint8_t smp_cmd,
+void LogMetricSmpPairingEvent(const RawAddress& address, uint16_t smp_cmd,
                               android::bluetooth::DirectionEnum direction,
-                              uint8_t smp_fail_reason);
+                              uint16_t smp_fail_reason);
 
 /**
  * Logs there is an event related Bluetooth classic pairing
diff --git a/system/stack/Android.bp b/system/stack/Android.bp
index b9eaeeb..e5e7b1c 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -235,6 +235,7 @@
     srcs: [
         "test/stack_a2dp_test.cc",
         "test/stack_avrcp_test.cc",
+        "test/gatt/gatt_api_test.cc",
     ],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
@@ -481,8 +482,12 @@
 // Bluetooth stack connection multiplexing
 cc_test {
     name: "net_test_gatt_conn_multiplexing",
-    defaults: ["fluoride_defaults"],
+    defaults: [
+        "fluoride_defaults",
+        "mts_defaults",
+    ],
     host_supported: true,
+    test_suites: ["general-tests"],
     local_include_dirs: [
         "include",
         "btm",
@@ -998,9 +1003,14 @@
         "libprotobuf-cpp-lite",
     ],
     sanitize: {
-      hwaddress: true,
-      integer_overflow: true,
-      scs: true,
+        address: true,
+        all_undefined: true,
+        cfi: true,
+        integer_overflow: true,
+        scs: true,
+        diag: {
+            undefined : true
+        },
     },
 }
 
diff --git a/system/stack/acl/btm_acl.cc b/system/stack/acl/btm_acl.cc
index c6264dd..eb74e90 100644
--- a/system/stack/acl/btm_acl.cc
+++ b/system/stack/acl/btm_acl.cc
@@ -50,6 +50,7 @@
 #include "main/shim/dumpsys.h"
 #include "main/shim/l2c_api.h"
 #include "main/shim/shim.h"
+#include "os/parameter_provider.h"
 #include "osi/include/allocator.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"  // UNUSED_ATTR
@@ -339,6 +340,11 @@
   uint8_t sca;
   uint8_t status;
 
+  if (len < 4) {
+    LOG_WARN("Malformatted packet, not containing enough data");
+    return;
+  }
+
   STREAM_TO_UINT8(status, data);
 
   if (status != HCI_SUCCESS) {
@@ -630,6 +636,23 @@
     return;
   }
 
+  /* Common Criteria mode only: if we are trying to drop encryption on an
+   * encrypted connection, drop the connection */
+  if (bluetooth::os::ParameterProvider::IsCommonCriteriaMode()) {
+    if (p->is_encrypted && !encr_enable) {
+      LOG(ERROR)
+          << __func__
+          << " attempting to decrypt encrypted connection, disconnecting. "
+             "handle: "
+          << loghex(handle);
+
+      acl_disconnect_from_handle(handle, HCI_ERR_HOST_REJECT_SECURITY,
+                                 "stack::btu::btu_hcif::read_drop_encryption "
+                                 "Connection Already Encrypted");
+      return;
+    }
+  }
+
   p->is_encrypted = encr_enable;
 
   /* Process Role Switch if active */
diff --git a/system/stack/btm/btm_ble_batchscan.cc b/system/stack/btm/btm_ble_batchscan.cc
index 2278880..bdce367 100644
--- a/system/stack/btm/btm_ble_batchscan.cc
+++ b/system/stack/btm/btm_ble_batchscan.cc
@@ -60,12 +60,15 @@
 /* VSE callback for batch scan, filter, and tracking events */
 void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len,
                                                   const uint8_t* p) {
-  tBTM_BLE_TRACK_ADV_DATA adv_data;
-
+  tBTM_BLE_TRACK_ADV_DATA adv_data{};
   uint8_t sub_event = 0;
   tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
-  if (len == 0) return;
+
+  if (len < 1)
+    goto err_out;
+
   STREAM_TO_UINT8(sub_event, p);
+  len -= 1;
 
   BTM_TRACE_EVENT(
       "btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x",
@@ -78,30 +81,45 @@
 
   if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event &&
       NULL != ble_advtrack_cb.p_track_cback) {
-    if (len < 10) return;
 
-    memset(&adv_data, 0, sizeof(tBTM_BLE_TRACK_ADV_DATA));
     BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
     adv_data.client_if = (uint8_t)ble_advtrack_cb.ref_value;
     if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) {
+      if (len < 10) {
+        goto err_out;
+      }
+
       STREAM_TO_UINT8(adv_data.filt_index, p);
       STREAM_TO_UINT8(adv_data.advertiser_state, p);
       STREAM_TO_UINT8(adv_data.advertiser_info_present, p);
       STREAM_TO_BDADDR(adv_data.bd_addr, p);
       STREAM_TO_UINT8(adv_data.addr_type, p);
 
+      len -= 10;
+
       /* Extract the adv info details */
       if (ADV_INFO_PRESENT == adv_data.advertiser_info_present) {
-        if (len < 15) return;
+
+        if (len < 5) {
+          goto err_out;
+        }
+
         STREAM_TO_UINT8(adv_data.tx_power, p);
         STREAM_TO_UINT8(adv_data.rssi_value, p);
         STREAM_TO_UINT16(adv_data.time_stamp, p);
-
         STREAM_TO_UINT8(adv_data.adv_pkt_len, p);
+
+        len -= 5;
+
         if (adv_data.adv_pkt_len > 0) {
           adv_data.p_adv_pkt_data =
               static_cast<uint8_t*>(osi_malloc(adv_data.adv_pkt_len));
+          if (adv_data.p_adv_pkt_data == nullptr || \
+            len < adv_data.adv_pkt_len) {
+            goto err_out;
+          }
           memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len);
+          len -= adv_data.adv_pkt_len;
           p += adv_data.adv_pkt_len;
         }
 
@@ -109,11 +127,19 @@
         if (adv_data.scan_rsp_len > 0) {
           adv_data.p_scan_rsp_data =
               static_cast<uint8_t*>(osi_malloc(adv_data.scan_rsp_len));
+
+          if (adv_data.p_scan_rsp_data == nullptr || len < adv_data.scan_rsp_len) {
+            goto err_out;
+          }
           memcpy(adv_data.p_scan_rsp_data, p, adv_data.scan_rsp_len);
         }
       }
     } else {
       /* Based on L-release version */
+      if (len < 9) {
+        goto err_out;
+      }
+
       STREAM_TO_UINT8(adv_data.filt_index, p);
       STREAM_TO_UINT8(adv_data.addr_type, p);
       STREAM_TO_BDADDR(adv_data.bd_addr, p);
@@ -129,8 +155,15 @@
                         to_ble_addr_type(adv_data.addr_type));
 
     ble_advtrack_cb.p_track_cback(&adv_data);
-    return;
   }
+
+  return;
+
+err_out:
+  BTM_TRACE_ERROR("malformatted packet detected");
+
+  osi_free_and_reset((void **) &adv_data.p_adv_pkt_data);
+  osi_free_and_reset((void **) &adv_data.p_scan_rsp_data);
 }
 
 void feat_enable_cb(uint8_t* p, uint16_t len) {
diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc
index 5aa30e7..57192f8 100644
--- a/system/stack/btm/btm_ble_gap.cc
+++ b/system/stack/btm/btm_ble_gap.cc
@@ -1436,7 +1436,7 @@
  ******************************************************************************/
 void btm_ble_periodic_adv_sync_tx_rcvd(uint8_t* p, uint16_t param_len) {
   LOG_DEBUG("[PAST]: PAST received, param_len=%u", param_len);
-  if (param_len == 0) {
+  if (param_len < 19) {
     LOG_ERROR("%s", "Insufficient data");
     return;
   }
@@ -2438,7 +2438,8 @@
                 data.size() - (p_service_data - data.data()) - service_data_len,
                 BTM_BLE_AD_TYPE_SERVICE_DATA_TYPE, &service_data_len))) {
       uint16_t uuid;
-      STREAM_TO_UINT16(uuid, p_service_data);
+      const uint8_t* p_uuid = p_service_data;
+      STREAM_TO_UINT16(uuid, p_uuid);
 
       if (uuid == 0x184E /* Audio Stream Control service */ ||
           uuid == 0x184F /* Broadcast Audio Scan service */ ||
diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc
index 5904115..10c19d4 100644
--- a/system/stack/btm/btm_dev.cc
+++ b/system/stack/btm/btm_dev.cc
@@ -375,7 +375,7 @@
 
 static bool has_lenc_and_address_is_equal(void* data, void* context) {
   tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
-  if (!(p_dev_rec->ble.key_type & BTM_LE_KEY_LENC)) return false;
+  if (!(p_dev_rec->ble.key_type & BTM_LE_KEY_LENC)) return true;
 
   return is_address_equal(data, context);
 }
@@ -650,3 +650,25 @@
   p_dev_rec->bond_type = bond_type;
   return true;
 }
+
+/*******************************************************************************
+ *
+ * Function         btm_get_sec_dev_rec
+ *
+ * Description      Get security device records satisfying given filter
+ *
+ * Returns          A vector containing pointers of security device records
+ *
+ ******************************************************************************/
+std::vector<tBTM_SEC_DEV_REC*> btm_get_sec_dev_rec() {
+  std::vector<tBTM_SEC_DEV_REC*> result{};
+
+  list_node_t* end = list_end(btm_cb.sec_dev_rec);
+  for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end;
+       node = list_next(node)) {
+    tBTM_SEC_DEV_REC* p_dev_rec =
+        static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
+    result.push_back(p_dev_rec);
+  }
+  return result;
+}
diff --git a/system/stack/btm/btm_dev.h b/system/stack/btm/btm_dev.h
index 7591129..84d73e7 100644
--- a/system/stack/btm/btm_dev.h
+++ b/system/stack/btm/btm_dev.h
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <functional>
+
 #include "osi/include/log.h"
 #include "stack/btm/btm_ble_int.h"
 #include "stack/btm/security_device_record.h"
@@ -197,3 +199,14 @@
  ******************************************************************************/
 bool btm_set_bond_type_dev(const RawAddress& bd_addr,
                            tBTM_SEC_DEV_REC::tBTM_BOND_TYPE bond_type);
+
+/*******************************************************************************
+ *
+ * Function         btm_get_sec_dev_rec
+ *
+ * Description      Get security device records satisfying given filter
+ *
+ * Returns          A vector containing pointers of security device records
+ *
+ ******************************************************************************/
+std::vector<tBTM_SEC_DEV_REC*> btm_get_sec_dev_rec();
diff --git a/system/stack/btm/btm_iso_impl.h b/system/stack/btm/btm_iso_impl.h
index 0abe21f..9559e1d 100644
--- a/system/stack/btm/btm_iso_impl.h
+++ b/system/stack/btm/btm_iso_impl.h
@@ -367,6 +367,10 @@
     uint8_t status;
     uint16_t conn_handle;
 
+    if (len < 3) {
+      LOG(WARNING) << __func__ << "Malformatted packet received";
+      return;
+    }
     STREAM_TO_UINT8(status, stream);
     STREAM_TO_UINT16(conn_handle, stream);
 
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index 8df08bb..df9b6cc 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -44,6 +44,7 @@
 #include "osi/include/compat.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
+#include "osi/include/properties.h"
 #include "stack/btm/btm_dev.h"
 #include "stack/btm/security_device_record.h"
 #include "stack/eatt/eatt.h"
@@ -153,6 +154,14 @@
   }
 }
 
+static bool concurrentPeerAuthIsEnabled() {
+  // Was previously named BTM_DISABLE_CONCURRENT_PEER_AUTH.
+  // Renamed to ENABLED for homogeneity with system properties
+  static const bool sCONCURRENT_PEER_AUTH_IS_ENABLED = osi_property_get_bool(
+      "bluetooth.btm.sec.concurrent_peer_auth.enabled", true);
+  return sCONCURRENT_PEER_AUTH_IS_ENABLED;
+}
+
 void NotifyBondingCanceled(tBTM_STATUS btm_status) {
   if (btm_cb.api.p_bond_cancel_cmpl_callback) {
     btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS);
@@ -3406,11 +3415,9 @@
                       __func__, p_dev_rec, p_dev_rec->p_callback);
       p_dev_rec->p_callback = NULL;
       l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr);
-#ifdef BTM_DISABLE_CONCURRENT_PEER_AUTH
-    } else if (BTM_DISABLE_CONCURRENT_PEER_AUTH &&
+    } else if (!concurrentPeerAuthIsEnabled() &&
                p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
       p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
-#endif
     }
     return;
   }
@@ -4035,10 +4042,9 @@
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
 
   VLOG(2) << __func__ << " bda: " << bda;
-#if (defined(BTM_DISABLE_CONCURRENT_PEER_AUTH) && \
-     (BTM_DISABLE_CONCURRENT_PEER_AUTH == TRUE))
-  p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
-#endif
+  if (!concurrentPeerAuthIsEnabled()) {
+    p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+  }
 
   if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) &&
       (btm_cb.collision_start_time != 0) &&
@@ -4498,12 +4504,16 @@
 static void btm_sec_wait_and_start_authentication(tBTM_SEC_DEV_REC* p_dev_rec) {
   p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
   auto addr = new RawAddress(p_dev_rec->bd_addr);
+
+  static const int32_t delay_auth =
+      osi_property_get_int32("bluetooth.btm.sec.delay_auth_ms.value", 0);
+
   bt_status_t status = do_in_main_thread_delayed(
       FROM_HERE, base::Bind(&btm_sec_auth_timer_timeout, addr),
 #if BASE_VER < 931007
-      base::TimeDelta::FromMilliseconds(BTM_DELAY_AUTH_MS));
+      base::TimeDelta::FromMilliseconds(delay_auth));
 #else
-      base::Milliseconds(BTM_DELAY_AUTH_MS));
+      base::Milliseconds(delay_auth));
 #endif
   if (status != BT_STATUS_SUCCESS) {
     LOG(ERROR) << __func__
diff --git a/system/stack/btu/btu_hcif.cc b/system/stack/btu/btu_hcif.cc
index 552b174..ec05df2 100644
--- a/system/stack/btu/btu_hcif.cc
+++ b/system/stack/btu/btu_hcif.cc
@@ -93,7 +93,7 @@
 static void btu_hcif_io_cap_request_evt(const uint8_t* p);
 
 static void btu_ble_ll_conn_param_upd_evt(uint8_t* p, uint16_t evt_len);
-static void btu_ble_proc_ltk_req(uint8_t* p);
+static void btu_ble_proc_ltk_req(uint8_t* p, uint16_t evt_len);
 static void btu_hcif_encryption_key_refresh_cmpl_evt(uint8_t* p);
 static void btu_ble_data_length_change_evt(uint8_t* p, uint16_t evt_len);
 static void btu_ble_rc_param_req_evt(uint8_t* p, uint8_t len);
@@ -346,7 +346,7 @@
           btm_ble_read_remote_features_complete(p, ble_evt_len);
           break;
         case HCI_BLE_LTK_REQ_EVT: /* received only at peripheral device */
-          btu_ble_proc_ltk_req(p);
+          btu_ble_proc_ltk_req(p, ble_evt_len);
           break;
         case HCI_BLE_RC_PARAM_REQ_EVT:
           btu_ble_rc_param_req_evt(p, ble_evt_len);
@@ -1660,10 +1660,22 @@
                                 interval, latency, timeout);
 }
 
-static void btu_ble_proc_ltk_req(uint8_t* p) {
+static void btu_ble_proc_ltk_req(uint8_t* p, uint16_t evt_len) {
   uint16_t ediv, handle;
   uint8_t* pp;
 
+  // following the spec in Core_v5.3/Vol 4/Part E
+  // / 7.7.65.5 LE Long Term Key Request event
+  // A BLE Long Term Key Request event contains:
+  // - 1-byte subevent (already consumed in btu_hcif_process_event)
+  // - 2-byte connection handler
+  // - 8-byte random number
+  // - 2 byte Encrypted_Diversifier
+  if (evt_len < 2 + 8 + 2) {
+    LOG_ERROR("Event packet too short");
+    return;
+  }
+
   STREAM_TO_UINT16(handle, p);
   pp = p + 8;
   STREAM_TO_UINT16(ediv, pp);
diff --git a/system/stack/eatt/eatt_impl.h b/system/stack/eatt/eatt_impl.h
index f0d8254..998fc10 100644
--- a/system/stack/eatt/eatt_impl.h
+++ b/system/stack/eatt/eatt_impl.h
@@ -153,7 +153,8 @@
     tL2CAP_LE_CFG_INFO local_coc_cfg = {
         .mtu = eatt_dev->rx_mtu_,
         .mps = eatt_dev->rx_mps_ < max_mps ? eatt_dev->rx_mps_ : max_mps,
-        .credits = L2CAP_LE_CREDIT_DEFAULT};
+        .credits = L2CA_LeCreditDefault(),
+    };
 
     if (!L2CA_ConnectCreditBasedRsp(bda, identifier, lcids, L2CAP_CONN_OK,
                                     &local_coc_cfg))
@@ -584,7 +585,7 @@
     tL2CAP_LE_CFG_INFO local_coc_cfg = {
         .mtu = eatt_dev->rx_mtu_,
         .mps = eatt_dev->rx_mps_,
-        .credits = L2CAP_LE_CREDIT_DEFAULT,
+        .credits = L2CA_LeCreditDefault(),
         .number_of_channels = num_of_channels,
     };
 
diff --git a/system/stack/gap/gap_conn.cc b/system/stack/gap/gap_conn.cc
index d1b8219..23d9589 100644
--- a/system/stack/gap/gap_conn.cc
+++ b/system/stack/gap/gap_conn.cc
@@ -207,7 +207,7 @@
 
   /* Configure L2CAP COC, if transport is LE */
   if (transport == BT_TRANSPORT_LE) {
-    p_ccb->local_coc_cfg.credits = L2CAP_LE_CREDIT_DEFAULT;
+    p_ccb->local_coc_cfg.credits = L2CA_LeCreditDefault();
     p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
 
     uint16_t max_mps = controller_get_interface()->get_acl_data_size_ble();
diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc
index 3861016..9a1152b 100644
--- a/system/stack/gatt/gatt_api.cc
+++ b/system/stack/gatt/gatt_api.cc
@@ -21,7 +21,7 @@
  *  this file contains GATT interface functions
  *
  ******************************************************************************/
-#include "gatt_api.h"
+#include "stack/include/gatt_api.h"
 
 #include <base/logging.h>
 #include <base/strings/string_number_conversions.h>
@@ -31,13 +31,16 @@
 
 #include "bt_target.h"
 #include "device/include/controller.h"
-#include "gatt_int.h"
+#include "gd/os/system_properties.h"
 #include "internal_include/stack_config.h"
 #include "l2c_api.h"
 #include "main/shim/dumpsys.h"
 #include "osi/include/allocator.h"
+#include "osi/include/list.h"
 #include "osi/include/log.h"
+#include "stack/btm/btm_dev.h"
 #include "stack/gatt/connection_manager.h"
+#include "stack/gatt/gatt_int.h"
 #include "stack/include/bt_hdr.h"
 #include "types/bluetooth/uuid.h"
 #include "types/bt_transport.h"
@@ -304,7 +307,7 @@
   elem.type = list.asgn_range.is_primary ? GATT_UUID_PRI_SERVICE
                                          : GATT_UUID_SEC_SERVICE;
 
-  if (elem.type == GATT_UUID_PRI_SERVICE) {
+  if (elem.type == GATT_UUID_PRI_SERVICE && gatt_cb.over_br_enabled) {
     Uuid* p_uuid = gatts_get_service_uuid(elem.p_db);
     if (*p_uuid != Uuid::From16Bit(UUID_SERVCLASS_GMCS_SERVER) &&
         *p_uuid != Uuid::From16Bit(UUID_SERVCLASS_GTBS_SERVER)) {
@@ -1479,3 +1482,48 @@
   LOG_DEBUG("status=%d", status);
   return status;
 }
+
+static void gatt_bonded_check_add_address(const RawAddress& bda) {
+  if (!gatt_is_bda_in_the_srv_chg_clt_list(bda)) {
+    gatt_add_a_bonded_dev_for_srv_chg(bda);
+  }
+}
+
+std::optional<bool> OVERRIDE_GATT_LOAD_BONDED = std::nullopt;
+
+static bool gatt_load_bonded_is_enabled() {
+  static const bool sGATT_LOAD_BONDED = bluetooth::os::GetSystemPropertyBool(
+      "bluetooth.gatt.load_bonded.enabled", false);
+  if (OVERRIDE_GATT_LOAD_BONDED.has_value()) {
+    return OVERRIDE_GATT_LOAD_BONDED.value();
+  }
+  return sGATT_LOAD_BONDED;
+}
+
+/* Initialize GATTS list of bonded device service change updates.
+ *
+ * Addresses for bonded devices (publict for BR/EDR or pseudo for BLE) are added
+ * to GATTS service change control list so that updates are sent to bonded
+ * devices on next connect after any handles for GATTS services change due to
+ * services added/removed.
+ */
+void gatt_load_bonded(void) {
+  const bool load_bonded = gatt_load_bonded_is_enabled();
+  LOG_INFO("load bonded: %s", load_bonded ? "True" : "False");
+  if (!load_bonded) {
+    return;
+  }
+  for (tBTM_SEC_DEV_REC* p_dev_rec : btm_get_sec_dev_rec()) {
+    if (p_dev_rec->is_link_key_known()) {
+      LOG_VERBOSE("Add bonded BR/EDR transport %s",
+                  PRIVATE_ADDRESS(p_dev_rec->bd_addr));
+      gatt_bonded_check_add_address(p_dev_rec->bd_addr);
+    }
+    if (p_dev_rec->is_le_link_key_known()) {
+      VLOG(1) << " add bonded BLE " << p_dev_rec->ble.pseudo_addr;
+      LOG_VERBOSE("Add bonded BLE %s",
+                  PRIVATE_ADDRESS(p_dev_rec->ble.pseudo_addr));
+      gatt_bonded_check_add_address(p_dev_rec->ble.pseudo_addr);
+    }
+  }
+}
diff --git a/system/stack/gatt/gatt_int.h b/system/stack/gatt/gatt_int.h
index a05c27c..fa173f5 100644
--- a/system/stack/gatt/gatt_int.h
+++ b/system/stack/gatt/gatt_int.h
@@ -259,6 +259,8 @@
 }
 #undef CASE_RETURN_TEXT
 
+// If you change these values make sure to look at b/262219144 before.
+// Some platform rely on this to never changes
 #define GATT_GATT_START_HANDLE 1
 #define GATT_GAP_START_HANDLE 20
 #define GATT_GMCS_START_HANDLE 40
@@ -266,14 +268,6 @@
 #define GATT_TMAS_START_HANDLE 130
 #define GATT_APP_START_HANDLE 134
 
-#ifndef GATT_DEFAULT_START_HANDLE
-#define GATT_DEFAULT_START_HANDLE GATT_GATT_START_HANDLE
-#endif
-
-#ifndef GATT_LAST_HANDLE
-#define GATT_LAST_HANDLE 0xFFFF
-#endif
-
 typedef struct hdl_cfg {
   uint16_t gatt_start_hdl;
   uint16_t gap_start_hdl;
@@ -452,6 +446,7 @@
   tGATT_APPL_INFO cb_info;
 
   tGATT_HDL_CFG hdl_cfg;
+  bool over_br_enabled;
 } tGATT_CB;
 
 #define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4
diff --git a/system/stack/gatt/gatt_main.cc b/system/stack/gatt/gatt_main.cc
index 09eccb6..b9d1120 100644
--- a/system/stack/gatt/gatt_main.cc
+++ b/system/stack/gatt/gatt_main.cc
@@ -123,10 +123,10 @@
 
   L2CA_RegisterFixedChannel(L2CAP_ATT_CID, &fixed_reg);
 
-  bool gatt_over_br_is_disabled =
-      osi_property_get_bool("bluetooth.gatt_over_bredr.disabled", false);
+  gatt_cb.over_br_enabled =
+      osi_property_get_bool("bluetooth.gatt.over_bredr.enabled", true);
   /* Now, register with L2CAP for ATT PSM over BR/EDR */
-  if (!gatt_over_br_is_disabled &&
+  if (gatt_cb.over_br_enabled &&
       !L2CA_Register2(BT_PSM_ATT, dyn_info, false /* enable_snoop */, nullptr,
                       GATT_MAX_MTU_SIZE, 0, BTM_SEC_NONE)) {
     LOG(ERROR) << "ATT Dynamic Registration failed";
@@ -909,6 +909,13 @@
 /** This function is called to send a service chnaged indication to the
  * specified bd address */
 void gatt_send_srv_chg_ind(const RawAddress& peer_bda) {
+  static const uint16_t sGATT_DEFAULT_START_HANDLE =
+      (uint16_t)osi_property_get_int32(
+          "bluetooth.gatt.default_start_handle_for_srvc_change.value",
+          GATT_GATT_START_HANDLE);
+  static const uint16_t sGATT_LAST_HANDLE = (uint16_t)osi_property_get_int32(
+      "bluetooth.gatt.last_handle_for_srvc_change.value", 0xFFFF);
+
   VLOG(1) << __func__;
 
   if (!gatt_cb.handle_of_h_r) return;
@@ -921,8 +928,8 @@
 
   uint8_t handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
   uint8_t* p = handle_range;
-  UINT16_TO_STREAM(p, GATT_DEFAULT_START_HANDLE);
-  UINT16_TO_STREAM(p, GATT_LAST_HANDLE);
+  UINT16_TO_STREAM(p, sGATT_DEFAULT_START_HANDLE);
+  UINT16_TO_STREAM(p, sGATT_LAST_HANDLE);
   GATTS_HandleValueIndication(conn_id, gatt_cb.handle_of_h_r,
                               GATT_SIZE_OF_SRV_CHG_HNDL_RANGE, handle_range);
 }
diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc
index 38f91a0..d65b6d6 100644
--- a/system/stack/gatt/gatt_utils.cc
+++ b/system/stack/gatt/gatt_utils.cc
@@ -1715,10 +1715,12 @@
     pseduo_op_code_idx = 0x15; /* just an index to op_code_name */
   }
 
-  if (pseduo_op_code_idx <= GATT_OP_CODE_MAX)
+  #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
+  if (pseduo_op_code_idx < ARR_SIZE(op_code_name))
     return (uint8_t*)op_code_name[pseduo_op_code_idx];
   else
     return (uint8_t*)"Op Code Exceed Max";
+  #undef ARR_SIZE
 }
 
 /** Remove the application interface for the specified background device */
diff --git a/system/stack/hid/hidd_conn.cc b/system/stack/hid/hidd_conn.cc
index da78d40..fc0a245 100644
--- a/system/stack/hid/hidd_conn.cc
+++ b/system/stack/hid/hidd_conn.cc
@@ -27,6 +27,7 @@
 
 #include "bta/include/bta_api.h"
 #include "btif/include/btif_hd.h"
+#include "gd/common/init_flags.h"
 #include "osi/include/allocator.h"
 #include "stack/hid/hidd_int.h"
 #include "stack/include/bt_hdr.h"
@@ -347,7 +348,6 @@
 static void hidd_l2cif_disconnect(uint16_t cid) {
   L2CA_DisconnectReq(cid);
 
-
   HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
 
   tHID_CONN* p_hcon = &hd_cb.device.conn;
@@ -365,6 +365,10 @@
 
     // now disconnect CTRL
     L2CA_DisconnectReq(p_hcon->ctrl_cid);
+    if (bluetooth::common::init_flags::
+            clear_hidd_interrupt_cid_on_disconnect_is_enabled()) {
+      p_hcon->ctrl_cid = 0;
+    }
   }
 
   if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
diff --git a/system/stack/include/gatt_api.h b/system/stack/include/gatt_api.h
index 05d4115..eb37910 100644
--- a/system/stack/include/gatt_api.h
+++ b/system/stack/include/gatt_api.h
@@ -1190,4 +1190,7 @@
  * true, as there is no need to wipe controller acceptlist in this case. */
 extern void gatt_reset_bgdev_list(bool after_reset);
 
+// Initialize GATTS list of bonded device service change updates.
+extern void gatt_load_bonded(void);
+
 #endif /* GATT_API_H */
diff --git a/system/stack/include/l2c_api.h b/system/stack/include/l2c_api.h
index d62da3c..c4e452f 100644
--- a/system/stack/include/l2c_api.h
+++ b/system/stack/include/l2c_api.h
@@ -180,14 +180,11 @@
 
 // This is initial amout of credits we send, and amount to which we increase
 // credits once they fall below threshold
-constexpr uint16_t L2CAP_LE_CREDIT_DEFAULT = 0xffff;
+uint16_t L2CA_LeCreditDefault();
 
 // If credit count on remote fall below this value, we send back credits to
 // reach default value.
-constexpr uint16_t L2CAP_LE_CREDIT_THRESHOLD = 0x0040;
-
-static_assert(L2CAP_LE_CREDIT_THRESHOLD < L2CAP_LE_CREDIT_DEFAULT,
-              "Threshold must be smaller than default credits");
+uint16_t L2CA_LeCreditThreshold();
 
 // Max number of CIDs in the L2CAP CREDIT BASED CONNECTION REQUEST
 constexpr uint16_t L2CAP_CREDIT_BASED_MAX_CIDS = 5;
@@ -199,7 +196,7 @@
   uint16_t result; /* Only used in confirm messages */
   uint16_t mtu = 100;
   uint16_t mps = 100;
-  uint16_t credits = L2CAP_LE_CREDIT_DEFAULT;
+  uint16_t credits = L2CA_LeCreditDefault();
   uint8_t number_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS;
 };
 
diff --git a/system/stack/include/stack_metrics_logging.h b/system/stack/include/stack_metrics_logging.h
index 158c98f..58d869f 100644
--- a/system/stack/include/stack_metrics_logging.h
+++ b/system/stack/include/stack_metrics_logging.h
@@ -34,9 +34,9 @@
     uint32_t hci_cmd, uint16_t hci_event, uint16_t hci_ble_event,
     uint16_t cmd_status, uint16_t reason_code);
 
-void log_smp_pairing_event(const RawAddress& address, uint8_t smp_cmd,
+void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd,
                            android::bluetooth::DirectionEnum direction,
-                           uint8_t smp_fail_reason);
+                           uint16_t smp_fail_reason);
 
 void log_sdp_attribute(const RawAddress& address, uint16_t protocol_uuid,
                        uint16_t attribute_id, size_t attribute_size,
diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc
index 5464cb4..2a7efd8 100644
--- a/system/stack/l2cap/l2c_api.cc
+++ b/system/stack/l2cap/l2c_api.cc
@@ -34,6 +34,7 @@
 
 #include "device/include/controller.h"  // TODO Remove
 #include "gd/common/init_flags.h"
+#include "gd/os/system_properties.h"
 #include "main/shim/shim.h"
 #include "osi/include/allocator.h"
 #include "osi/include/log.h"
@@ -65,6 +66,29 @@
   return ret;
 }
 
+uint16_t L2CA_LeCreditDefault() {
+  static const uint16_t sL2CAP_LE_CREDIT_DEFAULT =
+      bluetooth::os::GetSystemPropertyUint32Base(
+          "bluetooth.l2cap.le.credit_default.value", 0xffff);
+  return sL2CAP_LE_CREDIT_DEFAULT;
+}
+
+uint16_t L2CA_LeCreditThreshold() {
+  static const uint16_t sL2CAP_LE_CREDIT_THRESHOLD =
+      bluetooth::os::GetSystemPropertyUint32Base(
+          "bluetooth.l2cap.le.credit_threshold.value", 0x0040);
+  return sL2CAP_LE_CREDIT_THRESHOLD;
+}
+
+static bool check_l2cap_credit() {
+  CHECK(L2CA_LeCreditThreshold() < L2CA_LeCreditDefault())
+      << "Threshold must be smaller than default credits";
+  return true;
+}
+
+// Replace static assert with startup assert depending of the config
+static const bool enforce_assert = check_l2cap_credit();
+
 /*******************************************************************************
  *
  * Function         L2CA_Register
diff --git a/system/stack/l2cap/l2c_ble.cc b/system/stack/l2cap/l2c_ble.cc
index a17ba28..890304d 100755
--- a/system/stack/l2cap/l2c_ble.cc
+++ b/system/stack/l2cap/l2c_ble.cc
@@ -990,7 +990,7 @@
       p_ccb->local_conn_cfg.mtu = L2CAP_SDU_LENGTH_LE_MAX;
       p_ccb->local_conn_cfg.mps =
           controller_get_interface()->get_acl_data_size_ble();
-      p_ccb->local_conn_cfg.credits = L2CAP_LE_CREDIT_DEFAULT,
+      p_ccb->local_conn_cfg.credits = L2CA_LeCreditDefault(),
 
       p_ccb->peer_conn_cfg.mtu = mtu;
       p_ccb->peer_conn_cfg.mps = mps;
diff --git a/system/stack/l2cap/l2c_fcr.cc b/system/stack/l2cap/l2c_fcr.cc
index 9c76005..d6d06d9 100644
--- a/system/stack/l2cap/l2c_fcr.cc
+++ b/system/stack/l2cap/l2c_fcr.cc
@@ -734,6 +734,10 @@
 
   } else {
     p_data = p_ccb->ble_sdu;
+    if (p_data == NULL) {
+      osi_free(p_buf);
+      return;
+    }
     if (p_buf->len > (p_ccb->ble_sdu_length - p_data->len)) {
       L2CAP_TRACE_ERROR("%s: buffer length=%d too big. max=%d. Dropped",
                         __func__, p_data->len,
diff --git a/system/stack/l2cap/l2c_main.cc b/system/stack/l2cap/l2c_main.cc
index 06714cb..1d412f7 100644
--- a/system/stack/l2cap/l2c_main.cc
+++ b/system/stack/l2cap/l2c_main.cc
@@ -221,9 +221,9 @@
     --p_ccb->remote_credit_count;
 
     /* If the credits left on the remote device are getting low, send some */
-    if (p_ccb->remote_credit_count <= L2CAP_LE_CREDIT_THRESHOLD) {
-      uint16_t credits = L2CAP_LE_CREDIT_DEFAULT - p_ccb->remote_credit_count;
-      p_ccb->remote_credit_count = L2CAP_LE_CREDIT_DEFAULT;
+    if (p_ccb->remote_credit_count <= L2CA_LeCreditThreshold()) {
+      uint16_t credits = L2CA_LeCreditDefault() - p_ccb->remote_credit_count;
+      p_ccb->remote_credit_count = L2CA_LeCreditDefault();
 
       /* Return back credits */
       l2c_csm_execute(p_ccb, L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT, &credits);
diff --git a/system/stack/metrics/stack_metrics_logging.cc b/system/stack/metrics/stack_metrics_logging.cc
index 4e23bd2..d69d54e 100644
--- a/system/stack/metrics/stack_metrics_logging.cc
+++ b/system/stack/metrics/stack_metrics_logging.cc
@@ -42,9 +42,9 @@
       hci_ble_event, cmd_status, reason_code);
 }
 
-void log_smp_pairing_event(const RawAddress& address, uint8_t smp_cmd,
+void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd,
                            android::bluetooth::DirectionEnum direction,
-                           uint8_t smp_fail_reason) {
+                           uint16_t smp_fail_reason) {
   bluetooth::shim::LogMetricSmpPairingEvent(address, smp_cmd, direction,
                                             smp_fail_reason);
 }
diff --git a/system/stack/smp/smp_int.h b/system/stack/smp/smp_int.h
index c4ddf3e..52b5c2b 100644
--- a/system/stack/smp/smp_int.h
+++ b/system/stack/smp/smp_int.h
@@ -32,6 +32,15 @@
 #include "stack/include/bt_octets.h"
 #include "types/raw_address.h"
 
+typedef enum : uint16_t {
+  SMP_METRIC_COMMAND_LE_FLAG = 0x0000,
+  SMP_METRIC_COMMAND_BR_FLAG = 0x0100,
+  SMP_METRIC_COMMAND_LE_PAIRING_CMPL = 0xFF00,
+  SMP_METRIC_COMMAND_BR_PAIRING_CMPL = 0xFF01,
+} tSMP_METRIC_COMMAND;
+
+constexpr uint16_t SMP_METRIC_STATUS_INTERNAL_FLAG = 0x0100;
+
 typedef enum : uint8_t {
   /* Legacy mode */
   SMP_MODEL_ENCRYPTION_ONLY = 0, /* Just Works model */
@@ -414,7 +423,8 @@
 
 /* smp_util.cc */
 extern void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing,
-                            const uint8_t* p_buf, size_t buf_len);
+                            const uint8_t* p_buf, size_t buf_len,
+                            bool is_over_br);
 extern bool smp_send_cmd(uint8_t cmd_code, tSMP_CB* p_cb);
 extern void smp_cb_cleanup(tSMP_CB* p_cb);
 extern void smp_reset_control_value(tSMP_CB* p_cb);
diff --git a/system/stack/smp/smp_l2c.cc b/system/stack/smp/smp_l2c.cc
index 6a13e8a..264cdc3 100644
--- a/system/stack/smp/smp_l2c.cc
+++ b/system/stack/smp/smp_l2c.cc
@@ -195,7 +195,8 @@
                        smp_rsp_timeout, NULL);
 
     smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
-                    p_buf->data + p_buf->offset, p_buf->len);
+                    p_buf->data + p_buf->offset, p_buf->len,
+                    false /* is_over_br */);
 
     if (cmd == SMP_OPCODE_CONFIRM) {
       SMP_TRACE_DEBUG(
@@ -334,7 +335,8 @@
                        smp_rsp_timeout, NULL);
 
     smp_log_metrics(p_cb->pairing_bda, false /* incoming */,
-                    p_buf->data + p_buf->offset, p_buf->len);
+                    p_buf->data + p_buf->offset, p_buf->len,
+                    true /* is_over_br */);
 
     p_cb->rcvd_cmd_code = cmd;
     p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
diff --git a/system/stack/smp/smp_utils.cc b/system/stack/smp/smp_utils.cc
index 71fa55d..f2aba5e 100644
--- a/system/stack/smp/smp_utils.cc
+++ b/system/stack/smp/smp_utils.cc
@@ -316,22 +316,26 @@
  * @param buf_len length available to read for p_buf
  */
 void smp_log_metrics(const RawAddress& bd_addr, bool is_outgoing,
-                     const uint8_t* p_buf, size_t buf_len) {
+                     const uint8_t* p_buf, size_t buf_len, bool is_over_br) {
   if (buf_len < 1) {
     LOG(WARNING) << __func__ << ": buffer is too small, size is " << buf_len;
     return;
   }
-  uint8_t cmd;
-  STREAM_TO_UINT8(cmd, p_buf);
+  uint8_t raw_cmd;
+  STREAM_TO_UINT8(raw_cmd, p_buf);
   buf_len--;
   uint8_t failure_reason = 0;
-  if (cmd == SMP_OPCODE_PAIRING_FAILED && buf_len >= 1) {
+  if (raw_cmd == SMP_OPCODE_PAIRING_FAILED && buf_len >= 1) {
     STREAM_TO_UINT8(failure_reason, p_buf);
   }
+  uint16_t metric_cmd =
+      is_over_br ? SMP_METRIC_COMMAND_BR_FLAG : SMP_METRIC_COMMAND_LE_FLAG;
+  metric_cmd |= static_cast<uint16_t>(raw_cmd);
   android::bluetooth::DirectionEnum direction =
       is_outgoing ? android::bluetooth::DirectionEnum::DIRECTION_OUTGOING
                   : android::bluetooth::DirectionEnum::DIRECTION_INCOMING;
-  log_smp_pairing_event(bd_addr, cmd, direction, failure_reason);
+  log_smp_pairing_event(bd_addr, metric_cmd, direction,
+                        static_cast<uint16_t>(failure_reason));
 }
 
 /*******************************************************************************
@@ -352,7 +356,8 @@
   SMP_TRACE_EVENT("%s", __func__);
 
   smp_log_metrics(rem_bda, true /* outgoing */,
-                  p_toL2CAP->data + p_toL2CAP->offset, p_toL2CAP->len);
+                  p_toL2CAP->data + p_toL2CAP->offset, p_toL2CAP->len,
+                  smp_cb.smp_over_br /* is_over_br */);
 
   l2cap_ret = L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_toL2CAP);
   if (l2cap_ret == L2CAP_DW_FAILED) {
@@ -980,6 +985,23 @@
                            smp_status_text(evt_data.cmplt.reason).c_str()));
   }
 
+  // Log pairing complete event
+  {
+    auto direction =
+        p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD
+            ? android::bluetooth::DirectionEnum::DIRECTION_OUTGOING
+            : android::bluetooth::DirectionEnum::DIRECTION_INCOMING;
+    uint16_t metric_cmd = p_cb->smp_over_br
+                              ? SMP_METRIC_COMMAND_BR_PAIRING_CMPL
+                              : SMP_METRIC_COMMAND_LE_PAIRING_CMPL;
+    uint16_t metric_status = p_cb->status;
+    if (metric_status > SMP_MAX_FAIL_RSN_PER_SPEC) {
+      metric_status |= SMP_METRIC_STATUS_INTERNAL_FLAG;
+    }
+    log_smp_pairing_event(p_cb->pairing_bda, metric_cmd, direction,
+                          metric_status);
+  }
+
   if (p_cb->status == SMP_SUCCESS && p_cb->smp_over_br) {
     btm_dev_consolidate_existing_connections(pairing_bda);
   }
diff --git a/system/stack/test/common/mock_l2cap_layer.cc b/system/stack/test/common/mock_l2cap_layer.cc
index 2892759..d03d143 100644
--- a/system/stack/test/common/mock_l2cap_layer.cc
+++ b/system/stack/test/common/mock_l2cap_layer.cc
@@ -94,3 +94,8 @@
                                       tL2CAP_LE_CFG_INFO* peer_cfg) {
   return l2cap_interface->ReconfigCreditBasedConnsReq(bd_addr, lcids, peer_cfg);
 }
+uint16_t L2CA_LeCreditDefault() { return l2cap_interface->LeCreditDefault(); }
+
+uint16_t L2CA_LeCreditThreshold() {
+  return l2cap_interface->LeCreditThreshold();
+}
diff --git a/system/stack/test/common/mock_l2cap_layer.h b/system/stack/test/common/mock_l2cap_layer.h
index edb662b..cb2b36d 100644
--- a/system/stack/test/common/mock_l2cap_layer.h
+++ b/system/stack/test/common/mock_l2cap_layer.h
@@ -51,6 +51,8 @@
                                 tL2CAP_LE_CFG_INFO* p_cfg) = 0;
   virtual bool ReconfigCreditBasedConnsReq(const RawAddress& bd_addr, std::vector<uint16_t> &lcids,
                                 tL2CAP_LE_CFG_INFO* peer_cfg) = 0;
+  virtual uint16_t LeCreditDefault() = 0;
+  virtual uint16_t LeCreditThreshold() = 0;
   virtual ~L2capInterface() = default;
 };
 
@@ -84,6 +86,8 @@
                     tL2CAP_LE_CFG_INFO* p_cfg));
   MOCK_METHOD3(ReconfigCreditBasedConnsReq,
                bool(const RawAddress& p_bd_addr, std::vector<uint16_t> &lcids, tL2CAP_LE_CFG_INFO* peer_cfg));
+  MOCK_METHOD(uint16_t, LeCreditDefault, ());
+  MOCK_METHOD(uint16_t, LeCreditThreshold, ());
 };
 
 /**
diff --git a/system/stack/test/gatt/gatt_api_test.cc b/system/stack/test/gatt/gatt_api_test.cc
new file mode 100644
index 0000000..7900b77
--- /dev/null
+++ b/system/stack/test/gatt/gatt_api_test.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gatt_api.h"
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+#include "btm/btm_dev.h"
+#include "gatt/gatt_int.h"
+
+extern tBTM_CB btm_cb;
+
+static const size_t QUEUE_SIZE_MAX = 10;
+
+static tBTM_SEC_DEV_REC* make_bonded_ble_device(const RawAddress& bda,
+                                                const RawAddress& rra) {
+  tBTM_SEC_DEV_REC* dev = btm_sec_allocate_dev_rec();
+  dev->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
+  dev->bd_addr = bda;
+  dev->ble.pseudo_addr = rra;
+  dev->ble.key_type = BTM_LE_KEY_PID | BTM_LE_KEY_PENC | BTM_LE_KEY_LENC;
+  return dev;
+}
+
+static tBTM_SEC_DEV_REC* make_bonded_dual_device(const RawAddress& bda,
+                                                 const RawAddress& rra) {
+  tBTM_SEC_DEV_REC* dev = make_bonded_ble_device(bda, rra);
+  dev->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+  return dev;
+}
+
+extern std::optional<bool> OVERRIDE_GATT_LOAD_BONDED;
+
+class GattApiTest : public ::testing::Test {
+ protected:
+  GattApiTest() = default;
+
+  virtual ~GattApiTest() = default;
+
+  void SetUp() override {
+    btm_cb.sec_dev_rec = list_new(osi_free);
+    gatt_cb.srv_chg_clt_q = fixed_queue_new(QUEUE_SIZE_MAX);
+    logging::SetMinLogLevel(-2);
+  }
+
+  void TearDown() override { list_free(btm_cb.sec_dev_rec); }
+};
+
+static const RawAddress SAMPLE_PUBLIC_BDA = {
+    {0x00, 0x00, 0x11, 0x22, 0x33, 0x44}};
+
+static const RawAddress SAMPLE_RRA_BDA = {{0xAA, 0xAA, 0x11, 0x22, 0x33, 0x44}};
+
+TEST_F(GattApiTest, test_gatt_load_bonded_ble_only) {
+  OVERRIDE_GATT_LOAD_BONDED = std::optional{true};
+  make_bonded_ble_device(SAMPLE_PUBLIC_BDA, SAMPLE_RRA_BDA);
+
+  gatt_load_bonded();
+
+  ASSERT_TRUE(gatt_is_bda_in_the_srv_chg_clt_list(SAMPLE_RRA_BDA));
+  ASSERT_FALSE(gatt_is_bda_in_the_srv_chg_clt_list(SAMPLE_PUBLIC_BDA));
+  OVERRIDE_GATT_LOAD_BONDED.reset();
+}
+
+TEST_F(GattApiTest, test_gatt_load_bonded_dual) {
+  OVERRIDE_GATT_LOAD_BONDED = std::optional{true};
+  make_bonded_dual_device(SAMPLE_PUBLIC_BDA, SAMPLE_RRA_BDA);
+
+  gatt_load_bonded();
+
+  ASSERT_TRUE(gatt_is_bda_in_the_srv_chg_clt_list(SAMPLE_RRA_BDA));
+  ASSERT_TRUE(gatt_is_bda_in_the_srv_chg_clt_list(SAMPLE_PUBLIC_BDA));
+  OVERRIDE_GATT_LOAD_BONDED.reset();
+}
diff --git a/system/stack/test/stack_l2cap_test.cc b/system/stack/test/stack_l2cap_test.cc
index 2418772..e8a6f1a 100644
--- a/system/stack/test/stack_l2cap_test.cc
+++ b/system/stack/test/stack_l2cap_test.cc
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include "common/init_flags.h"
+#include "device/include/controller.h"
 #include "internal_include/bt_trace.h"
 #include "stack/btm/btm_int_types.h"
 #include "stack/include/l2cap_hci_link_interface.h"
@@ -26,24 +27,38 @@
 tBTM_CB btm_cb;
 extern tL2C_CB l2cb;
 
+void l2c_link_send_to_lower_br_edr(tL2C_LCB* p_lcb, BT_HDR* p_buf);
+void l2c_link_send_to_lower_ble(tL2C_LCB* p_lcb, BT_HDR* p_buf);
+
 // Global trace level referred in the code under test
 uint8_t appl_trace_level = BT_TRACE_LEVEL_VERBOSE;
 
 extern "C" void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
 
-const char* test_flags[] = {
-    "INIT_logging_debug_enabled_for_all=true",
-    nullptr,
-};
+namespace {
+constexpr uint16_t kAclBufferCountClassic = 123;
+constexpr uint8_t kAclBufferCountBle = 45;
+
+}  // namespace
 
 class StackL2capTest : public ::testing::Test {
  protected:
   void SetUp() override {
-    bluetooth::common::InitFlags::Load(test_flags);
-    l2cb = {};  // TODO Use proper init/free APIs
+    bluetooth::common::InitFlags::SetAllForTesting();
+    controller_.get_acl_buffer_count_classic = []() {
+      return kAclBufferCountClassic;
+    };
+    controller_.get_acl_buffer_count_ble = []() { return kAclBufferCountBle; };
+    controller_.supports_ble = []() -> bool { return true; };
+    l2c_init();
   }
 
-  void TearDown() override {}
+  void TearDown() override {
+    l2c_free();
+    controller_ = {};
+  }
+
+  controller_t controller_;
 };
 
 TEST_F(StackL2capTest, l2cble_process_data_length_change_event) {
@@ -65,3 +80,117 @@
   l2cble_process_data_length_change_event(0x1234, 0x001b, 0x001b);
   ASSERT_EQ(0x001b, l2cb.lcb_pool[0].tx_data_len);
 }
+
+class StackL2capChannelTest : public StackL2capTest {
+ protected:
+  void SetUp() override { StackL2capTest::SetUp(); }
+
+  void TearDown() override { StackL2capTest::TearDown(); }
+
+  tL2C_CCB ccb_ = {
+      .in_use = true,
+      .chnl_state = CST_OPEN,  // tL2C_CHNL_STATE
+      .local_conn_cfg =
+          {
+              // tL2CAP_LE_CFG_INFO
+              .result = 0,
+              .mtu = 100,
+              .mps = 100,
+              .credits = L2CA_LeCreditDefault(),
+              .number_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS,
+          },
+      .peer_conn_cfg =
+          {
+              // tL2CAP_LE_CFG_INFO
+              .result = 0,
+              .mtu = 100,
+              .mps = 100,
+              .credits = L2CA_LeCreditDefault(),
+              .number_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS,
+          },
+      .is_first_seg = false,
+      .ble_sdu = nullptr,     // BT_HDR*; Buffer for storing unassembled sdu
+      .ble_sdu_length = 0,    /* Length of unassembled sdu length*/
+      .p_next_ccb = nullptr,  // struct t_l2c_ccb* Next CCB in the chain
+      .p_prev_ccb = nullptr,  // struct t_l2c_ccb* Previous CCB in the chain
+      .p_lcb = nullptr,  // struct t_l2c_linkcb* Link this CCB is assigned to
+      .local_cid = 40,
+      .remote_cid = 80,
+      .l2c_ccb_timer = nullptr,  // alarm_t* CCB Timer Entry
+      .p_rcb = nullptr,          // tL2C_RCB* Registration CB for this Channel
+      .config_done = 0,          // Configuration flag word
+      .remote_config_rsp_result = 0,  // The config rsp result from remote
+      .local_id = 12,                 // Transaction ID for local trans
+      .remote_id = 22,                // Transaction ID for local
+      .flags = 0,
+      .connection_initiator = false,
+      .our_cfg = {},   // tL2CAP_CFG_INFO Our saved configuration options
+      .peer_cfg = {},  // tL2CAP_CFG_INFO Peer's saved configuration options
+      .xmit_hold_q = nullptr,  // fixed_queue_t*  Transmit data hold queue
+      .cong_sent = false,
+      .buff_quota = 0,
+
+      .ccb_priority =
+          L2CAP_CHNL_PRIORITY_HIGH,  // tL2CAP_CHNL_PRIORITY Channel priority
+      .tx_data_rate = 0,  // tL2CAP_CHNL_PRIORITY  Channel Tx data rate
+      .rx_data_rate = 0,  // tL2CAP_CHNL_PRIORITY  Channel Rx data rate
+
+      .ertm_info =
+          {
+              // .tL2CAP_ERTM_INFO
+              .preferred_mode = 0,
+          },
+      .fcrb =
+          {
+              // tL2C_FCRB
+              .next_tx_seq = 0,
+              .last_rx_ack = 0,
+              .next_seq_expected = 0,
+              .last_ack_sent = 0,
+              .num_tries = 0,
+              .max_held_acks = 0,
+              .remote_busy = false,
+              .rej_sent = false,
+              .srej_sent = false,
+              .wait_ack = false,
+              .rej_after_srej = false,
+              .send_f_rsp = false,
+              .rx_sdu_len = 0,
+              .p_rx_sdu =
+                  nullptr,  // BT_HDR* Buffer holding the SDU being received
+              .waiting_for_ack_q = nullptr,  // fixed_queue_t*
+              .srej_rcv_hold_q = nullptr,    // fixed_queue_t*
+              .retrans_q = nullptr,          // fixed_queue_t*
+              .ack_timer = nullptr,          // alarm_t*
+              .mon_retrans_timer = nullptr,  // alarm_t*
+          },
+      .tx_mps = 0,
+      .max_rx_mtu = 0,
+      .fcr_cfg_tries = 0,
+      .peer_cfg_already_rejected = false,
+      .out_cfg_fcr_present = false,
+      .is_flushable = false,
+      .fixed_chnl_idle_tout = 0,
+      .tx_data_len = 0,
+      .remote_credit_count = 0,
+      .ecoc = false,
+      .reconfig_started = false,
+      .metrics = {},
+  };
+};
+
+TEST_F(StackL2capChannelTest, l2c_lcc_proc_pdu__FirstSegment) {
+  ccb_.is_first_seg = true;
+
+  BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + 32);
+  p_buf->len = 32;
+
+  l2c_lcc_proc_pdu(&ccb_, p_buf);
+}
+
+TEST_F(StackL2capChannelTest, l2c_lcc_proc_pdu__NextSegment) {
+  BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + 32);
+  p_buf->len = 32;
+
+  l2c_lcc_proc_pdu(&ccb_, p_buf);
+}
diff --git a/system/test/mock/mock_bta_hearing_aid.cc b/system/test/mock/mock_bta_hearing_aid.cc
index eabcd09..200df2d 100644
--- a/system/test/mock/mock_bta_hearing_aid.cc
+++ b/system/test/mock/mock_bta_hearing_aid.cc
@@ -52,22 +52,39 @@
   mock_function_count_map[__func__]++;
   return 0;
 }
+
 void HearingAid::AddFromStorage(const HearingDevice& dev_info,
                                 uint16_t is_acceptlisted) {
   mock_function_count_map[__func__]++;
 }
+
 void HearingAid::DebugDump(int fd) { mock_function_count_map[__func__]++; }
-HearingAid* HearingAid::Get() {
-  mock_function_count_map[__func__]++;
-  return nullptr;
-}
+
 bool HearingAid::IsHearingAidRunning() {
   mock_function_count_map[__func__]++;
   return false;
 }
+
 void HearingAid::CleanUp() { mock_function_count_map[__func__]++; }
+
 void HearingAid::Initialize(
     bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
     base::Closure initCb) {
   mock_function_count_map[__func__]++;
 }
+
+void HearingAid::Connect(const RawAddress& address) {
+  mock_function_count_map[__func__]++;
+}
+
+void HearingAid::Disconnect(const RawAddress& address) {
+  mock_function_count_map[__func__]++;
+}
+
+void HearingAid::AddToAcceptlist(const RawAddress& address) {
+  mock_function_count_map[__func__]++;
+}
+
+void HearingAid::SetVolume(int8_t volume) {
+  mock_function_count_map[__func__]++;
+}
diff --git a/system/test/mock/mock_main_shim.cc b/system/test/mock/mock_main_shim.cc
index 69cd8df..1e997ce 100644
--- a/system/test/mock/mock_main_shim.cc
+++ b/system/test/mock/mock_main_shim.cc
@@ -25,6 +25,7 @@
 extern std::map<std::string, int> mock_function_count_map;
 
 #define LOG_TAG "bt_shim"
+
 #include "gd/common/init_flags.h"
 #include "main/shim/entry.h"
 #include "main/shim/shim.h"
@@ -45,9 +46,14 @@
   mock_function_count_map[__func__]++;
   return false;
 }
+namespace test {
+namespace mock {
+bool bluetooth_shim_is_gd_stack_started_up = false;
+}
+}  // namespace test
 bool bluetooth::shim::is_gd_stack_started_up() {
   mock_function_count_map[__func__]++;
-  return false;
+  return test::mock::bluetooth_shim_is_gd_stack_started_up;
 }
 bool bluetooth::shim::is_gd_link_policy_enabled() {
   mock_function_count_map[__func__]++;
diff --git a/system/test/mock/mock_main_shim_metrics_api.cc b/system/test/mock/mock_main_shim_metrics_api.cc
index 30aeeb1..8330b85 100644
--- a/system/test/mock/mock_main_shim_metrics_api.cc
+++ b/system/test/mock/mock_main_shim_metrics_api.cc
@@ -128,8 +128,8 @@
       raw_address, handle, cmd_status, transmit_power_level);
 }
 void bluetooth::shim::LogMetricSmpPairingEvent(
-    const RawAddress& raw_address, uint8_t smp_cmd,
-    android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason) {
+    const RawAddress& raw_address, uint16_t smp_cmd,
+    android::bluetooth::DirectionEnum direction, uint16_t smp_fail_reason) {
   mock_function_count_map[__func__]++;
   test::mock::main_shim_metrics_api::LogMetricSmpPairingEvent(
       raw_address, smp_cmd, direction, smp_fail_reason);
diff --git a/system/test/mock/mock_main_shim_metrics_api.h b/system/test/mock/mock_main_shim_metrics_api.h
index b42529f..d85088f 100644
--- a/system/test/mock/mock_main_shim_metrics_api.h
+++ b/system/test/mock/mock_main_shim_metrics_api.h
@@ -171,19 +171,19 @@
 };
 extern struct LogMetricReadTxPowerLevelResult LogMetricReadTxPowerLevelResult;
 // Name: LogMetricSmpPairingEvent
-// Params: const RawAddress& raw_address, uint8_t smp_cmd,
+// Params: const RawAddress& raw_address, uint16_t smp_cmd,
 // android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason Returns:
 // void
 struct LogMetricSmpPairingEvent {
-  std::function<void(const RawAddress& raw_address, uint8_t smp_cmd,
+  std::function<void(const RawAddress& raw_address, uint16_t smp_cmd,
                      android::bluetooth::DirectionEnum direction,
-                     uint8_t smp_fail_reason)>
-      body{[](const RawAddress& raw_address, uint8_t smp_cmd,
+                     uint16_t smp_fail_reason)>
+      body{[](const RawAddress& raw_address, uint16_t smp_cmd,
               android::bluetooth::DirectionEnum direction,
-              uint8_t smp_fail_reason) {}};
-  void operator()(const RawAddress& raw_address, uint8_t smp_cmd,
+              uint16_t smp_fail_reason) {}};
+  void operator()(const RawAddress& raw_address, uint16_t smp_cmd,
                   android::bluetooth::DirectionEnum direction,
-                  uint8_t smp_fail_reason) {
+                  uint16_t smp_fail_reason) {
     body(raw_address, smp_cmd, direction, smp_fail_reason);
   };
 };
diff --git a/system/test/mock/mock_stack_btm_dev.cc b/system/test/mock/mock_stack_btm_dev.cc
index bfd3081..cc959d3 100644
--- a/system/test/mock/mock_stack_btm_dev.cc
+++ b/system/test/mock/mock_stack_btm_dev.cc
@@ -118,3 +118,7 @@
 void BTM_SecDumpDev(const RawAddress& bd_addr) {
   mock_function_count_map[__func__]++;
 }
+std::vector<tBTM_SEC_DEV_REC*> btm_get_sec_dev_rec() {
+  mock_function_count_map[__func__]++;
+  return {};
+}
diff --git a/system/test/mock/mock_stack_l2cap_api.cc b/system/test/mock/mock_stack_l2cap_api.cc
index 27cd1e3..7311b3b 100644
--- a/system/test/mock/mock_stack_l2cap_api.cc
+++ b/system/test/mock/mock_stack_l2cap_api.cc
@@ -99,6 +99,8 @@
 struct L2CA_SetChnlFlushability L2CA_SetChnlFlushability;
 struct L2CA_FlushChannel L2CA_FlushChannel;
 struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished;
+struct L2CA_LeCreditDefault L2CA_LeCreditDefault;
+struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold;
 
 }  // namespace stack_l2cap_api
 }  // namespace mock
@@ -287,5 +289,13 @@
   return test::mock::stack_l2cap_api::L2CA_IsLinkEstablished(bd_addr,
                                                              transport);
 }
+uint16_t L2CA_LeCreditDefault() {
+  mock_function_count_map[__func__]++;
+  return test::mock::stack_l2cap_api::L2CA_LeCreditDefault();
+}
+uint16_t L2CA_LeCreditThreshold() {
+  mock_function_count_map[__func__]++;
+  return test::mock::stack_l2cap_api::L2CA_LeCreditThreshold();
+}
 
 // END mockcify generation
diff --git a/system/test/mock/mock_stack_l2cap_api.h b/system/test/mock/mock_stack_l2cap_api.h
index 4488101..592485c 100644
--- a/system/test/mock/mock_stack_l2cap_api.h
+++ b/system/test/mock/mock_stack_l2cap_api.h
@@ -485,6 +485,22 @@
   };
 };
 extern struct L2CA_IsLinkEstablished L2CA_IsLinkEstablished;
+// Name: L2CA_LeCreditDefault
+// Params:
+// Returns: uint16_t
+struct L2CA_LeCreditDefault {
+  std::function<uint16_t()> body{[]() { return 0; }};
+  uint16_t operator()() { return body(); };
+};
+extern struct L2CA_LeCreditDefault L2CA_LeCreditDefault;
+// Name: L2CA_LeCreditThreshold
+// Params:
+// Returns: uint16_t
+struct L2CA_LeCreditThreshold {
+  std::function<uint16_t()> body{[]() { return 0; }};
+  uint16_t operator()() { return body(); };
+};
+extern struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold;
 
 }  // namespace stack_l2cap_api
 }  // namespace mock
diff --git a/system/test/mock/mock_stack_metrics_logging.cc b/system/test/mock/mock_stack_metrics_logging.cc
index 1f51191..028636d 100644
--- a/system/test/mock/mock_stack_metrics_logging.cc
+++ b/system/test/mock/mock_stack_metrics_logging.cc
@@ -86,9 +86,9 @@
       address, connection_handle, direction, link_type, hci_cmd, hci_event,
       hci_ble_event, cmd_status, reason_code);
 }
-void log_smp_pairing_event(const RawAddress& address, uint8_t smp_cmd,
+void log_smp_pairing_event(const RawAddress& address, uint16_t smp_cmd,
                            android::bluetooth::DirectionEnum direction,
-                           uint8_t smp_fail_reason) {
+                           uint16_t smp_fail_reason) {
   mock_function_count_map[__func__]++;
   test::mock::stack_metrics_logging::log_smp_pairing_event(
       address, smp_cmd, direction, smp_fail_reason);
diff --git a/system/test/mock/mock_stack_metrics_logging.h b/system/test/mock/mock_stack_metrics_logging.h
index 967b2f8..8b695f4 100644
--- a/system/test/mock/mock_stack_metrics_logging.h
+++ b/system/test/mock/mock_stack_metrics_logging.h
@@ -96,19 +96,19 @@
 };
 extern struct log_link_layer_connection_event log_link_layer_connection_event;
 // Name: log_smp_pairing_event
-// Params: const RawAddress& address, uint8_t smp_cmd,
+// Params: const RawAddress& address, uint16_t smp_cmd,
 // android::bluetooth::DirectionEnum direction, uint8_t smp_fail_reason Returns:
 // void
 struct log_smp_pairing_event {
-  std::function<void(const RawAddress& address, uint8_t smp_cmd,
+  std::function<void(const RawAddress& address, uint16_t smp_cmd,
                      android::bluetooth::DirectionEnum direction,
-                     uint8_t smp_fail_reason)>
-      body{[](const RawAddress& address, uint8_t smp_cmd,
+                     uint16_t smp_fail_reason)>
+      body{[](const RawAddress& address, uint16_t smp_cmd,
               android::bluetooth::DirectionEnum direction,
-              uint8_t smp_fail_reason) {}};
-  void operator()(const RawAddress& address, uint8_t smp_cmd,
+              uint16_t smp_fail_reason) {}};
+  void operator()(const RawAddress& address, uint16_t smp_cmd,
                   android::bluetooth::DirectionEnum direction,
-                  uint8_t smp_fail_reason) {
+                  uint16_t smp_fail_reason) {
     body(address, smp_cmd, direction, smp_fail_reason);
   };
 };
diff --git a/system/types/ble_address_with_type.h b/system/types/ble_address_with_type.h
index 38a52cc..250072d 100644
--- a/system/types/ble_address_with_type.h
+++ b/system/types/ble_address_with_type.h
@@ -116,9 +116,19 @@
     return (other & ~kBleAddressIdentityBit) ==
            (type & ~kBleAddressIdentityBit);
   }
+
   std::string ToString() const {
     return std::string(bda.ToString() + "[" + AddressTypeText(type) + "]");
   }
+
+  std::string ToStringForLogging() const {
+    return bda.ToStringForLogging() + "[" + AddressTypeText(type) + "]";
+  }
+
+  std::string ToRedactedStringForLogging() const {
+    return bda.ToRedactedStringForLogging() + "[" + AddressTypeText(type) + "]";
+  }
+
   bool operator==(const tBLE_BD_ADDR rhs) const {
     return rhs.type == type && rhs.bda == bda;
   }
diff --git a/system/types/raw_address.cc b/system/types/raw_address.cc
index afaf4ef..0cd9de0 100644
--- a/system/types/raw_address.cc
+++ b/system/types/raw_address.cc
@@ -38,12 +38,22 @@
   std::copy(mac.begin(), mac.end(), address);
 }
 
-std::string RawAddress::ToString() const {
+std::string RawAddress::ToString() const { return ToColonSepHexString(); }
+
+std::string RawAddress::ToColonSepHexString() const {
   return base::StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", address[0],
                             address[1], address[2], address[3], address[4],
                             address[5]);
 }
 
+std::string RawAddress::ToStringForLogging() const {
+  return ToColonSepHexString();
+}
+
+std::string RawAddress::ToRedactedStringForLogging() const {
+  return base::StringPrintf("xx:xx:xx:xx:%02x:%02x", address[4], address[5]);
+}
+
 std::array<uint8_t, RawAddress::kLength> RawAddress::ToArray() const {
   std::array<uint8_t, kLength> mac;
   std::copy(std::begin(address), std::end(address), std::begin(mac));
diff --git a/system/types/raw_address.h b/system/types/raw_address.h
index b3e7530..d623b9f 100644
--- a/system/types/raw_address.h
+++ b/system/types/raw_address.h
@@ -46,8 +46,22 @@
 
   bool IsEmpty() const { return *this == kEmpty; }
 
+  // TODO (b/258090765): remove it and
+  // replace its usage with ToColonSepHexString
   std::string ToString() const;
 
+  // Return a string representation in the form of
+  // hexadecimal string separated by colon (:), e.g.,
+  // "12:34:56:ab:cd:ef"
+  std::string ToColonSepHexString() const;
+  // same as ToColonSepHexString
+  std::string ToStringForLogging() const;
+
+  // Similar with ToColonHexString, ToRedactedStringForLogging returns a
+  // colon separated hexadecimal reprentation of the address but, with the
+  // leftmost 4 bytes masked with "xx", e.g., "xx:xx:xx:xx:ab:cd".
+  std::string ToRedactedStringForLogging() const;
+
   // Converts |string| to RawAddress and places it in |to|. If |from| does
   // not represent a Bluetooth address, |to| is not modified and this function
   // returns false. Otherwise, it returns true.
diff --git a/system/types/test/raw_address_unittest.cc b/system/types/test/raw_address_unittest.cc
index 3a34295..513c8b7 100644
--- a/system/types/test/raw_address_unittest.cc
+++ b/system/types/test/raw_address_unittest.cc
@@ -198,3 +198,14 @@
   std::array<uint8_t, 6> mac2 = bdaddr.ToArray();
   ASSERT_EQ(mac, mac2);
 }
+
+TEST(RawAddress, ToStringForLoggingTest) {
+  std::array<uint8_t, 6> addr_bytes = {0x11, 0x22, 0x33, 0x44, 0x55, 0xab};
+  RawAddress addr(addr_bytes);
+  const std::string redacted_loggable_str = "xx:xx:xx:xx:55:ab";
+  const std::string loggbable_str = "11:22:33:44:55:ab";
+  std::string ret1 = addr.ToStringForLogging();
+  ASSERT_STREQ(ret1.c_str(), loggbable_str.c_str());
+  std::string ret2 = addr.ToRedactedStringForLogging();
+  ASSERT_STREQ(ret2.c_str(), redacted_loggable_str.c_str());
+}