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