Bluetooth: log bond loss on API 36.1 / Android 16 QPR2

This commit is contained in:
Thomas Kuehne
2025-10-01 21:31:26 +02:00
committed by José Rebelo
parent bf7094d616
commit a7d9088cc6
3 changed files with 73 additions and 0 deletions
@@ -0,0 +1,56 @@
/* Copyright (C) 2025 Thomas Kuehne
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Parcelable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BleNamesResolver;
/// Log why a previously bonded device couldn't provide keys to establish encryption
/// on API 36.1 and higher. On lower API levels this broadcast usually requires
/// Manifest.permission.BLUETOOTH_PRIVILEGED to receive.
public class KeyMissingReceiver extends BroadcastReceiver {
private static final Logger LOG = LoggerFactory.getLogger(KeyMissingReceiver.class);
public static final String ACTION_KEY_MISSING = "android.bluetooth.device.action.KEY_MISSING";
public static final String EXTRA_BOND_LOSS_REASON = "android.bluetooth.device.extra.BOND_LOSS_REASON";
@Override
public void onReceive(Context context, Intent intent) {
if (context == null){
LOG.warn("context is null");
}else if (intent == null){
LOG.warn("intent is null");
} else if (ACTION_KEY_MISSING.equals(intent.getAction())) {
Parcelable device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int reason = intent.getIntExtra(EXTRA_BOND_LOSS_REASON, -1);
LOG.error("Bluetooth bond failed: KEY_MISSING {} {}",
BleNamesResolver.getBondLossReasonString(reason),
device);
} else {
LOG.warn("received unexpected broadcast action '{}'", intent.getAction());
}
}
}
@@ -78,6 +78,7 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.DeviceSettingsReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.GenericWeatherReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.IntentApiReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.KeyMissingReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.LineageOsWeatherReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.OmniJawsObserver;
@@ -260,6 +261,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
private MusicPlaybackReceiver mMusicPlaybackReceiver = null;
private TimeChangeReceiver mTimeChangeReceiver = null;
private BluetoothConnectReceiver mBlueToothConnectReceiver = null;
private KeyMissingReceiver mKeyMissingReceiver = null;
private BluetoothPairingRequestReceiver mBlueToothPairingRequestReceiver = null;
private AlarmClockReceiver mAlarmClockReceiver = null;
private SilentModeReceiver mSilentModeReceiver = null;
@@ -536,6 +538,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
ContextCompat.registerReceiver(this, deviceSettingsReceiver, deviceSettingsIntentFilter, ContextCompat.RECEIVER_EXPORTED);
ContextCompat.registerReceiver(this, intentApiReceiver, intentApiReceiver.buildFilter(), ContextCompat.RECEIVER_EXPORTED);
mKeyMissingReceiver = new KeyMissingReceiver();
ContextCompat.registerReceiver(this, mKeyMissingReceiver, new IntentFilter(KeyMissingReceiver.ACTION_KEY_MISSING), ContextCompat.RECEIVER_EXPORTED);
}
@Override
@@ -375,6 +375,18 @@ public class BleNamesResolver {
};
}
/// lookup description for numeric bond loss reasons (introduced in API 36.1)
public static String getBondLossReasonString(int reason){
return switch (reason) {
case 0 -> "BOND_LOSS_REASON_UNKNOWN";
case 1 -> "BOND_LOSS_REASON_BREDR_AUTH_FAILURE";
case 2 -> "BOND_LOSS_REASON_BREDR_INCOMING_PAIRING";
case 3 -> "BOND_LOSS_REASON_LE_ENCRYPT_FAILURE";
case 4 -> "BOND_LOSS_REASON_LE_INCOMING_PAIRING";
default -> "reason_" + reason;
};
}
static public String getCharacteristicPropertyString(int property) {
StringBuilder builder = new StringBuilder();
if (BluetoothGattCharacteristic.PROPERTY_BROADCAST == (BluetoothGattCharacteristic.PROPERTY_BROADCAST & property)) {