com_android_bluetooth_btservice_AdapterService.cpp revision 6c91bc0a163cc7600c40d7fb979777fd911d1ef1
1/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5#define LOG_TAG "BluetoothServiceJni"
6
7#include "com_android_bluetooth.h"
8#include "utils/Log.h"
9#include "utils/misc.h"
10#include "cutils/properties.h"
11#include "android_runtime/AndroidRuntime.h"
12
13#include <string.h>
14#include <pthread.h>
15
16#include <sys/stat.h>
17#include <fcntl.h>
18
19namespace android {
20
21#define ADDITIONAL_NREFS 50
22
23static jmethodID method_stateChangeCallback;
24static jmethodID method_adapterPropertyChangedCallback;
25static jmethodID method_devicePropertyChangedCallback;
26static jmethodID method_deviceFoundCallback;
27static jmethodID method_pinRequestCallback;
28static jmethodID method_sspRequestCallback;
29static jmethodID method_bondStateChangeCallback;
30static jmethodID method_discoveryStateChangeCallback;
31
32static const bt_interface_t *sBluetoothInterface = NULL;
33static JNIEnv *callbackEnv = NULL;
34
35static jobject sJniCallbacksObj;
36static jfieldID sJniCallbacksField;
37
38const bt_interface_t* getBluetoothInterface() {
39    return sBluetoothInterface;
40}
41
42JNIEnv* getCallbackEnv() {
43   return callbackEnv;
44}
45
46void checkAndClearExceptionFromCallback(JNIEnv* env,
47                                               const char* methodName) {
48    if (env->ExceptionCheck()) {
49        LOGE("An exception was thrown by callback '%s'.", methodName);
50        LOGE_EX(env);
51        env->ExceptionClear();
52    }
53}
54
55static bool checkCallbackThread() {
56    JNIEnv* env = AndroidRuntime::getJNIEnv();
57    if (callbackEnv != env || callbackEnv == NULL) return false;
58    return true;
59}
60
61static void adapter_state_change_callback(bt_state_t status) {
62    if (!checkCallbackThread()) {
63       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
64       return;
65    }
66    LOGV("%s: Status is: %d", __FUNCTION__, status);
67
68    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status);
69
70    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
71}
72
73static int get_properties(int num_properties, bt_property_t *properties, jintArray *types,
74                        jobjectArray *props) {
75    jbyteArray propVal, val;
76    val = (jbyteArray) callbackEnv->NewByteArray(num_properties);
77    if (val == NULL) goto Fail;
78
79    //TODO(BT) Is this the best way to do it ?
80    *props = callbackEnv->NewObjectArray(num_properties, callbackEnv->GetObjectClass(val),
81                                             NULL);
82    if (*props == NULL) goto Fail;
83
84    *types = callbackEnv->NewIntArray(num_properties);
85    if (*types == NULL) goto Fail;
86
87    for (int i = 0; i < num_properties; i++) {
88       propVal = callbackEnv->NewByteArray(properties[i].len);
89       if (propVal == NULL) goto Fail;
90
91       callbackEnv->SetByteArrayRegion(propVal, 0, properties[i].len,
92                                            (jbyte*)properties[i].val);
93       callbackEnv->SetObjectArrayElement(*props, i, propVal);
94
95       callbackEnv->SetIntArrayRegion(*types, i, 1, (jint *)&properties[i].type);
96    }
97    return 0;
98Fail:
99    if (val) callbackEnv->DeleteLocalRef(val);
100    if (propVal) callbackEnv->DeleteLocalRef(propVal);
101    LOGE("Error while allocation of array in %s", __FUNCTION__);
102    return -1;
103}
104
105static void adapter_properties_callback(bt_status_t status, int num_properties,
106                                        bt_property_t *properties) {
107    jobjectArray props;
108    jintArray types;
109    if (!checkCallbackThread()) {
110       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
111       return;
112    }
113
114    LOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties);
115
116    if (status != BT_STATUS_SUCCESS) {
117        LOGE("%s: Status %d is incorrect", __FUNCTION__, status);
118        return;
119    }
120
121    if (get_properties(num_properties, properties, &types, &props) < 0) {
122        if (props) callbackEnv->DeleteLocalRef(props);
123        if (types) callbackEnv->DeleteLocalRef(types);
124        return;
125    }
126
127    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_adapterPropertyChangedCallback, types,
128                                props);
129    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
130    callbackEnv->DeleteLocalRef(props);
131    callbackEnv->DeleteLocalRef(types);
132    return;
133
134}
135
136static void remote_device_properties_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
137                                              int num_properties, bt_property_t *properties) {
138    if (!checkCallbackThread()) {
139       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
140       return;
141    }
142
143    LOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties);
144
145    if (status != BT_STATUS_SUCCESS) {
146        LOGE("%s: Status %d is incorrect", __FUNCTION__, status);
147        return;
148    }
149
150    callbackEnv->PushLocalFrame(ADDITIONAL_NREFS);
151
152    jobjectArray props;
153    jbyteArray addr;
154    jintArray types;
155
156    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
157    if (addr == NULL) goto Fail;
158    if (addr) callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
159
160    if (get_properties(num_properties, properties, &types, &props) < 0) {
161        if (props) callbackEnv->DeleteLocalRef(props);
162        if (types) callbackEnv->DeleteLocalRef(types);
163        callbackEnv->PopLocalFrame(NULL);
164        return;
165    }
166
167    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_devicePropertyChangedCallback, addr,
168                                types, props);
169    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
170    callbackEnv->DeleteLocalRef(props);
171    callbackEnv->DeleteLocalRef(types);
172    callbackEnv->PopLocalFrame(NULL);
173    return;
174
175Fail:
176    LOGE("Error while allocation byte array in %s", __FUNCTION__);
177}
178
179
180static void device_found_callback(int num_properties, bt_property_t *properties) {
181    jbyteArray addr = NULL;
182    int addr_index;
183
184    for (int i = 0; i < num_properties; i++) {
185        if (properties[i].type == BT_PROPERTY_BDADDR) {
186            addr = callbackEnv->NewByteArray(properties[i].len);
187            if (addr) {
188                callbackEnv->SetByteArrayRegion(addr, 0, properties[i].len,
189                                                (jbyte*)properties[i].val);
190                addr_index = i;
191            } else {
192                LOGE("Address is NULL (unable to allocate) in %s", __FUNCTION__);
193                return;
194            }
195        }
196    }
197    if (addr == NULL) {
198        LOGE("Address is NULL in %s", __FUNCTION__);
199        return;
200    }
201
202    LOGV("%s: Properties: %d, Address: %s", __FUNCTION__, num_properties,
203        (const char *)properties[addr_index].val);
204
205    remote_device_properties_callback(BT_STATUS_SUCCESS, (bt_bdaddr_t *)properties[addr_index].val,
206                                      num_properties, properties);
207
208    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback, addr);
209    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
210    callbackEnv->DeleteLocalRef(addr);
211}
212
213static void bond_state_changed_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
214                                        bt_bond_state_t state) {
215    jbyteArray addr;
216    int i;
217    if (!checkCallbackThread()) {
218       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
219       return;
220    }
221    if (!bd_addr) {
222        LOGE("Address is null in %s", __FUNCTION__);
223        return;
224    }
225    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
226    if (addr == NULL) {
227       LOGE("Address allocation failed in %s", __FUNCTION__);
228       return;
229    }
230    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
231
232    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback, (jint) status,
233                                addr, (jint)state);
234    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
235    callbackEnv->DeleteLocalRef(addr);
236}
237
238static void discovery_state_changed_callback(bt_discovery_state_t state) {
239    jbyteArray addr;
240    if (!checkCallbackThread()) {
241       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
242       return;
243    }
244
245    LOGV("%s: DiscoveryState:%d ", __FUNCTION__, state);
246
247    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_discoveryStateChangeCallback,
248                                (jint)state);
249
250    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
251}
252
253static void pin_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod) {
254    jbyteArray addr, devname;
255    if (!checkCallbackThread()) {
256       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
257       return;
258    }
259    if (!bd_addr) {
260        LOGE("Address is null in %s", __FUNCTION__);
261        return;
262    }
263
264    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
265    if (addr == NULL) goto Fail;
266    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
267
268    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
269    if (devname == NULL) goto Fail;
270
271    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
272
273    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_pinRequestCallback, addr, devname, cod);
274
275    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
276    callbackEnv->DeleteLocalRef(addr);
277    callbackEnv->DeleteLocalRef(devname);
278    return;
279
280Fail:
281    if (addr) callbackEnv->DeleteLocalRef(addr);
282    if (devname) callbackEnv->DeleteLocalRef(devname);
283    LOGE("Error while allocating in: %s", __FUNCTION__);
284}
285
286static void ssp_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod,
287                                 bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
288    jbyteArray addr, devname;
289    if (!checkCallbackThread()) {
290       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
291       return;
292    }
293    if (!bd_addr) {
294        LOGE("Address is null in %s", __FUNCTION__);
295        return;
296    }
297
298    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
299    if (addr == NULL) goto Fail;
300    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
301
302    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
303    if (devname == NULL) goto Fail;
304    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
305
306    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_sspRequestCallback, addr, devname, cod,
307                                (jint) pairing_variant, pass_key);
308
309    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
310    callbackEnv->DeleteLocalRef(addr);
311    callbackEnv->DeleteLocalRef(devname);
312    return;
313
314Fail:
315    if (addr) callbackEnv->DeleteLocalRef(addr);
316    if (devname) callbackEnv->DeleteLocalRef(devname);
317
318    LOGE("Error while allocating in: %s", __FUNCTION__);
319}
320
321static void callback_thread_event(bt_cb_thread_evt event) {
322    JavaVM* vm = AndroidRuntime::getJavaVM();
323    if (event  == ASSOCIATE_JVM) {
324        JavaVMAttachArgs args;
325        char name[] = "BT Service Callback Thread";
326        //TODO(BT)
327        //args.version = nat->envVer;
328        args.name = name;
329        args.group = NULL;
330        vm->AttachCurrentThread(&callbackEnv, &args);
331        LOGV("Callback thread attached: %p", callbackEnv);
332    } else if (event == DISASSOCIATE_JVM) {
333        if (!checkCallbackThread()) {
334            LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
335            return;
336        }
337        vm->DetachCurrentThread();
338    }
339}
340
341bt_callbacks_t sBluetoothCallbacks = {
342    sizeof(sBluetoothCallbacks),
343    adapter_state_change_callback,
344    adapter_properties_callback,
345    remote_device_properties_callback,
346    device_found_callback,
347    discovery_state_changed_callback,
348    pin_request_callback,
349    ssp_request_callback,
350    bond_state_changed_callback,
351    callback_thread_event,
352};
353
354static void classInitNative(JNIEnv* env, jclass clazz) {
355    int err;
356    hw_module_t* module;
357
358    jclass jniCallbackClass =
359        env->FindClass("com/android/bluetooth/btservice/JniCallbacks");
360    sJniCallbacksField = env->GetFieldID(clazz, "mJniCallbacks",
361        "Lcom/android/bluetooth/btservice/JniCallbacks;");
362
363    method_stateChangeCallback = env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V");
364
365    method_adapterPropertyChangedCallback = env->GetMethodID(jniCallbackClass,
366                                                             "adapterPropertyChangedCallback",
367                                                             "([I[[B)V");
368    method_discoveryStateChangeCallback = env->GetMethodID(jniCallbackClass,
369                                                           "discoveryStateChangeCallback", "(I)V");
370
371    method_devicePropertyChangedCallback = env->GetMethodID(jniCallbackClass,
372                                                            "devicePropertyChangedCallback",
373                                                            "([B[I[[B)V");
374    method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
375    method_pinRequestCallback = env->GetMethodID(jniCallbackClass, "pinRequestCallback",
376                                                 "([B[BI)V");
377    method_sspRequestCallback = env->GetMethodID(jniCallbackClass, "sspRequestCallback",
378                                                 "([B[BIII)V");
379
380    method_bondStateChangeCallback = env->GetMethodID(jniCallbackClass,
381                                                     "bondStateChangeCallback", "(I[BI)V");
382
383    char value[PROPERTY_VALUE_MAX];
384    property_get("bluetooth.mock_stack", value, "");
385
386    const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID);
387
388    err = hw_get_module(id, (hw_module_t const**)&module);
389
390    if (err == 0) {
391        hw_device_t* abstraction;
392        err = module->methods->open(module, id, &abstraction);
393        if (err == 0) {
394            bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction;
395            sBluetoothInterface = btStack->get_bluetooth_interface();
396        } else {
397           LOGE("Error while opening Bluetooth library");
398        }
399    } else {
400        LOGE("No Bluetooth Library found");
401    }
402}
403
404static bool initNative(JNIEnv* env, jobject obj) {
405    LOGV("%s:",__FUNCTION__);
406
407    sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));
408
409    if (sBluetoothInterface) {
410        int ret = sBluetoothInterface->init(&sBluetoothCallbacks);
411        if (ret != BT_STATUS_SUCCESS) {
412            LOGE("Error while setting the callbacks \n");
413            sBluetoothInterface = NULL;
414            return JNI_FALSE;
415        }
416        return JNI_TRUE;
417    }
418    return JNI_FALSE;
419}
420
421static bool cleanupNative(JNIEnv *env, jobject obj) {
422    LOGV("%s:",__FUNCTION__);
423
424    jboolean result = JNI_FALSE;
425    if (!sBluetoothInterface) return result;
426
427    sBluetoothInterface->cleanup();
428    env->DeleteGlobalRef(sJniCallbacksObj);
429    return JNI_TRUE;
430}
431
432static jboolean enableNative(JNIEnv* env, jobject obj) {
433    LOGV("%s:",__FUNCTION__);
434
435    jboolean result = JNI_FALSE;
436    if (!sBluetoothInterface) return result;
437
438    int ret = sBluetoothInterface->enable();
439    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
440    return result;
441}
442
443static jboolean disableNative(JNIEnv* env, jobject obj) {
444    LOGV("%s:",__FUNCTION__);
445
446    jboolean result = JNI_FALSE;
447    if (!sBluetoothInterface) return result;
448
449    int ret = sBluetoothInterface->disable();
450    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
451    return result;
452}
453
454static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
455    LOGV("%s:",__FUNCTION__);
456
457    jboolean result = JNI_FALSE;
458    if (!sBluetoothInterface) return result;
459
460    int ret = sBluetoothInterface->start_discovery();
461    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
462    return result;
463}
464
465static jboolean cancelDiscoveryNative(JNIEnv* env, jobject obj) {
466    LOGV("%s:",__FUNCTION__);
467
468    jboolean result = JNI_FALSE;
469    if (!sBluetoothInterface) return result;
470
471    int ret = sBluetoothInterface->cancel_discovery();
472    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
473    return result;
474}
475
476static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
477    LOGV("%s:",__FUNCTION__);
478
479    jbyte *addr;
480    jboolean result = JNI_FALSE;
481
482    if (!sBluetoothInterface) return result;
483
484    addr = env->GetByteArrayElements(address, NULL);
485    if (addr == NULL) {
486        jniThrowIOException(env, EINVAL);
487        return result;
488    }
489
490    int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr);
491    env->ReleaseByteArrayElements(address, addr, NULL);
492    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
493
494    return result;
495}
496
497static jboolean removeBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
498    LOGV("%s:",__FUNCTION__);
499
500    jbyte *addr;
501    jboolean result;
502    if (!sBluetoothInterface) return JNI_FALSE;
503
504    addr = env->GetByteArrayElements(address, NULL);
505    if (addr == NULL) {
506        jniThrowIOException(env, EINVAL);
507        return JNI_FALSE;
508    }
509
510    int ret = sBluetoothInterface->remove_bond((bt_bdaddr_t *)addr);
511    env->ReleaseByteArrayElements(address, addr, NULL);
512    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
513
514    return result;
515}
516
517static jboolean cancelBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
518    LOGV("%s:",__FUNCTION__);
519
520    jbyte *addr;
521    jboolean result;
522    if (!sBluetoothInterface) return JNI_FALSE;
523
524    addr = env->GetByteArrayElements(address, NULL);
525    if (addr == NULL) {
526        jniThrowIOException(env, EINVAL);
527        return JNI_FALSE;
528    }
529
530    int ret = sBluetoothInterface->cancel_bond((bt_bdaddr_t *)addr);
531    env->ReleaseByteArrayElements(address, addr, NULL);
532    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
533
534    return result;
535}
536
537static jboolean pinReplyNative(JNIEnv *env, jobject obj, jbyteArray address, jboolean accept,
538                               jint len, jbyteArray pinArray) {
539    LOGV("%s:",__FUNCTION__);
540
541    jbyte *addr, *pinPtr = NULL;
542    jboolean result = JNI_FALSE;
543    if (!sBluetoothInterface) return result;
544
545    addr = env->GetByteArrayElements(address, NULL);
546    if (addr == NULL) {
547        jniThrowIOException(env, EINVAL);
548        return result;
549    }
550
551    if (accept) {
552        pinPtr = env->GetByteArrayElements(pinArray, NULL);
553        if (pinPtr == NULL) {
554           jniThrowIOException(env, EINVAL);
555           env->ReleaseByteArrayElements(address, addr, NULL);
556           return result;
557        }
558    }
559
560    int ret = sBluetoothInterface->pin_reply((bt_bdaddr_t*)addr, accept, len,
561                                              (bt_pin_code_t *) pinPtr);
562    env->ReleaseByteArrayElements(address, addr, NULL);
563    env->ReleaseByteArrayElements(pinArray, pinPtr, NULL);
564    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
565
566    return result;
567}
568
569static jboolean sspReplyNative(JNIEnv *env, jobject obj, jbyteArray address,
570                               jint type, jboolean accept, jint passkey) {
571    LOGV("%s:",__FUNCTION__);
572
573    jbyte *addr;
574    jboolean result = JNI_FALSE;
575    if (!sBluetoothInterface) return result;
576
577    addr = env->GetByteArrayElements(address, NULL);
578    if (addr == NULL) {
579        jniThrowIOException(env, EINVAL);
580        return result;
581    }
582
583    int ret = sBluetoothInterface->ssp_reply((bt_bdaddr_t *)addr,
584         (bt_ssp_variant_t) type, accept, passkey);
585    env->ReleaseByteArrayElements(address, addr, NULL);
586    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
587
588    return result;
589}
590
591static jboolean setAdapterPropertyNative(JNIEnv *env, jobject obj, jint type, jbyteArray value) {
592    LOGV("%s:",__FUNCTION__);
593
594    jbyte *val;
595    jboolean result = JNI_FALSE;
596    if (!sBluetoothInterface) return result;
597
598    val = env->GetByteArrayElements(value, NULL);
599    bt_property_t prop;
600    prop.type = (bt_property_type_t) type;
601    prop.len = env->GetArrayLength(value);
602    prop.val = val;
603
604    int ret = sBluetoothInterface->set_adapter_property(&prop);
605    env->ReleaseByteArrayElements(value, val, NULL);
606    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
607
608    return result;
609}
610
611static jboolean getAdapterPropertiesNative(JNIEnv *env, jobject obj) {
612    LOGV("%s:",__FUNCTION__);
613
614    jboolean result = JNI_FALSE;
615    if (!sBluetoothInterface) return result;
616
617    int ret = sBluetoothInterface->get_adapter_properties();
618    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
619
620    return result;
621}
622
623static jboolean getAdapterPropertyNative(JNIEnv *env, jobject obj, jint type) {
624    LOGV("%s:",__FUNCTION__);
625
626    jboolean result = JNI_FALSE;
627    if (!sBluetoothInterface) return result;
628
629    int ret = sBluetoothInterface->get_adapter_property((bt_property_type_t) type);
630    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
631
632    return result;
633}
634
635static jboolean getDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address, jint type) {
636    LOGV("%s:",__FUNCTION__);
637
638    jbyte *addr = NULL;
639    jboolean result = JNI_FALSE;
640    if (!sBluetoothInterface) return result;
641
642    addr = env->GetByteArrayElements(address, NULL);
643    if (addr == NULL) {
644        jniThrowIOException(env, EINVAL);
645        return result;
646    }
647
648    int ret = sBluetoothInterface->get_remote_device_property((bt_bdaddr_t *)addr,
649                                                              (bt_property_type_t) type);
650    env->ReleaseByteArrayElements(address, addr, NULL);
651    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
652
653    return result;
654}
655
656static jboolean setDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address,
657                                        jint type, jbyteArray value) {
658    LOGV("%s:",__FUNCTION__);
659
660    jbyte *val, *addr;
661    jboolean result = JNI_FALSE;
662    if (!sBluetoothInterface) return result;
663
664    val = env->GetByteArrayElements(value, NULL);
665    if (val == NULL) {
666        jniThrowIOException(env, EINVAL);
667        return result;
668    }
669
670    addr = env->GetByteArrayElements(address, NULL);
671    if (addr == NULL) {
672        env->ReleaseByteArrayElements(value, val, NULL);
673        jniThrowIOException(env, EINVAL);
674        return result;
675    }
676
677
678    bt_property_t prop;
679    prop.type = (bt_property_type_t) type;
680    prop.len = env->GetArrayLength(value);
681    prop.val = val;
682
683    int ret = sBluetoothInterface->set_remote_device_property((bt_bdaddr_t *)addr, &prop);
684    env->ReleaseByteArrayElements(value, val, NULL);
685    env->ReleaseByteArrayElements(address, addr, NULL);
686
687    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
688
689    return result;
690}
691
692static JNINativeMethod sMethods[] = {
693     /* name, signature, funcPtr */
694    {"classInitNative", "()V", (void *) classInitNative},
695    {"initNative", "()Z", (void *) initNative},
696    {"cleanupNative", "()V", (void*) cleanupNative},
697    {"enableNative", "()Z",  (void*) enableNative},
698    {"disableNative", "()Z",  (void*) disableNative},
699    {"setAdapterPropertyNative", "(I[B)Z", (void*) setAdapterPropertyNative},
700    {"getAdapterPropertiesNative", "()Z", (void*) getAdapterPropertiesNative},
701    {"getAdapterPropertyNative", "(I)Z", (void*) getAdapterPropertyNative},
702    {"getDevicePropertyNative", "([BI)Z", (void*) getDevicePropertyNative},
703    {"setDevicePropertyNative", "([BI[B)Z", (void*) setDevicePropertyNative},
704    {"startDiscoveryNative", "()Z", (void*) startDiscoveryNative},
705    {"cancelDiscoveryNative", "()Z", (void*) cancelDiscoveryNative},
706    {"createBondNative", "([B)Z", (void*) createBondNative},
707    {"removeBondNative", "([B)Z", (void*) removeBondNative},
708    {"cancelBondNative", "([B)Z", (void*) cancelBondNative},
709    {"pinReplyNative", "([BZI[B)Z", (void*) pinReplyNative},
710    {"sspReplyNative", "([BIZI)Z", (void*) sspReplyNative},
711};
712
713int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env)
714{
715    return jniRegisterNativeMethods(env, "com/android/bluetooth/btservice/AdapterService",
716                                    sMethods, NELEM(sMethods));
717}
718
719} /* namespace android */
720
721
722/*
723 * JNI Initialization
724 */
725jint JNI_OnLoad(JavaVM *jvm, void *reserved)
726{
727   JNIEnv *e;
728   int status;
729
730   LOGV("Bluetooth Adapter Service : loading JNI\n");
731
732   // Check JNI version
733   if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) {
734       LOGE("JNI version mismatch error");
735      return JNI_ERR;
736   }
737
738   if ((status = android::register_com_android_bluetooth_btservice_AdapterService(e)) < 0) {
739       LOGE("jni adapter service registration failure, status: %d", status);
740      return JNI_ERR;
741   }
742
743   if ((status = android::register_com_android_bluetooth_hfp(e)) < 0) {
744       LOGE("jni hfp registration failure, status: %d", status);
745      return JNI_ERR;
746   }
747
748   if ((status = android::register_com_android_bluetooth_a2dp(e)) < 0) {
749       LOGE("jni a2dp registration failure: %d", status);
750      return JNI_ERR;
751   }
752
753   return JNI_VERSION_1_6;
754}
755