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

Commit 3cd588c8 authored by Liang Li's avatar Liang Li Committed by Automerger Merge Worker
Browse files

Merge "Add logging for BLE scan and adv new atoms" into main am: 22dbc318

parents b3930d83 22dbc318
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -266,8 +266,8 @@ public class BluetoothMethodProxy {

    /** Proxies {@link AppAdvertiseStats}. */
    public AppAdvertiseStats createAppAdvertiseStats(
            int id, String name, ContextMap map, GattService service) {
        return new AppAdvertiseStats(id, name, map, service);
            int appUid, int id, String name, ContextMap map, GattService service) {
        return new AppAdvertiseStats(appUid, id, name, map, service);
    }

    /** Proxies {@link Thread#start()}. */
+82 −0
Original line number Diff line number Diff line
@@ -389,6 +389,88 @@ public class MetricsLogger {
        return matchedString;
    }

    /** Logs the app scan stats with app attribution when the app scan state changed. */
    public void logAppScanStateChanged(
            int[] uids,
            String[] tags,
            boolean enabled,
            boolean isFilterScan,
            boolean isCallbackScan,
            int scanCallBackType,
            int scanType,
            int scanMode,
            long reportDelayMillis,
            long scanDurationMillis,
            int numOngoingScan,
            boolean isScreenOn,
            boolean isAppDead) {
        BluetoothStatsLog.write(
                BluetoothStatsLog.LE_APP_SCAN_STATE_CHANGED,
                uids,
                tags,
                enabled,
                isFilterScan,
                isCallbackScan,
                scanCallBackType,
                scanType,
                scanMode,
                reportDelayMillis,
                scanDurationMillis,
                numOngoingScan,
                isScreenOn,
                isAppDead);
    }

    /** Logs the radio scan stats with app attribution when the radio scan stopped. */
    public void logRadioScanStopped(
            int[] uids,
            String[] tags,
            int scanType,
            int scanMode,
            long scanIntervalMillis,
            long scanWindowMillis,
            boolean isScreenOn,
            long scanDurationMillis) {
        BluetoothStatsLog.write(
                BluetoothStatsLog.LE_RADIO_SCAN_STOPPED,
                uids,
                tags,
                scanType,
                scanMode,
                scanIntervalMillis,
                scanWindowMillis,
                isScreenOn,
                scanDurationMillis);
    }

    /** Logs the advertise stats with app attribution when the advertise state changed. */
    public void logAdvStateChanged(
            int[] uids,
            String[] tags,
            boolean enabled,
            int interval,
            int txPowerLevel,
            boolean isConnectable,
            boolean isPeriodicAdvertisingEnabled,
            boolean hasScanResponse,
            boolean isExtendedAdv,
            int instanceCount,
            long advDurationMs) {
        BluetoothStatsLog.write(
                BluetoothStatsLog.LE_ADV_STATE_CHANGED,
                uids,
                tags,
                enabled,
                interval,
                txPowerLevel,
                isConnectable,
                isPeriodicAdvertisingEnabled,
                hasScanResponse,
                isExtendedAdv,
                instanceCount,
                advDurationMs);
    }

    protected String getAllowlistedDeviceNameHash(String deviceName) {
        List<String> wordBreakdownList = getWordBreakdownList(deviceName);
        String matchedString = getMatchedString(wordBreakdownList);
+3 −4
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.bluetooth.gatt;

import static android.bluetooth.BluetoothProtoEnums.LE_ADV_ERROR_ON_START_COUNT;

import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
@@ -169,10 +168,10 @@ public class AdvertiseManager {

            AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(regId);
            if (stats != null) {
                stats.recordAdvertiseStop();
                stats.recordAdvertiseStop(mAdvertisers.size());
                stats.recordAdvertiseErrorCount(status);
            }
            mAdvertiserMap.removeAppAdvertiseStats(regId);
            AppAdvertiseStats.recordAdvertiseErrorCount(LE_ADV_ERROR_ON_START_COUNT);
        }

        IBinder gattBinder = mService.getBinder();
@@ -204,7 +203,7 @@ public class AdvertiseManager {
        if (!enable && status != 0) {
            AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(advertiserId);
            if (stats != null) {
                stats.recordAdvertiseStop();
                stats.recordAdvertiseStop(mAdvertisers.size());
            }
        }
    }
+103 −21
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.bluetooth.gatt;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertisingSetCallback;
import android.bluetooth.le.AdvertisingSetParameters;
import android.bluetooth.le.PeriodicAdvertisingParameters;
import android.os.ParcelUuid;
@@ -25,7 +26,9 @@ import android.util.SparseArray;

import androidx.annotation.VisibleForTesting;

import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.flags.Flags;

import java.time.Duration;
import java.time.Instant;
@@ -35,7 +38,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/** ScanStats class helps keep track of information about scans on a per application basis. */
/** AdvStats class helps keep track of information about advertising on a per application basis. */
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public class AppAdvertiseStats {
    private static final String TAG = AppAdvertiseStats.class.getSimpleName();
@@ -84,6 +87,7 @@ public class AppAdvertiseStats {
        }
    }

    private int mAppUid;
    private String mAppName;
    private int mId;
    private boolean mAdvertisingEnabled = false;
@@ -104,7 +108,8 @@ public class AppAdvertiseStats {
    public ArrayList<AppAdvertiserRecord> mAdvertiserRecords = new ArrayList<AppAdvertiserRecord>();

    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
    public AppAdvertiseStats(int id, String name, ContextMap map, GattService service) {
    public AppAdvertiseStats(int appUid, int id, String name, ContextMap map, GattService service) {
        this.mAppUid = appUid;
        this.mId = id;
        this.mAppName = name;
        this.mContextMap = map;
@@ -118,7 +123,8 @@ public class AppAdvertiseStats {
            PeriodicAdvertisingParameters periodicParameters,
            AdvertiseData periodicData,
            int duration,
            int maxExtAdvEvents) {
            int maxExtAdvEvents,
            int instanceCount) {
        mAdvertisingEnabled = true;
        AppAdvertiserRecord record = new AppAdvertiserRecord(Instant.now());
        record.duration = duration;
@@ -174,20 +180,24 @@ public class AppAdvertiseStats {
            mPeriodicIncludeTxPower = periodicParameters.getIncludeTxPower();
            mPeriodicInterval = periodicParameters.getInterval();
        }
        recordAdvertiseEnableCount(true, mConnectable, mPeriodicAdvertisingEnabled);
        recordAdvertiseEnableCount(true, instanceCount, 0 /* durationMs */);
    }

    void recordAdvertiseStart(int duration, int maxExtAdvEvents) {
        recordAdvertiseStart(null, null, null, null, null, duration, maxExtAdvEvents);
    void recordAdvertiseStart(int duration, int maxExtAdvEvents, int instanceCount) {
        recordAdvertiseStart(
                null, null, null, null, null, duration, maxExtAdvEvents, instanceCount);
    }

    void recordAdvertiseStop() {
        recordAdvertiseEnableCount(false, mConnectable, mPeriodicAdvertisingEnabled);
    void recordAdvertiseStop(int instanceCount) {
        if (!mAdvertiserRecords.isEmpty()) {
            AppAdvertiserRecord record = mAdvertiserRecords.get(mAdvertiserRecords.size() - 1);
            record.stopTime = Instant.now();
            Duration duration = Duration.between(record.startTime, record.stopTime);
            recordAdvertiseDurationCount(duration, mConnectable, mPeriodicAdvertisingEnabled);
            recordAdvertiseEnableCount(
                    false,
                    instanceCount,
                    record.stopTime.toEpochMilli() - record.startTime.toEpochMilli());
        }
        mAdvertisingEnabled = false;
        mPeriodicAdvertisingEnabled = false;
@@ -206,23 +216,53 @@ public class AppAdvertiseStats {
        }
    }

    static void recordAdvertiseErrorCount(int key) {
        if (key != BluetoothProtoEnums.LE_ADV_ERROR_ON_START_COUNT) {
            return;
        }
        MetricsLogger.getInstance().cacheCount(key, 1);
    }

    void enableAdvertisingSet(boolean enable, int duration, int maxExtAdvEvents) {
    void recordAdvertiseErrorCount(int status) {
        if (Flags.bleScanAdvMetricsRedesign()) {
            BluetoothStatsLog.write(
                    BluetoothStatsLog.LE_ADV_ERROR_REPORTED,
                    new int[] {mAppUid},
                    new String[] {mAppName},
                    BluetoothStatsLog.LE_ADV_ERROR_REPORTED__LE_ADV_OP_CODE__ERROR_CODE_ON_START,
                    convertStatusCode(status));
        }
        MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.LE_ADV_ERROR_ON_START_COUNT, 1);
    }

    private int convertStatusCode(int status) {
        switch (status) {
            case AdvertisingSetCallback.ADVERTISE_SUCCESS:
                return BluetoothStatsLog.LE_ADV_ERROR_REPORTED__STATUS_CODE__ADV_STATUS_SUCCESS;
            case AdvertisingSetCallback.ADVERTISE_FAILED_DATA_TOO_LARGE:
                return BluetoothStatsLog
                        .LE_ADV_ERROR_REPORTED__STATUS_CODE__ADV_STATUS_FAILED_DATA_TOO_LARGE;
            case AdvertisingSetCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS:
                return BluetoothStatsLog
                        .LE_ADV_ERROR_REPORTED__STATUS_CODE__ADV_STATUS_FAILED_TOO_MANY_ADVERTISERS;
            case AdvertisingSetCallback.ADVERTISE_FAILED_ALREADY_STARTED:
                return BluetoothStatsLog
                        .LE_ADV_ERROR_REPORTED__STATUS_CODE__ADV_STATUS_FAILED_ALREADY_STARTED;
            case AdvertisingSetCallback.ADVERTISE_FAILED_INTERNAL_ERROR:
                return BluetoothStatsLog
                        .LE_ADV_ERROR_REPORTED__STATUS_CODE__ADV_STATUS_FAILED_INTERNAL_ERROR;
            case AdvertisingSetCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED:
                return BluetoothStatsLog
                        .LE_ADV_ERROR_REPORTED__STATUS_CODE__ADV_STATUS_FAILED_FEATURE_UNSUPPORTED;
            default:
                return BluetoothStatsLog.LE_ADV_ERROR_REPORTED__STATUS_CODE__ADV_STATUS_UNKNOWN;
        }
    }

    void enableAdvertisingSet(
            boolean enable, int duration, int maxExtAdvEvents, int instanceCount) {
        if (enable) {
            // if the advertisingSet have not been disabled, skip enabling.
            if (!mAdvertisingEnabled) {
                recordAdvertiseStart(duration, maxExtAdvEvents);
                recordAdvertiseStart(duration, maxExtAdvEvents, instanceCount);
            }
        } else {
            // if the advertisingSet have not been enabled, skip disabling.
            if (mAdvertisingEnabled) {
                recordAdvertiseStop();
                recordAdvertiseStop(instanceCount);
            }
        }
    }
@@ -369,31 +409,73 @@ public class AppAdvertiseStats {
        }
    }

    private static void recordAdvertiseEnableCount(
            boolean enable, boolean isConnectable, boolean inPeriodic) {
    private void recordAdvertiseEnableCount(boolean enable, int instanceCount, long durationMs) {
        if (Flags.bleScanAdvMetricsRedesign()) {
            MetricsLogger.getInstance()
                    .logAdvStateChanged(
                            new int[] {mAppUid},
                            new String[] {mAppName},
                            enable /* enabled */,
                            convertAdvInterval(mInterval),
                            convertTxPowerLevel(mTxPowerLevel),
                            mConnectable,
                            mPeriodicAdvertisingEnabled,
                            mScanResponseData != null && mScannable /* hasScanResponse */,
                            !mLegacy /* isExtendedAdv */,
                            instanceCount,
                            durationMs);
        }
        if (enable) {
            MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.LE_ADV_COUNT_ENABLE, 1);
            if (isConnectable) {
            if (mConnectable) {
                MetricsLogger.getInstance()
                        .cacheCount(BluetoothProtoEnums.LE_ADV_COUNT_CONNECTABLE_ENABLE, 1);
            }
            if (inPeriodic) {
            if (mPeriodicAdvertisingEnabled) {
                MetricsLogger.getInstance()
                        .cacheCount(BluetoothProtoEnums.LE_ADV_COUNT_PERIODIC_ENABLE, 1);
            }
        } else {
            MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.LE_ADV_COUNT_DISABLE, 1);
            if (isConnectable) {
            if (mConnectable) {
                MetricsLogger.getInstance()
                        .cacheCount(BluetoothProtoEnums.LE_ADV_COUNT_CONNECTABLE_DISABLE, 1);
            }
            if (inPeriodic) {
            if (mPeriodicAdvertisingEnabled) {
                MetricsLogger.getInstance()
                        .cacheCount(BluetoothProtoEnums.LE_ADV_COUNT_PERIODIC_DISABLE, 1);
            }
        }
    }

    private int convertAdvInterval(int interval) {
        switch (interval) {
            case AdvertisingSetParameters.INTERVAL_HIGH:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_INTERVAL__INTERVAL_HIGH;
            case AdvertisingSetParameters.INTERVAL_MEDIUM:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_INTERVAL__INTERVAL_MEDIUM;
            case AdvertisingSetParameters.INTERVAL_LOW:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_INTERVAL__INTERVAL_LOW;
            default:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_INTERVAL__INTERVAL_UNKNOWN;
        }
    }

    private int convertTxPowerLevel(int level) {
        switch (level) {
            case AdvertisingSetParameters.TX_POWER_ULTRA_LOW:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_TX_POWER__TX_POWER_ULTRA_LOW;
            case AdvertisingSetParameters.TX_POWER_LOW:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_TX_POWER__TX_POWER_LOW;
            case AdvertisingSetParameters.TX_POWER_MEDIUM:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_TX_POWER__TX_POWER_MEDIUM;
            case AdvertisingSetParameters.TX_POWER_HIGH:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_TX_POWER__TX_POWER_HIGH;
            default:
                return BluetoothStatsLog.LE_ADV_STATE_CHANGED__ADV_TX_POWER__TX_POWER_UNKNOWN;
        }
    }

    private static void dumpAppAdvertiserData(StringBuilder sb, AppAdvertiserData advData) {
        sb.append(
                "\n          └Include Device Name                          : "
+9 −7
Original line number Diff line number Diff line
@@ -252,7 +252,7 @@ public class ContextMap<C, T> {
                if (!mAppAdvertiseStats.containsKey(id)) {
                    AppAdvertiseStats appAdvertiseStats =
                            BluetoothMethodProxy.getInstance()
                                    .createAppAdvertiseStats(id, appName, this, service);
                                    .createAppAdvertiseStats(appUid, id, appName, this, service);
                    mAppAdvertiseStats.put(id, appAdvertiseStats);
                }
            }
@@ -450,6 +450,9 @@ public class ContextMap<C, T> {
            if (stats == null) {
                return;
            }
            int advertiseInstanceCount = mAppAdvertiseStats.size();
            Log.d(TAG, "advertiseInstanceCount is " + advertiseInstanceCount);
            AppAdvertiseStats.recordAdvertiseInstanceCount(advertiseInstanceCount);
            stats.recordAdvertiseStart(
                    parameters,
                    advertiseData,
@@ -457,10 +460,8 @@ public class ContextMap<C, T> {
                    periodicParameters,
                    periodicData,
                    duration,
                    maxExtAdvEvents);
            int advertiseInstanceCount = mAppAdvertiseStats.size();
            Log.d(TAG, "advertiseInstanceCount is " + advertiseInstanceCount);
            AppAdvertiseStats.recordAdvertiseInstanceCount(advertiseInstanceCount);
                    maxExtAdvEvents,
                    advertiseInstanceCount);
        }
    }

@@ -470,7 +471,7 @@ public class ContextMap<C, T> {
            if (stats == null) {
                return;
            }
            stats.recordAdvertiseStop();
            stats.recordAdvertiseStop(mAppAdvertiseStats.size());
            mAppAdvertiseStats.remove(id);
            mLastAdvertises.add(stats);
        }
@@ -482,7 +483,8 @@ public class ContextMap<C, T> {
            if (stats == null) {
                return;
            }
            stats.enableAdvertisingSet(enable, duration, maxExtAdvEvents);
            stats.enableAdvertisingSet(
                    enable, duration, maxExtAdvEvents, mAppAdvertiseStats.size());
        }
    }

Loading