I have a project that connects to a device over Bluetooth. It used to work fairly reliably, but now it fails the BluetoothSocket.connect() call every time. (Well, I got it to connect once during the thousands of attempts over a 4 hour period.) Most of the code has been taken from the standard sample chat code in the API, with the exception of the common modification in getting the BluetoothSocket device itself:
Method m = device.getClass().getMethod(
"createRfcommSocket", new Class[] { int.class });
tmp = (BluetoothSocket) m.invoke(device, Integer.valueOf(1));
Here's the method of interest, which gets run once a BluetoothSocket is obtained:
public void run() {
setName("ConnectThread" + mSocketType);
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
mmSocket.connect();
} catch (Exception e) {
Log.e(TAG, "Connection to " + mmDevice.getName() + " at "
+ mmDevice.getAddress() + " failed:" + e.getMessage());
// Close the socket
try {
mmSocket.close();
} catch (Exception e2) {
Log.e(TAG, "unable to close() " + mSocketType
+ " socket during connection failure", e2);
}
connectionFailed(e.getMessage());
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothChatService.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice, mSocketType);
}
The relevant log entry (printed when the exception is caught while calling connect()) is this:
11-30 10:23:51.685: E/BluetoothChatService(2870): Connection to
ZYNO-700091 at 00:06:66:42:8E:01 failed:read failed, socket might
closed, read ret: -1
This error used to come up once in a while. I have an aggressive reconnect system - it basically hammers the connection over and over until it connects, and if it were ever to disconnect, it starts hammering it again. So, it kills the connection thread and starts from scratch constantly. I had considered that there might be an issue there - maybe a multithreading one, or maybe in handling the socket cleanup/initialization. However, if that were the case, I'd still expect the first connection attempt to succeed, since that system doesn't kick in until there's a failed connection attempt.
I looked into the source code throwing the exception. The issue seems to be that the underlying InputStream has no data. Of course, that's not really an answer, just a step towards it. Why would the stream have no data?
I'm trying to keep an open mind about the potential issue. Am I getting the BluetoothSocket properly? The fact that it was once an intermittent issue and is now nearly constant makes me suspect multithreading, but that's a relatively simple topic in Java compared to C++ - hard to screw up if you know what you're doing. Plus, the majority of this code (in particular, the parts dealing with synchronizing the threads) is straight out of the sample code.
The device on the other end is an embedded Bluetooth device, so there's not much hope of debugging the problem from that end.
UPDATE ===========================
It occurred to me that it might be due to an OS upgrade (I'm running on Galaxy Nexus phones - I have several to test with). So I unpacked a new phone with 4.0.4 and it worked! So then went back and tested on the two original test phones, both running 4.2, expecting the failure I've been seeing all this time. Strangely, now it works on those phones too. I'd like to say I did something to make this work again, but I didn't. I'm still mystified, and now also suspicious that this thing is going to work when I really need it to.
I wonder if there's a possibility that somehow connecting using 4.0.4 could have properly set the state of the server module, making it receptive to the 4.2 devices? Just a shot in the dark, I suppose...
UPDATE 2 ===========================
I've found that unpairing and re-pairing will allow the devices to connect. It's a workaround, but it's better than nothing.
Jellybean has a completely different Bluetooth stack, so version differences could certainly be triggering something, but that in itself wouldn't explain why it stays working or not-working after connecting with an older device. Could it be to do with pairing? If it happens again, try unpairing from the device and pairing again.
I know this is kind of an old question. But as I was not able to find any solution on the web, here is a workaround I recently have created: IOException: read failed, socket might closed - Bluetooth on Android 4.3
In my case it was due to bad UUID in createRfcommSocketToServiceRecord() function.
I want to connect to SPP serial profile in raspberry pi 3 and I used this UUID:
private static final UUID MY_UUID_SECURE =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
I found somewhere in android documents' page for SPP.
I had the same problem while connecting to the arduino via bluetooth module.The problem only arised while connecting with arduino as it connected smoothly with another android phone bluetooth.
What worked for me was changing the UUID string..
Related
I have written an app that connects to a BLE device. The app works OK on most devices; but some devices (most noticeably Huawei P8 Lite and Nexus 6P) refuse to connect after the Bluetooth adapter has been disabled.
This is the test sequence:
Make sure the app is NOT running.
Slide down from the top, disable BT for a couple of seconds, then re-enable bluetooth.
Start the app. The app automatically connects to a bluetooth address stored in the preferences.
Wait for connect. This is where nothing happens on Huawei phones, but other phones, such as Samsung, works like a charm.
Verify from another phone the device is advertising and you can
connect to it.
This is the code I use to connect:
private final Runnable mBeginConnectRunnable = new Runnable() {
#Override
public void run() {
synchronized (GattConnection.this) {
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
try {
mBluetoothAdapter.cancelDiscovery();
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(mAddress);
mGatt = mBluetoothDevice.connectGatt(mContext, mBackgroundConnect, mGattCallback);
final boolean connectSuccess = mGatt.connect();
Log.d(TAG, String.format(Locale.ENGLISH, "mGatt.connect(%s, %s) %s",
mAddress,
mBackgroundConnect ? "background[slow]" : "foreground[fast]",
connectSuccess ? "success" : "failed"));
refreshDeviceCache(mGatt);
} catch (Exception ex) {
Log.e(TAG, "Create connection failed: " + ex.getMessage());
setState(State.Closed);
}
} else {
Log.d(TAG, "Can't create connection. Adapter is disabled");
setState(State.Closed);
}
}
}
};
All calls are posted via a Handler to the main thread. I can see it waits for a connect, gives up after 30 seconds at which I call BluetoothGatt.close() on the object and nulls it. It's like nothing is out there.
After some time, later in the day, it works again.
Help is highly appreciated :-)
Update September 14, 2018: After great explanation from Emil I've updated our app and as such don't have this problem on the Nexus. I've noticed the Huawei P8 Lite continues to scan in the background and it seems there is nothing you can do to stop it.
To demonstrate the problems I've made a very simple and clean app that exercise the Bluetooth LE functionality on a phone and used it to demonstrate this problem and also the P8 is broken. The app is available here: https://play.google.com/store/apps/details?id=eu.millibit.bluetootherror
Source is available here: https://bitbucket.org/millibit/eu.millibit.bluetootherror/src/master/
I hope I over time can extend this app to make it a test vehicle for Android documenting all the stange behavior from Android and collect it in a database. In case you are interested in contributing, don't hesitate to drop me a mail on bt.error#millibit.dk
The Android Bluetooth stack has a design flaw in its API. When you connect to a specific device by Bluetooth Device Address, there is no way to tell if you mean a Public address or Random address.
If you start to connect to a device with autoConnect=false which is not bonded and has not recently been seen in a Scan, it will assume you mean a Public address. So if you try to connect to a device having a static random address, it will fail.
To be sure you connect with the correct address type if the device is not bonded, you MUST perform a scan first, find the device and THEN start the connection attempt.
I try to create BluetoothServerSocket on Samsung Galaxy Gio.
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket tmp = null;
try
{
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_INSECURE, MY_UUID_INSECURE);
}
catch (IOException e)
{
}
mmServerSocket = tmp;
When I no longer need to use a socket I just close it.
public void cancel()
{
try
{
mmServerSocket.close();
}
catch (IOException e)
{
}
}
In both cases no exceptions are throws. So my problem is. When i try to use 1st pease of code again( without exit from app) Log cat show me exception :
07-07 18:27:44.239: D/BluetoothSocket(13672): create BluetoothSocket: type = 1, fd =-1,
uuid = [null], port = 25
07-07 18:27:44.339: E/BLZ20_WRAPPER(13672): ##### ERROR : __listen_prot_rfcomm: failed
with reason 1#####
That happens till then i don't reboot my phone or TurnOFF\wait\TurnOn my bluetooth. So i think the problem is that BluetoothServerSocket create sockets but he don't close it. Maybe my preconceptions is not right so i want to help.
After a bit of searching, I found this thread whose poster appears to get the same exception (Although it's in Italian, so I don't really understand...). If you scroll down a little, you'll see a java exception thrown for this native exception (__listen_prot_rfcomm: failed with reason 1). The java exception is java.io.IOException: Bad file number.
You can find this problem in many threads online (Android Bluetooth IOException bad file number, Bluetooth failed to get port number). From these 2 we can learn that this problem is device specific. Some devices seem to keep the file descriptor of the socket alive, even after you close it with BluetoothServerSocket.close(), so you can't recreate any sockets using the same settings.
The solution will depend on your application audience:
If you are not planning to publish it in the Play Store/Any other market, you could call BluetoothAdapter.disable(), and then re-enable it. This is very bad user experience, as an application shouldn't disable the bluetooth without asking the users first. But it will solve your problem, because all bluetooth file descriptors will be disposed automatically. So if the only user is you, it's a possible solution.
If you do plan on publishing this, you should find a real solution... It might not be easy, but this is indeed a major problem and it also seems that many devices are affected by it, so you can't publish your app as long as this problem persists.
I've worked before with Kryonet doing 1-to-1 communication and it worked nicely.
Now I'm doing a more 'standard' project where we'll have 1 server and several clients to connect to it.
The issue I'm having is as described in the title: client 1 connects, no problem. Then I ask for client 2 to connect and immediately client 1 disconnects. Somehow the server doesn't want to keep more than one simultaneous connection.
A couple of times we managed to have 2 connected and then whenever the 3rd connects the other drops.
Running on several different devices all ICS+ (galaxy nexus, tab2, SGS3).
The codes I'm using are very much like the examples:
server side:
server = new Server();
ServiceData.RegisterKryo(server.getKryo());
server.addListener(new MyServerListener());
try {
server.bind(ServiceData.SERVER_PORT_TCP);
server.start();
} catch (IOException e) {
Log.e(TAG, "IOException. Failed to start server. " + e.getMessage());
MyServer.this.stopSelf();
}
And then client side:
final String ip = intent.getExtras().getString(KEY_SERVER_IP);
listener = new MyClientListener();
client = new Client();
client.start();
ServiceData.RegisterKryo(client.getKryo());
client.addListener(listener);
try {
client.connect(5000, ip, ServiceData.SERVER_PORT_TCP);
} catch (IOException e) {
Log.e(TAG, "IOException. Failed to start client. " + e.getMessage() + "\n");
e.printStackTrace();
MyClient.this.stopSelf();
}
the listeners at the moment are just Log.v(TAG, "something happened); and I've also enabled all the logs from the Kryonet library with com.esotericsoftware.minlog.Log.set(com.esotericsoftware.minlog.Log.LEVEL_TRACE); so I can see when it's connecting and when it's disconnecting.
I receive two different messages upon disconnection:
DEBUG: [kryonet] Connection 3 timed out.
and
DEBUG: [kryonet] Unable to read TCP from:
really not sure what's on here and any help will be appreciated.
edit:
a bit more info:
I've realised that between INFO: [kryonet] Connection 3 connected: /192.168.0.104 and my listener receive the connected callback, it's taking around 9 seconds! Very odd.
To whom might get into the same issue.
Apparently it's an Android limitation (probably imposed because it's a mobile device)
I just moved the Server code to a normal Java application .jar and let the Android clients connect to the PC and it all works fine now. Until now tested with 6 devices connected with no problems.
I have a project that connects to a device over Bluetooth. It used to work fairly reliably, but now it fails the BluetoothSocket.connect() call every time. (Well, I got it to connect once during the thousands of attempts over a 4 hour period.) Most of the code has been taken from the standard sample chat code in the API, with the exception of the common modification in getting the BluetoothSocket device itself:
Method m = device.getClass().getMethod(
"createRfcommSocket", new Class[] { int.class });
tmp = (BluetoothSocket) m.invoke(device, Integer.valueOf(1));
Here's the method of interest, which gets run once a BluetoothSocket is obtained:
public void run() {
setName("ConnectThread" + mSocketType);
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
mmSocket.connect();
} catch (Exception e) {
Log.e(TAG, "Connection to " + mmDevice.getName() + " at "
+ mmDevice.getAddress() + " failed:" + e.getMessage());
// Close the socket
try {
mmSocket.close();
} catch (Exception e2) {
Log.e(TAG, "unable to close() " + mSocketType
+ " socket during connection failure", e2);
}
connectionFailed(e.getMessage());
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothChatService.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice, mSocketType);
}
The relevant log entry (printed when the exception is caught while calling connect()) is this:
11-30 10:23:51.685: E/BluetoothChatService(2870): Connection to
ZYNO-700091 at 00:06:66:42:8E:01 failed:read failed, socket might
closed, read ret: -1
This error used to come up once in a while. I have an aggressive reconnect system - it basically hammers the connection over and over until it connects, and if it were ever to disconnect, it starts hammering it again. So, it kills the connection thread and starts from scratch constantly. I had considered that there might be an issue there - maybe a multithreading one, or maybe in handling the socket cleanup/initialization. However, if that were the case, I'd still expect the first connection attempt to succeed, since that system doesn't kick in until there's a failed connection attempt.
I looked into the source code throwing the exception. The issue seems to be that the underlying InputStream has no data. Of course, that's not really an answer, just a step towards it. Why would the stream have no data?
I'm trying to keep an open mind about the potential issue. Am I getting the BluetoothSocket properly? The fact that it was once an intermittent issue and is now nearly constant makes me suspect multithreading, but that's a relatively simple topic in Java compared to C++ - hard to screw up if you know what you're doing. Plus, the majority of this code (in particular, the parts dealing with synchronizing the threads) is straight out of the sample code.
The device on the other end is an embedded Bluetooth device, so there's not much hope of debugging the problem from that end.
UPDATE ===========================
It occurred to me that it might be due to an OS upgrade (I'm running on Galaxy Nexus phones - I have several to test with). So I unpacked a new phone with 4.0.4 and it worked! So then went back and tested on the two original test phones, both running 4.2, expecting the failure I've been seeing all this time. Strangely, now it works on those phones too. I'd like to say I did something to make this work again, but I didn't. I'm still mystified, and now also suspicious that this thing is going to work when I really need it to.
I wonder if there's a possibility that somehow connecting using 4.0.4 could have properly set the state of the server module, making it receptive to the 4.2 devices? Just a shot in the dark, I suppose...
UPDATE 2 ===========================
I've found that unpairing and re-pairing will allow the devices to connect. It's a workaround, but it's better than nothing.
Jellybean has a completely different Bluetooth stack, so version differences could certainly be triggering something, but that in itself wouldn't explain why it stays working or not-working after connecting with an older device. Could it be to do with pairing? If it happens again, try unpairing from the device and pairing again.
I know this is kind of an old question. But as I was not able to find any solution on the web, here is a workaround I recently have created: IOException: read failed, socket might closed - Bluetooth on Android 4.3
In my case it was due to bad UUID in createRfcommSocketToServiceRecord() function.
I want to connect to SPP serial profile in raspberry pi 3 and I used this UUID:
private static final UUID MY_UUID_SECURE =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
I found somewhere in android documents' page for SPP.
I had the same problem while connecting to the arduino via bluetooth module.The problem only arised while connecting with arduino as it connected smoothly with another android phone bluetooth.
What worked for me was changing the UUID string..
I´m writing an android app that connects to a device through bluetooth using RFCOMM. I use the BluetoothChat example as basis for establishing a connection and everything works perfectly most of the time.
However, sometimes I cannot reconnect due to a message that the socket is already open:
RFCOMM_CreateConnection - already opened state:2, RFC state:4, MCB
state:5
This tends to happen if I connect to the device, close the app (call onDestroy()), reopen it and try to connect again, which results in the above.
I use this method for connecting in the ConnectThread(ref.BluetoothChat example):
Method m = device.getClass().getMethod("createRfcommSocket",new Class[] {int.class });
tmp = (BluetoothSocket) m.invoke(device, Integer.valueOf(1));
mmSocket = tmp;
The only thing that resolves this problem is turning off/on the Bluetooth of the Android phone.
This leads me to believe that the socket is not being closed in onDestroy() but still I´m calling on closing all threads as shown in the before mentioned example.
Any ideas would be appreciated.
I stumbled upon this one too, and here is the answer I found:
This error may happen, if you open and close a bluetooth socket connection multiple times.
Solution
Starting from API Level 14 there is a Method in BluetoothSocket called isConected(), which returns true, if this socket is already connected and false otherwise, here the original excerpt from the API:
Get the connection status of this socket, ie, whether there is an
active connection with remote device.
For API levels < 14 you can work around this issue by putting your Bluetooth Handling Thread to sleep after closing the connection - 1000 ms should be enough, here is an example (btDevice is of the type BluetoothDevice and has been initialized prior to the code snippet below):
try {
//Open the socket to an SPP device (UUID taken from Android API for createRfcommSocketToServiceRecord)
BluetoothSocket btSocket = btDevice.createRfcommSocketToServiceRecord("00001101-0000-1000-8000-00805F9B34FB");
//Connect to the socket
btSocket.connect();
//Close the socket
btSocket.close();
//Sleep time of 1000ms after closing the socket
SystemClock.sleep(POST_RESET_DELAY);
} catch (Throwable e) {
// Log error message
}
P.s. Instead of SystemClock.sleep you can also use Thread.sleep - however the SystemCock's sleep can't be interrupted, whereas the Thread.sleep can be interrupted, so it depends on your use-case which option better suits your purpose.
Source: Louis A. Prado