From 11b41d8123241ba8e693e21c4db308bacff23f57 Mon Sep 17 00:00:00 2001 From: Mudumba Ananth Date: Tue, 29 Jul 2014 06:19:43 -0700 Subject: [PATCH] Pairing failed after 50 attempts -> The issue was caused due to delayed message sent for bond_state_changed_callback in BondStateMachine and RemoteDevices was sending the pairing request(sspRequestcallback) intent to the Settings APP before even the bond state is changed. -> Moved the SSPRequestCallback and PinRequestCallback to BondStateMachine to synchronize the above two callbacks using a single message queue in the BondStateMachine message handler. -> Changed the pending command state to accept the SSP_REQUEST and PIN_REQUEST messages and send the intents. Bug: 16560957 Change-Id: I8372bdd2e96aa09215f2f1e98d6eed4e892637e6 --- .../bluetooth/btservice/BondStateMachine.java | 125 ++++++++++++++++++++- .../android/bluetooth/btservice/JniCallbacks.java | 4 +- .../android/bluetooth/btservice/RemoteDevices.java | 89 +-------------- 3 files changed, 122 insertions(+), 96 deletions(-) diff --git a/src/com/android/bluetooth/btservice/BondStateMachine.java b/src/com/android/bluetooth/btservice/BondStateMachine.java index 8d305772..f67c301a 100644 --- a/src/com/android/bluetooth/btservice/BondStateMachine.java +++ b/src/com/android/bluetooth/btservice/BondStateMachine.java @@ -17,6 +17,7 @@ package com.android.bluetooth.btservice; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothDevice; import com.android.bluetooth.a2dp.A2dpService; @@ -51,7 +52,8 @@ final class BondStateMachine extends StateMachine { static final int CANCEL_BOND = 2; static final int REMOVE_BOND = 3; static final int BONDING_STATE_CHANGE = 4; - + static final int SSP_REQUEST = 5; + static final int PIN_REQUEST = 6; static final int BOND_STATE_NONE = 0; static final int BOND_STATE_BONDING = 1; static final int BOND_STATE_BONDED = 2; @@ -151,12 +153,16 @@ final class BondStateMachine extends StateMachine { public boolean processMessage(Message msg) { BluetoothDevice dev = (BluetoothDevice)msg.obj; + DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev); boolean result = false; - if (mDevices.contains(dev) && - msg.what != CANCEL_BOND && msg.what != BONDING_STATE_CHANGE) { - deferMessage(msg); - return true; - } + if (mDevices.contains(dev) && msg.what != CANCEL_BOND && + msg.what != BONDING_STATE_CHANGE && msg.what != SSP_REQUEST && + msg.what != PIN_REQUEST) { + deferMessage(msg); + return true; + } + + Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); switch (msg.what) { case CREATE_BOND: @@ -201,6 +207,34 @@ final class BondStateMachine extends StateMachine { else if(!mDevices.contains(dev)) result=true; break; + case SSP_REQUEST: + int passkey = msg.arg1; + int variant = msg.arg2; + sendDisplayPinIntent(devProp.getAddress(), passkey, variant); + break; + case PIN_REQUEST: + BluetoothClass btClass = dev.getBluetoothClass(); + int btDeviceClass = btClass.getDeviceClass(); + if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD || + btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { + // Its a keyboard. Follow the HID spec recommendation of creating the + // passkey and displaying it to the user. If the keyboard doesn't follow + // the spec recommendation, check if the keyboard has a fixed PIN zero + // and pair. + //TODO: Maintain list of devices that have fixed pin + // Generate a variable 6-digit PIN in range of 100000-999999 + // This is not truly random but good enough. + int pin = 100000 + (int)Math.floor((Math.random() * (999999 - 100000))); + sendDisplayPinIntent(devProp.getAddress(), pin, + BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN); + break; + } + //In PIN_REQUEST, there is no passkey to display.So do not send the + //EXTRA_PAIRING_KEY type in the intent( 0 in SendDisplayPinIntent() ) + sendDisplayPinIntent(devProp.getAddress(), 0, + BluetoothDevice.PAIRING_VARIANT_PIN); + + break; default: Log.e(TAG, "Received unhandled event:" + msg.what); return false; @@ -253,6 +287,16 @@ final class BondStateMachine extends StateMachine { return false; } + private void sendDisplayPinIntent(byte[] address, int pin, int variant) { + Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevices.getDevice(address)); + if (pin != 0) { + intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin); + } + intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant); + mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); + } + private void sendIntent(BluetoothDevice device, int newState, int reason) { DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device); int oldState = BluetoothDevice.BOND_NONE; @@ -301,6 +345,71 @@ final class BondStateMachine extends StateMachine { sendMessage(msg); } + void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, + int passkey) { + //TODO(BT): Get wakelock and update name and cod + BluetoothDevice bdDevice = mRemoteDevices.getDevice(address); + if (bdDevice == null) { + mRemoteDevices.addDeviceProperties(address); + } + infoLog("sspRequestCallback: " + address + " name: " + name + " cod: " + + cod + " pairingVariant " + pairingVariant + " passkey: " + passkey); + int variant; + boolean displayPasskey = false; + switch(pairingVariant) { + + case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION : + variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; + displayPasskey = true; + break; + + case AbstractionLayer.BT_SSP_VARIANT_CONSENT : + variant = BluetoothDevice.PAIRING_VARIANT_CONSENT; + break; + + case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY : + variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY; + break; + + case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION : + variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY; + displayPasskey = true; + break; + + default: + errorLog("SSP Pairing variant not present"); + return; + } + BluetoothDevice device = mRemoteDevices.getDevice(address); + if (device == null) { + warnLog("Device is not known for:" + Utils.getAddressStringFromByte(address)); + mRemoteDevices.addDeviceProperties(address); + device = mRemoteDevices.getDevice(address); + } + + Message msg = obtainMessage(SSP_REQUEST); + msg.obj = device; + if(displayPasskey) + msg.arg1 = passkey; + msg.arg2 = variant; + sendMessage(msg); + } + + void pinRequestCallback(byte[] address, byte[] name, int cod) { + //TODO(BT): Get wakelock and update name and cod + BluetoothDevice bdDevice = mRemoteDevices.getDevice(address); + if (bdDevice == null) { + mRemoteDevices.addDeviceProperties(address); + } + infoLog("pinRequestCallback: " + address + " name:" + name + " cod:" + + cod); + + Message msg = obtainMessage(PIN_REQUEST); + msg.obj = bdDevice; + + sendMessage(msg); + } + private void setProfilePriorty (BluetoothDevice device){ HidService hidService = HidService.getHidService(); A2dpService a2dpService = A2dpService.getA2dpService(); @@ -343,6 +452,10 @@ final class BondStateMachine extends StateMachine { Log.e(TAG, msg); } + private void warnLog(String msg) { + Log.w(TAG, msg); + } + private int getUnbondReasonFromHALCode (int reason) { if (reason == AbstractionLayer.BT_STATUS_SUCCESS) return BluetoothDevice.BOND_SUCCESS; diff --git a/src/com/android/bluetooth/btservice/JniCallbacks.java b/src/com/android/bluetooth/btservice/JniCallbacks.java index bf922af6..d6eab6c7 100644 --- a/src/com/android/bluetooth/btservice/JniCallbacks.java +++ b/src/com/android/bluetooth/btservice/JniCallbacks.java @@ -47,7 +47,7 @@ final class JniCallbacks { void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, int passkey) { - mRemoteDevices.sspRequestCallback(address, name, cod, pairingVariant, + mBondStateMachine.sspRequestCallback(address, name, cod, pairingVariant, passkey); } void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] val) { @@ -59,7 +59,7 @@ final class JniCallbacks { } void pinRequestCallback(byte[] address, byte[] name, int cod) { - mRemoteDevices.pinRequestCallback(address, name, cod); + mBondStateMachine.pinRequestCallback(address, name, cod); } void bondStateChangeCallback(int status, byte[] address, int newState) { diff --git a/src/com/android/bluetooth/btservice/RemoteDevices.java b/src/com/android/bluetooth/btservice/RemoteDevices.java index ce39922d..4f182789 100644 --- a/src/com/android/bluetooth/btservice/RemoteDevices.java +++ b/src/com/android/bluetooth/btservice/RemoteDevices.java @@ -234,6 +234,7 @@ final class RemoteDevices { mSdpTracker.remove(device); } + private void sendMasInstanceIntent(BluetoothDevice device, ArrayList instances) { Intent intent = new Intent(BluetoothDevice.ACTION_MAS_INSTANCE); @@ -245,17 +246,6 @@ final class RemoteDevices { //Remove the outstanding UUID request mSdpMasTracker.remove(device); } - - private void sendDisplayPinIntent(byte[] address, int pin) { - Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address)); - intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin); - intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, - BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); - } - void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) { Intent intent; byte[] val; @@ -349,83 +339,6 @@ final class RemoteDevices { mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); } - void pinRequestCallback(byte[] address, byte[] name, int cod) { - //TODO(BT): Get wakelock and update name and cod - BluetoothDevice bdDevice = getDevice(address); - if (bdDevice == null) { - addDeviceProperties(address); - } - BluetoothClass btClass = bdDevice.getBluetoothClass(); - int btDeviceClass = btClass.getDeviceClass(); - if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD || - btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { - // Its a keyboard. Follow the HID spec recommendation of creating the - // passkey and displaying it to the user. If the keyboard doesn't follow - // the spec recommendation, check if the keyboard has a fixed PIN zero - // and pair. - //TODO: Add sFixedPinZerosAutoPairKeyboard() and maintain list of devices that have fixed pin - /*if (mAdapterService.isFixedPinZerosAutoPairKeyboard(address)) { - mAdapterService.setPin(address, BluetoothDevice.convertPinToBytes("0000")); - return; - }*/ - // Generate a variable PIN. This is not truly random but good enough. - int pin = (int) Math.floor(Math.random() * 1000000); - sendDisplayPinIntent(address, pin); - return; - } - infoLog("pinRequestCallback: " + address + " name:" + name + " cod:" + - cod); - Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address)); - intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, - BluetoothDevice.PAIRING_VARIANT_PIN); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); - return; - } - - void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, - int passkey) { - //TODO(BT): Get wakelock and update name and cod - BluetoothDevice bdDevice = getDevice(address); - if (bdDevice == null) { - addDeviceProperties(address); - } - - infoLog("sspRequestCallback: " + address + " name: " + name + " cod: " + - cod + " pairingVariant " + pairingVariant + " passkey: " + passkey); - int variant; - boolean displayPasskey = false; - if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION) { - variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; - displayPasskey = true; - } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_CONSENT) { - variant = BluetoothDevice.PAIRING_VARIANT_CONSENT; - } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY) { - variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY; - } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION) { - variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY; - displayPasskey = true; - } else { - errorLog("SSP Pairing variant not present"); - return; - } - BluetoothDevice device = getDevice(address); - if (device == null) { - warnLog("Device is not known for:" + Utils.getAddressStringFromByte(address)); - addDeviceProperties(address); - device = getDevice(address); - } - Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); - intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); - if (displayPasskey) { - intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey); - } - intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); - } - void aclStateChangeCallback(int status, byte[] address, int newState) { BluetoothDevice device = getDevice(address); -- 2.11.0