1 /* 2 * Copyright 2023 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 package com.android.bluetooth.sdp; 17 18 import com.android.internal.annotations.GuardedBy; 19 import com.android.internal.annotations.VisibleForTesting; 20 21 /** Native interface to be used by SdpManager */ 22 public class SdpManagerNativeInterface { 23 private static final String TAG = SdpManagerNativeInterface.class.getSimpleName(); 24 25 @GuardedBy("INSTANCE_LOCK") 26 private static SdpManagerNativeInterface sInstance; 27 28 private static final Object INSTANCE_LOCK = new Object(); 29 30 private SdpManager mSdpManager; 31 private boolean mNativeAvailable = false; 32 33 /** This class is a singleton because native library should only be loaded once */ getInstance()34 public static SdpManagerNativeInterface getInstance() { 35 synchronized (INSTANCE_LOCK) { 36 if (sInstance == null) { 37 sInstance = new SdpManagerNativeInterface(); 38 } 39 return sInstance; 40 } 41 } 42 43 /** Set singleton instance. */ 44 @VisibleForTesting setInstance(SdpManagerNativeInterface instance)45 public static void setInstance(SdpManagerNativeInterface instance) { 46 synchronized (INSTANCE_LOCK) { 47 sInstance = instance; 48 } 49 } 50 init(SdpManager sdpManager)51 void init(SdpManager sdpManager) { 52 mSdpManager = sdpManager; 53 initializeNative(); 54 mNativeAvailable = true; 55 } 56 cleanup()57 void cleanup() { 58 mNativeAvailable = false; 59 cleanupNative(); 60 } 61 isAvailable()62 public boolean isAvailable() { 63 return mNativeAvailable; 64 } 65 sdpSearch(byte[] address, byte[] uuid)66 void sdpSearch(byte[] address, byte[] uuid) { 67 sdpSearchNative(address, uuid); 68 } 69 70 /** 71 * Create a server side Message Access Profile Service Record. Create the record once, and reuse 72 * it for all connections. If changes to a record is needed remove the old record using {@link 73 * removeSdpRecord} and then create a new one. 74 * 75 * @param serviceName The textual name of the service 76 * @param masId The MAS ID to associate with this SDP record 77 * @param rfcommChannel The RFCOMM channel that clients can connect to (obtain from 78 * BluetoothServerSocket) 79 * @param l2capPsm The L2CAP PSM channel that clients can connect to (obtain from 80 * BluetoothServerSocket) Supply -1 to omit the L2CAP PSM from the record. 81 * @param version The Profile version number (As specified in the Bluetooth MAP specification) 82 * @param msgTypes The supported message types bit mask (As specified in the Bluetooth MAP 83 * specification) 84 * @param features The feature bit mask (As specified in the Bluetooth MAP specification) 85 * @return a handle to the record created. The record can be removed again using {@link 86 * removeSdpRecord}(). The record is not linked to the creation/destruction of 87 * BluetoothSockets, hence SDP record cleanup is a separate process. 88 */ createMapMasRecord( String serviceName, int masId, int rfcommChannel, int l2capPsm, int version, int msgTypes, int features)89 public int createMapMasRecord( 90 String serviceName, 91 int masId, 92 int rfcommChannel, 93 int l2capPsm, 94 int version, 95 int msgTypes, 96 int features) { 97 if (!mNativeAvailable) { 98 throw new RuntimeException(TAG + " mNativeAvailable == false - native not initialized"); 99 } 100 return sdpCreateMapMasRecordNative( 101 serviceName, masId, rfcommChannel, l2capPsm, version, msgTypes, features); 102 } 103 104 /** 105 * Create a client side Message Access Profile Service Record. Create the record once, and reuse 106 * it for all connections. If changes to a record is needed remove the old record using {@link 107 * removeSdpRecord} and then create a new one. 108 * 109 * @param serviceName The textual name of the service 110 * @param rfcommChannel The RFCOMM channel that clients can connect to (obtain from 111 * BluetoothServerSocket) 112 * @param l2capPsm The L2CAP PSM channel that clients can connect to (obtain from 113 * BluetoothServerSocket) Supply -1 to omit the L2CAP PSM from the record. 114 * @param version The Profile version number (As specified in the Bluetooth MAP specification) 115 * @param features The feature bit mask (As specified in the Bluetooth MAP specification) 116 * @return a handle to the record created. The record can be removed again using {@link 117 * removeSdpRecord}(). The record is not linked to the creation/destruction of 118 * BluetoothSockets, hence SDP record cleanup is a separate process. 119 */ createMapMnsRecord( String serviceName, int rfcommChannel, int l2capPsm, int version, int features)120 public int createMapMnsRecord( 121 String serviceName, int rfcommChannel, int l2capPsm, int version, int features) { 122 if (!mNativeAvailable) { 123 throw new RuntimeException(TAG + " mNativeAvailable == false - native not initialized"); 124 } 125 return sdpCreateMapMnsRecordNative(serviceName, rfcommChannel, l2capPsm, version, features); 126 } 127 128 /** 129 * Create a Client side Phone Book Access Profile Service Record. Create the record once, and 130 * reuse it for all connections. If changes to a record is needed remove the old record using 131 * {@link removeSdpRecord} and then create a new one. 132 * 133 * @param serviceName The textual name of the service 134 * @param version The Profile version number (As specified in the Bluetooth PBAP specification) 135 * @return a handle to the record created. The record can be removed again using {@link 136 * removeSdpRecord}(). The record is not linked to the creation/destruction of 137 * BluetoothSockets, hence SDP record cleanup is a separate process. 138 */ createPbapPceRecord(String serviceName, int version)139 public int createPbapPceRecord(String serviceName, int version) { 140 if (!mNativeAvailable) { 141 throw new RuntimeException(TAG + " mNativeAvailable == false - native not initialized"); 142 } 143 return sdpCreatePbapPceRecordNative(serviceName, version); 144 } 145 146 /** 147 * Create a Server side Phone Book Access Profile Service Record. Create the record once, and 148 * reuse it for all connections. If changes to a record is needed remove the old record using 149 * {@link removeSdpRecord} and then create a new one. 150 * 151 * @param serviceName The textual name of the service 152 * @param rfcommChannel The RFCOMM channel that clients can connect to (obtain from 153 * BluetoothServerSocket) 154 * @param l2capPsm The L2CAP PSM channel that clients can connect to (obtain from 155 * BluetoothServerSocket) Supply -1 to omit the L2CAP PSM from the record. 156 * @param version The Profile version number (As specified in the Bluetooth PBAP specification) 157 * @param repositories The supported repositories bit mask (As specified in the Bluetooth PBAP 158 * specification) 159 * @param features The feature bit mask (As specified in the Bluetooth PBAP specification) 160 * @return a handle to the record created. The record can be removed again using {@link 161 * removeSdpRecord}(). The record is not linked to the creation/destruction of 162 * BluetoothSockets, hence SDP record cleanup is a separate process. 163 */ createPbapPseRecord( String serviceName, int rfcommChannel, int l2capPsm, int version, int repositories, int features)164 public int createPbapPseRecord( 165 String serviceName, 166 int rfcommChannel, 167 int l2capPsm, 168 int version, 169 int repositories, 170 int features) { 171 if (!mNativeAvailable) { 172 throw new RuntimeException(TAG + " mNativeAvailable == false - native not initialized"); 173 } 174 return sdpCreatePbapPseRecordNative( 175 serviceName, rfcommChannel, l2capPsm, version, repositories, features); 176 } 177 178 /** 179 * Create a Server side Object Push Profile Service Record. Create the record once, and reuse it 180 * for all connections. If changes to a record is needed remove the old record using {@link 181 * removeSdpRecord} and then create a new one. 182 * 183 * @param serviceName The textual name of the service 184 * @param rfcommChannel The RFCOMM channel that clients can connect to (obtain from 185 * BluetoothServerSocket) 186 * @param l2capPsm The L2CAP PSM channel that clients can connect to (obtain from 187 * BluetoothServerSocket) Supply -1 to omit the L2CAP PSM from the record. 188 * @param version The Profile version number (As specified in the Bluetooth OPP specification) 189 * @param formatsList A list of the supported formats (As specified in the Bluetooth OPP 190 * specification) 191 * @return a handle to the record created. The record can be removed again using {@link 192 * removeSdpRecord}(). The record is not linked to the creation/destruction of 193 * BluetoothSockets, hence SDP record cleanup is a separate process. 194 */ createOppOpsRecord( String serviceName, int rfcommChannel, int l2capPsm, int version, byte[] formatsList)195 public int createOppOpsRecord( 196 String serviceName, int rfcommChannel, int l2capPsm, int version, byte[] formatsList) { 197 if (!mNativeAvailable) { 198 throw new RuntimeException(TAG + " mNativeAvailable == false - native not initialized"); 199 } 200 return sdpCreateOppOpsRecordNative( 201 serviceName, rfcommChannel, l2capPsm, version, formatsList); 202 } 203 204 /** 205 * Create a server side Sim Access Profile Service Record. Create the record once, and reuse it 206 * for all connections. If changes to a record is needed remove the old record using {@link 207 * removeSdpRecord} and then create a new one. 208 * 209 * @param serviceName The textual name of the service 210 * @param rfcommChannel The RFCOMM channel that clients can connect to (obtain from 211 * BluetoothServerSocket) 212 * @param version The Profile version number (As specified in the Bluetooth SAP specification) 213 * @return a handle to the record created. The record can be removed again using {@link 214 * removeSdpRecord}(). The record is not linked to the creation/destruction of 215 * BluetoothSockets, hence SDP record cleanup is a separate process. 216 */ createSapsRecord(String serviceName, int rfcommChannel, int version)217 public int createSapsRecord(String serviceName, int rfcommChannel, int version) { 218 if (!mNativeAvailable) { 219 throw new RuntimeException(TAG + " mNativeAvailable == false - native not initialized"); 220 } 221 return sdpCreateSapsRecordNative(serviceName, rfcommChannel, version); 222 } 223 224 /** 225 * Remove a SDP record. When Bluetooth is disabled all records will be deleted, hence there is 226 * no need to call this function when bluetooth is disabled. 227 * 228 * @param recordId The Id returned by on of the createXxxXxxRecord() functions. 229 * @return TRUE if the record removal was initiated successfully. FALSE if the record handle is 230 * not known/have already been removed. 231 */ removeSdpRecord(int recordId)232 public boolean removeSdpRecord(int recordId) { 233 if (!mNativeAvailable) { 234 throw new RuntimeException(TAG + " mNativeAvailable == false - native not initialized"); 235 } 236 return sdpRemoveSdpRecordNative(recordId); 237 } 238 239 /**********************************************************************************************/ 240 /*********************************** callbacks from native ************************************/ 241 /**********************************************************************************************/ 242 sdpRecordFoundCallback( int status, byte[] address, byte[] uuid, int sizeRecord, byte[] record)243 void sdpRecordFoundCallback( 244 int status, byte[] address, byte[] uuid, int sizeRecord, byte[] record) { 245 mSdpManager.sdpRecordFoundCallback(status, address, uuid, sizeRecord, record); 246 } 247 sdpMasRecordFoundCallback( int status, byte[] address, byte[] uuid, int masInstanceId, int l2capPsm, int rfcommCannelNumber, int profileVersion, int supportedFeatures, int supportedMessageTypes, String serviceName, boolean moreResults)248 void sdpMasRecordFoundCallback( 249 int status, 250 byte[] address, 251 byte[] uuid, 252 int masInstanceId, 253 int l2capPsm, 254 int rfcommCannelNumber, 255 int profileVersion, 256 int supportedFeatures, 257 int supportedMessageTypes, 258 String serviceName, 259 boolean moreResults) { 260 mSdpManager.sdpMasRecordFoundCallback( 261 status, 262 address, 263 uuid, 264 masInstanceId, 265 l2capPsm, 266 rfcommCannelNumber, 267 profileVersion, 268 supportedFeatures, 269 supportedMessageTypes, 270 serviceName, 271 moreResults); 272 } 273 sdpMnsRecordFoundCallback( int status, byte[] address, byte[] uuid, int l2capPsm, int rfcommCannelNumber, int profileVersion, int supportedFeatures, String serviceName, boolean moreResults)274 void sdpMnsRecordFoundCallback( 275 int status, 276 byte[] address, 277 byte[] uuid, 278 int l2capPsm, 279 int rfcommCannelNumber, 280 int profileVersion, 281 int supportedFeatures, 282 String serviceName, 283 boolean moreResults) { 284 mSdpManager.sdpMnsRecordFoundCallback( 285 status, 286 address, 287 uuid, 288 l2capPsm, 289 rfcommCannelNumber, 290 profileVersion, 291 supportedFeatures, 292 serviceName, 293 moreResults); 294 } 295 sdpPseRecordFoundCallback( int status, byte[] address, byte[] uuid, int l2capPsm, int rfcommCannelNumber, int profileVersion, int supportedFeatures, int supportedRepositories, String serviceName, boolean moreResults)296 void sdpPseRecordFoundCallback( 297 int status, 298 byte[] address, 299 byte[] uuid, 300 int l2capPsm, 301 int rfcommCannelNumber, 302 int profileVersion, 303 int supportedFeatures, 304 int supportedRepositories, 305 String serviceName, 306 boolean moreResults) { 307 mSdpManager.sdpPseRecordFoundCallback( 308 status, 309 address, 310 uuid, 311 l2capPsm, 312 rfcommCannelNumber, 313 profileVersion, 314 supportedFeatures, 315 supportedRepositories, 316 serviceName, 317 moreResults); 318 } 319 sdpOppOpsRecordFoundCallback( int status, byte[] address, byte[] uuid, int l2capPsm, int rfcommCannelNumber, int profileVersion, String serviceName, byte[] formatsList, boolean moreResults)320 void sdpOppOpsRecordFoundCallback( 321 int status, 322 byte[] address, 323 byte[] uuid, 324 int l2capPsm, 325 int rfcommCannelNumber, 326 int profileVersion, 327 String serviceName, 328 byte[] formatsList, 329 boolean moreResults) { 330 mSdpManager.sdpOppOpsRecordFoundCallback( 331 status, 332 address, 333 uuid, 334 l2capPsm, 335 rfcommCannelNumber, 336 profileVersion, 337 serviceName, 338 formatsList, 339 moreResults); 340 } 341 sdpSapsRecordFoundCallback( int status, byte[] address, byte[] uuid, int rfcommCannelNumber, int profileVersion, String serviceName, boolean moreResults)342 void sdpSapsRecordFoundCallback( 343 int status, 344 byte[] address, 345 byte[] uuid, 346 int rfcommCannelNumber, 347 int profileVersion, 348 String serviceName, 349 boolean moreResults) { 350 mSdpManager.sdpSapsRecordFoundCallback( 351 status, 352 address, 353 uuid, 354 rfcommCannelNumber, 355 profileVersion, 356 serviceName, 357 moreResults); 358 } 359 sdpDipRecordFoundCallback( int status, byte[] address, byte[] uuid, int specificationId, int vendorId, int vendorIdSource, int productId, int version, boolean primaryRecord, boolean moreResults)360 void sdpDipRecordFoundCallback( 361 int status, 362 byte[] address, 363 byte[] uuid, 364 int specificationId, 365 int vendorId, 366 int vendorIdSource, 367 int productId, 368 int version, 369 boolean primaryRecord, 370 boolean moreResults) { 371 mSdpManager.sdpDipRecordFoundCallback( 372 status, 373 address, 374 uuid, 375 specificationId, 376 vendorId, 377 vendorIdSource, 378 productId, 379 version, 380 primaryRecord, 381 moreResults); 382 } 383 384 /**********************************************************************************************/ 385 /******************************************* native *******************************************/ 386 /**********************************************************************************************/ 387 initializeNative()388 private native void initializeNative(); 389 cleanupNative()390 private native void cleanupNative(); 391 sdpSearchNative(byte[] address, byte[] uuid)392 private native boolean sdpSearchNative(byte[] address, byte[] uuid); 393 sdpCreateMapMasRecordNative( String serviceName, int masId, int rfcommChannel, int l2capPsm, int version, int msgTypes, int features)394 private native int sdpCreateMapMasRecordNative( 395 String serviceName, 396 int masId, 397 int rfcommChannel, 398 int l2capPsm, 399 int version, 400 int msgTypes, 401 int features); 402 sdpCreateMapMnsRecordNative( String serviceName, int rfcommChannel, int l2capPsm, int version, int features)403 private native int sdpCreateMapMnsRecordNative( 404 String serviceName, int rfcommChannel, int l2capPsm, int version, int features); 405 sdpCreatePbapPceRecordNative(String serviceName, int version)406 private native int sdpCreatePbapPceRecordNative(String serviceName, int version); 407 sdpCreatePbapPseRecordNative( String serviceName, int rfcommChannel, int l2capPsm, int version, int repositories, int features)408 private native int sdpCreatePbapPseRecordNative( 409 String serviceName, 410 int rfcommChannel, 411 int l2capPsm, 412 int version, 413 int repositories, 414 int features); 415 sdpCreateOppOpsRecordNative( String serviceName, int rfcommChannel, int l2capPsm, int version, byte[] formatsList)416 private native int sdpCreateOppOpsRecordNative( 417 String serviceName, int rfcommChannel, int l2capPsm, int version, byte[] formatsList); 418 sdpCreateSapsRecordNative( String serviceName, int rfcommChannel, int version)419 private native int sdpCreateSapsRecordNative( 420 String serviceName, int rfcommChannel, int version); 421 sdpRemoveSdpRecordNative(int recordId)422 private native boolean sdpRemoveSdpRecordNative(int recordId); 423 } 424