Cleaned up Android Bluetooth reflection code and added logging.

This commit is contained in:
akwizgran
2013-03-11 10:35:14 +00:00
parent a02ca4b356
commit cd5d922b5e

View File

@@ -1,11 +1,14 @@
package net.sf.briar.plugins.droidtooth; package net.sf.briar.plugins.droidtooth;
import static java.util.logging.Level.INFO;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Logger;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
@@ -21,16 +24,22 @@ import android.os.ParcelUuid;
// Based on http://stanford.edu/~tpurtell/InsecureBluetooth.java by T.J. Purtell // Based on http://stanford.edu/~tpurtell/InsecureBluetooth.java by T.J. Purtell
class InsecureBluetooth { class InsecureBluetooth {
private static final Logger LOG =
Logger.getLogger(InsecureBluetooth.class.getName());
private static final int TYPE_RFCOMM = 1; private static final int TYPE_RFCOMM = 1;
@SuppressLint("NewApi") @SuppressLint("NewApi")
static BluetoothServerSocket listen(BluetoothAdapter adapter, String name, static BluetoothServerSocket listen(BluetoothAdapter adapter, String name,
UUID uuid) throws IOException { UUID uuid) throws IOException {
if(Build.VERSION.SDK_INT >= 10) { if(Build.VERSION.SDK_INT >= 10) {
if(LOG.isLoggable(INFO)) LOG.info("Listening with new API");
return adapter.listenUsingInsecureRfcommWithServiceRecord(name, return adapter.listenUsingInsecureRfcommWithServiceRecord(name,
uuid); uuid);
} }
try { try {
if(LOG.isLoggable(INFO)) LOG.info("Listening via reflection");
// Find an available channel
String className = BluetoothAdapter.class.getName() String className = BluetoothAdapter.class.getName()
+ ".RfcommChannelPicker"; + ".RfcommChannelPicker";
Class<?> channelPickerClass = null; Class<?> channelPickerClass = null;
@@ -48,15 +57,15 @@ class InsecureBluetooth {
if(constructor == null) if(constructor == null)
throw new IOException("Can't find channel picker constructor"); throw new IOException("Can't find channel picker constructor");
Object channelPicker = constructor.newInstance(uuid); Object channelPicker = constructor.newInstance(uuid);
Method nextChannel = channelPickerClass.getDeclaredMethod( Method nextChannel =
"nextChannel", new Class[0]); channelPickerClass.getDeclaredMethod("nextChannel");
nextChannel.setAccessible(true); nextChannel.setAccessible(true);
BluetoothServerSocket socket = null; int channel = (Integer) nextChannel.invoke(channelPicker);
int channel = (Integer) nextChannel.invoke(channelPicker,
new Object[0]);
if(channel == -1) throw new IOException("No available channels"); if(channel == -1) throw new IOException("No available channels");
socket = listen(channel); // Listen on the channel
Field f = adapter.getClass().getDeclaredField("mService"); BluetoothServerSocket socket = listen(channel);
// Add a service record
Field f = BluetoothAdapter.class.getDeclaredField("mService");
f.setAccessible(true); f.setAccessible(true);
Object mService = f.get(adapter); Object mService = f.get(adapter);
Method addRfcommServiceRecord = Method addRfcommServiceRecord =
@@ -70,7 +79,7 @@ class InsecureBluetooth {
socket.close(); socket.close();
throw new IOException("Can't register SDP record for " + name); throw new IOException("Can't register SDP record for " + name);
} }
Field f1 = adapter.getClass().getDeclaredField("mHandler"); Field f1 = BluetoothAdapter.class.getDeclaredField("mHandler");
f1.setAccessible(true); f1.setAccessible(true);
Object mHandler = f1.get(adapter); Object mHandler = f1.get(adapter);
Method setCloseHandler = socket.getClass().getDeclaredMethod( Method setCloseHandler = socket.getClass().getDeclaredMethod(
@@ -96,7 +105,6 @@ class InsecureBluetooth {
} }
private static BluetoothServerSocket listen(int port) throws IOException { private static BluetoothServerSocket listen(int port) throws IOException {
BluetoothServerSocket socket = null;
try { try {
Constructor<BluetoothServerSocket> constructor = Constructor<BluetoothServerSocket> constructor =
BluetoothServerSocket.class.getDeclaredConstructor( BluetoothServerSocket.class.getDeclaredConstructor(
@@ -104,15 +112,15 @@ class InsecureBluetooth {
if(constructor == null) if(constructor == null)
throw new IOException("Can't find server socket constructor"); throw new IOException("Can't find server socket constructor");
constructor.setAccessible(true); constructor.setAccessible(true);
socket = constructor.newInstance(TYPE_RFCOMM, false, false, port); BluetoothServerSocket socket = constructor.newInstance(TYPE_RFCOMM,
Field f = socket.getClass().getDeclaredField("mSocket"); false, false, port);
Field f = BluetoothServerSocket.class.getDeclaredField("mSocket");
f.setAccessible(true); f.setAccessible(true);
Object mSocket = f.get(socket); Object mSocket = f.get(socket);
Method bindListen = mSocket.getClass().getDeclaredMethod( Method bindListen =
"bindListen", new Class[0]); mSocket.getClass().getDeclaredMethod("bindListen");
bindListen.setAccessible(true); bindListen.setAccessible(true);
Object result = bindListen.invoke(mSocket, new Object[0]); int errno = (Integer) bindListen.invoke(mSocket);
int errno = (Integer) result;
if(errno != 0) { if(errno != 0) {
socket.close(); socket.close();
throw new IOException("Can't bind: errno " + errno); throw new IOException("Can't bind: errno " + errno);
@@ -138,10 +146,12 @@ class InsecureBluetooth {
@SuppressLint("NewApi") @SuppressLint("NewApi")
static BluetoothSocket createSocket(BluetoothDevice device, UUID uuid) static BluetoothSocket createSocket(BluetoothDevice device, UUID uuid)
throws IOException { throws IOException {
if(Build.VERSION.SDK_INT >= 10) if(Build.VERSION.SDK_INT >= 10) {
if(LOG.isLoggable(INFO)) LOG.info("Creating socket with new API");
return device.createInsecureRfcommSocketToServiceRecord(uuid); return device.createInsecureRfcommSocketToServiceRecord(uuid);
}
try { try {
BluetoothSocket socket = null; if(LOG.isLoggable(INFO)) LOG.info("Creating socket via reflection");
Constructor<BluetoothSocket> constructor = Constructor<BluetoothSocket> constructor =
BluetoothSocket.class.getDeclaredConstructor(int.class, BluetoothSocket.class.getDeclaredConstructor(int.class,
int.class, boolean.class, boolean.class, int.class, boolean.class, boolean.class,
@@ -149,9 +159,8 @@ class InsecureBluetooth {
if(constructor == null) if(constructor == null)
throw new IOException("Can't find socket constructor"); throw new IOException("Can't find socket constructor");
constructor.setAccessible(true); constructor.setAccessible(true);
socket = constructor.newInstance(TYPE_RFCOMM, -1, false, true, return constructor.newInstance(TYPE_RFCOMM, -1, false, true, device,
device, -1, uuid != null ? new ParcelUuid(uuid) : null); -1, new ParcelUuid(uuid));
return socket;
} catch(NoSuchMethodException e) { } catch(NoSuchMethodException e) {
throw new IOException(e.toString()); throw new IOException(e.toString());
} catch(IllegalAccessException e) { } catch(IllegalAccessException e) {