Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
788 views
in Technique[技术] by (71.8m points)

android - How could I achieve maximum thread safety with a read/write BLE Gatt Characteristic?

I am communicating with a BLE device that sends me lots of data via one characteristic. The same Characteristic is used to send data to the device.

Inside Androids BluetoothGattCharacteristic there are the methods

public byte[] getValue() {
    return mValue;
}

public boolean setValue(byte[] value) {
    mValue = value;
    return true;
}

However, the execution happens from different threads. Android runs about 5 different binder-threads and they call

onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)

I now try to grab the array as first operation in the callback, but it is NOT guaranteed that another thread (not under my control) is setting the array at the same time.

While above seems to do the trick, a more complicated matter is sending data 'against an incoming stream of data'.

I have to use the same Characteristic to send data down to the device, so I setValue() and then BluetoothGatt.writeCharacteristic.

public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
// some null checks etc

//now it locks the device
synchronized(mDeviceBusy) {
    if (mDeviceBusy) return false;
    mDeviceBusy = true;
}

//the actual execution

return true;
}

I will then at some point receive a callback from some thread

onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) 

However, when I grab the value and try to check if it is what I wanted to send, sometimes it already is a received package that has just been updated from some other thread.

How could i make this more thread-safe without having access to Androids BLE API or the stack etc ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In SDK27, the onNotify() callback function in BluetoothGatt.java was updated to call BOTH BluetoothGattCharacteristic.setValue() and BluetoothGattCallback.onCharacteristicChanged() in the Runnable's run().

This change allows us to force all calls to BluetoothGattCharacteristic.setValue() - both for our outbound writing to the characteristic and the inbound notifications - onto the same thread, which eliminates the race condition corrupting the BluetoothGattCharacteristic.mValue;

  1. Create a HandlerThread
  2. Create a Handler attached to your HandlerThread
  3. Pass your Handler into BluetoothDevice.connectGatt() - congratulations, when a notify is received the setValue() and onCharacteristicChanged() will be called on your HandlerThread.
  4. When you want to write to the characteristic, post your setValue() and writeCharacteristic() to your HandlerThread via your Handler

Now all the function calls that were involved in the race condition are being executed on the same thread, eliminating the race condition.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...