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