Loading android/app/src/com/android/bluetooth/ObexServerSockets.java +27 −6 Original line number Diff line number Diff line Loading @@ -80,7 +80,20 @@ public class ObexServerSockets { */ public static ObexServerSockets create(IObexConnectionHandler validator) { return create(validator, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP); BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, true); } /** * Creates an Insecure RFCOMM {@link BluetoothServerSocket} and a L2CAP * {@link BluetoothServerSocket} * @param validator a reference to the {@link IObexConnectionHandler} object to call * to validate an incoming connection. * @return a reference to a {@link ObexServerSockets} object instance. * @throws IOException if it occurs while creating the {@link BluetoothServerSocket}s. */ public static ObexServerSockets createInsecure(IObexConnectionHandler validator) { return create(validator, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false); } /** Loading @@ -90,14 +103,15 @@ public class ObexServerSockets { * {@link #getRfcommChannel()} in {@link ObexServerSockets}. * @param validator a reference to the {@link IObexConnectionHandler} object to call * to validate an incoming connection. * @param isSecure boolean flag to determine whther socket would be secured or inseucure. * @return a reference to a {@link ObexServerSockets} object instance. * @throws IOException if it occurs while creating the {@link BluetoothServerSocket}s. * * TODO: Make public when it becomes possible to determine that the listen-call * failed due to channel-in-use. */ private static ObexServerSockets create(IObexConnectionHandler validator, int rfcommChannel, int l2capPsm) { private static ObexServerSockets create( IObexConnectionHandler validator, int rfcommChannel, int l2capPsm, boolean isSecure) { if(D) Log.d(STAG,"create(rfcomm = " +rfcommChannel + ", l2capPsm = " + l2capPsm +")"); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); if(bt == null) { Loading @@ -113,10 +127,18 @@ public class ObexServerSockets { initSocketOK = true; try { if(rfcommSocket == null) { if (isSecure) { rfcommSocket = bt.listenUsingRfcommOn(rfcommChannel); } else { rfcommSocket = bt.listenUsingInsecureRfcommOn(rfcommChannel); } } if(l2capSocket == null) { if (isSecure) { l2capSocket = bt.listenUsingL2capOn(l2capPsm); } else { l2capSocket = bt.listenUsingInsecureL2capOn(l2capPsm); } } } catch (IOException e) { Log.e(STAG, "Error create ServerSockets ",e); Loading Loading @@ -380,5 +402,4 @@ public class ObexServerSockets { } } } } android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java +12 −2 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import javax.obex.ServerRequestHandler; import javax.obex.ServerSession; import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.ObexServerSockets; /** * This class runs as an OBEX server Loading Loading @@ -97,9 +98,13 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler implemen boolean mTimeoutMsgSent = false; public BluetoothOppObexServerSession(Context context, ObexTransport transport) { private ObexServerSockets mServerSocket; public BluetoothOppObexServerSession( Context context, ObexTransport transport, ObexServerSockets serverSocket) { mContext = context; mTransport = transport; mServerSocket = serverSocket; PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); } Loading Loading @@ -583,9 +588,14 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler implemen @Override public void onClose() { if (V) Log.v(TAG, "release WakeLock"); if (D) Log.d(TAG, "onClose"); releaseWakeLocks(); if (mServerSocket != null) { if (D) Log.d(TAG, "prepareForNewConnect"); mServerSocket.prepareForNewConnect(); } /* onClose could happen even before start() where mCallback is set */ if (mCallback != null) { Message msg = Message.obtain(mCallback); Loading android/app/src/com/android/bluetooth/opp/BluetoothOppRfcommListener.javadeleted 100755 → 0 +0 −230 Original line number Diff line number Diff line /* * Copyright (c) 2008-2009, Motorola, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the Motorola, Inc. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package com.android.bluetooth.opp; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import com.android.bluetooth.BluetoothObexTransport; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUuid; import android.os.Handler; import android.os.Message; import android.util.Log; /** * This class listens on OPUSH channel for incoming connection */ public class BluetoothOppRfcommListener { private static final String TAG = "BtOppRfcommListener"; private static final boolean V = Constants.VERBOSE; public static final int MSG_INCOMING_BTOPP_CONNECTION = 100; private volatile boolean mInterrupted; private Thread mSocketAcceptThread; private Handler mCallback; private static final int CREATE_RETRY_TIME = 10; private final BluetoothAdapter mAdapter; private BluetoothServerSocket mBtServerSocket = null; private ServerSocket mTcpServerSocket = null; public BluetoothOppRfcommListener(BluetoothAdapter adapter) { mAdapter = adapter; } public synchronized boolean start(Handler callback) { if (mSocketAcceptThread == null) { mCallback = callback; mSocketAcceptThread = new Thread(TAG) { public void run() { if (Constants.USE_TCP_DEBUG) { try { if (V) Log.v(TAG, "Create TCP ServerSocket"); mTcpServerSocket = new ServerSocket(Constants.TCP_DEBUG_PORT, 1); } catch (IOException e) { Log.e(TAG, "Error listing on port" + Constants.TCP_DEBUG_PORT); mInterrupted = true; } while (!mInterrupted) { try { Socket clientSocket = mTcpServerSocket.accept(); if (V) Log.v(TAG, "Socket connected!"); TestTcpTransport transport = new TestTcpTransport(clientSocket); Message msg = Message.obtain(); msg.setTarget(mCallback); msg.what = MSG_INCOMING_BTOPP_CONNECTION; msg.obj = transport; msg.sendToTarget(); } catch (IOException e) { Log.e(TAG, "Error accept connection " + e); } } if (V) Log.v(TAG, "TCP listen thread finished"); } else { boolean serverOK = true; /* * it's possible that create will fail in some cases. * retry for 10 times */ for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) { try { if (V) Log.v(TAG, "Starting RFCOMM listener...."); mBtServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord("OBEX Object Push", BluetoothUuid.ObexObjectPush.getUuid()); if (V) Log.v(TAG, "Started RFCOMM listener...."); } catch (IOException e1) { Log.e(TAG, "Error create RfcommServerSocket " + e1); serverOK = false; } if (!serverOK) { synchronized (this) { try { if (V) Log.v(TAG, "Wait 300 ms"); Thread.sleep(300); } catch (InterruptedException e) { Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); mInterrupted = true; } } } else { break; } } if (!serverOK) { Log.e(TAG, "Error start listening after " + CREATE_RETRY_TIME + " try"); mInterrupted = true; } if (!mInterrupted) { Log.i(TAG, "Accept thread started."); } BluetoothSocket clientSocket; while (!mInterrupted) { try { if (V) Log.v(TAG, "Accepting connection..."); if (mBtServerSocket == null) { } BluetoothServerSocket sSocket = mBtServerSocket; if (sSocket ==null) { mInterrupted = true; } else { clientSocket = sSocket.accept(); if (V) Log.v(TAG, "Accepted connection from " + clientSocket.getRemoteDevice()); BluetoothObexTransport transport = new BluetoothObexTransport( clientSocket); Message msg = Message.obtain(); msg.setTarget(mCallback); msg.what = MSG_INCOMING_BTOPP_CONNECTION; msg.obj = transport; msg.sendToTarget(); } } catch (IOException e) { Log.e(TAG, "Error accept connection " + e); try { Thread.sleep(500); } catch (InterruptedException ie) {} } } Log.i(TAG, "BluetoothSocket listen thread finished"); } } }; mInterrupted = false; if(!Constants.USE_TCP_SIMPLE_SERVER) { mSocketAcceptThread.start(); } } return true; } public synchronized void stop() { if (mSocketAcceptThread != null) { Log.i(TAG, "stopping Accept Thread"); mInterrupted = true; if (Constants.USE_TCP_DEBUG) { if (V) Log.v(TAG, "close mTcpServerSocket"); if (mTcpServerSocket != null) { try { mTcpServerSocket.close(); mTcpServerSocket = null; } catch (IOException e) { Log.e(TAG, "Error close mTcpServerSocket"); } } } else { if (V) Log.v(TAG, "close mBtServerSocket"); if (mBtServerSocket != null) { try { mBtServerSocket.close(); mBtServerSocket = null; } catch (IOException e) { Log.e(TAG, "Error close mBtServerSocket"); } } } try { mSocketAcceptThread.interrupt(); if (V) Log.v(TAG, "waiting for thread to terminate"); //mSocketAcceptThread.join(JOIN_TIMEOUT_MS); mSocketAcceptThread.join(); if (V) Log.v(TAG, "done waiting for thread to terminate"); mSocketAcceptThread = null; mCallback = null; } catch (InterruptedException e) { if (V) Log.v(TAG, "Interrupted waiting for Accept Thread to join"); } } } } android/app/src/com/android/bluetooth/opp/BluetoothOppService.java +104 −13 Original line number Diff line number Diff line Loading @@ -37,7 +37,10 @@ import javax.obex.ObexTransport; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevicePicker; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; Loading @@ -55,20 +58,25 @@ import android.os.IBinder; import android.os.Message; import android.os.PowerManager; import android.util.Log; import android.widget.Toast; import android.os.Process; import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.IObexConnectionHandler; import com.android.bluetooth.ObexServerSockets; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; import java.io.IOException; import java.util.ArrayList; import com.android.bluetooth.sdp.SdpManager; /** * Performs the background Bluetooth OPP transfer. It also starts thread to * accept incoming OPP connection. */ public class BluetoothOppService extends ProfileService { public class BluetoothOppService extends ProfileService implements IObexConnectionHandler { private static final boolean D = Constants.DEBUG; private static final boolean V = Constants.VERBOSE; Loading Loading @@ -120,8 +128,6 @@ public class BluetoothOppService extends ProfileService { private PowerManager mPowerManager; private BluetoothOppRfcommListener mSocketListener; private boolean mListenStarted = false; private boolean mMediaScanInProgress; Loading @@ -130,6 +136,8 @@ public class BluetoothOppService extends ProfileService { private ObexTransport mPendingConnection = null; private int mOppSdpHandle = -1; /* * TODO No support for queue incoming from multiple devices. * Make an array list of server session to support receiving queue from Loading @@ -145,7 +153,6 @@ public class BluetoothOppService extends ProfileService { @Override protected void create() { if (V) Log.v(TAG, "onCreate"); mSocketListener = new BluetoothOppRfcommListener(mAdapter); mShares = Lists.newArrayList(); mBatchs = Lists.newArrayList(); mObserver = new BluetoothShareContentObserver(); Loading Loading @@ -205,6 +212,8 @@ public class BluetoothOppService extends ProfileService { private static final int MSG_INCOMING_CONNECTION_RETRY = 4; private static final int MSG_INCOMING_BTOPP_CONNECTION = 100; private static final int STOP_LISTENER = 200; private Handler mHandler = new Handler() { Loading @@ -212,9 +221,15 @@ public class BluetoothOppService extends ProfileService { public void handleMessage(Message msg) { switch (msg.what) { case STOP_LISTENER: if(mSocketListener != null){ mSocketListener.stop(); } if (mAdapter != null && mOppSdpHandle >= 0 && SdpManager.getDefaultManager() != null) { if (D) Log.d(TAG, "Removing SDP record mOppSdpHandle :" + mOppSdpHandle); boolean status = SdpManager.getDefaultManager().removeSdpRecord(mOppSdpHandle); Log.d(TAG, "RemoveSDPrecord returns " + status); mOppSdpHandle = -1; } stopListeners(); mListenStarted = false; //Stop Active INBOUND Transfer if(mServerTransfer != null){ Loading Loading @@ -268,9 +283,10 @@ public class BluetoothOppService extends ProfileService { mMediaScanInProgress = false; } break; case BluetoothOppRfcommListener.MSG_INCOMING_BTOPP_CONNECTION: case MSG_INCOMING_BTOPP_CONNECTION: if (D) Log.d(TAG, "Get incoming connection"); ObexTransport transport = (ObexTransport)msg.obj; /* * Strategy for incoming connections: * 1. If there is no ongoing transfer, no on-hold connection, start it Loading Loading @@ -330,10 +346,19 @@ public class BluetoothOppService extends ProfileService { } }; private ObexServerSockets mServerSocket; private void startSocketListener() { if (V) Log.v(TAG, "start RfcommListener"); mSocketListener.start(mHandler); if (V) Log.v(TAG, "RfcommListener started"); if (D) Log.d(TAG, "start Socket Listeners"); stopListeners(); mServerSocket = ObexServerSockets.createInsecure(this); SdpManager sdpManager = SdpManager.getDefaultManager(); if (sdpManager == null || mServerSocket == null) { Log.e(TAG, "ERROR:serversocket object is NULL sdp manager :" + sdpManager + " mServerSocket:" + mServerSocket); return; } sdpManager.createOppOpsRecord("OBEX Object Push", mServerSocket.getRfcommChannel(), mServerSocket.getL2capPsm(), 0x0102, SdpManager.OPP_FORMAT_ALL); } @Override Loading @@ -341,8 +366,7 @@ public class BluetoothOppService extends ProfileService { if (V) Log.v(TAG, "onDestroy"); getContentResolver().unregisterContentObserver(mObserver); unregisterReceiver(mBluetoothReceiver); mSocketListener.stop(); stopListeners(); if (mBatchs != null) { mBatchs.clear(); } Loading @@ -357,7 +381,7 @@ public class BluetoothOppService extends ProfileService { /* suppose we auto accept an incoming OPUSH connection */ private void createServerSession(ObexTransport transport) { mServerSession = new BluetoothOppObexServerSession(this, transport); mServerSession = new BluetoothOppObexServerSession(this, transport, mServerSocket); mServerSession.preStart(); if (D) Log.d(TAG, "Get ServerSession " + mServerSession.toString() + " for incoming connection" + transport.toString()); Loading Loading @@ -1029,4 +1053,71 @@ public class BluetoothOppService extends ProfileService { } } } private void stopListeners() { if (mServerSocket != null) { mServerSocket.shutdown(false); mServerSocket = null; } if (D) Log.d(TAG, "stopListeners mServerSocket :" + mServerSocket); } private BluetoothServerSocket getConnectionSocket(boolean isL2cap) { BluetoothServerSocket socket = null; boolean socketCreate = false; final int CREATE_RETRY_TIME = 10; // It's possible that create will fail in some cases. retry for 10 times for (int i = 0; i < CREATE_RETRY_TIME; i++) { if (D) Log.d(TAG, " CREATE_RETRY_TIME " + i); socketCreate = true; try { socket = (isL2cap) ? mAdapter.listenUsingInsecureL2capOn( BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) : mAdapter.listenUsingInsecureRfcommOn( BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP); } catch (IOException e) { Log.e(TAG, "Error create ServerSockets ", e); socketCreate = false; } if (!socketCreate) { // Need to break out of this loop if BT is being turned off. int state = mAdapter.getState(); if ((state != BluetoothAdapter.STATE_TURNING_ON) && (state != BluetoothAdapter.STATE_ON)) { Log.e(TAG, "initServerSockets failed as Bt State :" + state); break; } try { if (V) Log.d(TAG, "waiting 300 ms..."); Thread.sleep(300); } catch (InterruptedException e) { Log.e(TAG, "create() was interrupted"); } } else { break; } } if (D) Log.d(TAG, " socketCreate :" + socketCreate + " isL2cap :" + isL2cap); return socket; } @Override public boolean onConnect(BluetoothDevice device, BluetoothSocket socket) { if (D) Log.d(TAG, " onConnect BluetoothSocket :" + socket + " \n :device :" + device); BluetoothObexTransport transport = new BluetoothObexTransport(socket); Message msg = Message.obtain(); msg.setTarget(mHandler); msg.what = MSG_INCOMING_BTOPP_CONNECTION; msg.obj = transport; msg.sendToTarget(); return true; } @Override public void onAcceptFailed() { // TODO Auto-generated method stub Log.d(TAG, " onAcceptFailed:"); mHandler.sendMessage(mHandler.obtainMessage(START_LISTENER)); } } Loading
android/app/src/com/android/bluetooth/ObexServerSockets.java +27 −6 Original line number Diff line number Diff line Loading @@ -80,7 +80,20 @@ public class ObexServerSockets { */ public static ObexServerSockets create(IObexConnectionHandler validator) { return create(validator, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP); BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, true); } /** * Creates an Insecure RFCOMM {@link BluetoothServerSocket} and a L2CAP * {@link BluetoothServerSocket} * @param validator a reference to the {@link IObexConnectionHandler} object to call * to validate an incoming connection. * @return a reference to a {@link ObexServerSockets} object instance. * @throws IOException if it occurs while creating the {@link BluetoothServerSocket}s. */ public static ObexServerSockets createInsecure(IObexConnectionHandler validator) { return create(validator, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false); } /** Loading @@ -90,14 +103,15 @@ public class ObexServerSockets { * {@link #getRfcommChannel()} in {@link ObexServerSockets}. * @param validator a reference to the {@link IObexConnectionHandler} object to call * to validate an incoming connection. * @param isSecure boolean flag to determine whther socket would be secured or inseucure. * @return a reference to a {@link ObexServerSockets} object instance. * @throws IOException if it occurs while creating the {@link BluetoothServerSocket}s. * * TODO: Make public when it becomes possible to determine that the listen-call * failed due to channel-in-use. */ private static ObexServerSockets create(IObexConnectionHandler validator, int rfcommChannel, int l2capPsm) { private static ObexServerSockets create( IObexConnectionHandler validator, int rfcommChannel, int l2capPsm, boolean isSecure) { if(D) Log.d(STAG,"create(rfcomm = " +rfcommChannel + ", l2capPsm = " + l2capPsm +")"); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); if(bt == null) { Loading @@ -113,10 +127,18 @@ public class ObexServerSockets { initSocketOK = true; try { if(rfcommSocket == null) { if (isSecure) { rfcommSocket = bt.listenUsingRfcommOn(rfcommChannel); } else { rfcommSocket = bt.listenUsingInsecureRfcommOn(rfcommChannel); } } if(l2capSocket == null) { if (isSecure) { l2capSocket = bt.listenUsingL2capOn(l2capPsm); } else { l2capSocket = bt.listenUsingInsecureL2capOn(l2capPsm); } } } catch (IOException e) { Log.e(STAG, "Error create ServerSockets ",e); Loading Loading @@ -380,5 +402,4 @@ public class ObexServerSockets { } } } }
android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java +12 −2 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import javax.obex.ServerRequestHandler; import javax.obex.ServerSession; import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.ObexServerSockets; /** * This class runs as an OBEX server Loading Loading @@ -97,9 +98,13 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler implemen boolean mTimeoutMsgSent = false; public BluetoothOppObexServerSession(Context context, ObexTransport transport) { private ObexServerSockets mServerSocket; public BluetoothOppObexServerSession( Context context, ObexTransport transport, ObexServerSockets serverSocket) { mContext = context; mTransport = transport; mServerSocket = serverSocket; PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); } Loading Loading @@ -583,9 +588,14 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler implemen @Override public void onClose() { if (V) Log.v(TAG, "release WakeLock"); if (D) Log.d(TAG, "onClose"); releaseWakeLocks(); if (mServerSocket != null) { if (D) Log.d(TAG, "prepareForNewConnect"); mServerSocket.prepareForNewConnect(); } /* onClose could happen even before start() where mCallback is set */ if (mCallback != null) { Message msg = Message.obtain(mCallback); Loading
android/app/src/com/android/bluetooth/opp/BluetoothOppRfcommListener.javadeleted 100755 → 0 +0 −230 Original line number Diff line number Diff line /* * Copyright (c) 2008-2009, Motorola, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the Motorola, Inc. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package com.android.bluetooth.opp; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import com.android.bluetooth.BluetoothObexTransport; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUuid; import android.os.Handler; import android.os.Message; import android.util.Log; /** * This class listens on OPUSH channel for incoming connection */ public class BluetoothOppRfcommListener { private static final String TAG = "BtOppRfcommListener"; private static final boolean V = Constants.VERBOSE; public static final int MSG_INCOMING_BTOPP_CONNECTION = 100; private volatile boolean mInterrupted; private Thread mSocketAcceptThread; private Handler mCallback; private static final int CREATE_RETRY_TIME = 10; private final BluetoothAdapter mAdapter; private BluetoothServerSocket mBtServerSocket = null; private ServerSocket mTcpServerSocket = null; public BluetoothOppRfcommListener(BluetoothAdapter adapter) { mAdapter = adapter; } public synchronized boolean start(Handler callback) { if (mSocketAcceptThread == null) { mCallback = callback; mSocketAcceptThread = new Thread(TAG) { public void run() { if (Constants.USE_TCP_DEBUG) { try { if (V) Log.v(TAG, "Create TCP ServerSocket"); mTcpServerSocket = new ServerSocket(Constants.TCP_DEBUG_PORT, 1); } catch (IOException e) { Log.e(TAG, "Error listing on port" + Constants.TCP_DEBUG_PORT); mInterrupted = true; } while (!mInterrupted) { try { Socket clientSocket = mTcpServerSocket.accept(); if (V) Log.v(TAG, "Socket connected!"); TestTcpTransport transport = new TestTcpTransport(clientSocket); Message msg = Message.obtain(); msg.setTarget(mCallback); msg.what = MSG_INCOMING_BTOPP_CONNECTION; msg.obj = transport; msg.sendToTarget(); } catch (IOException e) { Log.e(TAG, "Error accept connection " + e); } } if (V) Log.v(TAG, "TCP listen thread finished"); } else { boolean serverOK = true; /* * it's possible that create will fail in some cases. * retry for 10 times */ for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) { try { if (V) Log.v(TAG, "Starting RFCOMM listener...."); mBtServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord("OBEX Object Push", BluetoothUuid.ObexObjectPush.getUuid()); if (V) Log.v(TAG, "Started RFCOMM listener...."); } catch (IOException e1) { Log.e(TAG, "Error create RfcommServerSocket " + e1); serverOK = false; } if (!serverOK) { synchronized (this) { try { if (V) Log.v(TAG, "Wait 300 ms"); Thread.sleep(300); } catch (InterruptedException e) { Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); mInterrupted = true; } } } else { break; } } if (!serverOK) { Log.e(TAG, "Error start listening after " + CREATE_RETRY_TIME + " try"); mInterrupted = true; } if (!mInterrupted) { Log.i(TAG, "Accept thread started."); } BluetoothSocket clientSocket; while (!mInterrupted) { try { if (V) Log.v(TAG, "Accepting connection..."); if (mBtServerSocket == null) { } BluetoothServerSocket sSocket = mBtServerSocket; if (sSocket ==null) { mInterrupted = true; } else { clientSocket = sSocket.accept(); if (V) Log.v(TAG, "Accepted connection from " + clientSocket.getRemoteDevice()); BluetoothObexTransport transport = new BluetoothObexTransport( clientSocket); Message msg = Message.obtain(); msg.setTarget(mCallback); msg.what = MSG_INCOMING_BTOPP_CONNECTION; msg.obj = transport; msg.sendToTarget(); } } catch (IOException e) { Log.e(TAG, "Error accept connection " + e); try { Thread.sleep(500); } catch (InterruptedException ie) {} } } Log.i(TAG, "BluetoothSocket listen thread finished"); } } }; mInterrupted = false; if(!Constants.USE_TCP_SIMPLE_SERVER) { mSocketAcceptThread.start(); } } return true; } public synchronized void stop() { if (mSocketAcceptThread != null) { Log.i(TAG, "stopping Accept Thread"); mInterrupted = true; if (Constants.USE_TCP_DEBUG) { if (V) Log.v(TAG, "close mTcpServerSocket"); if (mTcpServerSocket != null) { try { mTcpServerSocket.close(); mTcpServerSocket = null; } catch (IOException e) { Log.e(TAG, "Error close mTcpServerSocket"); } } } else { if (V) Log.v(TAG, "close mBtServerSocket"); if (mBtServerSocket != null) { try { mBtServerSocket.close(); mBtServerSocket = null; } catch (IOException e) { Log.e(TAG, "Error close mBtServerSocket"); } } } try { mSocketAcceptThread.interrupt(); if (V) Log.v(TAG, "waiting for thread to terminate"); //mSocketAcceptThread.join(JOIN_TIMEOUT_MS); mSocketAcceptThread.join(); if (V) Log.v(TAG, "done waiting for thread to terminate"); mSocketAcceptThread = null; mCallback = null; } catch (InterruptedException e) { if (V) Log.v(TAG, "Interrupted waiting for Accept Thread to join"); } } } }
android/app/src/com/android/bluetooth/opp/BluetoothOppService.java +104 −13 Original line number Diff line number Diff line Loading @@ -37,7 +37,10 @@ import javax.obex.ObexTransport; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevicePicker; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; Loading @@ -55,20 +58,25 @@ import android.os.IBinder; import android.os.Message; import android.os.PowerManager; import android.util.Log; import android.widget.Toast; import android.os.Process; import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.IObexConnectionHandler; import com.android.bluetooth.ObexServerSockets; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; import java.io.IOException; import java.util.ArrayList; import com.android.bluetooth.sdp.SdpManager; /** * Performs the background Bluetooth OPP transfer. It also starts thread to * accept incoming OPP connection. */ public class BluetoothOppService extends ProfileService { public class BluetoothOppService extends ProfileService implements IObexConnectionHandler { private static final boolean D = Constants.DEBUG; private static final boolean V = Constants.VERBOSE; Loading Loading @@ -120,8 +128,6 @@ public class BluetoothOppService extends ProfileService { private PowerManager mPowerManager; private BluetoothOppRfcommListener mSocketListener; private boolean mListenStarted = false; private boolean mMediaScanInProgress; Loading @@ -130,6 +136,8 @@ public class BluetoothOppService extends ProfileService { private ObexTransport mPendingConnection = null; private int mOppSdpHandle = -1; /* * TODO No support for queue incoming from multiple devices. * Make an array list of server session to support receiving queue from Loading @@ -145,7 +153,6 @@ public class BluetoothOppService extends ProfileService { @Override protected void create() { if (V) Log.v(TAG, "onCreate"); mSocketListener = new BluetoothOppRfcommListener(mAdapter); mShares = Lists.newArrayList(); mBatchs = Lists.newArrayList(); mObserver = new BluetoothShareContentObserver(); Loading Loading @@ -205,6 +212,8 @@ public class BluetoothOppService extends ProfileService { private static final int MSG_INCOMING_CONNECTION_RETRY = 4; private static final int MSG_INCOMING_BTOPP_CONNECTION = 100; private static final int STOP_LISTENER = 200; private Handler mHandler = new Handler() { Loading @@ -212,9 +221,15 @@ public class BluetoothOppService extends ProfileService { public void handleMessage(Message msg) { switch (msg.what) { case STOP_LISTENER: if(mSocketListener != null){ mSocketListener.stop(); } if (mAdapter != null && mOppSdpHandle >= 0 && SdpManager.getDefaultManager() != null) { if (D) Log.d(TAG, "Removing SDP record mOppSdpHandle :" + mOppSdpHandle); boolean status = SdpManager.getDefaultManager().removeSdpRecord(mOppSdpHandle); Log.d(TAG, "RemoveSDPrecord returns " + status); mOppSdpHandle = -1; } stopListeners(); mListenStarted = false; //Stop Active INBOUND Transfer if(mServerTransfer != null){ Loading Loading @@ -268,9 +283,10 @@ public class BluetoothOppService extends ProfileService { mMediaScanInProgress = false; } break; case BluetoothOppRfcommListener.MSG_INCOMING_BTOPP_CONNECTION: case MSG_INCOMING_BTOPP_CONNECTION: if (D) Log.d(TAG, "Get incoming connection"); ObexTransport transport = (ObexTransport)msg.obj; /* * Strategy for incoming connections: * 1. If there is no ongoing transfer, no on-hold connection, start it Loading Loading @@ -330,10 +346,19 @@ public class BluetoothOppService extends ProfileService { } }; private ObexServerSockets mServerSocket; private void startSocketListener() { if (V) Log.v(TAG, "start RfcommListener"); mSocketListener.start(mHandler); if (V) Log.v(TAG, "RfcommListener started"); if (D) Log.d(TAG, "start Socket Listeners"); stopListeners(); mServerSocket = ObexServerSockets.createInsecure(this); SdpManager sdpManager = SdpManager.getDefaultManager(); if (sdpManager == null || mServerSocket == null) { Log.e(TAG, "ERROR:serversocket object is NULL sdp manager :" + sdpManager + " mServerSocket:" + mServerSocket); return; } sdpManager.createOppOpsRecord("OBEX Object Push", mServerSocket.getRfcommChannel(), mServerSocket.getL2capPsm(), 0x0102, SdpManager.OPP_FORMAT_ALL); } @Override Loading @@ -341,8 +366,7 @@ public class BluetoothOppService extends ProfileService { if (V) Log.v(TAG, "onDestroy"); getContentResolver().unregisterContentObserver(mObserver); unregisterReceiver(mBluetoothReceiver); mSocketListener.stop(); stopListeners(); if (mBatchs != null) { mBatchs.clear(); } Loading @@ -357,7 +381,7 @@ public class BluetoothOppService extends ProfileService { /* suppose we auto accept an incoming OPUSH connection */ private void createServerSession(ObexTransport transport) { mServerSession = new BluetoothOppObexServerSession(this, transport); mServerSession = new BluetoothOppObexServerSession(this, transport, mServerSocket); mServerSession.preStart(); if (D) Log.d(TAG, "Get ServerSession " + mServerSession.toString() + " for incoming connection" + transport.toString()); Loading Loading @@ -1029,4 +1053,71 @@ public class BluetoothOppService extends ProfileService { } } } private void stopListeners() { if (mServerSocket != null) { mServerSocket.shutdown(false); mServerSocket = null; } if (D) Log.d(TAG, "stopListeners mServerSocket :" + mServerSocket); } private BluetoothServerSocket getConnectionSocket(boolean isL2cap) { BluetoothServerSocket socket = null; boolean socketCreate = false; final int CREATE_RETRY_TIME = 10; // It's possible that create will fail in some cases. retry for 10 times for (int i = 0; i < CREATE_RETRY_TIME; i++) { if (D) Log.d(TAG, " CREATE_RETRY_TIME " + i); socketCreate = true; try { socket = (isL2cap) ? mAdapter.listenUsingInsecureL2capOn( BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) : mAdapter.listenUsingInsecureRfcommOn( BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP); } catch (IOException e) { Log.e(TAG, "Error create ServerSockets ", e); socketCreate = false; } if (!socketCreate) { // Need to break out of this loop if BT is being turned off. int state = mAdapter.getState(); if ((state != BluetoothAdapter.STATE_TURNING_ON) && (state != BluetoothAdapter.STATE_ON)) { Log.e(TAG, "initServerSockets failed as Bt State :" + state); break; } try { if (V) Log.d(TAG, "waiting 300 ms..."); Thread.sleep(300); } catch (InterruptedException e) { Log.e(TAG, "create() was interrupted"); } } else { break; } } if (D) Log.d(TAG, " socketCreate :" + socketCreate + " isL2cap :" + isL2cap); return socket; } @Override public boolean onConnect(BluetoothDevice device, BluetoothSocket socket) { if (D) Log.d(TAG, " onConnect BluetoothSocket :" + socket + " \n :device :" + device); BluetoothObexTransport transport = new BluetoothObexTransport(socket); Message msg = Message.obtain(); msg.setTarget(mHandler); msg.what = MSG_INCOMING_BTOPP_CONNECTION; msg.obj = transport; msg.sendToTarget(); return true; } @Override public void onAcceptFailed() { // TODO Auto-generated method stub Log.d(TAG, " onAcceptFailed:"); mHandler.sendMessage(mHandler.obtainMessage(START_LISTENER)); } }