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

Commit 174926bb authored by William Escande's avatar William Escande
Browse files

AppScanStats: allow to inject time provider

By injecting an interface that can be used to get the time, we allow
test to fake the time

Bug: 330956986
Fix: 330956986
Bug: 380539632
Bug: 380510617
Bug: 380510672
Bug: 380536618
Bug: 380510672
Bug: 380510672
Bug: 380536573
Bug: 378542424
Bug: 346028665
Bug: 347474468
Test: atest ScanManagerTest --rerun-until-failure 3000
Flag: TEST_ONLY || The change in app are no-op
Change-Id: I82fcae4a1c366249ae96924ae49527e44e004fb4
parent 676252a0
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -1285,4 +1285,17 @@ public final class Utils {
    public static @NonNull String formatSimple(@NonNull String format, Object... args) {
        return android.bluetooth.BluetoothUtils.formatSimple(format, args);
    }

    public interface TimeProvider {
        long elapsedRealtime();
    }

    public static final TimeProvider sSystemClock = new SystemClockTimeProvider();

    private static final class SystemClockTimeProvider implements TimeProvider {
        @Override
        public long elapsedRealtime() {
            return android.os.SystemClock.elapsedRealtime();
        }
    }
}
+29 −19
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.bluetooth.le_scan;

import static java.util.Objects.requireNonNull;

import android.annotation.Nullable;
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.le.ScanFilter;
@@ -23,11 +25,11 @@ import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.os.BatteryStatsManager;
import android.os.Binder;
import android.os.SystemClock;
import android.os.WorkSource;

import com.android.bluetooth.BluetoothMetricsProto;
import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.Utils.TimeProvider;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.flags.Flags;
@@ -71,6 +73,7 @@ public class AppScanStats {
    BatteryStatsManager mBatteryStatsManager;

    private final AdapterService mAdapterService;
    private final TimeProvider mTimeProvider;

    private static Object sLock = new Object();

@@ -171,7 +174,9 @@ public class AppScanStats {
            WorkSource source,
            ScannerMap map,
            Context context,
            TransitionalScanHelper scanHelper) {
            TransitionalScanHelper scanHelper,
            TimeProvider timeProvider) {
        mTimeProvider = requireNonNull(timeProvider);
        mAppName = name;
        mScannerMap = map;
        mScanHelper = scanHelper;
@@ -250,7 +255,7 @@ public class AppScanStats {
            return;
        }
        this.mScansStarted++;
        startTime = SystemClock.elapsedRealtime();
        startTime = mTimeProvider.elapsedRealtime();

        LastScan scan =
                new LastScan(
@@ -333,7 +338,7 @@ public class AppScanStats {
            return;
        }
        this.mScansStopped++;
        stopTime = SystemClock.elapsedRealtime();
        stopTime = mTimeProvider.elapsedRealtime();
        long scanDuration = stopTime - scan.timestamp;
        scan.duration = scanDuration;
        if (scan.isSuspended) {
@@ -582,12 +587,17 @@ public class AppScanStats {
    }

    static boolean recordScanRadioStart(
            int scanMode, int scannerId, AppScanStats stats, int scanWindowMs, int scanIntervalMs) {
            int scanMode,
            int scannerId,
            AppScanStats stats,
            int scanWindowMs,
            int scanIntervalMs,
            TimeProvider timeProvider) {
        synchronized (sLock) {
            if (sIsRadioStarted) {
                return false;
            }
            sRadioStartTime = SystemClock.elapsedRealtime();
            sRadioStartTime = timeProvider.elapsedRealtime();
            sRadioScanWorkSourceUtil = stats.mWorkSourceUtil;
            sRadioScanType = convertScanType(stats.getScanFromScannerId(scannerId));
            sRadioScanMode = scanMode;
@@ -598,12 +608,12 @@ public class AppScanStats {
        return true;
    }

    static boolean recordScanRadioStop() {
    static boolean recordScanRadioStop(TimeProvider timeProvider) {
        synchronized (sLock) {
            if (!sIsRadioStarted) {
                return false;
            }
            recordScanRadioDurationMetrics();
            recordScanRadioDurationMetrics(timeProvider);
            if (!Flags.bleScanAdvMetricsRedesign()) {
                sRadioStartTime = 0;
                sIsRadioStarted = false;
@@ -613,12 +623,12 @@ public class AppScanStats {
    }

    @GuardedBy("sLock")
    private static void recordScanRadioDurationMetrics() {
    private static void recordScanRadioDurationMetrics(TimeProvider timeProvider) {
        if (!sIsRadioStarted) {
            return;
        }
        MetricsLogger logger = MetricsLogger.getInstance();
        long currentTime = SystemClock.elapsedRealtime();
        long currentTime = timeProvider.elapsedRealtime();
        long radioScanDuration = currentTime - sRadioStartTime;
        double scanWeight = getScanWeight(sRadioScanMode) * 0.01;
        long weightedDuration = (long) (radioScanDuration * scanWeight);
@@ -746,14 +756,14 @@ public class AppScanStats {
        }
    }

    static void setScreenState(boolean isScreenOn) {
    static void setScreenState(boolean isScreenOn, TimeProvider timeProvider) {
        synchronized (sLock) {
            if (sIsScreenOn == isScreenOn) {
                return;
            }
            if (sIsRadioStarted) {
                recordScanRadioDurationMetrics();
                sRadioStartTime = SystemClock.elapsedRealtime();
                recordScanRadioDurationMetrics(timeProvider);
                sRadioStartTime = timeProvider.elapsedRealtime();
            }
            recordScreenOnOffMetrics(isScreenOn);
            sIsScreenOn = isScreenOn;
@@ -765,7 +775,7 @@ public class AppScanStats {
        if (scan == null || scan.isSuspended) {
            return;
        }
        scan.suspendStartTime = SystemClock.elapsedRealtime();
        scan.suspendStartTime = mTimeProvider.elapsedRealtime();
        scan.isSuspended = true;
    }

@@ -775,7 +785,7 @@ public class AppScanStats {
            return;
        }
        scan.isSuspended = false;
        stopTime = SystemClock.elapsedRealtime();
        stopTime = mTimeProvider.elapsedRealtime();
        long suspendDuration = stopTime - scan.suspendStartTime;
        scan.suspendDuration += suspendDuration;
        mTotalSuspendTime += suspendDuration;
@@ -815,7 +825,7 @@ public class AppScanStats {
            return false;
        }

        return (SystemClock.elapsedRealtime() - mLastScans.get(0).timestamp)
        return (mTimeProvider.elapsedRealtime() - mLastScans.get(0).timestamp)
                < mAdapterService.getScanQuotaWindowMillis();
    }

@@ -823,7 +833,7 @@ public class AppScanStats {
        if (!isScanning()) {
            return false;
        }
        return (SystemClock.elapsedRealtime() - mScanStartTime)
        return (mTimeProvider.elapsedRealtime() - mScanStartTime)
                >= mAdapterService.getScanTimeoutMillis();
    }

@@ -832,7 +842,7 @@ public class AppScanStats {
            return false;
        }
        LastScan lastScan = mLastScans.get(mLastScans.size() - 1);
        return ((SystemClock.elapsedRealtime() - lastScan.duration - lastScan.timestamp)
        return ((mTimeProvider.elapsedRealtime() - lastScan.duration - lastScan.timestamp)
                < LARGE_SCAN_TIME_GAP_MS);
    }

@@ -947,7 +957,7 @@ public class AppScanStats {
    @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate
    public synchronized void dumpToString(StringBuilder sb) {
        long currentTime = System.currentTimeMillis();
        long currTime = SystemClock.elapsedRealtime();
        long currTime = mTimeProvider.elapsedRealtime();
        long scanDuration = 0;
        long suspendDuration = 0;
        long activeDuration = 0;
+17 −12
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
@@ -47,6 +46,7 @@ import android.util.SparseIntArray;
import android.view.Display;

import com.android.bluetooth.Utils;
import com.android.bluetooth.Utils.TimeProvider;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.flags.Flags;
@@ -123,6 +123,7 @@ public class ScanManager {
    private final Context mContext;
    private final TransitionalScanHelper mScanHelper;
    private final AdapterService mAdapterService;
    private final TimeProvider mTimeProvider;
    private ScanNative mScanNative;
    private volatile ClientHandler mHandler;
    private BluetoothAdapterProxy mBluetoothAdapterProxy;
@@ -164,7 +165,8 @@ public class ScanManager {
            TransitionalScanHelper scanHelper,
            AdapterService adapterService,
            BluetoothAdapterProxy bluetoothAdapterProxy,
            Looper looper) {
            Looper looper,
            TimeProvider timeProvider) {
        mRegularScanClients =
                Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
        mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
@@ -173,6 +175,7 @@ public class ScanManager {
        mContext = context;
        mScanHelper = scanHelper;
        mAdapterService = adapterService;
        mTimeProvider = timeProvider;
        mScanNative = new ScanNative(scanHelper);
        mDisplayManager = mContext.getSystemService(DisplayManager.class);
        mActivityManager = mContext.getSystemService(ActivityManager.class);
@@ -195,7 +198,7 @@ public class ScanManager {
        }
        mScreenOn = isScreenOn();
        AppScanStats.initScanRadioState();
        AppScanStats.setScreenState(mScreenOn);
        AppScanStats.setScreenState(mScreenOn, mTimeProvider);
        if (mActivityManager != null) {
            mActivityManager.addOnUidImportanceListener(
                    mUidImportanceListener, FOREGROUND_IMPORTANCE_CUTOFF);
@@ -545,7 +548,7 @@ public class ScanManager {
        }

        void handleScreenOff() {
            AppScanStats.setScreenState(false);
            AppScanStats.setScreenState(false, mTimeProvider);
            if (!mScreenOn) {
                return;
            }
@@ -880,7 +883,7 @@ public class ScanManager {
        }

        void handleScreenOn() {
            AppScanStats.setScreenState(true);
            AppScanStats.setScreenState(true, mTimeProvider);
            if (mScreenOn) {
                return;
            }
@@ -1050,7 +1053,7 @@ public class ScanManager {
                    new BroadcastReceiver() {
                        @Override
                        public void onReceive(Context context, Intent intent) {
                            Log.d(TAG, "awakened up at time " + SystemClock.elapsedRealtime());
                            Log.d(TAG, "awakened up at time " + mTimeProvider.elapsedRealtime());
                            String action = intent.getAction();

                            if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) {
@@ -1107,7 +1110,7 @@ public class ScanManager {
                    int scanInterval = Utils.millsToUnit(scanIntervalMs);
                    int scanPhyMask = getScanPhyMask(client.settings);
                    mNativeInterface.gattClientScan(false);
                    if (!AppScanStats.recordScanRadioStop()) {
                    if (!AppScanStats.recordScanRadioStop(mTimeProvider)) {
                        Log.w(TAG, "There is no scan radio to stop");
                    }
                    Log.d(
@@ -1139,7 +1142,8 @@ public class ScanManager {
                                    client.scannerId,
                                    client.stats,
                                    scanWindowMs,
                                    scanIntervalMs)) {
                                    scanIntervalMs,
                                    mTimeProvider)) {
                        Log.w(TAG, "Scan radio already started");
                    }
                    mLastConfiguredScanSetting = curScanSetting;
@@ -1188,7 +1192,8 @@ public class ScanManager {
                                    client.scannerId,
                                    client.stats,
                                    getScanWindowMillis(client.settings),
                                    getScanIntervalMillis(client.settings))) {
                                    getScanIntervalMillis(client.settings),
                                    mTimeProvider)) {
                        Log.w(TAG, "Scan radio already started");
                    }
                }
@@ -1382,7 +1387,7 @@ public class ScanManager {
            // Allows the alarm to be triggered within
            // [batchTriggerIntervalMillis, 1.1 * batchTriggerIntervalMillis]
            long windowLengthMillis = batchTriggerIntervalMillis / 10;
            long windowStartMillis = SystemClock.elapsedRealtime() + batchTriggerIntervalMillis;
            long windowStartMillis = mTimeProvider.elapsedRealtime() + batchTriggerIntervalMillis;
            mAlarmManager.setWindow(
                    AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    windowStartMillis,
@@ -1418,7 +1423,7 @@ public class ScanManager {
            if (numRegularScanClients() == 0) {
                Log.d(TAG, "stop gattClientScanNative");
                mNativeInterface.gattClientScan(false);
                if (!AppScanStats.recordScanRadioStop()) {
                if (!AppScanStats.recordScanRadioStop(mTimeProvider)) {
                    Log.w(TAG, "There is no scan radio to stop");
                }
            }
@@ -1465,7 +1470,7 @@ public class ScanManager {
            if (numRegularScanClients() == 0) {
                Log.d(TAG, "stop gattClientScanNative");
                mNativeInterface.gattClientScan(false);
                if (!AppScanStats.recordScanRadioStop()) {
                if (!AppScanStats.recordScanRadioStop(mTimeProvider)) {
                    Log.w(TAG, "There is no scan radio to stop");
                }
            }
+4 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.bluetooth.le_scan;

import static com.android.bluetooth.Utils.sSystemClock;

import android.content.Context;
import android.os.Looper;
import android.util.Log;
@@ -79,7 +81,8 @@ public class ScanObjectsFactory {
            AdapterService adapterService,
            BluetoothAdapterProxy bluetoothAdapterProxy,
            Looper looper) {
        return new ScanManager(context, scanHelper, adapterService, bluetoothAdapterProxy, looper);
        return new ScanManager(
                context, scanHelper, adapterService bluetoothAdapterProxy, looper, sSystemClock);
    }

    public PeriodicScanManager createPeriodicScanManager(AdapterService adapterService) {
+3 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.bluetooth.le_scan;

import static com.android.bluetooth.Utils.sSystemClock;
import static com.android.bluetooth.util.AttributionSourceUtil.getLastAttributionTag;

import android.annotation.Nullable;
@@ -91,7 +92,8 @@ public class ScannerMap {
        }
        AppScanStats appScanStats = mAppScanStatsMap.get(appUid);
        if (appScanStats == null) {
            appScanStats = new AppScanStats(appName, workSource, this, context, scanHelper);
            appScanStats =
                    new AppScanStats(appName, workSource, this, context, scanHelper, sSystemClock);
            mAppScanStatsMap.put(appUid, appScanStats);
        }
        ScannerApp app =
Loading