Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9b43860 authored by Wei Wang's avatar Wei Wang Committed by Android Git Automerger
Browse files

am 378a265d: Fix service data filter and report delay issue.

* commit '378a265d':
  Fix service data filter and report delay issue.
parents cc786225 378a265d
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@ import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ProfileService;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.HashSet;
@@ -595,6 +596,7 @@ public class GattService extends ProfileService {
        if (client.filters == null || client.filters.isEmpty()) {
        if (client.filters == null || client.filters.isEmpty()) {
            return true;
            return true;
        }
        }
        if (DBG) Log.d(TAG, "result: " + scanResult.toString());
        for (ScanFilter filter : client.filters) {
        for (ScanFilter filter : client.filters) {
            if (DBG) Log.d(TAG, "filter: " + filter.toString());
            if (DBG) Log.d(TAG, "filter: " + filter.toString());
            if (filter.matches(scanResult)) {
            if (filter.matches(scanResult)) {
@@ -954,6 +956,9 @@ public class GattService extends ProfileService {
        ClientMap.App app = mClientMap.getById(clientIf);
        ClientMap.App app = mClientMap.getById(clientIf);
        if (app == null) return;
        if (app == null) return;
        Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData);
        Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData);
        for (ScanResult result : new ArrayList<ScanResult>(results)) {
            Log.d(TAG, result.getScanRecord().toString());
        }
        app.callback.onBatchScanResults(new ArrayList<ScanResult>(results));
        app.callback.onBatchScanResults(new ArrayList<ScanResult>(results));
    }
    }


@@ -994,6 +999,7 @@ public class GattService extends ProfileService {
    }
    }


    private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) {
    private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) {
        Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord));
        Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
        Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
        int position = 0;
        int position = 0;
        while (position < batchRecord.length) {
        while (position < batchRecord.length) {
@@ -1019,6 +1025,7 @@ public class GattService extends ProfileService {
            System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen);
            System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen);
            System.arraycopy(scanResponseBytes, 0, scanRecord,
            System.arraycopy(scanResponseBytes, 0, scanRecord,
                    advertisePacketLen, scanResponsePacketLen);
                    advertisePacketLen, scanResponsePacketLen);
            Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord));
            results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord),
            results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord),
                    rssi, timestampNanos));
                    rssi, timestampNanos));
        }
        }
+50 −3
Original line number Original line Diff line number Diff line
@@ -16,7 +16,10 @@


package com.android.bluetooth.gatt;
package com.android.bluetooth.gatt;


import android.bluetooth.BluetoothUuid;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanFilter;
import android.os.ParcelUuid;
import android.util.Log;


import java.util.Arrays;
import java.util.Arrays;
import java.util.HashSet;
import java.util.HashSet;
@@ -32,11 +35,15 @@ import java.util.UUID;
 */
 */
/* package */class ScanFilterQueue {
/* package */class ScanFilterQueue {
    public static final int TYPE_DEVICE_ADDRESS = 0;
    public static final int TYPE_DEVICE_ADDRESS = 0;
    public static final int TYPE_SERVICE_DATA = 1;
    public static final int TYPE_SERVICE_DATA_CHANGED = 1;
    public static final int TYPE_SERVICE_UUID = 2;
    public static final int TYPE_SERVICE_UUID = 2;
    public static final int TYPE_SOLICIT_UUID = 3;
    public static final int TYPE_SOLICIT_UUID = 3;
    public static final int TYPE_LOCAL_NAME = 4;
    public static final int TYPE_LOCAL_NAME = 4;
    public static final int TYPE_MANUFACTURER_DATA = 5;
    public static final int TYPE_MANUFACTURER_DATA = 5;
    public static final int TYPE_SERVICE_DATA = 6;

    // Max length is 31 - 3(flags) - 2 (one byte for length and one byte for type).
    private static final int MAX_LEN_PER_FIELD = 26;


    // Values defined in bluedroid.
    // Values defined in bluedroid.
    private static final byte DEVICE_TYPE_ALL = 0;
    private static final byte DEVICE_TYPE_ALL = 0;
@@ -91,7 +98,7 @@ import java.util.UUID;


    void addServiceChanged() {
    void addServiceChanged() {
        Entry entry = new Entry();
        Entry entry = new Entry();
        entry.type = TYPE_SERVICE_DATA;
        entry.type = TYPE_SERVICE_DATA_CHANGED;
        mEntries.add(entry);
        mEntries.add(entry);
    }
    }


@@ -146,6 +153,14 @@ import java.util.UUID;
        mEntries.add(entry);
        mEntries.add(entry);
    }
    }


    void addServiceData(byte[] data, byte[] dataMask) {
        Entry entry = new Entry();
        entry.type = TYPE_SERVICE_DATA;
        entry.data = data;
        entry.data_mask = dataMask;
        mEntries.add(entry);
    }

    Entry pop() {
    Entry pop() {
        if (isEmpty()) {
        if (isEmpty()) {
            return null;
            return null;
@@ -178,7 +193,6 @@ import java.util.UUID;
    int getFeatureSelection() {
    int getFeatureSelection() {
        int selc = 0;
        int selc = 0;
        for (Entry entry : mEntries) {
        for (Entry entry : mEntries) {
            System.out.println("entry selc value " + (1 << entry.type));
            selc |= (1 << entry.type);
            selc |= (1 << entry.type);
        }
        }
        return selc;
        return selc;
@@ -212,5 +226,38 @@ import java.util.UUID;
                        filter.getManufacturerData(), filter.getManufacturerDataMask());
                        filter.getManufacturerData(), filter.getManufacturerDataMask());
            }
            }
        }
        }
        if (filter.getServiceDataUuid() != null && filter.getServiceData() != null) {
            ParcelUuid serviceDataUuid = filter.getServiceDataUuid();
            byte[] serviceData = filter.getServiceData();
            byte[] serviceDataMask = filter.getServiceDataMask();
            if (serviceDataMask == null) {
                serviceDataMask = new byte[serviceData.length];
                Arrays.fill(serviceDataMask, (byte) 0xFF);
            }
            serviceData = concate(serviceDataUuid, serviceData);
            serviceDataMask = concate(serviceDataUuid, serviceDataMask);
            if (serviceData != null && serviceDataMask != null) {
                addServiceData(serviceData, serviceDataMask);
            }
        }
    }

    private byte[] concate(ParcelUuid serviceDataUuid, byte[] serviceData) {
        int dataLen = 2 + (serviceData == null ? 0 : serviceData.length);
        // If data is too long, don't add it to hardware scan filter.
        if (dataLen > MAX_LEN_PER_FIELD) {
            return null;
        }
        byte[] concated = new byte[dataLen];
        // Extract 16 bit UUID value.
        int uuidValue = BluetoothUuid.getServiceIdentifierFromParcelUuid(
                serviceDataUuid);
        // First two bytes are service data UUID in little-endian.
        concated[0] = (byte) (uuidValue & 0xFF);
        concated[1] = (byte) ((uuidValue >> 8) & 0xFF);
        if (serviceData != null) {
            System.arraycopy(serviceData, 0, concated, 2, serviceData.length);
        }
        return concated;
    }
    }
}
}
+70 −7
Original line number Original line Diff line number Diff line
@@ -16,13 +16,20 @@


package com.android.bluetooth.gatt;
package com.android.bluetooth.gatt;


import android.app.AlarmManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanSettings;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.util.Log;


import com.android.bluetooth.Utils;
import com.android.bluetooth.Utils;
@@ -57,6 +64,9 @@ public class ScanManager {
    private static final int MSG_STOP_BLE_SCAN = 1;
    private static final int MSG_STOP_BLE_SCAN = 1;
    private static final int MSG_FLUSH_BATCH_RESULTS = 2;
    private static final int MSG_FLUSH_BATCH_RESULTS = 2;


    private static final String ACTION_REFRESH_BATCHED_SCAN =
            "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN";

    // Timeout for each controller operation.
    // Timeout for each controller operation.
    private static final int OPERATION_TIME_OUT_MILLIS = 500;
    private static final int OPERATION_TIME_OUT_MILLIS = 500;


@@ -72,8 +82,8 @@ public class ScanManager {
    ScanManager(GattService service) {
    ScanManager(GattService service) {
        mRegularScanClients = new HashSet<ScanClient>();
        mRegularScanClients = new HashSet<ScanClient>();
        mBatchClients = new HashSet<ScanClient>();
        mBatchClients = new HashSet<ScanClient>();
        mScanNative = new ScanNative();
        mService = service;
        mService = service;
        mScanNative = new ScanNative();
    }
    }


    void start() {
    void start() {
@@ -85,6 +95,7 @@ public class ScanManager {
    void cleanup() {
    void cleanup() {
        mRegularScanClients.clear();
        mRegularScanClients.clear();
        mBatchClients.clear();
        mBatchClients.clear();
        mScanNative.cleanup();
    }
    }


    /**
    /**
@@ -236,10 +247,34 @@ public class ScanManager {
        private final Deque<Integer> mFilterIndexStack;
        private final Deque<Integer> mFilterIndexStack;
        // Map of clientIf and Filter indices used by client.
        // Map of clientIf and Filter indices used by client.
        private final Map<Integer, Deque<Integer>> mClientFilterIndexMap;
        private final Map<Integer, Deque<Integer>> mClientFilterIndexMap;
        private AlarmManager mAlarmManager;
        private PendingIntent mBatchScanIntervalIntent;


        ScanNative() {
        ScanNative() {
            mFilterIndexStack = new ArrayDeque<Integer>();
            mFilterIndexStack = new ArrayDeque<Integer>();
            mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>();
            mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>();

            mAlarmManager = (AlarmManager) mService.getSystemService(Context.ALARM_SERVICE);
            Intent batchIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null);
            mBatchScanIntervalIntent = PendingIntent.getBroadcast(mService, 0, batchIntent, 0);
            IntentFilter filter = new IntentFilter();
            filter.addAction(ACTION_REFRESH_BATCHED_SCAN);
            mService.registerReceiver(
                    new BroadcastReceiver() {
                    @Override
                        public void onReceive(Context context, Intent intent) {
                            Log.d(TAG, "awakened up at time " + SystemClock.elapsedRealtime());
                            String action = intent.getAction();

                            if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) {
                                if (mBatchClients.isEmpty()) {
                                    return;
                                }
                                // TODO: find out if we need to flush all clients at once.
                                flushBatchScanResults(mBatchClients.iterator().next());
                            }
                        }
                    }, filter);
        }
        }


        private void resetCountDownLatch() {
        private void resetCountDownLatch() {
@@ -286,10 +321,24 @@ public class ScanManager {
            int scanWindowUnit = 8;
            int scanWindowUnit = 8;
            int discardRule = 2;
            int discardRule = 2;
            int addressType = 0;
            int addressType = 0;
            logd("Starting BLE batch scan");
            gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit,
            gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit, scanWindowUnit,
                    scanWindowUnit, addressType, discardRule);
                    addressType,
            logd("Starting BLE batch scan, scanMode -" + scanMode);
                    discardRule);
            gattClientStartBatchScanNative(client.clientIf, scanMode, scanIntervalUnit,
                    scanWindowUnit, addressType, discardRule);
            setBatchAlarm();
        }

        private void setBatchAlarm() {
            if (mBatchClients.isEmpty()) {
                mAlarmManager.cancel(mBatchScanIntervalIntent);
                return;
            }
            long batchTriggerIntervalMillis = getBatchTriggerIntervalMillis();
            mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    SystemClock.elapsedRealtime() + batchTriggerIntervalMillis,
                    batchTriggerIntervalMillis,
                    mBatchScanIntervalIntent);
        }
        }


        void stopRegularScan(ScanClient client) {
        void stopRegularScan(ScanClient client) {
@@ -306,6 +355,7 @@ public class ScanManager {
            removeScanFilters(client.clientIf);
            removeScanFilters(client.clientIf);
            mBatchClients.remove(client);
            mBatchClients.remove(client);
            gattClientStopBatchScanNative(client.clientIf);
            gattClientStopBatchScanNative(client.clientIf);
            setBatchAlarm();
        }
        }


        void flushBatchResults(int clientIf) {
        void flushBatchResults(int clientIf) {
@@ -319,6 +369,21 @@ public class ScanManager {
            gattClientReadScanReportsNative(client.clientIf, resultType);
            gattClientReadScanReportsNative(client.clientIf, resultType);
        }
        }


        void cleanup() {
            mAlarmManager.cancel(mBatchScanIntervalIntent);
        }

        private long getBatchTriggerIntervalMillis() {
            long intervalMillis = Long.MAX_VALUE;
            for (ScanClient client : mBatchClients) {
                if (client.settings != null && client.settings.getReportDelayMillis() > 0) {
                    intervalMillis = Math.min(intervalMillis,
                            client.settings.getReportDelayMillis());
                }
            }
            return intervalMillis;
        }

        // Add scan filters. The logic is:
        // Add scan filters. The logic is:
        // If no offload filter can/needs to be set, set ALLOW_ALL filter.
        // If no offload filter can/needs to be set, set ALLOW_ALL filter.
        // Otherwise offload all filters to hardware and enable all filters.
        // Otherwise offload all filters to hardware and enable all filters.
@@ -430,7 +495,6 @@ public class ScanManager {
                    break;
                    break;


                case ScanFilterQueue.TYPE_MANUFACTURER_DATA:
                case ScanFilterQueue.TYPE_MANUFACTURER_DATA:
                {
                    int len = entry.data.length;
                    int len = entry.data.length;
                    if (entry.data_mask.length != len)
                    if (entry.data_mask.length != len)
                        return;
                        return;
@@ -440,7 +504,6 @@ public class ScanManager {
                    break;
                    break;
            }
            }
        }
        }
        }


        private void initFilterIndexStack() {
        private void initFilterIndexStack() {
            int maxFiltersSupported =
            int maxFiltersSupported =