diff options
author | Jessica Wagantall <jwagantall@cyngn.com> | 2016-05-16 11:28:05 -0700 |
---|---|---|
committer | Jessica Wagantall <jwagantall@cyngn.com> | 2016-05-16 11:38:55 -0700 |
commit | ed52dff0f25c14b8478d2b96be962f6f25b29f0c (patch) | |
tree | 626532699aa6e40a3c6c8264298899a7261bc095 | |
parent | 39cd78c8f9508b4874b09aa47a0796fb2728333f (diff) | |
parent | 38516fd6ef6d2849ea0369413377e4e8a5632c2b (diff) | |
download | android_packages_apps_Bluetooth-ed52dff0f25c14b8478d2b96be962f6f25b29f0c.tar.gz android_packages_apps_Bluetooth-ed52dff0f25c14b8478d2b96be962f6f25b29f0c.tar.bz2 android_packages_apps_Bluetooth-ed52dff0f25c14b8478d2b96be962f6f25b29f0c.zip |
Merge remote-tracking branch 'github/cm-13.0' into HEAD
OPO-618
Change-Id: I11479a6ae1f1b9e0fa1561e8992a3da929dfc8f6
24 files changed, 403 insertions, 221 deletions
diff --git a/jni/com_android_bluetooth_a2dp.cpp b/jni/com_android_bluetooth_a2dp.cpp index df8fe9837..565cd99a9 100644 --- a/jni/com_android_bluetooth_a2dp.cpp +++ b/jni/com_android_bluetooth_a2dp.cpp @@ -27,6 +27,7 @@ #include "android_runtime/AndroidRuntime.h" #include <string.h> +#include <pthread.h> namespace android { static jmethodID method_onConnectionStateChanged; @@ -39,6 +40,8 @@ static const btav_interface_t *sBluetoothA2dpInterface = NULL; static jobject mCallbacksObj = NULL; static JNIEnv *sCallbackEnv = NULL; +static pthread_mutex_t mMutex = PTHREAD_MUTEX_INITIALIZER; + static bool checkCallbackThread() { // Always fetch the latest callbackEnv from AdapterService. // Caching this could cause this sCallbackEnv to go out-of-sync @@ -58,10 +61,6 @@ static void bta2dp_connection_state_callback(btav_connection_state_t state, bt_b ALOGI("%s", __FUNCTION__); - if (mCallbacksObj == NULL) { - ALOGE("Callbacks Obj is no more valid: '%s", __FUNCTION__); - return; - } if (!checkCallbackThread()) { \ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ return; \ @@ -75,8 +74,16 @@ static void bta2dp_connection_state_callback(btav_connection_state_t state, bt_b } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint) state, - addr); + + pthread_mutex_lock(&mMutex); + if (mCallbacksObj != NULL) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, + (jint) state, addr); + } else { + ALOGE("Callbacks Obj is no more valid: '%s", __FUNCTION__); + } + pthread_mutex_unlock(&mMutex); + checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); sCallbackEnv->DeleteLocalRef(addr); } @@ -86,10 +93,6 @@ static void bta2dp_audio_state_callback(btav_audio_state_t state, bt_bdaddr_t* b ALOGI("%s", __FUNCTION__); - if (mCallbacksObj == NULL) { - ALOGE("Callbacks Obj is no more valid: '%s", __FUNCTION__); - return; - } if (!checkCallbackThread()) { \ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ return; \ @@ -102,8 +105,16 @@ static void bta2dp_audio_state_callback(btav_audio_state_t state, bt_bdaddr_t* b } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, - addr); + + pthread_mutex_lock(&mMutex); + if (mCallbacksObj != NULL) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, + (jint) state, addr); + } else { + ALOGE("Callbacks Obj is no more valid: '%s", __FUNCTION__); + } + pthread_mutex_unlock(&mMutex); + checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); sCallbackEnv->DeleteLocalRef(addr); } @@ -113,10 +124,6 @@ static void bta2dp_connection_priority_callback(bt_bdaddr_t* bd_addr) { ALOGI("%s", __FUNCTION__); - if (mCallbacksObj == NULL) { - ALOGE("Callbacks Obj is no more valid: '%s", __FUNCTION__); - return; - } if (!checkCallbackThread()) { \ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ return; \ @@ -129,7 +136,16 @@ static void bta2dp_connection_priority_callback(bt_bdaddr_t* bd_addr) { } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCheckConnectionPriority, addr); + + pthread_mutex_lock(&mMutex); + if (mCallbacksObj != NULL) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCheckConnectionPriority, + addr); + } else { + ALOGE("Callbacks Obj is no more valid: '%s", __FUNCTION__); + } + pthread_mutex_unlock(&mMutex); + checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); sCallbackEnv->DeleteLocalRef(addr); } @@ -138,16 +154,20 @@ static void bta2dp_multicast_enabled_callback(int state) { ALOGI("%s", __FUNCTION__); - if (mCallbacksObj == NULL) { - ALOGE("Callbacks Obj is no more valid: '%s", __FUNCTION__); - return; - } if (!checkCallbackThread()) { \ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ return; \ } - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onMulticastStateChanged, state); + pthread_mutex_lock(&mMutex); + if (mCallbacksObj != NULL) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onMulticastStateChanged, + state); + } else { + ALOGE("Callbacks Obj is no more valid: '%s", __FUNCTION__); + } + pthread_mutex_unlock(&mMutex); + checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); } @@ -218,29 +238,32 @@ static void initNative(JNIEnv *env, jobject object, jint maxA2dpConnections, sBluetoothA2dpInterface = NULL; } - if (mCallbacksObj != NULL) { - ALOGW("Cleaning up A2DP callback object"); - env->DeleteGlobalRef(mCallbacksObj); - mCallbacksObj = NULL; - } - if ( (sBluetoothA2dpInterface = (btav_interface_t *) btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) { ALOGE("Failed to get Bluetooth A2DP Interface"); return; } + pthread_mutex_lock(&mMutex); + if (mCallbacksObj != NULL) { + ALOGW("Cleaning up A2DP callback object"); + env->DeleteGlobalRef(mCallbacksObj); + mCallbacksObj = NULL; + } mCallbacksObj = env->NewGlobalRef(object); + pthread_mutex_unlock(&mMutex); if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks, maxA2dpConnections, multiCastState)) != BT_STATUS_SUCCESS) { ALOGE("Failed to initialize Bluetooth A2DP, status: %d", status); sBluetoothA2dpInterface = NULL; + pthread_mutex_lock(&mMutex); if (mCallbacksObj != NULL) { ALOGW("Clean up A2DP callback object"); env->DeleteGlobalRef(mCallbacksObj); mCallbacksObj = NULL; } + pthread_mutex_unlock(&mMutex); return; } @@ -260,10 +283,12 @@ static void cleanupNative(JNIEnv *env, jobject object) { sBluetoothA2dpInterface = NULL; } + pthread_mutex_lock(&mMutex); if (mCallbacksObj != NULL) { env->DeleteGlobalRef(mCallbacksObj); mCallbacksObj = NULL; } + pthread_mutex_unlock(&mMutex); } static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) { diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp index 2544eb8d4..f18856c1a 100644 --- a/jni/com_android_bluetooth_btservice_AdapterService.cpp +++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp @@ -1256,6 +1256,27 @@ static jboolean factoryResetNative(JNIEnv *env, jobject obj) { return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } +static void interopDatabaseClearNative(JNIEnv *env, jobject obj) { + ALOGV("%s()", __FUNCTION__); + if (!sBluetoothInterface) return; + sBluetoothInterface->interop_database_clear(); +} + +static void interopDatabaseAddNative(JNIEnv *env, jobject obj, int feature, + jbyteArray address, int length) { + ALOGV("%s()", __FUNCTION__); + if (!sBluetoothInterface) return; + + jbyte *addr = env->GetByteArrayElements(address, NULL); + if (addr == NULL) { + jniThrowIOException(env, EINVAL); + return; + } + + sBluetoothInterface->interop_database_add(feature, (bt_bdaddr_t *)addr, length); + env->ReleaseByteArrayElements(address, addr, 0); +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"classInitNative", "()V", (void *) classInitNative}, @@ -1287,8 +1308,9 @@ static JNINativeMethod sMethods[] = { {"dumpNative", "(Ljava/io/FileDescriptor;)V", (void*) dumpNative}, {"factoryResetNative", "()Z", (void*)factoryResetNative}, {"getSocketOptNative", "(III[B)I", (void*) getSocketOptNative}, - {"setSocketOptNative", "(III[BI)I", (void*) setSocketOptNative} - + {"setSocketOptNative", "(III[BI)I", (void*) setSocketOptNative}, + {"interopDatabaseClearNative", "()V", (void*) interopDatabaseClearNative}, + {"interopDatabaseAddNative", "(I[BI)V", (void*) interopDatabaseAddNative} }; int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) diff --git a/jni/com_android_bluetooth_hdp.cpp b/jni/com_android_bluetooth_hdp.cpp index 81c8312c1..8556e6a89 100644 --- a/jni/com_android_bluetooth_hdp.cpp +++ b/jni/com_android_bluetooth_hdp.cpp @@ -195,7 +195,10 @@ static jint registerHealthAppNative(JNIEnv *env, jobject object, jint data_type, bthl_reg_param_t reg_param; int app_id; - if (!sBluetoothHdpInterface) return NULL; + if (!sBluetoothHdpInterface) { + ALOGE("Failed register health app. No Bluetooth Health Interface available"); + return -1; + } mdep_cfg.mdep_role = (bthl_mdep_role_t) role; mdep_cfg.data_type = data_type; diff --git a/src/com/android/bluetooth/Utils.java b/src/com/android/bluetooth/Utils.java index e87a6d9e3..6a467f9c3 100644 --- a/src/com/android/bluetooth/Utils.java +++ b/src/com/android/bluetooth/Utils.java @@ -204,19 +204,15 @@ final public class Utils { int callingUser = UserHandle.getCallingUserId(); int callingUid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); - Log.d(TAG,"callingUid =" + callingUid); try { // With calling identity cleared the current user is the foreground user. int foregroundUser = ActivityManager.getCurrentUser(); ok = (foregroundUser == callingUser); - Log.e(TAG, "foregroundUser =" + foregroundUser); - Log.e(TAG, "callingUser =" + callingUser); if (!ok) { // Always allow SystemUI/System access. int systemUiUid = ActivityThread.getPackageManager().getPackageUid( "com.android.systemui", UserHandle.USER_OWNER); - Log.d(TAG," systemUiUid :" + systemUiUid); ok = (systemUiUid == callingUid) || (Process.SYSTEM_UID == callingUid); } } catch (Exception ex) { diff --git a/src/com/android/bluetooth/avrcp/Avrcp.java b/src/com/android/bluetooth/avrcp/Avrcp.java index 2195559c0..dfdb42c27 100644 --- a/src/com/android/bluetooth/avrcp/Avrcp.java +++ b/src/com/android/bluetooth/avrcp/Avrcp.java @@ -4266,7 +4266,7 @@ public final class Avrcp { } } } - return !absVolumeSupported.contains((byte)0); + return !(absVolumeSupported.contains((byte)0) || absVolumeSupported.isEmpty()); } /** diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java index fba0c8933..ba597c3e4 100644 --- a/src/com/android/bluetooth/btservice/AdapterService.java +++ b/src/com/android/bluetooth/btservice/AdapterService.java @@ -395,6 +395,8 @@ public class AdapterService extends Service { mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STOPPED)); } else if (isTurningOn) { + updateInteropDatabase(); + //Process start pending //Check if all services are started if so, update state synchronized (mProfileServicesState) { @@ -421,6 +423,59 @@ public class AdapterService extends Service { } } + private void updateInteropDatabase() { + interopDatabaseClearNative(); + + String interop_string = Settings.Global.getString(getContentResolver(), + Settings.Global.BLUETOOTH_INTEROPERABILITY_LIST); + if (interop_string == null) return; + Log.d(TAG, "updateInteropDatabase: [" + interop_string + "]"); + + String[] entries = interop_string.split(";"); + for (String entry : entries) { + String[] tokens = entry.split(","); + if (tokens.length != 2) continue; + + // Get feature + int feature = 0; + try { + feature = Integer.parseInt(tokens[1]); + } catch (NumberFormatException e) { + Log.e(TAG, "updateInteropDatabase: Invalid feature '" + tokens[1] + "'"); + continue; + } + + // Get address bytes and length + int length = (tokens[0].length() + 1) / 3; + if (length < 1 || length > 6) { + Log.e(TAG, "updateInteropDatabase: Malformed address string '" + tokens[0] + "'"); + continue; + } + + byte[] addr = new byte[6]; + int offset = 0; + for (int i = 0; i < tokens[0].length(); ) { + if (tokens[0].charAt(i) == ':') { + i += 1; + } else { + try { + addr[offset++] = (byte) Integer.parseInt(tokens[0].substring(i, i + 2), 16); + } catch (NumberFormatException e) { + offset = 0; + break; + } + i += 2; + } + } + + // Check if address was parsed ok, otherwise, move on... + if (offset == 0) continue; + + // Add entry + interopDatabaseAddNative(feature, addr, length); + } + } + @Override public void onCreate() { super.onCreate(); @@ -2528,6 +2583,9 @@ public class AdapterService extends Service { private native void alarmFiredNative(); private native void dumpNative(FileDescriptor fd); + private native void interopDatabaseClearNative(); + private native void interopDatabaseAddNative(int feature, byte[] address, int length); + protected void finalize() { cleanup(); if (TRACE_REF) { diff --git a/src/com/android/bluetooth/map/BluetoothMapAppObserver.java b/src/com/android/bluetooth/map/BluetoothMapAppObserver.java index ee0075669..7721b7e9e 100644 --- a/src/com/android/bluetooth/map/BluetoothMapAppObserver.java +++ b/src/com/android/bluetooth/map/BluetoothMapAppObserver.java @@ -55,6 +55,7 @@ public class BluetoothMapAppObserver{ private PackageManager mPackageManager = null; BluetoothMapAccountEmailLoader mLoader; BluetoothMapService mMapService = null; + private boolean mRegisteredReceiver = false; public BluetoothMapAppObserver(final Context context, BluetoothMapService mapService) { mContext = context; @@ -283,12 +284,26 @@ public class BluetoothMapAppObserver{ } } }; - mContext.registerReceiver(mReceiver,intentFilter); + if (!mRegisteredReceiver) { + try { + mContext.registerReceiver(mReceiver,intentFilter); + mRegisteredReceiver = true; + } catch (Exception e) { + Log.e(TAG,"Unable to register MapAppObserver receiver",e); + } + } } private void removeReceiver(){ if(D)Log.d(TAG,"removeReceiver()\n"); - mContext.unregisterReceiver(mReceiver); + if (mRegisteredReceiver) { + try { + mRegisteredReceiver = false; + mContext.unregisterReceiver(mReceiver); + } catch (Exception e) { + Log.e(TAG,"Unable to unregister mapAppObserver receiver",e); + } + } } /** diff --git a/src/com/android/bluetooth/map/BluetoothMapContentObserver.java b/src/com/android/bluetooth/map/BluetoothMapContentObserver.java index 92899c23a..e8bde44af 100644 --- a/src/com/android/bluetooth/map/BluetoothMapContentObserver.java +++ b/src/com/android/bluetooth/map/BluetoothMapContentObserver.java @@ -3402,7 +3402,9 @@ public class BluetoothMapContentObserver { }; public void init() { - mSmsBroadcastReceiver.register(); + if (mSmsBroadcastReceiver != null ) { + mSmsBroadcastReceiver.register(); + } registerPhoneServiceStateListener(); mInitialized = true; } @@ -3410,7 +3412,9 @@ public class BluetoothMapContentObserver { public void deinit() { mInitialized = false; unregisterObserver(); - mSmsBroadcastReceiver.unregister(); + if (mSmsBroadcastReceiver != null ) { + mSmsBroadcastReceiver.unregister(); + } unRegisterPhoneServiceStateListener(); failPendingMessages(); removeDeletedMessages(); diff --git a/src/com/android/bluetooth/map/BluetoothMapMasInstance.java b/src/com/android/bluetooth/map/BluetoothMapMasInstance.java index 4cc371883..0fa12c607 100644 --- a/src/com/android/bluetooth/map/BluetoothMapMasInstance.java +++ b/src/com/android/bluetooth/map/BluetoothMapMasInstance.java @@ -421,6 +421,8 @@ public class BluetoothMapMasInstance implements IObexConnectionHandler { closeConnectionSocket(); + if(V) Log.v(TAG, "Block acceptThreads: TRUE"); + // Block to clean acceptThreads and avoid garbage collection closeServerSockets(true); } diff --git a/src/com/android/bluetooth/map/BluetoothMapService.java b/src/com/android/bluetooth/map/BluetoothMapService.java index 743c1b924..003687658 100755 --- a/src/com/android/bluetooth/map/BluetoothMapService.java +++ b/src/com/android/bluetooth/map/BluetoothMapService.java @@ -150,6 +150,7 @@ public class BluetoothMapService extends ProfileService { private boolean mSdpSearchInitiated = false; SdpMnsRecord mMnsRecord = null; private MapServiceMessageHandler mSessionStatusHandler; + private boolean mStartError = true; // package and class name to which we send intent to check phone book access permission private static final String ACCESS_AUTHORITY_PACKAGE = "com.android.settings"; @@ -167,23 +168,19 @@ public class BluetoothMapService extends ProfileService { } - private synchronized void closeService(CountDownLatch latch) { + private synchronized void closeService() { if (DEBUG) Log.d(TAG, "MAP Service closeService in"); if (mBluetoothMnsObexClient != null) { mBluetoothMnsObexClient.shutdown(); mBluetoothMnsObexClient = null; } - - for(int i=0, c=mMasInstances.size(); i < c; i++) { - mMasInstances.valueAt(i).shutdown(); - } - mMasInstances.clear(); - - if (mSessionStatusHandler != null) { - mSessionStatusHandler.removeCallbacksAndMessages(null); + if (mMasInstances.size() > 0) { + for(int i=0, c=mMasInstances.size(); i < c; i++) { + mMasInstances.valueAt(i).shutdown(); + } + mMasInstances.clear(); } - mIsWaitingAuthorization = false; mPermission = BluetoothDevice.ACCESS_UNKNOWN; setState(BluetoothMap.STATE_DISCONNECTED); @@ -193,12 +190,21 @@ public class BluetoothMapService extends ProfileService { if (VERBOSE) Log.v(TAG, "CloseService(): Release Wake Lock"); mWakeLock = null; } + /* Only one SHUTDOWN message expected to closeService. + * Hence, quit looper and Handler on first SHUTDOWN message*/ + if (mSessionStatusHandler != null) { + //Perform cleanup in Handler running on worker Thread + mSessionStatusHandler.removeCallbacksAndMessages(null); + Looper looper = mSessionStatusHandler.getLooper(); + if (looper != null) { + looper.quit(); + if(VERBOSE) Log.i(TAG, "Quit looper"); + } + mSessionStatusHandler = null; + if(VERBOSE) Log.i(TAG, "Remove Handler"); + } mRemoteDevice = null; - if (DEBUG) Log.d(TAG, "MAP Service closeService out"); - if(latch != null) { - latch.countDown(); - } } /** @@ -379,8 +385,7 @@ public class BluetoothMapService extends ProfileService { case SHUTDOWN: /* Ensure to call close from this handler to avoid starting new stuff because of pending messages */ - CountDownLatch latch = (CountDownLatch) msg.obj; - closeService(latch); + closeService(); break; case MSG_ACQUIRE_WAKE_LOCK: if (VERBOSE) Log.v(TAG, "Acquire Wake Lock request message"); @@ -465,6 +470,10 @@ public class BluetoothMapService extends ProfileService { return mState; } + protected boolean isMapStarted() { + return !mStartError; + } + public static BluetoothDevice getRemoteDevice() { return mRemoteDevice; } @@ -504,7 +513,7 @@ public class BluetoothMapService extends ProfileService { public boolean disconnectMap(BluetoothDevice device) { boolean result = false; if (DEBUG) Log.d(TAG, "disconnectMap"); - if (getRemoteDevice().equals(device)) { + if (getRemoteDevice()!= null && getRemoteDevice().equals(device)) { switch (mState) { case BluetoothMap.STATE_CONNECTED: /* Disconnect all connections and restart all MAS instances */ @@ -585,13 +594,13 @@ public class BluetoothMapService extends ProfileService { if(!VERBOSE) VERBOSE = Log.isLoggable(LOG_TAG, Log.VERBOSE); - if (!Utils.checkCaller()) { - Log.w(TAG, "start received for non-active user, ignoring"); + //Start MapProfile if not already done. + if (isMapStarted()) { + Log.w(TAG, "start received for already started, ignoring"); return false; } if (VERBOSE) Log.v(TAG, "verbose logging is enabled"); - HandlerThread thread = new HandlerThread("BluetoothMapHandler"); thread.start(); Looper looper = thread.getLooper(); @@ -631,7 +640,8 @@ public class BluetoothMapService extends ProfileService { // start RFCOMM listener sendStartListenerMessage(-1); - return true; + mStartError = false; + return !mStartError; } /** @@ -797,24 +807,18 @@ public class BluetoothMapService extends ProfileService { Log.e(TAG,"Unable to unregister map receiver",e); } } - CountDownLatch latch = new CountDownLatch(1); - sendShutdownMessage(latch); - // We need to wait for shutdown to complete to avoid being garbage collected before - // shutdown completes. - if(DEBUG) Log.i(TAG, "Waiting for shutdown to complete"); - try { - latch.await(); - } catch (InterruptedException e) { - Log.e(TAG, "Interrupt received while waiting for shutdown to complete", e); + //Stop MapProfile if already started. + //TODO: Check if the profile state can be retreived from ProfileService or AdapterService. + if (!isMapStarted()) { + if (DEBUG) Log.d(TAG, "Service Not Available to STOP, ignoring"); + return true; + } else { + if (VERBOSE) Log.d(TAG, "Service Stoping()"); } if (mSessionStatusHandler != null) { - mSessionStatusHandler.removeCallbacksAndMessages(null); - Looper looper = mSessionStatusHandler.getLooper(); - if (looper != null) { - looper.quit(); - } - mSessionStatusHandler = null; + sendShutdownMessage(); } + mStartError = true; setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED); if (DEBUG) Log.d(TAG, "stop() out"); return true; @@ -823,8 +827,9 @@ public class BluetoothMapService extends ProfileService { public boolean cleanup() { if (DEBUG) Log.d(TAG, "cleanup()"); setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED); - // TODO: Change to use message? - do we need to wait for completion? - closeService(null); // Stop() should be called to handle cleanup - hence this is not needed + //Cleanup already handled in Stop(). + //Move this extra check to Handler. + sendShutdownMessage(); return true; } @@ -918,13 +923,16 @@ public class BluetoothMapService extends ProfileService { * @param masId the MasID to start. Use -1 to start all listeners. */ public void sendStartListenerMessage(int masId) { - if(mSessionStatusHandler != null) { + if(mSessionStatusHandler != null && ! mSessionStatusHandler.hasMessages(START_LISTENER)) { Message msg = mSessionStatusHandler.obtainMessage(START_LISTENER, masId, 0); /* We add a small delay here to ensure the call returns true before this message is * handled. It seems wrong to add a delay, but the alternative is to build a lock * system to handle synchronization, which isn't nice either... */ mSessionStatusHandler.sendMessageDelayed(msg, 20); - } // Can only be null during shutdown + } else if(mSessionStatusHandler != null ) { + if(DEBUG) + Log.w(TAG, "mSessionStatusHandler START_LISTENER message already in Queue"); + } } private void sendConnectMessage(int masId) { @@ -950,7 +958,8 @@ public class BluetoothMapService extends ProfileService { } // Can only be null during shutdown } - private void sendShutdownMessage(CountDownLatch latch) { + private void sendShutdownMessage() { + if (VERBOSE) Log.d(TAG, "sendShutdownMessage() In"); /* Any pending messages are no longer valid. To speed up things, simply delete them. */ if (mRemoveTimeoutMsg) { @@ -960,23 +969,23 @@ public class BluetoothMapService extends ProfileService { mIsWaitingAuthorization = false; cancelUserTimeoutAlarm(); } - if (mSessionStatusHandler != null) { + if (mSessionStatusHandler != null && !mSessionStatusHandler.hasMessages(SHUTDOWN)) { mSessionStatusHandler.removeCallbacksAndMessages(null); // Request release of all resources - Message msg = mSessionStatusHandler.obtainMessage(SHUTDOWN,latch); + Message msg = mSessionStatusHandler.obtainMessage(SHUTDOWN); if( mSessionStatusHandler.sendMessage(msg) == false) { /* most likely caused by shutdown being called from multiple sources - e.g.BT off * signaled through intent and a service shutdown simultaneously. * Intended behavior not documented, hence we need to be able to handle all cases. */ - Log.e(TAG, "mSessionStatusHandler.sendMessage() failed trigger latch locally"); - if(latch != null) { - latch.countDown(); - } } else { if(DEBUG) Log.e(TAG, "mSessionStatusHandler.sendMessage() dispatched shutdown message"); } + } else if(mSessionStatusHandler != null) { + if(DEBUG) + Log.w(TAG, "mSessionStatusHandler shutdown message already in Queue"); } + if (VERBOSE) Log.d(TAG, "sendShutdownMessage() Out"); } private MapBroadcastReceiver mMapReceiver = new MapBroadcastReceiver(); @@ -992,7 +1001,7 @@ public class BluetoothMapService extends ProfileService { BluetoothAdapter.ERROR); if (state == BluetoothAdapter.STATE_TURNING_OFF) { if (DEBUG) Log.d(TAG, "STATE_TURNING_OFF"); - sendShutdownMessage(null); + sendShutdownMessage(); } else if (state == BluetoothAdapter.STATE_ON) { if (DEBUG) Log.d(TAG, "STATE_ON"); // start ServerSocket listener threads diff --git a/src/com/android/bluetooth/map/BluetoothMapUtils.java b/src/com/android/bluetooth/map/BluetoothMapUtils.java index 1537807a0..7ca55301a 100644 --- a/src/com/android/bluetooth/map/BluetoothMapUtils.java +++ b/src/com/android/bluetooth/map/BluetoothMapUtils.java @@ -394,15 +394,16 @@ public class BluetoothMapUtils { static public byte[] truncateUtf8StringToBytearray(String utf8String, int maxLength) throws UnsupportedEncodingException { - byte[] utf8Bytes = null; + byte[] utf8Bytes = new byte[utf8String.length() + 1]; try { - utf8Bytes = utf8String.getBytes("UTF-8"); + System.arraycopy(utf8String.getBytes("UTF-8"), 0, + utf8Bytes, 0, utf8String.length()); } catch (UnsupportedEncodingException e) { Log.e(TAG,"truncateUtf8StringToBytearray: getBytes exception ", e); throw e; } - if (utf8Bytes.length > (maxLength - 1)) { + if (utf8Bytes.length > maxLength) { /* if 'continuation' byte is in place 200, * then strip previous bytes until utf-8 start byte is found */ if ( (utf8Bytes[maxLength - 1] & 0xC0) == 0x80 ) { diff --git a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java index e1f24c253..aa2af081d 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java +++ b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java @@ -34,9 +34,11 @@ public class BluetoothOppHandoverReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); + if(D) Log.d(TAG, "Action :" + action); + if (action.equals(Constants.ACTION_HANDOVER_SEND) || action.equals(Constants.ACTION_HANDOVER_SEND_MULTIPLE)) { - if (V) Log.v(TAG, "Transfer initiated from HANDOVER"); + BluetoothDevice device = (BluetoothDevice)intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device == null) { diff --git a/src/com/android/bluetooth/opp/BluetoothOppManager.java b/src/com/android/bluetooth/opp/BluetoothOppManager.java index 7d259e15f..8805818e5 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppManager.java +++ b/src/com/android/bluetooth/opp/BluetoothOppManager.java @@ -119,8 +119,6 @@ public class BluetoothOppManager { // The time for which the whitelist entries remain valid. private static final int WHITELIST_DURATION_MS = 15000; - public boolean isOPPServiceUp = false; - /** * Get singleton instance. */ @@ -429,28 +427,17 @@ public class BluetoothOppManager { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - while (true) { - if (mRemoteDevice == null) { - Log.e(TAG, "Target bt device is null!"); - return; - } - - if (V) Log.v(TAG, "OPPServiceUP = " + isOPPServiceUp); - if (isOPPServiceUp) { - if (mIsMultiple) { - insertMultipleShare(); - } else { - insertSingleShare(); - } - - synchronized (BluetoothOppManager.this) { - mInsertShareThreadNum--; - } - return; - } else if (!isEnabled()) { - Log.v(TAG, "BT is OFF"); - return; - } + if (mRemoteDevice == null) { + Log.e(TAG, "Target bt device is null!"); + return; + } + if (mIsMultiple) { + insertMultipleShare(); + } else { + insertSingleShare(); + } + synchronized (BluetoothOppManager.this) { + mInsertShareThreadNum--; } } diff --git a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java index d3b0c28de..7248a4d72 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java +++ b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java @@ -128,11 +128,13 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession { private static final int sSleepTime = 1000; private Uri contentUri; private Context mContext1; + private volatile boolean interrupted = false; public ContentResolverUpdateThread(Context context, Uri cntUri) { super("BtOpp ContentResolverUpdateThread"); mContext1 = context; contentUri = cntUri; + interrupted = false; } @@ -144,19 +146,33 @@ public class BluetoothOppObexClientSession implements BluetoothOppObexSession { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); if (V) Log.v(TAG, "Is ContentResolverUpdateThread Interrupted :" + isInterrupted()); /* Check if the Operation is interrupted before entering into loop */ - while (!isInterrupted()) { + while (!interrupted) { updateValues = new ContentValues(); updateValues.put(BluetoothShare.CURRENT_BYTES, position); mContext1.getContentResolver().update(contentUri, updateValues, null, null); + + /* Check if the Operation is interrupted before entering sleep */ + if (interrupted) { + if (V) Log.v(TAG, "ContentResolverUpdateThread was interrupted before sleep !, exiting"); + return; + } + try { Thread.sleep(sSleepTime); } catch (InterruptedException e1) { if (V) Log.v(TAG, "ContentResolverUpdateThread was interrupted (1), exiting"); + interrupted = true; return; } } } + + @Override + public void interrupt() { + interrupted = true; + super.interrupt(); + } } private class ClientThread extends Thread { diff --git a/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java b/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java index 39355eb40..37dd8b199 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java +++ b/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java @@ -112,7 +112,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler implemen boolean mTransferInProgress = false; - private int position; + private long position; public BluetoothOppObexServerSession(Context context, ObexTransport transport) { mContext = context; @@ -183,6 +183,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler implemen super("BtOpp Server ContentResolverUpdateThread"); mContext1 = context; contentUri = cntUri; + interrupted = false; } @Override @@ -192,14 +193,15 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler implemen ContentValues updateValues; if (V) Log.v(TAG, "Is ContentResolverUpdateThread Interrupted :" + isInterrupted()); /* Check if the Operation is interrupted before entering into loop */ - while ( !isInterrupted() ) { - updateValues = new ContentValues(); - updateValues.put(BluetoothShare.CURRENT_BYTES, position); - mContext1.getContentResolver().update(contentUri, updateValues, - null, null); - /* Check if the Operation is interrupted before entering sleep */ - if (isInterrupted()) { - if (V) Log.v(TAG, "ContentResolverUpdateThread was interrupted before sleep !,"+ + while (!interrupted) { + + updateValues = new ContentValues(); + updateValues.put(BluetoothShare.CURRENT_BYTES, position); + mContext1.getContentResolver().update(contentUri, updateValues, + null, null); + /* Check if the Operation is interrupted before entering sleep */ + if (interrupted) { + if (V) Log.v(TAG, "ContentResolverUpdateThread was interrupted before sleep !,"+ " exiting"); return ; } @@ -209,9 +211,16 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler implemen } catch (InterruptedException e1) { if (V) Log.v(TAG, "Server ContentResolverUpdateThread was interrupted (1),"+ " exiting"); + interrupted = true; return ; - } - } + } + } + } + + @Override + public void interrupt() { + interrupted = true; + super.interrupt(); } } /* diff --git a/src/com/android/bluetooth/opp/BluetoothOppReceiver.java b/src/com/android/bluetooth/opp/BluetoothOppReceiver.java index 1479646eb..b4626c0be 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppReceiver.java +++ b/src/com/android/bluetooth/opp/BluetoothOppReceiver.java @@ -48,7 +48,6 @@ import android.database.Cursor; import android.net.Uri; import android.util.Log; import android.widget.Toast; -import com.android.bluetooth.Utils; /** * Receives and handles: system broadcasts; Intents from other applications; @@ -62,13 +61,8 @@ public class BluetoothOppReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); + if (D) Log.d(TAG, "Action :" + action); - /* Ignore if Broadcast action is not transfer complete and Invalid user */ - if (!Utils.checkCaller() && !action.equals(BluetoothShare.TRANSFER_COMPLETED_ACTION)) { - Log.w(TAG, action + " received for non-active user, ignoring!!"); - return; - } - if (V) Log.v(TAG, action + " Intent received for active user"); if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { if (BluetoothAdapter.STATE_ON == intent.getIntExtra( diff --git a/src/com/android/bluetooth/opp/BluetoothOppService.java b/src/com/android/bluetooth/opp/BluetoothOppService.java index 27519cc5b..c70d0fe17 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppService.java +++ b/src/com/android/bluetooth/opp/BluetoothOppService.java @@ -148,8 +148,6 @@ public class BluetoothOppService extends Service { */ private BluetoothOppObexServerSession mServerSession; - BluetoothOppManager mOppManager = null; - @Override public IBinder onBind(Intent arg0) { throw new UnsupportedOperationException("Cannot bind to Bluetooth OPP Service"); @@ -158,7 +156,7 @@ public class BluetoothOppService extends Service { @Override public void onCreate() { super.onCreate(); - if (V) Log.v(TAG, "onCreate"); + if (D) Log.d(TAG, "onCreate"); mAdapter = BluetoothAdapter.getDefaultAdapter(); mShares = Lists.newArrayList(); mBatchs = Lists.newArrayList(); @@ -170,11 +168,12 @@ public class BluetoothOppService extends Service { mNotifier.updateNotification(); final ContentResolver contentResolver = getContentResolver(); - synchronized (BluetoothOppService.this) { - trimDatabase(contentResolver); - } + new Thread("trimDatabase") { + public void run() { + trimDatabase(contentResolver); + } + }.start(); - mOppManager = BluetoothOppManager.getInstance(this); IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); registerReceiver(mBluetoothReceiver, filter); @@ -184,7 +183,6 @@ public class BluetoothOppService extends Service { } else { startListener(); } - mOppManager.isOPPServiceUp = true; } if (V) BluetoothOppPreference.getInstance(this).dump(); updateFromProvider(); @@ -396,7 +394,6 @@ public class BluetoothOppService extends Service { public void onDestroy() { if (V) Log.v(TAG, "onDestroy"); super.onDestroy(); - mOppManager.isOPPServiceUp = false; getContentResolver().unregisterContentObserver(mObserver); unregisterReceiver(mBluetoothReceiver); if(mSocketListener != null) { @@ -658,9 +655,9 @@ public class BluetoothOppService extends Service { cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.VISIBILITY)), cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION)), cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.STATUS)), - cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES)), - cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES)), - cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)), + cursor.getLong(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES)), + cursor.getLong(cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES)), + cursor.getLong(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)), cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) != Constants.MEDIA_SCANNED_NOT_SCANNED); if (V) { @@ -808,10 +805,10 @@ public class BluetoothOppService extends Service { } info.mStatus = newStatus; - info.mTotalBytes = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES)); - info.mCurrentBytes = cursor.getInt(cursor + info.mTotalBytes = cursor.getLong(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES)); + info.mCurrentBytes = cursor.getLong(cursor .getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES)); - info.mTimestamp = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)); + info.mTimestamp = cursor.getLong(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)); info.mMediaScanned = (cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) != Constants.MEDIA_SCANNED_NOT_SCANNED); if (confirmUpdated) { diff --git a/src/com/android/bluetooth/opp/BluetoothOppShareInfo.java b/src/com/android/bluetooth/opp/BluetoothOppShareInfo.java index 32f6b3cb3..cb35f6da0 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppShareInfo.java +++ b/src/com/android/bluetooth/opp/BluetoothOppShareInfo.java @@ -60,17 +60,18 @@ public class BluetoothOppShareInfo { public int mStatus; - public int mTotalBytes; + public long mTotalBytes; - public int mCurrentBytes; + public long mCurrentBytes; public long mTimestamp; public boolean mMediaScanned; public BluetoothOppShareInfo(int id, Uri uri, String hint, String filename, String mimetype, - int direction, String destination, int visibility, int confirm, int status, - int totalBytes, int currentBytes, int timestamp, boolean mediaScanned) { + int direction, String destination, int visibility, int confirm, int status, + long totalBytes, long currentBytes, long timestamp, boolean mediaScanned) { + mId = id; mUri = uri; mHint = hint; @@ -96,6 +97,7 @@ public class BluetoothOppShareInfo { if (mStatus == BluetoothShare.STATUS_PENDING && mUri != null) { return true; } + } else if (mDirection == BluetoothShare.DIRECTION_INBOUND) { if (mStatus == BluetoothShare.STATUS_PENDING) { //&& mConfirm != BluetoothShare.USER_CONFIRMATION_PENDING) { diff --git a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java index 3943ea164..c4960d4f1 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java +++ b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java @@ -535,6 +535,7 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch if (mBluetoothReceiver != null){ mContext.unregisterReceiver(mBluetoothReceiver); mBluetoothReceiver = null; + if (V) Log.v(TAG, "Un Registered mBluetoothReceiver"); } } catch (Exception e) { Log.e(TAG, "Exception:unregisterReceiver"); @@ -566,10 +567,17 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch mConnectThread = new SocketConnectThread("localhost", Constants.TCP_DEBUG_PORT, 0); mConnectThread.start(); } else { - OolConnManager.setSdpInitiatedAddress(mBatch.mDestination); - mBatch.mDestination.sdpSearch(BluetoothUuid.ObexObjectPush); - mConnectThread = new SocketConnectThread(mBatch.mDestination,false); - mConnectThread.start(); + OolConnManager.setSdpInitiatedAddress(mBatch.mDestination); + if (!mBatch.mDestination.sdpSearch(BluetoothUuid.ObexObjectPush)) { + /* SDP failed, start rfcomm connect directly */ + mConnectThread = new SocketConnectThread(mBatch.mDestination, false, false); + /* update bd address as sdp could not be started */ + OolConnManager.setSdpInitiatedAddress(null); + } else { + /* SDP sucessfully started, start l2cap connect after sdp completes */ + mConnectThread = new SocketConnectThread(mBatch.mDestination, false, true); + } + mConnectThread.start(); } } @@ -592,6 +600,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch private boolean mRetry = false; + private boolean mSdpInitiated = false; + /* create a TCP socket */ public SocketConnectThread(String host, int port, int dummy) { super("Socket Connect Thread"); @@ -599,9 +609,10 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch this.channel = port; this.device = null; isConnected = false; + mSdpInitiated = false; } - /* create a Rfcomm Socket */ + /* create a Rfcomm/L2CAP Socket */ public SocketConnectThread(BluetoothDevice device, int channel, boolean retry) { super("Socket Connect Thread"); @@ -610,17 +621,30 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch this.channel = channel; isConnected = false; mRetry = retry; + mSdpInitiated = false; } - /* create a Rfcomm Socket */ - public SocketConnectThread(BluetoothDevice device, boolean - retry) { + /* create a Rfcomm/L2CAP Socket */ + public SocketConnectThread(BluetoothDevice device, boolean retry) { + super("Socket Connect Thread"); + this.device = device; + this.host = null; + this.channel = -1; + isConnected = false; + mRetry = retry; + mSdpInitiated = false; + } + + /* create a Rfcomm/L2CAP Socket */ + public SocketConnectThread(BluetoothDevice device, boolean retry, + boolean sdpInitiated) { super("Socket Connect Thread"); this.device = device; this.host = null; this.channel = -1; isConnected = false; mRetry = retry; + mSdpInitiated = sdpInitiated; } public void interrupt() { @@ -744,11 +768,32 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch return ; } + Log.d(TAG, "sdp initiated = " + mSdpInitiated); + + // check if sdp initiated successfully for l2cap or not. If not connect + // directly to rfcomm + if (!mSdpInitiated) { + /* sdp failed for some reason, connect on rfcomm */ + Log.d(TAG, "sdp not initiated, connecting on rfcomm"); + connectRfcommSocket(); + return; + } + + /* Reset the flag */ + mSdpInitiated = false; + /* Use BluetoothSocket to connect */ l2cChannel = 0; try { l2cChannel = OolConnManager.getL2cPSM(device); - btSocket = device.createInsecureL2capSocket(l2cChannel); + if (l2cChannel > 0) { + Log.d(TAG, "Connecting to l2cap psm = " + l2cChannel); + btSocket = device.createInsecureL2capSocket(l2cChannel); + } else { + Log.d(TAG, "L2cap psm not found, connecting on rfcomm"); + connectRfcommSocket(); + return; + } } catch (IOException e1) { Log.e(TAG, "L2cap socket create error",e1); connectRfcommSocket(); diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapService.java b/src/com/android/bluetooth/pbap/BluetoothPbapService.java index dcfc5c209..6cfd71339 100644 --- a/src/com/android/bluetooth/pbap/BluetoothPbapService.java +++ b/src/com/android/bluetooth/pbap/BluetoothPbapService.java @@ -200,10 +200,6 @@ public class BluetoothPbapService extends Service { mInterrupted = false; mAdapter = BluetoothAdapter.getDefaultAdapter(); - if (!Utils.checkCaller()) { - Log.w(TAG, "onCreate received for non-active user, ignoring"); - return; - } if (!mHasStarted) { mHasStarted = true; diff --git a/src/com/android/bluetooth/sap/SapMessage.java b/src/com/android/bluetooth/sap/SapMessage.java index 451d9280c..251c67e1a 100644 --- a/src/com/android/bluetooth/sap/SapMessage.java +++ b/src/com/android/bluetooth/sap/SapMessage.java @@ -26,8 +26,8 @@ import android.util.Log; public class SapMessage { public static final String TAG = "SapMessage"; - public static final boolean DEBUG = Log.isLoggable(SapService.LOG_TAG, Log.DEBUG); - public static final boolean VERBOSE = Log.isLoggable(SapService.LOG_TAG, Log.VERBOSE); + public static final boolean DEBUG = true; + public static final boolean VERBOSE = SapService.VERBOSE; public static final boolean TEST = false; /* Message IDs - SAP specification */ @@ -721,6 +721,7 @@ public class SapMessage { msg.setType(SapApi.REQUEST); msg.setError(SapApi.RIL_E_UNUSED); + if(DEBUG) Log.d(TAG, "Writing request, message type:" + mMsgType); switch(mMsgType) { case ID_CONNECT_REQ: { diff --git a/src/com/android/bluetooth/sap/SapRilReceiver.java b/src/com/android/bluetooth/sap/SapRilReceiver.java index 6cfd6db84..542519344 100644 --- a/src/com/android/bluetooth/sap/SapRilReceiver.java +++ b/src/com/android/bluetooth/sap/SapRilReceiver.java @@ -18,7 +18,7 @@ import android.util.Log; public class SapRilReceiver implements Runnable { private static final String TAG = "SapRilReceiver"; - public static final boolean DEBUG = Log.isLoggable(SapService.LOG_TAG, Log.DEBUG); + public static final boolean DEBUG = true; public static final boolean VERBOSE = Log.isLoggable(SapService.LOG_TAG, Log.VERBOSE); private static final String SOCKET_NAME_RIL_BT = "sap_uim_socket1"; diff --git a/src/com/android/bluetooth/sap/SapServer.java b/src/com/android/bluetooth/sap/SapServer.java index d8c24722f..c30e63bfc 100644 --- a/src/com/android/bluetooth/sap/SapServer.java +++ b/src/com/android/bluetooth/sap/SapServer.java @@ -50,8 +50,8 @@ import com.google.protobuf.micro.CodedOutputStreamMicro; public class SapServer extends Thread implements Callback { private static final String TAG = "SapServer"; private static final String TAG_HANDLER = "SapServerHandler"; - public static final boolean DEBUG = Log.isLoggable(SapService.LOG_TAG, Log.DEBUG); - public static final boolean VERBOSE = Log.isLoggable(SapService.LOG_TAG, Log.VERBOSE); + public static final boolean DEBUG = true; + public static final boolean VERBOSE = SapService.VERBOSE; private enum SAP_STATE { DISCONNECTED, CONNECTING, CONNECTING_CALL_ONGOING, CONNECTED, @@ -198,6 +198,7 @@ public class SapServer extends Thread implements Callback { } else { SapMessage msg = new SapMessage(SapMessage.ID_DISCONNECT_REQ); /* Force disconnect of RFCOMM - but first we need to clean up. */ + if(DEBUG) Log.d(TAG, "Cleaning up before force disconnecting rfcomm"); clearPendingRilResponses(msg); /* We simply need to forward to RIL, but not change state to busy - hence send and set diff --git a/src/com/android/bluetooth/sap/SapService.java b/src/com/android/bluetooth/sap/SapService.java index 9199d7fd1..a02afc648 100644 --- a/src/com/android/bluetooth/sap/SapService.java +++ b/src/com/android/bluetooth/sap/SapService.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.concurrent.CountDownLatch; import android.annotation.TargetApi; import android.app.AlarmManager; @@ -50,7 +49,7 @@ public class SapService extends ProfileService { private static final int SDP_SAP_VERSION = 0x0102; private static final String TAG = "SapService"; public static final String LOG_TAG = "BluetoothSap"; - public static boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG); + public static boolean DEBUG = true; public static boolean VERBOSE = Log.isLoggable(LOG_TAG, Log.VERBOSE); /* Message ID's */ @@ -79,7 +78,7 @@ public class SapService extends ProfileService { /* Intent indicating timeout for user confirmation. */ public static final String USER_CONFIRM_TIMEOUT_ACTION = "com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT"; - private static final int USER_CONFIRM_TIMEOUT_VALUE = 25000; + private static final int USER_CONFIRM_TIMEOUT_VALUE = 30000; private PowerManager.WakeLock mWakeLock = null; private BluetoothAdapter mAdapter; @@ -129,17 +128,20 @@ public class SapService extends ProfileService { } private void startRfcommSocketListener() { - if (VERBOSE) Log.v(TAG, "Sap Service startRfcommSocketListener"); + if (DEBUG) Log.d(TAG, "Sap Service startRfcommSocketListener"); if (mAcceptThread == null) { + Log.d(TAG, "Sap Service startRfcommSocketListener"); mAcceptThread = new SocketAcceptThread(); mAcceptThread.setName("SapAcceptThread"); mAcceptThread.start(); + } else { + Log.d(TAG, "Sap Service Already ON: startRfcommSocketListener"); } } private final boolean initSocket() { - if (VERBOSE) Log.v(TAG, "Sap Service initSocket"); + if (DEBUG) Log.d(TAG, "Sap Service initSocket"); boolean initSocketOK = false; final int CREATE_RETRY_TIME = 10; @@ -201,7 +203,7 @@ public class SapService extends ProfileService { if (mServerSocket != null) { try { // this will cause mServerSocket.accept() return early with IOException - if (VERBOSE) Log.v(TAG, "Closing server socket"); + if (DEBUG) Log.d(TAG, "Closing server socket"); mServerSocket.close(); mServerSocket = null; } catch (IOException ex) { @@ -213,7 +215,7 @@ public class SapService extends ProfileService { private final synchronized void closeConnectionSocket() { if (mConnSocket != null) { try { - if (VERBOSE) Log.v(TAG, "Closing conenction socket"); + if (DEBUG) Log.d(TAG, "Closing conenction socket"); mConnSocket.close(); mConnSocket = null; } catch (IOException e) { @@ -222,8 +224,8 @@ public class SapService extends ProfileService { } } - synchronized private final void closeService(CountDownLatch latch) { - if (VERBOSE) Log.v(TAG, "SAP Service closeService in"); + synchronized private final void closeService() { + if (DEBUG) Log.d(TAG, "SAP Service closeService in"); // exit initSocket early mInterrupted = true; @@ -243,9 +245,20 @@ public class SapService extends ProfileService { } releaseWakeLockResources(); - if(latch != null) { - latch.countDown(); + /* Only one SHUTDOWN message expected to closeService. + * Hence, quit looper and Handler on first SHUTDOWN message*/ + if (mSessionStatusHandler != null) { + //Perform cleanup in Handler running on worker Thread + mSessionStatusHandler.removeCallbacksAndMessages(null); + Looper looper = mSessionStatusHandler.getLooper(); + if (looper != null) { + looper.quit(); + if(VERBOSE) Log.i(TAG, "Quit looper"); + } + mSessionStatusHandler = null; + if(VERBOSE) Log.i(TAG, "Remove Handler"); } + if (VERBOSE) Log.v(TAG, "SAP Service closeService out"); } @@ -278,7 +291,7 @@ public class SapService extends ProfileService { } private synchronized void startSapServerSession() throws IOException { - if (VERBOSE) Log.v(TAG, "Sap Service startSapServerSession"); + if (DEBUG) Log.d(TAG, "Sap Service startSapServerSession"); // acquire the wakeLock before start SAP transaction thread if (mWakeLock == null) { @@ -309,7 +322,7 @@ public class SapService extends ProfileService { /* When we reach this point, the SapServer is closed down, and the client is * supposed to close the RFCOMM connection. */ - if (VERBOSE) Log.v(TAG, "SAP Service stopSapServerSession"); + if (DEBUG) Log.d(TAG, "SAP Service stopSapServerSession"); mAcceptThread = null; closeConnectionSocket(); @@ -318,7 +331,8 @@ public class SapService extends ProfileService { setState(BluetoothSap.STATE_DISCONNECTED); awaitSapServerSessionStop(); - + // Extra check to startListener if already not available + // This will not actually restart listener on every connect/disconnect. // Last SAP transaction is finished, we start to listen for incoming // rfcomm connection again if (mAdapter.isEnabled()) { @@ -471,7 +485,8 @@ public class SapService extends ProfileService { if (VERBOSE) Log.v(TAG, "Release Wake Lock request message"); if (mWakeLock != null) { mWakeLock.release(); - if (DEBUG) Log.d(TAG, " Released Wake Lock by message"); + mWakeLock = null; + Log.w(TAG, "Release Wake Lock"); } break; case MSG_CHANGE_STATE: @@ -479,10 +494,7 @@ public class SapService extends ProfileService { setState(msg.arg1); break; case SHUTDOWN: - /* Ensure to call close from this handler to avoid starting new stuff - because of pending messages */ - CountDownLatch latch = (CountDownLatch)msg.obj; - closeService(latch); + closeService(); break; default: break; @@ -648,7 +660,7 @@ public class SapService extends ProfileService { @Override protected boolean stop() { - if (VERBOSE) Log.v(TAG, "Stoping SAPService"); + if (DEBUG) Log.d(TAG, "Stoping SAPService"); if (!mIsRegistered){ Log.i(TAG, "Avoid unregister when receiver it is not registered"); @@ -661,34 +673,19 @@ public class SapService extends ProfileService { Log.w(TAG,"Unable to unregister sap receiver",e); } setState(BluetoothSap.STATE_DISCONNECTED, BluetoothSap.RESULT_CANCELED, true); - CountDownLatch latch = new CountDownLatch(1); - sendShutdownMessage(latch); - // We need to wait for shutdown to complete to avoid being garbage collected before - // shutdown completes. - if(DEBUG) Log.i(TAG, "Waiting for shutdown to complete"); - try { - latch.await(); - } catch (InterruptedException e) { - Log.e(TAG, "Interrupt received while waiting for shutdown to complete", e); - } - if (mSessionStatusHandler != null) { - mSessionStatusHandler.removeCallbacksAndMessages(null); - Looper looper = mSessionStatusHandler.getLooper(); - if (looper != null) { - looper.quit(); - } - mSessionStatusHandler = null; - } + + if (mSessionStatusHandler != null) + sendShutdownMessage(); + if(DEBUG) Log.v(TAG, "stop() out"); return true; } public boolean cleanup() { setState(BluetoothSap.STATE_DISCONNECTED, BluetoothSap.RESULT_CANCELED, true); - closeService(null); // No latch needed as the call is blocking - if(mSessionStatusHandler != null) { - mSessionStatusHandler.removeCallbacksAndMessages(null); - } + //Cleanup already handled in Stop(). + //Move this extra check to Handler. + sendShutdownMessage(); return true; } @@ -725,7 +722,7 @@ public class SapService extends ProfileService { sendBroadcast(intent, BLUETOOTH_PERM); } - private void sendShutdownMessage(CountDownLatch latch) { + private void sendShutdownMessage() { /* Any pending messages are no longer valid. To speed up things, simply delete them. */ if (mRemoveTimeoutMsg) { @@ -745,20 +742,20 @@ public class SapService extends ProfileService { if (mSessionStatusHandler != null) { mSessionStatusHandler.removeCallbacksAndMessages(null); // Request release of all resources - Message msg = mSessionStatusHandler.obtainMessage(SHUTDOWN,latch); + Message msg = mSessionStatusHandler.obtainMessage(SHUTDOWN); if( mSessionStatusHandler.sendMessage(msg) == false) { /* most likely caused by shutdown being called from multiple sources - e.g.BT off * signaled through intent and a service shutdown simultaneously. * Intended behavior not documented, hence we need to be able to handle all cases. */ - Log.e(TAG, "mSessionStatusHandler.sendMessage() failed trigger latch locally"); - if(latch != null) { - latch.countDown(); - } } else { if(DEBUG) Log.e(TAG, "mSessionStatusHandler.sendMessage() dispatched shutdown msg"); } + } else if (mSessionStatusHandler != null) { + if(DEBUG) Log.w(TAG, "mSessionStatusHandler shutdown message already in Queue"); } + + if (VERBOSE) Log.d(TAG, "sendShutdownMessage() Out"); } private void sendConnectTimeoutMessage() { @@ -782,7 +779,7 @@ public class SapService extends ProfileService { BluetoothAdapter.ERROR); if (state == BluetoothAdapter.STATE_TURNING_OFF) { if (DEBUG) Log.d(TAG, "STATE_TURNING_OFF"); - sendShutdownMessage(null); + sendShutdownMessage(); } else if (state == BluetoothAdapter.STATE_ON) { if (DEBUG) Log.d(TAG, "STATE_ON"); // start RFCOMM listener |