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