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

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

am d4bda90f: Merge "Fixed batch scan returning status 12 when restarted." into lmp-dev

* commit 'd4bda90f':
  Fixed batch scan returning status 12 when restarted.
parents 85f7b1ae d4bda90f
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @hide
@@ -38,6 +39,8 @@ import java.util.UUID;

final public class Utils {
    private static final String TAG = "BluetoothUtils";
    private static final int MICROS_PER_UNIT = 625;

    static final int BD_ADDR_LEN = 6; // bytes
    static final int BD_UUID_LEN = 16; // bytes

@@ -217,4 +220,10 @@ final public class Utils {
                "Need BLUETOOTH_ADMIN permission");
    }

    /**
     * Converts {@code millisecond} to unit. Each unit is 0.625 millisecond.
     */
    public static int millsToUnit(int milliseconds) {
        return (int) (TimeUnit.MILLISECONDS.toMicros(milliseconds) / MICROS_PER_UNIT);
    }
}
+4 −10
Original line number Diff line number Diff line
@@ -238,7 +238,6 @@ class AdvertiseManager {
        // Add some randomness to the advertising min/max interval so the controller can do some
        // optimization.
        private static final int ADVERTISING_INTERVAL_DELTA_UNIT = 10;
        private static final int ADVERTISING_INTERVAL_MICROS_PER_UNIT = 625;

        // The following constants should be kept the same as those defined in bt stack.
        private static final int ADVERTISING_CHANNEL_37 = 1 << 0;
@@ -417,22 +416,17 @@ class AdvertiseManager {
        private long getAdvertisingIntervalUnit(AdvertiseSettings settings) {
            switch (settings.getMode()) {
                case AdvertiseSettings.ADVERTISE_MODE_LOW_POWER:
                    return millsToUnit(ADVERTISING_INTERVAL_HIGH_MILLS);
                    return Utils.millsToUnit(ADVERTISING_INTERVAL_HIGH_MILLS);
                case AdvertiseSettings.ADVERTISE_MODE_BALANCED:
                    return millsToUnit(ADVERTISING_INTERVAL_MEDIUM_MILLS);
                    return Utils.millsToUnit(ADVERTISING_INTERVAL_MEDIUM_MILLS);
                case AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY:
                    return millsToUnit(ADVERTISING_INTERVAL_LOW_MILLS);
                    return Utils.millsToUnit(ADVERTISING_INTERVAL_LOW_MILLS);
                default:
                    // Shouldn't happen, just in case.
                    return millsToUnit(ADVERTISING_INTERVAL_HIGH_MILLS);
                    return Utils.millsToUnit(ADVERTISING_INTERVAL_HIGH_MILLS);
            }
        }

        private long millsToUnit(int millisecond) {
            return TimeUnit.MILLISECONDS.toMicros(millisecond)
                    / ADVERTISING_INTERVAL_MICROS_PER_UNIT;
        }

        // Native functions
        private native void gattClientDisableAdvNative(int client_if);

+1 −1
Original line number Diff line number Diff line
@@ -981,7 +981,7 @@ public class GattService extends ProfileService {
            if (app == null) return;
            app.callback.onBatchScanResults(new ArrayList<ScanResult>(results));
        } else {
            for (ScanClient client : mScanManager.getBatchScanQueue()) {
            for (ScanClient client : mScanManager.getFullBatchScanQueue()) {
                // Deliver results for each client.
                deliverBatchScan(client, results);
            }
+183 −148
Original line number Diff line number Diff line
@@ -36,11 +36,9 @@ import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -58,6 +56,7 @@ public class ScanManager {
    // Result type defined in bt stack. Need to be accessed by GattService.
    static final int SCAN_RESULT_TYPE_TRUNCATED = 1;
    static final int SCAN_RESULT_TYPE_FULL = 2;
    static final int SCAN_RESULT_TYPE_BOTH = 3;

    // Internal messages for handling BLE scan operations.
    private static final int MSG_START_BLE_SCAN = 0;
@@ -71,10 +70,8 @@ public class ScanManager {
    private static final int OPERATION_TIME_OUT_MILLIS = 500;

    private int mLastConfiguredScanSetting = Integer.MIN_VALUE;
    private int mLastConfiguredBatchFullScanSetting = Integer.MIN_VALUE;
    private int mLastConfiguredBatchFullClientIf = Integer.MIN_VALUE;
    private int mLastConfiguredBatchTruncScanSetting = Integer.MIN_VALUE;
    private int mLastConfiguredBatchTruncClientIf = Integer.MIN_VALUE;
    // Scan parameters for batch scan.
    private BatchScanParams mBatchScanParms;

    private GattService mService;
    private BroadcastReceiver mBatchAlarmReceiver;
@@ -120,6 +117,21 @@ public class ScanManager {
        return mBatchClients;
    }

    /**
     * Returns a set of full batch scan clients.
     */
    Set<ScanClient> getFullBatchScanQueue() {
        // TODO: split full batch scan clients and truncated batch clients so we don't need to
        // construct this every time.
        Set<ScanClient> fullBatchClients = new HashSet<ScanClient>();
        for (ScanClient client : mBatchClients) {
            if (client.settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL) {
                fullBatchClients.add(client);
            }
        }
        return fullBatchClients;
    }

    void startScan(ScanClient client) {
        sendMessage(MSG_START_BLE_SCAN, client);
    }
@@ -195,8 +207,6 @@ public class ScanManager {
            if (isBatchClient(client)) {
                mBatchClients.add(client);
                mScanNative.startBatchScan(client);
                mScanNative.configureBatchScanParams(SCAN_RESULT_TYPE_FULL);
                mScanNative.configureBatchScanParams(SCAN_RESULT_TYPE_TRUNCATED);
            } else {
                mRegularScanClients.add(client);
                mScanNative.startRegularScan(client);
@@ -249,6 +259,35 @@ public class ScanManager {
        }
    }

    /**
     * Parameters for batch scans.
     */
    class BatchScanParams {
        int scanMode;
        int fullScanClientIf;
        int truncatedScanClientIf;

        BatchScanParams() {
            scanMode = -1;
            fullScanClientIf = -1;
            truncatedScanClientIf = -1;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }
            BatchScanParams other = (BatchScanParams) obj;
            return scanMode == other.scanMode && fullScanClientIf == other.fullScanClientIf
                    && truncatedScanClientIf == other.truncatedScanClientIf;

        }
    }

    private class ScanNative {

        // Delivery mode defined in bt stack.
@@ -335,62 +374,17 @@ public class ScanManager {
            }
        }

        void updateAndConfigureScanParam(int clientIf, int curScanSetting, int resultType,
                int scanWindow, int scanInterval) {

            int discardRule = DISCARD_OLDEST_WHEN_BUFFER_FULL;
            int addressType = 0;

            if (resultType == SCAN_RESULT_TYPE_FULL) {
                if (mLastConfiguredBatchFullClientIf != Integer.MIN_VALUE) {
                    gattClientStopBatchScanNative(mLastConfiguredBatchFullClientIf);
                }
                gattClientStartBatchScanNative(clientIf, resultType, scanInterval,
                            scanWindow, addressType, discardRule);
                mLastConfiguredBatchFullScanSetting = curScanSetting;
                mLastConfiguredBatchFullClientIf = clientIf;
            } else if (resultType == SCAN_RESULT_TYPE_TRUNCATED) {
                if (mLastConfiguredBatchTruncClientIf != Integer.MIN_VALUE) {
                    gattClientStopBatchScanNative(mLastConfiguredBatchTruncClientIf);
                }
                gattClientStartBatchScanNative(clientIf, resultType, scanInterval,
                            scanWindow, addressType, discardRule);
                mLastConfiguredBatchTruncScanSetting = curScanSetting;
                mLastConfiguredBatchTruncClientIf = clientIf;
            }
        }

        int getLastConfiguredBatchScanSetting(int resultType) {
            if (resultType == SCAN_RESULT_TYPE_FULL) {
                return mLastConfiguredBatchFullScanSetting;
            } else if (resultType == SCAN_RESULT_TYPE_TRUNCATED) {
                return mLastConfiguredBatchTruncScanSetting;
            }
            return Integer.MIN_VALUE;
        }

        void resetBatchScanParam(int resultType) {
            if (resultType == SCAN_RESULT_TYPE_FULL) {
                mLastConfiguredBatchFullScanSetting = Integer.MIN_VALUE;
                mLastConfiguredBatchFullClientIf = Integer.MIN_VALUE;
            } else if (resultType == SCAN_RESULT_TYPE_TRUNCATED) {
                mLastConfiguredBatchTruncScanSetting = Integer.MIN_VALUE;
                mLastConfiguredBatchTruncClientIf = Integer.MIN_VALUE;
            }
        }


        void configureRegularScanParams() {
            if (DBG) Log.d(TAG, "configureRegularScanParams() - queue=" + mRegularScanClients.size());
            logd("configureRegularScanParams() - queue=" + mRegularScanClients.size());
            int curScanSetting = Integer.MIN_VALUE;
            ScanClient client = null;

            client = getAggressiveClient(mRegularScanClients, false, SCAN_RESULT_TYPE_FULL);
            client = getAggressiveClient(mRegularScanClients);
            if (client != null) {
                curScanSetting = client.settings.getScanMode();
            }

            if (DBG) Log.d(TAG, "configureRegularScanParams() - ScanSetting Scan mode=" + curScanSetting +
            logd("configureRegularScanParams() - ScanSetting Scan mode=" + curScanSetting +
                    " mLastConfiguredScanSetting=" + mLastConfiguredScanSetting);

            if (curScanSetting != Integer.MIN_VALUE) {
@@ -416,8 +410,8 @@ public class ScanManager {
                            break;
                    }
                    // convert scanWindow and scanInterval from ms to LE scan units(0.625ms)
                    scanWindow = (scanWindow * 1000)/625;
                    scanInterval = (scanInterval * 1000)/625;
                    scanWindow = Utils.millsToUnit(scanWindow);
                    scanInterval = Utils.millsToUnit(scanInterval);
                    gattClientScanNative(false);
                    gattSetScanParametersNative(scanInterval, scanWindow);
                    gattClientScanNative(true);
@@ -425,80 +419,23 @@ public class ScanManager {
                }
            } else {
                mLastConfiguredScanSetting = curScanSetting;
                if (DBG) Log.d(TAG, "configureRegularScanParams() - queue emtpy, scan stopped");
                logd("configureRegularScanParams() - queue emtpy, scan stopped");
            }
        }

       ScanClient getAggressiveClient(Set<ScanClient> cList, boolean isBatchClientList, int resultType) {
        ScanClient getAggressiveClient(Set<ScanClient> cList) {
            ScanClient result = null;
            int curScanSetting = Integer.MIN_VALUE;
            for (ScanClient client : cList) {
                // ScanClient scan settings are assumed to be monotonically increasing in value for more
                // power hungry(higher duty cycle) operation
                // For batch clients, there are 2 possible scan modes Truncated or Full
                // Match resultType based on client list
                if (!isBatchClientList ||
                    (isBatchClientList && resultType == getResultType(client.settings))) {
                // ScanClient scan settings are assumed to be monotonically increasing in value for
                // more power hungry(higher duty cycle) operation.
                if (client.settings.getScanMode() > curScanSetting) {
                    result = client;
                }
            }
            }
            return result;
        }

        void configureBatchScanParams(int resultType) {
            if (DBG) Log.d(TAG, "configureBathScanParams() - queue=" + mBatchClients.size());
            int curScanSetting = Integer.MIN_VALUE;
            int clientIf = Integer.MIN_VALUE;
            ScanClient client = null;
            int lastConfiguredBatchScanSetting = getLastConfiguredBatchScanSetting(resultType);

            client = getAggressiveClient(mBatchClients, true, resultType);
            if (client != null) {
                curScanSetting = client.settings.getScanMode();
                clientIf = client.clientIf;
            }

            if (DBG) Log.d(TAG, "configureBatchScanParams() - ScanSetting Scan mode=" + curScanSetting +
                    " lastConfiguredBatchScanSetting=" + lastConfiguredBatchScanSetting +
                    " scanType=" + resultType);

            if (curScanSetting != Integer.MIN_VALUE) {
                if (curScanSetting != lastConfiguredBatchScanSetting) {
                    int scanWindow, scanInterval;
                    switch (curScanSetting){
                        case ScanSettings.SCAN_MODE_LOW_POWER:
                            scanWindow = SCAN_MODE_BATCH_LOW_POWER_WINDOW_MS;
                            scanInterval = SCAN_MODE_BATCH_LOW_POWER_INTERVAL_MS;
                            break;
                        case ScanSettings.SCAN_MODE_BALANCED:
                            scanWindow = SCAN_MODE_BATCH_BALANCED_WINDOW_MS;
                            scanInterval = SCAN_MODE_BATCH_BALANCED_INTERVAL_MS;
                            break;
                        case ScanSettings.SCAN_MODE_LOW_LATENCY:
                            scanWindow = SCAN_MODE_BATCH_LOW_LATENCY_WINDOW_MS;
                            scanInterval = SCAN_MODE_BATCH_LOW_LATENCY_INTERVAL_MS;
                            break;
                        default:
                            Log.e(TAG, "Invalid value for curScanSetting " + curScanSetting);
                            scanWindow = SCAN_MODE_BATCH_LOW_POWER_WINDOW_MS;
                            scanInterval = SCAN_MODE_BATCH_LOW_POWER_INTERVAL_MS;
                            break;
                    }
                    // convert scanWindow and scanInterval from ms to LE scan units(0.625ms)
                    scanWindow = (scanWindow * 1000)/625;
                    scanInterval = (scanInterval * 1000)/625;
                    updateAndConfigureScanParam(clientIf, curScanSetting, resultType,
                            scanWindow, scanInterval);
                }
            } else {
                resetBatchScanParam(resultType);
                if (DBG) Log.d(TAG, "configureBatchScanParams() - queue emtpy," +
                            "resetting batch scan config params");
            }
        }

        void startRegularScan(ScanClient client) {
            if (mFilterIndexStack.isEmpty() && isFilteringSupported()) {
                initFilterIndexStack();
@@ -517,22 +454,112 @@ public class ScanManager {
                initFilterIndexStack();
            }
            configureScanFilters(client);
            int fullScanPercent = 50;
            // Reset batch scan. May need to stop the existing batch scan and update scan params.
            resetBatchScan(client);
        }

        private void resetBatchScan(ScanClient client) {
            int clientIf = client.clientIf;
            BatchScanParams batchScanParams = getBatchScanParams();
            // Stop batch if batch scan params changed and previous params is not null.
            if (mBatchScanParms != null && (!mBatchScanParms.equals(batchScanParams))) {
                logd("stopping BLe Batch");
                resetCountDownLatch();
                gattClientStopBatchScanNative(clientIf);
                waitForCallback();
                // Clear pending results as it's illegal to config storage if there are still
                // pending results.
                flushBatchResults(clientIf);
            }
            // Start batch if batchScanParams changed and current params is not null.
            if (batchScanParams != null && (!batchScanParams.equals(mBatchScanParms))) {
                int notifyThreshold = 95;
                logd("Starting BLE batch scan");
                int resultType = getResultType(batchScanParams);
                int fullScanPercent = getFullScanStoragePercent(resultType);
                resetCountDownLatch();
                logd("configuring batch scan storage, appIf " + client.clientIf);
                gattClientConfigBatchScanStorageNative(client.clientIf, fullScanPercent,
                        100 - fullScanPercent, notifyThreshold);
                waitForCallback();
            logd("Starting BLE batch scan");
                resetCountDownLatch();
                int scanInterval =
                        Utils.millsToUnit(getBatchScanIntervalMillis(batchScanParams.scanMode));
                int scanWindow =
                        Utils.millsToUnit(getBatchScanWindowMillis(batchScanParams.scanMode));
                gattClientStartBatchScanNative(clientIf, resultType, scanInterval,
                        scanWindow, 0, DISCARD_OLDEST_WHEN_BUFFER_FULL);
                waitForCallback();
            }
            mBatchScanParms = batchScanParams;
            setBatchAlarm();
        }

        private int getFullScanStoragePercent(int resultType) {
            switch (resultType) {
                case SCAN_RESULT_TYPE_FULL:
                    return 100;
                case SCAN_RESULT_TYPE_TRUNCATED:
                    return 0;
                case SCAN_RESULT_TYPE_BOTH:
                    return 50;
                default:
                    return 50;
            }
        }

        private BatchScanParams getBatchScanParams() {
            if (mBatchClients.isEmpty()) {
                return null;
            }
            BatchScanParams params = new BatchScanParams();
            // TODO: split full batch scan results and truncated batch scan results to different
            // collections.
            for (ScanClient client : mBatchClients) {
                params.scanMode = Math.max(params.scanMode, client.settings.getScanMode());
                if (client.settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL) {
                    params.fullScanClientIf = client.clientIf;
                } else {
                    params.truncatedScanClientIf = client.clientIf;
                }
            }
            return params;
        }

        private int getBatchScanWindowMillis(int scanMode) {
            switch (scanMode) {
                case ScanSettings.SCAN_MODE_LOW_LATENCY:
                    return SCAN_MODE_BATCH_LOW_LATENCY_WINDOW_MS;
                case ScanSettings.SCAN_MODE_BALANCED:
                    return SCAN_MODE_BATCH_BALANCED_WINDOW_MS;
                case ScanSettings.SCAN_MODE_LOW_POWER:
                    return SCAN_MODE_BATCH_LOW_POWER_WINDOW_MS;
                default:
                    return SCAN_MODE_BATCH_LOW_POWER_WINDOW_MS;
            }
        }

        private int getBatchScanIntervalMillis(int scanMode) {
            switch (scanMode) {
                case ScanSettings.SCAN_MODE_LOW_LATENCY:
                    return SCAN_MODE_BATCH_LOW_LATENCY_INTERVAL_MS;
                case ScanSettings.SCAN_MODE_BALANCED:
                    return SCAN_MODE_BATCH_BALANCED_INTERVAL_MS;
                case ScanSettings.SCAN_MODE_LOW_POWER:
                    return SCAN_MODE_BATCH_LOW_POWER_INTERVAL_MS;
                default:
                    return SCAN_MODE_BATCH_LOW_POWER_INTERVAL_MS;
            }
        }

        // Set the batch alarm to be triggered within a short window after batch interval. This
        // allows system to optimize wake up time while still allows a degree of precise control.
        private void setBatchAlarm() {
            // Cancel any pending alarm just in case.
            mAlarmManager.cancel(mBatchScanIntervalIntent);
            if (mBatchClients.isEmpty()) {
                return;
            }
            long batchTriggerIntervalMillis = getBatchTriggerIntervalMillis();
            // Allows the alarm to be triggered within
            // [batchTriggerIntervalMillis, 1.1 * batchTriggerIntervalMillis]
@@ -554,25 +581,25 @@ public class ScanManager {
        }

        void stopBatchScan(ScanClient client) {
            flushBatchResults(client.clientIf);
            removeScanFilters(client.clientIf);
            mBatchClients.remove(client);
            configureBatchScanParams(SCAN_RESULT_TYPE_FULL);
            configureBatchScanParams(SCAN_RESULT_TYPE_TRUNCATED);
            setBatchAlarm();
            removeScanFilters(client.clientIf);
            resetBatchScan(client);
        }

        void flushBatchResults(int clientIf) {
            logd("flushPendingBatchResults - clientIf = " + clientIf);
            ScanClient client = getBatchScanClient(clientIf);
            if (client == null) {
                logd("unknown client : " + clientIf);
                return;
            if (mBatchScanParms.fullScanClientIf != -1) {
                resetCountDownLatch();
                gattClientReadScanReportsNative(mBatchScanParms.fullScanClientIf,
                        SCAN_RESULT_TYPE_FULL);
                waitForCallback();
            }
            int resultType = getResultType(client.settings);
            if (mBatchScanParms.truncatedScanClientIf != -1) {
                resetCountDownLatch();
            gattClientReadScanReportsNative(client.clientIf, resultType);
                gattClientReadScanReportsNative(mBatchScanParms.truncatedScanClientIf,
                        SCAN_RESULT_TYPE_TRUNCATED);
                waitForCallback();
            }
            setBatchAlarm();
        }

@@ -659,9 +686,17 @@ public class ScanManager {
        /**
         * Return batch scan result type value defined in bt stack.
         */
        private int getResultType(ScanSettings settings) {
            return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL ?
                    SCAN_RESULT_TYPE_FULL : SCAN_RESULT_TYPE_TRUNCATED;
        private int getResultType(BatchScanParams params) {
            if (params.fullScanClientIf != -1 && params.truncatedScanClientIf != -1) {
                return SCAN_RESULT_TYPE_BOTH;
            }
            if (params.truncatedScanClientIf != -1) {
                return SCAN_RESULT_TYPE_TRUNCATED;
            }
            if (params.fullScanClientIf != -1) {
                return SCAN_RESULT_TYPE_FULL;
            }
            return -1;
        }

        // Check if ALLOW_FILTER should be used for the client.
@@ -823,6 +858,6 @@ public class ScanManager {
    }

    private void logd(String s) {
        Log.d(TAG, s);
        if (DBG) Log.d(TAG, s);
    }
}