replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / android / caleserver.c
index 8f8ec34..3cbb821 100644 (file)
 #include "caleutils.h"
 #include "caleinterface.h"
 #include "caadapterutils.h"
+#include "calestate.h"
 
 #include "logger.h"
 #include "oic_malloc.h"
 #include "cathreadpool.h"
-#include "camutex.h"
+#include "octhread.h"
 #include "uarraylist.h"
 #include "org_iotivity_ca_CaLeServerInterface.h"
 
-#define TAG PCF("CA_LE_SERVER")
+#define TAG PCF("OIC_CA_LE_SERVER")
+
+#define WAIT_TIME_WRITE_CHARACTERISTIC 10000000
+#define INVALID_STATE -1
 
 static JavaVM *g_jvm = NULL;
 static jobject g_context = NULL;
 static jobject g_bluetoothGattServer = NULL;
 static jobject g_bluetoothGattServerCallback = NULL;
 static jobject g_leAdvertiseCallback = NULL;
+static jobject g_bluetoothManager = NULL;
 
 static CAPacketReceiveCallback g_packetReceiveCallback = NULL;
 static CABLEErrorHandleCallback g_serverErrorCallback;
 
 static u_arraylist_t *g_connectedDeviceList = NULL;
-static ca_thread_pool_t g_threadPoolHandle = NULL;
+static u_arraylist_t *g_deviceStateList = NULL;
 
 static bool g_isStartServer = false;
 static bool g_isInitializedServer = false;
 
+static jbyteArray g_sendBuffer = NULL;
+static jobject g_obj_bluetoothDevice = NULL;
+
 static CABLEDataReceivedCallback g_CABLEServerDataReceivedCallback = NULL;
-static ca_mutex g_bleReqRespCbMutex = NULL;
-static ca_mutex g_bleClientBDAddressMutex = NULL;
-static ca_mutex g_connectedDeviceListMutex = NULL;
+static oc_mutex g_bleReqRespCbMutex = NULL;
+static oc_mutex g_bleClientBDAddressMutex = NULL;
+static oc_mutex g_connectedDeviceListMutex = NULL;
+
+static oc_mutex g_threadSendMutex = NULL;
+static oc_mutex g_threadSendNotifyMutex = NULL;
+static oc_cond g_threadSendNotifyCond = NULL;
+static bool g_isSignalSetFlag = false;
+
+static oc_mutex g_deviceStateListMutex = NULL;
+
+static jint g_state_connected = INVALID_STATE;
+static jint g_state_disconnected = INVALID_STATE;
+
+static const char CLASSPATH_BT_ADVERTISE_CB[] = "android/bluetooth/le/AdvertiseCallback";
+static const char CLASSPATH_BT_GATTSERVER[] = "android/bluetooth/BluetoothGattServer";
+
+static bool g_setHighQoS = true;
 
 void CALEServerJNISetContext()
 {
@@ -86,7 +109,7 @@ CAResult_t CALEServerCreateJniInterfaceObject()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -136,55 +159,73 @@ CAResult_t CALEServerCreateJniInterfaceObject()
     return CA_STATUS_FAILED;
 }
 
-jobject CALEServerSetResponseData(JNIEnv *env, jbyteArray responseData)
+/**
+ * get the current connection state of the gatt profile to the remote device.
+ * @param[in]   env              JNI interface pointer.
+ * @param[in]   device           bluetooth device object
+ * @return  state of the profile connection.
+ */
+static jint CALEServerGetConnectionState(JNIEnv *env, jobject device)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEServerSetResponseData");
-    VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
-    VERIFY_NON_NULL_RET(responseData, TAG, "responseData is null", NULL);
+    OIC_LOG(DEBUG, TAG, "CALEServerGetConnectionState");
 
-    if (!g_bluetoothGattServer)
+    VERIFY_NON_NULL_RET(env, TAG, "env", -1);
+    VERIFY_NON_NULL_RET(device, TAG, "device", -1);
+
+    jmethodID jni_mid_getConnectionState = CAGetJNIMethodID(env, "android/bluetooth"
+                                                            "/BluetoothManager",
+                                                            "getConnectionState",
+                                                            "(Landroid/bluetooth/BluetoothDevice"
+                                                            ";I)I");
+    if (!jni_mid_getConnectionState)
     {
-        OIC_LOG(ERROR, TAG, "Check BluetoothGattServer status");
-        return NULL;
+        OIC_LOG(ERROR, TAG, "jni_mid_getConnectionState is null");
+        return -1;
     }
 
-    if (!CALEIsEnableBTAdapter(env))
+    if (!g_bluetoothManager)
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
-        return NULL;
+        OIC_LOG(ERROR, TAG, "g_bluetoothManager is null");
+        return -1;
     }
 
-    OIC_LOG(DEBUG, TAG, "CALEServerSetResponseData");
-
-    jclass jni_cid_bluetoothGattServer = (*env)->FindClass(env,
-                                                           "android/bluetooth/BluetoothGattServer");
-    if (!jni_cid_bluetoothGattServer)
+    jint jni_state = (jint)(*env)->CallIntMethod(env, g_bluetoothManager,
+                                                 jni_mid_getConnectionState,
+                                                 device, GATT_PROFILE);
+    if (CACheckJNIException(env))
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattServer is null");
-        return NULL;
+        OIC_LOG(ERROR, TAG, "getConnectionState has failed");
+        return -1;
     }
 
-    jclass jni_cid_bluetoothGattService = (*env)->FindClass(env, "android/bluetooth/"
-                                                            "BluetoothGattService");
-    if (!jni_cid_bluetoothGattService)
+    OIC_LOG_V(INFO, TAG, "connection state is %d", jni_state);
+    return jni_state;
+}
+
+jobject CALEServerSetResponseData(JNIEnv *env, jbyteArray responseData)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CALEServerSetResponseData");
+    VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
+    VERIFY_NON_NULL_RET(responseData, TAG, "responseData is null", NULL);
+
+    if (!g_bluetoothGattServer)
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattService is null");
+        OIC_LOG(ERROR, TAG, "Check BluetoothGattServer status");
         return NULL;
     }
 
-    jclass jni_cid_bluetoothGattCharacteristic = (*env)->FindClass(env, "android/bluetooth/"
-                                                                   "BluetoothGattCharacteristic");
-    if (!jni_cid_bluetoothGattService)
+    if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattCharacteristic is null");
+        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
         return NULL;
     }
 
-    jmethodID jni_mid_getService = (*env)->GetMethodID(env, jni_cid_bluetoothGattServer,
-                                                       "getService",
-                                                       "(Ljava/util/UUID;)Landroid/bluetooth/"
-                                                       "BluetoothGattService;");
-    if (!jni_cid_bluetoothGattService)
+    OIC_LOG(DEBUG, TAG, "CALEServerSetResponseData");
+    jmethodID jni_mid_getService = CAGetJNIMethodID(env, CLASSPATH_BT_GATTSERVER,
+                                                    "getService",
+                                                    "(Ljava/util/UUID;)Landroid/bluetooth/"
+                                                    "BluetoothGattService;");
+    if (!jni_mid_getService)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getService is null");
         return NULL;
@@ -203,14 +244,16 @@ jobject CALEServerSetResponseData(JNIEnv *env, jbyteArray responseData)
     if (!jni_obj_bluetoothGattService)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_bluetoothGattService is null");
+        CACheckJNIException(env);
         return NULL;
     }
 
-    jmethodID jni_mid_getCharacteristic = (*env)->GetMethodID(env, jni_cid_bluetoothGattService,
-                                                              "getCharacteristic",
-                                                              "(Ljava/util/UUID;)"
-                                                              "Landroid/bluetooth/"
-                                                              "BluetoothGattCharacteristic;");
+    jmethodID jni_mid_getCharacteristic = CAGetJNIMethodID(env, "android/bluetooth/"
+                                                           "BluetoothGattService",
+                                                           "getCharacteristic",
+                                                           "(Ljava/util/UUID;)"
+                                                           "Landroid/bluetooth/"
+                                                           "BluetoothGattCharacteristic;");
     if (!jni_mid_getCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getCharacteristic is null");
@@ -230,11 +273,13 @@ jobject CALEServerSetResponseData(JNIEnv *env, jbyteArray responseData)
     if (!jni_obj_bluetoothGattCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_bluetoothGattCharacteristic is null");
+        CACheckJNIException(env);
         return NULL;
     }
 
-    jmethodID jni_mid_setValue = (*env)->GetMethodID(env, jni_cid_bluetoothGattCharacteristic,
-                                                     "setValue", "([B)Z");
+    jmethodID jni_mid_setValue = CAGetJNIMethodID(env, "android/bluetooth/"
+                                                  "BluetoothGattCharacteristic",
+                                                  "setValue", "([B)Z");
     if (!jni_mid_setValue)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_setValue is null");
@@ -247,6 +292,7 @@ jobject CALEServerSetResponseData(JNIEnv *env, jbyteArray responseData)
     if (JNI_FALSE == jni_boolean_setValue)
     {
         OIC_LOG(ERROR, TAG, "Fail to set response data");
+        CACheckJNIException(env);
     }
 
     OIC_LOG(DEBUG, TAG, "OUT - CALEServerSetResponseData");
@@ -255,7 +301,7 @@ jobject CALEServerSetResponseData(JNIEnv *env, jbyteArray responseData)
 
 CAResult_t CALEServerSendResponseData(JNIEnv *env, jobject device, jobject responseData)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEServerSendResponseData");
+    OIC_LOG(DEBUG, TAG, "CALEServerSendResponseData");
     VERIFY_NON_NULL(responseData, TAG, "responseData is null");
     VERIFY_NON_NULL(device, TAG, "device is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
@@ -266,34 +312,59 @@ CAResult_t CALEServerSendResponseData(JNIEnv *env, jobject device, jobject respo
         return CA_ADAPTER_NOT_ENABLED;
     }
 
-    jclass jni_cid_bluetoothGattServer = (*env)->FindClass(env,
-                                                           "android/bluetooth/BluetoothGattServer");
-    if (!jni_cid_bluetoothGattServer)
+    if (!g_bluetoothGattServer)
+    {
+        OIC_LOG(ERROR, TAG, "g_bluetoothGattServer is not available");
+        return CA_STATUS_FAILED;
+    }
+
+    if (g_state_connected != CALEServerGetConnectionState(env, device))
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattServer is null");
+        OIC_LOG(ERROR, TAG, "it is not connected state");
         return CA_STATUS_FAILED;
     }
 
-    jmethodID jni_mid_notifyCharacteristicChanged = (*env)->GetMethodID(
-            env, jni_cid_bluetoothGattServer, "notifyCharacteristicChanged",
-            "(Landroid/bluetooth/BluetoothDevice;"
-            "Landroid/bluetooth/BluetoothGattCharacteristic;Z)Z");
+    jmethodID jni_mid_notifyCharacteristicChanged = CAGetJNIMethodID(env,
+                                                      CLASSPATH_BT_GATTSERVER,
+                                                      "notifyCharacteristicChanged",
+                                                      "(Landroid/bluetooth/BluetoothDevice;"
+                                                      "Landroid/bluetooth/"
+                                                      "BluetoothGattCharacteristic;Z)Z");
     if (!jni_mid_notifyCharacteristicChanged)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_notifyCharacteristicChanged is null");
         return CA_STATUS_FAILED;
     }
 
+    OIC_LOG(DEBUG, TAG, "CALL API - notifyCharacteristicChanged");
+
     jboolean jni_boolean_notifyCharacteristicChanged = (*env)->CallBooleanMethod(
             env, g_bluetoothGattServer, jni_mid_notifyCharacteristicChanged, device, responseData,
             JNI_FALSE);
     if (JNI_FALSE == jni_boolean_notifyCharacteristicChanged)
     {
         OIC_LOG(ERROR, TAG, "Fail to notify characteristic");
+        CACheckJNIException(env);
         return CA_SEND_FAILED;
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEServerSendResponseData");
+    OIC_LOG_V(DEBUG, TAG, "callback flag is %d", g_isSignalSetFlag);
+    oc_mutex_lock(g_threadSendNotifyMutex);
+    if (!g_isSignalSetFlag)
+    {
+        OIC_LOG(DEBUG, TAG, "wait for callback to notify notifyCharacteristic is success");
+        if (0 != oc_cond_wait_for(g_threadSendNotifyCond, g_threadSendNotifyMutex,
+                                  WAIT_TIME_WRITE_CHARACTERISTIC))
+        {
+            OIC_LOG(ERROR, TAG, "there is no response. notifyCharacteristic has failed");
+            oc_mutex_unlock(g_threadSendNotifyMutex);
+            return CA_STATUS_FAILED;
+        }
+    }
+    // reset flag set by writeCharacteristic Callback
+    g_isSignalSetFlag = false;
+    oc_mutex_unlock(g_threadSendNotifyMutex);
+    OIC_LOG(INFO, TAG, "notifyCharacteristic success");
     return CA_STATUS_OK;
 }
 
@@ -313,18 +384,16 @@ CAResult_t CALEServerSendResponse(JNIEnv *env, jobject device, jint requestId, j
         return CA_ADAPTER_NOT_ENABLED;
     }
 
-    jclass jni_cid_bluetoothGattServer = (*env)->FindClass(env,
-                                                           "android/bluetooth/BluetoothGattServer");
-    if (!jni_cid_bluetoothGattServer)
+    if (!g_bluetoothGattServer)
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattServer is null");
+        OIC_LOG(ERROR, TAG, "g_bluetoothGattServer is not available");
         return CA_STATUS_FAILED;
     }
 
-    jmethodID jni_mid_sendResponse = (*env)->GetMethodID(env, jni_cid_bluetoothGattServer,
-                                                         "sendResponse",
-                                                         "(Landroid/bluetooth/BluetoothDevice;"
-                                                         "III[B)Z");
+    jmethodID jni_mid_sendResponse = CAGetJNIMethodID(env, CLASSPATH_BT_GATTSERVER,
+                                                      "sendResponse",
+                                                      "(Landroid/bluetooth/BluetoothDevice;"
+                                                      "III[B)Z");
     if (!jni_mid_sendResponse)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_sendResponse is null");
@@ -338,6 +407,7 @@ CAResult_t CALEServerSendResponse(JNIEnv *env, jobject device, jint requestId, j
     if (JNI_FALSE == jni_boolean_sendResponse)
     {
         OIC_LOG(ERROR, TAG, "Fail to send response for gatt characteristic write request");
+        CACheckJNIException(env);
         return CA_SEND_FAILED;
     }
 
@@ -345,9 +415,54 @@ CAResult_t CALEServerSendResponse(JNIEnv *env, jobject device, jint requestId, j
     return CA_STATUS_OK;
 }
 
-CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
+CAResult_t CALEServerStartAdvertise()
+{
+    if ((caglobals.bleFlags & CA_LE_ADV_DISABLE) || CA_DEFAULT_BT_FLAGS == caglobals.bleFlags)
+    {
+        OIC_LOG_V(INFO, TAG, "the advertisement of the bleFlags is disable[%d]",
+                  caglobals.bleFlags);
+        return CA_STATUS_OK;
+    }
+
+    if (!g_jvm)
+    {
+        OIC_LOG(ERROR, TAG, "g_jvm is null");
+        return CA_STATUS_FAILED;
+    }
+
+    bool isAttached = false;
+    JNIEnv* env = NULL;
+    jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
+    if (JNI_OK != res)
+    {
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
+        res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
+
+        if (JNI_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
+            return CA_STATUS_FAILED;
+        }
+        isAttached = true;
+    }
+
+    // start advertise
+    CAResult_t ret = CALEServerStartAdvertiseImpl(env, g_leAdvertiseCallback);
+    if (CA_STATUS_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "CALEServerStartAdvertiseImpl has failed");
+    }
+
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
+    return ret;
+}
+
+CAResult_t CALEServerStartAdvertiseImpl(JNIEnv *env, jobject advertiseCallback)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEServerStartAdvertise");
+    OIC_LOG(DEBUG, TAG, "IN - CALEServerStartAdvertiseImpl");
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(advertiseCallback, TAG, "advertiseCallback is null");
 
@@ -363,7 +478,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_cid_AdvertiseSettings)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_AdvertiseSettings is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_AdvertiseSettings = (*env)->GetMethodID(env, jni_cid_AdvertiseSettings,
@@ -371,7 +486,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_AdvertiseSettings)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_AdvertiseSettings is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_AdvertiseSettings = (*env)->NewObject(env, jni_cid_AdvertiseSettings,
@@ -379,7 +494,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_AdvertiseSettings)
     {
         OIC_LOG(ERROR, TAG, "jni_AdvertiseSettings is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_setAdvertiseMode = (*env)->GetMethodID(env, jni_cid_AdvertiseSettings,
@@ -389,7 +504,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_setAdvertiseMode)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_setAdvertiseMode is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     // 0: Low power, 1: Balanced
@@ -398,7 +513,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_setAdvertiseMode)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_setAdvertiseMode is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_setConnectable = (*env)->GetMethodID(env, jni_cid_AdvertiseSettings,
@@ -408,7 +523,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_setConnectable)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_setConnectable is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_setConnectable = (*env)->CallObjectMethod(env, jni_AdvertiseSettings,
@@ -416,7 +531,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_setConnectable)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_setConnectable is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_setTimeout = (*env)->GetMethodID(env, jni_cid_AdvertiseSettings, "setTimeout",
@@ -425,7 +540,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_setTimeout)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_setTimeout is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     //A value of 0 will disable the time limit
@@ -434,7 +549,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_setTimeout)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_setTimeout is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jclass jni_cid_AdvertiseDataBuilder = (*env)->FindClass(env,
@@ -443,7 +558,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_cid_AdvertiseDataBuilder)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_AdvertiseDataBuilder is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_AdvertiseDataBuilder = (*env)->GetMethodID(env, jni_cid_AdvertiseDataBuilder,
@@ -451,7 +566,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_AdvertiseDataBuilder)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_AdvertiseDataBuilder is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_AdvertiseDataBuilder = (*env)->NewObject(env, jni_cid_AdvertiseDataBuilder,
@@ -459,7 +574,16 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_AdvertiseDataBuilder)
     {
         OIC_LOG(ERROR, TAG, "jni_AdvertiseDataBuilder is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
+    }
+
+    jobject jni_AdvertiseDataBuilderForScanRsp = (*env)->NewObject(env,
+                                                                   jni_cid_AdvertiseDataBuilder,
+                                                                   jni_mid_AdvertiseDataBuilder);
+    if (!jni_AdvertiseDataBuilderForScanRsp)
+    {
+        OIC_LOG(ERROR, TAG, "jni_AdvertiseDataBuilderForScanRsp is null");
+        goto error_exit;
     }
 
     jobject jni_obj_serviceUUID = CALEGetUuidFromString(env, OIC_GATT_SERVICE_UUID);
@@ -483,7 +607,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_addServiceUuid)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_addServiceUuid is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_addServiceUuid = (*env)->CallObjectMethod(env, jni_AdvertiseDataBuilder,
@@ -492,7 +616,30 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_addServiceUuid)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_addServiceUuid is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
+    }
+
+    // Device name has to be included in advertise packet after Android API 23
+    OIC_LOG(DEBUG, TAG, "device name will be added into advertise packet");
+    jmethodID jni_mid_setIncludeDeviceName = (*env)->GetMethodID(env, jni_cid_AdvertiseDataBuilder,
+                                                                 "setIncludeDeviceName",
+                                                                 "(Z)Landroid/"
+                                                                 "bluetooth/le/"
+                                                                 "AdvertiseData$Builder;");
+    if (!jni_mid_setIncludeDeviceName)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_setIncludeDeviceName is null");
+        goto error_exit;
+    }
+
+    jobject jni_obj_setIncludeDeviceName  = (*env)->CallObjectMethod(env,
+                                                               jni_AdvertiseDataBuilderForScanRsp,
+                                                               jni_mid_setIncludeDeviceName,
+                                                               JNI_TRUE);
+    if (!jni_obj_setIncludeDeviceName)
+    {
+        OIC_LOG(ERROR, TAG, "jni_obj_setIncludeDeviceName is null");
+        goto error_exit;
     }
 
     jclass jni_cid_BTAdapter = (*env)->FindClass(env, "android/bluetooth/BluetoothAdapter");
@@ -509,7 +656,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_getDefaultAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_BTAdapter = (*env)->CallStaticObjectMethod(env, jni_cid_BTAdapter,
@@ -517,7 +664,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_BTAdapter is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_getBluetoothLeAdvertiser = (*env)->GetMethodID(env, jni_cid_BTAdapter,
@@ -527,7 +674,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_getBluetoothLeAdvertiser)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getBluetoothLeAdvertiser is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_getBluetoothLeAdvertiser = (*env)->CallObjectMethod(
@@ -535,7 +682,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_getBluetoothLeAdvertiser)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_getBluetoothLeAdvertiser is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_build_LeAdvertiseSettings = (*env)->GetMethodID(env,
@@ -546,7 +693,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_build_LeAdvertiseSettings)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_build_LeAdvertiseSettings is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_build_LeAdvertiseSettings = (*env)->CallObjectMethod(
@@ -554,7 +701,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_build_LeAdvertiseSettings)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_build_LeAdvertiseSettings is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_build_LeAdvertiseData = (*env)->GetMethodID(env, jni_cid_AdvertiseDataBuilder,
@@ -564,7 +711,7 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_build_LeAdvertiseData)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_build_LeAdvertiseData is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_build_LeAdvertiseData = (*env)->CallObjectMethod(env, jni_AdvertiseDataBuilder,
@@ -572,50 +719,91 @@ CAResult_t CALEServerStartAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_build_LeAdvertiseData)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_build_LeAdvertiseData is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
-    jclass jni_cid_leAdvertiser = (*env)->FindClass(env,
-                                                    "android/bluetooth/le/BluetoothLeAdvertiser");
-    if (!jni_cid_leAdvertiser)
+    jobject jni_obj_build_LeAdvertiseDataForScanRsp = (*env)->CallObjectMethod(env,
+                                                                jni_AdvertiseDataBuilderForScanRsp,
+                                                                jni_mid_build_LeAdvertiseData);
+    if (!jni_obj_build_LeAdvertiseDataForScanRsp)
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_leAdvertiser is null");
-        return CA_STATUS_FAILED;
+        OIC_LOG(ERROR, TAG, "jni_obj_build_LeAdvertiseDataForScanRsp is null");
+        goto error_exit;
     }
 
-    jmethodID jni_mid_startAdvertising = (*env)->GetMethodID(env, jni_cid_leAdvertiser,
-                                                             "startAdvertising",
-                                                             "(Landroid/bluetooth/le/"
-                                                             "AdvertiseSettings;Landroid/bluetooth/"
-                                                             "le/AdvertiseData;Landroid/bluetooth/"
-                                                             "le/AdvertiseCallback;)V");
+    jmethodID jni_mid_startAdvertising = CAGetJNIMethodID(env, "android/bluetooth/le/"
+                                                          "BluetoothLeAdvertiser",
+                                                          "startAdvertising",
+                                                          "(Landroid/bluetooth/le/"
+                                                          "AdvertiseSettings;Landroid/bluetooth/"
+                                                          "le/AdvertiseData;Landroid/bluetooth/"
+                                                          "le/AdvertiseData;Landroid/bluetooth/"
+                                                          "le/AdvertiseCallback;)V");
     if (!jni_mid_startAdvertising)
     {
-        OIC_LOG(ERROR, TAG, "jni_mid_startAdvertising is null");
-        return CA_STATUS_FAILED;
+       OIC_LOG(ERROR, TAG, "jni_mid_startAdvertising is null");
+       return CA_STATUS_FAILED;
     }
 
     (*env)->CallVoidMethod(env, jni_obj_getBluetoothLeAdvertiser, jni_mid_startAdvertising,
                            jni_obj_build_LeAdvertiseSettings, jni_obj_build_LeAdvertiseData,
-                           advertiseCallback);
-
-    if ((*env)->ExceptionCheck(env))
+                           jni_obj_build_LeAdvertiseDataForScanRsp, advertiseCallback);
+    if (CACheckJNIException(env))
     {
         OIC_LOG(ERROR, TAG, "StartAdvertising has failed");
-        (*env)->ExceptionDescribe(env);
-        (*env)->ExceptionClear(env);
         return CA_STATUS_FAILED;
     }
 
     OIC_LOG(DEBUG, TAG, "Advertising started!!");
-
     OIC_LOG(DEBUG, TAG, "OUT - CALEServerStartAdvertise");
     return CA_STATUS_OK;
+
+error_exit:
+    CACheckJNIException(env);
+    return CA_STATUS_FAILED;
+}
+
+CAResult_t CALEServerStopAdvertise()
+{
+    if (!g_jvm)
+    {
+        OIC_LOG(ERROR, TAG, "g_jvm is null");
+        return CA_STATUS_FAILED;
+    }
+
+    bool isAttached = false;
+    JNIEnv* env = NULL;
+    jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
+    if (JNI_OK != res)
+    {
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
+        res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
+
+        if (JNI_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
+            return CA_STATUS_FAILED;
+        }
+        isAttached = true;
+    }
+
+    CAResult_t ret = CALEServerStopAdvertiseImpl(env, g_leAdvertiseCallback);
+    if (CA_STATUS_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "CALEServerStopAdvertise has failed");
+    }
+
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
+
+    return ret;
 }
 
-CAResult_t CALEServerStopAdvertise(JNIEnv *env, jobject advertiseCallback)
+CAResult_t CALEServerStopAdvertiseImpl(JNIEnv *env, jobject advertiseCallback)
 {
-    OIC_LOG(DEBUG, TAG, "IN - LEServerStopAdvertise");
+    OIC_LOG(DEBUG, TAG, "CALEServerStopAdvertiseImpl");
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(advertiseCallback, TAG, "advertiseCallback is null");
 
@@ -629,25 +817,17 @@ CAResult_t CALEServerStopAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_cid_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_BTAdapter is null");
-        return CA_STATUS_FAILED;
-    }
-
-    jclass jni_cid_leAdvertiser = (*env)->FindClass(env,
-                                                    "android/bluetooth/le/BluetoothLeAdvertiser");
-    if (!jni_cid_leAdvertiser)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_leAdvertiser is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_getDefaultAdapter = (*env)->GetStaticMethodID(env, jni_cid_BTAdapter,
                                                                     "getDefaultAdapter",
                                                                     "()Landroid/bluetooth/"
                                                                     "BluetoothAdapter;");
-    if (!jni_cid_leAdvertiser)
+    if (!jni_mid_getDefaultAdapter)
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_leAdvertiser is null");
-        return CA_STATUS_FAILED;
+        OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        goto error_exit;
     }
 
     jmethodID jni_mid_getBTLeAdvertiser = (*env)->GetMethodID(env, jni_cid_BTAdapter,
@@ -657,17 +837,18 @@ CAResult_t CALEServerStopAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_mid_getBTLeAdvertiser)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getBTLeAdvertiser is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
-    jmethodID jni_mid_stopAdvertising = (*env)->GetMethodID(env, jni_cid_leAdvertiser,
-                                                            "stopAdvertising",
-                                                            "(Landroid/bluetooth/le/"
-                                                            "AdvertiseCallback;)V");
+    jmethodID jni_mid_stopAdvertising = CAGetJNIMethodID(env, "android/bluetooth/le/"
+                                                         "BluetoothLeAdvertiser",
+                                                         "stopAdvertising",
+                                                         "(Landroid/bluetooth/le/"
+                                                         "AdvertiseCallback;)V");
     if (!jni_mid_stopAdvertising)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_stopAdvertising is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_BTAdapter = (*env)->CallStaticObjectMethod(env, jni_cid_BTAdapter,
@@ -675,7 +856,7 @@ CAResult_t CALEServerStopAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_BTAdapter is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_getBluetoothLeAdvertiser = (*env)->CallObjectMethod(env, jni_obj_BTAdapter,
@@ -683,23 +864,23 @@ CAResult_t CALEServerStopAdvertise(JNIEnv *env, jobject advertiseCallback)
     if (!jni_obj_getBluetoothLeAdvertiser)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_getBluetoothLeAdvertiser is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     (*env)->CallVoidMethod(env, jni_obj_getBluetoothLeAdvertiser, jni_mid_stopAdvertising,
                            advertiseCallback);
-    if ((*env)->ExceptionCheck(env))
+    if (CACheckJNIException(env))
     {
         OIC_LOG(ERROR, TAG, "getBluetoothLeAdvertiser has failed");
-        (*env)->ExceptionDescribe(env);
-        (*env)->ExceptionClear(env);
         return CA_STATUS_FAILED;
     }
 
     OIC_LOG(DEBUG, TAG, "Advertising stopped!!");
-
-    OIC_LOG(DEBUG, TAG, "OUT - LEServerStopAdvertise");
     return CA_STATUS_OK;
+
+error_exit:
+    CACheckJNIException(env);
+    return CA_STATUS_FAILED;
 }
 
 CAResult_t CALEServerStartGattServer(JNIEnv *env, jobject gattServerCallback)
@@ -762,21 +943,14 @@ jobject CALEServerOpenGattServer(JNIEnv *env)
     if (!CALEIsEnableBTAdapter(env))
     {
         OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
-        return NULL;
+        goto error_exit;
     }
 
     jclass jni_cid_context = (*env)->FindClass(env, "android/content/Context");
     if (!jni_cid_context)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_context is null");
-        return NULL;
-    }
-
-    jclass jni_cid_bluetoothManager = (*env)->FindClass(env, "android/bluetooth/BluetoothManager");
-    if (!jni_cid_bluetoothManager)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothManager is null");
-        return NULL;
+        goto error_exit;
     }
 
     jfieldID jni_fid_bluetoothService = (*env)->GetStaticFieldID(env, jni_cid_context,
@@ -785,7 +959,7 @@ jobject CALEServerOpenGattServer(JNIEnv *env)
     if (!jni_fid_bluetoothService)
     {
         OIC_LOG(ERROR, TAG, "jni_fid_bluetoothService is null");
-        return NULL;
+        goto error_exit;
     }
 
     jmethodID jni_mid_getSystemService = (*env)->GetMethodID(env, jni_cid_context,
@@ -795,16 +969,17 @@ jobject CALEServerOpenGattServer(JNIEnv *env)
     if (!jni_mid_getSystemService)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getSystemService is null");
-        return NULL;
+        goto error_exit;
     }
 
-    jmethodID jni_mid_openGattServer = (*env)->GetMethodID(env, jni_cid_bluetoothManager,
-                                                           "openGattServer",
-                                                           "(Landroid/content/Context;"
-                                                           "Landroid/bluetooth/"
-                                                           "BluetoothGattServerCallback;)"
-                                                           "Landroid/bluetooth/"
-                                                           "BluetoothGattServer;");
+    jmethodID jni_mid_openGattServer = CAGetJNIMethodID(env, "android/bluetooth/"
+                                                        "BluetoothManager",
+                                                        "openGattServer",
+                                                        "(Landroid/content/Context;"
+                                                        "Landroid/bluetooth/"
+                                                        "BluetoothGattServerCallback;)"
+                                                        "Landroid/bluetooth/"
+                                                        "BluetoothGattServer;");
     if (!jni_mid_openGattServer)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_openGattServer is null");
@@ -816,7 +991,7 @@ jobject CALEServerOpenGattServer(JNIEnv *env)
     if (!jni_obj_bluetoothService)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_bluetoothService is null");
-        return NULL;
+        goto error_exit;
     }
 
     jobject jni_obj_bluetoothManager = (*env)->CallObjectMethod(env, g_context,
@@ -825,9 +1000,15 @@ jobject CALEServerOpenGattServer(JNIEnv *env)
     if (!jni_obj_bluetoothManager)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_bluetoothManager is null");
-        return NULL;
+        goto error_exit;
     }
 
+    if (g_bluetoothManager)
+    {
+        (*env)->DeleteGlobalRef(env, g_bluetoothManager);
+    }
+    g_bluetoothManager = (*env)->NewGlobalRef(env, jni_obj_bluetoothManager);
+
     jobject jni_obj_bluetoothGattServer = (*env)->CallObjectMethod(env, jni_obj_bluetoothManager,
                                                                    jni_mid_openGattServer,
                                                                    g_context,
@@ -835,11 +1016,15 @@ jobject CALEServerOpenGattServer(JNIEnv *env)
     if (!jni_obj_bluetoothGattServer)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_bluetoothGattServer is null");
-        return NULL;
+        goto error_exit;
     }
 
     OIC_LOG(DEBUG, TAG, "OUT - CALEServerOpenGattServer");
     return jni_obj_bluetoothGattServer;
+
+error_exit:
+    CACheckJNIException(env);
+    return NULL;
 }
 
 jobject CALEServerCreateGattService(JNIEnv *env)
@@ -858,7 +1043,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_cid_bluetoothGattService)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattService is null");
-        return NULL;
+        goto error_exit;
     }
 
     jclass jni_cid_bluetoothGattCharacteristic = (*env)->FindClass(env, "android/bluetooth/"
@@ -866,7 +1051,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_cid_bluetoothGattCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattCharacteristic is null");
-        return NULL;
+        goto error_exit;
     }
 
     jfieldID jni_fid_serviceType = (*env)->GetStaticFieldID(env, jni_cid_bluetoothGattService,
@@ -874,25 +1059,50 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_fid_serviceType)
     {
         OIC_LOG(ERROR, TAG, "jni_fid_serviceType is null");
-        return NULL;
+        goto error_exit;
     }
 
-    jfieldID jni_fid_readProperties = (*env)->GetStaticFieldID(env,
-                                                               jni_cid_bluetoothGattCharacteristic,
-                                                               "PROPERTY_NOTIFY", "I");
-    if (!jni_fid_readProperties)
+    jfieldID jni_fid_readProperties = NULL;
+    jfieldID jni_fid_writeProperties = NULL;
+    if (g_setHighQoS)
     {
-        OIC_LOG(ERROR, TAG, "jni_fid_readProperties is null");
-        return NULL;
-    }
+        jni_fid_readProperties = (*env)->GetStaticFieldID(env,
+                                                          jni_cid_bluetoothGattCharacteristic,
+                                                          "PROPERTY_INDICATE", "I");
+        if (!jni_fid_readProperties)
+        {
+            OIC_LOG(ERROR, TAG, "jni_fid_readProperties is null");
+            goto error_exit;
+        }
 
-    jfieldID jni_fid_writeProperties = (*env)->GetStaticFieldID(env,
-                                                                jni_cid_bluetoothGattCharacteristic,
-                                                                "PROPERTY_WRITE_NO_RESPONSE", "I");
-    if (!jni_fid_writeProperties)
+        jni_fid_writeProperties = (*env)->GetStaticFieldID(env,
+                                                           jni_cid_bluetoothGattCharacteristic,
+                                                           "PROPERTY_WRITE", "I");
+        if (!jni_fid_writeProperties)
+        {
+            OIC_LOG(ERROR, TAG, "jni_fid_writeProperties is null");
+            goto error_exit;
+        }
+    }
+    else
     {
-        OIC_LOG(ERROR, TAG, "jni_fid_writeProperties is null");
-        return NULL;
+        jni_fid_readProperties = (*env)->GetStaticFieldID(env,
+                                                          jni_cid_bluetoothGattCharacteristic,
+                                                          "PROPERTY_NOTIFY", "I");
+        if (!jni_fid_readProperties)
+        {
+            OIC_LOG(ERROR, TAG, "jni_fid_readProperties is null");
+            goto error_exit;
+        }
+
+        jni_fid_writeProperties = (*env)->GetStaticFieldID(env,
+                                                           jni_cid_bluetoothGattCharacteristic,
+                                                           "PROPERTY_WRITE_NO_RESPONSE", "I");
+        if (!jni_fid_writeProperties)
+        {
+            OIC_LOG(ERROR, TAG, "jni_fid_writeProperties is null");
+            goto error_exit;
+        }
     }
 
     jfieldID jni_fid_readPermissions = (*env)->GetStaticFieldID(env,
@@ -901,7 +1111,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_fid_readPermissions)
     {
         OIC_LOG(ERROR, TAG, "jni_fid_readPermissions is null");
-        return NULL;
+        goto error_exit;
     }
 
     jfieldID jni_fid_writePermissions = (*env)->GetStaticFieldID(
@@ -909,7 +1119,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_fid_writePermissions)
     {
         OIC_LOG(ERROR, TAG, "jni_fid_writePermissions is null");
-        return NULL;
+        goto error_exit;
     }
 
     jmethodID jni_mid_bluetoothGattService = (*env)->GetMethodID(env, jni_cid_bluetoothGattService,
@@ -917,7 +1127,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_mid_bluetoothGattService)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_bluetoothGattService is null");
-        return NULL;
+        goto error_exit;
     }
 
     jmethodID jni_mid_addCharacteristic = (*env)->GetMethodID(env, jni_cid_bluetoothGattService,
@@ -927,7 +1137,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_mid_addCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_addCharacteristic is null");
-        return NULL;
+        goto error_exit;
     }
 
     jmethodID jni_mid_bluetoothGattCharacteristic = (*env)->GetMethodID(
@@ -935,7 +1145,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_mid_bluetoothGattCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_bluetoothGattCharacteristic is null");
-        return NULL;
+        goto error_exit;
     }
 
     jobject jni_obj_serviceUUID = CALEGetUuidFromString(env, OIC_GATT_SERVICE_UUID);
@@ -953,7 +1163,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_bluetoothGattService)
     {
         OIC_LOG(ERROR, TAG, "jni_bluetoothGattService is null");
-        return NULL;
+        goto error_exit;
     }
 
     jobject jni_obj_readUuid = CALEGetUuidFromString(env, OIC_GATT_CHARACTERISTIC_RESPONSE_UUID);
@@ -966,14 +1176,17 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     jint jni_int_readProperties = (*env)->GetStaticIntField(env,
                                                             jni_cid_bluetoothGattCharacteristic,
                                                             jni_fid_readProperties);
+    CACheckJNIException(env);
 
     jint jni_int_readPermissions = (*env)->GetStaticIntField(env,
                                                              jni_cid_bluetoothGattCharacteristic,
                                                              jni_fid_readPermissions);
+    CACheckJNIException(env);
 
     jint jni_int_writePermissions = (*env)->GetStaticIntField(env,
                                                               jni_cid_bluetoothGattCharacteristic,
                                                               jni_fid_writePermissions);
+    CACheckJNIException(env);
 
     jobject jni_readCharacteristic = (*env)->NewObject(env, jni_cid_bluetoothGattCharacteristic,
                                                        jni_mid_bluetoothGattCharacteristic,
@@ -983,7 +1196,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_readCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_readCharacteristic is null");
-        return NULL;
+        goto error_exit;
     }
 
     jboolean jni_boolean_addReadCharacteristic = (*env)->CallBooleanMethod(
@@ -991,7 +1204,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_boolean_addReadCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_boolean_addReadCharacteristic is null");
-        return NULL;
+        goto error_exit;
     }
 
     jobject jni_obj_writeUuid = CALEGetUuidFromString(env, OIC_GATT_CHARACTERISTIC_REQUEST_UUID);
@@ -1004,6 +1217,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     jint jni_int_writeProperties = (*env)->GetStaticIntField(env,
                                                              jni_cid_bluetoothGattCharacteristic,
                                                              jni_fid_writeProperties);
+    CACheckJNIException(env);
 
     jobject jni_writeCharacteristic = (*env)->NewObject(env, jni_cid_bluetoothGattCharacteristic,
                                                         jni_mid_bluetoothGattCharacteristic,
@@ -1012,7 +1226,7 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (!jni_writeCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_writeCharacteristic is null");
-        return NULL;
+        goto error_exit;
     }
 
     jboolean jni_boolean_addWriteCharacteristic = (*env)->CallBooleanMethod(
@@ -1020,16 +1234,20 @@ jobject CALEServerCreateGattService(JNIEnv *env)
     if (JNI_FALSE == jni_boolean_addWriteCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "Fail to add jni_boolean_addReadCharacteristic");
-        return NULL;
+        goto error_exit;
     }
 
     OIC_LOG(DEBUG, TAG, "OUT - CALEServerCreateGattService");
     return jni_bluetoothGattService;
+
+error_exit:
+    CACheckJNIException(env);
+    return NULL;
 }
 
 CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEServerAddDescriptor");
+    OIC_LOG(DEBUG, TAG, "CALEServerAddDescriptor");
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(characteristic, TAG, "characteristic is null");
 
@@ -1038,7 +1256,7 @@ CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
     if (!jni_cid_bluetoothGattDescriptor)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattDescriptor is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_bluetoothGattDescriptor = (*env)->GetMethodID(env,
@@ -1048,7 +1266,7 @@ CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
     if (!jni_mid_bluetoothGattDescriptor)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_bluetoothGattDescriptor is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jfieldID jni_fid_readPermissions = (*env)->GetStaticFieldID(env,
@@ -1057,7 +1275,7 @@ CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
     if (!jni_fid_readPermissions)
     {
         OIC_LOG(ERROR, TAG, "jni_fid_readPermissions is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jobject jni_obj_readUuid = CALEGetUuidFromString(env, OIC_GATT_CHARACTERISTIC_CONFIG_UUID);
@@ -1069,6 +1287,7 @@ CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
 
     jint jni_int_readPermissions = (*env)->GetStaticIntField(env, jni_cid_bluetoothGattDescriptor,
                                                              jni_fid_readPermissions);
+    CACheckJNIException(env);
 
     OIC_LOG(DEBUG, TAG, "initialize new Descriptor");
 
@@ -1078,7 +1297,7 @@ CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
     if (!jni_readDescriptor)
     {
         OIC_LOG(ERROR, TAG, "jni_readDescriptor is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jclass jni_cid_GattCharacteristic = (*env)->FindClass(env, "android/bluetooth/"
@@ -1086,7 +1305,7 @@ CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
     if (!jni_cid_GattCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_GattCharacteristic is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_addDescriptor = (*env)->GetMethodID(env, jni_cid_GattCharacteristic,
@@ -1096,7 +1315,7 @@ CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
     if (!jni_mid_addDescriptor)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_addDescriptor is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jboolean jni_boolean_addDescriptor = (*env)->CallBooleanMethod(env, characteristic,
@@ -1106,15 +1325,17 @@ CAResult_t CALEServerAddDescriptor(JNIEnv *env, jobject characteristic)
     if (JNI_FALSE == jni_boolean_addDescriptor)
     {
         OIC_LOG(ERROR, TAG, "addDescriptor has failed");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
     else
     {
         OIC_LOG(DEBUG, TAG, "addDescriptor success");
     }
-
-    OIC_LOG(DEBUG, TAG, "OUT - CALEServerAddDescriptor");
     return CA_STATUS_OK;
+
+error_exit:
+    CACheckJNIException(env);
+    return CA_STATUS_FAILED;
 }
 
 CAResult_t CALEServerAddGattService(JNIEnv *env, jobject bluetoothGattServer,
@@ -1131,23 +1352,15 @@ CAResult_t CALEServerAddGattService(JNIEnv *env, jobject bluetoothGattServer,
         return CA_ADAPTER_NOT_ENABLED;
     }
 
-    jclass jni_cid_bluetoothGattServer = (*env)->FindClass(env,
-                                                           "android/bluetooth/BluetoothGattServer");
-    if (!jni_cid_bluetoothGattServer)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattServer is null");
-        return CA_STATUS_FAILED;
-    }
-
-    jmethodID jni_mid_addService = (*env)->GetMethodID(env, jni_cid_bluetoothGattServer,
-                                                       "addService",
-                                                       "(Landroid/bluetooth/BluetoothGattService;)"
-                                                       "Z");
-    if (!jni_mid_addService)
-    {
-        OIC_LOG(ERROR, TAG, "jni_mid_addService is null");
-        return CA_STATUS_FAILED;
-    }
+    jmethodID jni_mid_addService = CAGetJNIMethodID(env, CLASSPATH_BT_GATTSERVER,
+                                                    "addService",
+                                                    "(Landroid/bluetooth/BluetoothGattService;)"
+                                                    "Z");
+     if (!jni_mid_addService)
+     {
+         OIC_LOG(ERROR, TAG, "jni_mid_addService is null");
+         return CA_STATUS_FAILED;
+     }
 
     jboolean jni_boolean_addService = (*env)->CallBooleanMethod(env, bluetoothGattServer,
                                                                 jni_mid_addService,
@@ -1156,6 +1369,7 @@ CAResult_t CALEServerAddGattService(JNIEnv *env, jobject bluetoothGattServer,
     if (JNI_FALSE == jni_boolean_addService)
     {
         OIC_LOG(ERROR, TAG, "Fail to add GATT service");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -1175,16 +1389,9 @@ CAResult_t CALEServerConnect(JNIEnv *env, jobject bluetoothDevice)
         return CA_ADAPTER_NOT_ENABLED;
     }
 
-    jclass jni_cid_bluetoothGattServer = (*env)->FindClass(env,
-                                                           "android/bluetooth/BluetoothGattServer");
-    if (!jni_cid_bluetoothGattServer)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattServer is null");
-        return CA_STATUS_FAILED;
-    }
-
-    jmethodID jni_mid_connect = (*env)->GetMethodID(env, jni_cid_bluetoothGattServer, "connect",
-                                                    "(Landroid/bluetooth/BluetoothDevice;Z)Z");
+    jmethodID jni_mid_connect = CAGetJNIMethodID(env, CLASSPATH_BT_GATTSERVER,
+                                                 "connect",
+                                                 "(Landroid/bluetooth/BluetoothDevice;Z)Z");
     if (!jni_mid_connect)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_connect is null");
@@ -1197,6 +1404,7 @@ CAResult_t CALEServerConnect(JNIEnv *env, jobject bluetoothDevice)
     if (JNI_FALSE == jni_boolean_connect)
     {
         OIC_LOG(ERROR, TAG, "Fail to connect");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -1209,11 +1417,11 @@ CAResult_t CALEServerDisconnectAllDevices(JNIEnv *env)
     OIC_LOG(DEBUG, TAG, "IN - CALEServerDisconnectAllDevices");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_connectedDeviceListMutex);
+    oc_mutex_lock(g_connectedDeviceListMutex);
     if (!g_connectedDeviceList)
     {
         OIC_LOG(ERROR, TAG, "g_connectedDeviceList is null");
-        ca_mutex_unlock(g_connectedDeviceListMutex);
+        oc_mutex_unlock(g_connectedDeviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -1236,7 +1444,7 @@ CAResult_t CALEServerDisconnectAllDevices(JNIEnv *env)
         }
     }
 
-    ca_mutex_unlock(g_connectedDeviceListMutex);
+    oc_mutex_unlock(g_connectedDeviceListMutex);
     OIC_LOG(DEBUG, TAG, "OUT - CALEServerDisconnectAllDevices");
     return CA_STATUS_OK;
 }
@@ -1253,18 +1461,10 @@ CAResult_t CALEServerDisconnect(JNIEnv *env, jobject bluetoothDevice)
         return CA_ADAPTER_NOT_ENABLED;
     }
 
-    jclass jni_cid_bluetoothGattServer = (*env)->FindClass(env,
-                                                           "android/bluetooth/BluetoothGattServer");
-    if (!jni_cid_bluetoothGattServer)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothGattServer is null");
-        return CA_STATUS_FAILED;
-    }
-
-    jmethodID jni_mid_cancelConnection = (*env)->GetMethodID(env, jni_cid_bluetoothGattServer,
-                                                             "cancelConnection",
-                                                             "(Landroid/bluetooth/BluetoothDevice;)"
-                                                             "V");
+    jmethodID jni_mid_cancelConnection = CAGetJNIMethodID(env, CLASSPATH_BT_GATTSERVER,
+                                                          "cancelConnection",
+                                                          "(Landroid/bluetooth/BluetoothDevice;)"
+                                                          "V");
     if (!jni_mid_cancelConnection)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_cancelConnection is null");
@@ -1273,11 +1473,9 @@ CAResult_t CALEServerDisconnect(JNIEnv *env, jobject bluetoothDevice)
 
     (*env)->CallVoidMethod(env, g_bluetoothGattServer, jni_mid_cancelConnection, bluetoothDevice);
 
-    if ((*env)->ExceptionCheck(env))
+    if (CACheckJNIException(env))
     {
         OIC_LOG(ERROR, TAG, "cancelConnection has failed");
-        (*env)->ExceptionDescribe(env);
-        (*env)->ExceptionClear(env);
         return CA_STATUS_FAILED;
     }
 
@@ -1294,15 +1492,9 @@ CAResult_t CALEServerGattClose(JNIEnv *env, jobject bluetoothGattServer)
 
     // get BluetoothGatt class
     OIC_LOG(DEBUG, TAG, "get BluetoothGatt class");
-    jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, "android/bluetooth/BluetoothGattServer");
-    if (!jni_cid_BluetoothGatt)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null");
-        return CA_STATUS_FAILED;
-    }
-
-    jmethodID jni_mid_closeGatt = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, "close", "()V");
-    if (!jni_mid_closeGatt)
+    jmethodID jni_mid_closeGatt = CAGetJNIMethodID(env, CLASSPATH_BT_GATTSERVER,
+                                                   "close", "()V");
+    if (!jni_mid_closeGatt)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_closeGatt is null");
         return CA_STATUS_OK;
@@ -1312,11 +1504,9 @@ CAResult_t CALEServerGattClose(JNIEnv *env, jobject bluetoothGattServer)
     OIC_LOG(DEBUG, TAG, "request to close GATT");
     (*env)->CallVoidMethod(env, bluetoothGattServer, jni_mid_closeGatt);
 
-    if ((*env)->ExceptionCheck(env))
+    if (CACheckJNIException(env))
     {
         OIC_LOG(ERROR, TAG, "closeGATT has failed");
-        (*env)->ExceptionDescribe(env);
-        (*env)->ExceptionClear(env);
         return CA_STATUS_FAILED;
     }
 
@@ -1354,7 +1544,7 @@ CAResult_t CALEServerSend(JNIEnv *env, jobject bluetoothDevice, jbyteArray respo
     return result;
 }
 
-CAResult_t CALEServerInitialize(ca_thread_pool_t handle)
+CAResult_t CALEServerInitialize()
 {
     OIC_LOG(DEBUG, TAG, "IN - CALEServerInitialize");
 
@@ -1367,7 +1557,7 @@ CAResult_t CALEServerInitialize(ca_thread_pool_t handle)
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -1394,7 +1584,7 @@ CAResult_t CALEServerInitialize(ca_thread_pool_t handle)
         return ret;
     }
 
-    g_threadPoolHandle = handle;
+    g_threadSendNotifyCond = oc_cond_new();
 
     ret = CALEServerInitMutexVaraibles();
     if (CA_STATUS_OK != ret)
@@ -1444,11 +1634,11 @@ void CALEServerTerminate()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
 
         if (JNI_OK != res)
@@ -1459,43 +1649,24 @@ void CALEServerTerminate()
         isAttached = true;
     }
 
-    CAResult_t ret = CALEServerStopMulticastServer(0);
-    if (CA_STATUS_OK != ret)
+    if (g_sendBuffer)
     {
-        OIC_LOG(ERROR, TAG, "CALEServerStopMulticastServer has failed");
+        (*env)->DeleteGlobalRef(env, g_sendBuffer);
+        g_sendBuffer = NULL;
     }
 
-    ret = CALEServerDisconnectAllDevices(env);
-    if (CA_STATUS_OK != ret)
+    if (g_bluetoothManager)
     {
-        OIC_LOG(ERROR, TAG, "CALEServerDisconnectAllDevices has failed");
+        (*env)->DeleteGlobalRef(env, g_bluetoothManager);
+        g_bluetoothManager = NULL;
     }
 
-    ret = CALEServerRemoveAllDevices(env);
-    if (CA_STATUS_OK != ret)
-    {
-        OIC_LOG(ERROR, TAG, "CALEServerRemoveAllDevices has failed");
-    }
-
-    if (g_leAdvertiseCallback)
-    {
-        (*env)->DeleteGlobalRef(env, g_leAdvertiseCallback);
-    }
-
-    if (g_bluetoothGattServer)
-    {
-        (*env)->DeleteGlobalRef(env, g_bluetoothGattServer);
-    }
-
-    if (g_bluetoothGattServerCallback)
-    {
-        (*env)->DeleteGlobalRef(env, g_bluetoothGattServerCallback);
-    }
+    oc_cond_free(g_threadSendNotifyCond);
+    g_threadSendNotifyCond = NULL;
 
     CALEServerTerminateMutexVaraibles();
     CALEServerTerminateConditionVaraibles();
 
-    g_isStartServer = false;
     g_isInitializedServer = false;
 
     if (isAttached)
@@ -1508,7 +1679,7 @@ void CALEServerTerminate()
 
 CAResult_t CALEServerSendUnicastMessage(const char* address, const uint8_t* data, uint32_t dataLen)
 {
-    OIC_LOG_V(DEBUG, TAG, "IN - CALEServerSendUnicastMessage(%s, %p)", address, data);
+    OIC_LOG_V(DEBUG, TAG, "CALEServerSendUnicastMessage(%s, %p)", address, data);
     VERIFY_NON_NULL(address, TAG, "address is null");
     VERIFY_NON_NULL(data, TAG, "data is null");
 
@@ -1519,11 +1690,11 @@ CAResult_t CALEServerSendUnicastMessage(const char* address, const uint8_t* data
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
 
         if (JNI_OK != res)
@@ -1545,13 +1716,12 @@ CAResult_t CALEServerSendUnicastMessage(const char* address, const uint8_t* data
         (*g_jvm)->DetachCurrentThread(g_jvm);
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEServerSendUnicastMessage");
     return ret;
 }
 
 CAResult_t CALEServerSendMulticastMessage(const uint8_t* data, uint32_t dataLen)
 {
-    OIC_LOG_V(DEBUG, TAG, "IN - CALEServerSendMulticastMessage(%p)", data);
+    OIC_LOG_V(DEBUG, TAG, "CALEServerSendMulticastMessage(%p)", data);
     VERIFY_NON_NULL(data, TAG, "data is null");
 
     if (!g_jvm)
@@ -1561,11 +1731,11 @@ CAResult_t CALEServerSendMulticastMessage(const uint8_t* data, uint32_t dataLen)
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
 
         if (JNI_OK != res)
@@ -1587,7 +1757,6 @@ CAResult_t CALEServerSendMulticastMessage(const uint8_t* data, uint32_t dataLen)
         (*g_jvm)->DetachCurrentThread(g_jvm);
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEServerSendMulticastMessage");
     return ret;
 }
 
@@ -1614,11 +1783,11 @@ CAResult_t CALEServerStartMulticastServer()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
 
         if (JNI_OK != res)
@@ -1640,12 +1809,16 @@ CAResult_t CALEServerStartMulticastServer()
     }
 
     // start advertise
-    ret = CALEServerStartAdvertise(env, g_leAdvertiseCallback);
+    ret = CALEServerStartAdvertise();
     if (CA_STATUS_OK != ret)
     {
         OIC_LOG(ERROR, TAG, "CALEServerStartAdvertise has failed");
     }
 
+    // get Constants Value from Android Platform
+    g_state_connected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_CONNECTED");
+    g_state_disconnected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_DISCONNECTED");
+
     if (isAttached)
     {
         (*g_jvm)->DetachCurrentThread(g_jvm);
@@ -1665,29 +1838,7 @@ CAResult_t CALEServerStopMulticastServer()
         return CA_STATUS_FAILED;
     }
 
-    if (!g_jvm)
-    {
-        OIC_LOG(ERROR, TAG, "g_jvm is null");
-        return CA_STATUS_FAILED;
-    }
-
-    bool isAttached = false;
-    JNIEnv* env;
-    jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
-    if (JNI_OK != res)
-    {
-        OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
-        res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
-
-        if (JNI_OK != res)
-        {
-            OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
-            return CA_STATUS_FAILED;
-        }
-        isAttached = true;
-    }
-
-    CAResult_t ret = CALEServerStopAdvertise(env, g_leAdvertiseCallback);
+    CAResult_t ret = CALEServerStopAdvertise();
     if (CA_STATUS_OK != ret)
     {
         OIC_LOG(ERROR, TAG, "CALEServerStopAdvertise has failed");
@@ -1695,11 +1846,6 @@ CAResult_t CALEServerStopMulticastServer()
 
     g_isStartServer = false;
 
-    if (isAttached)
-    {
-        (*g_jvm)->DetachCurrentThread(g_jvm);
-    }
-
     OIC_LOG(DEBUG, TAG, "OUT - CALEServerStopMulticastServer");
     return ret;
 }
@@ -1713,7 +1859,7 @@ void CALEServerSetCallback(CAPacketReceiveCallback callback)
 CAResult_t CALEServerSendUnicastMessageImpl(JNIEnv *env, const char* address, const uint8_t* data,
                                             uint32_t dataLen)
 {
-    OIC_LOG_V(DEBUG, TAG, "IN - CALEServerSendUnicastMessageImpl, address: %s, data: %p",
+    OIC_LOG_V(DEBUG, TAG, "CALEServerSendUnicastMessageImpl, address: %s, data: %p",
             address, data);
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(address, TAG, "address is null");
@@ -1725,7 +1871,8 @@ CAResult_t CALEServerSendUnicastMessageImpl(JNIEnv *env, const char* address, co
         return CA_STATUS_FAILED;
     }
 
-    jobject jni_obj_bluetoothDevice = NULL;
+    oc_mutex_lock(g_threadSendMutex);
+
     uint32_t length = u_arraylist_length(g_connectedDeviceList);
     for (uint32_t index = 0; index < length; index++)
     {
@@ -1734,60 +1881,98 @@ CAResult_t CALEServerSendUnicastMessageImpl(JNIEnv *env, const char* address, co
         if (!jarrayObj)
         {
             OIC_LOG(ERROR, TAG, "jarrayObj is null");
-            return CA_STATUS_FAILED;
+            goto error_exit;
         }
 
         jstring jni_setAddress = CALEGetAddressFromBTDevice(env, jarrayObj);
         if (!jni_setAddress)
         {
             OIC_LOG(ERROR, TAG, "jni_setAddress is null");
-            return CA_STATUS_FAILED;
+            goto error_exit;
         }
         const char* setAddress = (*env)->GetStringUTFChars(env, jni_setAddress, NULL);
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
-            return CA_STATUS_FAILED;
+            goto error_exit;
         }
 
         OIC_LOG_V(DEBUG, TAG, "setAddress : %s", setAddress);
         OIC_LOG_V(DEBUG, TAG, "address : %s", address);
 
-        if (!strcmp(setAddress, address))
+        if (!strcasecmp(setAddress, address))
         {
             OIC_LOG(DEBUG, TAG, "found the device");
-            jni_obj_bluetoothDevice = jarrayObj;
+
+            if (g_obj_bluetoothDevice)
+            {
+                (*env)->DeleteGlobalRef(env, g_obj_bluetoothDevice);
+                g_obj_bluetoothDevice = NULL;
+            }
+
+            if (jarrayObj)
+            {
+                g_obj_bluetoothDevice = (*env)->NewGlobalRef(env, jarrayObj);
+                CACheckJNIException(env);
+            }
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
             break;
         }
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
     }
 
-    if (jni_obj_bluetoothDevice)
+    if (g_obj_bluetoothDevice)
     {
-        jbyteArray jni_bytearr_data = (*env)->NewByteArray(env, dataLen);
-        (*env)->SetByteArrayRegion(env, jni_bytearr_data, 0, dataLen, (jbyte*) data);
+        jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen);
+        CACheckJNIException(env);
+        (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data);
+        CACheckJNIException(env);
+        g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr);
+        CACheckJNIException(env);
 
-        CAResult_t res = CALEServerSend(env, jni_obj_bluetoothDevice, jni_bytearr_data);
+        CAResult_t res = CALEServerSend(env, g_obj_bluetoothDevice, g_sendBuffer);
         if (CA_STATUS_OK != res)
         {
             OIC_LOG(ERROR, TAG, "send has failed");
-            return CA_SEND_FAILED;
+            goto error_exit;
         }
     }
     else
     {
         OIC_LOG(ERROR, TAG, "There are no device to send in the list");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEServerSendUnicastMessageImpl");
+    if (g_sendBuffer)
+    {
+        (*env)->DeleteGlobalRef(env, g_sendBuffer);
+        g_sendBuffer = NULL;
+    }
+
+    oc_mutex_unlock(g_threadSendMutex);
+    OIC_LOG(INFO, TAG, "unicast - send request is successful");
     return CA_STATUS_OK;
+
+error_exit:
+    if (g_sendBuffer)
+    {
+        (*env)->DeleteGlobalRef(env, g_sendBuffer);
+        g_sendBuffer = NULL;
+    }
+
+    if (g_obj_bluetoothDevice)
+    {
+        (*env)->DeleteGlobalRef(env, g_obj_bluetoothDevice);
+        g_obj_bluetoothDevice = NULL;
+    }
+
+    oc_mutex_unlock(g_threadSendMutex);
+    return CA_SEND_FAILED;
 }
 
 CAResult_t CALEServerSendMulticastMessageImpl(JNIEnv *env, const uint8_t *data, uint32_t dataLen)
 {
-    OIC_LOG_V(DEBUG, TAG, "IN - CALEServerSendMulticastMessageImpl, send to, data: %s", data);
+    OIC_LOG_V(DEBUG, TAG, "CALEServerSendMulticastMessageImpl, send to, data: %s", data);
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(data, TAG, "data is null");
 
@@ -1797,6 +1982,21 @@ CAResult_t CALEServerSendMulticastMessageImpl(JNIEnv *env, const uint8_t *data,
         return CA_STATUS_FAILED;
     }
 
+    oc_mutex_lock(g_threadSendMutex);
+
+    OIC_LOG(DEBUG, TAG, "set data into g_sendBuffer for notify");
+    if (g_sendBuffer)
+    {
+        (*env)->DeleteGlobalRef(env, g_sendBuffer);
+        g_sendBuffer = NULL;
+    }
+    jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen);
+    CACheckJNIException(env);
+    (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data);
+    CACheckJNIException(env);
+    g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr);
+    CACheckJNIException(env);
+
     uint32_t length = u_arraylist_length(g_connectedDeviceList);
     for (uint32_t index = 0; index < length; index++)
     {
@@ -1804,43 +2004,91 @@ CAResult_t CALEServerSendMulticastMessageImpl(JNIEnv *env, const uint8_t *data,
         if (!jarrayObj)
         {
             OIC_LOG(ERROR, TAG, "jarrayObj is null");
-            return CA_STATUS_FAILED;
+            continue;
         }
 
         // send data for all device
         jbyteArray jni_bytearr_data = (*env)->NewByteArray(env, dataLen);
+        CACheckJNIException(env);
         (*env)->SetByteArrayRegion(env, jni_bytearr_data, 0, dataLen, (jbyte*) data);
-        CAResult_t res = CALEServerSend(env, jarrayObj, jni_bytearr_data);
+        CACheckJNIException(env);
+
+        jstring jni_address = CALEGetAddressFromBTDevice(env, jarrayObj);
+        if (!jni_address)
+        {
+            OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
+            continue;
+        }
+
+        const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+        if (!address)
+        {
+            OIC_LOG(ERROR, TAG, "address is not available");
+            continue;
+        }
+
+        if (g_obj_bluetoothDevice)
+        {
+            (*env)->DeleteGlobalRef(env, g_obj_bluetoothDevice);
+            g_obj_bluetoothDevice = NULL;
+        }
+
+        if (jarrayObj)
+        {
+            g_obj_bluetoothDevice = (*env)->NewGlobalRef(env, jarrayObj);
+            CACheckJNIException(env);
+        }
+
+        CAResult_t res = CALEServerSend(env, g_obj_bluetoothDevice, jni_bytearr_data);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "send has failed");
-            return CA_SEND_FAILED;
+            OIC_LOG_V(ERROR, TAG, "send has failed for the device[%s]", address);
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
+            if (g_obj_bluetoothDevice)
+            {
+                (*env)->DeleteGlobalRef(env, g_obj_bluetoothDevice);
+                g_obj_bluetoothDevice = NULL;
+            }
+            continue;
         }
+
+        OIC_LOG_V(INFO, TAG, "unicast - send request is successful for a device[%s]", address);
+        (*env)->ReleaseStringUTFChars(env, jni_address, address);
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEServerSendMulticastMessageImpl");
+    if (g_sendBuffer)
+    {
+        (*env)->DeleteGlobalRef(env, g_sendBuffer);
+        g_sendBuffer = NULL;
+    }
+
+    oc_mutex_unlock(g_threadSendMutex);
     return CA_STATUS_OK;
 }
 
 void CALEServerCreateCachedDeviceList()
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEServerCreateCachedDeviceList");
-
-    ca_mutex_lock(g_connectedDeviceListMutex);
+    oc_mutex_lock(g_connectedDeviceListMutex);
     // create new object array
     if (!g_connectedDeviceList)
     {
         OIC_LOG(DEBUG, TAG, "Create device list");
         g_connectedDeviceList = u_arraylist_create();
     }
-    ca_mutex_unlock(g_connectedDeviceListMutex);
+    oc_mutex_unlock(g_connectedDeviceListMutex);
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEServerCreateCachedDeviceList");
+    oc_mutex_lock(g_deviceStateListMutex);
+    // create new object array
+    if (!g_deviceStateList)
+    {
+        OIC_LOG(DEBUG, TAG, "Create device list");
+        g_deviceStateList = u_arraylist_create();
+    }
+    oc_mutex_unlock(g_deviceStateListMutex);
 }
 
 bool CALEServerIsDeviceInList(JNIEnv *env, const char* remoteAddress)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEServerIsDeviceInList");
     VERIFY_NON_NULL_RET(env, TAG, "env is null", false);
     VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", false);
 
@@ -1875,7 +2123,7 @@ bool CALEServerIsDeviceInList(JNIEnv *env, const char* remoteAddress)
             return false;
         }
 
-        if (!strcmp(remoteAddress, setAddress))
+        if (!strcasecmp(remoteAddress, setAddress))
         {
             OIC_LOG(ERROR, TAG, "the device is already set");
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
@@ -1889,7 +2137,6 @@ bool CALEServerIsDeviceInList(JNIEnv *env, const char* remoteAddress)
     }
 
     OIC_LOG(DEBUG, TAG, "there are no device in the list");
-    OIC_LOG(DEBUG, TAG, "OUT - CALEServerCreateCachedDeviceList");
     return false;
 }
 
@@ -1899,12 +2146,12 @@ CAResult_t CALEServerAddDeviceToList(JNIEnv *env, jobject device)
     VERIFY_NON_NULL(device, TAG, "device is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_connectedDeviceListMutex);
+    oc_mutex_lock(g_connectedDeviceListMutex);
 
     if (!g_connectedDeviceList)
     {
         OIC_LOG(ERROR, TAG, "list is null");
-        ca_mutex_unlock(g_connectedDeviceListMutex);
+        oc_mutex_unlock(g_connectedDeviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -1912,7 +2159,7 @@ CAResult_t CALEServerAddDeviceToList(JNIEnv *env, jobject device)
     if (!jni_remoteAddress)
     {
         OIC_LOG(ERROR, TAG, "jni_remoteAddress is null");
-        ca_mutex_unlock(g_connectedDeviceListMutex);
+        oc_mutex_unlock(g_connectedDeviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -1920,7 +2167,7 @@ CAResult_t CALEServerAddDeviceToList(JNIEnv *env, jobject device)
     if (!remoteAddress)
     {
         OIC_LOG(ERROR, TAG, "remoteAddress is null");
-        ca_mutex_unlock(g_connectedDeviceListMutex);
+        oc_mutex_unlock(g_connectedDeviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -1932,7 +2179,7 @@ CAResult_t CALEServerAddDeviceToList(JNIEnv *env, jobject device)
     }
 
     (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
-    ca_mutex_unlock(g_connectedDeviceListMutex);
+    oc_mutex_unlock(g_connectedDeviceListMutex);
     OIC_LOG(DEBUG, TAG, "OUT - CALEServerAddDeviceToList");
     return CA_STATUS_OK;
 }
@@ -1942,11 +2189,11 @@ CAResult_t CALEServerRemoveAllDevices(JNIEnv *env)
     OIC_LOG(DEBUG, TAG, "IN - CALEServerRemoveAllDevices");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_connectedDeviceListMutex);
+    oc_mutex_lock(g_connectedDeviceListMutex);
     if (!g_connectedDeviceList)
     {
         OIC_LOG(ERROR, TAG, "g_connectedDeviceList is null");
-        ca_mutex_unlock(g_connectedDeviceListMutex);
+        oc_mutex_unlock(g_connectedDeviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -1962,7 +2209,7 @@ CAResult_t CALEServerRemoveAllDevices(JNIEnv *env)
 
     OICFree(g_connectedDeviceList);
     g_connectedDeviceList = NULL;
-    ca_mutex_unlock(g_connectedDeviceListMutex);
+    oc_mutex_unlock(g_connectedDeviceListMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT - CALEServerRemoveAllDevices");
     return CA_STATUS_OK;
@@ -1974,11 +2221,11 @@ CAResult_t CALEServerRemoveDevice(JNIEnv *env, jstring address)
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(address, TAG, "address is null");
 
-    ca_mutex_lock(g_connectedDeviceListMutex);
+    oc_mutex_lock(g_connectedDeviceListMutex);
     if (!g_connectedDeviceList)
     {
         OIC_LOG(ERROR, TAG, "no deviceList");
-        ca_mutex_unlock(g_connectedDeviceListMutex);
+        oc_mutex_unlock(g_connectedDeviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -2010,21 +2257,22 @@ CAResult_t CALEServerRemoveDevice(JNIEnv *env, jstring address)
                 continue;
             }
 
-            if (!strcmp(setAddress, remoteAddress))
+            if (!strcasecmp(setAddress, remoteAddress))
             {
                 OIC_LOG_V(DEBUG, TAG, "device address : %s", remoteAddress);
 
                 (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
                 (*env)->ReleaseStringUTFChars(env, address, remoteAddress);
                 (*env)->DeleteGlobalRef(env, jarrayObj);
+                jarrayObj = NULL;
 
                 if (NULL == u_arraylist_remove(g_connectedDeviceList, index))
                 {
                     OIC_LOG(ERROR, TAG, "List removal failed.");
-                    ca_mutex_unlock(g_connectedDeviceListMutex);
+                    oc_mutex_unlock(g_connectedDeviceListMutex);
                     return CA_STATUS_FAILED;
                 }
-                ca_mutex_unlock(g_connectedDeviceListMutex);
+                oc_mutex_unlock(g_connectedDeviceListMutex);
                 return CA_STATUS_OK;
             }
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
@@ -2032,7 +2280,7 @@ CAResult_t CALEServerRemoveDevice(JNIEnv *env, jstring address)
         }
     }
 
-    ca_mutex_unlock(g_connectedDeviceListMutex);
+    oc_mutex_unlock(g_connectedDeviceListMutex);
 
     OIC_LOG(DEBUG, TAG, "there are no device in the device list");
 
@@ -2050,6 +2298,7 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeRegisterGattServerCallback(JNIEnv *
     VERIFY_NON_NULL_VOID(callback, TAG, "callback");
 
     g_bluetoothGattServerCallback = (*env)->NewGlobalRef(env, callback);
+    CACheckJNIException(env);
 }
 
 JNIEXPORT void JNICALL
@@ -2063,6 +2312,7 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeRegisterBluetoothLeAdvertiseCallbac
     VERIFY_NON_NULL_VOID(callback, TAG, "callback");
 
     g_leAdvertiseCallback = (*env)->NewGlobalRef(env, callback);
+    CACheckJNIException(env);
 }
 
 JNIEXPORT void JNICALL
@@ -2076,77 +2326,85 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerConnectionStateChangeCall
     VERIFY_NON_NULL_VOID(obj, TAG, "obj");
     VERIFY_NON_NULL_VOID(device, TAG, "device");
 
-    jclass jni_cid_bluetoothProfile = (*env)->FindClass(env, "android/bluetooth/BluetoothProfile");
-    if (!jni_cid_bluetoothProfile)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_bluetoothProfile is null");
-        return;
-    }
-
-    jfieldID jni_fid_state_connected = (*env)->GetStaticFieldID(env, jni_cid_bluetoothProfile,
-                                                                "STATE_CONNECTED", "I");
-    if(!jni_fid_state_connected)
+    jstring jni_remoteAddress = CALEGetAddressFromBTDevice(env, device);
+    if (!jni_remoteAddress)
     {
-        OIC_LOG(ERROR, TAG, "jni_fid_state_connected is null");
+        OIC_LOG(ERROR, TAG, "jni_remoteAddress is null");
         return;
     }
 
-    jfieldID jni_fid_state_disconnected = (*env)->GetStaticFieldID(env, jni_cid_bluetoothProfile,
-                                                                   "STATE_DISCONNECTED", "I");
-    if(!jni_fid_state_disconnected)
+    const char* remoteAddress = (*env)->GetStringUTFChars(env, jni_remoteAddress, NULL);
+    if (!remoteAddress)
     {
-        OIC_LOG(ERROR, TAG, "jni_fid_state_disconnected is null");
+        OIC_LOG(ERROR, TAG, "remoteAddress is null");
+        CACheckJNIException(env);
         return;
     }
 
-    // STATE_CONNECTED
-    jint jni_int_state_connected = (*env)->GetStaticIntField(env, jni_cid_bluetoothProfile,
-                                                             jni_fid_state_connected);
-
-    // STATE_DISCONNECTED
-    jint jni_int_state_disconnected = (*env)->GetStaticIntField(env, jni_cid_bluetoothProfile,
-                                                                jni_fid_state_disconnected);
-
-    if (newState == jni_int_state_connected)
+    if (newState == g_state_connected)
     {
-
         OIC_LOG(DEBUG, TAG, "LE CONNECTED");
 
-        jstring jni_remoteAddress = CALEGetAddressFromBTDevice(env, device);
-        if (!jni_remoteAddress)
+        if (false == CALEServerIsDeviceInList(env, remoteAddress))
         {
-            OIC_LOG(ERROR, TAG, "jni_remoteAddress is null");
-            return;
+            OIC_LOG(DEBUG, TAG, "add connected device to cache");
+            CALEServerAddDeviceToList(env, device);
         }
 
-        const char* remoteAddress = (*env)->GetStringUTFChars(env, jni_remoteAddress, NULL);
-        if (!remoteAddress)
+        CAResult_t res = CALEUpdateDeviceState(remoteAddress,
+                                               CA_LE_CONNECTION_STATE,
+                                               STATE_CONNECTED,
+                                               g_deviceStateList,
+                                               g_deviceStateListMutex);
+        if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "remoteAddress is null");
-            return;
+            OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
         }
 
-        if (false == CALEServerIsDeviceInList(env, remoteAddress))
+        res = CALEServerStopAdvertise();
+        if (CA_STATUS_OK != res)
         {
-            OIC_LOG(DEBUG, TAG, "add connected device to cache");
-            CALEServerAddDeviceToList(env, device);
+            OIC_LOG(DEBUG, TAG, "CALEServerStopAdvertise has failed");
         }
-        (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
     }
-    else if (newState == jni_int_state_disconnected)
+    else if (newState == g_state_disconnected)
     {
         OIC_LOG(DEBUG, TAG, "LE DISCONNECTED");
-        CAResult_t res = CALEServerGattClose(env, g_bluetoothGattServer);
+
+        jstring jni_remoteAddress = CALEGetAddressFromBTDevice(env, device);
+        CAResult_t res = CALEServerRemoveDevice(env, jni_remoteAddress);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "CALEServerRemoveDevice has failed");
+        }
+
+        res = CALEUpdateDeviceState(remoteAddress,
+                                    CA_LE_CONNECTION_STATE,
+                                    STATE_DISCONNECTED,
+                                    g_deviceStateList,
+                                    g_deviceStateListMutex);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "CALEServerGattClose has failed");
+            OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
+        }
+
+        // start advertise
+        res = CALEServerStartAdvertise();
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "CALEServerStartAdvertise has failed");
         }
     }
     else
     {
+#ifndef TB_LOG
+        (void)status;
+#endif
         OIC_LOG_V(DEBUG, TAG, "LE Connection state is [newState : %d, status %d]", newState,
                 status);
     }
+    (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
+    (*env)->DeleteLocalRef(env, jni_remoteAddress);
 }
 
 JNIEXPORT void JNICALL
@@ -2158,7 +2416,9 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerServiceAddedCallback(JNIE
     VERIFY_NON_NULL_VOID(env, TAG, "env");
     VERIFY_NON_NULL_VOID(obj, TAG, "obj");
     VERIFY_NON_NULL_VOID(gattService, TAG, "gattService");
-
+#ifndef TB_LOG
+    (void)status;
+#endif
     OIC_LOG_V(DEBUG, TAG, "Gatt Service Added Callback(%d)", status);
 }
 
@@ -2175,7 +2435,8 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerCharacteristicReadRequest
 
 JNIEXPORT void JNICALL
 Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerCharacteristicWriteRequestCallback(
-        JNIEnv *env, jobject obj, jobject device, jbyteArray data)
+        JNIEnv *env, jobject obj, jobject device, jbyteArray data,
+        jint requestId, jint offset, jbyteArray value)
 {
     OIC_LOG_V(DEBUG, TAG, "Gatt Server Characteristic Write Request Callback");
     VERIFY_NON_NULL_VOID(env, TAG, "env");
@@ -2183,11 +2444,24 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerCharacteristicWriteReques
     VERIFY_NON_NULL_VOID(device, TAG, "device");
     VERIFY_NON_NULL_VOID(data, TAG, "data");
 
+    if (g_setHighQoS)
+    {
+        CALEServerSendResponse(env, device, requestId, 0, offset, value);
+    }
+    else
+    {
+        (void)requestId;
+        (void)offset;
+        (void)value;
+    }
+
     // get Byte Array and covert to uint8_t*
     jint length = (*env)->GetArrayLength(env, data);
+    CACheckJNIException(env);
 
     jboolean isCopy;
     jbyte *jni_byte_requestData = (jbyte *) (*env)->GetByteArrayElements(env, data, &isCopy);
+    CACheckJNIException(env);
 
     uint8_t* requestData = NULL;
     requestData = OICMalloc(length);
@@ -2212,17 +2486,18 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerCharacteristicWriteReques
     if (!address)
     {
         OIC_LOG(ERROR, TAG, "address is null");
+        CACheckJNIException(env);
         OICFree(requestData);
         return;
     }
 
     OIC_LOG_V(DEBUG, TAG, "remote device address : %s, %p, %d", address, requestData, length);
 
-    ca_mutex_lock(g_bleClientBDAddressMutex);
+    oc_mutex_lock(g_bleClientBDAddressMutex);
     uint32_t sentLength = 0;
     g_CABLEServerDataReceivedCallback(address, requestData, length,
                                       &sentLength);
-    ca_mutex_unlock(g_bleClientBDAddressMutex);
+    oc_mutex_unlock(g_bleClientBDAddressMutex);
 
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
 }
@@ -2237,8 +2512,76 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerNotificationSentCallback(
     VERIFY_NON_NULL_VOID(obj, TAG, "obj");
     VERIFY_NON_NULL_VOID(device, TAG, "device");
 
-    OIC_LOG_V(DEBUG, TAG, "Gatt Server Notification Sent Callback(%d)",
+    OIC_LOG_V(DEBUG, TAG, "Gatt Server Notification Sent Callback (status : %d)",
               status);
+
+    jstring jni_address = CALEGetAddressFromBTDevice(env, device);
+    if (!jni_address)
+    {
+        OIC_LOG(ERROR, TAG, "jni_address is null");
+        return;
+    }
+
+    const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+    if (!address)
+    {
+        OIC_LOG(ERROR, TAG, "address is not available");
+        (*env)->DeleteLocalRef(env, jni_address);
+        return;
+    }
+
+    jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS");
+    if (gatt_success != status) // error case
+    {
+        OIC_LOG(ERROR, TAG, "it will be sent again.");
+
+        CAResult_t res = CALEServerSend(env, device, g_sendBuffer);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "send has failed");
+
+            if (g_obj_bluetoothDevice)
+            {
+                (*env)->DeleteGlobalRef(env, g_obj_bluetoothDevice);
+                g_obj_bluetoothDevice = NULL;
+            }
+
+            oc_mutex_lock(g_threadSendNotifyMutex);
+            g_isSignalSetFlag = true;
+            oc_cond_signal(g_threadSendNotifyCond);
+            oc_mutex_unlock(g_threadSendNotifyMutex);
+
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
+            (*env)->DeleteLocalRef(env, jni_address);
+            return;
+        }
+
+        CALogSendStateInfo(CA_ADAPTER_GATT_BTLE, address, 0, -1,
+                           false, "notifyChar failure");
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "notify success");
+
+        if (g_obj_bluetoothDevice)
+        {
+            (*env)->DeleteGlobalRef(env, g_obj_bluetoothDevice);
+            g_obj_bluetoothDevice = NULL;
+        }
+
+        // next data can be sent
+        oc_mutex_lock(g_threadSendNotifyMutex);
+        OIC_LOG(DEBUG, TAG, "g_isSignalSetFlag is set true and signal");
+        g_isSignalSetFlag = true;
+        oc_cond_signal(g_threadSendNotifyCond);
+        oc_mutex_unlock(g_threadSendNotifyMutex);
+
+        CALogSendStateInfo(CA_ADAPTER_GATT_BTLE, address, 0, -1,
+                           true, "notifyChar success");
+    }
+    (*env)->ReleaseStringUTFChars(env, jni_address, address);
+    (*env)->DeleteLocalRef(env, jni_address);
+
 }
 
 JNIEXPORT void JNICALL
@@ -2261,8 +2604,69 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeAdvertiseStartFailureCallback(JNIEn
     VERIFY_NON_NULL_VOID(env, TAG, "env");
     VERIFY_NON_NULL_VOID(obj, TAG, "obj");
 
-    OIC_LOG_V(ERROR, TAG, "LE Advertise Start Failure Callback(%d)",
-              errorCode);
+    OIC_LOG_V(INFO, TAG, "LE Advertise Start Failure Callback(%d)", errorCode);
+
+    jint data_too_large = CALEGetConstantsValue(env, CLASSPATH_BT_ADVERTISE_CB,
+                                                "ADVERTISE_FAILED_DATA_TOO_LARGE");
+    jint already_started = CALEGetConstantsValue(env, CLASSPATH_BT_ADVERTISE_CB,
+                                                 "ADVERTISE_FAILED_ALREADY_STARTED");
+
+    if (data_too_large == errorCode)
+    {
+        OIC_LOG_V(ERROR, TAG, "advertise data too large. please check length of device name");
+    }
+    else if (already_started == errorCode)
+    {
+        OIC_LOG_V(INFO, TAG, "advertising is already started");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_org_iotivity_ca_CaLeServerInterface_caLeGattServerMtuChangedCallback(JNIEnv * env,
+                                                                          jobject obj,
+                                                                          jobject device,
+                                                                          jint mtu)
+{
+    VERIFY_NON_NULL_VOID(env, TAG, "env");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj");
+    VERIFY_NON_NULL_VOID(device, TAG, "device");
+
+    OIC_LOG_V(INFO, TAG, "gatt MTU size is changed (%d byte)", mtu);
+
+    jstring jni_address = CALEGetAddressFromBTDevice(env, device);
+    if (!jni_address)
+    {
+        OIC_LOG(ERROR, TAG, "jni_address is null");
+        return;
+    }
+
+    const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+    if (!address)
+    {
+        OIC_LOG(ERROR, TAG, "address is not available");
+        (*env)->DeleteLocalRef(env, jni_address);
+        return;
+    }
+
+    // update mtu size
+    CAResult_t res = CALESetMtuSize(address, mtu - CA_BLE_MTU_HEADER_SIZE,
+                                    g_deviceStateList, g_deviceStateListMutex);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "CALESetMtuSize has failed");
+    }
+
+    res = CALEUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                STATE_SEND_MTU_NEGO_SUCCESS,
+                                g_deviceStateList,
+                                g_deviceStateListMutex);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
+    }
+
+    (*env)->ReleaseStringUTFChars(env, jni_address, address);
+    (*env)->DeleteLocalRef(env, jni_address);
 }
 
 /**
@@ -2271,58 +2675,118 @@ Java_org_iotivity_ca_CaLeServerInterface_caLeAdvertiseStartFailureCallback(JNIEn
 
 CAResult_t CAStartLEGattServer()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
+    // start gatt service
+    CALEServerStartMulticastServer();
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAStopLEGattServer()
+{
+    OIC_LOG(DEBUG, TAG, "CAStopLEGattServer");
+
+    if (!g_jvm)
+    {
+        OIC_LOG(ERROR, TAG, "g_jvm is null");
+        return CA_STATUS_FAILED;
+    }
+
+    bool isAttached = false;
+    JNIEnv* env = NULL;
+    jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
+    if (JNI_OK != res)
+    {
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
+        res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
+
+        if (JNI_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
+            return CA_STATUS_FAILED;
+        }
+        isAttached = true;
+    }
 
-    CAResult_t ret = CALEServerInitMutexVaraibles();
+    CAResult_t ret = CALEServerGattClose(env, g_bluetoothGattServer);
     if (CA_STATUS_OK != ret)
     {
-        OIC_LOG(ERROR, TAG, "CALEServerInitMutexVaraibles has failed!");
-        CALEServerTerminateMutexVaraibles();
-        return CA_SERVER_NOT_STARTED;
+        OIC_LOG(ERROR, TAG, "CALEServerGattClose has failed");
+        return CA_STATUS_FAILED;
     }
 
-    ret = CALEServerInitConditionVaraibles();
+    ret = CALEServerStopMulticastServer();
     if (CA_STATUS_OK != ret)
     {
-        OIC_LOG(ERROR, TAG, "CALEServerInitConditionVaraibles has failed!");
-        CALEServerTerminateConditionVaraibles();
-        return CA_SERVER_NOT_STARTED;
+        OIC_LOG(ERROR, TAG, "CALEServerStopMulticastServer has failed");
+        return CA_STATUS_FAILED;
     }
 
-    // start gatt service
-    CALEServerStartMulticastServer();
+    ret = CALEServerDisconnectAllDevices(env);
+    if (CA_STATUS_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "CALEServerDisconnectAllDevices has failed");
+        return CA_STATUS_FAILED;
+    }
+
+    ret = CALEServerRemoveAllDevices(env);
+    if (CA_STATUS_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "CALEServerRemoveAllDevices has failed");
+        return CA_STATUS_FAILED;
+    }
+
+    if (g_leAdvertiseCallback)
+    {
+        (*env)->DeleteGlobalRef(env, g_leAdvertiseCallback);
+    }
+
+    if (g_bluetoothGattServer)
+    {
+        (*env)->DeleteGlobalRef(env, g_bluetoothGattServer);
+    }
+
+    if (g_bluetoothGattServerCallback)
+    {
+        (*env)->DeleteGlobalRef(env, g_bluetoothGattServerCallback);
+    }
+
+    if (g_obj_bluetoothDevice)
+    {
+        (*env)->DeleteGlobalRef(env, g_obj_bluetoothDevice);
+        g_obj_bluetoothDevice = NULL;
+    }
+
+    oc_mutex_lock(g_threadSendNotifyMutex);
+    oc_cond_signal(g_threadSendNotifyCond);
+    oc_mutex_unlock(g_threadSendNotifyMutex);
+
+    g_isStartServer = false;
+
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 }
 
-CAResult_t CAStopLEGattServer()
+CAResult_t CAInitializeLEGattServer()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    OIC_LOG(DEBUG, TAG, "OUT");
-    return CA_STATUS_OK;
+    OIC_LOG(DEBUG, TAG, "Initialize Gatt Server");
+    return CALEServerInitialize();
 }
 
 void CATerminateLEGattServer()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    OIC_LOG(DEBUG, TAG, "Terminat Gatt Server");
+    OIC_LOG(DEBUG, TAG, "Terminate Gatt Server");
     CALEServerTerminate();
-
-    OIC_LOG(DEBUG, TAG, "OUT");
 }
 
 void CASetLEReqRespServerCallback(CABLEDataReceivedCallback callback)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    ca_mutex_lock(g_bleReqRespCbMutex);
+    oc_mutex_lock(g_bleReqRespCbMutex);
     g_CABLEServerDataReceivedCallback = callback;
-    ca_mutex_unlock(g_bleReqRespCbMutex);
-
-    OIC_LOG(DEBUG, TAG, "OUT");
+    oc_mutex_unlock(g_bleReqRespCbMutex);
 }
 
 void CASetBLEServerErrorHandleCallback(CABLEErrorHandleCallback callback)
@@ -2335,103 +2799,140 @@ CAResult_t CAUpdateCharacteristicsToGattClient(const char *address,
                                                uint32_t charValueLen)
 {
     CAResult_t result = CA_SEND_FAILED;
-    OIC_LOG(DEBUG, TAG, "IN");
     VERIFY_NON_NULL(address, TAG, "env is null");
     VERIFY_NON_NULL(charValue, TAG, "device is null");
 
     if (address)
     {
-        OIC_LOG(DEBUG, TAG, "CALEServerSendUnicastData");
         result = CALEServerSendUnicastMessage(address, charValue, charValueLen);
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
-
     return result;
 }
 
 CAResult_t CAUpdateCharacteristicsToAllGattClients(const uint8_t *charValue,
                                                    uint32_t charValueLen)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
     VERIFY_NON_NULL(charValue, TAG, "device is null");
 
-    OIC_LOG(DEBUG, TAG, "CALEServerSendMulticastMessage");
     CAResult_t result = CALEServerSendMulticastMessage(charValue, charValueLen);
 
-    OIC_LOG(DEBUG, TAG, "OUT");
     return result;
 }
 
 void CASetLEServerThreadPoolHandle(ca_thread_pool_t handle)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    CALEServerInitialize(handle);
-
-    OIC_LOG(DEBUG, TAG, "OUT");
+    OIC_LOG(INFO, TAG, "CASetLEServerThreadPoolHandle is not support");
+    (void)handle;
 }
 
 CAResult_t CALEServerInitMutexVaraibles()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
     if (NULL == g_bleReqRespCbMutex)
     {
-        g_bleReqRespCbMutex = ca_mutex_new();
+        g_bleReqRespCbMutex = oc_mutex_new();
         if (NULL == g_bleReqRespCbMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_bleClientBDAddressMutex)
     {
-        g_bleClientBDAddressMutex = ca_mutex_new();
+        g_bleClientBDAddressMutex = oc_mutex_new();
         if (NULL == g_bleClientBDAddressMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_connectedDeviceListMutex)
     {
-        g_connectedDeviceListMutex = ca_mutex_new();
+        g_connectedDeviceListMutex = oc_mutex_new();
         if (NULL == g_connectedDeviceListMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
-    return CA_STATUS_OK;
-}
+    if (NULL == g_threadSendMutex)
+    {
+        g_threadSendMutex = oc_mutex_new();
+        if (NULL == g_threadSendMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_threadSendNotifyMutex)
+    {
+        g_threadSendNotifyMutex = oc_mutex_new();
+        if (NULL == g_threadSendNotifyMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_deviceStateListMutex)
+    {
+        g_deviceStateListMutex = oc_mutex_new();
+        if (NULL == g_deviceStateListMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
 
-CAResult_t CALEServerInitConditionVaraibles()
-{
-    OIC_LOG(DEBUG, TAG, "this method is not supported");
     return CA_STATUS_OK;
 }
 
 void CALEServerTerminateMutexVaraibles()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    ca_mutex_free(g_bleReqRespCbMutex);
+    oc_mutex_free(g_bleReqRespCbMutex);
     g_bleReqRespCbMutex = NULL;
 
-    ca_mutex_free(g_bleClientBDAddressMutex);
+    oc_mutex_free(g_bleClientBDAddressMutex);
     g_bleClientBDAddressMutex = NULL;
 
-    ca_mutex_free(g_connectedDeviceListMutex);
+    oc_mutex_free(g_connectedDeviceListMutex);
     g_connectedDeviceListMutex = NULL;
 
-    OIC_LOG(DEBUG, TAG, "OUT");
+    oc_mutex_free(g_threadSendMutex);
+    g_threadSendMutex = NULL;
+
+    oc_mutex_free(g_threadSendNotifyMutex);
+    g_threadSendNotifyMutex = NULL;
+
+    oc_mutex_free(g_deviceStateListMutex);
+    g_deviceStateListMutex = NULL;
 }
 
 void CALEServerTerminateConditionVaraibles()
 {
     OIC_LOG(DEBUG, TAG, "this method is not supported");
 }
+
+bool CALEServerIsConnected(const char* address)
+{
+    if (CALEIsValidState(address, CA_LE_CONNECTION_STATE,
+                         STATE_SERVICE_CONNECTED,
+                         g_deviceStateList,
+                         g_deviceStateListMutex))
+    {
+        OIC_LOG(DEBUG, TAG, "current state is connected");
+        return true;
+    }
+    OIC_LOG(DEBUG, TAG, "current state is not connected");
+    return false;
+}
+
+uint16_t CALEServerGetMtuSize(const char* address)
+{
+    return CALEGetMtuSize(address, g_deviceStateList, g_deviceStateListMutex);
+}
+