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