• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
initializeNative(JNIEnv * env,jobject object)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 
classInitNative(JNIEnv * env,jclass clazz)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 
sdpSearchNative(JNIEnv * env,jobject obj,jbyteArray address,jbyteArray uuidObj)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 
sdp_search_callback(bt_status_t status,const RawAddress & bd_addr,const Uuid & uuid_in,int count,bluetooth_sdp_record * records)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 
sdpCreateMapMasRecordNative(JNIEnv * env,jobject obj,jstring name_str,jint mas_id,jint scn,jint l2cap_psm,jint version,jint msg_types,jint features)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 
sdpCreateMapMnsRecordNative(JNIEnv * env,jobject obj,jstring name_str,jint scn,jint l2cap_psm,jint version,jint features)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 
sdpCreatePbapPceRecordNative(JNIEnv * env,jobject obj,jstring name_str,jint version)310 static jint sdpCreatePbapPceRecordNative(JNIEnv* env, jobject obj,
311                                          jstring name_str, jint version) {
312   ALOGD("%s", __func__);
313   if (!sBluetoothSdpInterface) return -1;
314 
315   bluetooth_sdp_record record = {};  // Must be zero initialized
316   record.pce.hdr.type = SDP_TYPE_PBAP_PCE;
317 
318   const char* service_name = NULL;
319   if (name_str != NULL) {
320     service_name = env->GetStringUTFChars(name_str, NULL);
321     record.pce.hdr.service_name = (char*)service_name;
322     record.pce.hdr.service_name_length = strlen(service_name);
323   } else {
324     record.pce.hdr.service_name = NULL;
325     record.pce.hdr.service_name_length = 0;
326   }
327   record.pce.hdr.profile_version = version;
328 
329   int handle = -1;
330   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
331   if (ret != BT_STATUS_SUCCESS) {
332     ALOGE("SDP Create record failed: %d", ret);
333   } else {
334     ALOGD("SDP Create record success - handle: %d", handle);
335   }
336 
337   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
338   return handle;
339 }
340 
sdpCreatePbapPseRecordNative(JNIEnv * env,jobject obj,jstring name_str,jint scn,jint l2cap_psm,jint version,jint supported_repositories,jint features)341 static jint sdpCreatePbapPseRecordNative(JNIEnv* env, jobject obj,
342                                          jstring name_str, jint scn,
343                                          jint l2cap_psm, jint version,
344                                          jint supported_repositories,
345                                          jint features) {
346   ALOGD("%s", __func__);
347   if (!sBluetoothSdpInterface) return -1;
348 
349   bluetooth_sdp_record record = {};  // Must be zero initialized
350   record.pse.hdr.type = SDP_TYPE_PBAP_PSE;
351 
352   const char* service_name = NULL;
353   if (name_str != NULL) {
354     service_name = env->GetStringUTFChars(name_str, NULL);
355     record.pse.hdr.service_name = (char*)service_name;
356     record.pse.hdr.service_name_length = strlen(service_name);
357   } else {
358     record.pse.hdr.service_name = NULL;
359     record.pse.hdr.service_name_length = 0;
360   }
361   record.pse.hdr.rfcomm_channel_number = scn;
362   record.pse.hdr.l2cap_psm = l2cap_psm;
363   record.pse.hdr.profile_version = version;
364 
365   record.pse.supported_features = features;
366   record.pse.supported_repositories = supported_repositories;
367 
368   int handle = -1;
369   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
370   if (ret != BT_STATUS_SUCCESS) {
371     ALOGE("SDP Create record failed: %d", ret);
372   } else {
373     ALOGD("SDP Create record success - handle: %d", handle);
374   }
375 
376   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
377   return handle;
378 }
379 
sdpCreateOppOpsRecordNative(JNIEnv * env,jobject obj,jstring name_str,jint scn,jint l2cap_psm,jint version,jbyteArray supported_formats_list)380 static jint sdpCreateOppOpsRecordNative(JNIEnv* env, jobject obj,
381                                         jstring name_str, jint scn,
382                                         jint l2cap_psm, jint version,
383                                         jbyteArray supported_formats_list) {
384   ALOGD("%s", __func__);
385   if (!sBluetoothSdpInterface) return -1;
386 
387   bluetooth_sdp_record record = {};  // Must be zero initialized
388   record.ops.hdr.type = SDP_TYPE_OPP_SERVER;
389 
390   const char* service_name = NULL;
391   if (name_str != NULL) {
392     service_name = env->GetStringUTFChars(name_str, NULL);
393     record.ops.hdr.service_name = (char*)service_name;
394     record.ops.hdr.service_name_length = strlen(service_name);
395   } else {
396     record.ops.hdr.service_name = NULL;
397     record.ops.hdr.service_name_length = 0;
398   }
399   record.ops.hdr.rfcomm_channel_number = scn;
400   record.ops.hdr.l2cap_psm = l2cap_psm;
401   record.ops.hdr.profile_version = version;
402 
403   int formats_list_len = 0;
404   jbyte* formats_list = env->GetByteArrayElements(supported_formats_list, NULL);
405   if (formats_list != NULL) {
406     formats_list_len = env->GetArrayLength(supported_formats_list);
407     if (formats_list_len > SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH) {
408       formats_list_len = SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH;
409     }
410     memcpy(record.ops.supported_formats_list, formats_list, formats_list_len);
411   }
412 
413   record.ops.supported_formats_list_len = formats_list_len;
414 
415   int handle = -1;
416   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
417   if (ret != BT_STATUS_SUCCESS) {
418     ALOGE("SDP Create record failed: %d", ret);
419   } else {
420     ALOGD("SDP Create record success - handle: %d", handle);
421   }
422 
423   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
424   if (formats_list)
425     env->ReleaseByteArrayElements(supported_formats_list, formats_list, 0);
426   return handle;
427 }
428 
sdpCreateSapsRecordNative(JNIEnv * env,jobject obj,jstring name_str,jint scn,jint version)429 static jint sdpCreateSapsRecordNative(JNIEnv* env, jobject obj,
430                                       jstring name_str, jint scn,
431                                       jint version) {
432   ALOGD("%s", __func__);
433   if (!sBluetoothSdpInterface) return -1;
434 
435   bluetooth_sdp_record record = {};  // Must be zero initialized
436   record.sap.hdr.type = SDP_TYPE_SAP_SERVER;
437 
438   const char* service_name = NULL;
439   if (name_str != NULL) {
440     service_name = env->GetStringUTFChars(name_str, NULL);
441     record.mas.hdr.service_name = (char*)service_name;
442     record.mas.hdr.service_name_length = strlen(service_name);
443   } else {
444     record.mas.hdr.service_name = NULL;
445     record.mas.hdr.service_name_length = 0;
446   }
447   record.mas.hdr.rfcomm_channel_number = scn;
448   record.mas.hdr.profile_version = version;
449 
450   int handle = -1;
451   int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle);
452   if (ret != BT_STATUS_SUCCESS) {
453     ALOGE("SDP Create record failed: %d", ret);
454   } else {
455     ALOGD("SDP Create record success - handle: %d", handle);
456   }
457 
458   if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
459   return handle;
460 }
461 
sdpRemoveSdpRecordNative(JNIEnv * env,jobject obj,jint record_id)462 static jboolean sdpRemoveSdpRecordNative(JNIEnv* env, jobject obj,
463                                          jint record_id) {
464   ALOGD("%s", __func__);
465   if (!sBluetoothSdpInterface) return false;
466 
467   int ret = sBluetoothSdpInterface->remove_sdp_record(record_id);
468   if (ret != BT_STATUS_SUCCESS) {
469     ALOGE("SDP Remove record failed: %d", ret);
470     return false;
471   }
472 
473   ALOGD("SDP Remove record success - handle: %d", record_id);
474   return true;
475 }
476 
cleanupNative(JNIEnv * env,jobject object)477 static void cleanupNative(JNIEnv* env, jobject object) {
478   const bt_interface_t* btInf = getBluetoothInterface();
479 
480   if (btInf == NULL) {
481     ALOGE("Bluetooth module is not loaded");
482     return;
483   }
484 
485   if (sBluetoothSdpInterface != NULL) {
486     ALOGW("Cleaning up Bluetooth SDP Interface...");
487     sBluetoothSdpInterface->deinit();
488     sBluetoothSdpInterface = NULL;
489   }
490 
491   if (sCallbacksObj != NULL) {
492     ALOGW("Cleaning up Bluetooth SDP object");
493     env->DeleteGlobalRef(sCallbacksObj);
494     sCallbacksObj = NULL;
495   }
496 }
497 
498 static JNINativeMethod sMethods[] = {
499     /* name, signature, funcPtr */
500     {"classInitNative", "()V", (void*)classInitNative},
501     {"initializeNative", "()V", (void*)initializeNative},
502     {"cleanupNative", "()V", (void*)cleanupNative},
503     {"sdpSearchNative", "([B[B)Z", (void*)sdpSearchNative},
504     {"sdpCreateMapMasRecordNative", "(Ljava/lang/String;IIIIII)I",
505      (void*)sdpCreateMapMasRecordNative},
506     {"sdpCreateMapMnsRecordNative", "(Ljava/lang/String;IIII)I",
507      (void*)sdpCreateMapMnsRecordNative},
508     {"sdpCreatePbapPceRecordNative", "(Ljava/lang/String;I)I",
509      (void*)sdpCreatePbapPceRecordNative},
510     {"sdpCreatePbapPseRecordNative", "(Ljava/lang/String;IIIII)I",
511      (void*)sdpCreatePbapPseRecordNative},
512     {"sdpCreateOppOpsRecordNative", "(Ljava/lang/String;III[B)I",
513      (void*)sdpCreateOppOpsRecordNative},
514     {"sdpCreateSapsRecordNative", "(Ljava/lang/String;II)I",
515      (void*)sdpCreateSapsRecordNative},
516     {"sdpRemoveSdpRecordNative", "(I)Z", (void*)sdpRemoveSdpRecordNative}};
517 
register_com_android_bluetooth_sdp(JNIEnv * env)518 int register_com_android_bluetooth_sdp(JNIEnv* env) {
519   return jniRegisterNativeMethods(env, "com/android/bluetooth/sdp/SdpManager",
520                                   sMethods, NELEM(sMethods));
521 }
522 }
523