Home | History | Annotate | Download | only in jni
      1 /*
      2 ** Copyright 2006, The Android Open Source Project
      3 **
      4 ** Licensed under the Apache License, Version 2.0 (the "License");
      5 ** you may not use this file except in compliance with the License.
      6 ** You may obtain a copy of the License at
      7 **
      8 **     http://www.apache.org/licenses/LICENSE-2.0
      9 **
     10 ** Unless required by applicable law or agreed to in writing, software
     11 ** distributed under the License is distributed on an "AS IS" BASIS,
     12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 ** See the License for the specific language governing permissions and
     14 ** limitations under the License.
     15 */
     16 
     17 #define LOG_TAG "bluetooth_common.cpp"
     18 
     19 #include "android_bluetooth_common.h"
     20 #include "JNIHelp.h"
     21 #include "jni.h"
     22 #include "utils/Log.h"
     23 #include "utils/misc.h"
     24 
     25 #include <stdio.h>
     26 #include <string.h>
     27 #include <stdlib.h>
     28 #include <errno.h>
     29 #include <unistd.h>
     30 #include <cutils/properties.h>
     31 
     32 #ifdef HAVE_BLUETOOTH
     33 #include <dbus/dbus.h>
     34 #endif
     35 
     36 namespace android {
     37 
     38 #ifdef HAVE_BLUETOOTH
     39 
     40 static Properties remote_device_properties[] = {
     41     {"Address",  DBUS_TYPE_STRING},
     42     {"Name", DBUS_TYPE_STRING},
     43     {"Icon", DBUS_TYPE_STRING},
     44     {"Class", DBUS_TYPE_UINT32},
     45     {"UUIDs", DBUS_TYPE_ARRAY},
     46     {"Services", DBUS_TYPE_ARRAY},
     47     {"Paired", DBUS_TYPE_BOOLEAN},
     48     {"Connected", DBUS_TYPE_BOOLEAN},
     49     {"Trusted", DBUS_TYPE_BOOLEAN},
     50     {"Blocked", DBUS_TYPE_BOOLEAN},
     51     {"Alias", DBUS_TYPE_STRING},
     52     {"Nodes", DBUS_TYPE_ARRAY},
     53     {"Adapter", DBUS_TYPE_OBJECT_PATH},
     54     {"LegacyPairing", DBUS_TYPE_BOOLEAN},
     55     {"RSSI", DBUS_TYPE_INT16},
     56     {"TX", DBUS_TYPE_UINT32},
     57     {"Broadcaster", DBUS_TYPE_BOOLEAN}
     58 };
     59 
     60 static Properties adapter_properties[] = {
     61     {"Address", DBUS_TYPE_STRING},
     62     {"Name", DBUS_TYPE_STRING},
     63     {"Class", DBUS_TYPE_UINT32},
     64     {"Powered", DBUS_TYPE_BOOLEAN},
     65     {"Discoverable", DBUS_TYPE_BOOLEAN},
     66     {"DiscoverableTimeout", DBUS_TYPE_UINT32},
     67     {"Pairable", DBUS_TYPE_BOOLEAN},
     68     {"PairableTimeout", DBUS_TYPE_UINT32},
     69     {"Discovering", DBUS_TYPE_BOOLEAN},
     70     {"Devices", DBUS_TYPE_ARRAY},
     71     {"UUIDs", DBUS_TYPE_ARRAY},
     72 };
     73 
     74 static Properties input_properties[] = {
     75     {"Connected", DBUS_TYPE_BOOLEAN},
     76 };
     77 
     78 static Properties pan_properties[] = {
     79     {"Connected", DBUS_TYPE_BOOLEAN},
     80     {"Interface", DBUS_TYPE_STRING},
     81     {"UUID", DBUS_TYPE_STRING},
     82 };
     83 
     84 static Properties health_device_properties[] = {
     85     {"MainChannel", DBUS_TYPE_OBJECT_PATH},
     86 };
     87 
     88 static Properties health_channel_properties[] = {
     89     {"Type", DBUS_TYPE_STRING},
     90     {"Device", DBUS_TYPE_OBJECT_PATH},
     91     {"Application", DBUS_TYPE_OBJECT_PATH},
     92 };
     93 
     94 typedef union {
     95     char *str_val;
     96     int int_val;
     97     char **array_val;
     98 } property_value;
     99 
    100 jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
    101                    const char *mtype) {
    102     jfieldID field = env->GetFieldID(clazz, member, mtype);
    103     if (field == NULL) {
    104         ALOGE("Can't find member %s", member);
    105     }
    106     return field;
    107 }
    108 
    109 typedef struct {
    110     void (*user_cb)(DBusMessage *, void *, void *);
    111     void *user;
    112     void *nat;
    113     JNIEnv *env;
    114 } dbus_async_call_t;
    115 
    116 void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
    117 
    118     dbus_async_call_t *req = (dbus_async_call_t *)data;
    119     DBusMessage *msg;
    120 
    121     /* This is guaranteed to be non-NULL, because this function is called only
    122        when once the remote method invokation returns. */
    123     msg = dbus_pending_call_steal_reply(call);
    124 
    125     if (msg) {
    126         if (req->user_cb) {
    127             // The user may not deref the message object.
    128             req->user_cb(msg, req->user, req->nat);
    129         }
    130         dbus_message_unref(msg);
    131     }
    132 
    133     //dbus_message_unref(req->method);
    134     dbus_pending_call_cancel(call);
    135     dbus_pending_call_unref(call);
    136     free(req);
    137 }
    138 
    139 static dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
    140                                         DBusConnection *conn,
    141                                         int timeout_ms,
    142                                         void (*user_cb)(DBusMessage *,
    143                                                         void *,
    144                                                         void*),
    145                                         void *user,
    146                                         void *nat,
    147                                         const char *path,
    148                                         const char *ifc,
    149                                         const char *func,
    150                                         int first_arg_type,
    151                                         va_list args) {
    152     DBusMessage *msg = NULL;
    153     const char *name;
    154     dbus_async_call_t *pending;
    155     dbus_bool_t reply = FALSE;
    156 
    157     /* Compose the command */
    158     msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
    159 
    160     if (msg == NULL) {
    161         ALOGE("Could not allocate D-Bus message object!");
    162         goto done;
    163     }
    164 
    165     /* append arguments */
    166     if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
    167         ALOGE("Could not append argument to method call!");
    168         goto done;
    169     }
    170 
    171     /* Make the call. */
    172     pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
    173     if (pending) {
    174         DBusPendingCall *call;
    175 
    176         pending->env = env;
    177         pending->user_cb = user_cb;
    178         pending->user = user;
    179         pending->nat = nat;
    180         //pending->method = msg;
    181 
    182         reply = dbus_connection_send_with_reply(conn, msg,
    183                                                 &call,
    184                                                 timeout_ms);
    185         if (reply == TRUE) {
    186             dbus_pending_call_set_notify(call,
    187                                          dbus_func_args_async_callback,
    188                                          pending,
    189                                          NULL);
    190         }
    191     }
    192 
    193 done:
    194     if (msg) dbus_message_unref(msg);
    195     return reply;
    196 }
    197 
    198 dbus_bool_t dbus_func_args_async(JNIEnv *env,
    199                                  DBusConnection *conn,
    200                                  int timeout_ms,
    201                                  void (*reply)(DBusMessage *, void *, void*),
    202                                  void *user,
    203                                  void *nat,
    204                                  const char *path,
    205                                  const char *ifc,
    206                                  const char *func,
    207                                  int first_arg_type,
    208                                  ...) {
    209     dbus_bool_t ret;
    210     va_list lst;
    211     va_start(lst, first_arg_type);
    212 
    213     ret = dbus_func_args_async_valist(env, conn,
    214                                       timeout_ms,
    215                                       reply, user, nat,
    216                                       path, ifc, func,
    217                                       first_arg_type, lst);
    218     va_end(lst);
    219     return ret;
    220 }
    221 
    222 // If err is NULL, then any errors will be ALOGE'd, and free'd and the reply
    223 // will be NULL.
    224 // If err is not NULL, then it is assumed that dbus_error_init was already
    225 // called, and error's will be returned to the caller without logging. The
    226 // return value is NULL iff an error was set. The client must free the error if
    227 // set.
    228 DBusMessage * dbus_func_args_timeout_valist(JNIEnv *env,
    229                                             DBusConnection *conn,
    230                                             int timeout_ms,
    231                                             DBusError *err,
    232                                             const char *path,
    233                                             const char *ifc,
    234                                             const char *func,
    235                                             int first_arg_type,
    236                                             va_list args) {
    237 
    238     DBusMessage *msg = NULL, *reply = NULL;
    239     const char *name;
    240     bool return_error = (err != NULL);
    241 
    242     if (!return_error) {
    243         err = (DBusError*)malloc(sizeof(DBusError));
    244         dbus_error_init(err);
    245     }
    246 
    247     /* Compose the command */
    248     msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
    249 
    250     if (msg == NULL) {
    251         ALOGE("Could not allocate D-Bus message object!");
    252         goto done;
    253     }
    254 
    255     /* append arguments */
    256     if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
    257         ALOGE("Could not append argument to method call!");
    258         goto done;
    259     }
    260 
    261     /* Make the call. */
    262     reply = dbus_connection_send_with_reply_and_block(conn, msg, timeout_ms, err);
    263     if (!return_error && dbus_error_is_set(err)) {
    264         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg);
    265     }
    266 
    267 done:
    268     if (!return_error) {
    269         free(err);
    270     }
    271     if (msg) dbus_message_unref(msg);
    272     return reply;
    273 }
    274 
    275 DBusMessage * dbus_func_args_timeout(JNIEnv *env,
    276                                      DBusConnection *conn,
    277                                      int timeout_ms,
    278                                      const char *path,
    279                                      const char *ifc,
    280                                      const char *func,
    281                                      int first_arg_type,
    282                                      ...) {
    283     DBusMessage *ret;
    284     va_list lst;
    285     va_start(lst, first_arg_type);
    286     ret = dbus_func_args_timeout_valist(env, conn, timeout_ms, NULL,
    287                                         path, ifc, func,
    288                                         first_arg_type, lst);
    289     va_end(lst);
    290     return ret;
    291 }
    292 
    293 DBusMessage * dbus_func_args(JNIEnv *env,
    294                              DBusConnection *conn,
    295                              const char *path,
    296                              const char *ifc,
    297                              const char *func,
    298                              int first_arg_type,
    299                              ...) {
    300     DBusMessage *ret;
    301     va_list lst;
    302     va_start(lst, first_arg_type);
    303     ret = dbus_func_args_timeout_valist(env, conn, -1, NULL,
    304                                         path, ifc, func,
    305                                         first_arg_type, lst);
    306     va_end(lst);
    307     return ret;
    308 }
    309 
    310 DBusMessage * dbus_func_args_error(JNIEnv *env,
    311                                    DBusConnection *conn,
    312                                    DBusError *err,
    313                                    const char *path,
    314                                    const char *ifc,
    315                                    const char *func,
    316                                    int first_arg_type,
    317                                    ...) {
    318     DBusMessage *ret;
    319     va_list lst;
    320     va_start(lst, first_arg_type);
    321     ret = dbus_func_args_timeout_valist(env, conn, -1, err,
    322                                         path, ifc, func,
    323                                         first_arg_type, lst);
    324     va_end(lst);
    325     return ret;
    326 }
    327 
    328 jint dbus_returns_unixfd(JNIEnv *env, DBusMessage *reply) {
    329 
    330     DBusError err;
    331     jint ret = -1;
    332 
    333     dbus_error_init(&err);
    334     if (!dbus_message_get_args(reply, &err,
    335                                DBUS_TYPE_UNIX_FD, &ret,
    336                                DBUS_TYPE_INVALID)) {
    337         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    338     }
    339     dbus_message_unref(reply);
    340     return ret;
    341 }
    342 
    343 
    344 jint dbus_returns_int32(JNIEnv *env, DBusMessage *reply) {
    345 
    346     DBusError err;
    347     jint ret = -1;
    348 
    349     dbus_error_init(&err);
    350     if (!dbus_message_get_args(reply, &err,
    351                                DBUS_TYPE_INT32, &ret,
    352                                DBUS_TYPE_INVALID)) {
    353         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    354     }
    355     dbus_message_unref(reply);
    356     return ret;
    357 }
    358 
    359 jint dbus_returns_uint32(JNIEnv *env, DBusMessage *reply) {
    360 
    361     DBusError err;
    362     jint ret = -1;
    363 
    364     dbus_error_init(&err);
    365     if (!dbus_message_get_args(reply, &err,
    366                                DBUS_TYPE_UINT32, &ret,
    367                                DBUS_TYPE_INVALID)) {
    368         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    369     }
    370     dbus_message_unref(reply);
    371     return ret;
    372 }
    373 
    374 jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply) {
    375 
    376     DBusError err;
    377     jstring ret = NULL;
    378     const char *name;
    379 
    380     dbus_error_init(&err);
    381     if (dbus_message_get_args(reply, &err,
    382                                DBUS_TYPE_STRING, &name,
    383                                DBUS_TYPE_INVALID)) {
    384         ret = env->NewStringUTF(name);
    385     } else {
    386         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    387     }
    388     dbus_message_unref(reply);
    389 
    390     return ret;
    391 }
    392 
    393 jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply) {
    394     DBusError err;
    395     jboolean ret = JNI_FALSE;
    396     dbus_bool_t val = FALSE;
    397 
    398     dbus_error_init(&err);
    399 
    400     /* Check the return value. */
    401     if (dbus_message_get_args(reply, &err,
    402                                DBUS_TYPE_BOOLEAN, &val,
    403                                DBUS_TYPE_INVALID)) {
    404         ret = val == TRUE ? JNI_TRUE : JNI_FALSE;
    405     } else {
    406         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    407     }
    408 
    409     dbus_message_unref(reply);
    410     return ret;
    411 }
    412 
    413 static void set_object_array_element(JNIEnv *env, jobjectArray strArray,
    414                                      const char *value, int index) {
    415     jstring obj;
    416     obj = env->NewStringUTF(value);
    417     env->SetObjectArrayElement(strArray, index, obj);
    418     env->DeleteLocalRef(obj);
    419 }
    420 
    421 jobjectArray dbus_returns_array_of_object_path(JNIEnv *env,
    422                                                DBusMessage *reply) {
    423 
    424     DBusError err;
    425     char **list;
    426     int i, len;
    427     jobjectArray strArray = NULL;
    428 
    429     dbus_error_init(&err);
    430     if (dbus_message_get_args (reply,
    431                                &err,
    432                                DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
    433                                &list, &len,
    434                                DBUS_TYPE_INVALID)) {
    435         jclass stringClass;
    436         jstring classNameStr;
    437 
    438         stringClass = env->FindClass("java/lang/String");
    439         strArray = env->NewObjectArray(len, stringClass, NULL);
    440 
    441         for (i = 0; i < len; i++)
    442             set_object_array_element(env, strArray, list[i], i);
    443     } else {
    444         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    445     }
    446 
    447     dbus_message_unref(reply);
    448     return strArray;
    449 }
    450 
    451 jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) {
    452 
    453     DBusError err;
    454     char **list;
    455     int i, len;
    456     jobjectArray strArray = NULL;
    457 
    458     dbus_error_init(&err);
    459     if (dbus_message_get_args (reply,
    460                                &err,
    461                                DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
    462                                &list, &len,
    463                                DBUS_TYPE_INVALID)) {
    464         jclass stringClass;
    465         jstring classNameStr;
    466 
    467         //ALOGV("%s: there are %d elements in string array!", __FUNCTION__, len);
    468 
    469         stringClass = env->FindClass("java/lang/String");
    470         strArray = env->NewObjectArray(len, stringClass, NULL);
    471 
    472         for (i = 0; i < len; i++)
    473             set_object_array_element(env, strArray, list[i], i);
    474     } else {
    475         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    476     }
    477 
    478     dbus_message_unref(reply);
    479     return strArray;
    480 }
    481 
    482 jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply) {
    483 
    484     DBusError err;
    485     int i, len;
    486     jbyte *list;
    487     jbyteArray byteArray = NULL;
    488 
    489     dbus_error_init(&err);
    490     if (dbus_message_get_args(reply, &err,
    491                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &list, &len,
    492                               DBUS_TYPE_INVALID)) {
    493         //ALOGV("%s: there are %d elements in byte array!", __FUNCTION__, len);
    494         byteArray = env->NewByteArray(len);
    495         if (byteArray)
    496             env->SetByteArrayRegion(byteArray, 0, len, list);
    497 
    498     } else {
    499         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    500     }
    501 
    502     dbus_message_unref(reply);
    503     return byteArray;
    504 }
    505 
    506 void append_variant(DBusMessageIter *iter, int type, void *val)
    507 {
    508     DBusMessageIter value_iter;
    509     char var_type[2] = { type, '\0'};
    510     dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, var_type, &value_iter);
    511     dbus_message_iter_append_basic(&value_iter, type, val);
    512     dbus_message_iter_close_container(iter, &value_iter);
    513 }
    514 
    515 static void dict_append_entry(DBusMessageIter *dict,
    516                         const char *key, int type, void *val)
    517 {
    518         DBusMessageIter dict_entry;
    519         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
    520                                                         NULL, &dict_entry);
    521 
    522         dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING, &key);
    523         append_variant(&dict_entry, type, val);
    524         dbus_message_iter_close_container(dict, &dict_entry);
    525 }
    526 
    527 static void append_dict_valist(DBusMessageIter *iterator, const char *first_key,
    528                                 va_list var_args)
    529 {
    530         DBusMessageIter dict;
    531         int val_type;
    532         const char *val_key;
    533         void *val;
    534 
    535         dbus_message_iter_open_container(iterator, DBUS_TYPE_ARRAY,
    536                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
    537                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
    538                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
    539 
    540         val_key = first_key;
    541         while (val_key) {
    542                 val_type = va_arg(var_args, int);
    543                 val = va_arg(var_args, void *);
    544                 dict_append_entry(&dict, val_key, val_type, val);
    545                 val_key = va_arg(var_args, char *);
    546         }
    547 
    548         dbus_message_iter_close_container(iterator, &dict);
    549 }
    550 
    551 void append_dict_args(DBusMessage *reply, const char *first_key, ...)
    552 {
    553         DBusMessageIter iter;
    554         va_list var_args;
    555 
    556         dbus_message_iter_init_append(reply, &iter);
    557 
    558         va_start(var_args, first_key);
    559         append_dict_valist(&iter, first_key, var_args);
    560         va_end(var_args);
    561 }
    562 
    563 
    564 int get_property(DBusMessageIter iter, Properties *properties,
    565                   int max_num_properties, int *prop_index, property_value *value, int *len) {
    566     DBusMessageIter prop_val, array_val_iter;
    567     char *property = NULL;
    568     uint32_t array_type;
    569     char *str_val;
    570     int i, j, type, int_val;
    571 
    572     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
    573         return -1;
    574     dbus_message_iter_get_basic(&iter, &property);
    575     if (!dbus_message_iter_next(&iter))
    576         return -1;
    577     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
    578         return -1;
    579     for (i = 0; i <  max_num_properties; i++) {
    580         if (!strncmp(property, properties[i].name, strlen(property)))
    581             break;
    582     }
    583     *prop_index = i;
    584     if (i == max_num_properties)
    585         return -1;
    586 
    587     dbus_message_iter_recurse(&iter, &prop_val);
    588     type = properties[*prop_index].type;
    589     if (dbus_message_iter_get_arg_type(&prop_val) != type) {
    590         ALOGE("Property type mismatch in get_property: %d, expected:%d, index:%d",
    591              dbus_message_iter_get_arg_type(&prop_val), type, *prop_index);
    592         return -1;
    593     }
    594 
    595     switch(type) {
    596     case DBUS_TYPE_STRING:
    597     case DBUS_TYPE_OBJECT_PATH:
    598         dbus_message_iter_get_basic(&prop_val, &value->str_val);
    599         *len = 1;
    600         break;
    601     case DBUS_TYPE_UINT32:
    602     case DBUS_TYPE_INT16:
    603     case DBUS_TYPE_BOOLEAN:
    604         dbus_message_iter_get_basic(&prop_val, &int_val);
    605         value->int_val = int_val;
    606         *len = 1;
    607         break;
    608     case DBUS_TYPE_ARRAY:
    609         dbus_message_iter_recurse(&prop_val, &array_val_iter);
    610         array_type = dbus_message_iter_get_arg_type(&array_val_iter);
    611         *len = 0;
    612         value->array_val = NULL;
    613         if (array_type == DBUS_TYPE_OBJECT_PATH ||
    614             array_type == DBUS_TYPE_STRING){
    615             j = 0;
    616             do {
    617                j ++;
    618             } while(dbus_message_iter_next(&array_val_iter));
    619             dbus_message_iter_recurse(&prop_val, &array_val_iter);
    620             // Allocate  an array of char *
    621             *len = j;
    622             char **tmp = (char **)malloc(sizeof(char *) * *len);
    623             if (!tmp)
    624                 return -1;
    625             j = 0;
    626             do {
    627                dbus_message_iter_get_basic(&array_val_iter, &tmp[j]);
    628                j ++;
    629             } while(dbus_message_iter_next(&array_val_iter));
    630             value->array_val = tmp;
    631         }
    632         break;
    633     default:
    634         return -1;
    635     }
    636     return 0;
    637 }
    638 
    639 void create_prop_array(JNIEnv *env, jobjectArray strArray, Properties *property,
    640                        property_value *value, int len, int *array_index ) {
    641     char **prop_val = NULL;
    642     char buf[32] = {'\0'}, buf1[32] = {'\0'};
    643     int i;
    644 
    645     char *name = property->name;
    646     int prop_type = property->type;
    647 
    648     set_object_array_element(env, strArray, name, *array_index);
    649     *array_index += 1;
    650 
    651     if (prop_type == DBUS_TYPE_UINT32 || prop_type == DBUS_TYPE_INT16) {
    652         sprintf(buf, "%d", value->int_val);
    653         set_object_array_element(env, strArray, buf, *array_index);
    654         *array_index += 1;
    655     } else if (prop_type == DBUS_TYPE_BOOLEAN) {
    656         sprintf(buf, "%s", value->int_val ? "true" : "false");
    657 
    658         set_object_array_element(env, strArray, buf, *array_index);
    659         *array_index += 1;
    660     } else if (prop_type == DBUS_TYPE_ARRAY) {
    661         // Write the length first
    662         sprintf(buf1, "%d", len);
    663         set_object_array_element(env, strArray, buf1, *array_index);
    664         *array_index += 1;
    665 
    666         prop_val = value->array_val;
    667         for (i = 0; i < len; i++) {
    668             set_object_array_element(env, strArray, prop_val[i], *array_index);
    669             *array_index += 1;
    670         }
    671     } else {
    672         set_object_array_element(env, strArray, (const char *) value->str_val, *array_index);
    673         *array_index += 1;
    674     }
    675 }
    676 
    677 jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
    678                               const int max_num_properties) {
    679     DBusMessageIter dict_entry, dict;
    680     jobjectArray strArray = NULL;
    681     property_value value;
    682     int i, size = 0,array_index = 0;
    683     int len = 0, prop_type = DBUS_TYPE_INVALID, prop_index = -1, type;
    684     struct {
    685         property_value value;
    686         int len;
    687         bool used;
    688     } values[max_num_properties];
    689     int t, j;
    690 
    691     jclass stringClass = env->FindClass("java/lang/String");
    692     DBusError err;
    693     dbus_error_init(&err);
    694 
    695     for (i = 0; i < max_num_properties; i++) {
    696         values[i].used = false;
    697     }
    698 
    699     if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
    700         goto failure;
    701     dbus_message_iter_recurse(iter, &dict);
    702     do {
    703         len = 0;
    704         if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
    705             goto failure;
    706         dbus_message_iter_recurse(&dict, &dict_entry);
    707 
    708         if (!get_property(dict_entry, properties, max_num_properties, &prop_index,
    709                           &value, &len)) {
    710             size += 2;
    711             if (properties[prop_index].type == DBUS_TYPE_ARRAY)
    712                 size += len;
    713             values[prop_index].value = value;
    714             values[prop_index].len = len;
    715             values[prop_index].used = true;
    716         } else {
    717             goto failure;
    718         }
    719     } while(dbus_message_iter_next(&dict));
    720 
    721     strArray = env->NewObjectArray(size, stringClass, NULL);
    722 
    723     for (i = 0; i < max_num_properties; i++) {
    724         if (values[i].used) {
    725             create_prop_array(env, strArray, &properties[i], &values[i].value, values[i].len,
    726                               &array_index);
    727 
    728             if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used
    729                    && values[i].value.array_val != NULL)
    730                 free(values[i].value.array_val);
    731         }
    732 
    733     }
    734     return strArray;
    735 
    736 failure:
    737     if (dbus_error_is_set(&err))
    738         LOG_AND_FREE_DBUS_ERROR(&err);
    739     for (i = 0; i < max_num_properties; i++)
    740         if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used == true
    741                                         && values[i].value.array_val != NULL)
    742             free(values[i].value.array_val);
    743     return NULL;
    744 }
    745 
    746 jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
    747                            Properties *properties, int max_num_properties) {
    748     DBusMessageIter iter;
    749     DBusError err;
    750     jobjectArray strArray = NULL;
    751     jclass stringClass= env->FindClass("java/lang/String");
    752     int len = 0, prop_index = -1;
    753     int array_index = 0, size = 0;
    754     property_value value;
    755 
    756     dbus_error_init(&err);
    757     if (!dbus_message_iter_init(msg, &iter))
    758         goto failure;
    759 
    760     if (!get_property(iter, properties, max_num_properties,
    761                       &prop_index, &value, &len)) {
    762         size += 2;
    763         if (properties[prop_index].type == DBUS_TYPE_ARRAY)
    764             size += len;
    765         strArray = env->NewObjectArray(size, stringClass, NULL);
    766 
    767         create_prop_array(env, strArray, &properties[prop_index],
    768                           &value, len, &array_index);
    769 
    770         if (properties[prop_index].type == DBUS_TYPE_ARRAY && value.array_val != NULL)
    771              free(value.array_val);
    772 
    773         return strArray;
    774     }
    775 failure:
    776     LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    777     return NULL;
    778 }
    779 
    780 jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg) {
    781     return parse_property_change(env, msg, (Properties *) &adapter_properties,
    782                     sizeof(adapter_properties) / sizeof(Properties));
    783 }
    784 
    785 jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg) {
    786     return parse_property_change(env, msg, (Properties *) &remote_device_properties,
    787                     sizeof(remote_device_properties) / sizeof(Properties));
    788 }
    789 
    790 jobjectArray parse_input_property_change(JNIEnv *env, DBusMessage *msg) {
    791     return parse_property_change(env, msg, (Properties *) &input_properties,
    792                     sizeof(input_properties) / sizeof(Properties));
    793 }
    794 
    795 jobjectArray parse_pan_property_change(JNIEnv *env, DBusMessage *msg) {
    796     return parse_property_change(env, msg, (Properties *) &pan_properties,
    797                     sizeof(pan_properties) / sizeof(Properties));
    798 }
    799 
    800 jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) {
    801     return parse_properties(env, iter, (Properties *) &adapter_properties,
    802                             sizeof(adapter_properties) / sizeof(Properties));
    803 }
    804 
    805 jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter) {
    806     return parse_properties(env, iter, (Properties *) &remote_device_properties,
    807                           sizeof(remote_device_properties) / sizeof(Properties));
    808 }
    809 
    810 jobjectArray parse_input_properties(JNIEnv *env, DBusMessageIter *iter) {
    811     return parse_properties(env, iter, (Properties *) &input_properties,
    812                           sizeof(input_properties) / sizeof(Properties));
    813 }
    814 
    815 jobjectArray parse_health_device_properties(JNIEnv *env, DBusMessageIter *iter) {
    816     return parse_properties(env, iter, (Properties *) &health_device_properties,
    817                           sizeof(health_device_properties) / sizeof(Properties));
    818 }
    819 
    820 jobjectArray parse_health_device_property_change(JNIEnv *env, DBusMessage *msg) {
    821     return parse_property_change(env, msg, (Properties *) &health_device_properties,
    822                     sizeof(health_device_properties) / sizeof(Properties));
    823 }
    824 
    825 jobjectArray parse_health_channel_properties(JNIEnv *env, DBusMessageIter *iter) {
    826     return parse_properties(env, iter, (Properties *) &health_channel_properties,
    827                           sizeof(health_channel_properties) / sizeof(Properties));
    828 }
    829 
    830 int get_bdaddr(const char *str, bdaddr_t *ba) {
    831     char *d = ((char *)ba) + 5, *endp;
    832     int i;
    833     for(i = 0; i < 6; i++) {
    834         *d-- = strtol(str, &endp, 16);
    835         if (*endp != ':' && i != 5) {
    836             memset(ba, 0, sizeof(bdaddr_t));
    837             return -1;
    838         }
    839         str = endp + 1;
    840     }
    841     return 0;
    842 }
    843 
    844 void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
    845     const uint8_t *b = (const uint8_t *)ba;
    846     sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
    847             b[5], b[4], b[3], b[2], b[1], b[0]);
    848 }
    849 
    850 bool debug_no_encrypt() {
    851     return false;
    852 #if 0
    853     char value[PROPERTY_VALUE_MAX] = "";
    854 
    855     property_get("debug.bt.no_encrypt", value, "");
    856     if (!strncmp("true", value, PROPERTY_VALUE_MAX) ||
    857         !strncmp("1", value, PROPERTY_VALUE_MAX)) {
    858         ALOGD("mandatory bluetooth encryption disabled");
    859         return true;
    860     } else {
    861         return false;
    862     }
    863 #endif
    864 }
    865 #endif
    866 
    867 } /* namespace android */
    868