diff --git a/android/app/jni/com_android_bluetooth_hid_host.cpp b/android/app/jni/com_android_bluetooth_hid_host.cpp index b21fc9c5b5b35f894173c20e7040e064c316e28f..f60a6a2d735c84e1af4dde3944607370f4b77ab6 100644 --- a/android/app/jni/com_android_bluetooth_hid_host.cpp +++ b/android/app/jni/com_android_bluetooth_hid_host.cpp @@ -271,7 +271,8 @@ static jboolean connectHidNative(JNIEnv* env, jobject /* object */, } static jboolean disconnectHidNative(JNIEnv* env, jobject /* object */, - jbyteArray address) { + jbyteArray address, + jboolean reconnect_allowed) { jbyte* addr; jboolean ret = JNI_TRUE; if (!sBluetoothHidInterface) return JNI_FALSE; @@ -282,7 +283,8 @@ static jboolean disconnectHidNative(JNIEnv* env, jobject /* object */, return JNI_FALSE; } - bt_status_t status = sBluetoothHidInterface->disconnect((RawAddress*)addr); + bt_status_t status = + sBluetoothHidInterface->disconnect((RawAddress*)addr, reconnect_allowed); if (status != BT_STATUS_SUCCESS) { log::error("Failed disconnect hid channel, status: {}", bt_status_text(status)); @@ -500,7 +502,7 @@ int register_com_android_bluetooth_hid_host(JNIEnv* env) { {"initializeNative", "()V", (void*)initializeNative}, {"cleanupNative", "()V", (void*)cleanupNative}, {"connectHidNative", "([B)Z", (void*)connectHidNative}, - {"disconnectHidNative", "([B)Z", (void*)disconnectHidNative}, + {"disconnectHidNative", "([BZ)Z", (void*)disconnectHidNative}, {"getProtocolModeNative", "([B)Z", (void*)getProtocolModeNative}, {"virtualUnPlugNative", "([B)Z", (void*)virtualUnPlugNative}, {"setProtocolModeNative", "([BB)Z", (void*)setProtocolModeNative}, diff --git a/android/app/src/com/android/bluetooth/hid/HidHostNativeInterface.java b/android/app/src/com/android/bluetooth/hid/HidHostNativeInterface.java index 3a717023ca0c7bab4d58244874b2fd2aeab90762..6d6c5b404336f167d100bf1d726a08b229931fa5 100644 --- a/android/app/src/com/android/bluetooth/hid/HidHostNativeInterface.java +++ b/android/app/src/com/android/bluetooth/hid/HidHostNativeInterface.java @@ -64,8 +64,8 @@ public class HidHostNativeInterface { return connectHidNative(address); } - boolean disconnectHid(byte[] address) { - return disconnectHidNative(address); + boolean disconnectHid(byte[] address, boolean reconnectAllowed) { + return disconnectHidNative(address, reconnectAllowed); } boolean getProtocolMode(byte[] address) { @@ -168,7 +168,7 @@ public class HidHostNativeInterface { private native boolean connectHidNative(byte[] btAddress); - private native boolean disconnectHidNative(byte[] btAddress); + private native boolean disconnectHidNative(byte[] btAddress, boolean reconnectAllowed); private native boolean getProtocolModeNative(byte[] btAddress); diff --git a/android/app/src/com/android/bluetooth/hid/HidHostService.java b/android/app/src/com/android/bluetooth/hid/HidHostService.java index 433ab301606aa0361d431925f50c40dbfcbf4a65..745aedd2cc19d4fa069fae2b5fd4fde907c8d108 100644 --- a/android/app/src/com/android/bluetooth/hid/HidHostService.java +++ b/android/app/src/com/android/bluetooth/hid/HidHostService.java @@ -201,7 +201,10 @@ public class HidHostService extends ProfileService { break; case MESSAGE_DISCONNECT: { BluetoothDevice device = (BluetoothDevice) msg.obj; - if (!mNativeInterface.disconnectHid(getByteAddress(device))) { + int connectionPolicy = getConnectionPolicy(device); + boolean reconnectAllowed = + connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED; + if (!mNativeInterface.disconnectHid(getByteAddress(device), reconnectAllowed)) { broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); break; @@ -352,9 +355,7 @@ public class HidHostService extends ProfileService { } }; - /** - * Handlers for incoming service calls - */ + /** Handlers for incoming service calls */ @VisibleForTesting static class BluetoothHidHostBinder extends IBluetoothHidHost.Stub implements IProfileServiceBinder { diff --git a/system/btif/include/btif_hh.h b/system/btif/include/btif_hh.h index 7dd5aa1cdcf8d32151594901db1e418adf90d03b..59d39cbde84cda21092a8a6d49774eec8aa0d6c7 100644 --- a/system/btif/include/btif_hh.h +++ b/system/btif/include/btif_hh.h @@ -109,6 +109,7 @@ typedef struct { uint8_t dev_handle; tAclLinkSpec link_spec; tBTA_HH_ATTR_MASK attr_mask; + bool reconnect_allowed; } btif_hh_added_device_t; /** @@ -133,7 +134,8 @@ extern btif_hh_cb_t btif_hh_cb; btif_hh_device_t* btif_hh_find_connected_dev_by_handle(uint8_t handle); void btif_hh_remove_device(const tAclLinkSpec& link_spec); bool btif_hh_add_added_dev(const tAclLinkSpec& link_spec, - tBTA_HH_ATTR_MASK attr_mask); + tBTA_HH_ATTR_MASK attr_mask, + bool reconnect_allowed); bt_status_t btif_hh_virtual_unplug(const tAclLinkSpec* link_spec); void btif_hh_disconnect(const tAclLinkSpec* link_spec); void btif_hh_setreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type, diff --git a/system/btif/include/btif_storage.h b/system/btif/include/btif_storage.h index 394cd5b5b7da4f58ecc414548d2feefb8c1555b4..51600d535b31b31cd7b3edfd0352816d36e66a61 100644 --- a/system/btif/include/btif_storage.h +++ b/system/btif/include/btif_storage.h @@ -215,6 +215,29 @@ void btif_storage_load_le_devices(void); ******************************************************************************/ bt_status_t btif_storage_load_bonded_devices(void); +/******************************************************************************* + * + * Function btif_storage_set_hid_connection_policy + * + * Description Stores connection policy info in nvram + * + * Returns BT_STATUS_SUCCESS + * + ******************************************************************************/ +bt_status_t btif_storage_set_hid_connection_policy(const RawAddress& addr, + bool reconnect_allowed); +/******************************************************************************* + * + * Function btif_storage_get_hid_connection_policy + * + * Description get connection policy info from nvram + * + * Returns BT_STATUS_SUCCESS + * + ******************************************************************************/ +bt_status_t btif_storage_get_hid_connection_policy(const RawAddress& addr, + bool* reconnect_allowed); + /******************************************************************************* * * Function btif_storage_add_hid_device_info diff --git a/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index 56887822a07514669c23e62c614b37de12a98d81..ccd67812ceae90af10023aa3e139a77c11fa8afb 100644 --- a/system/btif/src/btif_hh.cc +++ b/system/btif/src/btif_hh.cc @@ -280,6 +280,24 @@ static void sync_lockstate_on_connect(btif_hh_device_t* p_dev) { } } +/******************************************************************************* + * + * Function btif_hh_find_added_dev + * + * Description Return the added device pointer of the specified address + * + * Returns Added device entry + ******************************************************************************/ +btif_hh_added_device_t* btif_hh_find_added_dev(const RawAddress& addr) { + for (int i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) { + btif_hh_added_device_t* added_dev = &btif_hh_cb.added_devices[i]; + if (added_dev->link_spec.addrt.bda == addr) { + return added_dev; + } + } + return nullptr; +} + /******************************************************************************* * * Function btif_hh_find_connected_dev_by_handle @@ -390,9 +408,38 @@ static void hh_connect_complete(uint8_t handle, tAclLinkSpec& link_spec, HAL_CBACK(bt_hh_callbacks, connection_state_cb, &link_spec.addrt.bda, state); } +static bool hh_connection_allowed(const RawAddress& bda) { + /* Accept connection only if reconnection is allowed for the known device, or + * outgoing connection was requested */ + btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(bda); + if (added_dev != nullptr && added_dev->reconnect_allowed) { + LOG_VERBOSE("Connection allowed %s", ADDRESS_TO_LOGGABLE_CSTR(bda)); + return true; + } else if (btif_hh_cb.pending_link_spec.addrt.bda == bda) { + LOG_VERBOSE("Device connection was pending for: %s, status: %s", + ADDRESS_TO_LOGGABLE_CSTR(bda), + btif_hh_status_text(btif_hh_cb.status).c_str()); + return true; + } + + return false; +} + static void hh_open_handler(tBTA_HH_CONN& conn) { log::debug("status = {}, handle = {}", conn.status, conn.handle); + if (!hh_connection_allowed(conn.link_spec.addrt.bda)) { + LOG_WARN("Reject unexpected incoming HID Connection, device: %s", + ADDRESS_TO_LOGGABLE_CSTR(conn.link_spec)); + btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_handle(conn.handle); + if (p_dev != nullptr) { + p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED; + } + + hh_connect_complete(conn.handle, conn.link_spec, BTIF_HH_DEV_DISCONNECTED); + return; + } + HAL_CBACK(bt_hh_callbacks, connection_state_cb, (RawAddress*)&conn.link_spec.addrt.bda, BTHH_CONN_STATE_CONNECTING); btif_hh_cb.pending_link_spec = {}; @@ -447,7 +494,8 @@ static void hh_open_handler(tBTA_HH_CONN& conn) { * Returns true if add successfully, otherwise false. ******************************************************************************/ bool btif_hh_add_added_dev(const tAclLinkSpec& link_spec, - tBTA_HH_ATTR_MASK attr_mask) { + tBTA_HH_ATTR_MASK attr_mask, + bool reconnect_allowed) { int i; for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) { if (btif_hh_cb.added_devices[i].link_spec.addrt.bda == @@ -458,10 +506,12 @@ bool btif_hh_add_added_dev(const tAclLinkSpec& link_spec, } for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) { if (btif_hh_cb.added_devices[i].link_spec.addrt.bda.IsEmpty()) { - log::warn("Added device {}", ADDRESS_TO_LOGGABLE_STR(link_spec)); + log::warn("Added device {} reconnection allowed: {}", + ADDRESS_TO_LOGGABLE_STR(link_spec), reconnect_allowed); btif_hh_cb.added_devices[i].link_spec = link_spec; btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE; btif_hh_cb.added_devices[i].attr_mask = attr_mask; + btif_hh_cb.added_devices[i].reconnect_allowed = reconnect_allowed; return true; } } @@ -1012,7 +1062,7 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { p_data->dscp_info.version, p_data->dscp_info.ctry_code, len, p_data->dscp_info.descriptor.dsc_list); - if (btif_hh_add_added_dev(p_dev->link_spec, p_dev->attr_mask)) { + if (btif_hh_add_added_dev(p_dev->link_spec, p_dev->attr_mask, true)) { tBTA_HH_DEV_DSCP_INFO dscp_info; bt_status_t ret; btif_hh_copy_hid_info(&dscp_info, &p_data->dscp_info); @@ -1029,6 +1079,8 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { p_data->dscp_info.ssr_min_tout, len, p_data->dscp_info.descriptor.dsc_list); + btif_storage_set_hid_connection_policy(p_dev->link_spec.addrt.bda, true); + ASSERTC(ret == BT_STATUS_SUCCESS, "storing hid info failed", ret); log::warn("BTA_HH_GET_DSCP_EVT: Called add device"); @@ -1334,6 +1386,13 @@ static bt_status_t connect(RawAddress* bd_addr) { link_spec.addrt.type = BLE_ADDR_PUBLIC; link_spec.transport = BT_TRANSPORT_AUTO; + /* If the device was already added, ensure that reconnections are allowed */ + btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(*bd_addr); + if (added_dev != nullptr && !added_dev->reconnect_allowed) { + added_dev->reconnect_allowed = true; + btif_storage_set_hid_connection_policy(*bd_addr, true); + } + p_dev = btif_hh_find_connected_dev_by_bda(link_spec); if (p_dev) { if (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED || @@ -1361,7 +1420,7 @@ static bt_status_t connect(RawAddress* bd_addr) { * Returns bt_status_t * ******************************************************************************/ -static bt_status_t disconnect(RawAddress* bd_addr) { +static bt_status_t disconnect(RawAddress* bd_addr, bool reconnect_allowed) { CHECK_BTHH_INIT(); log::verbose("BTHH"); btif_hh_device_t* p_dev; @@ -1377,6 +1436,16 @@ static bt_status_t disconnect(RawAddress* bd_addr) { link_spec.addrt.type = BLE_ADDR_PUBLIC; link_spec.transport = BT_TRANSPORT_AUTO; + if (!reconnect_allowed) { + LOG_INFO("Incoming reconnections disabled for device %s", + ADDRESS_TO_LOGGABLE_CSTR(*bd_addr)); + btif_hh_added_device_t* added_dev = btif_hh_find_added_dev(*bd_addr); + if (added_dev != nullptr && added_dev->reconnect_allowed) { + added_dev->reconnect_allowed = false; + btif_storage_set_hid_connection_policy(added_dev->link_spec.addrt.bda, false); + } + } + p_dev = btif_hh_find_connected_dev_by_bda(link_spec); if (!p_dev) { log::error("Error, device {} not opened.", @@ -1541,9 +1610,10 @@ static bt_status_t set_info(RawAddress* bd_addr, bthh_hid_info_t hid_info) { link_spec.addrt.type = BLE_ADDR_PUBLIC; link_spec.transport = BT_TRANSPORT_AUTO; - if (btif_hh_add_added_dev(link_spec, hid_info.attr_mask)) { + if (btif_hh_add_added_dev(link_spec, hid_info.attr_mask, true)) { BTA_HhAddDev(link_spec, hid_info.attr_mask, hid_info.sub_class, hid_info.app_id, dscp_info); + btif_storage_set_hid_connection_policy(*bd_addr, true); } osi_free_and_reset((void**)&dscp_info.descriptor.dsc_list); diff --git a/system/btif/src/btif_profile_storage.cc b/system/btif/src/btif_profile_storage.cc index 2884fb15d0d31f9bbd0309a83e94741f6d3a8b95..2676c36afb2e6b71aa0f05e2850145597ef3e99c 100644 --- a/system/btif/src/btif_profile_storage.cc +++ b/system/btif/src/btif_profile_storage.cc @@ -80,6 +80,49 @@ using namespace bluetooth; STORAGE_HID_VERSION_SIZE + 1 + STORAGE_HID_CTRY_CODE_SIZE + 1 + \ STORAGE_HID_DESC_LEN_SIZE + 1 + STORAGE_HID_DESC_MAX_SIZE + 1) +/******************************************************************************* + * + * Function btif_storage_set_hid_connection_policy + * + * Description Stores connection policy info in nvram + * + * Returns BT_STATUS_SUCCESS + * + ******************************************************************************/ +bt_status_t btif_storage_set_hid_connection_policy(const RawAddress& addr, + bool reconnect_allowed) { + std::string bdstr = addr.ToString(); + + if (btif_config_set_int(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED, + reconnect_allowed)) { + return BT_STATUS_SUCCESS; + } else { + return BT_STATUS_FAIL; + } +} + +/******************************************************************************* + * + * Function btif_storage_get_hid_connection_policy + * + * Description get connection policy info from nvram + * + * Returns BT_STATUS_SUCCESS + * + ******************************************************************************/ +bt_status_t btif_storage_get_hid_connection_policy(const RawAddress& addr, + bool* reconnect_allowed) { + std::string bdstr = addr.ToString(); + + // For backward compatibility, assume that the reconnection is allowed in the + // absence of the key + int value = 1; + btif_config_get_int(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED, &value); + *reconnect_allowed = (value != 0); + + return BT_STATUS_SUCCESS; +} + /******************************************************************************* * * Function btif_storage_add_hid_device_info @@ -181,11 +224,14 @@ bt_status_t btif_storage_load_bonded_hid_info(void) { (uint8_t*)dscp_info.descriptor.dsc_list, &len); } + bool reconnect_allowed = false; + btif_storage_get_hid_connection_policy(bd_addr, &reconnect_allowed); + // add extracted information to BTA HH link_spec.addrt.bda = bd_addr; link_spec.addrt.type = BLE_ADDR_PUBLIC; link_spec.transport = BT_TRANSPORT_AUTO; - if (btif_hh_add_added_dev(link_spec, attr_mask)) { + if (btif_hh_add_added_dev(link_spec, attr_mask, reconnect_allowed)) { BTA_HhAddDev(link_spec, attr_mask, sub_class, app_id, dscp_info); } } @@ -217,6 +263,7 @@ bt_status_t btif_storage_remove_hid_info(const RawAddress& remote_bd_addr) { btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_SSR_MAX_LATENCY); btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_SSR_MIN_TIMEOUT); btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_DESCRIPTOR); + btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED); btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_REPORT); btif_config_remove(bdstr, BTIF_STORAGE_KEY_HID_REPORT_VERSION); return BT_STATUS_SUCCESS; diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs index 2e0cf877c40670809cc7040b59be7ccc686618ba..4b4eb4c70a085d3c57937316d57ebaba7ddd1b4c 100644 --- a/system/gd/rust/linux/stack/src/bluetooth.rs +++ b/system/gd/rust/linux/stack/src/bluetooth.rs @@ -2718,7 +2718,7 @@ impl IBluetooth for Bluetooth { if UuidHelper::is_profile_supported(&p) { match p { Profile::Hid | Profile::Hogp => { - self.hh.as_ref().unwrap().disconnect(&mut addr.unwrap()); + self.hh.as_ref().unwrap().disconnect(&mut addr.unwrap(), true); } Profile::A2dpSink @@ -2889,7 +2889,7 @@ impl BtifHHCallbacks for Bluetooth { "[{}]: Rejecting a unbonded device's attempt to connect to HID/HOG profiles", DisplayAddress(&address) ); - self.hh.as_ref().unwrap().disconnect(&mut address); + self.hh.as_ref().unwrap().disconnect(&mut address, true); } } diff --git a/system/gd/rust/topshim/src/profiles/hid_host.rs b/system/gd/rust/topshim/src/profiles/hid_host.rs index c77fa9b4754653351e2648e448bb3446f00ec8fa..d9d724b4cad78152083e336a5ce8a91d33af68a5 100644 --- a/system/gd/rust/topshim/src/profiles/hid_host.rs +++ b/system/gd/rust/topshim/src/profiles/hid_host.rs @@ -238,7 +238,7 @@ impl HidHost { #[profile_enabled_or(BtStatus::NotReady)] pub fn disconnect(&self, addr: &mut RawAddress) -> BtStatus { let addr_ptr = LTCheckedPtrMut::from_ref(addr); - BtStatus::from(ccall!(self, disconnect, addr_ptr.into())) + BtStatus::from(ccall!(self, disconnect, addr_ptr.into(), true)) } #[profile_enabled_or(BtStatus::NotReady)] diff --git a/system/gd/storage/config_keys.h b/system/gd/storage/config_keys.h index d5e19d8794a749c0358b103adaaee5fbc4794f04..827badbc4650cdfaf7473e7fad1046b8bdcb4127 100644 --- a/system/gd/storage/config_keys.h +++ b/system/gd/storage/config_keys.h @@ -58,6 +58,7 @@ #define BTIF_STORAGE_KEY_HID_DESCRIPTOR "HidDescriptor" #define BTIF_STORAGE_KEY_HID_DEVICE_CABLED "HidDeviceCabled" #define BTIF_STORAGE_KEY_HID_PRODUCT_ID "HidProductId" +#define BTIF_STORAGE_KEY_HID_RECONNECT_ALLOWED "HidReConnectAllowed" #define BTIF_STORAGE_KEY_HID_REPORT "HidReport" #define BTIF_STORAGE_KEY_HID_REPORT_VERSION "HidReportVersion" #define BTIF_STORAGE_KEY_HID_SSR_MAX_LATENCY "HidSSRMaxLatency" diff --git a/system/include/hardware/bt_hh.h b/system/include/hardware/bt_hh.h index c9ee0a95f1fbc2cd86bcc7d39ea6ecd610882a16..cc12e897411cabccced21df4988b935cdb7d6b0e 100644 --- a/system/include/hardware/bt_hh.h +++ b/system/include/hardware/bt_hh.h @@ -178,7 +178,7 @@ typedef struct { bt_status_t (*connect)(RawAddress* bd_addr); /** dis-connect from hid device */ - bt_status_t (*disconnect)(RawAddress* bd_addr); + bt_status_t (*disconnect)(RawAddress* bd_addr, bool reconnect_allowed); /** Virtual UnPlug (VUP) the specified HID device */ bt_status_t (*virtual_unplug)(RawAddress* bd_addr);