Приложение, использующее профиль Bluetooth SPP, не работает после обновления с Android 4.2 до Android 4.3
Я написал простое приложение на основе bluetoothChat. Я общаюсь между телефоном и модулем Bluetooth, используя профиль SPP. Телефон всегда инициирует связь. Приложение прекрасно работало на Android 4.2 с использованием Nexus 3 и Samsung Galaxy 3. После обновления до Android 4.3 приложение больше не работает. Я подключаюсь все время, могу отправлять outpustream и получать нужные данные, но после 1-й команды outputtream приложение всегда отключается примерно через 6 секунд. Как показано в logcat ниже, похоже, что существует проблема таймера на входном потоке.
08-23 14:10:00.726: D/mems(23193): STEVAL-MKI106V1
08-23 14:10:00.804: D/Main Activity(23193): firmware version*setdb106V1
08-23 14:10:00.812: D/Main Activity(23193): sent message*setdb106V1
08-23 14:10:00.812: D/BluetoothMEMSCommunication(23193): dans write3
08-23 14:10:00.812: D/BluetoothMEMSCommunication(23193): envoi stream
08-23 14:10:05.812: W/bt-btif(20368): dm_pm_timer expires
08-23 14:10:05.812: W/bt-btif(20368): dm_pm_timer expires 0
08-23 14:10:05.812: W/bt-btif(20368): proc dm_pm_timer expires
08-23 14:10:11.656: E/bt-btm(20368): btm_sec_disconnected - Clearing Pending flag
08-23 14:10:11.656: W/bt-btif(20368): invalid rfc slot id: 15
08-23 14:10:11.656: I/connection(23193): connectionlost
Что такое dm_pm_timer? Я пытался подключиться по-другому, с безопасным и небезопасным rfcom. Я знаю, что блютуз-чат не оптимизирован для приема буфера, поэтому я изменил его, но никакого эффекта. Я также использовал команду flush для outpustream, но и без эффекта.
package com.meneujj.memsbtbis;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
public class BluetoothMEMSCommunication {
// debugging
private static final String TAG = "BluetoothMEMSCommunication";
private static final boolean D = true;
// eMotion BT h as this standard UUID
private static final UUID STANDARD_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private int mState;
private int handlerCalling;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
// Constants they indicate the current connection state
public static final int STATE_NONE = 0;
public static final int STATE_CONNECTED = 3; // now connected to a remote device
// constructor. Prepares a new Bluetooth Connection
// context The UI Activity Context
// handler an Handler to send messages back to the UI Activity
public BluetoothMEMSCommunication(Context context, Handler handler, int i) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
handlerCalling = i;
}
private synchronized void setState(int state) {
mState = state;
Log.d(TAG, Integer.toString(mState));
mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized void connect(BluetoothDevice device) {
// start the thread to connect with the given device
if (mConnectThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
Log.d(TAG,"routine connect lancee");
mConnectThread = new ConnectThread(device);
mConnectThread.start();
}
private void ConnectionLost() {
// Send a failure message back to the activity
Message msg = mHandler.obtainMessage(MainActivityMemsBT.CONNECTION_LOST_MESSAGE);
Bundle bundle = new Bundle();
bundle.putString(MainActivityMemsBT.TOAST_CONNECTION_LOST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
Log.i("connection","connectionlost");
setState(STATE_NONE);
StopAllThreads();
}
public synchronized void StopAllThreads() {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_NONE);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device, final String socketType) {
// cancel the thread they completed the connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to manage the connection and perform transmission
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
// Send the name of the connected device back to the UI activity
Message msg = mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(MainActivityMemsBT.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public void write(byte[] out) {
// create temporary object
ConnectedThread r;
Log.d(TAG,"dans write" + Integer.toString(mState));
// synchronize a copy of the ConnectedThread
synchronized (this) {
if (handlerCalling == 2) setState(STATE_CONNECTED);
if (mState != STATE_CONNECTED) {
Log.d(TAG, "different de STATE_CONNECTED");
Log.i(TAG, Integer.toString(handlerCalling));
return;}
r= mConnectedThread;
}
r.write(out);
}
Любая идея, есть ли обходной путь? Или любая очевидная ошибка в моем коде
Спасибо
// Thread runs while attempting to an an outgoing connection with a device.
// it runs straight through; the connection either succeeds or fails.
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(STANDARD_UUID);
//tmp = device.createInsecureRfcommSocketToServiceRecord(STANDARD_UUID);
/* try {
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
try {
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} */
} catch (IOException e) {
}
mmSocket = tmp;
}
public void run () {
setName("ConnectThread" + mSocketType);
mAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() " + mSocketType + "socket during connection failure", e2);
}
return;
}
// reset the CoonectThread because the job is over
synchronized (BluetoothMEMSCommunication.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
// close connectThread class
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
ConnectionLost();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
// Thread to listen to input sockets
public void run() {
Log.i(TAG, "Begin mConnectedThread");
byte[] buffer = new byte[1024];
// int bytes;
int bytesRead = -1;
String message = "";
// keep listening to the InputStream while connected
while(true) {
try {
// read from the input stream
// bytesRead = mmInStream.read(buffer);
// message = message+ new String(buffer, 0, bytesRead);
// byte[] byteString = message.getBytes();
Log.i("info","pret a faire read");
bytesRead = mmInStream.read(buffer, 0, 1024);
if (bytesRead != -1 && handlerCalling == 1) {
mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_READ, bytesRead, -1, buffer).sendToTarget(); }
if (bytesRead !=-1 && handlerCalling == 2) {
mHandler.obtainMessage(DemoAccelerometer.MESSAGE_READ, bytesRead, -1, buffer).sendToTarget(); }
}
catch (IOException e) {
ConnectionLost();
break;
}
}
}
public void write(byte[] buffer) {
try{
mmOutStream.write(buffer);
// if (handlerCalling == 1) {
// mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
Log.d(TAG,"envoi stream");
// mmOutStream.flush();
// }
} catch (IOException e) {
}
}
public void cancel() {
try{
mmSocket.close();
} catch (IOException e) {
}
}
}
}
3 ответа
Мы можем подтвердить отключение Bluetooth через 6 секунд при обмене данными из нашего приложения Nexus 4 с внешней ЭКГ по Bluetooth (медицинское устройство) после обновления с Android 4.2 до 4.3. Это происходит конкретно во время измерения ЭКГ с большим количеством входящих данных (от ЭКГ до приложения Android), но без исходящих данных. "Нормальная" связь Bluetooth с некоторыми входящими и исходящими данными время от времени, по-видимому, не затрагивается.
Через 6 секунд мы видим те же сообщения журнала adb, о которых сообщает JJM
dm_pm_timer expires
dm_pm_timer expires 0
proc dm_pm_timer expires
btm_sec_disconnected - Clearing Pending flag
Это истечение времени таймера на стороне Android вызывает что-то (закрытие выходного потока, потому что нет исходящих данных?) На внешней Bluetooth-ЭКГ, которая, в свою очередь, отправляет специфическую для ЭКГ команду, которую мы получаем на входном потоке, который мы никогда не получим на Nexus 4 с Android 4.2.
Изменение реализации приложения Android для периодической отправки произвольной команды "сохранить в живых" в ЭКГ решает проблему. Время истечения таймера больше не отображается в логах adb, и измерение ЭКГ теперь ведет себя так же, как в Android 4.2.
Спасибо JJM за подсказки.
Я нашел работу вокруг. Он отключается, если в течение нескольких секунд нет потоковой активности. Мне удалось получить поток вывода или ввода несколько раз в секунду, и теперь он никогда не отключается.
Я нашел в Stackru ответ, который помог мне решить проблему. Я думаю, это как-то связано с тем, что inputStream и outputStream не закрываются должным образом и не обнуляются, а также с разъемом Bluetooth. После использования этой функции:
* Reset input and output streams and make sure socket is closed.
* This method will be used during shutdown() to ensure that the connection is properly closed during a shutdown.
* @return
*/
private void resetConnection() {
setState(STATE_NONE);
Log.d(TAG, "reset connection");
if (mmInStream != null) {
try {
mmInStream.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing inputstream - " + e.getMessage());
}
mmInStream = null;
}
if (mmOutStream != null) {
try {
mmOutStream.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing outputstream - " + e.getMessage());
}
mmOutStream = null;
}
if (mmSocket != null) {
try {
mmSocket.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing socket - " + e.getMessage());
}
mmSocket = null;
}
}
в ConnectedThread и вызывать его при необходимости я убрал эту проблему. Это также может быть проблемой при чтении из inputStream, возможно, потому что там не было ничего при попытке чтения.
Я предлагаю вам выполнить логическую функцию readWrite(), чтобы при записи в outputStream вы также читали inputStream и отправляли readBuffer в пользовательский интерфейс с помощью mHandler. Если и чтение и запись в порядке, тогда верните true, если один из них пошёл не так, верните false и используйте resetConection перед закрытием ConnectedThread.
Это сработало очень хорошо для меня.
ОБНОВЛЕНИЕ: (30-СЕНТЯБРЯ-2013) Я запускаю свое приложение и все еще получаю hci_status = 36 через несколько минут. У меня есть приложение, которое подключается к внешнему устройству Bluetooth. Я отправляю данные и получаю данные ок. 3 раза / сек Я использую Thread.sleep(300) между записями. В моих тестах я получал эту ошибку от нескольких минут до почти 30 минут при запуске приложения.
Любые отзывы приветствуются!