• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_field(JNIEnv * env,jclass clazz,const char * member,const char * mtype)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         LOGE("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 
dbus_func_args_async_callback(DBusPendingCall * call,void * data)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 
dbus_func_args_async_valist(JNIEnv * env,DBusConnection * conn,int timeout_ms,void (* user_cb)(DBusMessage *,void *,void *),void * user,void * nat,const char * path,const char * ifc,const char * func,int first_arg_type,va_list args)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         LOGE("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         LOGE("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 
dbus_func_args_async(JNIEnv * env,DBusConnection * conn,int timeout_ms,void (* reply)(DBusMessage *,void *,void *),void * user,void * nat,const char * path,const char * ifc,const char * func,int first_arg_type,...)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 LOGE'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.
dbus_func_args_timeout_valist(JNIEnv * env,DBusConnection * conn,int timeout_ms,DBusError * err,const char * path,const char * ifc,const char * func,int first_arg_type,va_list args)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         LOGE("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         LOGE("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 
dbus_func_args_timeout(JNIEnv * env,DBusConnection * conn,int timeout_ms,const char * path,const char * ifc,const char * func,int first_arg_type,...)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 
dbus_func_args(JNIEnv * env,DBusConnection * conn,const char * path,const char * ifc,const char * func,int first_arg_type,...)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 
dbus_func_args_error(JNIEnv * env,DBusConnection * conn,DBusError * err,const char * path,const char * ifc,const char * func,int first_arg_type,...)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 
dbus_returns_unixfd(JNIEnv * env,DBusMessage * reply)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 
dbus_returns_int32(JNIEnv * env,DBusMessage * reply)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 
dbus_returns_uint32(JNIEnv * env,DBusMessage * reply)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 
dbus_returns_string(JNIEnv * env,DBusMessage * reply)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 
dbus_returns_boolean(JNIEnv * env,DBusMessage * reply)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 
set_object_array_element(JNIEnv * env,jobjectArray strArray,const char * value,int index)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 
dbus_returns_array_of_object_path(JNIEnv * env,DBusMessage * reply)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 
dbus_returns_array_of_strings(JNIEnv * env,DBusMessage * reply)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         //LOGV("%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 
dbus_returns_array_of_bytes(JNIEnv * env,DBusMessage * reply)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         //LOGV("%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 
append_variant(DBusMessageIter * iter,int type,void * val)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 
dict_append_entry(DBusMessageIter * dict,const char * key,int type,void * val)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 
append_dict_valist(DBusMessageIter * iterator,const char * first_key,va_list var_args)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 
append_dict_args(DBusMessage * reply,const char * first_key,...)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 
get_property(DBusMessageIter iter,Properties * properties,int max_num_properties,int * prop_index,property_value * value,int * len)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         LOGE("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 
create_prop_array(JNIEnv * env,jobjectArray strArray,Properties * property,property_value * value,int len,int * array_index)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 
parse_properties(JNIEnv * env,DBusMessageIter * iter,Properties * properties,const int max_num_properties)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 
parse_property_change(JNIEnv * env,DBusMessage * msg,Properties * properties,int max_num_properties)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 
parse_adapter_property_change(JNIEnv * env,DBusMessage * msg)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 
parse_remote_device_property_change(JNIEnv * env,DBusMessage * msg)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 
parse_input_property_change(JNIEnv * env,DBusMessage * msg)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 
parse_pan_property_change(JNIEnv * env,DBusMessage * msg)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 
parse_adapter_properties(JNIEnv * env,DBusMessageIter * iter)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 
parse_remote_device_properties(JNIEnv * env,DBusMessageIter * iter)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 
parse_input_properties(JNIEnv * env,DBusMessageIter * iter)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 
parse_health_device_properties(JNIEnv * env,DBusMessageIter * iter)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 
parse_health_device_property_change(JNIEnv * env,DBusMessage * msg)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 
parse_health_channel_properties(JNIEnv * env,DBusMessageIter * iter)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 
get_bdaddr(const char * str,bdaddr_t * ba)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 
get_bdaddr_as_string(const bdaddr_t * ba,char * str)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 
debug_no_encrypt()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         LOGD("mandatory bluetooth encryption disabled");
859         return true;
860     } else {
861         return false;
862     }
863 #endif
864 }
865 #endif
866 
867 } /* namespace android */
868