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