Added new rfcomm multi accept code
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 8d4c3af..c4595a1 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -848,51 +848,6 @@
}
/**
- /**
- * Picks RFCOMM channels until none are left.
- * Avoids reserved channels.
- */
- private static class RfcommChannelPicker {
- private static final int[] RESERVED_RFCOMM_CHANNELS = new int[] {
- 10, // HFAG
- 11, // HSAG
- 12, // OPUSH
- 19, // PBAP
- };
- private static LinkedList<Integer> sChannels; // master list of non-reserved channels
- private static Random sRandom;
-
- private final LinkedList<Integer> mChannels; // local list of channels left to try
-
- private final UUID mUuid;
-
- public RfcommChannelPicker(UUID uuid) {
- synchronized (RfcommChannelPicker.class) {
- if (sChannels == null) {
- // lazy initialization of non-reserved rfcomm channels
- sChannels = new LinkedList<Integer>();
- for (int i = 1; i <= BluetoothSocket.MAX_RFCOMM_CHANNEL; i++) {
- sChannels.addLast(new Integer(i));
- }
- for (int reserved : RESERVED_RFCOMM_CHANNELS) {
- sChannels.remove(new Integer(reserved));
- }
- sRandom = new Random();
- }
- mChannels = (LinkedList<Integer>)sChannels.clone();
- }
- mUuid = uuid;
- }
- /* Returns next random channel, or -1 if we're out */
- public int nextChannel() {
- if (mChannels.size() == 0) {
- return -1;
- }
- return mChannels.remove(sRandom.nextInt(mChannels.size()));
- }
- }
-
- /**
* Create a listening, secure RFCOMM Bluetooth socket.
* <p>A remote device connecting to this socket will be authenticated and
* communication on this socket will be encrypted.
@@ -911,10 +866,10 @@
BluetoothSocket.TYPE_RFCOMM, true, true, channel);
int errno = socket.mSocket.bindListen();
if (errno != 0) {
- try {
- socket.close();
- } catch (IOException e) {}
- socket.mSocket.throwErrnoNative(errno);
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
+ throw new IOException("Error: " + errno);
}
return socket;
}
@@ -1015,72 +970,23 @@
return createNewRfcommSocketAndRecord(name, uuid, false, true);
}
+
private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
boolean auth, boolean encrypt) throws IOException {
- RfcommChannelPicker picker = new RfcommChannelPicker(uuid);
BluetoothServerSocket socket;
- int channel;
- int errno;
- while (true) {
- channel = picker.nextChannel();
-
- if (channel == -1) {
- throw new IOException("No available channels");
- }
-
- socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel);
- errno = socket.mSocket.bindListen();
- if (errno == 0) {
- if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel);
- break; // success
- } else if (errno == BluetoothSocket.EADDRINUSE) {
- if (DBG) Log.d(TAG, "RFCOMM channel " + channel + " in use");
- try {
- socket.close();
- } catch (IOException e) {}
- continue; // try another channel
- } else {
- try {
- socket.close();
- } catch (IOException e) {}
- socket.mSocket.throwErrnoNative(errno); // Exception as a result of bindListen()
- }
+ socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth,
+ encrypt, new ParcelUuid(uuid));
+ socket.setServiceName(name);
+ int errno = socket.mSocket.bindListen();
+ if (errno != 0) {
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
+ throw new IOException("Error: " + errno);
}
-
- int handle = -1;
- //TODO(BT):
- /*try {
- handle = mService.addRfcommServiceRecord(name, new ParcelUuid(uuid), channel,
- new Binder());
- } catch (RemoteException e) {Log.e(TAG, "", e);}*/
- if (handle == -1) {
- try {
- socket.close();
- } catch (IOException e) {}
- throw new IOException("Not able to register SDP record for " + name);
- }
-
- if (mServiceRecordHandler == null) {
- mServiceRecordHandler = new Handler(Looper.getMainLooper()) {
- public void handleMessage(Message msg) {
- /* handle socket closing */
- int handle = msg.what;
- // TODO(BT):
- /*
- try {
- if (DBG) Log.d(TAG, "Removing service record " +
- Integer.toHexString(handle));
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- */
- }
- };
- }
- socket.setCloseHandler(mServiceRecordHandler, handle);
return socket;
}
-
/**
* Construct an unencrypted, unauthenticated, RFCOMM server socket.
* Call #accept to retrieve connections to this socket.
@@ -1094,10 +1000,10 @@
BluetoothSocket.TYPE_RFCOMM, false, false, port);
int errno = socket.mSocket.bindListen();
if (errno != 0) {
- try {
- socket.close();
- } catch (IOException e) {}
- socket.mSocket.throwErrnoNative(errno);
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
+ throw new IOException("Error: " + errno);
}
return socket;
}
@@ -1115,11 +1021,11 @@
BluetoothServerSocket socket = new BluetoothServerSocket(
BluetoothSocket.TYPE_RFCOMM, false, true, port);
int errno = socket.mSocket.bindListen();
- if (errno != 0) {
- try {
- socket.close();
- } catch (IOException e) {}
- socket.mSocket.throwErrnoNative(errno);
+ if (errno < 0) {
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
+ throw new IOException("Error: " + errno);
}
return socket;
}
@@ -1136,11 +1042,10 @@
BluetoothServerSocket socket = new BluetoothServerSocket(
BluetoothSocket.TYPE_SCO, false, false, -1);
int errno = socket.mSocket.bindListen();
- if (errno != 0) {
- try {
- socket.close();
- } catch (IOException e) {}
- socket.mSocket.throwErrnoNative(errno);
+ if (errno < 0) {
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
}
return socket;
}
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 4021f7b..96be8a2 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -17,6 +17,8 @@
package android.bluetooth;
import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelUuid;
import java.io.Closeable;
import java.io.IOException;
@@ -86,6 +88,22 @@
}
/**
+ * Construct a socket for incoming connections.
+ * @param type type of socket
+ * @param auth require the remote device to be authenticated
+ * @param encrypt require the connection to be encrypted
+ * @param uuid uuid
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient privileges
+ */
+ /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid)
+ throws IOException {
+ mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, -1, uuid);
+ mChannel = mSocket.getPort();
+ }
+
+
+ /**
* Block until a connection is established.
* <p>Returns a connected {@link BluetoothSocket} on successful connection.
* <p>Once this call returns, it can be called again to accept subsequent
@@ -133,7 +151,9 @@
mHandler = handler;
mMessage = message;
}
-
+ /*package*/ void setServiceName(String ServiceName) {
+ mSocket.setServiceName(ServiceName);
+ }
/**
* Returns the channel on which this socket is bound.
* @hide
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 2662f39..9b0e1cb 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -1,32 +1,27 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Copyright (C) 2012 Google Inc.
*/
package android.bluetooth;
-import android.bluetooth.IBluetoothCallback;
+import android.os.IBinder;
import android.os.ParcelUuid;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
+import java.util.List;
+import android.net.LocalSocket;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
/**
* A connected or connecting Bluetooth socket.
*
@@ -89,31 +84,41 @@
/*package*/ static final int EBADFD = 77;
/*package*/ static final int EADDRINUSE = 98;
+ /*package*/ static final int SEC_FLAG_ENCRYPT = 1;
+ /*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
+
private final int mType; /* one of TYPE_RFCOMM etc */
- private final BluetoothDevice mDevice; /* remote device */
- private final String mAddress; /* remote address */
+ private BluetoothDevice mDevice; /* remote device */
+ private String mAddress; /* remote address */
private final boolean mAuth;
private final boolean mEncrypt;
private final BluetoothInputStream mInputStream;
private final BluetoothOutputStream mOutputStream;
- private final SdpHelper mSdp;
-
+ private final ParcelUuid mUuid;
+ private ParcelFileDescriptor mPfd;
+ private LocalSocket mSocket;
+ private InputStream mSocketIS;
+ private OutputStream mSocketOS;
private int mPort; /* RFCOMM channel or L2CAP psm */
+ private int mFd;
+ private String mServiceName;
+ private static IBluetooth sBluetoothProxy;
+ private static int PROXY_CONNECTION_TIMEOUT = 5000;
+
+ private static int SOCK_SIGNAL_SIZE = 16;
private enum SocketState {
INIT,
CONNECTED,
- CLOSED
+ LISTENING,
+ CLOSED,
}
/** prevents all native calls after destroyNative() */
- private SocketState mSocketState;
+ private volatile SocketState mSocketState;
/** protects mSocketState */
- private final ReentrantReadWriteLock mLock;
-
- /** used by native code only */
- private int mSocketData;
+ //private final ReentrantReadWriteLock mLock;
/**
* Construct a BluetoothSocket.
@@ -134,36 +139,63 @@
throw new IOException("Invalid RFCOMM channel: " + port);
}
}
- if (uuid == null) {
- mPort = port;
- mSdp = null;
- } else {
- mSdp = new SdpHelper(device, uuid);
- mPort = -1;
- }
+ mUuid = uuid;
mType = type;
mAuth = auth;
mEncrypt = encrypt;
mDevice = device;
+ mPort = port;
+ mFd = fd;
+
+ mSocketState = SocketState.INIT;
+
if (device == null) {
- mAddress = null;
+ // Server socket
+ mAddress = BluetoothAdapter.getDefaultAdapter().getAddress();
} else {
+ // Remote socket
mAddress = device.getAddress();
}
-
- //TODO(BT)
- /*
- if (fd == -1) {
- initSocketNative();
- } else {
- initSocketFromFdNative(fd);
- }*/
mInputStream = new BluetoothInputStream(this);
mOutputStream = new BluetoothOutputStream(this);
- mSocketState = SocketState.INIT;
- mLock = new ReentrantReadWriteLock();
- }
+ if (sBluetoothProxy == null) {
+ synchronized (BluetoothSocket.class) {
+ if (sBluetoothProxy == null) {
+ IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+ if (b == null)
+ throw new RuntimeException("Bluetooth service not available");
+ sBluetoothProxy = IBluetooth.Stub.asInterface(b);
+ }
+ }
+ }
+ }
+ private BluetoothSocket(BluetoothSocket s) {
+ mUuid = s.mUuid;
+ mType = s.mType;
+ mAuth = s.mAuth;
+ mEncrypt = s.mEncrypt;
+ mPort = s.mPort;
+ mInputStream = new BluetoothInputStream(this);
+ mOutputStream = new BluetoothOutputStream(this);
+ mServiceName = s.mServiceName;
+ }
+ private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException {
+ BluetoothSocket as = new BluetoothSocket(this);
+ as.mSocketState = SocketState.CONNECTED;
+ FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
+ Log.d(TAG, "socket fd passed by stack fds: " + fds);
+ if(fds == null || fds.length != 1) {
+ Log.e(TAG, "socket fd passed from stack failed, fds: " + fds);
+ throw new IOException("bt socket acept failed");
+ }
+ as.mSocket = new LocalSocket(fds[0]);
+ as.mSocketIS = as.mSocket.getInputStream();
+ as.mSocketOS = as.mSocket.getOutputStream();
+ as.mAddress = RemoteAddr;
+ as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(RemoteAddr);
+ return as;
+ }
/**
* Construct a BluetoothSocket from address. Used by native code.
* @param type type of socket
@@ -189,71 +221,13 @@
super.finalize();
}
}
-
- /**
- * Attempt to connect to a remote device.
- * <p>This method will block until a connection is made or the connection
- * fails. If this method returns without an exception then this socket
- * is now connected.
- * <p>Creating new connections to
- * remote Bluetooth devices should not be attempted while device discovery
- * is in progress. Device discovery is a heavyweight procedure on the
- * Bluetooth adapter and will significantly slow a device connection.
- * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing
- * discovery. Discovery is not managed by the Activity,
- * but is run as a system service, so an application should always call
- * {@link BluetoothAdapter#cancelDiscovery()} even if it
- * did not directly request a discovery, just to be sure.
- * <p>{@link #close} can be used to abort this call from another thread.
- * @throws IOException on error, for example connection failure
- */
- public void connect() throws IOException {
- mLock.readLock().lock();
- try {
- if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
-
- if (mSdp != null) {
- mPort = mSdp.doSdp(); // blocks
- }
-
- connectNative(); // blocks
- mSocketState = SocketState.CONNECTED;
- } finally {
- mLock.readLock().unlock();
- }
- }
-
- /**
- * Immediately close this socket, and release all associated resources.
- * <p>Causes blocked calls on this socket in other threads to immediately
- * throw an IOException.
- */
- public void close() throws IOException {
- // abort blocking operations on the socket
- //TODO(BT)
- /*
- mLock.readLock().lock();
- try {
- if (mSocketState == SocketState.CLOSED) return;
- if (mSdp != null) {
- mSdp.cancel();
- }
- abortNative();
- } finally {
- mLock.readLock().unlock();
- }
-
- // all native calls are guaranteed to immediately return after
- // abortNative(), so this lock should immediately acquire
- mLock.writeLock().lock();
- try {
- if (mSocketState != SocketState.CLOSED) {
- mSocketState = SocketState.CLOSED;
- destroyNative();
- }
- } finally {
- mLock.writeLock().unlock();
- }*/
+ private int getSecurityFlags() {
+ int flags = 0;
+ if(mAuth)
+ flags |= SEC_FLAG_AUTH;
+ if(mEncrypt)
+ flags |= SEC_FLAG_ENCRYPT;
+ return flags;
}
/**
@@ -293,7 +267,63 @@
* false if not connected
*/
public boolean isConnected() {
- return (mSocketState == SocketState.CONNECTED);
+ return mSocketState == SocketState.CONNECTED;
+ }
+
+ /*package*/ void setServiceName(String name) {
+ mServiceName = name;
+ }
+
+ /**
+ * Attempt to connect to a remote device.
+ * <p>This method will block until a connection is made or the connection
+ * fails. If this method returns without an exception then this socket
+ * is now connected.
+ * <p>Creating new connections to
+ * remote Bluetooth devices should not be attempted while device discovery
+ * is in progress. Device discovery is a heavyweight procedure on the
+ * Bluetooth adapter and will significantly slow a device connection.
+ * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing
+ * discovery. Discovery is not managed by the Activity,
+ * but is run as a system service, so an application should always call
+ * {@link BluetoothAdapter#cancelDiscovery()} even if it
+ * did not directly request a discovery, just to be sure.
+ * <p>{@link #close} can be used to abort this call from another thread.
+ * @throws IOException on error, for example connection failure
+ */
+ public void connect() throws IOException {
+ if (mDevice == null) throw new IOException("Connect is called on null device");
+
+ try {
+ // TODO(BT) derive flag from auth and encrypt
+ if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
+
+ mPfd = sBluetoothProxy.connectSocket(mDevice, mType,
+ mUuid, mPort, getSecurityFlags());
+ synchronized(this)
+ {
+ Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
+ if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
+ if (mPfd == null) throw new IOException("bt socket connect failed");
+ FileDescriptor fd = mPfd.getFileDescriptor();
+ mSocket = new LocalSocket(fd);
+ mSocketIS = mSocket.getInputStream();
+ mSocketOS = mSocket.getOutputStream();
+ }
+ int channel = readInt(mSocketIS);
+ if (channel <= 0)
+ throw new IOException("bt socket connect failed");
+ mPort = channel;
+ waitSocketSignal(mSocketIS);
+ synchronized(this)
+ {
+ if (mSocketState == SocketState.CLOSED)
+ throw new IOException("bt socket closed");
+ mSocketState = SocketState.CONNECTED;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
}
/**
@@ -301,134 +331,165 @@
* so that BluetoothAdapter can check the error code for EADDRINUSE
*/
/*package*/ int bindListen() {
- return -1;
- //TODO(BT)
- /*
- mLock.readLock().lock();
+ int ret;
+ if (mSocketState == SocketState.CLOSED) return EBADFD;
try {
- if (mSocketState == SocketState.CLOSED) return EBADFD;
- return bindListenNative();
- } finally {
- mLock.readLock().unlock();
- }*/
+ mPfd = sBluetoothProxy.createSocketChannel(mType, mServiceName,
+ mUuid, mPort, getSecurityFlags());
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ // TODO(BT) right error code?
+ return -1;
+ }
+
+ // read out port number
+ try {
+ synchronized(this) {
+ Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
+ if(mSocketState != SocketState.INIT) return EBADFD;
+ if(mPfd == null) return -1;
+ FileDescriptor fd = mPfd.getFileDescriptor();
+ Log.d(TAG, "bindListen(), new LocalSocket ");
+ mSocket = new LocalSocket(fd);
+ Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() ");
+ mSocketIS = mSocket.getInputStream();
+ mSocketOS = mSocket.getOutputStream();
+ }
+ Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
+ int channel = readInt(mSocketIS);
+ synchronized(this) {
+ if(mSocketState == SocketState.INIT)
+ mSocketState = SocketState.LISTENING;
+ }
+ Log.d(TAG, "channel: " + channel);
+ if (mPort == -1) {
+ mPort = channel;
+ } // else ASSERT(mPort == channel)
+ ret = 0;
+ } catch (IOException e) {
+ Log.e(TAG, "bindListen, fail to get port number, exception: " + e);
+ return -1;
+ }
+ return ret;
}
/*package*/ BluetoothSocket accept(int timeout) throws IOException {
- mLock.readLock().lock();
- try {
- if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
-
- BluetoothSocket acceptedSocket = acceptNative(timeout);
- mSocketState = SocketState.CONNECTED;
- return acceptedSocket;
- } finally {
- mLock.readLock().unlock();
+ BluetoothSocket acceptedSocket;
+ if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state");
+ // TODO(BT) wait on an incoming connection
+ String RemoteAddr = waitSocketSignal(mSocketIS);
+ synchronized(this)
+ {
+ if (mSocketState != SocketState.LISTENING)
+ throw new IOException("bt socket is not in listen state");
+ acceptedSocket = acceptSocket(RemoteAddr);
+ //quick drop the reference of the file handle
}
+ // TODO(BT) rfcomm socket only supports one connection, return this?
+ // return this;
+ return acceptedSocket;
}
/*package*/ int available() throws IOException {
- mLock.readLock().lock();
- try {
- if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
- return availableNative();
- } finally {
- mLock.readLock().unlock();
- }
+ Log.d(TAG, "available: " + mSocketIS);
+ return mSocketIS.available();
}
/*package*/ int read(byte[] b, int offset, int length) throws IOException {
- mLock.readLock().lock();
- try {
- if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
- return readNative(b, offset, length);
- } finally {
- mLock.readLock().unlock();
- }
+
+ Log.d(TAG, "read in: " + mSocketIS + " len: " + length);
+ int ret = mSocketIS.read(b, offset, length);
+ if(ret < 0)
+ throw new IOException("bt socket closed, read return: " + ret);
+ Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret);
+ return ret;
}
/*package*/ int write(byte[] b, int offset, int length) throws IOException {
- mLock.readLock().lock();
- try {
- if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
- return writeNative(b, offset, length);
- } finally {
- mLock.readLock().unlock();
- }
+
+ Log.d(TAG, "write: " + mSocketOS + " length: " + length);
+ mSocketOS.write(b, offset, length);
+ // There is no good way to confirm since the entire process is asynchronous anyway
+ Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
+ return length;
}
- private native void initSocketNative() throws IOException;
- private native void initSocketFromFdNative(int fd) throws IOException;
- private native void connectNative() throws IOException;
- private native int bindListenNative();
- private native BluetoothSocket acceptNative(int timeout) throws IOException;
- private native int availableNative() throws IOException;
- private native int readNative(byte[] b, int offset, int length) throws IOException;
- private native int writeNative(byte[] b, int offset, int length) throws IOException;
- private native void abortNative() throws IOException;
- private native void destroyNative() throws IOException;
- /**
- * Throws an IOException for given posix errno. Done natively so we can
- * use strerr to convert to string error.
- */
- /*package*/ native void throwErrnoNative(int errno) throws IOException;
-
- /**
- * Helper to perform blocking SDP lookup.
- */
- private static class SdpHelper extends IBluetoothCallback.Stub {
- private final IBluetooth service;
- private final ParcelUuid uuid;
- private final BluetoothDevice device;
- private int channel;
- private boolean canceled;
- public SdpHelper(BluetoothDevice device, ParcelUuid uuid) {
- service = BluetoothDevice.getService();
- this.device = device;
- this.uuid = uuid;
- canceled = false;
+ @Override
+ public void close() throws IOException {
+ Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
+ if(mSocketState == SocketState.CLOSED)
+ return;
+ else
+ {
+ synchronized(this)
+ {
+ if(mSocketState == SocketState.CLOSED)
+ return;
+ mSocketState = SocketState.CLOSED;
+ Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
+ ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket);
+ if(mSocket != null) {
+ Log.d(TAG, "Closing mSocket: " + mSocket);
+ mSocket.shutdownInput();
+ mSocket.shutdownOutput();
+ mSocket.close();
+ mSocket = null;
+ }
+ if(mPfd != null)
+ mPfd.detachFd();
+ }
}
- /**
- * Returns the RFCOMM channel for the UUID, or throws IOException
- * on failure.
- */
- public synchronized int doSdp() throws IOException {
- if (canceled) throw new IOException("Service discovery canceled");
- channel = -1;
+ // TODO(BT) unbind proxy,
+ }
- boolean inProgress = false;
- //TODO(BT)
- /*
- try {
- inProgress = service.fetchRemoteUuids(device.getAddress(), uuid, this);
- } catch (RemoteException e) {Log.e(TAG, "", e);}*/
+ /*package */ void removeChannel() {
+ }
- if (!inProgress) throw new IOException("Unable to start Service Discovery");
-
- try {
- /* 12 second timeout as a precaution - onRfcommChannelFound
- * should always occur before the timeout */
- wait(12000); // block
-
- } catch (InterruptedException e) {}
-
- if (canceled) throw new IOException("Service discovery canceled");
- if (channel < 1) throw new IOException("Service discovery failed");
-
- return channel;
+ /*package */ int getPort() {
+ return mPort;
+ }
+ private String convertAddr(final byte[] addr) {
+ return String.format("%02X:%02X:%02X:%02X:%02X:%02X",
+ addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]);
+ }
+ private String waitSocketSignal(InputStream is) throws IOException {
+ byte [] sig = new byte[SOCK_SIGNAL_SIZE];
+ int ret = readAll(is, sig);
+ Log.d(TAG, "waitSocketSignal read 16 bytes signal ret: " + ret);
+ ByteBuffer bb = ByteBuffer.wrap(sig);
+ bb.order(ByteOrder.nativeOrder());
+ int size = bb.getShort();
+ byte [] addr = new byte[6];
+ bb.get(addr);
+ int channel = bb.getInt();
+ int status = bb.getInt();
+ String RemoteAddr = convertAddr(addr);
+ Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: "
+ + RemoteAddr + ", channel: " + channel + ", status: " + status);
+ if(status != 0)
+ throw new IOException("Connection failure, status: " + status);
+ return RemoteAddr;
+ }
+ private int readAll(InputStream is, byte[] b) throws IOException {
+ int left = b.length;
+ while(left > 0) {
+ int ret = is.read(b, b.length - left, left);
+ if(ret < 0)
+ throw new IOException("read failed, socket might closed, read ret: " + ret);
+ left -= ret;
+ if(left != 0)
+ Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) +
+ ", expect size: " + b.length);
}
- /** Object cannot be re-used after calling cancel() */
- public synchronized void cancel() {
- if (!canceled) {
- canceled = true;
- channel = -1;
- notifyAll(); // unblock
- }
- }
- public synchronized void onRfcommChannelFound(int channel) {
- if (!canceled) {
- this.channel = channel;
- notifyAll(); // unblock
- }
- }
+ return b.length;
+ }
+
+ private int readInt(InputStream is) throws IOException {
+ byte[] ibytes = new byte[4];
+ int ret = readAll(is, ibytes);
+ Log.d(TAG, "inputStream.read ret: " + ret);
+ ByteBuffer bb = ByteBuffer.wrap(ibytes);
+ bb.order(ByteOrder.nativeOrder());
+ return bb.getInt();
}
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 80a3d61..e987954 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -73,4 +73,8 @@
boolean setPairingConfirmation(in BluetoothDevice device, boolean accept);
void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState);
+
+ // For Socket
+ ParcelFileDescriptor connectSocket(in BluetoothDevice device, int type, in ParcelUuid uuid, int port, int flag);
+ ParcelFileDescriptor createSocketChannel(int type, in String serviceName, in ParcelUuid uuid, int port, int flag);
}
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index 3ee8a80..34e0d9a 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -42,6 +42,15 @@
isBound = false;
isConnected = false;
}
+ /**
+ * Creates a AF_LOCAL/UNIX domain stream socket with FileDescriptor.
+ * @hide
+ */
+ public LocalSocket(FileDescriptor fd) throws IOException {
+ this(new LocalSocketImpl(fd));
+ isBound = true;
+ isConnected = true;
+ }
/**
* for use with AndroidServerSocket