com_android_bluetooth_btservice_AdapterService.cpp revision 5a60e47497f21f64e6d79420dc4c56c1907df22a
1/*
2 * Copyright (C) 2012 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 LOG_TAG "BluetoothServiceJni"
18#include "com_android_bluetooth.h"
19#include "hardware/bt_sock.h"
20#include "utils/Log.h"
21#include "utils/misc.h"
22#include "cutils/properties.h"
23#include "android_runtime/AndroidRuntime.h"
24#include "android_runtime/Log.h"
25
26#include <string.h>
27#include <pthread.h>
28
29#include <sys/stat.h>
30#include <fcntl.h>
31
32namespace android {
33
34#define ADDITIONAL_NREFS 50
35static jmethodID method_stateChangeCallback;
36static jmethodID method_adapterPropertyChangedCallback;
37static jmethodID method_devicePropertyChangedCallback;
38static jmethodID method_deviceFoundCallback;
39static jmethodID method_pinRequestCallback;
40static jmethodID method_sspRequestCallback;
41static jmethodID method_bondStateChangeCallback;
42static jmethodID method_aclStateChangeCallback;
43static jmethodID method_discoveryStateChangeCallback;
44static jmethodID method_setWakeAlarm;
45static jmethodID method_acquireWakeLock;
46static jmethodID method_releaseWakeLock;
47static jmethodID method_energyInfo;
48
49static const bt_interface_t *sBluetoothInterface = NULL;
50static const btsock_interface_t *sBluetoothSocketInterface = NULL;
51static JNIEnv *callbackEnv = NULL;
52
53static jobject sJniAdapterServiceObj;
54static jobject sJniCallbacksObj;
55static jfieldID sJniCallbacksField;
56
57
58const bt_interface_t* getBluetoothInterface() {
59    return sBluetoothInterface;
60}
61
62JNIEnv* getCallbackEnv() {
63    return callbackEnv;
64}
65
66void checkAndClearExceptionFromCallback(JNIEnv* env,
67                                               const char* methodName) {
68    if (env->ExceptionCheck()) {
69        ALOGE("An exception was thrown by callback '%s'.", methodName);
70        LOGE_EX(env);
71        env->ExceptionClear();
72    }
73}
74
75static bool checkCallbackThread() {
76    JNIEnv* env = AndroidRuntime::getJNIEnv();
77    if (callbackEnv != env || callbackEnv == NULL) {
78        ALOGE("Callback env check fail: env: %p, callback: %p", env, callbackEnv);
79        return false;
80    }
81    return true;
82}
83
84static void adapter_state_change_callback(bt_state_t status) {
85    if (!checkCallbackThread()) {
86       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
87       return;
88    }
89    ALOGV("%s: Status is: %d", __FUNCTION__, status);
90
91    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status);
92
93    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
94}
95
96static int get_properties(int num_properties, bt_property_t *properties, jintArray *types,
97                        jobjectArray *props) {
98    jbyteArray propVal;
99    for (int i = 0; i < num_properties; i++) {
100        propVal = callbackEnv->NewByteArray(properties[i].len);
101        if (propVal == NULL) goto Fail;
102
103        callbackEnv->SetByteArrayRegion(propVal, 0, properties[i].len,
104                                             (jbyte*)properties[i].val);
105        callbackEnv->SetObjectArrayElement(*props, i, propVal);
106        // Delete reference to propVal
107        callbackEnv->DeleteLocalRef(propVal);
108        callbackEnv->SetIntArrayRegion(*types, i, 1, (jint *)&properties[i].type);
109    }
110    return 0;
111Fail:
112    if (propVal) callbackEnv->DeleteLocalRef(propVal);
113    ALOGE("Error while allocation of array in %s", __FUNCTION__);
114    return -1;
115}
116
117static void adapter_properties_callback(bt_status_t status, int num_properties,
118                                        bt_property_t *properties) {
119    jobjectArray props;
120    jintArray types;
121    jbyteArray val;
122    jclass mclass;
123
124    if (!checkCallbackThread()) {
125       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
126       return;
127    }
128
129    ALOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties);
130
131    if (status != BT_STATUS_SUCCESS) {
132        ALOGE("%s: Status %d is incorrect", __FUNCTION__, status);
133        return;
134    }
135
136    val = (jbyteArray) callbackEnv->NewByteArray(num_properties);
137    if (val == NULL) {
138        ALOGE("%s: Error allocating byteArray", __FUNCTION__);
139        return;
140    }
141
142    mclass = callbackEnv->GetObjectClass(val);
143
144    /* (BT) Initialize the jobjectArray and jintArray here itself and send the
145     initialized array pointers alone to get_properties */
146
147    props = callbackEnv->NewObjectArray(num_properties, mclass,
148                                             NULL);
149    if (props == NULL) {
150        ALOGE("%s: Error allocating object Array for properties", __FUNCTION__);
151        return;
152    }
153
154    types = (jintArray)callbackEnv->NewIntArray(num_properties);
155
156    if (types == NULL) {
157        ALOGE("%s: Error allocating int Array for values", __FUNCTION__);
158        return;
159    }
160    // Delete the reference to val and mclass
161    callbackEnv->DeleteLocalRef(mclass);
162    callbackEnv->DeleteLocalRef(val);
163
164    if (get_properties(num_properties, properties, &types, &props) < 0) {
165        if (props) callbackEnv->DeleteLocalRef(props);
166        if (types) callbackEnv->DeleteLocalRef(types);
167        return;
168    }
169
170    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_adapterPropertyChangedCallback, types,
171                                props);
172    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
173    callbackEnv->DeleteLocalRef(props);
174    callbackEnv->DeleteLocalRef(types);
175    return;
176
177}
178
179static void remote_device_properties_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
180                                              int num_properties, bt_property_t *properties) {
181    if (!checkCallbackThread()) {
182       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
183       return;
184    }
185
186    ALOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties);
187
188    if (status != BT_STATUS_SUCCESS) {
189        ALOGE("%s: Status %d is incorrect", __FUNCTION__, status);
190        return;
191    }
192
193    callbackEnv->PushLocalFrame(ADDITIONAL_NREFS);
194
195    jobjectArray props;
196    jbyteArray addr;
197    jintArray types;
198    jbyteArray val;
199    jclass mclass;
200
201    val = (jbyteArray) callbackEnv->NewByteArray(num_properties);
202    if (val == NULL) {
203        ALOGE("%s: Error allocating byteArray", __FUNCTION__);
204        return;
205    }
206
207    mclass = callbackEnv->GetObjectClass(val);
208
209    /* Initialize the jobjectArray and jintArray here itself and send the
210     initialized array pointers alone to get_properties */
211
212    props = callbackEnv->NewObjectArray(num_properties, mclass,
213                                             NULL);
214    if (props == NULL) {
215        ALOGE("%s: Error allocating object Array for properties", __FUNCTION__);
216        return;
217    }
218
219    types = (jintArray)callbackEnv->NewIntArray(num_properties);
220
221    if (types == NULL) {
222        ALOGE("%s: Error allocating int Array for values", __FUNCTION__);
223        return;
224    }
225    // Delete the reference to val and mclass
226    callbackEnv->DeleteLocalRef(mclass);
227    callbackEnv->DeleteLocalRef(val);
228
229    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
230    if (addr == NULL) goto Fail;
231    if (addr) callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
232
233    if (get_properties(num_properties, properties, &types, &props) < 0) {
234        if (props) callbackEnv->DeleteLocalRef(props);
235        if (types) callbackEnv->DeleteLocalRef(types);
236        callbackEnv->PopLocalFrame(NULL);
237        return;
238    }
239
240    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_devicePropertyChangedCallback, addr,
241                                types, props);
242    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
243    callbackEnv->DeleteLocalRef(props);
244    callbackEnv->DeleteLocalRef(types);
245    callbackEnv->DeleteLocalRef(addr);
246    callbackEnv->PopLocalFrame(NULL);
247    return;
248
249Fail:
250    ALOGE("Error while allocation byte array in %s", __FUNCTION__);
251}
252
253
254static void device_found_callback(int num_properties, bt_property_t *properties) {
255    jbyteArray addr = NULL;
256    int addr_index;
257
258    for (int i = 0; i < num_properties; i++) {
259        if (properties[i].type == BT_PROPERTY_BDADDR) {
260            addr = callbackEnv->NewByteArray(properties[i].len);
261            if (addr) {
262                callbackEnv->SetByteArrayRegion(addr, 0, properties[i].len,
263                                                (jbyte*)properties[i].val);
264                addr_index = i;
265            } else {
266                ALOGE("Address is NULL (unable to allocate) in %s", __FUNCTION__);
267                return;
268            }
269        }
270    }
271    if (addr == NULL) {
272        ALOGE("Address is NULL in %s", __FUNCTION__);
273        return;
274    }
275
276    ALOGV("%s: Properties: %d, Address: %s", __FUNCTION__, num_properties,
277        (const char *)properties[addr_index].val);
278
279    remote_device_properties_callback(BT_STATUS_SUCCESS, (bt_bdaddr_t *)properties[addr_index].val,
280                                      num_properties, properties);
281
282    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback, addr);
283    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
284    callbackEnv->DeleteLocalRef(addr);
285}
286
287static void bond_state_changed_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
288                                        bt_bond_state_t state) {
289    jbyteArray addr;
290    int i;
291    if (!checkCallbackThread()) {
292       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
293       return;
294    }
295    if (!bd_addr) {
296        ALOGE("Address is null in %s", __FUNCTION__);
297        return;
298    }
299    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
300    if (addr == NULL) {
301       ALOGE("Address allocation failed in %s", __FUNCTION__);
302       return;
303    }
304    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
305
306    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback, (jint) status,
307                                addr, (jint)state);
308    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
309    callbackEnv->DeleteLocalRef(addr);
310}
311
312static void acl_state_changed_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
313                                       bt_acl_state_t state)
314{
315    jbyteArray addr;
316    int i;
317    if (!checkCallbackThread()) {
318       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
319       return;
320    }
321    if (!bd_addr) {
322        ALOGE("Address is null in %s", __FUNCTION__);
323        return;
324    }
325    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
326    if (addr == NULL) {
327       ALOGE("Address allocation failed in %s", __FUNCTION__);
328       return;
329    }
330    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
331
332    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_aclStateChangeCallback, (jint) status,
333                                addr, (jint)state);
334    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
335    callbackEnv->DeleteLocalRef(addr);
336}
337
338static void discovery_state_changed_callback(bt_discovery_state_t state) {
339    jbyteArray addr;
340    if (!checkCallbackThread()) {
341       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
342       return;
343    }
344
345    ALOGV("%s: DiscoveryState:%d ", __FUNCTION__, state);
346
347    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_discoveryStateChangeCallback,
348                                (jint)state);
349
350    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
351}
352
353static void pin_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod) {
354    jbyteArray addr, devname;
355    if (!checkCallbackThread()) {
356       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
357       return;
358    }
359    if (!bd_addr) {
360        ALOGE("Address is null in %s", __FUNCTION__);
361        return;
362    }
363
364    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
365    if (addr == NULL) goto Fail;
366    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
367
368    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
369    if (devname == NULL) goto Fail;
370
371    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
372
373    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_pinRequestCallback, addr, devname, cod);
374
375    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
376    callbackEnv->DeleteLocalRef(addr);
377    callbackEnv->DeleteLocalRef(devname);
378    return;
379
380Fail:
381    if (addr) callbackEnv->DeleteLocalRef(addr);
382    if (devname) callbackEnv->DeleteLocalRef(devname);
383    ALOGE("Error while allocating in: %s", __FUNCTION__);
384}
385
386static void ssp_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod,
387                                 bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
388    jbyteArray addr, devname;
389    if (!checkCallbackThread()) {
390       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
391       return;
392    }
393    if (!bd_addr) {
394        ALOGE("Address is null in %s", __FUNCTION__);
395        return;
396    }
397
398    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
399    if (addr == NULL) goto Fail;
400    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
401
402    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
403    if (devname == NULL) goto Fail;
404    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
405
406    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_sspRequestCallback, addr, devname, cod,
407                                (jint) pairing_variant, pass_key);
408
409    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
410    callbackEnv->DeleteLocalRef(addr);
411    callbackEnv->DeleteLocalRef(devname);
412    return;
413
414Fail:
415    if (addr) callbackEnv->DeleteLocalRef(addr);
416    if (devname) callbackEnv->DeleteLocalRef(devname);
417
418    ALOGE("Error while allocating in: %s", __FUNCTION__);
419}
420
421static void callback_thread_event(bt_cb_thread_evt event) {
422    JavaVM* vm = AndroidRuntime::getJavaVM();
423    if (event  == ASSOCIATE_JVM) {
424        JavaVMAttachArgs args;
425        char name[] = "BT Service Callback Thread";
426        args.version = JNI_VERSION_1_6;
427        args.name = name;
428        args.group = NULL;
429        vm->AttachCurrentThread(&callbackEnv, &args);
430        ALOGV("Callback thread attached: %p", callbackEnv);
431    } else if (event == DISASSOCIATE_JVM) {
432        if (!checkCallbackThread()) {
433            ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
434            return;
435        }
436        vm->DetachCurrentThread();
437    }
438}
439
440static void dut_mode_recv_callback (uint16_t opcode, uint8_t *buf, uint8_t len) {
441
442}
443static void le_test_mode_recv_callback (bt_status_t status, uint16_t packet_count) {
444
445    ALOGV("%s: status:%d packet_count:%d ", __FUNCTION__, status, packet_count);
446}
447
448static void energy_info_recv_callback(bt_activity_energy_info *p_energy_info)
449{
450    if (!checkCallbackThread()) {
451       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
452       return;
453    }
454
455    callbackEnv->CallVoidMethod(sJniAdapterServiceObj, method_energyInfo, p_energy_info->status,
456        p_energy_info->ctrl_state, p_energy_info->tx_time, p_energy_info->rx_time,
457        p_energy_info->idle_time, p_energy_info->energy_used);
458
459    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
460}
461
462static bt_callbacks_t sBluetoothCallbacks = {
463    sizeof(sBluetoothCallbacks),
464    adapter_state_change_callback,
465    adapter_properties_callback,
466    remote_device_properties_callback,
467    device_found_callback,
468    discovery_state_changed_callback,
469    pin_request_callback,
470    ssp_request_callback,
471    bond_state_changed_callback,
472    acl_state_changed_callback,
473    callback_thread_event,
474    dut_mode_recv_callback,
475    le_test_mode_recv_callback,
476    energy_info_recv_callback
477};
478
479// The callback to call when the wake alarm fires.
480static alarm_cb sAlarmCallback;
481
482// The data to pass to the wake alarm callback.
483static void *sAlarmCallbackData;
484
485static JavaVMAttachArgs sAttachArgs = {
486  .version = JNI_VERSION_1_6,
487  .name = "bluedroid wake/alarm thread",
488  .group = NULL
489};
490
491static bool set_wake_alarm_callout(uint64_t delay_millis, bool should_wake,
492        alarm_cb cb, void *data) {
493    JNIEnv *env;
494    JavaVM *vm = AndroidRuntime::getJavaVM();
495    jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
496
497    if (status != JNI_OK && status != JNI_EDETACHED) {
498        ALOGE("%s unable to get environment for JNI call", __func__);
499        return false;
500    }
501
502    if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
503        ALOGE("%s unable to attach thread to VM", __func__);
504        return false;
505    }
506
507    sAlarmCallback = cb;
508    sAlarmCallbackData = data;
509
510    jboolean jshould_wake = should_wake ? JNI_TRUE : JNI_FALSE;
511    jboolean ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_setWakeAlarm,
512            (jlong)delay_millis, jshould_wake);
513    if (!ret) {
514        sAlarmCallback = NULL;
515        sAlarmCallbackData = NULL;
516    }
517
518    if (status == JNI_EDETACHED) {
519        vm->DetachCurrentThread();
520    }
521
522    return !!ret;
523}
524
525static int acquire_wake_lock_callout(const char *lock_name) {
526    JNIEnv *env;
527    JavaVM *vm = AndroidRuntime::getJavaVM();
528    jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
529    if (status != JNI_OK && status != JNI_EDETACHED) {
530        ALOGE("%s unable to get environment for JNI call", __func__);
531        return BT_STATUS_FAIL;
532    }
533    if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
534        ALOGE("%s unable to attach thread to VM", __func__);
535        return BT_STATUS_FAIL;
536    }
537
538    jboolean ret = JNI_FALSE;
539    jstring lock_name_jni = env->NewStringUTF(lock_name);
540    if (lock_name_jni) {
541        ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_acquireWakeLock, lock_name_jni);
542        env->DeleteLocalRef(lock_name_jni);
543    } else {
544        ALOGE("%s unable to allocate string: %s", __func__, lock_name);
545    }
546
547    if (status == JNI_EDETACHED) {
548        vm->DetachCurrentThread();
549    }
550
551    return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
552}
553
554static int release_wake_lock_callout(const char *lock_name) {
555    JNIEnv *env;
556    JavaVM *vm = AndroidRuntime::getJavaVM();
557    jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
558
559    if (status != JNI_OK && status != JNI_EDETACHED) {
560        ALOGE("%s unable to get environment for JNI call", __func__);
561        return BT_STATUS_FAIL;
562    }
563    if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
564        ALOGE("%s unable to attach thread to VM", __func__);
565        return BT_STATUS_FAIL;
566    }
567    jboolean ret = JNI_FALSE;
568    jstring lock_name_jni = env->NewStringUTF(lock_name);
569    if (lock_name_jni) {
570        ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_releaseWakeLock, lock_name_jni);
571        env->DeleteLocalRef(lock_name_jni);
572    } else {
573        ALOGE("%s unable to allocate string: %s", __func__, lock_name);
574    }
575    if (status == JNI_EDETACHED) {
576        vm->DetachCurrentThread();
577    }
578    return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
579}
580
581// Called by Java code when alarm is fired. A wake lock is held by the caller
582// over the duration of this callback.
583static void alarmFiredNative(JNIEnv *env, jobject obj) {
584    if (sAlarmCallback) {
585        sAlarmCallback(sAlarmCallbackData);
586    } else {
587        ALOGE("%s() - Alarm fired with callback not set!", __FUNCTION__);
588    }
589}
590
591static bt_os_callouts_t sBluetoothOsCallouts = {
592    sizeof(sBluetoothOsCallouts),
593    set_wake_alarm_callout,
594    acquire_wake_lock_callout,
595    release_wake_lock_callout,
596};
597
598
599
600static void classInitNative(JNIEnv* env, jclass clazz) {
601    int err;
602    hw_module_t* module;
603
604    jclass jniCallbackClass =
605        env->FindClass("com/android/bluetooth/btservice/JniCallbacks");
606    sJniCallbacksField = env->GetFieldID(clazz, "mJniCallbacks",
607        "Lcom/android/bluetooth/btservice/JniCallbacks;");
608
609    method_stateChangeCallback = env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V");
610
611    method_adapterPropertyChangedCallback = env->GetMethodID(jniCallbackClass,
612                                                             "adapterPropertyChangedCallback",
613                                                             "([I[[B)V");
614    method_discoveryStateChangeCallback = env->GetMethodID(jniCallbackClass,
615                                                           "discoveryStateChangeCallback", "(I)V");
616
617    method_devicePropertyChangedCallback = env->GetMethodID(jniCallbackClass,
618                                                            "devicePropertyChangedCallback",
619                                                            "([B[I[[B)V");
620    method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
621    method_pinRequestCallback = env->GetMethodID(jniCallbackClass, "pinRequestCallback",
622                                                 "([B[BI)V");
623    method_sspRequestCallback = env->GetMethodID(jniCallbackClass, "sspRequestCallback",
624                                                 "([B[BIII)V");
625
626    method_bondStateChangeCallback = env->GetMethodID(jniCallbackClass,
627                                                     "bondStateChangeCallback", "(I[BI)V");
628
629    method_aclStateChangeCallback = env->GetMethodID(jniCallbackClass,
630                                                    "aclStateChangeCallback", "(I[BI)V");
631
632    method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z");
633    method_acquireWakeLock = env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z");
634    method_releaseWakeLock = env->GetMethodID(clazz, "releaseWakeLock", "(Ljava/lang/String;)Z");
635    method_energyInfo = env->GetMethodID(clazz, "energyInfoCallback", "(IIJJJJ)V");
636
637    char value[PROPERTY_VALUE_MAX];
638    property_get("bluetooth.mock_stack", value, "");
639
640    const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID);
641
642    err = hw_get_module(id, (hw_module_t const**)&module);
643
644    if (err == 0) {
645        hw_device_t* abstraction;
646        err = module->methods->open(module, id, &abstraction);
647        if (err == 0) {
648            bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction;
649            sBluetoothInterface = btStack->get_bluetooth_interface();
650        } else {
651           ALOGE("Error while opening Bluetooth library");
652        }
653    } else {
654        ALOGE("No Bluetooth Library found");
655    }
656}
657
658static bool initNative(JNIEnv* env, jobject obj) {
659    ALOGV("%s:",__FUNCTION__);
660
661    sJniAdapterServiceObj = env->NewGlobalRef(obj);
662    sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));
663
664    if (sBluetoothInterface) {
665        int ret = sBluetoothInterface->init(&sBluetoothCallbacks);
666        if (ret != BT_STATUS_SUCCESS) {
667            ALOGE("Error while setting the callbacks: %d\n", ret);
668            sBluetoothInterface = NULL;
669            return JNI_FALSE;
670        }
671        ret = sBluetoothInterface->set_os_callouts(&sBluetoothOsCallouts);
672        if (ret != BT_STATUS_SUCCESS) {
673            ALOGE("Error while setting Bluetooth callouts: %d\n", ret);
674            sBluetoothInterface->cleanup();
675            sBluetoothInterface = NULL;
676            return JNI_FALSE;
677        }
678
679        if ( (sBluetoothSocketInterface = (btsock_interface_t *)
680                  sBluetoothInterface->get_profile_interface(BT_PROFILE_SOCKETS_ID)) == NULL) {
681                ALOGE("Error getting socket interface");
682        }
683
684        return JNI_TRUE;
685    }
686    return JNI_FALSE;
687}
688
689static bool cleanupNative(JNIEnv *env, jobject obj) {
690    ALOGV("%s:",__FUNCTION__);
691
692    jboolean result = JNI_FALSE;
693    if (!sBluetoothInterface) return result;
694
695    sBluetoothInterface->cleanup();
696    ALOGI("%s: return from cleanup",__FUNCTION__);
697
698    env->DeleteGlobalRef(sJniCallbacksObj);
699    env->DeleteGlobalRef(sJniAdapterServiceObj);
700    return JNI_TRUE;
701}
702
703static jboolean enableNative(JNIEnv* env, jobject obj) {
704    ALOGV("%s:",__FUNCTION__);
705
706    jboolean result = JNI_FALSE;
707    if (!sBluetoothInterface) return result;
708
709    int ret = sBluetoothInterface->enable();
710    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
711    return result;
712}
713
714static jboolean disableNative(JNIEnv* env, jobject obj) {
715    ALOGV("%s:",__FUNCTION__);
716
717    jboolean result = JNI_FALSE;
718    if (!sBluetoothInterface) return result;
719
720    int ret = sBluetoothInterface->disable();
721    /* Retrun JNI_FALSE only when BTIF explicitly reports
722       BT_STATUS_FAIL. It is fine for the BT_STATUS_NOT_READY
723       case which indicates that stack had not been enabled.
724    */
725    result = (ret == BT_STATUS_FAIL) ? JNI_FALSE : JNI_TRUE;
726    return result;
727}
728
729static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
730    ALOGV("%s:",__FUNCTION__);
731
732    jboolean result = JNI_FALSE;
733    if (!sBluetoothInterface) return result;
734
735    int ret = sBluetoothInterface->start_discovery();
736    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
737    return result;
738}
739
740static jboolean cancelDiscoveryNative(JNIEnv* env, jobject obj) {
741    ALOGV("%s:",__FUNCTION__);
742
743    jboolean result = JNI_FALSE;
744    if (!sBluetoothInterface) return result;
745
746    int ret = sBluetoothInterface->cancel_discovery();
747    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
748    return result;
749}
750
751static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address, jint transport) {
752    ALOGV("%s:",__FUNCTION__);
753
754    jbyte *addr;
755    jboolean result = JNI_FALSE;
756
757    if (!sBluetoothInterface) return result;
758
759    addr = env->GetByteArrayElements(address, NULL);
760    if (addr == NULL) {
761        jniThrowIOException(env, EINVAL);
762        return result;
763    }
764
765    int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr, transport);
766    env->ReleaseByteArrayElements(address, addr, 0);
767    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
768
769    return result;
770}
771
772static jboolean removeBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
773    ALOGV("%s:",__FUNCTION__);
774
775    jbyte *addr;
776    jboolean result;
777    if (!sBluetoothInterface) return JNI_FALSE;
778
779    addr = env->GetByteArrayElements(address, NULL);
780    if (addr == NULL) {
781        jniThrowIOException(env, EINVAL);
782        return JNI_FALSE;
783    }
784
785    int ret = sBluetoothInterface->remove_bond((bt_bdaddr_t *)addr);
786    env->ReleaseByteArrayElements(address, addr, 0);
787    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
788
789    return result;
790}
791
792static jboolean cancelBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
793    ALOGV("%s:",__FUNCTION__);
794
795    jbyte *addr;
796    jboolean result;
797    if (!sBluetoothInterface) return JNI_FALSE;
798
799    addr = env->GetByteArrayElements(address, NULL);
800    if (addr == NULL) {
801        jniThrowIOException(env, EINVAL);
802        return JNI_FALSE;
803    }
804
805    int ret = sBluetoothInterface->cancel_bond((bt_bdaddr_t *)addr);
806    env->ReleaseByteArrayElements(address, addr, 0);
807    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
808
809    return result;
810}
811
812static int getConnectionStateNative(JNIEnv* env, jobject obj, jbyteArray address) {
813    ALOGV("%s:",__FUNCTION__);
814    if (!sBluetoothInterface) return JNI_FALSE;
815
816    jbyte *addr = env->GetByteArrayElements(address, NULL);
817    if (addr == NULL) {
818        jniThrowIOException(env, EINVAL);
819        return JNI_FALSE;
820    }
821
822    int ret = sBluetoothInterface->get_connection_state((bt_bdaddr_t *)addr);
823    env->ReleaseByteArrayElements(address, addr, 0);
824
825    return ret;
826}
827
828static jboolean pinReplyNative(JNIEnv *env, jobject obj, jbyteArray address, jboolean accept,
829                               jint len, jbyteArray pinArray) {
830    ALOGV("%s:",__FUNCTION__);
831
832    jbyte *addr, *pinPtr = NULL;
833    jboolean result = JNI_FALSE;
834    if (!sBluetoothInterface) return result;
835
836    addr = env->GetByteArrayElements(address, NULL);
837    if (addr == NULL) {
838        jniThrowIOException(env, EINVAL);
839        return result;
840    }
841
842    if (accept) {
843        pinPtr = env->GetByteArrayElements(pinArray, NULL);
844        if (pinPtr == NULL) {
845           jniThrowIOException(env, EINVAL);
846           env->ReleaseByteArrayElements(address, addr, 0);
847           return result;
848        }
849    }
850
851    int ret = sBluetoothInterface->pin_reply((bt_bdaddr_t*)addr, accept, len,
852                                              (bt_pin_code_t *) pinPtr);
853    env->ReleaseByteArrayElements(address, addr, 0);
854    env->ReleaseByteArrayElements(pinArray, pinPtr, 0);
855    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
856
857    return result;
858}
859
860static jboolean sspReplyNative(JNIEnv *env, jobject obj, jbyteArray address,
861                               jint type, jboolean accept, jint passkey) {
862    ALOGV("%s:",__FUNCTION__);
863
864    jbyte *addr;
865    jboolean result = JNI_FALSE;
866    if (!sBluetoothInterface) return result;
867
868    addr = env->GetByteArrayElements(address, NULL);
869    if (addr == NULL) {
870        jniThrowIOException(env, EINVAL);
871        return result;
872    }
873
874    int ret = sBluetoothInterface->ssp_reply((bt_bdaddr_t *)addr,
875         (bt_ssp_variant_t) type, accept, passkey);
876    env->ReleaseByteArrayElements(address, addr, 0);
877    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
878
879    return result;
880}
881
882static jboolean setAdapterPropertyNative(JNIEnv *env, jobject obj, jint type, jbyteArray value) {
883    ALOGV("%s:",__FUNCTION__);
884
885    jbyte *val;
886    jboolean result = JNI_FALSE;
887    if (!sBluetoothInterface) return result;
888
889    val = env->GetByteArrayElements(value, NULL);
890    bt_property_t prop;
891    prop.type = (bt_property_type_t) type;
892    prop.len = env->GetArrayLength(value);
893    prop.val = val;
894
895    int ret = sBluetoothInterface->set_adapter_property(&prop);
896    env->ReleaseByteArrayElements(value, val, 0);
897    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
898
899    return result;
900}
901
902static jboolean getAdapterPropertiesNative(JNIEnv *env, jobject obj) {
903    ALOGV("%s:",__FUNCTION__);
904
905    jboolean result = JNI_FALSE;
906    if (!sBluetoothInterface) return result;
907
908    int ret = sBluetoothInterface->get_adapter_properties();
909    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
910
911    return result;
912}
913
914static jboolean getAdapterPropertyNative(JNIEnv *env, jobject obj, jint type) {
915    ALOGV("%s:",__FUNCTION__);
916
917    jboolean result = JNI_FALSE;
918    if (!sBluetoothInterface) return result;
919
920    int ret = sBluetoothInterface->get_adapter_property((bt_property_type_t) type);
921    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
922
923    return result;
924}
925
926static jboolean getDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address, jint type) {
927    ALOGV("%s:",__FUNCTION__);
928
929    jbyte *addr = NULL;
930    jboolean result = JNI_FALSE;
931    if (!sBluetoothInterface) return result;
932
933    addr = env->GetByteArrayElements(address, NULL);
934    if (addr == NULL) {
935        jniThrowIOException(env, EINVAL);
936        return result;
937    }
938
939    int ret = sBluetoothInterface->get_remote_device_property((bt_bdaddr_t *)addr,
940                                                              (bt_property_type_t) type);
941    env->ReleaseByteArrayElements(address, addr, 0);
942    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
943
944    return result;
945}
946
947static jboolean setDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address,
948                                        jint type, jbyteArray value) {
949    ALOGV("%s:",__FUNCTION__);
950
951    jbyte *val, *addr;
952    jboolean result = JNI_FALSE;
953    if (!sBluetoothInterface) return result;
954
955    val = env->GetByteArrayElements(value, NULL);
956    if (val == NULL) {
957        jniThrowIOException(env, EINVAL);
958        return result;
959    }
960
961    addr = env->GetByteArrayElements(address, NULL);
962    if (addr == NULL) {
963        env->ReleaseByteArrayElements(value, val, 0);
964        jniThrowIOException(env, EINVAL);
965        return result;
966    }
967
968
969    bt_property_t prop;
970    prop.type = (bt_property_type_t) type;
971    prop.len = env->GetArrayLength(value);
972    prop.val = val;
973
974    int ret = sBluetoothInterface->set_remote_device_property((bt_bdaddr_t *)addr, &prop);
975    env->ReleaseByteArrayElements(value, val, 0);
976    env->ReleaseByteArrayElements(address, addr, 0);
977
978    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
979
980    return result;
981}
982
983static jboolean getRemoteServicesNative(JNIEnv *env, jobject obj, jbyteArray address) {
984    ALOGV("%s:",__FUNCTION__);
985
986    jbyte *addr = NULL;
987    jboolean result = JNI_FALSE;
988    if (!sBluetoothInterface) return result;
989
990    addr = env->GetByteArrayElements(address, NULL);
991    if (addr == NULL) {
992        jniThrowIOException(env, EINVAL);
993        return result;
994    }
995
996    int ret = sBluetoothInterface->get_remote_services((bt_bdaddr_t *)addr);
997    env->ReleaseByteArrayElements(address, addr, 0);
998    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
999    return result;
1000}
1001
1002static int connectSocketNative(JNIEnv *env, jobject object, jbyteArray address, jint type,
1003                                   jbyteArray uuidObj, jint channel, jint flag) {
1004    jbyte *addr = NULL, *uuid = NULL;
1005    int socket_fd;
1006    bt_status_t status;
1007
1008    if (!sBluetoothSocketInterface) return -1;
1009
1010    addr = env->GetByteArrayElements(address, NULL);
1011    if (!addr) {
1012        ALOGE("failed to get Bluetooth device address");
1013        goto Fail;
1014    }
1015
1016    if(uuidObj != NULL) {
1017        uuid = env->GetByteArrayElements(uuidObj, NULL);
1018        if (!uuid) {
1019            ALOGE("failed to get uuid");
1020            goto Fail;
1021        }
1022    }
1023
1024    if ( (status = sBluetoothSocketInterface->connect((bt_bdaddr_t *) addr, (btsock_type_t) type,
1025                       (const uint8_t*) uuid, channel, &socket_fd, flag)) != BT_STATUS_SUCCESS) {
1026        ALOGE("Socket connection failed: %d", status);
1027        goto Fail;
1028    }
1029
1030
1031    if (socket_fd < 0) {
1032        ALOGE("Fail to create file descriptor on socket fd");
1033        goto Fail;
1034    }
1035    env->ReleaseByteArrayElements(address, addr, 0);
1036    env->ReleaseByteArrayElements(uuidObj, uuid, 0);
1037    return socket_fd;
1038
1039Fail:
1040    if (addr) env->ReleaseByteArrayElements(address, addr, 0);
1041    if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
1042
1043    return -1;
1044}
1045
1046static int createSocketChannelNative(JNIEnv *env, jobject object, jint type,
1047                                     jstring name_str, jbyteArray uuidObj,
1048                                     jint channel, jint flag) {
1049    const char *service_name = NULL;
1050    jbyte *uuid = NULL;
1051    int socket_fd;
1052    bt_status_t status;
1053
1054    if (!sBluetoothSocketInterface) return -1;
1055
1056    ALOGV("%s: SOCK FLAG = %x", __FUNCTION__, flag);
1057
1058    if(name_str != NULL) {
1059        service_name = env->GetStringUTFChars(name_str, NULL);
1060    }
1061
1062    if(uuidObj != NULL) {
1063        uuid = env->GetByteArrayElements(uuidObj, NULL);
1064        if (!uuid) {
1065            ALOGE("failed to get uuid");
1066            goto Fail;
1067        }
1068    }
1069    if ( (status = sBluetoothSocketInterface->listen((btsock_type_t) type, service_name,
1070                       (const uint8_t*) uuid, channel, &socket_fd, flag)) != BT_STATUS_SUCCESS) {
1071        ALOGE("Socket listen failed: %d", status);
1072        goto Fail;
1073    }
1074
1075    if (socket_fd < 0) {
1076        ALOGE("Fail to creat file descriptor on socket fd");
1077        goto Fail;
1078    }
1079    if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
1080    if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
1081    return socket_fd;
1082
1083Fail:
1084    if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
1085    if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
1086    return -1;
1087}
1088
1089static jboolean configHciSnoopLogNative(JNIEnv* env, jobject obj, jboolean enable) {
1090    ALOGV("%s:",__FUNCTION__);
1091
1092    jboolean result = JNI_FALSE;
1093
1094    if (!sBluetoothInterface) return result;
1095
1096    int ret = sBluetoothInterface->config_hci_snoop_log(enable);
1097
1098    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1099
1100    return result;
1101}
1102
1103static int readEnergyInfo()
1104{
1105    ALOGV("%s:",__FUNCTION__);
1106    jboolean result = JNI_FALSE;
1107    if (!sBluetoothInterface) return result;
1108    int ret = sBluetoothInterface->read_energy_info();
1109    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1110    return result;
1111}
1112
1113static JNINativeMethod sMethods[] = {
1114    /* name, signature, funcPtr */
1115    {"classInitNative", "()V", (void *) classInitNative},
1116    {"initNative", "()Z", (void *) initNative},
1117    {"cleanupNative", "()V", (void*) cleanupNative},
1118    {"enableNative", "()Z",  (void*) enableNative},
1119    {"disableNative", "()Z",  (void*) disableNative},
1120    {"setAdapterPropertyNative", "(I[B)Z", (void*) setAdapterPropertyNative},
1121    {"getAdapterPropertiesNative", "()Z", (void*) getAdapterPropertiesNative},
1122    {"getAdapterPropertyNative", "(I)Z", (void*) getAdapterPropertyNative},
1123    {"getDevicePropertyNative", "([BI)Z", (void*) getDevicePropertyNative},
1124    {"setDevicePropertyNative", "([BI[B)Z", (void*) setDevicePropertyNative},
1125    {"startDiscoveryNative", "()Z", (void*) startDiscoveryNative},
1126    {"cancelDiscoveryNative", "()Z", (void*) cancelDiscoveryNative},
1127    {"createBondNative", "([BI)Z", (void*) createBondNative},
1128    {"removeBondNative", "([B)Z", (void*) removeBondNative},
1129    {"cancelBondNative", "([B)Z", (void*) cancelBondNative},
1130    {"getConnectionStateNative", "([B)I", (void*) getConnectionStateNative},
1131    {"pinReplyNative", "([BZI[B)Z", (void*) pinReplyNative},
1132    {"sspReplyNative", "([BIZI)Z", (void*) sspReplyNative},
1133    {"getRemoteServicesNative", "([B)Z", (void*) getRemoteServicesNative},
1134    {"connectSocketNative", "([BI[BII)I", (void*) connectSocketNative},
1135    {"createSocketChannelNative", "(ILjava/lang/String;[BII)I",
1136     (void*) createSocketChannelNative},
1137    {"configHciSnoopLogNative", "(Z)Z", (void*) configHciSnoopLogNative},
1138    {"alarmFiredNative", "()V", (void *) alarmFiredNative},
1139    {"readEnergyInfo", "()I", (void*) readEnergyInfo},
1140};
1141
1142int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env)
1143{
1144    return jniRegisterNativeMethods(env, "com/android/bluetooth/btservice/AdapterService",
1145                                    sMethods, NELEM(sMethods));
1146}
1147
1148} /* namespace android */
1149
1150
1151/*
1152 * JNI Initialization
1153 */
1154jint JNI_OnLoad(JavaVM *jvm, void *reserved)
1155{
1156    JNIEnv *e;
1157    int status;
1158
1159    ALOGV("Bluetooth Adapter Service : loading JNI\n");
1160
1161    // Check JNI version
1162    if (jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) {
1163        ALOGE("JNI version mismatch error");
1164        return JNI_ERR;
1165    }
1166
1167    if ((status = android::register_com_android_bluetooth_btservice_AdapterService(e)) < 0) {
1168        ALOGE("jni adapter service registration failure, status: %d", status);
1169        return JNI_ERR;
1170    }
1171
1172    if ((status = android::register_com_android_bluetooth_hfp(e)) < 0) {
1173        ALOGE("jni hfp registration failure, status: %d", status);
1174        return JNI_ERR;
1175    }
1176
1177    if ((status = android::register_com_android_bluetooth_hfpclient(e)) < 0) {
1178        ALOGE("jni hfp client registration failure, status: %d", status);
1179        return JNI_ERR;
1180    }
1181
1182    if ((status = android::register_com_android_bluetooth_a2dp(e)) < 0) {
1183        ALOGE("jni a2dp source registration failure: %d", status);
1184        return JNI_ERR;
1185    }
1186
1187    if ((status = android::register_com_android_bluetooth_a2dp_sink(e)) < 0) {
1188        ALOGE("jni a2dp sink registration failure: %d", status);
1189        return JNI_ERR;
1190    }
1191
1192    if ((status = android::register_com_android_bluetooth_avrcp(e)) < 0) {
1193        ALOGE("jni avrcp target registration failure: %d", status);
1194        return JNI_ERR;
1195    }
1196
1197    if ((status = android::register_com_android_bluetooth_avrcp_controller(e)) < 0) {
1198        ALOGE("jni avrcp controller registration failure: %d", status);
1199        return JNI_ERR;
1200    }
1201
1202    if ((status = android::register_com_android_bluetooth_hid(e)) < 0) {
1203        ALOGE("jni hid registration failure: %d", status);
1204        return JNI_ERR;
1205    }
1206
1207    if ((status = android::register_com_android_bluetooth_hdp(e)) < 0) {
1208        ALOGE("jni hdp registration failure: %d", status);
1209        return JNI_ERR;
1210    }
1211
1212    if ((status = android::register_com_android_bluetooth_pan(e)) < 0) {
1213        ALOGE("jni pan registration failure: %d", status);
1214        return JNI_ERR;
1215    }
1216
1217    if ((status = android::register_com_android_bluetooth_gatt(e)) < 0) {
1218        ALOGE("jni gatt registration failure: %d", status);
1219        return JNI_ERR;
1220    }
1221
1222    if ((status = android::register_com_android_bluetooth_sdp(e)) < 0) {
1223        ALOGE("jni sdp registration failure: %d", status);
1224        return JNI_ERR;
1225    }
1226
1227    return JNI_VERSION_1_6;
1228}
1229