Home | History | Annotate | Download | only in jni
      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 
     39 namespace android {
     40 
     41 static jmethodID method_onConnectStateChanged;
     42 static jmethodID method_onControlStateChanged;
     43 
     44 static const btpan_interface_t* sPanIf = NULL;
     45 static jobject mCallbacksObj = NULL;
     46 
     47 static jbyteArray marshall_bda(const RawAddress* bd_addr) {
     48   CallbackEnv sCallbackEnv(__func__);
     49   if (!sCallbackEnv.valid()) return NULL;
     50 
     51   jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
     52   if (!addr) {
     53     ALOGE("Fail to new jbyteArray bd addr");
     54     return NULL;
     55   }
     56   sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
     57                                    (jbyte*)bd_addr);
     58   return addr;
     59 }
     60 
     61 static 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 
     77 static void connection_state_callback(btpan_connection_state_t state,
     78                                       bt_status_t error,
     79                                       const RawAddress* bd_addr, int local_role,
     80                                       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 
     99 static btpan_callbacks_t sBluetoothPanCallbacks = {
    100     sizeof(sBluetoothPanCallbacks), control_state_callback,
    101     connection_state_callback};
    102 
    103 // Define native functions
    104 
    105 static 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 }
    113 static const bt_interface_t* btIf;
    114 
    115 static 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 
    158 static 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 
    175 static 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 }
    182 static 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 
    190 static 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((RawAddress*)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 
    213 static 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((RawAddress*)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 
    234 static 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 
    245 int register_com_android_bluetooth_pan(JNIEnv* env) {
    246   return jniRegisterNativeMethods(env, "com/android/bluetooth/pan/PanService",
    247                                   sMethods, NELEM(sMethods));
    248 }
    249 }
    250