1 /* 2 * Copyright (C) 2022 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 package com.android.bluetooth.le_scan; 18 19 import android.annotation.Nullable; 20 import android.os.RemoteException; 21 import android.util.Log; 22 23 import com.android.bluetooth.gatt.FilterParams; 24 import com.android.internal.annotations.VisibleForTesting; 25 26 import java.util.concurrent.CountDownLatch; 27 import java.util.concurrent.TimeUnit; 28 29 /** BLE Scan Native Interface to/from JNI. */ 30 public class ScanNativeInterface { 31 private static final String TAG = ScanNativeInterface.class.getSimpleName(); 32 33 private static ScanNativeInterface sInterface; 34 35 private CountDownLatch mLatch = new CountDownLatch(1); 36 @Nullable private TransitionalScanHelper mScanHelper; 37 ScanNativeInterface()38 private ScanNativeInterface() {} 39 40 /** 41 * This class is a singleton because native library should only be loaded once 42 * 43 * @return default instance 44 */ getInstance()45 public static ScanNativeInterface getInstance() { 46 synchronized (ScanNativeInterface.class) { 47 if (sInterface == null) { 48 sInterface = new ScanNativeInterface(); 49 } 50 } 51 return sInterface; 52 } 53 54 /** Set singleton instance. */ 55 @VisibleForTesting setInstance(ScanNativeInterface instance)56 public static void setInstance(ScanNativeInterface instance) { 57 synchronized (ScanNativeInterface.class) { 58 sInterface = instance; 59 } 60 } 61 init(TransitionalScanHelper scanHelper)62 void init(TransitionalScanHelper scanHelper) { 63 mScanHelper = scanHelper; 64 initializeNative(); 65 } 66 cleanup()67 void cleanup() { 68 cleanupNative(); 69 } 70 71 /* Native methods */ initializeNative()72 private native void initializeNative(); 73 cleanupNative()74 private native void cleanupNative(); 75 76 /************************** Regular scan related native methods **************************/ registerScannerNative(long appUuidLsb, long appUuidMsb)77 private native void registerScannerNative(long appUuidLsb, long appUuidMsb); 78 unregisterScannerNative(int scannerId)79 private native void unregisterScannerNative(int scannerId); 80 gattClientScanNative(boolean start)81 private native void gattClientScanNative(boolean start); 82 gattSetScanParametersNative( int clientIf, int scanInterval, int scanWindow, int scanPhy)83 private native void gattSetScanParametersNative( 84 int clientIf, int scanInterval, int scanWindow, int scanPhy); 85 86 /************************** Filter related native methods ********************************/ gattClientScanFilterAddNative( int clientId, ScanFilterQueue.Entry[] entries, int filterIndex)87 private native void gattClientScanFilterAddNative( 88 int clientId, ScanFilterQueue.Entry[] entries, int filterIndex); 89 gattClientScanFilterParamAddNative(FilterParams filtValue)90 private native void gattClientScanFilterParamAddNative(FilterParams filtValue); 91 92 // Note this effectively remove scan filters for ALL clients. gattClientScanFilterParamClearAllNative(int clientIf)93 private native void gattClientScanFilterParamClearAllNative(int clientIf); 94 gattClientScanFilterParamDeleteNative(int clientIf, int filtIndex)95 private native void gattClientScanFilterParamDeleteNative(int clientIf, int filtIndex); 96 gattClientScanFilterClearNative(int clientIf, int filterIndex)97 private native void gattClientScanFilterClearNative(int clientIf, int filterIndex); 98 gattClientScanFilterEnableNative(int clientIf, boolean enable)99 private native void gattClientScanFilterEnableNative(int clientIf, boolean enable); 100 101 /************************** Batch related native methods *********************************/ gattClientConfigBatchScanStorageNative( int clientIf, int maxFullReportsPercent, int maxTruncatedReportsPercent, int notifyThresholdPercent)102 private native void gattClientConfigBatchScanStorageNative( 103 int clientIf, 104 int maxFullReportsPercent, 105 int maxTruncatedReportsPercent, 106 int notifyThresholdPercent); 107 gattClientStartBatchScanNative( int clientIf, int scanMode, int scanIntervalUnit, int scanWindowUnit, int addressType, int discardRule)108 private native void gattClientStartBatchScanNative( 109 int clientIf, 110 int scanMode, 111 int scanIntervalUnit, 112 int scanWindowUnit, 113 int addressType, 114 int discardRule); 115 gattClientStopBatchScanNative(int clientIf)116 private native void gattClientStopBatchScanNative(int clientIf); 117 gattClientReadScanReportsNative(int clientIf, int scanType)118 private native void gattClientReadScanReportsNative(int clientIf, int scanType); 119 120 /** Register BLE scanner */ registerScanner(long appUuidLsb, long appUuidMsb)121 public void registerScanner(long appUuidLsb, long appUuidMsb) { 122 registerScannerNative(appUuidLsb, appUuidMsb); 123 } 124 125 /** Unregister BLE scanner */ unregisterScanner(int scannerId)126 public void unregisterScanner(int scannerId) { 127 unregisterScannerNative(scannerId); 128 } 129 130 /** Enable/disable BLE scan */ gattClientScan(boolean start)131 public void gattClientScan(boolean start) { 132 gattClientScanNative(start); 133 } 134 135 /** Configure BLE scan parameters */ gattSetScanParameters(int clientIf, int scanInterval, int scanWindow, int scanPhy)136 public void gattSetScanParameters(int clientIf, int scanInterval, int scanWindow, int scanPhy) { 137 gattSetScanParametersNative(clientIf, scanInterval, scanWindow, scanPhy); 138 } 139 140 /** Add BLE scan filter */ gattClientScanFilterAdd( int clientId, ScanFilterQueue.Entry[] entries, int filterIndex)141 public void gattClientScanFilterAdd( 142 int clientId, ScanFilterQueue.Entry[] entries, int filterIndex) { 143 gattClientScanFilterAddNative(clientId, entries, filterIndex); 144 } 145 146 /** Add BLE scan filter parameters */ gattClientScanFilterParamAdd(FilterParams filtValue)147 public void gattClientScanFilterParamAdd(FilterParams filtValue) { 148 gattClientScanFilterParamAddNative(filtValue); 149 } 150 151 /** Clear all BLE scan filter parameters */ 152 // Note this effectively remove scan filters for ALL clients. gattClientScanFilterParamClearAll(int clientIf)153 public void gattClientScanFilterParamClearAll(int clientIf) { 154 gattClientScanFilterParamClearAllNative(clientIf); 155 } 156 157 /** Delete BLE scan filter parameters */ gattClientScanFilterParamDelete(int clientIf, int filtIndex)158 public void gattClientScanFilterParamDelete(int clientIf, int filtIndex) { 159 gattClientScanFilterParamDeleteNative(clientIf, filtIndex); 160 } 161 162 /** Clear BLE scan filter */ gattClientScanFilterClear(int clientIf, int filterIndex)163 public void gattClientScanFilterClear(int clientIf, int filterIndex) { 164 gattClientScanFilterClearNative(clientIf, filterIndex); 165 } 166 167 /** Enable/disable BLE scan filter */ gattClientScanFilterEnable(int clientIf, boolean enable)168 public void gattClientScanFilterEnable(int clientIf, boolean enable) { 169 gattClientScanFilterEnableNative(clientIf, enable); 170 } 171 172 /** Configure BLE batch scan storage */ gattClientConfigBatchScanStorage( int clientIf, int maxFullReportsPercent, int maxTruncatedReportsPercent, int notifyThresholdPercent)173 public void gattClientConfigBatchScanStorage( 174 int clientIf, 175 int maxFullReportsPercent, 176 int maxTruncatedReportsPercent, 177 int notifyThresholdPercent) { 178 gattClientConfigBatchScanStorageNative( 179 clientIf, 180 maxFullReportsPercent, 181 maxTruncatedReportsPercent, 182 notifyThresholdPercent); 183 } 184 185 /** Enable BLE batch scan with the parameters */ gattClientStartBatchScan( int clientIf, int scanMode, int scanIntervalUnit, int scanWindowUnit, int addressType, int discardRule)186 public void gattClientStartBatchScan( 187 int clientIf, 188 int scanMode, 189 int scanIntervalUnit, 190 int scanWindowUnit, 191 int addressType, 192 int discardRule) { 193 gattClientStartBatchScanNative( 194 clientIf, scanMode, scanIntervalUnit, scanWindowUnit, addressType, discardRule); 195 } 196 197 /** Disable BLE batch scan */ gattClientStopBatchScan(int clientIf)198 public void gattClientStopBatchScan(int clientIf) { 199 gattClientStopBatchScanNative(clientIf); 200 } 201 202 /** Read BLE batch scan reports */ gattClientReadScanReports(int clientIf, int scanType)203 public void gattClientReadScanReports(int clientIf, int scanType) { 204 gattClientReadScanReportsNative(clientIf, scanType); 205 } 206 callbackDone()207 void callbackDone() { 208 mLatch.countDown(); 209 } 210 resetCountDownLatch()211 void resetCountDownLatch() { 212 mLatch = new CountDownLatch(1); 213 } 214 215 // Returns true if mLatch reaches 0, false if timeout or interrupted. waitForCallback(int timeoutMs)216 boolean waitForCallback(int timeoutMs) { 217 try { 218 return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS); 219 } catch (InterruptedException e) { 220 return false; 221 } 222 } 223 224 /* Callbacks */ 225 onScanResult( int eventType, int addressType, String address, int primaryPhy, int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt, byte[] advData, String originalAddress)226 void onScanResult( 227 int eventType, 228 int addressType, 229 String address, 230 int primaryPhy, 231 int secondaryPhy, 232 int advertisingSid, 233 int txPower, 234 int rssi, 235 int periodicAdvInt, 236 byte[] advData, 237 String originalAddress) { 238 if (mScanHelper == null) { 239 Log.e(TAG, "Scan helper is null!"); 240 return; 241 } 242 mScanHelper.onScanResult( 243 eventType, 244 addressType, 245 address, 246 primaryPhy, 247 secondaryPhy, 248 advertisingSid, 249 txPower, 250 rssi, 251 periodicAdvInt, 252 advData, 253 originalAddress); 254 } 255 onScannerRegistered(int status, int scannerId, long uuidLsb, long uuidMsb)256 void onScannerRegistered(int status, int scannerId, long uuidLsb, long uuidMsb) 257 throws RemoteException { 258 if (mScanHelper == null) { 259 Log.e(TAG, "Scan helper is null!"); 260 return; 261 } 262 mScanHelper.onScannerRegistered(status, scannerId, uuidLsb, uuidMsb); 263 } 264 onScanFilterEnableDisabled(int action, int status, int clientIf)265 void onScanFilterEnableDisabled(int action, int status, int clientIf) { 266 if (mScanHelper == null) { 267 Log.e(TAG, "Scan helper is null!"); 268 return; 269 } 270 mScanHelper.onScanFilterEnableDisabled(action, status, clientIf); 271 } 272 onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace)273 void onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace) { 274 if (mScanHelper == null) { 275 Log.e(TAG, "Scan helper is null!"); 276 return; 277 } 278 mScanHelper.onScanFilterParamsConfigured(action, status, clientIf, availableSpace); 279 } 280 onScanFilterConfig( int action, int status, int clientIf, int filterType, int availableSpace)281 void onScanFilterConfig( 282 int action, int status, int clientIf, int filterType, int availableSpace) { 283 if (mScanHelper == null) { 284 Log.e(TAG, "Scan helper is null!"); 285 return; 286 } 287 mScanHelper.onScanFilterConfig(action, status, clientIf, filterType, availableSpace); 288 } 289 onBatchScanStorageConfigured(int status, int clientIf)290 void onBatchScanStorageConfigured(int status, int clientIf) { 291 if (mScanHelper == null) { 292 Log.e(TAG, "Scan helper is null!"); 293 return; 294 } 295 mScanHelper.onBatchScanStorageConfigured(status, clientIf); 296 } 297 onBatchScanStartStopped(int startStopAction, int status, int clientIf)298 void onBatchScanStartStopped(int startStopAction, int status, int clientIf) { 299 if (mScanHelper == null) { 300 Log.e(TAG, "Scan helper is null!"); 301 return; 302 } 303 mScanHelper.onBatchScanStartStopped(startStopAction, status, clientIf); 304 } 305 onBatchScanReports( int status, int scannerId, int reportType, int numRecords, byte[] recordData)306 void onBatchScanReports( 307 int status, int scannerId, int reportType, int numRecords, byte[] recordData) 308 throws RemoteException { 309 if (mScanHelper == null) { 310 Log.e(TAG, "Scan helper is null!"); 311 return; 312 } 313 mScanHelper.onBatchScanReports(status, scannerId, reportType, numRecords, recordData); 314 } 315 onBatchScanThresholdCrossed(int clientIf)316 void onBatchScanThresholdCrossed(int clientIf) { 317 if (mScanHelper == null) { 318 Log.e(TAG, "Scan helper is null!"); 319 return; 320 } 321 mScanHelper.onBatchScanThresholdCrossed(clientIf); 322 } 323 324 @Nullable createOnTrackAdvFoundLostObject( int clientIf, int advPktLen, byte[] advPkt, int scanRspLen, byte[] scanRsp, int filtIndex, int advState, int advInfoPresent, String address, int addrType, int txPower, int rssiValue, int timeStamp)325 AdvtFilterOnFoundOnLostInfo createOnTrackAdvFoundLostObject( 326 int clientIf, 327 int advPktLen, 328 byte[] advPkt, 329 int scanRspLen, 330 byte[] scanRsp, 331 int filtIndex, 332 int advState, 333 int advInfoPresent, 334 String address, 335 int addrType, 336 int txPower, 337 int rssiValue, 338 int timeStamp) { 339 if (mScanHelper == null) { 340 Log.e(TAG, "Scan helper is null!"); 341 return null; 342 } 343 return mScanHelper.createOnTrackAdvFoundLostObject( 344 clientIf, 345 advPktLen, 346 advPkt, 347 scanRspLen, 348 scanRsp, 349 filtIndex, 350 advState, 351 advInfoPresent, 352 address, 353 addrType, 354 txPower, 355 rssiValue, 356 timeStamp); 357 } 358 onTrackAdvFoundLost(AdvtFilterOnFoundOnLostInfo trackingInfo)359 void onTrackAdvFoundLost(AdvtFilterOnFoundOnLostInfo trackingInfo) throws RemoteException { 360 if (mScanHelper == null) { 361 Log.e(TAG, "Scan helper is null!"); 362 return; 363 } 364 mScanHelper.onTrackAdvFoundLost(trackingInfo); 365 } 366 onScanParamSetupCompleted(int status, int scannerId)367 void onScanParamSetupCompleted(int status, int scannerId) throws RemoteException { 368 if (mScanHelper == null) { 369 Log.e(TAG, "Scan helper is null!"); 370 return; 371 } 372 mScanHelper.onScanParamSetupCompleted(status, scannerId); 373 } 374 } 375