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