Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2015 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 "BluetoothSdpJni"
     18 
     19 #define LOG_NDEBUG 0
     20 
     21 #include "android_runtime/AndroidRuntime.h"
     22 #include "com_android_bluetooth.h"
     23 #include "hardware/bt_sdp.h"
     24 #include "utils/Log.h"
     25 
     26 #include <string.h>
     27 
     28 using bluetooth::Uuid;
     29 
     30 static const Uuid UUID_OBEX_OBJECT_PUSH = Uuid::From16Bit(0x1105);
     31 static const Uuid UUID_PBAP_PSE = Uuid::From16Bit(0x112F);
     32 static const Uuid UUID_MAP_MAS = Uuid::From16Bit(0x1132);
     33 static const Uuid UUID_MAP_MNS = Uuid::From16Bit(0x1133);
     34 static const Uuid UUID_SAP = Uuid::From16Bit(0x112D);
     35 
     36 namespace android {
     37 static jmethodID method_sdpRecordFoundCallback;
     38 static jmethodID method_sdpMasRecordFoundCallback;
     39 static jmethodID method_sdpMnsRecordFoundCallback;
     40 static jmethodID method_sdpPseRecordFoundCallback;
     41 static jmethodID method_sdpOppOpsRecordFoundCallback;
     42 static jmethodID method_sdpSapsRecordFoundCallback;
     43 
     44 static const btsdp_interface_t* sBluetoothSdpInterface = NULL;
     45 
     46 static void sdp_search_callback(bt_status_t status, const RawAddress& bd_addr,
     47                                 const Uuid& uuid_in, int record_size,
     48                                 bluetooth_sdp_record* record);
     49 
     50 btsdp_callbacks_t sBluetoothSdpCallbacks = {sizeof(sBluetoothSdpCallbacks),
     51                                             sdp_search_callback};
     52 
     53 static jobject sCallbacksObj = NULL;
     54 
     55 static void initializeNative(JNIEnv* env, jobject object) {
     56   const bt_interface_t* btInf = getBluetoothInterface();
     57 
     58   if (btInf == NULL) {
     59     ALOGE("Bluetooth module is not loaded");
     60     return;
     61   }
     62   if (sBluetoothSdpInterface != NULL) {
     63     ALOGW("Cleaning up Bluetooth SDP Interface before initializing...");
     64     sBluetoothSdpInterface->deinit();
     65     sBluetoothSdpInterface = NULL;
     66   }
     67 
     68   sBluetoothSdpInterface = (btsdp_interface_t*)btInf->get_profile_interface(
     69       BT_PROFILE_SDP_CLIENT_ID);
     70   if (sBluetoothSdpInterface == NULL) {
     71     ALOGE("Error getting SDP client interface");
     72   } else {
     73     sBluetoothSdpInterface->init(&sBluetoothSdpCallbacks);
     74   }
     75 
     76   sCallbacksObj = env->NewGlobalRef(object);
     77 }
     78 
     79 static void classInitNative(JNIEnv* env, jclass clazz) {
     80   /* generic SDP record (raw data)*/
     81   method_sdpRecordFoundCallback =
     82       env->GetMethodID(clazz, "sdpRecordFoundCallback", "(I[B[BI[B)V");
     83 
     84   /* MAS SDP record*/
     85   method_sdpMasRecordFoundCallback = env->GetMethodID(
     86       clazz, "sdpMasRecordFoundCallback", "(I[B[BIIIIIILjava/lang/String;Z)V");
     87   /* MNS SDP record*/
     88   method_sdpMnsRecordFoundCallback = env->GetMethodID(
     89       clazz, "sdpMnsRecordFoundCallback", "(I[B[BIIIILjava/lang/String;Z)V");
     90   /* PBAP PSE record */
     91   method_sdpPseRecordFoundCallback = env->GetMethodID(
     92       clazz, "sdpPseRecordFoundCallback", "(I[B[BIIIIILjava/lang/String;Z)V");
     93   /* OPP Server record */
     94   method_sdpOppOpsRecordFoundCallback =
     95       env->GetMethodID(clazz, "sdpOppOpsRecordFoundCallback",
     96                        "(I[B[BIIILjava/lang/String;[BZ)V");
     97   /* SAP Server record */
     98   method_sdpSapsRecordFoundCallback = env->GetMethodID(
     99       clazz, "sdpSapsRecordFoundCallback", "(I[B[BIILjava/lang/String;Z)V");
    100 }
    101 
    102 static jboolean sdpSearchNative(JNIEnv* env, jobject obj, jbyteArray address,
    103                                 jbyteArray uuidObj) {
    104   ALOGD("%s", __func__);
    105 
    106   if (!sBluetoothSdpInterface) return JNI_FALSE;
    107 
    108   jbyte* addr = env->GetByteArrayElements(address, NULL);
    109   if (addr == NULL) {
    110     jniThrowIOException(env, EINVAL);
    111     return JNI_FALSE;
    112   }
    113 
    114   jbyte* uuid = env->GetByteArrayElements(uuidObj, NULL);
    115   if (!uuid) {
    116     ALOGE("failed to get uuid");
    117     env->ReleaseByteArrayElements(address, addr, 0);
    118     return JNI_FALSE;
    119   }
    120   ALOGD("%s UUID %.*s", __func__, 16, (uint8_t*)uuid);
    121 
    122   int ret = sBluetoothSdpInterface->sdp_search(
    123       (RawAddress*)addr, Uuid::From128BitBE((uint8_t*)uuid));
    124   if (ret != BT_STATUS_SUCCESS) {
    125     ALOGE("SDP Search initialization failed: %d", ret);
    126   }
    127 
    128   if (addr) env->ReleaseByteArrayElements(address, addr, 0);
    129   if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
    130   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    131 }
    132 
    133 static void sdp_search_callback(bt_status_t status, const RawAddress& bd_addr,
    134                                 const Uuid& uuid_in, int count,
    135                                 bluetooth_sdp_record* records) {
    136   CallbackEnv sCallbackEnv(__func__);
    137   if (!sCallbackEnv.valid()) return;
    138 
    139   ScopedLocalRef<jbyteArray> addr(
    140       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    141   if (!addr.get()) return;
    142 
    143   ScopedLocalRef<jbyteArray> uuid(sCallbackEnv.get(),
    144                                   sCallbackEnv->NewByteArray(sizeof(Uuid)));
    145   if (!uuid.get()) return;
    146 
    147   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
    148                                    (const jbyte*)&bd_addr);
    149   sCallbackEnv->SetByteArrayRegion(uuid.get(), 0, sizeof(Uuid),
    150                                    (const jbyte*)uuid_in.To128BitBE().data());
    151 
    152   ALOGD("%s: Status is: %d, Record count: %d", __func__, status, count);
    153 
    154   // Ensure we run the loop at least once, to also signal errors if they occur
    155   for (int i = 0; i < count || i == 0; i++) {
    156     bool more_results = (i < (count - 1)) ? true : false;
    157     bluetooth_sdp_record* record = &records[i];
    158     ScopedLocalRef<jstring> service_name(sCallbackEnv.get(), NULL);
    159     if (record->hdr.service_name_length > 0) {
    160       ALOGD("%s, ServiceName:  %s", __func__, record->mas.hdr.service_name);
    161       service_name.reset(
    162           (jstring)sCallbackEnv->NewStringUTF(record->mas.hdr.service_name));
    163     }
    164 
    165     /* call the right callback according to the uuid*/
    166     if (uuid_in == UUID_MAP_MAS) {
    167       sCallbackEnv->CallVoidMethod(
    168           sCallbacksObj, method_sdpMasRecordFoundCallback, (jint)status,
    169           addr.get(), uuid.get(), (jint)record->mas.mas_instance_id,
    170           (jint)record->mas.hdr.l2cap_psm,
    171           (jint)record->mas.hdr.rfcomm_channel_number,
    172           (jint)record->mas.hdr.profile_version,
    173           (jint)record->mas.supported_features,
    174           (jint)record->mas.supported_message_types, service_name.get(),
    175           more_results);
    176 
    177     } else if (uuid_in == UUID_MAP_MNS) {
    178       sCallbackEnv->CallVoidMethod(
    179           sCallbacksObj, method_sdpMnsRecordFoundCallback, (jint)status,
    180           addr.get(), uuid.get(), (jint)record->mns.hdr.l2cap_psm,
    181           (jint)record->mns.hdr.rfcomm_channel_number,
    182           (jint)record->mns.hdr.profile_version,
    183           (jint)record->mns.supported_features, service_name.get(),
    184           more_results);
    185 
    186     } else if (uuid_in == UUID_PBAP_PSE) {
    187       sCallbackEnv->CallVoidMethod(
    188           sCallbacksObj, method_sdpPseRecordFoundCallback, (jint)status,
    189           addr.get(), uuid.get(), (jint)record->pse.hdr.l2cap_psm,
    190           (jint)record->pse.hdr.rfcomm_channel_number,
    191           (jint)record->pse.hdr.profile_version,
    192           (jint)record->pse.supported_features,
    193           (jint)record->pse.supported_repositories, service_name.get(),
    194           more_results);
    195 
    196     } else if (uuid_in == UUID_OBEX_OBJECT_PUSH) {
    197       jint formats_list_size = record->ops.supported_formats_list_len;
    198       ScopedLocalRef<jbyteArray> formats_list(
    199           sCallbackEnv.get(), sCallbackEnv->NewByteArray(formats_list_size));
    200       if (!formats_list.get()) return;
    201       sCallbackEnv->SetByteArrayRegion(
    202           formats_list.get(), 0, formats_list_size,
    203           (jbyte*)record->ops.supported_formats_list);
    204 
    205       sCallbackEnv->CallVoidMethod(
    206           sCallbacksObj, method_sdpOppOpsRecordFoundCallback, (jint)status,
    207           addr.get(), uuid.get(), (jint)record->ops.hdr.l2cap_psm,
    208           (jint)record->ops.hdr.rfcomm_channel_number,
    209           (jint)record->ops.hdr.profile_version, service_name.get(),
    210           formats_list.get(), more_results);
    211 
    212     } else if (uuid_in == UUID_SAP) {
    213       sCallbackEnv->CallVoidMethod(
    214           sCallbacksObj, method_sdpSapsRecordFoundCallback, (jint)status,
    215           addr.get(), uuid.get(), (jint)record->mas.hdr.rfcomm_channel_number,
    216           (jint)record->mas.hdr.profile_version, service_name.get(),
    217           more_results);
    218     } else {
    219       // we don't have a wrapper for this uuid, send as raw data
    220       jint record_data_size = record->hdr.user1_ptr_len;
    221       ScopedLocalRef<jbyteArray> record_data(
    222           sCallbackEnv.get(), sCallbackEnv->NewByteArray(record_data_size));
    223       if (!record_data.get()) return;
    224 
    225       sCallbackEnv->SetByteArrayRegion(record_data.get(), 0, record_data_size,
    226                                        (jbyte*)record->hdr.user1_ptr);
    227       sCallbackEnv->CallVoidMethod(sCallbacksObj, method_sdpRecordFoundCallback,
    228                                    (jint)status, addr.get(), uuid.get(),
    229                                    record_data_size, record_data.get());
    230     }
    231   }  // End of for-loop
    232 }
    233 
    234 static jint sdpCreateMapMasRecordNative(JNIEnv* env, jobject obj,
    235                                         jstring name_str, jint mas_id, jint scn,
    236                                         jint l2cap_psm, jint version,
    237                                         jint msg_types, jint features) {
    238   ALOGD("%s", __func__);
    239   if (!sBluetoothSdpInterface) return -1;
    240 
    241   bluetooth_sdp_record record = {};  // Must be zero initialized
    242   record.mas.hdr.type = SDP_TYPE_MAP_MAS;
    243 
    244   const char* service_name = NULL;
    245   if (name_str != NULL) {
    246     service_name = env->GetStringUTFChars(name_str, NULL);
    247     record.mas.hdr.service_name = (char*)service_name;
    248     record.mas.hdr.service_name_length = strlen(service_name);
    249   } else {
    250     record.mas.hdr.service_name = NULL;
    251     record.mas.hdr.service_name_length = 0;
    252   }
    253   record.mas.hdr.rfcomm_channel_number = scn;
    254   record.mas.hdr.l2cap_psm = l2cap_psm;
    255   record.mas.hdr.profile_version = version;
    256 
    257   record.mas.mas_instance_id = mas_id;
    258   record.mas.supported_features = features;
    259   record.mas.supported_message_types = msg_types;
    260 
    261   int handle = -1;
    262   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
    263   if (ret != BT_STATUS_SUCCESS) {
    264     ALOGE("SDP Create record failed: %d", ret);
    265   } else {
    266     ALOGD("SDP Create record success - handle: %d", handle);
    267   }
    268 
    269   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
    270   return handle;
    271 }
    272 
    273 static jint sdpCreateMapMnsRecordNative(JNIEnv* env, jobject obj,
    274                                         jstring name_str, jint scn,
    275                                         jint l2cap_psm, jint version,
    276                                         jint features) {
    277   ALOGD("%s", __func__);
    278   if (!sBluetoothSdpInterface) return -1;
    279 
    280   bluetooth_sdp_record record = {};  // Must be zero initialized
    281   record.mns.hdr.type = SDP_TYPE_MAP_MNS;
    282 
    283   const char* service_name = NULL;
    284   if (name_str != NULL) {
    285     service_name = env->GetStringUTFChars(name_str, NULL);
    286     record.mns.hdr.service_name = (char*)service_name;
    287     record.mns.hdr.service_name_length = strlen(service_name);
    288   } else {
    289     record.mns.hdr.service_name = NULL;
    290     record.mns.hdr.service_name_length = 0;
    291   }
    292   record.mns.hdr.rfcomm_channel_number = scn;
    293   record.mns.hdr.l2cap_psm = l2cap_psm;
    294   record.mns.hdr.profile_version = version;
    295 
    296   record.mns.supported_features = features;
    297 
    298   int handle = -1;
    299   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
    300   if (ret != BT_STATUS_SUCCESS) {
    301     ALOGE("SDP Create record failed: %d", ret);
    302   } else {
    303     ALOGD("SDP Create record success - handle: %d", handle);
    304   }
    305 
    306   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
    307   return handle;
    308 }
    309 
    310 static jint sdpCreatePbapPseRecordNative(JNIEnv* env, jobject obj,
    311                                          jstring name_str, jint scn,
    312                                          jint l2cap_psm, jint version,
    313                                          jint supported_repositories,
    314                                          jint features) {
    315   ALOGD("%s", __func__);
    316   if (!sBluetoothSdpInterface) return -1;
    317 
    318   bluetooth_sdp_record record = {};  // Must be zero initialized
    319   record.pse.hdr.type = SDP_TYPE_PBAP_PSE;
    320 
    321   const char* service_name = NULL;
    322   if (name_str != NULL) {
    323     service_name = env->GetStringUTFChars(name_str, NULL);
    324     record.pse.hdr.service_name = (char*)service_name;
    325     record.pse.hdr.service_name_length = strlen(service_name);
    326   } else {
    327     record.pse.hdr.service_name = NULL;
    328     record.pse.hdr.service_name_length = 0;
    329   }
    330   record.pse.hdr.rfcomm_channel_number = scn;
    331   record.pse.hdr.l2cap_psm = l2cap_psm;
    332   record.pse.hdr.profile_version = version;
    333 
    334   record.pse.supported_features = features;
    335   record.pse.supported_repositories = supported_repositories;
    336 
    337   int handle = -1;
    338   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
    339   if (ret != BT_STATUS_SUCCESS) {
    340     ALOGE("SDP Create record failed: %d", ret);
    341   } else {
    342     ALOGD("SDP Create record success - handle: %d", handle);
    343   }
    344 
    345   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
    346   return handle;
    347 }
    348 
    349 static jint sdpCreateOppOpsRecordNative(JNIEnv* env, jobject obj,
    350                                         jstring name_str, jint scn,
    351                                         jint l2cap_psm, jint version,
    352                                         jbyteArray supported_formats_list) {
    353   ALOGD("%s", __func__);
    354   if (!sBluetoothSdpInterface) return -1;
    355 
    356   bluetooth_sdp_record record = {};  // Must be zero initialized
    357   record.ops.hdr.type = SDP_TYPE_OPP_SERVER;
    358 
    359   const char* service_name = NULL;
    360   if (name_str != NULL) {
    361     service_name = env->GetStringUTFChars(name_str, NULL);
    362     record.ops.hdr.service_name = (char*)service_name;
    363     record.ops.hdr.service_name_length = strlen(service_name);
    364   } else {
    365     record.ops.hdr.service_name = NULL;
    366     record.ops.hdr.service_name_length = 0;
    367   }
    368   record.ops.hdr.rfcomm_channel_number = scn;
    369   record.ops.hdr.l2cap_psm = l2cap_psm;
    370   record.ops.hdr.profile_version = version;
    371 
    372   int formats_list_len = 0;
    373   jbyte* formats_list = env->GetByteArrayElements(supported_formats_list, NULL);
    374   if (formats_list != NULL) {
    375     formats_list_len = env->GetArrayLength(supported_formats_list);
    376     if (formats_list_len > SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH) {
    377       formats_list_len = SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH;
    378     }
    379     memcpy(record.ops.supported_formats_list, formats_list, formats_list_len);
    380   }
    381 
    382   record.ops.supported_formats_list_len = formats_list_len;
    383 
    384   int handle = -1;
    385   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
    386   if (ret != BT_STATUS_SUCCESS) {
    387     ALOGE("SDP Create record failed: %d", ret);
    388   } else {
    389     ALOGD("SDP Create record success - handle: %d", handle);
    390   }
    391 
    392   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
    393   if (formats_list)
    394     env->ReleaseByteArrayElements(supported_formats_list, formats_list, 0);
    395   return handle;
    396 }
    397 
    398 static jint sdpCreateSapsRecordNative(JNIEnv* env, jobject obj,
    399                                       jstring name_str, jint scn,
    400                                       jint version) {
    401   ALOGD("%s", __func__);
    402   if (!sBluetoothSdpInterface) return -1;
    403 
    404   bluetooth_sdp_record record = {};  // Must be zero initialized
    405   record.sap.hdr.type = SDP_TYPE_SAP_SERVER;
    406 
    407   const char* service_name = NULL;
    408   if (name_str != NULL) {
    409     service_name = env->GetStringUTFChars(name_str, NULL);
    410     record.mas.hdr.service_name = (char*)service_name;
    411     record.mas.hdr.service_name_length = strlen(service_name);
    412   } else {
    413     record.mas.hdr.service_name = NULL;
    414     record.mas.hdr.service_name_length = 0;
    415   }
    416   record.mas.hdr.rfcomm_channel_number = scn;
    417   record.mas.hdr.profile_version = version;
    418 
    419   int handle = -1;
    420   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
    421   if (ret != BT_STATUS_SUCCESS) {
    422     ALOGE("SDP Create record failed: %d", ret);
    423   } else {
    424     ALOGD("SDP Create record success - handle: %d", handle);
    425   }
    426 
    427   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
    428   return handle;
    429 }
    430 
    431 static jboolean sdpRemoveSdpRecordNative(JNIEnv* env, jobject obj,
    432                                          jint record_id) {
    433   ALOGD("%s", __func__);
    434   if (!sBluetoothSdpInterface) return false;
    435 
    436   int ret = sBluetoothSdpInterface->remove_sdp_record(record_id);
    437   if (ret != BT_STATUS_SUCCESS) {
    438     ALOGE("SDP Remove record failed: %d", ret);
    439     return false;
    440   }
    441 
    442   ALOGD("SDP Remove record success - handle: %d", record_id);
    443   return true;
    444 }
    445 
    446 static void cleanupNative(JNIEnv* env, jobject object) {
    447   const bt_interface_t* btInf = getBluetoothInterface();
    448 
    449   if (btInf == NULL) {
    450     ALOGE("Bluetooth module is not loaded");
    451     return;
    452   }
    453 
    454   if (sBluetoothSdpInterface != NULL) {
    455     ALOGW("Cleaning up Bluetooth SDP Interface...");
    456     sBluetoothSdpInterface->deinit();
    457     sBluetoothSdpInterface = NULL;
    458   }
    459 
    460   if (sCallbacksObj != NULL) {
    461     ALOGW("Cleaning up Bluetooth SDP object");
    462     env->DeleteGlobalRef(sCallbacksObj);
    463     sCallbacksObj = NULL;
    464   }
    465 }
    466 
    467 static JNINativeMethod sMethods[] = {
    468     /* name, signature, funcPtr */
    469     {"classInitNative", "()V", (void*)classInitNative},
    470     {"initializeNative", "()V", (void*)initializeNative},
    471     {"cleanupNative", "()V", (void*)cleanupNative},
    472     {"sdpSearchNative", "([B[B)Z", (void*)sdpSearchNative},
    473     {"sdpCreateMapMasRecordNative", "(Ljava/lang/String;IIIIII)I",
    474      (void*)sdpCreateMapMasRecordNative},
    475     {"sdpCreateMapMnsRecordNative", "(Ljava/lang/String;IIII)I",
    476      (void*)sdpCreateMapMnsRecordNative},
    477     {"sdpCreatePbapPseRecordNative", "(Ljava/lang/String;IIIII)I",
    478      (void*)sdpCreatePbapPseRecordNative},
    479     {"sdpCreateOppOpsRecordNative", "(Ljava/lang/String;III[B)I",
    480      (void*)sdpCreateOppOpsRecordNative},
    481     {"sdpCreateSapsRecordNative", "(Ljava/lang/String;II)I",
    482      (void*)sdpCreateSapsRecordNative},
    483     {"sdpRemoveSdpRecordNative", "(I)Z", (void*)sdpRemoveSdpRecordNative}};
    484 
    485 int register_com_android_bluetooth_sdp(JNIEnv* env) {
    486   return jniRegisterNativeMethods(env, "com/android/bluetooth/sdp/SdpManager",
    487                                   sMethods, NELEM(sMethods));
    488 }
    489 }
    490