• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.gatt;
18 
19 import android.bluetooth.BluetoothAssignedNumbers.OrganizationId;
20 import android.bluetooth.BluetoothUuid;
21 import android.bluetooth.le.ScanFilter;
22 import android.bluetooth.le.TransportBlockFilter;
23 import android.os.ParcelUuid;
24 
25 import java.util.Arrays;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.Set;
29 import java.util.UUID;
30 
31 /**
32  * Helper class used to manage advertisement package filters.
33  *
34  * @hide
35  */
36 /* package */class ScanFilterQueue {
37     public static final int TYPE_DEVICE_ADDRESS = 0;
38     public static final int TYPE_SERVICE_DATA_CHANGED = 1;
39     public static final int TYPE_SERVICE_UUID = 2;
40     public static final int TYPE_SOLICIT_UUID = 3;
41     public static final int TYPE_LOCAL_NAME = 4;
42     public static final int TYPE_MANUFACTURER_DATA = 5;
43     public static final int TYPE_SERVICE_DATA = 6;
44     public static final int TYPE_TRANSPORT_DISCOVERY_DATA = 7;
45     public static final int TYPE_ADVERTISING_DATA_TYPE = 8;
46 
47     // Max length is 31 - 3(flags) - 2 (one byte for length and one byte for type).
48     private static final int MAX_LEN_PER_FIELD = 26;
49 
50     // Values defined in bluedroid.
51     private static final byte DEVICE_TYPE_ALL = 2;
52 
53     // Meta data type for Transport Block Filter
54     public static final int TYPE_INVALID = 0x00;
55     public static final int TYPE_WIFI_NAN_HASH = 0x01; // WIFI NAN HASH type
56 
57     class Entry {
58         public byte type;
59         public String address;
60         public byte addr_type;
61         public byte[] irk;
62         public UUID uuid;
63         public UUID uuid_mask;
64         public String name;
65         public int company;
66         public int company_mask;
67         public int ad_type;
68         public byte[] data;
69         public byte[] data_mask;
70         public int org_id;
71         public int tds_flags;
72         public int tds_flags_mask;
73         public int meta_data_type;
74         public byte[] meta_data;
75     }
76 
77     private Set<Entry> mEntries = new HashSet<Entry>();
78 
addDeviceAddress(String address, byte type, byte[] irk)79     void addDeviceAddress(String address, byte type, byte[] irk) {
80         Entry entry = new Entry();
81         entry.type = TYPE_DEVICE_ADDRESS;
82         entry.address = address;
83         entry.addr_type = type;
84         entry.irk = irk;
85         mEntries.add(entry);
86     }
87 
addServiceChanged()88     void addServiceChanged() {
89         Entry entry = new Entry();
90         entry.type = TYPE_SERVICE_DATA_CHANGED;
91         mEntries.add(entry);
92     }
93 
addUuid(UUID uuid)94     void addUuid(UUID uuid) {
95         Entry entry = new Entry();
96         entry.type = TYPE_SERVICE_UUID;
97         entry.uuid = uuid;
98         entry.uuid_mask = new UUID(0, 0);
99         mEntries.add(entry);
100     }
101 
addUuid(UUID uuid, UUID uuidMask)102     void addUuid(UUID uuid, UUID uuidMask) {
103         Entry entry = new Entry();
104         entry.type = TYPE_SERVICE_UUID;
105         entry.uuid = uuid;
106         entry.uuid_mask = uuidMask;
107         mEntries.add(entry);
108     }
109 
addSolicitUuid(UUID uuid)110     void addSolicitUuid(UUID uuid) {
111         Entry entry = new Entry();
112         entry.type = TYPE_SOLICIT_UUID;
113         entry.uuid = uuid;
114         entry.uuid_mask = new UUID(0, 0);
115         mEntries.add(entry);
116     }
117 
addSolicitUuid(UUID uuid, UUID uuidMask)118     void addSolicitUuid(UUID uuid, UUID uuidMask) {
119         Entry entry = new Entry();
120         entry.type = TYPE_SOLICIT_UUID;
121         entry.uuid = uuid;
122         entry.uuid_mask = uuidMask;
123         mEntries.add(entry);
124     }
125 
addName(String name)126     void addName(String name) {
127         Entry entry = new Entry();
128         entry.type = TYPE_LOCAL_NAME;
129         entry.name = name;
130         mEntries.add(entry);
131     }
132 
addManufacturerData(int company, byte[] data)133     void addManufacturerData(int company, byte[] data) {
134         Entry entry = new Entry();
135         entry.type = TYPE_MANUFACTURER_DATA;
136         entry.company = company;
137         entry.company_mask = 0xFFFF;
138         entry.data = data;
139         entry.data_mask = new byte[data.length];
140         Arrays.fill(entry.data_mask, (byte) 0xFF);
141         mEntries.add(entry);
142     }
143 
addManufacturerData(int company, int companyMask, byte[] data, byte[] dataMask)144     void addManufacturerData(int company, int companyMask, byte[] data, byte[] dataMask) {
145         Entry entry = new Entry();
146         entry.type = TYPE_MANUFACTURER_DATA;
147         entry.company = company;
148         entry.company_mask = companyMask;
149         entry.data = data;
150         entry.data_mask = dataMask;
151         mEntries.add(entry);
152     }
153 
addServiceData(byte[] data, byte[] dataMask)154     void addServiceData(byte[] data, byte[] dataMask) {
155         Entry entry = new Entry();
156         entry.type = TYPE_SERVICE_DATA;
157         entry.data = data;
158         entry.data_mask = dataMask;
159         mEntries.add(entry);
160     }
161 
addTransportDiscoveryData(int orgId, int tdsFlags, int tdsFlagsMask, byte[] transportData, byte[] transportDataMask, int metaDataType, byte[] metaData)162     void addTransportDiscoveryData(int orgId, int tdsFlags, int tdsFlagsMask,
163             byte[] transportData, byte[] transportDataMask, int metaDataType, byte[] metaData) {
164         Entry entry = new Entry();
165         entry.type = TYPE_TRANSPORT_DISCOVERY_DATA;
166         entry.org_id = orgId;
167         entry.tds_flags = tdsFlags;
168         entry.tds_flags_mask = tdsFlagsMask;
169         entry.data = transportData;
170         entry.data_mask = transportDataMask;
171         entry.meta_data_type = metaDataType;
172         entry.meta_data = metaData;
173         mEntries.add(entry);
174     }
175 
addAdvertisingDataType(int adType, byte[] data, byte[] dataMask)176     void addAdvertisingDataType(int adType, byte[] data, byte[] dataMask) {
177         Entry entry = new Entry();
178         entry.type = TYPE_ADVERTISING_DATA_TYPE;
179         entry.ad_type = adType;
180         entry.data = data;
181         entry.data_mask = dataMask;
182         mEntries.add(entry);
183     }
184 
pop()185     Entry pop() {
186         if (mEntries.isEmpty()) {
187             return null;
188         }
189         Iterator<Entry> iterator = mEntries.iterator();
190         Entry entry = iterator.next();
191         iterator.remove();
192         return entry;
193     }
194 
195     /**
196      * Compute feature selection based on the filters presented.
197      */
getFeatureSelection()198     int getFeatureSelection() {
199         int selc = 0;
200         for (Entry entry : mEntries) {
201             selc |= (1 << entry.type);
202         }
203         return selc;
204     }
205 
toArray()206     ScanFilterQueue.Entry[] toArray() {
207         return mEntries.toArray(new ScanFilterQueue.Entry[mEntries.size()]);
208     }
209 
210     /**
211      * Add ScanFilter to scan filter queue.
212      */
addScanFilter(ScanFilter filter)213     void addScanFilter(ScanFilter filter) {
214         if (filter == null) {
215             return;
216         }
217         if (filter.getDeviceName() != null) {
218             addName(filter.getDeviceName());
219         }
220         if (filter.getDeviceAddress() != null) {
221             /*
222              * Pass the addres type here.  This address type will be used for the resolving address,
223              * however, the host stack will force the type to 0x02 for the APCF filter in
224              * btm_ble_adv_filter.cc#BTM_LE_PF_addr_filter(...)
225              */
226             addDeviceAddress(filter.getDeviceAddress(), (byte) filter.getAddressType(),
227                     filter.getIrk());
228         }
229         if (filter.getServiceUuid() != null) {
230             if (filter.getServiceUuidMask() == null) {
231                 addUuid(filter.getServiceUuid().getUuid());
232             } else {
233                 addUuid(filter.getServiceUuid().getUuid(), filter.getServiceUuidMask().getUuid());
234             }
235         }
236         if (filter.getServiceSolicitationUuid() != null) {
237             if (filter.getServiceSolicitationUuidMask() == null) {
238                 addSolicitUuid(filter.getServiceSolicitationUuid().getUuid());
239             } else {
240                 addSolicitUuid(filter.getServiceSolicitationUuid().getUuid(),
241                         filter.getServiceSolicitationUuidMask().getUuid());
242             }
243         }
244         if (filter.getManufacturerData() != null) {
245             if (filter.getManufacturerDataMask() == null) {
246                 addManufacturerData(filter.getManufacturerId(), filter.getManufacturerData());
247             } else {
248                 addManufacturerData(filter.getManufacturerId(), 0xFFFF,
249                         filter.getManufacturerData(), filter.getManufacturerDataMask());
250             }
251         }
252         if (filter.getServiceDataUuid() != null && filter.getServiceData() != null) {
253             ParcelUuid serviceDataUuid = filter.getServiceDataUuid();
254             byte[] serviceData = filter.getServiceData();
255             byte[] serviceDataMask = filter.getServiceDataMask();
256             if (serviceDataMask == null) {
257                 serviceDataMask = new byte[serviceData.length];
258                 Arrays.fill(serviceDataMask, (byte) 0xFF);
259             }
260             serviceData = concate(serviceDataUuid, serviceData);
261             serviceDataMask = concate(serviceDataUuid, serviceDataMask);
262             if (serviceData != null && serviceDataMask != null) {
263                 addServiceData(serviceData, serviceDataMask);
264             }
265         }
266         if (filter.getAdvertisingDataType() > 0) {
267             addAdvertisingDataType(filter.getAdvertisingDataType(),
268                     filter.getAdvertisingData(), filter.getAdvertisingDataMask());
269         }
270         final TransportBlockFilter transportBlockFilter = filter.getTransportBlockFilter();
271         if (transportBlockFilter != null) {
272             if (transportBlockFilter.getOrgId()
273                     == OrganizationId.WIFI_ALLIANCE_NEIGHBOR_AWARENESS_NETWORKING) {
274                 addTransportDiscoveryData(transportBlockFilter.getOrgId(),
275                         transportBlockFilter.getTdsFlags(), transportBlockFilter.getTdsFlagsMask(),
276                         null, null, TYPE_WIFI_NAN_HASH, transportBlockFilter.getWifiNanHash());
277             } else {
278                 addTransportDiscoveryData(transportBlockFilter.getOrgId(),
279                         transportBlockFilter.getTdsFlags(), transportBlockFilter.getTdsFlagsMask(),
280                         transportBlockFilter.getTransportData(),
281                         transportBlockFilter.getTransportDataMask(), TYPE_INVALID, null);
282             }
283 
284         }
285     }
286 
concate(ParcelUuid serviceDataUuid, byte[] serviceData)287     private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) {
288         byte[] uuid = BluetoothUuid.uuidToBytes(serviceDataUuid);
289 
290         int dataLen = uuid.length + (serviceData == null ? 0 : serviceData.length);
291         // If data is too long, don't add it to hardware scan filter.
292         if (dataLen > MAX_LEN_PER_FIELD) {
293             return null;
294         }
295         byte[] concated = new byte[dataLen];
296         System.arraycopy(uuid, 0, concated, 0, uuid.length);
297         if (serviceData != null) {
298             System.arraycopy(serviceData, 0, concated, uuid.length, serviceData.length);
299         }
300         return concated;
301     }
302 }
303