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