com_android_bluetooth_btservice_AdapterService.cpp revision 6eb32d5f7c30f04da45c3da0974bbb63725a0978
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        bool min_16_digits) {
355    jbyteArray addr, devname;
356    if (!checkCallbackThread()) {
357       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
358       return;
359    }
360    if (!bd_addr) {
361        ALOGE("Address is null in %s", __FUNCTION__);
362        return;
363    }
364
365    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
366    if (addr == NULL) goto Fail;
367    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
368
369    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
370    if (devname == NULL) goto Fail;
371
372    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
373
374    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_pinRequestCallback, addr, devname, cod,
375            min_16_digits);
376
377    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
378    callbackEnv->DeleteLocalRef(addr);
379    callbackEnv->DeleteLocalRef(devname);
380    return;
381
382Fail:
383    if (addr) callbackEnv->DeleteLocalRef(addr);
384    if (devname) callbackEnv->DeleteLocalRef(devname);
385    ALOGE("Error while allocating in: %s", __FUNCTION__);
386}
387
388static void ssp_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod,
389                                 bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
390    jbyteArray addr, devname;
391    if (!checkCallbackThread()) {
392       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
393       return;
394    }
395    if (!bd_addr) {
396        ALOGE("Address is null in %s", __FUNCTION__);
397        return;
398    }
399
400    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
401    if (addr == NULL) goto Fail;
402    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
403
404    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
405    if (devname == NULL) goto Fail;
406    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
407
408    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_sspRequestCallback, addr, devname, cod,
409                                (jint) pairing_variant, pass_key);
410
411    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
412    callbackEnv->DeleteLocalRef(addr);
413    callbackEnv->DeleteLocalRef(devname);
414    return;
415
416Fail:
417    if (addr) callbackEnv->DeleteLocalRef(addr);
418    if (devname) callbackEnv->DeleteLocalRef(devname);
419
420    ALOGE("Error while allocating in: %s", __FUNCTION__);
421}
422
423static void callback_thread_event(bt_cb_thread_evt event) {
424    JavaVM* vm = AndroidRuntime::getJavaVM();
425    if (event  == ASSOCIATE_JVM) {
426        JavaVMAttachArgs args;
427        char name[] = "BT Service Callback Thread";
428        args.version = JNI_VERSION_1_6;
429        args.name = name;
430        args.group = NULL;
431        vm->AttachCurrentThread(&callbackEnv, &args);
432        ALOGV("Callback thread attached: %p", callbackEnv);
433    } else if (event == DISASSOCIATE_JVM) {
434        if (!checkCallbackThread()) {
435            ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
436            return;
437        }
438        vm->DetachCurrentThread();
439    }
440}
441
442static void dut_mode_recv_callback (uint16_t opcode, uint8_t *buf, uint8_t len) {
443
444}
445static void le_test_mode_recv_callback (bt_status_t status, uint16_t packet_count) {
446
447    ALOGV("%s: status:%d packet_count:%d ", __FUNCTION__, status, packet_count);
448}
449
450static void energy_info_recv_callback(bt_activity_energy_info *p_energy_info)
451{
452    if (!checkCallbackThread()) {
453       ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
454       return;
455    }
456
457    callbackEnv->CallVoidMethod(sJniAdapterServiceObj, method_energyInfo, p_energy_info->status,
458        p_energy_info->ctrl_state, p_energy_info->tx_time, p_energy_info->rx_time,
459        p_energy_info->idle_time, p_energy_info->energy_used);
460
461    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
462}
463
464static bt_callbacks_t sBluetoothCallbacks = {
465    sizeof(sBluetoothCallbacks),
466    adapter_state_change_callback,
467    adapter_properties_callback,
468    remote_device_properties_callback,
469    device_found_callback,
470    discovery_state_changed_callback,
471    pin_request_callback,
472    ssp_request_callback,
473    bond_state_changed_callback,
474    acl_state_changed_callback,
475    callback_thread_event,
476    dut_mode_recv_callback,
477    le_test_mode_recv_callback,
478    energy_info_recv_callback
479};
480
481// The callback to call when the wake alarm fires.
482static alarm_cb sAlarmCallback;
483
484// The data to pass to the wake alarm callback.
485static void *sAlarmCallbackData;
486
487static JavaVMAttachArgs sAttachArgs = {
488  .version = JNI_VERSION_1_6,
489  .name = "bluedroid wake/alarm thread",
490  .group = NULL
491};
492
493static bool set_wake_alarm_callout(uint64_t delay_millis, bool should_wake,
494        alarm_cb cb, void *data) {
495    JNIEnv *env;
496    JavaVM *vm = AndroidRuntime::getJavaVM();
497    jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
498
499    if (status != JNI_OK && status != JNI_EDETACHED) {
500        ALOGE("%s unable to get environment for JNI call", __func__);
501        return false;
502    }
503
504    if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
505        ALOGE("%s unable to attach thread to VM", __func__);
506        return false;
507    }
508
509    sAlarmCallback = cb;
510    sAlarmCallbackData = data;
511
512    jboolean jshould_wake = should_wake ? JNI_TRUE : JNI_FALSE;
513    jboolean ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_setWakeAlarm,
514            (jlong)delay_millis, jshould_wake);
515    if (!ret) {
516        sAlarmCallback = NULL;
517        sAlarmCallbackData = NULL;
518    }
519
520    if (status == JNI_EDETACHED) {
521        vm->DetachCurrentThread();
522    }
523
524    return !!ret;
525}
526
527static int acquire_wake_lock_callout(const char *lock_name) {
528    JNIEnv *env;
529    JavaVM *vm = AndroidRuntime::getJavaVM();
530    jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
531    if (status != JNI_OK && status != JNI_EDETACHED) {
532        ALOGE("%s unable to get environment for JNI call", __func__);
533        return BT_STATUS_FAIL;
534    }
535    if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
536        ALOGE("%s unable to attach thread to VM", __func__);
537        return BT_STATUS_FAIL;
538    }
539
540    jboolean ret = JNI_FALSE;
541    jstring lock_name_jni = env->NewStringUTF(lock_name);
542    if (lock_name_jni) {
543        ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_acquireWakeLock, lock_name_jni);
544        env->DeleteLocalRef(lock_name_jni);
545    } else {
546        ALOGE("%s unable to allocate string: %s", __func__, lock_name);
547    }
548
549    if (status == JNI_EDETACHED) {
550        vm->DetachCurrentThread();
551    }
552
553    return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
554}
555
556static int release_wake_lock_callout(const char *lock_name) {
557    JNIEnv *env;
558    JavaVM *vm = AndroidRuntime::getJavaVM();
559    jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
560
561    if (status != JNI_OK && status != JNI_EDETACHED) {
562        ALOGE("%s unable to get environment for JNI call", __func__);
563        return BT_STATUS_FAIL;
564    }
565    if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
566        ALOGE("%s unable to attach thread to VM", __func__);
567        return BT_STATUS_FAIL;
568    }
569    jboolean ret = JNI_FALSE;
570    jstring lock_name_jni = env->NewStringUTF(lock_name);
571    if (lock_name_jni) {
572        ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_releaseWakeLock, lock_name_jni);
573        env->DeleteLocalRef(lock_name_jni);
574    } else {
575        ALOGE("%s unable to allocate string: %s", __func__, lock_name);
576    }
577    if (status == JNI_EDETACHED) {
578        vm->DetachCurrentThread();
579    }
580    return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
581}
582
583// Called by Java code when alarm is fired. A wake lock is held by the caller
584// over the duration of this callback.
585static void alarmFiredNative(JNIEnv *env, jobject obj) {
586    if (sAlarmCallback) {
587        sAlarmCallback(sAlarmCallbackData);
588    } else {
589        ALOGE("%s() - Alarm fired with callback not set!", __FUNCTION__);
590    }
591}
592
593static bt_os_callouts_t sBluetoothOsCallouts = {
594    sizeof(sBluetoothOsCallouts),
595    set_wake_alarm_callout,
596    acquire_wake_lock_callout,
597    release_wake_lock_callout,
598};
599
600
601
602static void classInitNative(JNIEnv* env, jclass clazz) {
603    int err;
604    hw_module_t* module;
605
606    jclass jniCallbackClass =
607        env->FindClass("com/android/bluetooth/btservice/JniCallbacks");
608    sJniCallbacksField = env->GetFieldID(clazz, "mJniCallbacks",
609        "Lcom/android/bluetooth/btservice/JniCallbacks;");
610
611    method_stateChangeCallback = env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V");
612
613    method_adapterPropertyChangedCallback = env->GetMethodID(jniCallbackClass,
614                                                             "adapterPropertyChangedCallback",
615                                                             "([I[[B)V");
616    method_discoveryStateChangeCallback = env->GetMethodID(jniCallbackClass,
617                                                           "discoveryStateChangeCallback", "(I)V");
618
619    method_devicePropertyChangedCallback = env->GetMethodID(jniCallbackClass,
620                                                            "devicePropertyChangedCallback",
621                                                            "([B[I[[B)V");
622    method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
623    method_pinRequestCallback = env->GetMethodID(jniCallbackClass, "pinRequestCallback",
624                                                 "([B[BIZ)V");
625    method_sspRequestCallback = env->GetMethodID(jniCallbackClass, "sspRequestCallback",
626                                                 "([B[BIII)V");
627
628    method_bondStateChangeCallback = env->GetMethodID(jniCallbackClass,
629                                                     "bondStateChangeCallback", "(I[BI)V");
630
631    method_aclStateChangeCallback = env->GetMethodID(jniCallbackClass,
632                                                    "aclStateChangeCallback", "(I[BI)V");
633
634    method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z");
635    method_acquireWakeLock = env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z");
636    method_releaseWakeLock = env->GetMethodID(clazz, "releaseWakeLock", "(Ljava/lang/String;)Z");
637    method_energyInfo = env->GetMethodID(clazz, "energyInfoCallback", "(IIJJJJ)V");
638
639    char value[PROPERTY_VALUE_MAX];
640    property_get("bluetooth.mock_stack", value, "");
641
642    const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID);
643
644    err = hw_get_module(id, (hw_module_t const**)&module);
645
646    if (err == 0) {
647        hw_device_t* abstraction;
648        err = module->methods->open(module, id, &abstraction);
649        if (err == 0) {
650            bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction;
651            sBluetoothInterface = btStack->get_bluetooth_interface();
652        } else {
653           ALOGE("Error while opening Bluetooth library");
654        }
655    } else {
656        ALOGE("No Bluetooth Library found");
657    }
658}
659
660static bool initNative(JNIEnv* env, jobject obj) {
661    ALOGV("%s:",__FUNCTION__);
662
663    sJniAdapterServiceObj = env->NewGlobalRef(obj);
664    sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));
665
666    if (sBluetoothInterface) {
667        int ret = sBluetoothInterface->init(&sBluetoothCallbacks);
668        if (ret != BT_STATUS_SUCCESS) {
669            ALOGE("Error while setting the callbacks: %d\n", ret);
670            sBluetoothInterface = NULL;
671            return JNI_FALSE;
672        }
673        ret = sBluetoothInterface->set_os_callouts(&sBluetoothOsCallouts);
674        if (ret != BT_STATUS_SUCCESS) {
675            ALOGE("Error while setting Bluetooth callouts: %d\n", ret);
676            sBluetoothInterface->cleanup();
677            sBluetoothInterface = NULL;
678            return JNI_FALSE;
679        }
680
681        if ( (sBluetoothSocketInterface = (btsock_interface_t *)
682                  sBluetoothInterface->get_profile_interface(BT_PROFILE_SOCKETS_ID)) == NULL) {
683                ALOGE("Error getting socket interface");
684        }
685
686        return JNI_TRUE;
687    }
688    return JNI_FALSE;
689}
690
691static bool cleanupNative(JNIEnv *env, jobject obj) {
692    ALOGV("%s:",__FUNCTION__);
693
694    jboolean result = JNI_FALSE;
695    if (!sBluetoothInterface) return result;
696
697    sBluetoothInterface->cleanup();
698    ALOGI("%s: return from cleanup",__FUNCTION__);
699
700    env->DeleteGlobalRef(sJniCallbacksObj);
701    env->DeleteGlobalRef(sJniAdapterServiceObj);
702    return JNI_TRUE;
703}
704
705static jboolean enableNative(JNIEnv* env, jobject obj) {
706    ALOGV("%s:",__FUNCTION__);
707
708    jboolean result = JNI_FALSE;
709    if (!sBluetoothInterface) return result;
710
711    int ret = sBluetoothInterface->enable();
712    result = (ret == BT_STATUS_SUCCESS || ret == BT_STATUS_DONE) ? JNI_TRUE : JNI_FALSE;
713    return result;
714}
715
716static jboolean disableNative(JNIEnv* env, jobject obj) {
717    ALOGV("%s:",__FUNCTION__);
718
719    jboolean result = JNI_FALSE;
720    if (!sBluetoothInterface) return result;
721
722    int ret = sBluetoothInterface->disable();
723    /* Retrun JNI_FALSE only when BTIF explicitly reports
724       BT_STATUS_FAIL. It is fine for the BT_STATUS_NOT_READY
725       case which indicates that stack had not been enabled.
726    */
727    result = (ret == BT_STATUS_FAIL) ? JNI_FALSE : JNI_TRUE;
728    return result;
729}
730
731static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
732    ALOGV("%s:",__FUNCTION__);
733
734    jboolean result = JNI_FALSE;
735    if (!sBluetoothInterface) return result;
736
737    int ret = sBluetoothInterface->start_discovery();
738    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
739    return result;
740}
741
742static jboolean cancelDiscoveryNative(JNIEnv* env, jobject obj) {
743    ALOGV("%s:",__FUNCTION__);
744
745    jboolean result = JNI_FALSE;
746    if (!sBluetoothInterface) return result;
747
748    int ret = sBluetoothInterface->cancel_discovery();
749    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
750    return result;
751}
752
753static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address, jint transport) {
754    ALOGV("%s:",__FUNCTION__);
755
756    jbyte *addr;
757    jboolean result = JNI_FALSE;
758
759    if (!sBluetoothInterface) return result;
760
761    addr = env->GetByteArrayElements(address, NULL);
762    if (addr == NULL) {
763        jniThrowIOException(env, EINVAL);
764        return result;
765    }
766
767    int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr, transport);
768    env->ReleaseByteArrayElements(address, addr, 0);
769    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
770
771    return result;
772}
773
774static jboolean removeBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
775    ALOGV("%s:",__FUNCTION__);
776
777    jbyte *addr;
778    jboolean result;
779    if (!sBluetoothInterface) return JNI_FALSE;
780
781    addr = env->GetByteArrayElements(address, NULL);
782    if (addr == NULL) {
783        jniThrowIOException(env, EINVAL);
784        return JNI_FALSE;
785    }
786
787    int ret = sBluetoothInterface->remove_bond((bt_bdaddr_t *)addr);
788    env->ReleaseByteArrayElements(address, addr, 0);
789    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
790
791    return result;
792}
793
794static jboolean cancelBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
795    ALOGV("%s:",__FUNCTION__);
796
797    jbyte *addr;
798    jboolean result;
799    if (!sBluetoothInterface) return JNI_FALSE;
800
801    addr = env->GetByteArrayElements(address, NULL);
802    if (addr == NULL) {
803        jniThrowIOException(env, EINVAL);
804        return JNI_FALSE;
805    }
806
807    int ret = sBluetoothInterface->cancel_bond((bt_bdaddr_t *)addr);
808    env->ReleaseByteArrayElements(address, addr, 0);
809    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
810
811    return result;
812}
813
814static int getConnectionStateNative(JNIEnv* env, jobject obj, jbyteArray address) {
815    ALOGV("%s:",__FUNCTION__);
816    if (!sBluetoothInterface) return JNI_FALSE;
817
818    jbyte *addr = env->GetByteArrayElements(address, NULL);
819    if (addr == NULL) {
820        jniThrowIOException(env, EINVAL);
821        return JNI_FALSE;
822    }
823
824    int ret = sBluetoothInterface->get_connection_state((bt_bdaddr_t *)addr);
825    env->ReleaseByteArrayElements(address, addr, 0);
826
827    return ret;
828}
829
830static jboolean pinReplyNative(JNIEnv *env, jobject obj, jbyteArray address, jboolean accept,
831                               jint len, jbyteArray pinArray) {
832    ALOGV("%s:",__FUNCTION__);
833
834    jbyte *addr, *pinPtr = NULL;
835    jboolean result = JNI_FALSE;
836    if (!sBluetoothInterface) return result;
837
838    addr = env->GetByteArrayElements(address, NULL);
839    if (addr == NULL) {
840        jniThrowIOException(env, EINVAL);
841        return result;
842    }
843
844    if (accept) {
845        pinPtr = env->GetByteArrayElements(pinArray, NULL);
846        if (pinPtr == NULL) {
847           jniThrowIOException(env, EINVAL);
848           env->ReleaseByteArrayElements(address, addr, 0);
849           return result;
850        }
851    }
852
853    int ret = sBluetoothInterface->pin_reply((bt_bdaddr_t*)addr, accept, len,
854                                              (bt_pin_code_t *) pinPtr);
855    env->ReleaseByteArrayElements(address, addr, 0);
856    env->ReleaseByteArrayElements(pinArray, pinPtr, 0);
857    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
858
859    return result;
860}
861
862static jboolean sspReplyNative(JNIEnv *env, jobject obj, jbyteArray address,
863                               jint type, jboolean accept, jint passkey) {
864    ALOGV("%s:",__FUNCTION__);
865
866    jbyte *addr;
867    jboolean result = JNI_FALSE;
868    if (!sBluetoothInterface) return result;
869
870    addr = env->GetByteArrayElements(address, NULL);
871    if (addr == NULL) {
872        jniThrowIOException(env, EINVAL);
873        return result;
874    }
875
876    int ret = sBluetoothInterface->ssp_reply((bt_bdaddr_t *)addr,
877         (bt_ssp_variant_t) type, accept, passkey);
878    env->ReleaseByteArrayElements(address, addr, 0);
879    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
880
881    return result;
882}
883
884static jboolean setAdapterPropertyNative(JNIEnv *env, jobject obj, jint type, jbyteArray value) {
885    ALOGV("%s:",__FUNCTION__);
886
887    jbyte *val;
888    jboolean result = JNI_FALSE;
889    if (!sBluetoothInterface) return result;
890
891    val = env->GetByteArrayElements(value, NULL);
892    bt_property_t prop;
893    prop.type = (bt_property_type_t) type;
894    prop.len = env->GetArrayLength(value);
895    prop.val = val;
896
897    int ret = sBluetoothInterface->set_adapter_property(&prop);
898    env->ReleaseByteArrayElements(value, val, 0);
899    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
900
901    return result;
902}
903
904static jboolean getAdapterPropertiesNative(JNIEnv *env, jobject obj) {
905    ALOGV("%s:",__FUNCTION__);
906
907    jboolean result = JNI_FALSE;
908    if (!sBluetoothInterface) return result;
909
910    int ret = sBluetoothInterface->get_adapter_properties();
911    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
912
913    return result;
914}
915
916static jboolean getAdapterPropertyNative(JNIEnv *env, jobject obj, jint type) {
917    ALOGV("%s:",__FUNCTION__);
918
919    jboolean result = JNI_FALSE;
920    if (!sBluetoothInterface) return result;
921
922    int ret = sBluetoothInterface->get_adapter_property((bt_property_type_t) type);
923    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
924
925    return result;
926}
927
928static jboolean getDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address, jint type) {
929    ALOGV("%s:",__FUNCTION__);
930
931    jbyte *addr = NULL;
932    jboolean result = JNI_FALSE;
933    if (!sBluetoothInterface) return result;
934
935    addr = env->GetByteArrayElements(address, NULL);
936    if (addr == NULL) {
937        jniThrowIOException(env, EINVAL);
938        return result;
939    }
940
941    int ret = sBluetoothInterface->get_remote_device_property((bt_bdaddr_t *)addr,
942                                                              (bt_property_type_t) type);
943    env->ReleaseByteArrayElements(address, addr, 0);
944    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
945
946    return result;
947}
948
949static jboolean setDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address,
950                                        jint type, jbyteArray value) {
951    ALOGV("%s:",__FUNCTION__);
952
953    jbyte *val, *addr;
954    jboolean result = JNI_FALSE;
955    if (!sBluetoothInterface) return result;
956
957    val = env->GetByteArrayElements(value, NULL);
958    if (val == NULL) {
959        jniThrowIOException(env, EINVAL);
960        return result;
961    }
962
963    addr = env->GetByteArrayElements(address, NULL);
964    if (addr == NULL) {
965        env->ReleaseByteArrayElements(value, val, 0);
966        jniThrowIOException(env, EINVAL);
967        return result;
968    }
969
970
971    bt_property_t prop;
972    prop.type = (bt_property_type_t) type;
973    prop.len = env->GetArrayLength(value);
974    prop.val = val;
975
976    int ret = sBluetoothInterface->set_remote_device_property((bt_bdaddr_t *)addr, &prop);
977    env->ReleaseByteArrayElements(value, val, 0);
978    env->ReleaseByteArrayElements(address, addr, 0);
979
980    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
981
982    return result;
983}
984
985static jboolean getRemoteServicesNative(JNIEnv *env, jobject obj, jbyteArray address) {
986    ALOGV("%s:",__FUNCTION__);
987
988    jbyte *addr = NULL;
989    jboolean result = JNI_FALSE;
990    if (!sBluetoothInterface) return result;
991
992    addr = env->GetByteArrayElements(address, NULL);
993    if (addr == NULL) {
994        jniThrowIOException(env, EINVAL);
995        return result;
996    }
997
998    int ret = sBluetoothInterface->get_remote_services((bt_bdaddr_t *)addr);
999    env->ReleaseByteArrayElements(address, addr, 0);
1000    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1001    return result;
1002}
1003
1004static int connectSocketNative(JNIEnv *env, jobject object, jbyteArray address, jint type,
1005                                   jbyteArray uuidObj, jint channel, jint flag) {
1006    jbyte *addr = NULL, *uuid = NULL;
1007    int socket_fd;
1008    bt_status_t status;
1009
1010    if (!sBluetoothSocketInterface) return -1;
1011
1012    addr = env->GetByteArrayElements(address, NULL);
1013    if (!addr) {
1014        ALOGE("failed to get Bluetooth device address");
1015        goto Fail;
1016    }
1017
1018    if(uuidObj != NULL) {
1019        uuid = env->GetByteArrayElements(uuidObj, NULL);
1020        if (!uuid) {
1021            ALOGE("failed to get uuid");
1022            goto Fail;
1023        }
1024    }
1025
1026    if ( (status = sBluetoothSocketInterface->connect((bt_bdaddr_t *) addr, (btsock_type_t) type,
1027                       (const uint8_t*) uuid, channel, &socket_fd, flag)) != BT_STATUS_SUCCESS) {
1028        ALOGE("Socket connection failed: %d", status);
1029        goto Fail;
1030    }
1031
1032
1033    if (socket_fd < 0) {
1034        ALOGE("Fail to create file descriptor on socket fd");
1035        goto Fail;
1036    }
1037    env->ReleaseByteArrayElements(address, addr, 0);
1038    env->ReleaseByteArrayElements(uuidObj, uuid, 0);
1039    return socket_fd;
1040
1041Fail:
1042    if (addr) env->ReleaseByteArrayElements(address, addr, 0);
1043    if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
1044
1045    return -1;
1046}
1047
1048static int createSocketChannelNative(JNIEnv *env, jobject object, jint type,
1049                                     jstring name_str, jbyteArray uuidObj,
1050                                     jint channel, jint flag) {
1051    const char *service_name = NULL;
1052    jbyte *uuid = NULL;
1053    int socket_fd;
1054    bt_status_t status;
1055
1056    if (!sBluetoothSocketInterface) return -1;
1057
1058    ALOGV("%s: SOCK FLAG = %x", __FUNCTION__, flag);
1059
1060    if(name_str != NULL) {
1061        service_name = env->GetStringUTFChars(name_str, NULL);
1062    }
1063
1064    if(uuidObj != NULL) {
1065        uuid = env->GetByteArrayElements(uuidObj, NULL);
1066        if (!uuid) {
1067            ALOGE("failed to get uuid");
1068            goto Fail;
1069        }
1070    }
1071    if ( (status = sBluetoothSocketInterface->listen((btsock_type_t) type, service_name,
1072                       (const uint8_t*) uuid, channel, &socket_fd, flag)) != BT_STATUS_SUCCESS) {
1073        ALOGE("Socket listen failed: %d", status);
1074        goto Fail;
1075    }
1076
1077    if (socket_fd < 0) {
1078        ALOGE("Fail to creat file descriptor on socket fd");
1079        goto Fail;
1080    }
1081    if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
1082    if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
1083    return socket_fd;
1084
1085Fail:
1086    if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
1087    if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
1088    return -1;
1089}
1090
1091static jboolean configHciSnoopLogNative(JNIEnv* env, jobject obj, jboolean enable) {
1092    ALOGV("%s:",__FUNCTION__);
1093
1094    jboolean result = JNI_FALSE;
1095
1096    if (!sBluetoothInterface) return result;
1097
1098    int ret = sBluetoothInterface->config_hci_snoop_log(enable);
1099
1100    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1101
1102    return result;
1103}
1104
1105static int readEnergyInfo()
1106{
1107    ALOGV("%s:",__FUNCTION__);
1108    jboolean result = JNI_FALSE;
1109    if (!sBluetoothInterface) return result;
1110    int ret = sBluetoothInterface->read_energy_info();
1111    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1112    return result;
1113}
1114
1115static void dumpNative(JNIEnv *env, jobject obj, jobject fdObj)
1116{
1117    ALOGV("%s()", __FUNCTION__);
1118    if (!sBluetoothInterface) return;
1119
1120    int fd = jniGetFDFromFileDescriptor(env, fdObj);
1121    if (fd < 0) return;
1122
1123    sBluetoothInterface->dump(fd);
1124}
1125
1126static jboolean factoryResetNative(JNIEnv *env, jobject obj) {
1127    ALOGV("%s:", __FUNCTION__);
1128    if (!sBluetoothInterface) return JNI_FALSE;
1129    int ret = sBluetoothInterface->config_clear();
1130    return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1131}
1132
1133static JNINativeMethod sMethods[] = {
1134    /* name, signature, funcPtr */
1135    {"classInitNative", "()V", (void *) classInitNative},
1136    {"initNative", "()Z", (void *) initNative},
1137    {"cleanupNative", "()V", (void*) cleanupNative},
1138    {"enableNative", "()Z",  (void*) enableNative},
1139    {"disableNative", "()Z",  (void*) disableNative},
1140    {"setAdapterPropertyNative", "(I[B)Z", (void*) setAdapterPropertyNative},
1141    {"getAdapterPropertiesNative", "()Z", (void*) getAdapterPropertiesNative},
1142    {"getAdapterPropertyNative", "(I)Z", (void*) getAdapterPropertyNative},
1143    {"getDevicePropertyNative", "([BI)Z", (void*) getDevicePropertyNative},
1144    {"setDevicePropertyNative", "([BI[B)Z", (void*) setDevicePropertyNative},
1145    {"startDiscoveryNative", "()Z", (void*) startDiscoveryNative},
1146    {"cancelDiscoveryNative", "()Z", (void*) cancelDiscoveryNative},
1147    {"createBondNative", "([BI)Z", (void*) createBondNative},
1148    {"removeBondNative", "([B)Z", (void*) removeBondNative},
1149    {"cancelBondNative", "([B)Z", (void*) cancelBondNative},
1150    {"getConnectionStateNative", "([B)I", (void*) getConnectionStateNative},
1151    {"pinReplyNative", "([BZI[B)Z", (void*) pinReplyNative},
1152    {"sspReplyNative", "([BIZI)Z", (void*) sspReplyNative},
1153    {"getRemoteServicesNative", "([B)Z", (void*) getRemoteServicesNative},
1154    {"connectSocketNative", "([BI[BII)I", (void*) connectSocketNative},
1155    {"createSocketChannelNative", "(ILjava/lang/String;[BII)I",
1156     (void*) createSocketChannelNative},
1157    {"configHciSnoopLogNative", "(Z)Z", (void*) configHciSnoopLogNative},
1158    {"alarmFiredNative", "()V", (void *) alarmFiredNative},
1159    {"readEnergyInfo", "()I", (void*) readEnergyInfo},
1160    {"dumpNative", "(Ljava/io/FileDescriptor;)V", (void*) dumpNative},
1161    {"factoryResetNative", "()Z", (void*)factoryResetNative}
1162};
1163
1164int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env)
1165{
1166    return jniRegisterNativeMethods(env, "com/android/bluetooth/btservice/AdapterService",
1167                                    sMethods, NELEM(sMethods));
1168}
1169
1170} /* namespace android */
1171
1172
1173/*
1174 * JNI Initialization
1175 */
1176jint JNI_OnLoad(JavaVM *jvm, void *reserved)
1177{
1178    JNIEnv *e;
1179    int status;
1180
1181    ALOGV("Bluetooth Adapter Service : loading JNI\n");
1182
1183    // Check JNI version
1184    if (jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) {
1185        ALOGE("JNI version mismatch error");
1186        return JNI_ERR;
1187    }
1188
1189    if ((status = android::register_com_android_bluetooth_btservice_AdapterService(e)) < 0) {
1190        ALOGE("jni adapter service registration failure, status: %d", status);
1191        return JNI_ERR;
1192    }
1193
1194    if ((status = android::register_com_android_bluetooth_hfp(e)) < 0) {
1195        ALOGE("jni hfp registration failure, status: %d", status);
1196        return JNI_ERR;
1197    }
1198
1199    if ((status = android::register_com_android_bluetooth_hfpclient(e)) < 0) {
1200        ALOGE("jni hfp client registration failure, status: %d", status);
1201        return JNI_ERR;
1202    }
1203
1204    if ((status = android::register_com_android_bluetooth_a2dp(e)) < 0) {
1205        ALOGE("jni a2dp source registration failure: %d", status);
1206        return JNI_ERR;
1207    }
1208
1209    if ((status = android::register_com_android_bluetooth_a2dp_sink(e)) < 0) {
1210        ALOGE("jni a2dp sink registration failure: %d", status);
1211        return JNI_ERR;
1212    }
1213
1214    if ((status = android::register_com_android_bluetooth_avrcp(e)) < 0) {
1215        ALOGE("jni avrcp target registration failure: %d", status);
1216        return JNI_ERR;
1217    }
1218
1219    if ((status = android::register_com_android_bluetooth_avrcp_controller(e)) < 0) {
1220        ALOGE("jni avrcp controller registration failure: %d", status);
1221        return JNI_ERR;
1222    }
1223
1224    if ((status = android::register_com_android_bluetooth_hid(e)) < 0) {
1225        ALOGE("jni hid registration failure: %d", status);
1226        return JNI_ERR;
1227    }
1228
1229    if ((status = android::register_com_android_bluetooth_hdp(e)) < 0) {
1230        ALOGE("jni hdp registration failure: %d", status);
1231        return JNI_ERR;
1232    }
1233
1234    if ((status = android::register_com_android_bluetooth_pan(e)) < 0) {
1235        ALOGE("jni pan registration failure: %d", status);
1236        return JNI_ERR;
1237    }
1238
1239    if ((status = android::register_com_android_bluetooth_gatt(e)) < 0) {
1240        ALOGE("jni gatt registration failure: %d", status);
1241        return JNI_ERR;
1242    }
1243
1244    if ((status = android::register_com_android_bluetooth_sdp(e)) < 0) {
1245        ALOGE("jni sdp registration failure: %d", status);
1246        return JNI_ERR;
1247    }
1248
1249    return JNI_VERSION_1_6;
1250}
1251