Proper way to close a USB accessory connection - android

What is the proper way to close a connection to a UsbAccessory in Android?
It seems the even in the stock Google example, if I connect and accessory, exit the app and then go back to it, the connection is not re-established.
Looking closely, it seems that after calling close() on the FileDescriptor, it won't open again, and a "could not open /dev/usb_accessory" log is emitted.
NOT calling close() is a bad option, as a thread blocking on read() will not be released. Upon physical disconnection / reconnection of the device everything is OK.
It seems really surprising that the simple use-case of exiting the app and then opening it again does not work in the reference application and even more surprising if it is not feasible.
I'm using a Nexus S running stock Android 2.3.6.

The problem is that the reading thread never exits, thus the file descriptor stays open, and cannot be opened again when the app is resumed.
This has been confirmed to be a bug:
http://code.google.com/p/android/issues/detail?id=20545
Vote on this bug if you care about it.

try to reconnect twice
it seams that the first time that is unsuccess will close the connection and then try again to open it will work!
for me it worked!

Related

How can an App freeze Android OS

I am developing an Android app that is causing the OS to Freeze.
My question is rather simple but after lengthy searches I have come no closer to an answer.
The question is, how can an app which is sandboxed, cause the entire Android OS (4.0.4, 4.1.1, 4.1.2) to freeze?
Specifically, the entire OS freezes. No logcat, no adb, nothing! It is as frozen as an OS can get. The device is a Samsung Galaxy Tab 2. The app uses the UsbManager and the library from the usb-serial-for-android project. While the library may use the NDK, my app does not. Essentially, the app communicates serially with a propriety board, receiving data and sending serial commands. This is done on a worker thread that is disposed of in this manner:
try {
thread.interrupt();
thread.join();
while(thread.getState() != Thread.State.TERMINATED){
// wait until thread finishes
}
} catch (InterruptedException e) {
e.printStackTrace();
}
It all works fine, that is until the freeze occurs - when I disconnect the usb cable or instruct the library object to disconnect. Either way, the entire OS gets unstable and will freeze immediately or upon connecting the usb again (board or computer). I have posted this freeze issue to the usb-serial-for-android project but have not received any comments yet. I believe I am following the proper protocols when disengaging the usb.
I understand many things can go wrong - my app can crash et. al. But again how does a sandboxed app crash the OS - it does not seem to be very sandboxed if it can do that.
UPDATE
I have after much experimentation found that by removing the thread.interrupt(); line that it works without crashing the app or freezing the OS. It still freezes the OS if the USB is unplugged without first dismounting it.
I still desire to understand how a sandboxed app can freeze the entire OS though. There are comments here that elude to an answer, but are not an answer alone.
Where is your code sample above located?
It should be be on a UI thread, potentially blocking user interaction.
Are you also getting ANR messages before the freeze?
thread.join();
will block indefinitely. See Thread.join() documentation.
Also, the following looks like a busy loop to me.
What are you doing at the comment? If nothing, then the loop will spin like crazy (think while (true) { }).
while(thread.getState() != Thread.State.TERMINATED){
// wait until thread finishes
}

getBluetoothService called with no BluetoothManagerCallback

I am getting getBluetoothService() called with no BluetoothManagerCallback as an error frequently in my Android application.
I have no idea what is causing this or anything about bluetooth manager callbacks. Can anyone give me a good idea of what could be causing this problem or where to start looking.
By reading into the Android source code, it seems to be a warning you cannot do anything about. The source code shows that if you call
BluetoothSocket#connect();
Then it will call
BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
The key here, is the null parameter that it passes in the above line. Due to this, there will be no callback, and then the BluetoothSocket class will throw out a warning.
Since it is only a warning, I do not think you need to do anything about it.
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothSocket.java line 306
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothAdapter.java line 1610
It appears that this gets called when multiple bluetooth sockets are opened at once. I fixed this by ensuring I was only opening 1 socket at a time.
I get this error even after my application has been closed and I can't get rid of it in any possible way. After this start happening I need to hard-reboot my phone because I'm not able anymore to even turn ON bluetooth.
Right now (with the same code) it happens only on one of my phones.. maybe it's an issues of the drivers.
This also comes up if the BluetoothServerSocket isn't currently accepting [bluetoothServerSocket.accept()] with the same UUID you are trying to connect.
If you are sure you are accepting with the server socket, double check that you haven't provided a too short timeout (I had previously set it to 200 to check something, whoops).
I received this message after trying to BluetoothSocket.connect() directly after receiving the BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED with a state of BluetoothHeadset.STATE_CONNECTED. The BluetoothSocket.connect() also failed. After adding a timeout of 500ms before trying to BluetoothSocket.connect() this resolved my issue of actually connecting. The message "getBluetoothService() called with no BluetoothManagerCallback" still remains but everything works.
getBluetoothService() called with no BluetoothManagerCallback
I am also facing the same problem. But I solved.
In my case already one socket is in open state and I am trying to open another socket. So we trying to open more than one socket at a time as a client. I felt that this is the reason

Why does my phoneGap Android application crash on resume?

I recently began writing a phonegap android application and noticed that when the app is resumed from the background (so I deploy the app to an android tablet, press the home button and then reopen the app from the menu) it gives a timeout error (something to the effect of Error code =-6 The connection to the server was unsuccessful) and then crashes. From what I've tested this only seems to happen when the "Don't keep activities" option is checked in the developer options, when that option is not checked the app works as intended.
It's also worth noting that I recreated the default phonegap application, ran it and encountered the same issue.
Can anyone explain why this happens, or suggest a solution? Obviously I can get around this problem by simply leaving the Don't keep activities option unchecked, but I'm guessing the problem will persist on any android device that has this option checked, which just won't do.
I'm using phonegap 2.5.0 and testing on a device running Android 4.0.3,
Thanks,
Josh
"Don't keep activities" is a developer tool to simulate user activity that would be extremely hard to test for. I personally believe all apps should be tested a second time (at least run automated tests) with this setting turned on, and devs should turn it on / off during development.
Your issue (which I've just ran into on v2.7) comes from a silly implementation of a timeout feature. CordovaWebView.loadUrlIntoView creates and locks (wait()) a thread for 20 seconds (default value), after which time it checks a value to see if the url finished loading - if it hasn't finished, it shows an error message.
This thread exists outside of the lifetime of your activity, so if the activity stops running, the Webview can never finish loading the url, and when the thread wakes up, it does Bad Things trying to show the error.
The same crash could happen without using "Don't keep activities" by simply having the user leave the application and then the system reclaiming the activity's resources (because it is low on memory or something) within 20 seconds.
Using a Handler seems like a more appropriate way to handle this timeout, but without changing the source there are a couple of hacky work arounds.
Call System.exit(0) at the end of your Activity.onDestroy() - this is horrible, but if you only have the one activity and no services, it might be an option
Use reflection to change CordovaWebView.loadUrlTimeout - this is horrible, but it should work, this is the value that the thread checks to see if the url loaded (inc by 1).

How to stop a thread that is suspended on a Bluetooth read

My app displays data from a steady stream of Bluetooth text input.
In Android 2.3.4, if I close the socket the read immediately throws an IO exception. In 2.2 is does only most of the time.
I am trying to stop the reading when onStop() is called. Then in onStart() I reconnect.
Is there a better way to kill the thread that is suspended on an inputStream read that is likely to work over all versions?
Thanks
TomZ
I tried interrupting the task and got bogged down in multiple types of exceptions depending on what it was doing at the time of the interrupt and getting compile errors that I was catching exceptions that it said could not be thrown. Even when I did get some working code, it still had reliability problems on Froyo (Galaxy S - Vibrant).
So I backed up and tried using InputStream.available in a loop with a short sleep and a check of a flag that is set to end the read task (so the task was never suspended except on the sleep). This worked great on various android versions.
It seems the trick is to not externally stop the thread but to let it detect the need to quit and return on it's own.
Seems a bit of a kludge, sort of polling the reads. But the code is now stable and the phone performance does not seem to suffer.

How can i force Android to garbage collect old socket information?

I have project where i'm developing an Android App using a lot of existing C++ code accessed through JNI which opens and closes sockets.
Even though this C++ properly handles the closeing of the sockets it opens, it seems either the Android OS or the JVM keeps around references to those sockets/ports being used until the next GC call.
What happens is if we stop the app and start it again before the next GC call, the app cannot create connections on that same socket/port. If we wait for GC to be called by the OS and then restart the app, it successfully creates the connections.
Is there a way to manually free up a socket from Android's/the JVM's perspective? Perhaps a socket class utility? A manual call to GC?
The operating system's TCP/IP protocol stack holds TCP ports for two minutes after the application closes them. So if you've had a listening socket that has accepted connections, the port will remain unusable for a couple of minutes.
Before you bind the socket to the listening address, call setsockopt() on the socket with option=SO_REUSEADDR and value of 1.
Try
System.gc();
Docs say...
void java.lang.System.gc()
Indicates to the virtual
machine that it would be a good time
to run the garbage collector. Note
that this is a hint only. There is no
guarantee that the garbage collector
will actually be run.

Categories

Resources