diff options
Diffstat (limited to 'core/java/android/server')
-rw-r--r-- | core/java/android/server/BluetoothA2dpService.java | 16 | ||||
-rw-r--r-- | core/java/android/server/BluetoothEventLoop.java | 20 | ||||
-rw-r--r-- | core/java/android/server/BluetoothService.java | 133 |
3 files changed, 157 insertions, 12 deletions
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 6e221c8..bea01f3 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -457,6 +457,22 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority); } + public synchronized boolean allowIncomingConnect(BluetoothDevice device, boolean value) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); + String address = device.getAddress(); + if (!BluetoothAdapter.checkBluetoothAddress(address)) { + return false; + } + Integer data = mBluetoothService.getAuthorizationAgentRequestData(address); + if (data == null) { + Log.w(TAG, "allowIncomingConnect(" + device + ") called but no native data available"); + return false; + } + log("allowIncomingConnect: A2DP: " + device + ":" + value); + return mBluetoothService.setAuthorizationNative(address, value, data.intValue()); + } + private synchronized void onSinkPropertyChanged(String path, String []propValues) { if (!mBluetoothService.isEnabled()) { return; diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index c877c5c..af233a0 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -48,6 +48,7 @@ class BluetoothEventLoop { private boolean mInterrupted; private final HashMap<String, Integer> mPasskeyAgentRequestData; + private final HashMap<String, Integer> mAuthorizationAgentRequestData; private final BluetoothService mBluetoothService; private final BluetoothAdapter mAdapter; private final Context mContext; @@ -104,6 +105,7 @@ class BluetoothEventLoop { mBluetoothService = bluetoothService; mContext = context; mPasskeyAgentRequestData = new HashMap(); + mAuthorizationAgentRequestData = new HashMap<String, Integer>(); mAdapter = adapter; initializeNativeDataNative(); } @@ -120,6 +122,10 @@ class BluetoothEventLoop { return mPasskeyAgentRequestData; } + /* package */ HashMap<String, Integer> getAuthorizationAgentRequestData() { + return mAuthorizationAgentRequestData; + } + /* package */ void start() { if (!isEventLoopRunningNative()) { @@ -491,27 +497,29 @@ class BluetoothEventLoop { mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); } - private boolean onAgentAuthorize(String objectPath, String deviceUuid) { + private void onAgentAuthorize(String objectPath, String deviceUuid, int nativeData) { String address = mBluetoothService.getAddressFromObjectPath(objectPath); if (address == null) { Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize"); - return false; + return; } boolean authorized = false; ParcelUuid uuid = ParcelUuid.fromString(deviceUuid); BluetoothA2dp a2dp = new BluetoothA2dp(mContext); + BluetoothDevice device = mAdapter.getRemoteDevice(address); + mAuthorizationAgentRequestData.put(address, new Integer(nativeData)); + // Bluez sends the UUID of the local service being accessed, _not_ the // remote service if (mBluetoothService.isEnabled() && (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid) || BluetoothUuid.isAdvAudioDist(uuid)) && !isOtherSinkInNonDisconnectingState(address)) { - BluetoothDevice device = mAdapter.getRemoteDevice(address); authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF; if (authorized) { - Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address); + Log.i(TAG, "First check pass for incoming A2DP / AVRCP connection from " + address); // Some headsets try to connect AVCTP before AVDTP - against the recommendation // If AVCTP connection fails, we get stuck in IncomingA2DP state in the state // machine. We don't handle AVCTP signals currently. We only send @@ -519,6 +527,8 @@ class BluetoothEventLoop { // some cases. For now, just don't move to incoming state in this case. if (!BluetoothUuid.isAvrcpTarget(uuid)) { mBluetoothService.notifyIncomingA2dpConnection(address); + } else { + a2dp.allowIncomingConnect(device, authorized); } } else { Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address); @@ -527,7 +537,7 @@ class BluetoothEventLoop { Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address); } log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized); - return authorized; + if (!authorized) a2dp.allowIncomingConnect(device, authorized); } private boolean onAgentOutOfBandDataAvailable(String objectPath) { diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index c271021..88732f0 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -27,8 +27,8 @@ package android.server; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothDeviceProfileState; +import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfileState; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUuid; @@ -67,6 +67,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; @@ -142,6 +143,11 @@ public class BluetoothService extends IBluetooth.Stub { private static String mDockAddress; private String mDockPin; + private static final String INCOMING_CONNECTION_FILE = + "/data/misc/bluetooth/incoming_connection.conf"; + private HashMap<String, Pair<Integer, String>> mIncomingConnections; + + private static class RemoteService { public String address; public ParcelUuid uuid; @@ -209,6 +215,7 @@ public class BluetoothService extends IBluetooth.Stub { filter.addAction(Intent.ACTION_DOCK_EVENT); mContext.registerReceiver(mReceiver, filter); + mIncomingConnections = new HashMap<String, Pair<Integer, String>>(); } public static synchronized String readDockBluetoothAddress() { @@ -733,8 +740,6 @@ public class BluetoothService extends IBluetooth.Stub { if (state == BluetoothDevice.BOND_BONDED) { addProfileState(address); - } else if (state == BluetoothDevice.BOND_NONE) { - removeProfileState(address); } if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" + @@ -1312,6 +1317,8 @@ public class BluetoothService extends IBluetooth.Stub { } public synchronized boolean removeBondInternal(String address) { + // Unset the trusted device state and then unpair + setTrust(address, false); return removeDeviceNative(getObjectPathFromAddress(address)); } @@ -2161,10 +2168,6 @@ public class BluetoothService extends IBluetooth.Stub { return state; } - private void removeProfileState(String address) { - mDeviceProfileState.remove(address); - } - private void initProfileState() { String []bonds = null; String val = getPropertyInternal("Devices"); @@ -2213,6 +2216,11 @@ public class BluetoothService extends IBluetooth.Stub { mA2dpService = a2dpService; } + /*package*/ Integer getAuthorizationAgentRequestData(String address) { + Integer data = mEventLoop.getAuthorizationAgentRequestData().remove(address); + return data; + } + public void sendProfileStateMessage(int profile, int cmd) { Message msg = new Message(); msg.what = cmd; @@ -2223,6 +2231,116 @@ public class BluetoothService extends IBluetooth.Stub { } } + private void createIncomingConnectionStateFile() { + File f = new File(INCOMING_CONNECTION_FILE); + if (!f.exists()) { + try { + f.createNewFile(); + } catch (IOException e) { + Log.e(TAG, "IOException: cannot create file"); + } + } + } + + /** @hide */ + public Pair<Integer, String> getIncomingState(String address) { + if (mIncomingConnections.isEmpty()) { + createIncomingConnectionStateFile(); + readIncomingConnectionState(); + } + return mIncomingConnections.get(address); + } + + private void readIncomingConnectionState() { + synchronized(mIncomingConnections) { + FileInputStream fstream = null; + try { + fstream = new FileInputStream(INCOMING_CONNECTION_FILE); + DataInputStream in = new DataInputStream(fstream); + BufferedReader file = new BufferedReader(new InputStreamReader(in)); + String line; + while((line = file.readLine()) != null) { + line = line.trim(); + if (line.length() == 0) continue; + String[] value = line.split(","); + if (value != null && value.length == 3) { + Integer val1 = Integer.parseInt(value[1]); + Pair<Integer, String> val = new Pair(val1, value[2]); + mIncomingConnections.put(value[0], val); + } + } + } catch (FileNotFoundException e) { + log("FileNotFoundException: readIncomingConnectionState" + e.toString()); + } catch (IOException e) { + log("IOException: readIncomingConnectionState" + e.toString()); + } finally { + if (fstream != null) { + try { + fstream.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + } + + private void truncateIncomingConnectionFile() { + RandomAccessFile r = null; + try { + r = new RandomAccessFile(INCOMING_CONNECTION_FILE, "rw"); + r.setLength(0); + } catch (FileNotFoundException e) { + log("FileNotFoundException: truncateIncomingConnectionState" + e.toString()); + } catch (IOException e) { + log("IOException: truncateIncomingConnectionState" + e.toString()); + } finally { + if (r != null) { + try { + r.close(); + } catch (IOException e) { + // ignore + } + } + } + } + + /** @hide */ + public void writeIncomingConnectionState(String address, Pair<Integer, String> data) { + synchronized(mIncomingConnections) { + mIncomingConnections.put(address, data); + + truncateIncomingConnectionFile(); + BufferedWriter out = null; + StringBuilder value = new StringBuilder(); + try { + out = new BufferedWriter(new FileWriter(INCOMING_CONNECTION_FILE, true)); + for (String devAddress: mIncomingConnections.keySet()) { + Pair<Integer, String> val = mIncomingConnections.get(devAddress); + value.append(devAddress); + value.append(","); + value.append(val.first.toString()); + value.append(","); + value.append(val.second); + value.append("\n"); + } + out.write(value.toString()); + } catch (FileNotFoundException e) { + log("FileNotFoundException: writeIncomingConnectionState" + e.toString()); + } catch (IOException e) { + log("IOException: writeIncomingConnectionState" + e.toString()); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + } + private static void log(String msg) { Log.d(TAG, msg); } @@ -2273,4 +2391,5 @@ public class BluetoothService extends IBluetooth.Stub { short channel); private native boolean removeServiceRecordNative(int handle); private native boolean setLinkTimeoutNative(String path, int num_slots); + native boolean setAuthorizationNative(String address, boolean value, int data); } |