Monday, May 16, 2011

 

Looting Android's log files

Hello, my faithful droogsreaders. Been awhile since I've posted here, because I've been super-busy, mostly writing code. But I'm off travelling for a couple of months shortly (Ethiopia, France, Ladakh) so I thought I'd leave you with a little Android/Bluetooth tidbit before I go:

In theory, any Android 2.1-or-later device can open serial port protocols to any Bluetooth device. In practice, though, a bunch of handset manufacturers have, for reasons known to them alone, crippled their Bluetooth stack so that they can't Discover (a word with a loaded meaning in Bluetooth) any device with a generic (ie set to 0) Bluetooth class.

How annoying, no? However, it turns out that - even on those devices - you can pair with and connect to those devices, if you know their address. "But Jon," you say, "how can I get their address, if the Discovery process has been crippled?"

Well. It turns out that the Qualcomm drivers in question, when they ignore the generic Bluetooth devices, do write to the Android log file the fact that they are ignoring it. So all you need to do is mine your log files for the address. How do you do that? So glad you asked.

First, add to your AndroidManifest:

<uses-permission android:name="android.permission.READ_LOGS" />


Second, use this method:

private Set checkLogs() {
HashSet devices = new HashSet();
if (mAdapter==null)
return devices;

//check the logs
Log.i(""+this, "Log check...");
try {
Process process = Runtime.getRuntime().exec("logcat -d *:e");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
String deviceAddress=null;
while ((line = bufferedReader.readLine()) != null) {
if (line.indexOf("0x00 - skip it") > 0) {
int end = line.indexOf("] class");
int start = line.indexOf("Device [");
if (start>=0)
start=start+"Device [".length();
deviceAddress = line.substring(start, end);
Log.i(""+this, "Found "+deviceAddress+" in log");
BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress) ;
devices.add(device);
//String deviceName = device.getName()==null ? device.getAddress() : device.getName();
//Util.DoToast(Main.this, "Discovered device "+deviceName);
}
}
bufferedReader.close();
process.destroy();
return devices;
}
catch(IOException ex) {
Log.e(""+this, "Error checking logs - "+ex);
ex.printStackTrace();
return null;
}
}


...and finally, just connect to the device explicitly:


btSocket = device.createRfcommSocketToServiceRecord(GatewayManagerConversation.uuid);
btSocket.connect();


...and that should trigger the pairing process, and after pairing, you can connect to the device (which will be in your local cache of paired devices, as normal.)

Hope that helps!

Labels: , ,


Comments:
I took the same log file approach, but I have written an AsyncTask that kicks of discovery, and they retrieves just those devices that were 'skipped' during that discovery. This will avoid finding multiple devices, and won't require the user to kick of a discovery in the phone settings first :)

You can find it here.
 

Post a Comment

Subscribe to Post Comments [Atom]





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]