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