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