Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +27 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,7 @@ import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.Utils; import com.android.bluetooth.a2dp.A2dpService; import com.android.bluetooth.a2dpsink.A2dpSinkService; import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; import com.android.bluetooth.btservice.activityattribution.ActivityAttributionService; import com.android.bluetooth.btservice.bluetoothkeystore.BluetoothKeystoreService; Loading Loading @@ -305,6 +306,8 @@ public class AdapterService extends Service { private volatile boolean mTestModeEnabled = false; private MetricsLogger mMetricsLogger; /** * Register a {@link ProfileService} with AdapterService. * Loading Loading @@ -445,6 +448,7 @@ public class AdapterService extends Service { @Override public void onCreate() { super.onCreate(); initMetricsLogger(); debugLog("onCreate()"); mDeviceConfigListener.start(); mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper()); Loading Loading @@ -583,6 +587,27 @@ public class AdapterService extends Service { } }; private boolean initMetricsLogger() { if (mMetricsLogger != null) { return false; } mMetricsLogger = MetricsLogger.getInstance(); return mMetricsLogger.init(this); } private boolean closeMetricsLogger() { if (mMetricsLogger == null) { return false; } boolean result = mMetricsLogger.close(); mMetricsLogger = null; return result; } public void setMetricsLogger(MetricsLogger metricsLogger) { mMetricsLogger = metricsLogger; } void bringUpBle() { debugLog("bleOnProcessStart()"); Loading Loading @@ -777,6 +802,8 @@ public class AdapterService extends Service { return; } closeMetricsLogger(); clearAdapterService(this); mCleaningUp = true; Loading android/app/src/com/android/bluetooth/btservice/MetricsLogger.java +152 −1 Original line number Diff line number Diff line Loading @@ -15,18 +15,113 @@ */ package com.android.bluetooth.btservice; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.SystemClock; import android.util.Log; import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog; import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats; import com.android.bluetooth.BluetoothMetricsProto.ProfileId; import com.android.bluetooth.BluetoothStatsLog; import java.util.HashMap; /** * Class with static methods for logging metrics data * Class of Bluetooth Metrics */ public class MetricsLogger { private static final String TAG = "BluetoothMetricsLogger"; public static final boolean DEBUG = false; /** * Intent indicating Bluetooth counter metrics should send logs to BluetoothStatsLog */ public static final String BLUETOOTH_COUNTER_METRICS_ACTION = "com.android.bluetooth.map.BLUETOOTH_COUNTER_METRICS_ACTION"; // 6 hours timeout for counter metrics private static final long BLUETOOTH_COUNTER_METRICS_ACTION_DURATION_MILLIS = 6L * 3600L * 1000L; private static final HashMap<ProfileId, Integer> sProfileConnectionCounts = new HashMap<>(); HashMap<Integer, Long> mCounters = new HashMap<>(); private static MetricsLogger sInstance = null; private Context mContext = null; private AlarmManager mAlarmManager = null; private boolean mInitialized = false; static final private Object mLock = new Object(); private BroadcastReceiver mDrainReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (DEBUG) { Log.d(TAG, "onReceive: " + action); } if (action.equals(BLUETOOTH_COUNTER_METRICS_ACTION)) { drainBufferedCounters(); } } }; public static MetricsLogger getInstance() { if (sInstance == null) { synchronized (mLock) { if (sInstance == null) { sInstance = new MetricsLogger(); } } } return sInstance; } public boolean isInitialized() { return mInitialized; } public boolean init(Context context) { if (mInitialized) { return false; } mInitialized = true; mContext = context; IntentFilter filter = new IntentFilter(); filter.addAction(BLUETOOTH_COUNTER_METRICS_ACTION); mContext.registerReceiver(mDrainReceiver, filter); scheduleDrains(); return true; } public boolean count(int key, long count) { if (!mInitialized) { Log.w(TAG, "MetricsLogger isn't initialized"); return false; } if (count <= 0) { Log.w(TAG, "count is not larger than 0. count: " + count + " key: " + key); return false; } long total = 0; synchronized (mLock) { if (mCounters.containsKey(key)) { total = mCounters.get(key); } if (Long.MAX_VALUE - total < count) { Log.w(TAG, "count overflows. count: " + count + " current total: " + total); mCounters.put(key, Long.MAX_VALUE); return false; } mCounters.put(key, total + count); } return true; } /** * Log profile connection event by incrementing an internal counter for that profile. * This log persists over adapter enable/disable and only get cleared when metrics are Loading Loading @@ -57,4 +152,60 @@ public class MetricsLogger { sProfileConnectionCounts.clear(); } } protected void scheduleDrains() { if (DEBUG) { Log.d(TAG, "setCounterMetricsAlarm()"); } if (mAlarmManager == null) { mAlarmManager = mContext.getSystemService(AlarmManager.class); } mAlarmManager.setRepeating( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), BLUETOOTH_COUNTER_METRICS_ACTION_DURATION_MILLIS, getDrainIntent()); } protected void writeCounter(int key, long count) { BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_CODE_PATH_COUNTER, key, count); } protected void drainBufferedCounters() { Log.i(TAG, "drainBufferedCounters()."); synchronized (mLock) { // send mCounters to westworld for (int key : mCounters.keySet()) { writeCounter(key, mCounters.get(key)); } mCounters.clear(); } } public boolean close() { if (!mInitialized) { return false; } if (DEBUG) { Log.d(TAG, "close()"); } cancelPendingDrain(); drainBufferedCounters(); mAlarmManager = null; mContext = null; mInitialized = false; return true; } protected void cancelPendingDrain() { PendingIntent pIntent = getDrainIntent(); pIntent.cancel(); mAlarmManager.cancel(pIntent); } private PendingIntent getDrainIntent() { Intent counterMetricsIntent = new Intent(BLUETOOTH_COUNTER_METRICS_ACTION); return PendingIntent.getBroadcast( mContext, 0, counterMetricsIntent, PendingIntent.FLAG_IMMUTABLE); } } android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java +5 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ public class AdapterServiceTest { private @Mock Binder mBinder; private @Mock AudioManager mAudioManager; private @Mock android.app.Application mApplication; private @Mock MetricsLogger mMockMetricsLogger; // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the // underlying binder calls. Loading Loading @@ -215,6 +216,10 @@ public class AdapterServiceTest { when(mMockService.getName()).thenReturn("Service1"); when(mMockService2.getName()).thenReturn("Service2"); when(mMockMetricsLogger.init(any())).thenReturn(true); when(mMockMetricsLogger.close()).thenReturn(true); mAdapterService.setMetricsLogger(mMockMetricsLogger); // Attach a context to the service for permission checks. mAdapterService.attach(mMockContext, null, null, null, mApplication, null); mAdapterService.onCreate(); Loading android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java +103 −1 Original line number Diff line number Diff line Loading @@ -15,9 +15,13 @@ */ package com.android.bluetooth.btservice; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog; import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats; import com.android.bluetooth.BluetoothMetricsProto.ProfileId; Loading @@ -27,6 +31,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.HashMap; import java.util.List; Loading @@ -37,17 +43,42 @@ import java.util.List; @MediumTest @RunWith(AndroidJUnit4.class) public class MetricsLoggerTest { private TestableMetricsLogger mTestableMetricsLogger; @Mock private AdapterService mMockAdapterService; public class TestableMetricsLogger extends MetricsLogger { public HashMap<Integer, Long> mTestableCounters = new HashMap<>(); @Override protected void writeCounter(int key, long count) { mTestableCounters.put(key, count); } @Override protected void scheduleDrains() { } @Override protected void cancelPendingDrain() { } } @Before public void setUp() { MockitoAnnotations.initMocks(this); // Dump metrics to clean up internal states MetricsLogger.dumpProto(BluetoothLog.newBuilder()); mTestableMetricsLogger = new TestableMetricsLogger(); doReturn(null) .when(mMockAdapterService).registerReceiver(any(), any()); } @After public void tearDown() { // Dump metrics to clean up internal states MetricsLogger.dumpProto(BluetoothLog.newBuilder()); mTestableMetricsLogger.close(); } /** Loading Loading @@ -104,4 +135,75 @@ public class MetricsLoggerTest { return profileUsageStatsMap; } /** * Test add counters and send them to westworld */ @Test public void testAddAndSendCountersNormalCases() { mTestableMetricsLogger.init(mMockAdapterService); mTestableMetricsLogger.count(1, 10); mTestableMetricsLogger.count(1, 10); mTestableMetricsLogger.count(2, 5); mTestableMetricsLogger.drainBufferedCounters(); Assert.assertEquals(20L, mTestableMetricsLogger.mTestableCounters.get(1).longValue()); Assert.assertEquals(5L, mTestableMetricsLogger.mTestableCounters.get(2).longValue()); mTestableMetricsLogger.count(1, 3); mTestableMetricsLogger.count(2, 5); mTestableMetricsLogger.count(2, 5); mTestableMetricsLogger.count(3, 1); mTestableMetricsLogger.drainBufferedCounters(); Assert.assertEquals( 3L, mTestableMetricsLogger.mTestableCounters.get(1).longValue()); Assert.assertEquals( 10L, mTestableMetricsLogger.mTestableCounters.get(2).longValue()); Assert.assertEquals( 1L, mTestableMetricsLogger.mTestableCounters.get(3).longValue()); } @Test public void testAddAndSendCountersCornerCases() { mTestableMetricsLogger.init(mMockAdapterService); Assert.assertTrue(mTestableMetricsLogger.isInitialized()); mTestableMetricsLogger.count(1, -1); mTestableMetricsLogger.count(3, 0); mTestableMetricsLogger.count(2, 10); mTestableMetricsLogger.count(2, Long.MAX_VALUE - 8L); mTestableMetricsLogger.drainBufferedCounters(); Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(1)); Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(3)); Assert.assertEquals( Long.MAX_VALUE, mTestableMetricsLogger.mTestableCounters.get(2).longValue()); } @Test public void testMetricsLoggerClose() { mTestableMetricsLogger.init(mMockAdapterService); mTestableMetricsLogger.count(1, 1); mTestableMetricsLogger.count(2, 10); mTestableMetricsLogger.count(2, Long.MAX_VALUE); mTestableMetricsLogger.close(); Assert.assertEquals( 1, mTestableMetricsLogger.mTestableCounters.get(1).longValue()); Assert.assertEquals( Long.MAX_VALUE, mTestableMetricsLogger.mTestableCounters.get(2).longValue()); } @Test public void testMetricsLoggerNotInit() { Assert.assertFalse(mTestableMetricsLogger.count(1, 1)); mTestableMetricsLogger.drainBufferedCounters(); Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(1)); Assert.assertFalse(mTestableMetricsLogger.close()); } @Test public void testAddAndSendCountersDoubleInit() { Assert.assertTrue(mTestableMetricsLogger.init(mMockAdapterService)); Assert.assertTrue(mTestableMetricsLogger.isInitialized()); Assert.assertFalse(mTestableMetricsLogger.init(mMockAdapterService)); } } No newline at end of file Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +27 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,7 @@ import com.android.bluetooth.BluetoothStatsLog; import com.android.bluetooth.Utils; import com.android.bluetooth.a2dp.A2dpService; import com.android.bluetooth.a2dpsink.A2dpSinkService; import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; import com.android.bluetooth.btservice.activityattribution.ActivityAttributionService; import com.android.bluetooth.btservice.bluetoothkeystore.BluetoothKeystoreService; Loading Loading @@ -305,6 +306,8 @@ public class AdapterService extends Service { private volatile boolean mTestModeEnabled = false; private MetricsLogger mMetricsLogger; /** * Register a {@link ProfileService} with AdapterService. * Loading Loading @@ -445,6 +448,7 @@ public class AdapterService extends Service { @Override public void onCreate() { super.onCreate(); initMetricsLogger(); debugLog("onCreate()"); mDeviceConfigListener.start(); mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper()); Loading Loading @@ -583,6 +587,27 @@ public class AdapterService extends Service { } }; private boolean initMetricsLogger() { if (mMetricsLogger != null) { return false; } mMetricsLogger = MetricsLogger.getInstance(); return mMetricsLogger.init(this); } private boolean closeMetricsLogger() { if (mMetricsLogger == null) { return false; } boolean result = mMetricsLogger.close(); mMetricsLogger = null; return result; } public void setMetricsLogger(MetricsLogger metricsLogger) { mMetricsLogger = metricsLogger; } void bringUpBle() { debugLog("bleOnProcessStart()"); Loading Loading @@ -777,6 +802,8 @@ public class AdapterService extends Service { return; } closeMetricsLogger(); clearAdapterService(this); mCleaningUp = true; Loading
android/app/src/com/android/bluetooth/btservice/MetricsLogger.java +152 −1 Original line number Diff line number Diff line Loading @@ -15,18 +15,113 @@ */ package com.android.bluetooth.btservice; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.SystemClock; import android.util.Log; import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog; import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats; import com.android.bluetooth.BluetoothMetricsProto.ProfileId; import com.android.bluetooth.BluetoothStatsLog; import java.util.HashMap; /** * Class with static methods for logging metrics data * Class of Bluetooth Metrics */ public class MetricsLogger { private static final String TAG = "BluetoothMetricsLogger"; public static final boolean DEBUG = false; /** * Intent indicating Bluetooth counter metrics should send logs to BluetoothStatsLog */ public static final String BLUETOOTH_COUNTER_METRICS_ACTION = "com.android.bluetooth.map.BLUETOOTH_COUNTER_METRICS_ACTION"; // 6 hours timeout for counter metrics private static final long BLUETOOTH_COUNTER_METRICS_ACTION_DURATION_MILLIS = 6L * 3600L * 1000L; private static final HashMap<ProfileId, Integer> sProfileConnectionCounts = new HashMap<>(); HashMap<Integer, Long> mCounters = new HashMap<>(); private static MetricsLogger sInstance = null; private Context mContext = null; private AlarmManager mAlarmManager = null; private boolean mInitialized = false; static final private Object mLock = new Object(); private BroadcastReceiver mDrainReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (DEBUG) { Log.d(TAG, "onReceive: " + action); } if (action.equals(BLUETOOTH_COUNTER_METRICS_ACTION)) { drainBufferedCounters(); } } }; public static MetricsLogger getInstance() { if (sInstance == null) { synchronized (mLock) { if (sInstance == null) { sInstance = new MetricsLogger(); } } } return sInstance; } public boolean isInitialized() { return mInitialized; } public boolean init(Context context) { if (mInitialized) { return false; } mInitialized = true; mContext = context; IntentFilter filter = new IntentFilter(); filter.addAction(BLUETOOTH_COUNTER_METRICS_ACTION); mContext.registerReceiver(mDrainReceiver, filter); scheduleDrains(); return true; } public boolean count(int key, long count) { if (!mInitialized) { Log.w(TAG, "MetricsLogger isn't initialized"); return false; } if (count <= 0) { Log.w(TAG, "count is not larger than 0. count: " + count + " key: " + key); return false; } long total = 0; synchronized (mLock) { if (mCounters.containsKey(key)) { total = mCounters.get(key); } if (Long.MAX_VALUE - total < count) { Log.w(TAG, "count overflows. count: " + count + " current total: " + total); mCounters.put(key, Long.MAX_VALUE); return false; } mCounters.put(key, total + count); } return true; } /** * Log profile connection event by incrementing an internal counter for that profile. * This log persists over adapter enable/disable and only get cleared when metrics are Loading Loading @@ -57,4 +152,60 @@ public class MetricsLogger { sProfileConnectionCounts.clear(); } } protected void scheduleDrains() { if (DEBUG) { Log.d(TAG, "setCounterMetricsAlarm()"); } if (mAlarmManager == null) { mAlarmManager = mContext.getSystemService(AlarmManager.class); } mAlarmManager.setRepeating( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), BLUETOOTH_COUNTER_METRICS_ACTION_DURATION_MILLIS, getDrainIntent()); } protected void writeCounter(int key, long count) { BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_CODE_PATH_COUNTER, key, count); } protected void drainBufferedCounters() { Log.i(TAG, "drainBufferedCounters()."); synchronized (mLock) { // send mCounters to westworld for (int key : mCounters.keySet()) { writeCounter(key, mCounters.get(key)); } mCounters.clear(); } } public boolean close() { if (!mInitialized) { return false; } if (DEBUG) { Log.d(TAG, "close()"); } cancelPendingDrain(); drainBufferedCounters(); mAlarmManager = null; mContext = null; mInitialized = false; return true; } protected void cancelPendingDrain() { PendingIntent pIntent = getDrainIntent(); pIntent.cancel(); mAlarmManager.cancel(pIntent); } private PendingIntent getDrainIntent() { Intent counterMetricsIntent = new Intent(BLUETOOTH_COUNTER_METRICS_ACTION); return PendingIntent.getBroadcast( mContext, 0, counterMetricsIntent, PendingIntent.FLAG_IMMUTABLE); } }
android/app/tests/unit/src/com/android/bluetooth/btservice/AdapterServiceTest.java +5 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ public class AdapterServiceTest { private @Mock Binder mBinder; private @Mock AudioManager mAudioManager; private @Mock android.app.Application mApplication; private @Mock MetricsLogger mMockMetricsLogger; // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the // underlying binder calls. Loading Loading @@ -215,6 +216,10 @@ public class AdapterServiceTest { when(mMockService.getName()).thenReturn("Service1"); when(mMockService2.getName()).thenReturn("Service2"); when(mMockMetricsLogger.init(any())).thenReturn(true); when(mMockMetricsLogger.close()).thenReturn(true); mAdapterService.setMetricsLogger(mMockMetricsLogger); // Attach a context to the service for permission checks. mAdapterService.attach(mMockContext, null, null, null, mApplication, null); mAdapterService.onCreate(); Loading
android/app/tests/unit/src/com/android/bluetooth/btservice/MetricsLoggerTest.java +103 −1 Original line number Diff line number Diff line Loading @@ -15,9 +15,13 @@ */ package com.android.bluetooth.btservice; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.BluetoothMetricsProto.BluetoothLog; import com.android.bluetooth.BluetoothMetricsProto.ProfileConnectionStats; import com.android.bluetooth.BluetoothMetricsProto.ProfileId; Loading @@ -27,6 +31,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.HashMap; import java.util.List; Loading @@ -37,17 +43,42 @@ import java.util.List; @MediumTest @RunWith(AndroidJUnit4.class) public class MetricsLoggerTest { private TestableMetricsLogger mTestableMetricsLogger; @Mock private AdapterService mMockAdapterService; public class TestableMetricsLogger extends MetricsLogger { public HashMap<Integer, Long> mTestableCounters = new HashMap<>(); @Override protected void writeCounter(int key, long count) { mTestableCounters.put(key, count); } @Override protected void scheduleDrains() { } @Override protected void cancelPendingDrain() { } } @Before public void setUp() { MockitoAnnotations.initMocks(this); // Dump metrics to clean up internal states MetricsLogger.dumpProto(BluetoothLog.newBuilder()); mTestableMetricsLogger = new TestableMetricsLogger(); doReturn(null) .when(mMockAdapterService).registerReceiver(any(), any()); } @After public void tearDown() { // Dump metrics to clean up internal states MetricsLogger.dumpProto(BluetoothLog.newBuilder()); mTestableMetricsLogger.close(); } /** Loading Loading @@ -104,4 +135,75 @@ public class MetricsLoggerTest { return profileUsageStatsMap; } /** * Test add counters and send them to westworld */ @Test public void testAddAndSendCountersNormalCases() { mTestableMetricsLogger.init(mMockAdapterService); mTestableMetricsLogger.count(1, 10); mTestableMetricsLogger.count(1, 10); mTestableMetricsLogger.count(2, 5); mTestableMetricsLogger.drainBufferedCounters(); Assert.assertEquals(20L, mTestableMetricsLogger.mTestableCounters.get(1).longValue()); Assert.assertEquals(5L, mTestableMetricsLogger.mTestableCounters.get(2).longValue()); mTestableMetricsLogger.count(1, 3); mTestableMetricsLogger.count(2, 5); mTestableMetricsLogger.count(2, 5); mTestableMetricsLogger.count(3, 1); mTestableMetricsLogger.drainBufferedCounters(); Assert.assertEquals( 3L, mTestableMetricsLogger.mTestableCounters.get(1).longValue()); Assert.assertEquals( 10L, mTestableMetricsLogger.mTestableCounters.get(2).longValue()); Assert.assertEquals( 1L, mTestableMetricsLogger.mTestableCounters.get(3).longValue()); } @Test public void testAddAndSendCountersCornerCases() { mTestableMetricsLogger.init(mMockAdapterService); Assert.assertTrue(mTestableMetricsLogger.isInitialized()); mTestableMetricsLogger.count(1, -1); mTestableMetricsLogger.count(3, 0); mTestableMetricsLogger.count(2, 10); mTestableMetricsLogger.count(2, Long.MAX_VALUE - 8L); mTestableMetricsLogger.drainBufferedCounters(); Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(1)); Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(3)); Assert.assertEquals( Long.MAX_VALUE, mTestableMetricsLogger.mTestableCounters.get(2).longValue()); } @Test public void testMetricsLoggerClose() { mTestableMetricsLogger.init(mMockAdapterService); mTestableMetricsLogger.count(1, 1); mTestableMetricsLogger.count(2, 10); mTestableMetricsLogger.count(2, Long.MAX_VALUE); mTestableMetricsLogger.close(); Assert.assertEquals( 1, mTestableMetricsLogger.mTestableCounters.get(1).longValue()); Assert.assertEquals( Long.MAX_VALUE, mTestableMetricsLogger.mTestableCounters.get(2).longValue()); } @Test public void testMetricsLoggerNotInit() { Assert.assertFalse(mTestableMetricsLogger.count(1, 1)); mTestableMetricsLogger.drainBufferedCounters(); Assert.assertFalse(mTestableMetricsLogger.mTestableCounters.containsKey(1)); Assert.assertFalse(mTestableMetricsLogger.close()); } @Test public void testAddAndSendCountersDoubleInit() { Assert.assertTrue(mTestableMetricsLogger.init(mMockAdapterService)); Assert.assertTrue(mTestableMetricsLogger.isInitialized()); Assert.assertFalse(mTestableMetricsLogger.init(mMockAdapterService)); } } No newline at end of file