K.Gangster
K.Gangster

Reputation: 35

Ble GattServer DeadObject exception when bluetooth on/off

My gattServer advertise some data with paired bluetooth device and I run this gattServer with service.Everthing is well with Bluetooth state on but I turned off bluetooth and on again throw exception this line

 sGattServer.notifyCharacteristicChanged(device, getCharacteristic(Constants.NOTIFICATION_SOURCE), false);

This is my connection Method

  BluetoothAdapter bleAdapter = ((BluetoothManager) context.getSystemService(BLUETOOTH_SERVICE)).getAdapter();
    final Set<BluetoothDevice> pairedDevices = bleAdapter.getBondedDevices();
    for (BluetoothDevice d : pairedDevices) {

        d.connectGatt(context, true, new BluetoothGattCallback() {

            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onConnectionStateChange(BluetoothGatt
                                                        gatt, int status, int newState) {
                switch (newState) {
                    case BluetoothProfile.STATE_CONNECTED:


                        gatt.getServices();
                        break;
                    case BluetoothProfile.STATE_DISCONNECTED:


                        if (gatt !=null){
                            gatt.close();
                            gatt.disconnect();
                            gatt.connect();
                        }


                        break;
                }
            }
        });
    }

Stuck trace here:

10-23 10:04:53.978 27768-27768/E/BluetoothGattServer: android.os.DeadObjectException
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:496)
    at android.bluetooth.IBluetoothGatt$Stub$Proxy.sendNotification(IBluetoothGatt.java:1482)
    at android.bluetooth.BluetoothGattServer.notifyCharacteristicChanged(BluetoothGattServer.java:539)

Upvotes: 1

Views: 1167

Answers (1)

BitByteDog
BitByteDog

Reputation: 3504

When Bluetooth is turned off, Android restarts the Bluetooth stack to clean up its state. Kind of like cracking a walnut with a 40lb sledge hammer. See the Logcat

2019-08-02 11:56:29.274 10736-10736/? D/BluetoothAdapterService: onDestroy()
2019-08-02 11:56:29.281 10736-10736/? I/BluetoothAdapterService: Force exit to cleanup internal state in Bluetooth stack

In your GattServer Service you need to recreate the BluetoothGattServer object when the Bluetooth is powered back on.

You did not show the code from your service, which is where the problem lies, but you will need to do something like the following. Create a method createServerGattService which defines the service UUID and characteristics of you GATT server service, then registers it with the BLE stack. You already have this because you say the GATT server works fine until you turn the Bluetooth adapter off snd on.

Add a Bluetooth adapter power state receiver to your service:

    private BluetoothGattServer gattServer;

    private final BroadcastReceiver m_bluetoothAdapterPowerStateeceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();

            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                        BluetoothAdapter.ERROR);
                switch (state) {
                    case BluetoothAdapter.STATE_OFF:
                        gattServer = null;
                        break;
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        gattServer.close();
                        break;
                    case BluetoothAdapter.STATE_ON:
                        gattServer = createServerGattService();
                        break;
                    case BluetoothAdapter.STATE_TURNING_ON:
                        break;
                }
            }
        }
    };

In the onCreate() method of your service, register the receiver and instantiate your gatt server if the Bluetooth adapter is powered on:

    @Override
    public void onCreate() {
        super.onCreate();
        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
        registerReceiver(m_bluetoothAdapterPowerStateeceiver, filter);
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
            gattServer = createServerGattService();
        }
    }

In the onDestroy() method of your service, remove the receiver and close the GATT server connection:

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(m_bluetoothAdapterPowerStateeceiver);
        if(gattServer != null)
            gattServer.close();
    }

For completeness sake of the answer, the createServerGattService() should look something like this:

    private BluetoothGattServer createServerGattService() {
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        BluetoothGattServer server = null;
        if(bluetoothManager != null) {
           server = bluetoothManager.openGattServer(this, new BluetoothGattServerCallback() {
                @Override
                public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
                    super.onConnectionStateChange(device, status, newState);
                }

                @Override
                public void onServiceAdded(int status, BluetoothGattService service) {
                    super.onServiceAdded(status, service);
                }

                @Override
                public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
                    super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
                }

                @Override
                public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
                    super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
                }

                @Override
                public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
                    super.onDescriptorReadRequest(device, requestId, offset, descriptor);
                }

                @Override
                public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
                    super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
                }

                @Override
                public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
                    super.onExecuteWrite(device, requestId, execute);
                }

                @Override
                public void onNotificationSent(BluetoothDevice device, int status) {
                    super.onNotificationSent(device, status);
                }

                @Override
                public void onMtuChanged(BluetoothDevice device, int mtu) {
                    super.onMtuChanged(device, mtu);
                }

                @Override
                public void onPhyUpdate(BluetoothDevice device, int txPhy, int rxPhy, int status) {
                    super.onPhyUpdate(device, txPhy, rxPhy, status);
                }

                @Override
                public void onPhyRead(BluetoothDevice device, int txPhy, int rxPhy, int status) {
                    super.onPhyRead(device, txPhy, rxPhy, status);
                }
            });
            BluetoothGattService service = new BluetoothGattService(serviceUuid, BluetoothGattService.SERVICE_TYPE_PRIMARY);
            BluetoothGattCharacteristic characteristic1 = new BluetoothGattCharacteristic(
                    characteristic1Uuid,
                    BluetoothGattCharacteristic.PROPERTY_READ,
                    BluetoothGattCharacteristic.PERMISSION_READ);
            service.addCharacteristic(characteristic1);
            server.addService(service);
        }
        return server;
    }

Upvotes: 1

Related Questions