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