How do I close any previous Bluetooth sockets after my app starts? - java

In my app, I open and close a Bluetooth socket on the same device each session and listen for data. When I close one, I make sure to close the input and output streams and then socket in a cancel method. Still, for some people the app keeps trying to read from the device. I know because I read logs that are from run() in the listening thread, where there is a flag for listening that's set to false in cancel, and the listening thread will end when the socket is closed due to an IOException, but this never happens, so the socket must still be opened. I see logs of attempted reads every second of every day even though the person isn't using the app. This might be because the app crashes and the cancel method isn't called. Either way I can't guarantee the cancel method will be called. How do I close any Bluetooth sockets that were previously opened when I start up my app, if these were all opened in new threads created independently?
This guy had the same problem but I didn't see any solution:
Android bluetooth connection doesn't close after application crash
The accepted answer is no good because:
The current users haven't had the UncaughtExceptionHandler run that code yet and they need to have any previous connections closed when the new version is released
The UncaughtExceptionHandler must have a reference to the sockets, which it doesn't have. I want to be able to close any Bluetooth sockets when the app starts.
The guy who made that question asked how to get information about the socket to store for when the app starts up and you want to close them, and got no response.
EDIT:
How I open the socket (removed logging code):
try {
tmp.connect();;
} catch (IOException e) {
isConnected = false;
try {
tmp = (BluetoothSocket) device.getClass().getMethod("createRfcommSocket",
new Class[] {int.class}).invoke(device, 1);
} catch (Exception e2) {
e2.printStackTrace();
}
try {
tmp.connect();
setConnected();
} catch (IOException e1) {
e1.printStackTrace();
isConnected = false;
cancel();
}
How I close the socket:
public void cancel() {
isConnected = false;
listening = false;
try {
if (manageConnection.mmInStream != null) {
manageConnection.mmInStream.close();
manageConnection.mmInStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (manageConnection.mmOutStream != null) {
manageConnection.mmOutStream.close();
manageConnection.mmOutStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
mmSocket.close();
mmSocket = null;
manageConnection = null;
} catch (IOException e) {
// Logging code
}
}
}
Listening:
while (listening == true) {
try {
synchronized (ListeningActivity.lock) {
buffer = new byte[mmInStream.available()];
mmInStream.read(buffer);
....
} catch (IOException e) {
// Code that calls cancel()

Related

ThreadPoolExecutor.shutdownNow() not throwing InterruptedException in Thread

I am implementing a Transfer Server program which takes messages from clients (via console input) and then forwards it to some sort of mailbox.
To allow concurrent reception of several messages by different clients, I first created a class that implements the Runnable interface. Each of this class instances will handle the communication with exactly one client:
public class ClientConnection implements Runnable {
//...
//...
#Override
public void run() {
try {
// prepare the input reader and output writer
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
Message message = new Message();
String request = "";
// read client requests
while ((request = reader.readLine()) != null) {
System.out.println("Client sent the following request: " + request);
String response;
if (request.trim().equals("quit")) {
writer.println("ok bye");
return;
}
response = message.parseRequest(request);
if (message.isCompleted()) {
messagesQueue.put(message);
message = new Message();
}
writer.println(response);
}
} catch (SocketException e) {
System.out.println("ClientConnection: SocketException while handling socket: " + e.getMessage());
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (InterruptedException e) {
System.out.println("Client Connection was interrupted!");
e.printStackTrace();
} finally {
if (clientSocket != null && !clientSocket.isClosed()) {
try {
clientSocket.close();
} catch (IOException ignored) {}
}
}
}
}
I do have a parent thread which is responsible for starting and managing all the ClientConnection runnables:
#Override
public void run() {
clientConnectionExecutor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
while (true) {
Socket clientSocket;
try {
// wait for a Client to connect
clientSocket = serverSocket.accept();
ClientConnection clientConnection = new ClientConnection(clientSocket, messagesQueue);
clientConnectionExecutor.execute(clientConnection);
} catch (IOException e) {
// when this exception occurs, it means that we want to shut down everything
clientConnectionExecutor.shutdownNow(); // force terminate all ClientConnections
return;
}
}
}
Now according to this Stackoverflow Question, I would have expected that as soon as shutdownNow(); is being called, an InterruptedException would be thrown within my ClientConnection.run() method, and there, it should print Client Connection was interrupted!. But this does not happen, so the catch clause seems never to be reached, the input reading loop just goes on.
I read in another Stackoverflow question that this might be related to some other codeline within the block seems to be consuming the InterruptedException, but there wasn't any particular information on what codeline could do that. So I am thankful for any hints.
Edit: It turns out that as soon as I manually exit the loop by typing "quit" on the client, the loop will quit and then, Client Connection was interrupted! will be printed. So somehow the exception seems to be ignored as long as the loop is running, and only handled afterwards.
From Oracle docs for shutdownNow:
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
If you take a look into ThreadPoolExecutor sources, you will find out that shutdownNow interrupts threads with this code:
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
Your ClientConnection doesn't check the flag Thread.interrupted. Due to information in the post, I can't figure out which method throws InterruptedException. Probably, some other method, for example, readLine of reader or writer, blocks the thread, because they use socket's InputStream and OutputStream and because it's obvious that socket's streams block the thread if data is not immediatly available.
For example, I wrote this code to test it:
class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocket serverSocket = new ServerSocket()) {
serverSocket.bind(new InetSocketAddress(8080));
Socket socket = serverSocket.accept();
int dataByte = socket.getInputStream().read();
System.out.println(dataByte);
} catch (IOException e) {
e.printStackTrace();
}
});
thread.start();
thread.interrupt();
}
}
On OpenJdk-16.0.2 there is no actual interruption.
I see two possible solutions for your problem:
Check Thread.interrupted inside the while loop if you are sure that Socket doesn't block your thread.
If your are not sure, use SocketChannel in non-blocking mode instead of Socket for checking Thread.interrupted manually.
For the second way I tranformed my example into this:
class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocketChannel serverSocket = ServerSocketChannel.open()) {
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(8080));
SocketChannel socket = null;
while (socket == null) {
socket = serverSocket.accept();
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socket.read(byteBuffer);
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.flip();
byteBuffer.get(bytes);
System.out.println(new String(bytes, StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("Interrupted successfully");
}
});
thread.start();
thread.interrupt();
}
}
It works.
Good luck with Java :)
I would have expected that as soon as shutdownNow(); is being called, an InterruptedException would be thrown within my ClientConnection.run()
Your messagesQueue should be a BlockingQueue. So messagesQueue.put(message) will make you need to catch an Interrupted exception. So only when the thread is blocked in the put method(queue is full), you call threadpool#shutdownNow, then the thread will receive an Interrupted exception. In other cases, thread will not receive this Interrupted exception.
You can change while ((request = reader.readLine()) != null) to while ((request = reader.readLine()) != null && !Thread.interrupted()).
Another solution is to maintain all client sockets, and close all client sockets when you need to close them, this way, the client thread will directly receive an IOException:
List<Socket> clientSockets = new ArrayList<>();
while (true) {
try {
Socket accept = serverSocket.accept();
clientSockets.add(accept);
executorService.submit(new ClientConnection(accept));
}catch (Exception e) {
for (Socket socket : clientSockets) {
try {
socket.close();
} catch (Exception exception) {
//
}
}
//executorService.shutdownNow();
}
}

Android BluetoothSocket can't connect

I'm doing some stuff with bluetooth on android and I would like to connect to one of the discovered devices and open a socket connection towards it.
I've granted all of the needed permissions: Bluetooth, Bluetooth_Admin, Access_Fine_Location and Access_Coarse_Location and ask for them before I do anything with bluetooth.
Now, I've discovered some devices with adapter.startDiscovery(); and activity.registerReceiver(receiver, filter);
In the receiver finds a device of a certain name, I try connecting to it like this:
adapter.cancelDiscovery();
Log.d(TAG, "Create Bond");
device.createBond();
try {
socket = device.createRfcommSocketToServiceRecord(uuid);
Log.d(TAG, "Sleep 10");
sleep(10000);
Log.d(TAG, "Create Socket");
//socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
Log.d(TAG, "Connect socket");
socket.connect();
Log.d(TAG, "Connecting Done");
} catch (Exception e) {
Log.d(TAG, "Failed to connect to device", e);
try {
socket.close();
} catch (Exception e2) {
Log.d(TAG, "Failed to close socket", e2);
}
}
This is a test code with which I'm trying to create a socket and open a connection.
I get the following Exception on .connect():
java.io.IOException: read failed, socket might closed or timeout, read
ret: -1
at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:684)
at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:696)
at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:373)
What am I doing wrong.
The bluetooth device I connect to is a Android mobile device, but I plan on using others when I manage to get the connection.
Update1:
Android version is 7.0
use fetchUuidsWithSdp() and getUuids() to find all the published services and their associated UUID values.
You don't need to call device.createBond(); to connect to a Bluetooth device.
Try removing this line. Also check, that your phone is not already paired with the device you're trying to connect to.
You can check that on the Bluetooth settings screen (open it with a long press on the Bluetooth icon on your smartphone.
Here is a sample code to initiates a Bluetooth connection :
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket
// because mmSocket is final.
BluetoothSocket tmp = null;
mmDevice = device;
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it otherwise slows down the connection.
bluetoothAdapter.cancelDiscovery();
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and return.
try {
mmSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}
// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(mmSocket);
}
// Closes the client socket and causes the thread to finish.
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the client socket", e);
}
}
}
This code is from Android official doc:
https://developer.android.com/guide/topics/connectivity/bluetooth#ConnectAsAClient
I wrote another code instead of what I was using for server side.
Log.d(TAG,"Start server");
BluetoothServerSocket serverSocket = null;
try {
serverSocket = adapter.listenUsingRfcommWithServiceRecord("ime", uuid);
} catch (Exception e) {
e.printStackTrace();
}
while (true) {
try {
serverSocket.accept();
} catch (Exception e) {
e.printStackTrace();
}
}
I used this code inside of a thread which starts instead of calling the code from the question.
Installing the App with server code on one app and calling "connect" on socket did the trick.
I used the same UUID (previous was random generated, new one was static from string).

Android: BluetoothSocket receives its own output

I have an app that connects to a RaspberryPi via Bluetooth and loops the same data to it while it receives some data back.
I had some issues with the connection so this workaround is needed to connect my android phone to the RaspberryPi: IOException: read failed, socket might be closed - Bluetooth on Android 4.3
For some reason, the android phone is receiving its own output.
The String "Hello Raspberry. It's me, AndroidPhone" is sent to the output in a never-ending loop. The incoming data (from the RaspberryPi) is also read in a never-ending loop.
But somehow I don't only receive the data from the RaspberryPi but also the string sends via smartphone. This is my code:
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter bluetoothAdapter;
UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
#Override
protected void onCreate(Bundle savedInstanceState) {
// (...)
// Only GUI-stuff until this point
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice raspberryPi = bluetoothAdapter.getRemoteDevice("B8:27:EB:56:DC:B2");
BluetoothSocket btSocket;
try {
btSocket = raspberryPi.createRfcommSocketToServiceRecord(SERIAL_UUID);
btSocket.connect();
} catch (IOException e) {
Log.e("BTError", e.getMessage());
// Workaround, found on: https://stackoverflow.com/questions/18657427/ioexception-read-failed-socket-might-closed-bluetooth-on-android-4-3
try {
Log.e("BTError", "Trying fallback...");
btSocket = (BluetoothSocket) raspberryPi.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(raspberryPi, 1);
btSocket.connect();
(new Thread(new SendingThread(btSocket))).start();
(new Thread(new ReceivingThread(btSocket))).start();
} catch (Exception e2) {
Log.e("BTError", e2.getMessage());
Log.e("BTError", "Couldn't establish Bluetooth connection!");
}
}
}
private class SendingThread extends Thread {
private OutputStream out;
public SendingThread(BluetoothSocket btSocket) {
try {
out = btSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
try {
int delay = 100000000;
while (true) {
if (delay == 0) {
Log.i("WRT", "Written to RaspberryPi");
out.write("Hello Raspberry. It's me, AndroidPhone".getBytes());
delay = 100000000;
}
delay--;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class ReceivingThread extends Thread {
private InputStream in;
public ReceivingThread(BluetoothSocket btSocket) {
try {
in = btSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
int data = 0;
while (true) {
try {
data = in.read();
} catch (IOException e) {
e.printStackTrace();
}
Log.i("RCV", String.valueOf((char) data));
}
}
}
On the RaspberryPi end, everything looks normal. A simple java program starts the Linux command rfcomm listen /dev/rfcomm0 and reads from/writes to the file /dev/rfcomm0 with FileReader and FileWriter. The only relevant lines on this end are:
run {
// Inside writer-thread
bluetoothWriter = new BufferedWriter(new FileWriter("/dev/rfcomm0"));
while(true) {
bluetoothWriter.write("This is RaspPi");
bluetoothWriter.flush();
}
}
and
run {
// Inside reader-thread
bluetoothReader = new BufferedReader(new FileReader("/dev/rfcomm0"));
while(true) {
int incData = bluetoothReader.read();
System.out.print((char) incData);
}
}
Thank you for your help!
edit: Still no solution to this problem. I suspected that the RaspberryPi is somehow sending back what it received. But when I disabled that it sends out anything, the smartphone still directly receives what it has sent out.
I scoured over the Bluetooth classes sources. The workaround seems legit from the first glances. Try this first:
if (delay == 0) {
Log.i("WRT", "Written to RaspberryPi");
out.write("Hello Raspberry. It's me, AndroidPhone".getBytes());
out.flush(); // <-- You are not flushing
delay = 100000000;
}
And the message sticks in you socket for you to read over and over again.
If that does not fix it the other option I can think of is that somehow the socket is initialized to be a socket to your Android device. The .createRfcommSocket() method seems to create a socket to your own device if the Bluetooth device is null when the socket was being created. I'm not sure how this would exactly happen, but if the Raspberry Pi's state is somehow mangled after exception I suppose it could be something to look into.
On the raspy side: If you are just starting both of those threads doesn't it mean that you are constantly sending messages to /dev/rfcomm0 and flushing. I recommend that you change it so that raspy reacts to a received message by sending back the wanted message instead of spamming all the time. I'm not sure if this is part of your problem but it would at least make debugging & development a bit easier.
I am not sure if this is the solution you need, because I don't know if you are using bluetooth classic or bluetooth 4.0>+, but I wrote a library for text based BLE and WiFi P2P 2-way communication for android (and I know the Raspberry Pi is capable of BLE communication), I don't create a socket connection for BLE communication though, but I do for WiFi P2P. Take a look, I hope it helps. It isn't published yet, so you would have to clone/fork the repo.
I think you have trouble writing
As far as I know, for buffer, should use \n and ...
bluetoothWriter.write("This is RaspPi\n");
But I prefer to use a combination of DataOutputStream and BufferedReader
For Read:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
try {
String line = bufferedReader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
for write:
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
String s = "Hi\n";
try {
dataOutputStream.write(s.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
It is better to correct the point made by a dear friend about flush() ...
I'm not sure, please test yourself ...

How to synchronize closing socket by two threads?

I have two threads, one for reading, one for writing data through the same socket. When is problem with connection two threads catch exceptions and try reconnect.To do this they call the same methods
public synchronized void close_connection() {
try {
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
and after it second one to try establish connection:
public synchronized boolean connect() {
boolean result=true;
socket = new Socket();
try {
socket.connect(new InetSocketAddress(address, port), 500);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
} catch (IOException e) {
result=false;
}
return result;
}
The problem is how to avoid trying connect with server from two threads one by one immediatly (after connection error - for example afrter closing connection by server). I mean: if one thread tries do connection the second thread should know this and dosen't try do the same but wait for establish connection by first one (to avoid permanent fight threads problem disconnect,connect, disconnect, connect....). I've tried with synchronization but my experience is too small.
Regards,
Artik
You could try something like this:
while(not connected){
try reconnecting
if(success){
//Everything is ok, go on
} else {
//sleep for random period of time and retry
}
}
or you can implement the socket operations in an object and share that object between your threads using locks.
Use appropriate mutex locking. This will make sure only one thread will access the connect() portion of your code.

Interrupt a connecting socket

I have a GUI with a list of servers to connect to. If a user clicks a server it connects to it. If a user clicks a second server, it will disconnect the first and connect to the second. Each new connection runs in a new thread so that the program can perform other tasks.
However, if a user clicks a second server while the first is still connecting, there are two simultaneous connections.
I'm connecting using this, and connect() is the line that blocks:
Socket socket = new Socket();
socket.connect(socketAddress, connectTimeout);
I thought maybe Thread.currentThread().interrupt(); would work, but didn't.
Do I have to restructure my code a bit so that it continues making the first connection, but closes it straight after? Or is there actually a way to interrupt the connect method.
If you are using a blocking socket implementation, interrupting the thread won't 'cancel' or interrupt your socket connection. The only way of breaking out of the 'blocking call' is to 'close' the socket. You can expose a method on your Runnable tasks (e.g. cancel) which close the socket and clean up the resources when the user tries connecting to a second server.
If you want you can have a look at my throwaway attempt at interrupting threads which make blocking calls.
Can you instead use a non-blocking socket? I'm not much of a Java expert, but it looks like SocketChannel is their non-blocking socket class.
Here is an example:
// Create a non-blocking socket and check for connections
try {
// Create a non-blocking socket channel on port 80
SocketChannel sChannel = createSocketChannel("hostname.com", 80);
// Before the socket is usable, the connection must be completed
// by calling finishConnect(), which is non-blocking
while (!sChannel.finishConnect()) {
// Do something else
}
// Socket channel is now ready to use
} catch (IOException e) {
}
Taken from here:
http://www.exampledepot.com/egs/java.nio/NbClientSocket.html
Inside the while loop you can check for some shared notification that you need to be cancelled and bail out, closing the SocketChannel as you go.
I tried the suggested answers but nothing worked for me.
So what I did was, instead of setting my connection timeout to 10 seconds I try to connect 5 times in a row with a connection timeout of 2 seconds.
I also have a global variable boolean cancelConnection declared.
Every time a timeout exception is thrown, I can eather break out of or continue the loop based on the value of cancelConnection.
Here's a code snippet from an android app I'm writing:
try {
SocketAddress socketaddres = new InetSocketAddress(server.ip,server.port);
int max=5;
for (int i = 1; i<=max; i++) {
try {
socket = new Socket();
socket.connect(socketaddres, 2000);
break;
} catch (Exception e) {
Log.d(TAG, "attempt "+i+ " failed");
if (cancelConnection) {
Log.d(TAG, "cancelling connection");
throw new Exception();
} else if (i==max) {
throw new Exception();
}
}
}
} catch (Exception e) {
if (cancelConnection) {
// Do whatever you would do after connection was canceled.
} else {
// Do whatever you would do after connection error or timeout
}
}
You can use something like this construction:
ExecutorService es = Executors.newSingleThreadExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = Executors.defaultThreadFactory().newThread(r);
t.setDaemon(true);
return t;
}
});
Future<Socket> res = es.submit(() -> {
try {
return new Socket(addr, port);
} catch (Exception ex) {
logger.error("Error while connecting. " + ex.getMessage());
return null;
}
});
es.shutdown();
try {
while (!res.isDone()) {
Thread.sleep(5);
}
} catch (InterruptedException iex) {
logger.error("Connection interrupted.");
return;
}
Socket client = res.get();

Categories

Resources