• 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 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