Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 289d9ed8 authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Jakub Pawłowski
Browse files

Bluetooth key missing handling for LE transport

When we connect to peripheral we were bonded with, and it claims it is
missing keys, user must go to settings, and forget this peripheral
before bonding with it again.

Some users donn't know what they should do, or they just observe their
device stopped working and don't get any hint what to do.

After this aptch, Bluetooth stack will send a Broadcast that can be
handled by Settings or Fast Pair, and acted upon properly.

Test: Bond with device, remove bond just from peripheral, try to reconnect, observe dialog
Bug: 297598060
Bug: 311447399
Change-Id: I5ddde4da2c66280a9408fad2f960ffc352f82ee3
parent 3281f205
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ static jmethodID method_switchCodecCallback;
static jmethodID method_acquireWakeLock;
static jmethodID method_releaseWakeLock;
static jmethodID method_energyInfo;
static jmethodID method_keyMissingCallback;

static struct {
  jclass clazz;
@@ -752,6 +753,29 @@ static void le_rand_callback(uint64_t /* random */) {
  // Android doesn't support the LeRand API.
}

static void key_missing_callback(RawAddress bd_addr) {
  std::shared_lock<std::shared_timed_mutex> lock(jniObjMutex);
  if (!sJniCallbacksObj) {
    ALOGE("%s, JNI obj is null. Failed to call JNI callback", __func__);
    return;
  }

  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  ScopedLocalRef<jbyteArray> addr(
      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
  if (!addr.get()) {
    ALOGE("Address allocation failed in %s", __func__);
    return;
  }
  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                   (jbyte*)&bd_addr);

  sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_keyMissingCallback,
                               addr.get());
}

static void callback_thread_event(bt_cb_thread_evt event) {
  if (event == ASSOCIATE_JVM) {
    JavaVMAttachArgs args;
@@ -838,7 +862,8 @@ static bt_callbacks_t sBluetoothCallbacks = {sizeof(sBluetoothCallbacks),
                                             generate_local_oob_data_callback,
                                             switch_buffer_size_callback,
                                             switch_codec_callback,
                                             le_rand_callback};
                                             le_rand_callback,
                                             key_missing_callback};

class JNIThreadAttacher {
 public:
@@ -2207,6 +2232,7 @@ int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
      {"releaseWakeLock", "(Ljava/lang/String;)Z", &method_releaseWakeLock},
      {"energyInfoCallback", "(IIJJJJ[Landroid/bluetooth/UidTraffic;)V",
       &method_energyInfo},
      {"keyMissingCallback", "([B)V", &method_keyMissingCallback},
  };
  GET_JAVA_METHODS(env, "com/android/bluetooth/btservice/JniCallbacks",
                   javaMethods);
+4 −0
Original line number Diff line number Diff line
@@ -82,6 +82,10 @@ class JniCallbacks {
                transportLinkType, hciReason, handle);
    }

    void keyMissingCallback(byte[] address) {
        mRemoteDevices.keyMissingCallback(address);
    }

    void stateChangeCallback(int status) {
        mAdapterService.stateChangeCallback(status);
    }
+31 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.bluetooth.btservice;

import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import static android.Manifest.permission.BLUETOOTH_SCAN;

import android.annotation.RequiresPermission;
@@ -46,6 +47,7 @@ import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.R;
import com.android.bluetooth.Utils;
import com.android.bluetooth.bas.BatteryService;
import com.android.bluetooth.flags.FeatureFlagsImpl;
import com.android.bluetooth.hfp.HeadsetHalConstants;
import com.android.internal.annotations.VisibleForTesting;

@@ -68,6 +70,7 @@ public class RemoteDevices {

    private BluetoothAdapter mAdapter;
    private AdapterService mAdapterService;
    private FeatureFlagsImpl mFeatureFlags;
    private ArrayList<BluetoothDevice> mSdpTracker;
    private final Object mObject = new Object();

@@ -152,6 +155,7 @@ public class RemoteDevices {
    RemoteDevices(AdapterService service, Looper looper) {
        mAdapter = ((Context) service).getSystemService(BluetoothManager.class).getAdapter();
        mAdapterService = service;
        mFeatureFlags = new FeatureFlagsImpl();
        mSdpTracker = new ArrayList<BluetoothDevice>();
        mDevices = new HashMap<String, DeviceProperties>();
        mDualDevicesMap = new HashMap<String, String>();
@@ -1238,6 +1242,33 @@ public class RemoteDevices {
        }
    }

    void keyMissingCallback(byte[] address) {
        BluetoothDevice bluetoothDevice = getDevice(address);
        if (bluetoothDevice == null) {
            errorLog(
                    "keyMissingCallback: device is NULL, address="
                            + Utils.getRedactedAddressStringFromByte(address));
            return;
        }
        Log.d(TAG, "keyMissingCallback device: " + bluetoothDevice);

        if (bluetoothDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
            if (!mFeatureFlags.keyMissingBroadcast()) {
                Log.d(TAG, "flag not set - don't send key missing broadcast");
                return;
            }
            Intent intent =
                    new Intent(BluetoothDevice.ACTION_KEY_MISSING)
                            .putExtra(BluetoothDevice.EXTRA_DEVICE, bluetoothDevice)
                            .addFlags(
                                    Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                                            | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            mAdapterService.sendBroadcastMultiplePermissions(
                    intent,
                    new String[] {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
                    Utils.getTempBroadcastOptions());
        }
    }

    void fetchUuids(BluetoothDevice device, int transport) {
        if (mSdpTracker.contains(device)) {
+8 −0
Original line number Diff line number Diff line
@@ -119,6 +119,14 @@ void bta_dm_sec_enable(tBTA_DM_SEC_CBACK* p_sec_cback) {
  btm_local_io_caps = btif_storage_get_local_io_caps();
}

void bta_dm_remote_key_missing(RawAddress bd_addr) {
  if (bta_dm_sec_cb.p_sec_cback) {
    tBTA_DM_SEC sec_event;
    sec_event.key_missing.bd_addr = bd_addr;
    bta_dm_sec_cb.p_sec_cback(BTA_DM_KEY_MISSING_EVT, &sec_event);
  }
}

/*******************************************************************************
 *
 * Function         bta_dm_add_device
+3 −0
Original line number Diff line number Diff line
@@ -58,3 +58,6 @@ typedef struct {
  RawAddress id_addr;
} tBTA_DM_PROC_ID_ADDR;

typedef struct {
  RawAddress bd_addr;
} tBTA_DM_KEY_MISSING;
Loading