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