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