diff options
| author | Nick Pelly <npelly@google.com> | 2009-09-02 11:51:35 -0700 |
|---|---|---|
| committer | Nick Pelly <npelly@google.com> | 2009-09-02 11:51:35 -0700 |
| commit | 71c3c7806acb2b2b7b8441817c26a2101d447bbe (patch) | |
| tree | 615e8145d3d6506dc1bdeafa61f6b00675579eaf /core/java | |
| parent | 05a6f3cde52e5fbbad5187615bfc87d58559161f (diff) | |
| download | frameworks_base-71c3c7806acb2b2b7b8441817c26a2101d447bbe.zip frameworks_base-71c3c7806acb2b2b7b8441817c26a2101d447bbe.tar.gz frameworks_base-71c3c7806acb2b2b7b8441817c26a2101d447bbe.tar.bz2 | |
Immediately destroy BluetoothSocket's on close().
Unfortunatley, shutdown() on the underlying fd does not actually stop a
listening socket from listening. You need to call close() on the fd to
do this. There is no way around it.
So this means the Java BluetoothSocket code has to call destroyNative() during
BluetoothSocket.close().
Since native methods cannot be called after destroyNative(), add a ReadWrite
lock and mClosed field to protect access to native methods.
This fixes the "resource busy" error when Bluetooth OPP and Bluetooth PBAP
tried to resume listening after turning BT off and then on.
Diffstat (limited to 'core/java')
5 files changed, 104 insertions, 19 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 6bd2a5a..8975fe2 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -312,7 +312,7 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, true, true, channel); try { - socket.mSocket.bindListenNative(); + socket.mSocket.bindListen(); } catch (IOException e) { try { socket.close(); @@ -334,7 +334,7 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, false, false, port); try { - socket.mSocket.bindListenNative(); + socket.mSocket.bindListen(); } catch (IOException e) { try { socket.close(); @@ -356,7 +356,7 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_SCO, false, false, -1); try { - socket.mSocket.bindListenNative(); + socket.mSocket.bindListen(); } catch (IOException e) { try { socket.close(); diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java index c060f32..03af953 100644 --- a/core/java/android/bluetooth/BluetoothInputStream.java +++ b/core/java/android/bluetooth/BluetoothInputStream.java @@ -37,7 +37,7 @@ import java.io.InputStream; * Return number of bytes available before this stream will block. */ public int available() throws IOException { - return mSocket.availableNative(); + return mSocket.available(); } public void close() throws IOException { @@ -57,7 +57,7 @@ import java.io.InputStream; */ public int read() throws IOException { byte b[] = new byte[1]; - int ret = mSocket.readNative(b, 0, 1); + int ret = mSocket.read(b, 0, 1); if (ret == 1) { return (int)b[0] & 0xff; } else { @@ -93,6 +93,6 @@ import java.io.InputStream; if ((offset | length) < 0 || length > b.length - offset) { throw new ArrayIndexOutOfBoundsException("invalid offset or length"); } - return mSocket.readNative(b, offset, length); + return mSocket.read(b, offset, length); } } diff --git a/core/java/android/bluetooth/BluetoothOutputStream.java b/core/java/android/bluetooth/BluetoothOutputStream.java index 7e2ead4..62242a2 100644 --- a/core/java/android/bluetooth/BluetoothOutputStream.java +++ b/core/java/android/bluetooth/BluetoothOutputStream.java @@ -53,7 +53,7 @@ import java.io.OutputStream; public void write(int oneByte) throws IOException { byte b[] = new byte[1]; b[0] = (byte)oneByte; - mSocket.writeNative(b, 0, 1); + mSocket.write(b, 0, 1); } /** @@ -82,6 +82,6 @@ import java.io.OutputStream; if ((offset | count) < 0 || count > b.length - offset) { throw new IndexOutOfBoundsException("invalid offset or length"); } - mSocket.writeNative(b, offset, count); + mSocket.write(b, offset, count); } } diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java index e653c23..b650841 100644 --- a/core/java/android/bluetooth/BluetoothServerSocket.java +++ b/core/java/android/bluetooth/BluetoothServerSocket.java @@ -47,6 +47,7 @@ import java.io.IOException; * operations and close the socket. */ public final class BluetoothServerSocket implements Closeable { + /*package*/ final BluetoothSocket mSocket; /** @@ -88,7 +89,7 @@ public final class BluetoothServerSocket implements Closeable { * timeout */ public BluetoothSocket accept(int timeout) throws IOException { - return mSocket.acceptNative(timeout); + return mSocket.accept(timeout); } /** @@ -97,6 +98,6 @@ public final class BluetoothServerSocket implements Closeable { * throw an IOException. */ public void close() throws IOException { - mSocket.closeNative(); + mSocket.close(); } } diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index eae0f37..ccbe23e 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.concurrent.locks.ReentrantReadWriteLock; + /** * A connected or connecting Bluetooth socket. * @@ -63,7 +65,14 @@ public final class BluetoothSocket implements Closeable { private final BluetoothInputStream mInputStream; private final BluetoothOutputStream mOutputStream; - private int mSocketData; /* used by native code only */ + /** prevents all native calls after destroyNative() */ + private boolean mClosed; + + /** protects mClosed */ + private final ReentrantReadWriteLock mLock; + + /** used by native code only */ + private int mSocketData; /** * Construct a BluetoothSocket. @@ -95,6 +104,8 @@ public final class BluetoothSocket implements Closeable { } mInputStream = new BluetoothInputStream(this); mOutputStream = new BluetoothOutputStream(this); + mClosed = false; + mLock = new ReentrantReadWriteLock(); } /** @@ -132,7 +143,13 @@ public final class BluetoothSocket implements Closeable { * @throws IOException on error, for example connection failure */ public void connect() throws IOException { - connectNative(); + mLock.readLock().lock(); + try { + if (mClosed) throw new IOException("socket closed"); + connectNative(); + } finally { + mLock.readLock().unlock(); + } } /** @@ -141,7 +158,24 @@ public final class BluetoothSocket implements Closeable { * throw an IOException. */ public void close() throws IOException { - closeNative(); + // abort blocking operations on the socket + mLock.readLock().lock(); + try { + if (mClosed) return; + abortNative(); + } finally { + mLock.readLock().unlock(); + } + + // all native calls are guarenteed to immediately return after + // abortNative(), so this lock should immediatley acquire + mLock.writeLock().lock(); + try { + mClosed = true; + destroyNative(); + } finally { + mLock.writeLock().unlock(); + } } /** @@ -174,14 +208,64 @@ public final class BluetoothSocket implements Closeable { return mOutputStream; } + /*package*/ void bindListen() throws IOException { + mLock.readLock().lock(); + try { + if (mClosed) throw new IOException("socket closed"); + bindListenNative(); + } finally { + mLock.readLock().unlock(); + } + } + + /*package*/ BluetoothSocket accept(int timeout) throws IOException { + mLock.readLock().lock(); + try { + if (mClosed) throw new IOException("socket closed"); + return acceptNative(timeout); + } finally { + mLock.readLock().unlock(); + } + } + + /*package*/ int available() throws IOException { + mLock.readLock().lock(); + try { + if (mClosed) throw new IOException("socket closed"); + return availableNative(); + } finally { + mLock.readLock().unlock(); + } + } + + /*package*/ int read(byte[] b, int offset, int length) throws IOException { + mLock.readLock().lock(); + try { + if (mClosed) throw new IOException("socket closed"); + return readNative(b, offset, length); + } finally { + mLock.readLock().unlock(); + } + } + + /*package*/ int write(byte[] b, int offset, int length) throws IOException { + mLock.readLock().lock(); + try { + if (mClosed) throw new IOException("socket closed"); + return writeNative(b, offset, length); + } finally { + mLock.readLock().unlock(); + } + } + private native void initSocketNative() throws IOException; private native void initSocketFromFdNative(int fd) throws IOException; private native void connectNative() throws IOException; - /*package*/ native void bindListenNative() throws IOException; - /*package*/ native BluetoothSocket acceptNative(int timeout) throws IOException; - /*package*/ native int availableNative() throws IOException; - /*package*/ native int readNative(byte[] b, int offset, int length) throws IOException; - /*package*/ native int writeNative(byte[] b, int offset, int length) throws IOException; - /*package*/ native void closeNative() throws IOException; + private native void bindListenNative() throws IOException; + 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; } |
