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 DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
18 #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
19 #define LOG_TAG "BluetoothService.cpp"
20
21 #include "android_bluetooth_common.h"
22 #include "android_runtime/AndroidRuntime.h"
23 #include "JNIHelp.h"
24 #include "jni.h"
25 #include "utils/Log.h"
26 #include "utils/misc.h"
27
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <unistd.h>
34
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <fcntl.h>
38
39 #ifdef HAVE_BLUETOOTH
40 #include <dbus/dbus.h>
41 #include <bluedroid/bluetooth.h>
42 #endif
43
44 #include <cutils/properties.h>
45
46 namespace android {
47
48 #define BLUETOOTH_CLASS_ERROR 0xFF000000
49 #define PROPERTIES_NREFS 10
50
51 #ifdef HAVE_BLUETOOTH
52 // We initialize these variables when we load class
53 // android.server.BluetoothService
54 static jfieldID field_mNativeData;
55 static jfieldID field_mEventLoop;
56
57 typedef struct {
58 JNIEnv *env;
59 DBusConnection *conn;
60 const char *adapter; // dbus object name of the local adapter
61 } native_data_t;
62
63 extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
64 jobject);
65 extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
66 DBusMessage *msg,
67 void *data);
68 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
69 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
70 void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
71
72
73 /** Get native data stored in the opaque (Java code maintained) pointer mNativeData
74 * Perform quick sanity check, if there are any problems return NULL
75 */
get_native_data(JNIEnv * env,jobject object)76 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
77 native_data_t *nat =
78 (native_data_t *)(env->GetIntField(object, field_mNativeData));
79 if (nat == NULL || nat->conn == NULL) {
80 LOGE("Uninitialized native data\n");
81 return NULL;
82 }
83 return nat;
84 }
85 #endif
86
classInitNative(JNIEnv * env,jclass clazz)87 static void classInitNative(JNIEnv* env, jclass clazz) {
88 LOGV(__FUNCTION__);
89 #ifdef HAVE_BLUETOOTH
90 field_mNativeData = get_field(env, clazz, "mNativeData", "I");
91 field_mEventLoop = get_field(env, clazz, "mEventLoop",
92 "Landroid/server/BluetoothEventLoop;");
93 #endif
94 }
95
96 /* Returns true on success (even if adapter is present but disabled).
97 * Return false if dbus is down, or another serious error (out of memory)
98 */
initializeNativeDataNative(JNIEnv * env,jobject object)99 static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
100 LOGV(__FUNCTION__);
101 #ifdef HAVE_BLUETOOTH
102 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
103 if (NULL == nat) {
104 LOGE("%s: out of memory!", __FUNCTION__);
105 return false;
106 }
107 nat->env = env;
108
109 env->SetIntField(object, field_mNativeData, (jint)nat);
110 DBusError err;
111 dbus_error_init(&err);
112 dbus_threads_init_default();
113 nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
114 if (dbus_error_is_set(&err)) {
115 LOGE("Could not get onto the system bus: %s", err.message);
116 dbus_error_free(&err);
117 return false;
118 }
119 dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
120 #endif /*HAVE_BLUETOOTH*/
121 return true;
122 }
123
get_adapter_path(JNIEnv * env,jobject object)124 static const char *get_adapter_path(JNIEnv* env, jobject object) {
125 #ifdef HAVE_BLUETOOTH
126 event_loop_native_data_t *event_nat =
127 get_EventLoop_native_data(env, env->GetObjectField(object,
128 field_mEventLoop));
129 if (event_nat == NULL)
130 return NULL;
131 return event_nat->adapter;
132 #else
133 return NULL;
134 #endif
135 }
136
137 // This function is called when the adapter is enabled.
setupNativeDataNative(JNIEnv * env,jobject object)138 static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
139 LOGV(__FUNCTION__);
140 #ifdef HAVE_BLUETOOTH
141 native_data_t *nat =
142 (native_data_t *)env->GetIntField(object, field_mNativeData);
143 event_loop_native_data_t *event_nat =
144 get_EventLoop_native_data(env, env->GetObjectField(object,
145 field_mEventLoop));
146 // Register agent for remote devices.
147 const char *device_agent_path = "/android/bluetooth/remote_device_agent";
148 static const DBusObjectPathVTable agent_vtable = {
149 NULL, agent_event_filter, NULL, NULL, NULL, NULL };
150
151 if (!dbus_connection_register_object_path(nat->conn, device_agent_path,
152 &agent_vtable, event_nat)) {
153 LOGE("%s: Can't register object path %s for remote device agent!",
154 __FUNCTION__, device_agent_path);
155 return JNI_FALSE;
156 }
157 #endif /*HAVE_BLUETOOTH*/
158 return JNI_TRUE;
159 }
160
tearDownNativeDataNative(JNIEnv * env,jobject object)161 static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
162 LOGV(__FUNCTION__);
163 #ifdef HAVE_BLUETOOTH
164 native_data_t *nat =
165 (native_data_t *)env->GetIntField(object, field_mNativeData);
166 if (nat != NULL) {
167 const char *device_agent_path =
168 "/android/bluetooth/remote_device_agent";
169 dbus_connection_unregister_object_path (nat->conn, device_agent_path);
170 }
171 #endif /*HAVE_BLUETOOTH*/
172 return JNI_TRUE;
173 }
174
cleanupNativeDataNative(JNIEnv * env,jobject object)175 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
176 LOGV(__FUNCTION__);
177 #ifdef HAVE_BLUETOOTH
178 native_data_t *nat =
179 (native_data_t *)env->GetIntField(object, field_mNativeData);
180 if (nat) {
181 free(nat);
182 nat = NULL;
183 }
184 #endif
185 }
186
getAdapterPathNative(JNIEnv * env,jobject object)187 static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
188 LOGV(__FUNCTION__);
189 #ifdef HAVE_BLUETOOTH
190 native_data_t *nat = get_native_data(env, object);
191 if (nat) {
192 return (env->NewStringUTF(get_adapter_path(env, object)));
193 }
194 #endif
195 return NULL;
196 }
197
198
startDiscoveryNative(JNIEnv * env,jobject object)199 static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
200 LOGV(__FUNCTION__);
201 #ifdef HAVE_BLUETOOTH
202 DBusMessage *msg = NULL;
203 DBusMessage *reply = NULL;
204 DBusError err;
205 const char *name;
206 jboolean ret = JNI_FALSE;
207
208 native_data_t *nat = get_native_data(env, object);
209 if (nat == NULL) {
210 goto done;
211 }
212
213 dbus_error_init(&err);
214
215 /* Compose the command */
216 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
217 get_adapter_path(env, object),
218 DBUS_ADAPTER_IFACE, "StartDiscovery");
219
220 if (msg == NULL) {
221 if (dbus_error_is_set(&err)) {
222 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
223 }
224 goto done;
225 }
226
227 /* Send the command. */
228 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
229 if (dbus_error_is_set(&err)) {
230 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
231 ret = JNI_FALSE;
232 goto done;
233 }
234
235 ret = JNI_TRUE;
236 done:
237 if (reply) dbus_message_unref(reply);
238 if (msg) dbus_message_unref(msg);
239 return ret;
240 #else
241 return JNI_FALSE;
242 #endif
243 }
244
stopDiscoveryNative(JNIEnv * env,jobject object)245 static void stopDiscoveryNative(JNIEnv *env, jobject object) {
246 LOGV(__FUNCTION__);
247 #ifdef HAVE_BLUETOOTH
248 DBusMessage *msg = NULL;
249 DBusMessage *reply = NULL;
250 DBusError err;
251 const char *name;
252 jstring ret;
253 native_data_t *nat;
254
255 dbus_error_init(&err);
256
257 nat = get_native_data(env, object);
258 if (nat == NULL) {
259 goto done;
260 }
261
262 /* Compose the command */
263 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
264 get_adapter_path(env, object),
265 DBUS_ADAPTER_IFACE, "StopDiscovery");
266 if (msg == NULL) {
267 if (dbus_error_is_set(&err))
268 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
269 goto done;
270 }
271
272 /* Send the command. */
273 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
274 if (dbus_error_is_set(&err)) {
275 if(strncmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized",
276 strlen(BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized")) == 0) {
277 // hcid sends this if there is no active discovery to cancel
278 LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
279 dbus_error_free(&err);
280 } else {
281 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
282 }
283 }
284
285 done:
286 if (msg) dbus_message_unref(msg);
287 if (reply) dbus_message_unref(reply);
288 #endif
289 }
290
createPairedDeviceNative(JNIEnv * env,jobject object,jstring address,jint timeout_ms)291 static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
292 jstring address, jint timeout_ms) {
293 LOGV(__FUNCTION__);
294 #ifdef HAVE_BLUETOOTH
295 native_data_t *nat = get_native_data(env, object);
296 jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
297 struct event_loop_native_data_t *eventLoopNat =
298 get_EventLoop_native_data(env, eventLoop);
299
300 if (nat && eventLoopNat) {
301 const char *c_address = env->GetStringUTFChars(address, NULL);
302 LOGV("... address = %s", c_address);
303 char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
304 const char *capabilities = "DisplayYesNo";
305 const char *agent_path = "/android/bluetooth/remote_device_agent";
306
307 strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
308 bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
309 onCreatePairedDeviceResult, // callback
310 context_address,
311 eventLoopNat,
312 get_adapter_path(env, object),
313 DBUS_ADAPTER_IFACE,
314 "CreatePairedDevice",
315 DBUS_TYPE_STRING, &c_address,
316 DBUS_TYPE_OBJECT_PATH, &agent_path,
317 DBUS_TYPE_STRING, &capabilities,
318 DBUS_TYPE_INVALID);
319 env->ReleaseStringUTFChars(address, c_address);
320 return ret ? JNI_TRUE : JNI_FALSE;
321
322 }
323 #endif
324 return JNI_FALSE;
325 }
326
getDeviceServiceChannelNative(JNIEnv * env,jobject object,jstring path,jstring pattern,jint attr_id)327 static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
328 jstring path,
329 jstring pattern, jint attr_id) {
330 #ifdef HAVE_BLUETOOTH
331 LOGV(__FUNCTION__);
332 native_data_t *nat = get_native_data(env, object);
333 jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
334 struct event_loop_native_data_t *eventLoopNat =
335 get_EventLoop_native_data(env, eventLoop);
336 if (nat && eventLoopNat) {
337 const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
338 const char *c_path = env->GetStringUTFChars(path, NULL);
339 LOGV("... pattern = %s", c_pattern);
340 LOGV("... attr_id = %#X", attr_id);
341 DBusMessage *reply =
342 dbus_func_args(env, nat->conn, c_path,
343 DBUS_DEVICE_IFACE, "GetServiceAttributeValue",
344 DBUS_TYPE_STRING, &c_pattern,
345 DBUS_TYPE_UINT16, &attr_id,
346 DBUS_TYPE_INVALID);
347 env->ReleaseStringUTFChars(pattern, c_pattern);
348 env->ReleaseStringUTFChars(path, c_path);
349 return reply ? dbus_returns_int32(env, reply) : -1;
350 }
351 #endif
352 return -1;
353 }
354
cancelDeviceCreationNative(JNIEnv * env,jobject object,jstring address)355 static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
356 jstring address) {
357 LOGV(__FUNCTION__);
358 jboolean result = JNI_FALSE;
359 #ifdef HAVE_BLUETOOTH
360 native_data_t *nat = get_native_data(env, object);
361 if (nat) {
362 const char *c_address = env->GetStringUTFChars(address, NULL);
363 DBusError err;
364 dbus_error_init(&err);
365 LOGV("... address = %s", c_address);
366 DBusMessage *reply =
367 dbus_func_args_timeout(env, nat->conn, -1,
368 get_adapter_path(env, object),
369 DBUS_ADAPTER_IFACE, "CancelDeviceCreation",
370 DBUS_TYPE_STRING, &c_address,
371 DBUS_TYPE_INVALID);
372 env->ReleaseStringUTFChars(address, c_address);
373 if (!reply) {
374 if (dbus_error_is_set(&err)) {
375 LOG_AND_FREE_DBUS_ERROR(&err);
376 } else
377 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
378 return JNI_FALSE;
379 } else {
380 result = JNI_TRUE;
381 }
382 dbus_message_unref(reply);
383 }
384 #endif
385 return JNI_FALSE;
386 }
387
removeDeviceNative(JNIEnv * env,jobject object,jstring object_path)388 static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
389 LOGV(__FUNCTION__);
390 #ifdef HAVE_BLUETOOTH
391 native_data_t *nat = get_native_data(env, object);
392 if (nat) {
393 const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
394 bool ret = dbus_func_args_async(env, nat->conn, -1,
395 NULL,
396 NULL,
397 NULL,
398 get_adapter_path(env, object),
399 DBUS_ADAPTER_IFACE,
400 "RemoveDevice",
401 DBUS_TYPE_OBJECT_PATH, &c_object_path,
402 DBUS_TYPE_INVALID);
403 env->ReleaseStringUTFChars(object_path, c_object_path);
404 return ret ? JNI_TRUE : JNI_FALSE;
405 }
406 #endif
407 return JNI_FALSE;
408 }
409
enableNative(JNIEnv * env,jobject object)410 static jint enableNative(JNIEnv *env, jobject object) {
411 #ifdef HAVE_BLUETOOTH
412 LOGV(__FUNCTION__);
413 return bt_enable();
414 #endif
415 return -1;
416 }
417
disableNative(JNIEnv * env,jobject object)418 static jint disableNative(JNIEnv *env, jobject object) {
419 #ifdef HAVE_BLUETOOTH
420 LOGV(__FUNCTION__);
421 return bt_disable();
422 #endif
423 return -1;
424 }
425
isEnabledNative(JNIEnv * env,jobject object)426 static jint isEnabledNative(JNIEnv *env, jobject object) {
427 #ifdef HAVE_BLUETOOTH
428 LOGV(__FUNCTION__);
429 return bt_is_enabled();
430 #endif
431 return -1;
432 }
433
setPairingConfirmationNative(JNIEnv * env,jobject object,jstring address,bool confirm,int nativeData)434 static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object,
435 jstring address, bool confirm,
436 int nativeData) {
437 #ifdef HAVE_BLUETOOTH
438 LOGV(__FUNCTION__);
439 native_data_t *nat = get_native_data(env, object);
440 if (nat) {
441 DBusMessage *msg = (DBusMessage *)nativeData;
442 DBusMessage *reply;
443 if (confirm) {
444 reply = dbus_message_new_method_return(msg);
445 } else {
446 reply = dbus_message_new_error(msg,
447 "org.bluez.Error.Rejected", "User rejected confirmation");
448 }
449
450 if (!reply) {
451 LOGE("%s: Cannot create message reply to RequestPasskeyConfirmation or"
452 "RequestPairingConsent to D-Bus\n", __FUNCTION__);
453 dbus_message_unref(msg);
454 return JNI_FALSE;
455 }
456
457 dbus_connection_send(nat->conn, reply, NULL);
458 dbus_message_unref(msg);
459 dbus_message_unref(reply);
460 return JNI_TRUE;
461 }
462 #endif
463 return JNI_FALSE;
464 }
465
setPasskeyNative(JNIEnv * env,jobject object,jstring address,int passkey,int nativeData)466 static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
467 int passkey, int nativeData) {
468 #ifdef HAVE_BLUETOOTH
469 LOGV(__FUNCTION__);
470 native_data_t *nat = get_native_data(env, object);
471 if (nat) {
472 DBusMessage *msg = (DBusMessage *)nativeData;
473 DBusMessage *reply = dbus_message_new_method_return(msg);
474 if (!reply) {
475 LOGE("%s: Cannot create message reply to return Passkey code to "
476 "D-Bus\n", __FUNCTION__);
477 dbus_message_unref(msg);
478 return JNI_FALSE;
479 }
480
481 dbus_message_append_args(reply, DBUS_TYPE_UINT32, (uint32_t *)&passkey,
482 DBUS_TYPE_INVALID);
483
484 dbus_connection_send(nat->conn, reply, NULL);
485 dbus_message_unref(msg);
486 dbus_message_unref(reply);
487 return JNI_TRUE;
488 }
489 #endif
490 return JNI_FALSE;
491 }
492
setPinNative(JNIEnv * env,jobject object,jstring address,jstring pin,int nativeData)493 static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
494 jstring pin, int nativeData) {
495 #ifdef HAVE_BLUETOOTH
496 LOGV(__FUNCTION__);
497 native_data_t *nat = get_native_data(env, object);
498 if (nat) {
499 DBusMessage *msg = (DBusMessage *)nativeData;
500 DBusMessage *reply = dbus_message_new_method_return(msg);
501 if (!reply) {
502 LOGE("%s: Cannot create message reply to return PIN code to "
503 "D-Bus\n", __FUNCTION__);
504 dbus_message_unref(msg);
505 return JNI_FALSE;
506 }
507
508 const char *c_pin = env->GetStringUTFChars(pin, NULL);
509
510 dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
511 DBUS_TYPE_INVALID);
512
513 dbus_connection_send(nat->conn, reply, NULL);
514 dbus_message_unref(msg);
515 dbus_message_unref(reply);
516 env->ReleaseStringUTFChars(pin, c_pin);
517 return JNI_TRUE;
518 }
519 #endif
520 return JNI_FALSE;
521 }
522
cancelPairingUserInputNative(JNIEnv * env,jobject object,jstring address,int nativeData)523 static jboolean cancelPairingUserInputNative(JNIEnv *env, jobject object,
524 jstring address, int nativeData) {
525 #ifdef HAVE_BLUETOOTH
526 LOGV(__FUNCTION__);
527 native_data_t *nat = get_native_data(env, object);
528 if (nat) {
529 DBusMessage *msg = (DBusMessage *)nativeData;
530 DBusMessage *reply = dbus_message_new_error(msg,
531 "org.bluez.Error.Canceled", "Pairing User Input was canceled");
532 if (!reply) {
533 LOGE("%s: Cannot create message reply to return cancelUserInput to"
534 "D-BUS\n", __FUNCTION__);
535 dbus_message_unref(msg);
536 return JNI_FALSE;
537 }
538
539 dbus_connection_send(nat->conn, reply, NULL);
540 dbus_message_unref(msg);
541 dbus_message_unref(reply);
542 return JNI_TRUE;
543 }
544 #endif
545 return JNI_FALSE;
546 }
547
getDevicePropertiesNative(JNIEnv * env,jobject object,jstring path)548 static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
549 jstring path)
550 {
551 #ifdef HAVE_BLUETOOTH
552 LOGV(__FUNCTION__);
553 native_data_t *nat = get_native_data(env, object);
554 if (nat) {
555 DBusMessage *msg, *reply;
556 DBusError err;
557 dbus_error_init(&err);
558
559 const char *c_path = env->GetStringUTFChars(path, NULL);
560 reply = dbus_func_args_timeout(env,
561 nat->conn, -1, c_path,
562 DBUS_DEVICE_IFACE, "GetProperties",
563 DBUS_TYPE_INVALID);
564 env->ReleaseStringUTFChars(path, c_path);
565
566 if (!reply) {
567 if (dbus_error_is_set(&err)) {
568 LOG_AND_FREE_DBUS_ERROR(&err);
569 } else
570 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
571 return NULL;
572 }
573 env->PushLocalFrame(PROPERTIES_NREFS);
574
575 DBusMessageIter iter;
576 jobjectArray str_array = NULL;
577 if (dbus_message_iter_init(reply, &iter))
578 str_array = parse_remote_device_properties(env, &iter);
579 dbus_message_unref(reply);
580
581 env->PopLocalFrame(NULL);
582
583 return str_array;
584 }
585 #endif
586 return NULL;
587 }
588
getAdapterPropertiesNative(JNIEnv * env,jobject object)589 static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
590 #ifdef HAVE_BLUETOOTH
591 LOGV(__FUNCTION__);
592 native_data_t *nat = get_native_data(env, object);
593 if (nat) {
594 DBusMessage *msg, *reply;
595 DBusError err;
596 dbus_error_init(&err);
597
598 reply = dbus_func_args_timeout(env,
599 nat->conn, -1, get_adapter_path(env, object),
600 DBUS_ADAPTER_IFACE, "GetProperties",
601 DBUS_TYPE_INVALID);
602 if (!reply) {
603 if (dbus_error_is_set(&err)) {
604 LOG_AND_FREE_DBUS_ERROR(&err);
605 } else
606 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
607 return NULL;
608 }
609 env->PushLocalFrame(PROPERTIES_NREFS);
610
611 DBusMessageIter iter;
612 jobjectArray str_array = NULL;
613 if (dbus_message_iter_init(reply, &iter))
614 str_array = parse_adapter_properties(env, &iter);
615 dbus_message_unref(reply);
616
617 env->PopLocalFrame(NULL);
618 return str_array;
619 }
620 #endif
621 return NULL;
622 }
623
setAdapterPropertyNative(JNIEnv * env,jobject object,jstring key,void * value,jint type)624 static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key,
625 void *value, jint type) {
626 #ifdef HAVE_BLUETOOTH
627 LOGV(__FUNCTION__);
628 native_data_t *nat = get_native_data(env, object);
629 if (nat) {
630 DBusMessage *reply, *msg;
631 DBusMessageIter iter;
632 DBusError err;
633 const char *c_key = env->GetStringUTFChars(key, NULL);
634 dbus_error_init(&err);
635
636 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
637 get_adapter_path(env, object),
638 DBUS_ADAPTER_IFACE, "SetProperty");
639 if (!msg) {
640 LOGE("%s: Can't allocate new method call for GetProperties!",
641 __FUNCTION__);
642 env->ReleaseStringUTFChars(key, c_key);
643 return JNI_FALSE;
644 }
645
646 dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
647 dbus_message_iter_init_append(msg, &iter);
648 append_variant(&iter, type, value);
649
650 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
651 dbus_message_unref(msg);
652
653 env->ReleaseStringUTFChars(key, c_key);
654
655 if (!reply) {
656 if (dbus_error_is_set(&err)) {
657 LOG_AND_FREE_DBUS_ERROR(&err);
658 } else
659 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
660 return JNI_FALSE;
661 }
662 return JNI_TRUE;
663 }
664 #endif
665 return JNI_FALSE;
666 }
667
setAdapterPropertyStringNative(JNIEnv * env,jobject object,jstring key,jstring value)668 static jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key,
669 jstring value) {
670 #ifdef HAVE_BLUETOOTH
671 const char *c_value = env->GetStringUTFChars(value, NULL);
672 jboolean ret = setAdapterPropertyNative(env, object, key, (void *)&c_value, DBUS_TYPE_STRING);
673 env->ReleaseStringUTFChars(value, (char *)c_value);
674 return ret;
675 #else
676 return JNI_FALSE;
677 #endif
678 }
679
setAdapterPropertyIntegerNative(JNIEnv * env,jobject object,jstring key,jint value)680 static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key,
681 jint value) {
682 #ifdef HAVE_BLUETOOTH
683 return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32);
684 #else
685 return JNI_FALSE;
686 #endif
687 }
688
setAdapterPropertyBooleanNative(JNIEnv * env,jobject object,jstring key,jint value)689 static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key,
690 jint value) {
691 #ifdef HAVE_BLUETOOTH
692 return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN);
693 #else
694 return JNI_FALSE;
695 #endif
696 }
697
setDevicePropertyNative(JNIEnv * env,jobject object,jstring path,jstring key,void * value,jint type)698 static jboolean setDevicePropertyNative(JNIEnv *env, jobject object, jstring path,
699 jstring key, void *value, jint type) {
700 #ifdef HAVE_BLUETOOTH
701 LOGV(__FUNCTION__);
702 native_data_t *nat = get_native_data(env, object);
703 if (nat) {
704 DBusMessage *reply, *msg;
705 DBusMessageIter iter;
706 DBusError err;
707
708 const char *c_key = env->GetStringUTFChars(key, NULL);
709 const char *c_path = env->GetStringUTFChars(path, NULL);
710
711 dbus_error_init(&err);
712 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
713 c_path, DBUS_DEVICE_IFACE, "SetProperty");
714 if (!msg) {
715 LOGE("%s: Can't allocate new method call for device SetProperty!", __FUNCTION__);
716 env->ReleaseStringUTFChars(key, c_key);
717 env->ReleaseStringUTFChars(path, c_path);
718 return JNI_FALSE;
719 }
720
721 dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
722 dbus_message_iter_init_append(msg, &iter);
723 append_variant(&iter, type, value);
724
725 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
726 dbus_message_unref(msg);
727
728 env->ReleaseStringUTFChars(key, c_key);
729 env->ReleaseStringUTFChars(path, c_path);
730 if (!reply) {
731 if (dbus_error_is_set(&err)) {
732 LOG_AND_FREE_DBUS_ERROR(&err);
733 } else
734 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
735 return JNI_FALSE;
736 }
737 return JNI_TRUE;
738 }
739 #endif
740 return JNI_FALSE;
741 }
742
setDevicePropertyBooleanNative(JNIEnv * env,jobject object,jstring path,jstring key,jint value)743 static jboolean setDevicePropertyBooleanNative(JNIEnv *env, jobject object,
744 jstring path, jstring key, jint value) {
745 #ifdef HAVE_BLUETOOTH
746 return setDevicePropertyNative(env, object, path, key,
747 (void *)&value, DBUS_TYPE_BOOLEAN);
748 #else
749 return JNI_FALSE;
750 #endif
751 }
752
753
createDeviceNative(JNIEnv * env,jobject object,jstring address)754 static jboolean createDeviceNative(JNIEnv *env, jobject object,
755 jstring address) {
756 LOGV(__FUNCTION__);
757 #ifdef HAVE_BLUETOOTH
758 native_data_t *nat = get_native_data(env, object);
759 jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
760 struct event_loop_native_data_t *eventLoopNat =
761 get_EventLoop_native_data(env, eventLoop);
762
763 if (nat && eventLoopNat) {
764 const char *c_address = env->GetStringUTFChars(address, NULL);
765 LOGV("... address = %s", c_address);
766 char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
767 strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
768
769 bool ret = dbus_func_args_async(env, nat->conn, -1,
770 onCreateDeviceResult,
771 context_address,
772 eventLoopNat,
773 get_adapter_path(env, object),
774 DBUS_ADAPTER_IFACE,
775 "CreateDevice",
776 DBUS_TYPE_STRING, &c_address,
777 DBUS_TYPE_INVALID);
778 env->ReleaseStringUTFChars(address, c_address);
779 return ret ? JNI_TRUE : JNI_FALSE;
780 }
781 #endif
782 return JNI_FALSE;
783 }
784
discoverServicesNative(JNIEnv * env,jobject object,jstring path,jstring pattern)785 static jboolean discoverServicesNative(JNIEnv *env, jobject object,
786 jstring path, jstring pattern) {
787 LOGV(__FUNCTION__);
788 #ifdef HAVE_BLUETOOTH
789 native_data_t *nat = get_native_data(env, object);
790 jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
791 struct event_loop_native_data_t *eventLoopNat =
792 get_EventLoop_native_data(env, eventLoop);
793
794 if (nat && eventLoopNat) {
795 const char *c_path = env->GetStringUTFChars(path, NULL);
796 const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
797 int len = env->GetStringLength(path) + 1;
798 char *context_path = (char *)calloc(len, sizeof(char));
799 strlcpy(context_path, c_path, len); // for callback
800
801 LOGV("... Object Path = %s", c_path);
802 LOGV("... Pattern = %s, strlen = %d", c_pattern, strlen(c_pattern));
803
804 bool ret = dbus_func_args_async(env, nat->conn, -1,
805 onDiscoverServicesResult,
806 context_path,
807 eventLoopNat,
808 c_path,
809 DBUS_DEVICE_IFACE,
810 "DiscoverServices",
811 DBUS_TYPE_STRING, &c_pattern,
812 DBUS_TYPE_INVALID);
813 env->ReleaseStringUTFChars(path, c_path);
814 env->ReleaseStringUTFChars(pattern, c_pattern);
815 return ret ? JNI_TRUE : JNI_FALSE;
816 }
817 #endif
818 return JNI_FALSE;
819 }
820
addRfcommServiceRecordNative(JNIEnv * env,jobject object,jstring name,jlong uuidMsb,jlong uuidLsb,jshort channel)821 static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object,
822 jstring name, jlong uuidMsb, jlong uuidLsb, jshort channel) {
823 LOGV(__FUNCTION__);
824 #ifdef HAVE_BLUETOOTH
825 native_data_t *nat = get_native_data(env, object);
826 if (nat) {
827 const char *c_name = env->GetStringUTFChars(name, NULL);
828 LOGV("... name = %s", c_name);
829 LOGV("... uuid1 = %llX", uuidMsb);
830 LOGV("... uuid2 = %llX", uuidLsb);
831 LOGV("... channel = %d", channel);
832 DBusMessage *reply = dbus_func_args(env, nat->conn,
833 get_adapter_path(env, object),
834 DBUS_ADAPTER_IFACE, "AddRfcommServiceRecord",
835 DBUS_TYPE_STRING, &c_name,
836 DBUS_TYPE_UINT64, &uuidMsb,
837 DBUS_TYPE_UINT64, &uuidLsb,
838 DBUS_TYPE_UINT16, &channel,
839 DBUS_TYPE_INVALID);
840 env->ReleaseStringUTFChars(name, c_name);
841 return reply ? dbus_returns_uint32(env, reply) : -1;
842 }
843 #endif
844 return -1;
845 }
846
removeServiceRecordNative(JNIEnv * env,jobject object,jint handle)847 static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint handle) {
848 LOGV(__FUNCTION__);
849 #ifdef HAVE_BLUETOOTH
850 native_data_t *nat = get_native_data(env, object);
851 if (nat) {
852 LOGV("... handle = %X", handle);
853 DBusMessage *reply = dbus_func_args(env, nat->conn,
854 get_adapter_path(env, object),
855 DBUS_ADAPTER_IFACE, "RemoveServiceRecord",
856 DBUS_TYPE_UINT32, &handle,
857 DBUS_TYPE_INVALID);
858 return reply ? JNI_TRUE : JNI_FALSE;
859 }
860 #endif
861 return JNI_FALSE;
862 }
863
864 static JNINativeMethod sMethods[] = {
865 /* name, signature, funcPtr */
866 {"classInitNative", "()V", (void*)classInitNative},
867 {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
868 {"setupNativeDataNative", "()Z", (void *)setupNativeDataNative},
869 {"tearDownNativeDataNative", "()Z", (void *)tearDownNativeDataNative},
870 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
871 {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
872
873 {"isEnabledNative", "()I", (void *)isEnabledNative},
874 {"enableNative", "()I", (void *)enableNative},
875 {"disableNative", "()I", (void *)disableNative},
876
877 {"getAdapterPropertiesNative", "()[Ljava/lang/Object;", (void *)getAdapterPropertiesNative},
878 {"getDevicePropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
879 (void *)getDevicePropertiesNative},
880 {"setAdapterPropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
881 (void *)setAdapterPropertyStringNative},
882 {"setAdapterPropertyBooleanNative", "(Ljava/lang/String;I)Z",
883 (void *)setAdapterPropertyBooleanNative},
884 {"setAdapterPropertyIntegerNative", "(Ljava/lang/String;I)Z",
885 (void *)setAdapterPropertyIntegerNative},
886
887 {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
888 {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative},
889
890 {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative},
891 {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative},
892 {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative},
893 {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I",
894 (void *)getDeviceServiceChannelNative},
895
896 {"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z",
897 (void *)setPairingConfirmationNative},
898 {"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative},
899 {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
900 {"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z",
901 (void *)cancelPairingUserInputNative},
902 {"setDevicePropertyBooleanNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
903 (void *)setDevicePropertyBooleanNative},
904 {"createDeviceNative", "(Ljava/lang/String;)Z", (void *)createDeviceNative},
905 {"discoverServicesNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)discoverServicesNative},
906 {"addRfcommServiceRecordNative", "(Ljava/lang/String;JJS)I", (void *)addRfcommServiceRecordNative},
907 {"removeServiceRecordNative", "(I)Z", (void *)removeServiceRecordNative},
908 };
909
register_android_server_BluetoothService(JNIEnv * env)910 int register_android_server_BluetoothService(JNIEnv *env) {
911 return AndroidRuntime::registerNativeMethods(env,
912 "android/server/BluetoothService", sMethods, NELEM(sMethods));
913 }
914
915 } /* namespace android */
916