Rework the property parsing code.

1. Fix and remove CodeDuplication TODO
2. Fix crash while unpairing.
3. For array properties, make it a bit more efficient by passing,
   lesser String objects from JNI.
4. Remove void pointer usage and use union to make code more readble.
This commit is contained in:
Jaikumar Ganesh
2009-06-24 16:42:51 -07:00
parent afed82bca9
commit 8bc8ce44f7
3 changed files with 230 additions and 234 deletions

View File

@@ -545,15 +545,28 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
return;
}
for (int i = 0; i < properties.length; i+=2) {
String value = null;
if (mProperties.containsKey(properties[i])) {
value = mProperties.get(properties[i]);
value = value + ',' + properties[i+1];
} else
value = properties[i+1];
mProperties.put(properties[i], value);
for (int i = 0; i < properties.length; i++) {
String name = properties[i];
String newValue;
int len;
if (name == null) {
Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
continue;
}
if (name.equals("Devices")) {
len = Integer.valueOf(properties[++i]);
if (len != 0)
newValue = "";
else
newValue = null;
for (int j = 0; j < len; j++) {
newValue += properties[++i] + ",";
}
} else {
newValue = properties[++i];
}
mProperties.put(name, newValue);
}
// Add adapter object path property.
@@ -819,15 +832,27 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
propertyValues = new HashMap<String, String>();
}
for (int i = 0; i < properties.length; i+=2) {
String value = null;
if (propertyValues.containsKey(properties[i])) {
value = propertyValues.get(properties[i]);
value = value + ',' + properties[i+1];
} else {
value = properties[i+1];
for (int i = 0; i < properties.length; i++) {
String name = properties[i];
String newValue;
int len;
if (name == null) {
Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
continue;
}
propertyValues.put(properties[i], value);
if (name.equals("UUIDs") || name.equals("Nodes")) {
len = Integer.valueOf(properties[++i]);
if (len != 0)
newValue = "";
else
newValue = null;
for (int j = 0; j < len; j++) {
newValue += properties[++i] + ",";
}
} else {
newValue = properties[++i];
}
propertyValues.put(name, newValue);
}
mRemoteDeviceProperties.put(address, propertyValues);
}

View File

@@ -260,11 +260,15 @@ class BluetoothEventLoop {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mBluetoothService.setProperty(name, propValues[1]);
} else if (name.equals("Devices")) {
String value = "";
for (int i = 1; i < propValues.length; i++) {
value = value + propValues[i] + ',';
String value = null;
int len = Integer.valueOf(propValues[1]);
if (len > 0) {
value = "";
for (int i = 2; i < propValues.length; i++) {
value = value + propValues[i] + ',';
}
}
mBluetoothService.setProperty(name, value.equals("") ? null : value);
mBluetoothService.setProperty(name, value);
} else if (name.equals("Powered")) {
// bluetoothd has restarted, re-read all our properties.
// Note: bluez only sends this property change when it restarts.
@@ -303,12 +307,15 @@ class BluetoothEventLoop {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
} else if (name.equals("UUIDs")) {
String uuid = "" ;
for (int i = 1; i < propValues.length; i++) {
uuid = uuid + propValues[i] + ",";
String uuid = null;
int len = Integer.valueOf(propValues[1]);
if (len > 0) {
uuid = "";
for (int i = 2; i < propValues.length; i++) {
uuid = uuid + propValues[i] + ",";
}
}
mBluetoothService.setRemoteDeviceProperty(address, name,
uuid.equals("") ? null : uuid);
mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
}
}

View File

@@ -67,6 +67,11 @@ static Properties adapter_properties[] = {
{"Devices", DBUS_TYPE_ARRAY},
};
typedef union {
char *str_val;
int int_val;
char **array_val;
} property_value;
jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
const char *mtype) {
@@ -466,258 +471,217 @@ void append_variant(DBusMessageIter *iter, int type, void *val)
dbus_message_iter_close_container(iter, &value_iter);
}
//TODO(): Remove code duplication between parse_properties and
//parse_property_change
jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
const int max_num_properties) {
DBusMessageIter dict_entry, dict, prop_val, device_val, array_val_iter;
jobjectArray strArray = NULL;
char * property;
char values[max_num_properties][256];
char **uuid_array = NULL;
char **device_path = NULL;
char **array_elements = NULL;
char *string_val;
uint32_t int_val, bool_val;
int i, j, k, type, array_type, num_array_elements = 0;
int ret, num_properties = 0, num_uuids = 0, num_devices = 0;
jclass stringClass = env->FindClass("java/lang/String");
DBusError err;
dbus_error_init(&err);
for (i = 0; i < max_num_properties; i++)
memset(values[i], '\0', 128 * sizeof(char));
if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
goto failure;
dbus_message_iter_recurse(iter, &dict);
do {
if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
goto failure;
dbus_message_iter_recurse(&dict, &dict_entry);
if (dbus_message_iter_get_arg_type(&dict_entry) != DBUS_TYPE_STRING)
goto failure;
dbus_message_iter_get_basic(&dict_entry, &property);
if (!dbus_message_iter_next(&dict_entry))
goto failure;
if (dbus_message_iter_get_arg_type(&dict_entry) != DBUS_TYPE_VARIANT)
goto failure;
for (i = 0; i < max_num_properties; i++) {
if (!strncmp(properties[i].name, property, strlen(property))) {
num_properties ++;
break;
}
}
if (i == max_num_properties)
goto failure;
type = properties[i].type;
dbus_message_iter_recurse(&dict_entry, &prop_val);
if(dbus_message_iter_get_arg_type(&prop_val) != type) {
LOGE("Property type mismatch in parse_properties: %d, expected:%d",
dbus_message_iter_get_arg_type(&prop_val), type);
goto failure;
}
switch(type) {
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
dbus_message_iter_get_basic(&prop_val, &string_val);
strcpy(values[i], string_val);
break;
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT16:
dbus_message_iter_get_basic(&prop_val, &int_val);
sprintf(values[i], "%d", int_val);
break;
case DBUS_TYPE_BOOLEAN:
dbus_message_iter_get_basic(&prop_val, &bool_val);
sprintf(values[i], "%s", bool_val ? "true" : "false");
break;
case DBUS_TYPE_ARRAY:
dbus_message_iter_recurse(&prop_val, &array_val_iter);
array_type = dbus_message_iter_get_arg_type(&array_val_iter);
num_array_elements = 0;
if (array_type == DBUS_TYPE_OBJECT_PATH ||
array_type == DBUS_TYPE_STRING){
do {
num_array_elements++;
} while(dbus_message_iter_next(&array_val_iter));
dbus_message_iter_recurse(&prop_val, &array_val_iter);
// Allocate an array
array_elements = (char **)malloc(sizeof(char *) *
num_array_elements);
if (!array_elements)
goto failure;
j = 0;
do {
dbus_message_iter_get_basic(&array_val_iter, &array_elements[j]);
j++;
} while(dbus_message_iter_next(&array_val_iter));
if (!strncmp(property, "UUIDs", strlen("UUIDs"))) {
num_uuids = num_array_elements;
uuid_array = array_elements;
} else {
num_devices = num_array_elements;
device_path = array_elements;
}
}
break;
default:
goto failure;
}
} while(dbus_message_iter_next(&dict));
// Convert it to a array of strings.
strArray = env->NewObjectArray((num_properties + num_array_elements) * 2,
stringClass, NULL);
j = 0;
for (i = 0; i < max_num_properties; i++) {
if (properties[i].type == DBUS_TYPE_ARRAY) {
if (!strncmp(properties[i].name, "UUIDs", strlen("UUIDs"))) {
num_array_elements = num_uuids;
array_elements = uuid_array;
} else {
num_array_elements = num_devices;
array_elements = device_path;
}
for (k = 0; k < num_array_elements; k++) {
set_object_array_element(env, strArray, properties[i].name, j++);
set_object_array_element(env, strArray, array_elements[k], j++);
}
} else if (values[i][0] != '\0') {
set_object_array_element(env, strArray, properties[i].name, j++);
set_object_array_element(env, strArray, values[i], j++);
}
}
if (uuid_array)
free(uuid_array);
if (device_path)
free(device_path);
return strArray;
failure:
if (dbus_error_is_set(&err))
LOG_AND_FREE_DBUS_ERROR(&err);
if (uuid_array)
free(uuid_array);
if (device_path)
free(device_path);
return NULL;
}
jobjectArray create_prop_array(JNIEnv *env, Properties *properties,
int prop_index, void *value, int len ) {
jclass stringClass= env->FindClass("java/lang/String");
char **prop_val = NULL;
char buf[32] = {'\0'};
int i, j;
jobjectArray strArray = env->NewObjectArray(1 + len, stringClass, NULL);
j = 0;
set_object_array_element(env, strArray, properties[prop_index].name, j++);
if (properties[prop_index].type == DBUS_TYPE_UINT32) {
sprintf(buf, "%d", *(int *) value);
set_object_array_element(env, strArray, buf, j++);
} else if (properties[prop_index].type == DBUS_TYPE_BOOLEAN) {
sprintf(buf, "%s", *(int *) value ? "true" : "false");
set_object_array_element(env, strArray, buf, j++);
} else if (properties[prop_index].type == DBUS_TYPE_ARRAY) {
prop_val = (char **) value;
for (i = 0; i < len; i++)
set_object_array_element(env, strArray, prop_val[i], j++);
} else {
set_object_array_element(env, strArray, (const char *) value, j++);
}
if (prop_val)
free (prop_val);
return strArray;
}
jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
Properties *properties, int max_num_properties) {
DBusMessageIter iter, prop_val, array_val_iter;
DBusError err;
void *value;
char *property;
int get_property(DBusMessageIter iter, Properties *properties,
int max_num_properties, int *prop_index, property_value *value, int *len) {
DBusMessageIter prop_val, array_val_iter;
char *property = NULL;
uint32_t array_type;
int i, j, type, len, prop_index;
char *str_val;
int i, j, type, int_val;
dbus_error_init(&err);
if (!dbus_message_iter_init(msg, &iter))
goto failure;
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
goto failure;
return -1;
dbus_message_iter_get_basic(&iter, &property);
if (!dbus_message_iter_next(&iter))
goto failure;
return -1;
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
goto failure;
return -1;
for (i = 0; i < max_num_properties; i++) {
if (!strncmp(property, properties[i].name, strlen(properties[i].name)))
if (!strncmp(property, properties[i].name, strlen(property)))
break;
}
prop_index = i;
*prop_index = i;
if (i == max_num_properties)
goto failure;
return -1;
dbus_message_iter_recurse(&iter, &prop_val);
type = properties[prop_index].type;
type = properties[*prop_index].type;
if (dbus_message_iter_get_arg_type(&prop_val) != type) {
LOGE("Property type mismatch in parse_properties: %d, expected:%d",
dbus_message_iter_get_arg_type(&prop_val), type);
goto failure;
LOGE("Property type mismatch in get_property: %d, expected:%d, index:%d",
dbus_message_iter_get_arg_type(&prop_val), type, *prop_index);
return -1;
}
switch(type) {
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
dbus_message_iter_get_basic(&prop_val, &value);
len = 1;
dbus_message_iter_get_basic(&prop_val, &value->str_val);
*len = 1;
break;
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT16:
case DBUS_TYPE_BOOLEAN:
uint32_t int_val;
dbus_message_iter_get_basic(&prop_val, &int_val);
value = &int_val;
len = 1;
value->int_val = int_val;
*len = 1;
break;
case DBUS_TYPE_ARRAY:
dbus_message_iter_recurse(&prop_val, &array_val_iter);
array_type = dbus_message_iter_get_arg_type(&array_val_iter);
len = 0;
*len = 0;
value->array_val = NULL;
if (array_type == DBUS_TYPE_OBJECT_PATH ||
array_type == DBUS_TYPE_STRING){
j = 0;
do {
len ++;
j ++;
} while(dbus_message_iter_next(&array_val_iter));
dbus_message_iter_recurse(&prop_val, &array_val_iter);
// Allocate an array of char *
char **tmp = (char **)malloc(sizeof(char *) * len);
*len = j;
char **tmp = (char **)malloc(sizeof(char *) * *len);
if (!tmp)
goto failure;
return -1;
j = 0;
do {
dbus_message_iter_get_basic(&array_val_iter, &tmp[j]);
j ++;
} while(dbus_message_iter_next(&array_val_iter));
value = (char **) tmp;
value->array_val = tmp;
}
break;
default:
goto failure;
return -1;
}
return 0;
}
void create_prop_array(JNIEnv *env, jobjectArray strArray, Properties *property,
property_value *value, int len, int *array_index ) {
char **prop_val = NULL;
char buf[32] = {'\0'}, buf1[32] = {'\0'};
int i;
char *name = property->name;
int prop_type = property->type;
set_object_array_element(env, strArray, name, *array_index);
*array_index += 1;
if (prop_type == DBUS_TYPE_UINT32 || prop_type == DBUS_TYPE_INT16) {
sprintf(buf, "%d", value->int_val);
set_object_array_element(env, strArray, buf, *array_index);
*array_index += 1;
} else if (prop_type == DBUS_TYPE_BOOLEAN) {
sprintf(buf, "%s", value->int_val ? "true" : "false");
set_object_array_element(env, strArray, buf, *array_index);
*array_index += 1;
} else if (prop_type == DBUS_TYPE_ARRAY) {
// Write the length first
sprintf(buf1, "%d", len);
set_object_array_element(env, strArray, buf1, *array_index);
*array_index += 1;
prop_val = value->array_val;
for (i = 0; i < len; i++) {
set_object_array_element(env, strArray, prop_val[i], *array_index);
*array_index += 1;
}
} else {
set_object_array_element(env, strArray, (const char *) value->str_val, *array_index);
*array_index += 1;
}
}
jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
const int max_num_properties) {
DBusMessageIter dict_entry, dict;
jobjectArray strArray = NULL;
property_value value;
int i, size = 0,array_index = 0;
int len = 0, prop_type = DBUS_TYPE_INVALID, prop_index = -1, type;
struct {
property_value value;
int len;
bool used;
} values[max_num_properties];
int t, j;
jclass stringClass = env->FindClass("java/lang/String");
DBusError err;
dbus_error_init(&err);
for (i = 0; i < max_num_properties; i++) {
values[i].used = false;
}
if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
goto failure;
dbus_message_iter_recurse(iter, &dict);
do {
len = 0;
if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
goto failure;
dbus_message_iter_recurse(&dict, &dict_entry);
if (!get_property(dict_entry, properties, max_num_properties, &prop_index,
&value, &len)) {
size += 2;
if (properties[prop_index].type == DBUS_TYPE_ARRAY)
size += len;
values[prop_index].value = value;
values[prop_index].len = len;
values[prop_index].used = true;
} else {
goto failure;
}
} while(dbus_message_iter_next(&dict));
strArray = env->NewObjectArray(size, stringClass, NULL);
for (i = 0; i < max_num_properties; i++) {
if (values[i].used) {
create_prop_array(env, strArray, &properties[i], &values[i].value, values[i].len,
&array_index);
if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used
&& values[i].value.array_val != NULL)
free(values[i].value.array_val);
}
}
return strArray;
failure:
if (dbus_error_is_set(&err))
LOG_AND_FREE_DBUS_ERROR(&err);
for (i = 0; i < max_num_properties; i++)
if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used == true
&& values[i].value.array_val != NULL)
free(values[i].value.array_val);
return NULL;
}
jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
Properties *properties, int max_num_properties) {
DBusMessageIter iter;
DBusError err;
jobjectArray strArray = NULL;
jclass stringClass= env->FindClass("java/lang/String");
int len = 0, prop_index = -1;
int array_index = 0, size = 0;
property_value value;
dbus_error_init(&err);
if (!dbus_message_iter_init(msg, &iter))
goto failure;
if (!get_property(iter, properties, max_num_properties,
&prop_index, &value, &len)) {
size += 2;
if (properties[prop_index].type == DBUS_TYPE_ARRAY)
size += len;
strArray = env->NewObjectArray(size, stringClass, NULL);
create_prop_array(env, strArray, &properties[prop_index],
&value, len, &array_index);
if (properties[prop_index].type == DBUS_TYPE_ARRAY && value.array_val != NULL)
free(value.array_val);
return strArray;
}
return create_prop_array(env, properties, prop_index, value, len);
failure:
LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
return NULL;