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     {"Paired", DBUS_TYPE_BOOLEAN},
     47     {"Connected", DBUS_TYPE_BOOLEAN},
     48     {"Trusted", DBUS_TYPE_BOOLEAN},
     49     {"Blocked", DBUS_TYPE_BOOLEAN},
     50     {"Alias", DBUS_TYPE_STRING},
     51     {"Nodes", DBUS_TYPE_ARRAY},
     52     {"Adapter", DBUS_TYPE_OBJECT_PATH},
     53     {"LegacyPairing", DBUS_TYPE_BOOLEAN},
     54     {"RSSI", DBUS_TYPE_INT16},
     55     {"TX", DBUS_TYPE_UINT32}
     56 };
     57 
     58 static Properties adapter_properties[] = {
     59     {"Address", DBUS_TYPE_STRING},
     60     {"Name", DBUS_TYPE_STRING},
     61     {"Class", DBUS_TYPE_UINT32},
     62     {"Powered", DBUS_TYPE_BOOLEAN},
     63     {"Discoverable", DBUS_TYPE_BOOLEAN},
     64     {"DiscoverableTimeout", DBUS_TYPE_UINT32},
     65     {"Pairable", DBUS_TYPE_BOOLEAN},
     66     {"PairableTimeout", DBUS_TYPE_UINT32},
     67     {"Discovering", DBUS_TYPE_BOOLEAN},
     68     {"Devices", DBUS_TYPE_ARRAY},
     69     {"UUIDs", DBUS_TYPE_ARRAY},
     70 };
     71 
     72 typedef union {
     73     char *str_val;
     74     int int_val;
     75     char **array_val;
     76 } property_value;
     77 
     78 jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
     79                    const char *mtype) {
     80     jfieldID field = env->GetFieldID(clazz, member, mtype);
     81     if (field == NULL) {
     82         LOGE("Can't find member %s", member);
     83     }
     84     return field;
     85 }
     86 
     87 typedef struct {
     88     void (*user_cb)(DBusMessage *, void *, void *);
     89     void *user;
     90     void *nat;
     91     JNIEnv *env;
     92 } dbus_async_call_t;
     93 
     94 void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
     95 
     96     dbus_async_call_t *req = (dbus_async_call_t *)data;
     97     DBusMessage *msg;
     98 
     99     /* This is guaranteed to be non-NULL, because this function is called only
    100        when once the remote method invokation returns. */
    101     msg = dbus_pending_call_steal_reply(call);
    102 
    103     if (msg) {
    104         if (req->user_cb) {
    105             // The user may not deref the message object.
    106             req->user_cb(msg, req->user, req->nat);
    107         }
    108         dbus_message_unref(msg);
    109     }
    110 
    111     //dbus_message_unref(req->method);
    112     dbus_pending_call_cancel(call);
    113     dbus_pending_call_unref(call);
    114     free(req);
    115 }
    116 
    117 static dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
    118                                         DBusConnection *conn,
    119                                         int timeout_ms,
    120                                         void (*user_cb)(DBusMessage *,
    121                                                         void *,
    122                                                         void*),
    123                                         void *user,
    124                                         void *nat,
    125                                         const char *path,
    126                                         const char *ifc,
    127                                         const char *func,
    128                                         int first_arg_type,
    129                                         va_list args) {
    130     DBusMessage *msg = NULL;
    131     const char *name;
    132     dbus_async_call_t *pending;
    133     dbus_bool_t reply = FALSE;
    134 
    135     /* Compose the command */
    136     msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
    137 
    138     if (msg == NULL) {
    139         LOGE("Could not allocate D-Bus message object!");
    140         goto done;
    141     }
    142 
    143     /* append arguments */
    144     if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
    145         LOGE("Could not append argument to method call!");
    146         goto done;
    147     }
    148 
    149     /* Make the call. */
    150     pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
    151     if (pending) {
    152         DBusPendingCall *call;
    153 
    154         pending->env = env;
    155         pending->user_cb = user_cb;
    156         pending->user = user;
    157         pending->nat = nat;
    158         //pending->method = msg;
    159 
    160         reply = dbus_connection_send_with_reply(conn, msg,
    161                                                 &call,
    162                                                 timeout_ms);
    163         if (reply == TRUE) {
    164             dbus_pending_call_set_notify(call,
    165                                          dbus_func_args_async_callback,
    166                                          pending,
    167                                          NULL);
    168         }
    169     }
    170 
    171 done:
    172     if (msg) dbus_message_unref(msg);
    173     return reply;
    174 }
    175 
    176 dbus_bool_t dbus_func_args_async(JNIEnv *env,
    177                                  DBusConnection *conn,
    178                                  int timeout_ms,
    179                                  void (*reply)(DBusMessage *, void *, void*),
    180                                  void *user,
    181                                  void *nat,
    182                                  const char *path,
    183                                  const char *ifc,
    184                                  const char *func,
    185                                  int first_arg_type,
    186                                  ...) {
    187     dbus_bool_t ret;
    188     va_list lst;
    189     va_start(lst, first_arg_type);
    190     ret = dbus_func_args_async_valist(env, conn,
    191                                       timeout_ms,
    192                                       reply, user, nat,
    193                                       path, ifc, func,
    194                                       first_arg_type, lst);
    195     va_end(lst);
    196     return ret;
    197 }
    198 
    199 // If err is NULL, then any errors will be LOGE'd, and free'd and the reply
    200 // will be NULL.
    201 // If err is not NULL, then it is assumed that dbus_error_init was already
    202 // called, and error's will be returned to the caller without logging. The
    203 // return value is NULL iff an error was set. The client must free the error if
    204 // set.
    205 DBusMessage * dbus_func_args_timeout_valist(JNIEnv *env,
    206                                             DBusConnection *conn,
    207                                             int timeout_ms,
    208                                             DBusError *err,
    209                                             const char *path,
    210                                             const char *ifc,
    211                                             const char *func,
    212                                             int first_arg_type,
    213                                             va_list args) {
    214 
    215     DBusMessage *msg = NULL, *reply = NULL;
    216     const char *name;
    217     bool return_error = (err != NULL);
    218 
    219     if (!return_error) {
    220         err = (DBusError*)malloc(sizeof(DBusError));
    221         dbus_error_init(err);
    222     }
    223 
    224     /* Compose the command */
    225     msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
    226 
    227     if (msg == NULL) {
    228         LOGE("Could not allocate D-Bus message object!");
    229         goto done;
    230     }
    231 
    232     /* append arguments */
    233     if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
    234         LOGE("Could not append argument to method call!");
    235         goto done;
    236     }
    237 
    238     /* Make the call. */
    239     reply = dbus_connection_send_with_reply_and_block(conn, msg, timeout_ms, err);
    240     if (!return_error && dbus_error_is_set(err)) {
    241         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg);
    242     }
    243 
    244 done:
    245     if (!return_error) {
    246         free(err);
    247     }
    248     if (msg) dbus_message_unref(msg);
    249     return reply;
    250 }
    251 
    252 DBusMessage * dbus_func_args_timeout(JNIEnv *env,
    253                                      DBusConnection *conn,
    254                                      int timeout_ms,
    255                                      const char *path,
    256                                      const char *ifc,
    257                                      const char *func,
    258                                      int first_arg_type,
    259                                      ...) {
    260     DBusMessage *ret;
    261     va_list lst;
    262     va_start(lst, first_arg_type);
    263     ret = dbus_func_args_timeout_valist(env, conn, timeout_ms, NULL,
    264                                         path, ifc, func,
    265                                         first_arg_type, lst);
    266     va_end(lst);
    267     return ret;
    268 }
    269 
    270 DBusMessage * dbus_func_args(JNIEnv *env,
    271                              DBusConnection *conn,
    272                              const char *path,
    273                              const char *ifc,
    274                              const char *func,
    275                              int first_arg_type,
    276                              ...) {
    277     DBusMessage *ret;
    278     va_list lst;
    279     va_start(lst, first_arg_type);
    280     ret = dbus_func_args_timeout_valist(env, conn, -1, NULL,
    281                                         path, ifc, func,
    282                                         first_arg_type, lst);
    283     va_end(lst);
    284     return ret;
    285 }
    286 
    287 DBusMessage * dbus_func_args_error(JNIEnv *env,
    288                                    DBusConnection *conn,
    289                                    DBusError *err,
    290                                    const char *path,
    291                                    const char *ifc,
    292                                    const char *func,
    293                                    int first_arg_type,
    294                                    ...) {
    295     DBusMessage *ret;
    296     va_list lst;
    297     va_start(lst, first_arg_type);
    298     ret = dbus_func_args_timeout_valist(env, conn, -1, err,
    299                                         path, ifc, func,
    300                                         first_arg_type, lst);
    301     va_end(lst);
    302     return ret;
    303 }
    304 
    305 jint dbus_returns_int32(JNIEnv *env, DBusMessage *reply) {
    306 
    307     DBusError err;
    308     jint ret = -1;
    309 
    310     dbus_error_init(&err);
    311     if (!dbus_message_get_args(reply, &err,
    312                                DBUS_TYPE_INT32, &ret,
    313                                DBUS_TYPE_INVALID)) {
    314         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    315     }
    316     dbus_message_unref(reply);
    317     return ret;
    318 }
    319 
    320 jint dbus_returns_uint32(JNIEnv *env, DBusMessage *reply) {
    321 
    322     DBusError err;
    323     jint ret = -1;
    324 
    325     dbus_error_init(&err);
    326     if (!dbus_message_get_args(reply, &err,
    327                                DBUS_TYPE_UINT32, &ret,
    328                                DBUS_TYPE_INVALID)) {
    329         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    330     }
    331     dbus_message_unref(reply);
    332     return ret;
    333 }
    334 
    335 jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply) {
    336 
    337     DBusError err;
    338     jstring ret = NULL;
    339     const char *name;
    340 
    341     dbus_error_init(&err);
    342     if (dbus_message_get_args(reply, &err,
    343                                DBUS_TYPE_STRING, &name,
    344                                DBUS_TYPE_INVALID)) {
    345         ret = env->NewStringUTF(name);
    346     } else {
    347         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    348     }
    349     dbus_message_unref(reply);
    350 
    351     return ret;
    352 }
    353 
    354 jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply) {
    355     DBusError err;
    356     jboolean ret = JNI_FALSE;
    357     dbus_bool_t val = FALSE;
    358 
    359     dbus_error_init(&err);
    360 
    361     /* Check the return value. */
    362     if (dbus_message_get_args(reply, &err,
    363                                DBUS_TYPE_BOOLEAN, &val,
    364                                DBUS_TYPE_INVALID)) {
    365         ret = val == TRUE ? JNI_TRUE : JNI_FALSE;
    366     } else {
    367         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    368     }
    369 
    370     dbus_message_unref(reply);
    371     return ret;
    372 }
    373 
    374 static void set_object_array_element(JNIEnv *env, jobjectArray strArray,
    375                                      const char *value, int index) {
    376     jstring obj;
    377     obj = env->NewStringUTF(value);
    378     env->SetObjectArrayElement(strArray, index, obj);
    379     env->DeleteLocalRef(obj);
    380 }
    381 
    382 jobjectArray dbus_returns_array_of_object_path(JNIEnv *env,
    383                                                DBusMessage *reply) {
    384 
    385     DBusError err;
    386     char **list;
    387     int i, len;
    388     jobjectArray strArray = NULL;
    389 
    390     dbus_error_init(&err);
    391     if (dbus_message_get_args (reply,
    392                                &err,
    393                                DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
    394                                &list, &len,
    395                                DBUS_TYPE_INVALID)) {
    396         jclass stringClass;
    397         jstring classNameStr;
    398 
    399         stringClass = env->FindClass("java/lang/String");
    400         strArray = env->NewObjectArray(len, stringClass, NULL);
    401 
    402         for (i = 0; i < len; i++)
    403             set_object_array_element(env, strArray, list[i], i);
    404     } else {
    405         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    406     }
    407 
    408     dbus_message_unref(reply);
    409     return strArray;
    410 }
    411 
    412 jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) {
    413 
    414     DBusError err;
    415     char **list;
    416     int i, len;
    417     jobjectArray strArray = NULL;
    418 
    419     dbus_error_init(&err);
    420     if (dbus_message_get_args (reply,
    421                                &err,
    422                                DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
    423                                &list, &len,
    424                                DBUS_TYPE_INVALID)) {
    425         jclass stringClass;
    426         jstring classNameStr;
    427 
    428         //LOGV("%s: there are %d elements in string array!", __FUNCTION__, len);
    429 
    430         stringClass = env->FindClass("java/lang/String");
    431         strArray = env->NewObjectArray(len, stringClass, NULL);
    432 
    433         for (i = 0; i < len; i++)
    434             set_object_array_element(env, strArray, list[i], i);
    435     } else {
    436         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    437     }
    438 
    439     dbus_message_unref(reply);
    440     return strArray;
    441 }
    442 
    443 jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply) {
    444 
    445     DBusError err;
    446     int i, len;
    447     jbyte *list;
    448     jbyteArray byteArray = NULL;
    449 
    450     dbus_error_init(&err);
    451     if (dbus_message_get_args(reply, &err,
    452                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &list, &len,
    453                               DBUS_TYPE_INVALID)) {
    454         //LOGV("%s: there are %d elements in byte array!", __FUNCTION__, len);
    455         byteArray = env->NewByteArray(len);
    456         if (byteArray)
    457             env->SetByteArrayRegion(byteArray, 0, len, list);
    458 
    459     } else {
    460         LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
    461     }
    462 
    463     dbus_message_unref(reply);
    464     return byteArray;
    465 }
    466 
    467 void append_variant(DBusMessageIter *iter, int type, void *val)
    468 {
    469     DBusMessageIter value_iter;
    470     char var_type[2] = { type, '\0'};
    471     dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, var_type, &value_iter);
    472     dbus_message_iter_append_basic(&value_iter, type, val);
    473     dbus_message_iter_close_container(iter, &value_iter);
    474 }
    475 
    476 int get_property(DBusMessageIter iter, Properties *properties,
    477                   int max_num_properties, int *prop_index, property_value *value, int *len) {
    478     DBusMessageIter prop_val, array_val_iter;
    479     char *property = NULL;
    480     uint32_t array_type;
    481     char *str_val;
    482     int i, j, type, int_val;
    483 
    484     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
    485         return -1;
    486     dbus_message_iter_get_basic(&iter, &property);
    487     if (!dbus_message_iter_next(&iter))
    488         return -1;
    489     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
    490         return -1;
    491     for (i = 0; i <  max_num_properties; i++) {
    492         if (!strncmp(property, properties[i].name, strlen(property)))
    493             break;
    494     }
    495     *prop_index = i;
    496     if (i == max_num_properties)
    497         return -1;
    498 
    499     dbus_message_iter_recurse(&iter, &prop_val);
    500     type = properties[*prop_index].type;
    501     if (dbus_message_iter_get_arg_type(&prop_val) != type) {
    502         LOGE("Property type mismatch in get_property: %d, expected:%d, index:%d",
    503              dbus_message_iter_get_arg_type(&prop_val), type, *prop_index);
    504         return -1;
    505     }
    506 
    507     switch(type) {
    508     case DBUS_TYPE_STRING:
    509     case DBUS_TYPE_OBJECT_PATH:
    510         dbus_message_iter_get_basic(&prop_val, &value->str_val);
    511         *len = 1;
    512         break;
    513     case DBUS_TYPE_UINT32:
    514     case DBUS_TYPE_INT16:
    515     case DBUS_TYPE_BOOLEAN:
    516         dbus_message_iter_get_basic(&prop_val, &int_val);
    517         value->int_val = int_val;
    518         *len = 1;
    519         break;
    520     case DBUS_TYPE_ARRAY:
    521         dbus_message_iter_recurse(&prop_val, &array_val_iter);
    522         array_type = dbus_message_iter_get_arg_type(&array_val_iter);
    523         *len = 0;
    524         value->array_val = NULL;
    525         if (array_type == DBUS_TYPE_OBJECT_PATH ||
    526             array_type == DBUS_TYPE_STRING){
    527             j = 0;
    528             do {
    529                j ++;
    530             } while(dbus_message_iter_next(&array_val_iter));
    531             dbus_message_iter_recurse(&prop_val, &array_val_iter);
    532             // Allocate  an array of char *
    533             *len = j;
    534             char **tmp = (char **)malloc(sizeof(char *) * *len);
    535             if (!tmp)
    536                 return -1;
    537             j = 0;
    538             do {
    539                dbus_message_iter_get_basic(&array_val_iter, &tmp[j]);
    540                j ++;
    541             } while(dbus_message_iter_next(&array_val_iter));
    542             value->array_val = tmp;
    543         }
    544         break;
    545     default:
    546         return -1;
    547     }
    548     return 0;
    549 }
    550 
    551 void create_prop_array(JNIEnv *env, jobjectArray strArray, Properties *property,
    552                        property_value *value, int len, int *array_index ) {
    553     char **prop_val = NULL;
    554     char buf[32] = {'\0'}, buf1[32] = {'\0'};
    555     int i;
    556 
    557     char *name = property->name;
    558     int prop_type = property->type;
    559 
    560     set_object_array_element(env, strArray, name, *array_index);
    561     *array_index += 1;
    562 
    563     if (prop_type == DBUS_TYPE_UINT32 || prop_type == DBUS_TYPE_INT16) {
    564         sprintf(buf, "%d", value->int_val);
    565         set_object_array_element(env, strArray, buf, *array_index);
    566         *array_index += 1;
    567     } else if (prop_type == DBUS_TYPE_BOOLEAN) {
    568         sprintf(buf, "%s", value->int_val ? "true" : "false");
    569 
    570         set_object_array_element(env, strArray, buf, *array_index);
    571         *array_index += 1;
    572     } else if (prop_type == DBUS_TYPE_ARRAY) {
    573         // Write the length first
    574         sprintf(buf1, "%d", len);
    575         set_object_array_element(env, strArray, buf1, *array_index);
    576         *array_index += 1;
    577 
    578         prop_val = value->array_val;
    579         for (i = 0; i < len; i++) {
    580             set_object_array_element(env, strArray, prop_val[i], *array_index);
    581             *array_index += 1;
    582         }
    583     } else {
    584         set_object_array_element(env, strArray, (const char *) value->str_val, *array_index);
    585         *array_index += 1;
    586     }
    587 }
    588 
    589 jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
    590                               const int max_num_properties) {
    591     DBusMessageIter dict_entry, dict;
    592     jobjectArray strArray = NULL;
    593     property_value value;
    594     int i, size = 0,array_index = 0;
    595     int len = 0, prop_type = DBUS_TYPE_INVALID, prop_index = -1, type;
    596     struct {
    597         property_value value;
    598         int len;
    599         bool used;
    600     } values[max_num_properties];
    601     int t, j;
    602 
    603     jclass stringClass = env->FindClass("java/lang/String");
    604     DBusError err;
    605     dbus_error_init(&err);
    606 
    607     for (i = 0; i < max_num_properties; i++) {
    608         values[i].used = false;
    609     }
    610 
    611     if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
    612         goto failure;
    613     dbus_message_iter_recurse(iter, &dict);
    614     do {
    615         len = 0;
    616         if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
    617             goto failure;
    618         dbus_message_iter_recurse(&dict, &dict_entry);
    619 
    620         if (!get_property(dict_entry, properties, max_num_properties, &prop_index,
    621                           &value, &len)) {
    622             size += 2;
    623             if (properties[prop_index].type == DBUS_TYPE_ARRAY)
    624                 size += len;
    625             values[prop_index].value = value;
    626             values[prop_index].len = len;
    627             values[prop_index].used = true;
    628         } else {
    629             goto failure;
    630         }
    631     } while(dbus_message_iter_next(&dict));
    632 
    633     strArray = env->NewObjectArray(size, stringClass, NULL);
    634 
    635     for (i = 0; i < max_num_properties; i++) {
    636         if (values[i].used) {
    637             create_prop_array(env, strArray, &properties[i], &values[i].value, values[i].len,
    638                               &array_index);
    639 
    640             if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used
    641                    && values[i].value.array_val != NULL)
    642                 free(values[i].value.array_val);
    643         }
    644 
    645     }
    646     return strArray;
    647 
    648 failure:
    649     if (dbus_error_is_set(&err))
    650         LOG_AND_FREE_DBUS_ERROR(&err);
    651     for (i = 0; i < max_num_properties; i++)
    652         if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used == true
    653                                         && values[i].value.array_val != NULL)
    654             free(values[i].value.array_val);
    655     return NULL;
    656 }
    657 
    658 jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
    659                            Properties *properties, int max_num_properties) {
    660     DBusMessageIter iter;
    661     DBusError err;
    662     jobjectArray strArray = NULL;
    663     jclass stringClass= env->FindClass("java/lang/String");
    664     int len = 0, prop_index = -1;
    665     int array_index = 0, size = 0;
    666     property_value value;
    667 
    668     dbus_error_init(&err);
    669     if (!dbus_message_iter_init(msg, &iter))
    670         goto failure;
    671 
    672     if (!get_property(iter, properties, max_num_properties,
    673                       &prop_index, &value, &len)) {
    674         size += 2;
    675         if (properties[prop_index].type == DBUS_TYPE_ARRAY)
    676             size += len;
    677         strArray = env->NewObjectArray(size, stringClass, NULL);
    678 
    679         create_prop_array(env, strArray, &properties[prop_index],
    680                           &value, len, &array_index);
    681 
    682         if (properties[prop_index].type == DBUS_TYPE_ARRAY && value.array_val != NULL)
    683              free(value.array_val);
    684 
    685         return strArray;
    686     }
    687 failure:
    688     LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    689     return NULL;
    690 }
    691 
    692 jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg) {
    693     return parse_property_change(env, msg, (Properties *) &adapter_properties,
    694                     sizeof(adapter_properties) / sizeof(Properties));
    695 }
    696 
    697 jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg) {
    698     return parse_property_change(env, msg, (Properties *) &remote_device_properties,
    699                     sizeof(remote_device_properties) / sizeof(Properties));
    700 }
    701 
    702 jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) {
    703     return parse_properties(env, iter, (Properties *) &adapter_properties,
    704                             sizeof(adapter_properties) / sizeof(Properties));
    705 }
    706 
    707 jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter) {
    708     return parse_properties(env, iter, (Properties *) &remote_device_properties,
    709                           sizeof(remote_device_properties) / sizeof(Properties));
    710 }
    711 
    712 int get_bdaddr(const char *str, bdaddr_t *ba) {
    713     char *d = ((char *)ba) + 5, *endp;
    714     int i;
    715     for(i = 0; i < 6; i++) {
    716         *d-- = strtol(str, &endp, 16);
    717         if (*endp != ':' && i != 5) {
    718             memset(ba, 0, sizeof(bdaddr_t));
    719             return -1;
    720         }
    721         str = endp + 1;
    722     }
    723     return 0;
    724 }
    725 
    726 void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
    727     const uint8_t *b = (const uint8_t *)ba;
    728     sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
    729             b[5], b[4], b[3], b[2], b[1], b[0]);
    730 }
    731 
    732 bool debug_no_encrypt() {
    733     return false;
    734 #if 0
    735     char value[PROPERTY_VALUE_MAX] = "";
    736 
    737     property_get("debug.bt.no_encrypt", value, "");
    738     if (!strncmp("true", value, PROPERTY_VALUE_MAX) ||
    739         !strncmp("1", value, PROPERTY_VALUE_MAX)) {
    740         LOGD("mandatory bluetooth encryption disabled");
    741         return true;
    742     } else {
    743         return false;
    744     }
    745 #endif
    746 }
    747 #endif
    748 
    749 } /* namespace android */
    750