From b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Wed, 7 Sep 2011 14:16:52 -0700 Subject: [PATCH] Add error codes for channel disconnection / connection. Channel connection / disconnection was handled as boolean, doesn't capture all the values. Also make it asynchronous instead of the dbus call being synchronous. Change-Id: If30177b9f93b7c83f162fbbc1233edf3e46dbfea --- .../android/bluetooth/BluetoothHealth.java | 14 ++++ .../android/server/BluetoothEventLoop.java | 17 ++++ .../server/BluetoothHealthProfileHandler.java | 46 ++++++----- .../java/android/server/BluetoothService.java | 13 ++- core/jni/android_bluetooth_common.h | 7 ++ .../jni/android_server_BluetoothEventLoop.cpp | 37 +++++++++ core/jni/android_server_BluetoothService.cpp | 80 +++++++++---------- 7 files changed, 150 insertions(+), 64 deletions(-) diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java index c165d9231d62e..9b2b8cad20fea 100644 --- a/core/java/android/bluetooth/BluetoothHealth.java +++ b/core/java/android/bluetooth/BluetoothHealth.java @@ -81,6 +81,20 @@ public final class BluetoothHealth implements BluetoothProfile { */ public static final int CHANNEL_TYPE_ANY = 12; + /** @hide */ + public static final int HEALTH_OPERATION_SUCCESS = 6000; + /** @hide */ + public static final int HEALTH_OPERATION_ERROR = 6001; + /** @hide */ + public static final int HEALTH_OPERATION_INVALID_ARGS = 6002; + /** @hide */ + public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003; + /** @hide */ + public static final int HEALTH_OPERATION_NOT_FOUND = 6004; + /** @hide */ + public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005; + + /** * Register an application configuration that acts as a Health SINK. * This is the configuration that will be used to communicate with health devices diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 6eff796726e09..5dd8cd71d3b74 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -20,6 +20,7 @@ import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHealth; import android.bluetooth.BluetoothInputDevice; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; @@ -980,6 +981,22 @@ class BluetoothEventLoop { } } + /** + * Called by native code for the async response to a Connect + * method call to org.bluez.Health + * + * @param chanCode The internal id of the channel + * @param result Result code of the operation. + */ + private void onHealthDeviceConnectionResult(int chanCode, int result) { + log ("onHealthDeviceConnectionResult " + chanCode + " " + result); + // Success case gets handled by Property Change signal + if (result != BluetoothHealth.HEALTH_OPERATION_SUCCESS) { + mBluetoothService.onHealthDeviceChannelConnectionError(chanCode, + BluetoothHealth.STATE_CHANNEL_DISCONNECTED); + } + } + /** * Called by native code on a DeviceDisconnected signal from * org.bluez.NetworkServer. diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java index a6ada2bf3548e..2d80de4528bf8 100644 --- a/core/java/android/server/BluetoothHealthProfileHandler.java +++ b/core/java/android/server/BluetoothHealthProfileHandler.java @@ -84,7 +84,6 @@ final class BluetoothHealthProfileHandler { result = 31 * result + (mChannelPath == null ? 0 : mChannelPath.hashCode()); result = 31 * result + mDevice.hashCode(); result = 31 * result + mConfig.hashCode(); - result = 31 * result + mState; result = 31 * result + mChannelType; return result; } @@ -152,7 +151,7 @@ final class BluetoothHealthProfileHandler { String channelType = getStringChannelType(chan.mChannelType); if (!mBluetoothService.createChannelNative(deviceObjectPath, configPath, - channelType)) { + channelType, chan.hashCode())) { int prevState = chan.mState; int state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED; callHealthChannelCallback(chan.mConfig, chan.mDevice, prevState, state, null, @@ -258,7 +257,7 @@ final class BluetoothHealthProfileHandler { boolean disconnectChannel(BluetoothDevice device, BluetoothHealthAppConfiguration config, int id) { - HealthChannel chan = findChannelById(device, config, id); + HealthChannel chan = findChannelById(id); if (chan == null) { return false; } @@ -273,7 +272,8 @@ final class BluetoothHealthProfileHandler { callHealthChannelCallback(config, device, prevState, chan.mState, null, chan.hashCode()); - if (!mBluetoothService.destroyChannelNative(deviceObjectPath, chan.mChannelPath)) { + if (!mBluetoothService.destroyChannelNative(deviceObjectPath, chan.mChannelPath, + chan.hashCode())) { prevState = chan.mState; chan.mState = BluetoothHealth.STATE_CHANNEL_CONNECTED; callHealthChannelCallback(config, device, prevState, chan.mState, @@ -284,8 +284,7 @@ final class BluetoothHealthProfileHandler { } } - private HealthChannel findChannelById(BluetoothDevice device, - BluetoothHealthAppConfiguration config, int id) { + private HealthChannel findChannelById(int id) { for (HealthChannel chan : mHealthChannels) { if (chan.hashCode() == id) return chan; } @@ -384,6 +383,15 @@ final class BluetoothHealthProfileHandler { } } + /*package*/ void onHealthDeviceChannelConnectionError(int chanCode, + int state) { + HealthChannel channel = findChannelById(chanCode); + if (channel == null) errorLog("No record of this channel:" + chanCode); + + callHealthChannelCallback(channel.mConfig, channel.mDevice, channel.mState, state, null, + chanCode); + } + private BluetoothHealthAppConfiguration findHealthApplication( BluetoothDevice device, String channelPath) { BluetoothHealthAppConfiguration config = null; @@ -424,9 +432,19 @@ final class BluetoothHealthProfileHandler { config = findHealthApplication(device, channelPath); if (exists) { + channel = findConnectingChannel(device, config); + if (channel == null) { + channel = new HealthChannel(device, config, null, false, + channelPath); + channel.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED; + mHealthChannels.add(channel); + } + channel.mChannelPath = channelPath; + fd = mBluetoothService.getChannelFdNative(channelPath); if (fd == null) { errorLog("Error obtaining fd for channel:" + channelPath); + disconnectChannel(device, config, channel.hashCode()); return; } boolean mainChannel = @@ -440,18 +458,10 @@ final class BluetoothHealthProfileHandler { } if (mainChannelPath.equals(channelPath)) mainChannel = true; } - channel = findConnectingChannel(device, config); - if (channel != null) { - channel.mChannelFd = fd; - channel.mMainChannel = mainChannel; - channel.mChannelPath = channelPath; - prevState = channel.mState; - } else { - channel = new HealthChannel(device, config, fd, mainChannel, - channelPath); - mHealthChannels.add(channel); - prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED; - } + + channel.mChannelFd = fd; + channel.mMainChannel = mainChannel; + prevState = channel.mState; state = BluetoothHealth.STATE_CHANNEL_CONNECTED; } else { channel = findChannelByPath(device, channelPath); diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index 95474fe68faed..c5117e59144ad 100755 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -2276,6 +2276,14 @@ public class BluetoothService extends IBluetooth.Stub { } } + /*package*/ void onHealthDeviceChannelConnectionError(int channelCode, + int newState) { + synchronized(mBluetoothHealthProfileHandler) { + mBluetoothHealthProfileHandler.onHealthDeviceChannelConnectionError(channelCode, + newState); + } + } + public int getHealthDeviceConnectionState(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); @@ -2806,8 +2814,9 @@ public class BluetoothService extends IBluetooth.Stub { String channelType); native String registerHealthApplicationNative(int dataType, String role, String name); native boolean unregisterHealthApplicationNative(String path); - native boolean createChannelNative(String devicePath, String appPath, String channelType); - native boolean destroyChannelNative(String devicePath, String channelpath); + native boolean createChannelNative(String devicePath, String appPath, String channelType, + int code); + native boolean destroyChannelNative(String devicePath, String channelpath, int code); native String getMainChannelNative(String path); native String getChannelApplicationNative(String channelPath); native ParcelFileDescriptor getChannelFdNative(String channelPath); diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h index 2f5fd5a87c285..1f4da3afdacac 100644 --- a/core/jni/android_bluetooth_common.h +++ b/core/jni/android_bluetooth_common.h @@ -202,6 +202,13 @@ bool debug_no_encrypt(); #define INPUT_OPERATION_GENERIC_FAILURE 5003 #define INPUT_OPERATION_SUCCESS 5004 +#define HEALTH_OPERATION_SUCCESS 6000 +#define HEALTH_OPERATION_ERROR 6001 +#define HEALTH_OPERATION_INVALID_ARGS 6002 +#define HEALTH_OPERATION_GENERIC_FAILURE 6003 +#define HEALTH_OPERATION_NOT_FOUND 6004 +#define HEALTH_OPERATION_NOT_ALLOWED 6005 + #endif } /* namespace android */ diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index eee256a1dc783..0335ce7df7c0c 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -74,6 +74,7 @@ static jmethodID method_onPanDevicePropertyChanged; static jmethodID method_onPanDeviceConnectionResult; static jmethodID method_onHealthDevicePropertyChanged; static jmethodID method_onHealthDeviceChannelChanged; +static jmethodID method_onHealthDeviceConnectionResult; typedef event_loop_native_data_t native_data_t; @@ -141,6 +142,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) { "(Ljava/lang/String;[Ljava/lang/String;)V"); method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult", "(Ljava/lang/String;I)V"); + method_onHealthDeviceConnectionResult = env->GetMethodID(clazz, + "onHealthDeviceConnectionResult", + "(II)V"); method_onHealthDevicePropertyChanged = env->GetMethodID(clazz, "onHealthDevicePropertyChanged", "(Ljava/lang/String;[Ljava/lang/String;)V"); method_onHealthDeviceChannelChanged = env->GetMethodID(clazz, "onHealthDeviceChannelChanged", @@ -1533,6 +1537,39 @@ void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *n) { free(user); } +void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *n) { + LOGV("%s", __FUNCTION__); + + native_data_t *nat = (native_data_t *)n; + DBusError err; + dbus_error_init(&err); + JNIEnv *env; + nat->vm->GetEnv((void**)&env, nat->envVer); + + jint result = HEALTH_OPERATION_SUCCESS; + if (dbus_set_error_from_message(&err, msg)) { + if (!strcmp(err.name, BLUEZ_ERROR_IFC ".InvalidArgs")) { + result = HEALTH_OPERATION_INVALID_ARGS; + } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".HealthError")) { + result = HEALTH_OPERATION_ERROR; + } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotFound")) { + result = HEALTH_OPERATION_NOT_FOUND; + } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotAllowed")) { + result = HEALTH_OPERATION_NOT_ALLOWED; + } else { + result = HEALTH_OPERATION_GENERIC_FAILURE; + } + LOG_AND_FREE_DBUS_ERROR(&err); + } + + LOGV("... Health Device Code = %d, result = %d", code, result); + jint code = *(int *) user; + env->CallVoidMethod(nat->me, + method_onHealthDeviceConnectionResult, + code, + result); + free(user); +} #endif static JNINativeMethod sMethods[] = { diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp index 292047b224dd2..a49c91802b423 100644 --- a/core/jni/android_server_BluetoothService.cpp +++ b/core/jni/android_server_BluetoothService.cpp @@ -78,8 +78,8 @@ void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat); void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat); void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat); void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *nat); -void onConnectPanResult(DBusMessage *msg, void *user, void *n); void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *nat); +void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *nat); /** Get native data stored in the opaque (Java code maintained) pointer mNativeData @@ -1450,79 +1450,70 @@ static jboolean unregisterHealthApplicationNative(JNIEnv *env, jobject object, } static jboolean createChannelNative(JNIEnv *env, jobject object, - jstring devicePath, jstring appPath, jstring config) { + jstring devicePath, jstring appPath, jstring config, + jint code) { LOGV("%s", __FUNCTION__); - jboolean result = JNI_FALSE; #ifdef HAVE_BLUETOOTH native_data_t *nat = get_native_data(env, object); + jobject eventLoop = env->GetObjectField(object, field_mEventLoop); + struct event_loop_native_data_t *eventLoopNat = + get_EventLoop_native_data(env, eventLoop); - if (nat) { - DBusError err; - dbus_error_init(&err); - + if (nat && eventLoopNat) { const char *c_device_path = env->GetStringUTFChars(devicePath, NULL); const char *c_app_path = env->GetStringUTFChars(appPath, NULL); const char *c_config = env->GetStringUTFChars(config, NULL); + int *data = (int *) malloc(sizeof(int)); + if (data == NULL) return JNI_FALSE; - DBusMessage *reply = dbus_func_args(env, nat->conn, - c_device_path, - DBUS_HEALTH_DEVICE_IFACE, - "CreateChannel", - DBUS_TYPE_OBJECT_PATH, &c_app_path, - DBUS_TYPE_STRING, &c_config, - DBUS_TYPE_INVALID); + *data = code; + bool ret = dbus_func_args_async(env, nat->conn, -1, onHealthDeviceConnectionResult, + data, eventLoopNat, c_device_path, + DBUS_HEALTH_DEVICE_IFACE, "CreateChannel", + DBUS_TYPE_OBJECT_PATH, &c_app_path, + DBUS_TYPE_STRING, &c_config, + DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(devicePath, c_device_path); env->ReleaseStringUTFChars(appPath, c_app_path); env->ReleaseStringUTFChars(config, c_config); - if (!reply) { - if (dbus_error_is_set(&err)) { - LOG_AND_FREE_DBUS_ERROR(&err); - } - } else { - result = JNI_TRUE; - } + return ret ? JNI_TRUE : JNI_FALSE; } #endif - return result; + return JNI_FALSE; } static jboolean destroyChannelNative(JNIEnv *env, jobject object, jstring devicePath, - jstring channelPath) { + jstring channelPath, jint code) { LOGE("%s", __FUNCTION__); - jboolean result = JNI_FALSE; #ifdef HAVE_BLUETOOTH native_data_t *nat = get_native_data(env, object); + jobject eventLoop = env->GetObjectField(object, field_mEventLoop); + struct event_loop_native_data_t *eventLoopNat = + get_EventLoop_native_data(env, eventLoop); - if (nat) { - DBusError err; - dbus_error_init(&err); - + if (nat && eventLoopNat) { const char *c_device_path = env->GetStringUTFChars(devicePath, NULL); const char *c_channel_path = env->GetStringUTFChars(channelPath, NULL); + int *data = (int *) malloc(sizeof(int)); + if (data == NULL) return JNI_FALSE; - DBusMessage *reply = dbus_func_args(env, nat->conn, - c_device_path, - DBUS_HEALTH_DEVICE_IFACE, - "DestroyChannel", - DBUS_TYPE_OBJECT_PATH, &c_channel_path, - DBUS_TYPE_INVALID); + *data = code; + bool ret = dbus_func_args_async(env, nat->conn, -1, onHealthDeviceConnectionResult, + data, eventLoopNat, c_device_path, + DBUS_HEALTH_DEVICE_IFACE, "DestroyChannel", + DBUS_TYPE_OBJECT_PATH, &c_channel_path, + DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(devicePath, c_device_path); env->ReleaseStringUTFChars(channelPath, c_channel_path); - if (!reply) { - if (dbus_error_is_set(&err)) { - LOG_AND_FREE_DBUS_ERROR(&err); - } - } else { - result = JNI_TRUE; - } + return ret ? JNI_TRUE : JNI_FALSE; } #endif - return result; + return JNI_FALSE; } static jstring getMainChannelNative(JNIEnv *env, jobject object, jstring devicePath) { @@ -1755,9 +1746,10 @@ static JNINativeMethod sMethods[] = { {"unregisterHealthApplicationNative", "(Ljava/lang/String;)Z", (void *)unregisterHealthApplicationNative}, - {"createChannelNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z", + {"createChannelNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z", (void *)createChannelNative}, - {"destroyChannelNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)destroyChannelNative}, + {"destroyChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", + (void *)destroyChannelNative}, {"getMainChannelNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getMainChannelNative}, {"getChannelApplicationNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getChannelApplicationNative},