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 "BluetoothPanServiceJni" 18 19#define LOG_NDEBUG 0 20 21#include "android_runtime/AndroidRuntime.h" 22#include "com_android_bluetooth.h" 23#include "hardware/bt_pan.h" 24#include "utils/Log.h" 25 26#include <string.h> 27 28#include <cutils/log.h> 29#define info(fmt, ...) ALOGI("%s(L%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) 30#define debug(fmt, ...) \ 31 ALOGD("%s(L%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) 32#define warn(fmt, ...) \ 33 ALOGW("## WARNING : %s(L%d): " fmt "##", __func__, __LINE__, ##__VA_ARGS__) 34#define error(fmt, ...) \ 35 ALOGE("## ERROR : %s(L%d): " fmt "##", __func__, __LINE__, ##__VA_ARGS__) 36#define asrt(s) \ 37 if (!(s)) ALOGE("## %s(L%d): ASSERT %s failed! ##", __func__, __LINE__, #s) 38 39namespace android { 40 41static jmethodID method_onConnectStateChanged; 42static jmethodID method_onControlStateChanged; 43 44static const btpan_interface_t* sPanIf = NULL; 45static jobject mCallbacksObj = NULL; 46 47static jbyteArray marshall_bda(const bt_bdaddr_t* bd_addr) { 48 CallbackEnv sCallbackEnv(__func__); 49 if (!sCallbackEnv.valid()) return NULL; 50 51 jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 52 if (!addr) { 53 ALOGE("Fail to new jbyteArray bd addr"); 54 return NULL; 55 } 56 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), 57 (jbyte*)bd_addr); 58 return addr; 59} 60 61static void control_state_callback(btpan_control_state_t state, int local_role, 62 bt_status_t error, const char* ifname) { 63 debug("state:%d, local_role:%d, ifname:%s", state, local_role, ifname); 64 if (mCallbacksObj == NULL) { 65 error("Callbacks Obj is NULL: '%s", __func__); 66 return; 67 } 68 CallbackEnv sCallbackEnv(__func__); 69 if (!sCallbackEnv.valid()) return; 70 ScopedLocalRef<jstring> js_ifname(sCallbackEnv.get(), 71 sCallbackEnv->NewStringUTF(ifname)); 72 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onControlStateChanged, 73 (jint)local_role, (jint)state, (jint)error, 74 js_ifname.get()); 75} 76 77static void connection_state_callback(btpan_connection_state_t state, 78 bt_status_t error, 79 const bt_bdaddr_t* bd_addr, 80 int local_role, int remote_role) { 81 debug("state:%d, local_role:%d, remote_role:%d", state, local_role, 82 remote_role); 83 if (mCallbacksObj == NULL) { 84 error("Callbacks Obj is NULL: '%s", __func__); 85 return; 86 } 87 CallbackEnv sCallbackEnv(__func__); 88 if (!sCallbackEnv.valid()) return; 89 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); 90 if (!addr.get()) { 91 error("Fail to new jbyteArray bd addr for PAN channel state"); 92 return; 93 } 94 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, 95 addr.get(), (jint)state, (jint)error, 96 (jint)local_role, (jint)remote_role); 97} 98 99static btpan_callbacks_t sBluetoothPanCallbacks = { 100 sizeof(sBluetoothPanCallbacks), control_state_callback, 101 connection_state_callback}; 102 103// Define native functions 104 105static void classInitNative(JNIEnv* env, jclass clazz) { 106 method_onConnectStateChanged = 107 env->GetMethodID(clazz, "onConnectStateChanged", "([BIIII)V"); 108 method_onControlStateChanged = env->GetMethodID( 109 clazz, "onControlStateChanged", "(IIILjava/lang/String;)V"); 110 111 info("succeeds"); 112} 113static const bt_interface_t* btIf; 114 115static void initializeNative(JNIEnv* env, jobject object) { 116 debug("pan"); 117 if (btIf) return; 118 119 btIf = getBluetoothInterface(); 120 if (btIf == NULL) { 121 error("Bluetooth module is not loaded"); 122 return; 123 } 124 125 if (sPanIf != NULL) { 126 ALOGW("Cleaning up Bluetooth PAN Interface before initializing..."); 127 sPanIf->cleanup(); 128 sPanIf = NULL; 129 } 130 131 if (mCallbacksObj != NULL) { 132 ALOGW("Cleaning up Bluetooth PAN callback object"); 133 env->DeleteGlobalRef(mCallbacksObj); 134 mCallbacksObj = NULL; 135 } 136 137 sPanIf = (btpan_interface_t*)btIf->get_profile_interface(BT_PROFILE_PAN_ID); 138 if (sPanIf == NULL) { 139 error("Failed to get Bluetooth PAN Interface"); 140 return; 141 } 142 143 mCallbacksObj = env->NewGlobalRef(object); 144 145 bt_status_t status = sPanIf->init(&sBluetoothPanCallbacks); 146 if (status != BT_STATUS_SUCCESS) { 147 error("Failed to initialize Bluetooth PAN, status: %d", status); 148 sPanIf = NULL; 149 if (mCallbacksObj != NULL) { 150 ALOGW("initialization failed: Cleaning up Bluetooth PAN callback object"); 151 env->DeleteGlobalRef(mCallbacksObj); 152 mCallbacksObj = NULL; 153 } 154 return; 155 } 156} 157 158static void cleanupNative(JNIEnv* env, jobject object) { 159 if (!btIf) return; 160 161 if (sPanIf != NULL) { 162 ALOGW("Cleaning up Bluetooth PAN Interface..."); 163 sPanIf->cleanup(); 164 sPanIf = NULL; 165 } 166 167 if (mCallbacksObj != NULL) { 168 ALOGW("Cleaning up Bluetooth PAN callback object"); 169 env->DeleteGlobalRef(mCallbacksObj); 170 mCallbacksObj = NULL; 171 } 172 btIf = NULL; 173} 174 175static jboolean enablePanNative(JNIEnv* env, jobject object, jint local_role) { 176 bt_status_t status = BT_STATUS_FAIL; 177 debug("in"); 178 if (sPanIf) status = sPanIf->enable(local_role); 179 debug("out"); 180 return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE; 181} 182static jint getPanLocalRoleNative(JNIEnv* env, jobject object) { 183 debug("in"); 184 int local_role = 0; 185 if (sPanIf) local_role = sPanIf->get_local_role(); 186 debug("out"); 187 return (jint)local_role; 188} 189 190static jboolean connectPanNative(JNIEnv* env, jobject object, 191 jbyteArray address, jint src_role, 192 jint dest_role) { 193 debug("in"); 194 if (!sPanIf) return JNI_FALSE; 195 196 jbyte* addr = env->GetByteArrayElements(address, NULL); 197 if (!addr) { 198 error("Bluetooth device address null"); 199 return JNI_FALSE; 200 } 201 202 jboolean ret = JNI_TRUE; 203 bt_status_t status = sPanIf->connect((bt_bdaddr_t*)addr, src_role, dest_role); 204 if (status != BT_STATUS_SUCCESS) { 205 error("Failed PAN channel connection, status: %d", status); 206 ret = JNI_FALSE; 207 } 208 env->ReleaseByteArrayElements(address, addr, 0); 209 210 return ret; 211} 212 213static jboolean disconnectPanNative(JNIEnv* env, jobject object, 214 jbyteArray address) { 215 if (!sPanIf) return JNI_FALSE; 216 217 jbyte* addr = env->GetByteArrayElements(address, NULL); 218 if (!addr) { 219 error("Bluetooth device address null"); 220 return JNI_FALSE; 221 } 222 223 jboolean ret = JNI_TRUE; 224 bt_status_t status = sPanIf->disconnect((bt_bdaddr_t*)addr); 225 if (status != BT_STATUS_SUCCESS) { 226 error("Failed disconnect pan channel, status: %d", status); 227 ret = JNI_FALSE; 228 } 229 env->ReleaseByteArrayElements(address, addr, 0); 230 231 return ret; 232} 233 234static JNINativeMethod sMethods[] = { 235 {"classInitNative", "()V", (void*)classInitNative}, 236 {"initializeNative", "()V", (void*)initializeNative}, 237 {"cleanupNative", "()V", (void*)cleanupNative}, 238 {"connectPanNative", "([BII)Z", (void*)connectPanNative}, 239 {"enablePanNative", "(I)Z", (void*)enablePanNative}, 240 {"getPanLocalRoleNative", "()I", (void*)getPanLocalRoleNative}, 241 {"disconnectPanNative", "([B)Z", (void*)disconnectPanNative}, 242 // TBD cleanup 243}; 244 245int register_com_android_bluetooth_pan(JNIEnv* env) { 246 return jniRegisterNativeMethods(env, "com/android/bluetooth/pan/PanService", 247 sMethods, NELEM(sMethods)); 248} 249} 250