diff options
5 files changed, 81 insertions, 14 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java index 74ed334df897..59c9c7e943ab 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java @@ -26,6 +26,7 @@ import static com.android.server.tare.EconomicPolicy.TYPE_ACTION; import static com.android.server.tare.EconomicPolicy.TYPE_REWARD; import static com.android.server.tare.EconomicPolicy.eventToString; import static com.android.server.tare.EconomicPolicy.getEventType; +import static com.android.server.tare.TareUtils.getCurrentTimeMillis; import static com.android.server.tare.TareUtils.narcToString; import android.annotation.NonNull; @@ -183,7 +184,7 @@ class Agent { mCurrentOngoingEvents.get(userId, pkgName); if (ongoingEvents != null) { final long nowElapsed = SystemClock.elapsedRealtime(); - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); mTotalDeltaCalculator.reset(ledger, nowElapsed, now); ongoingEvents.forEach(mTotalDeltaCalculator); balance += mTotalDeltaCalculator.mTotal; @@ -194,7 +195,7 @@ class Agent { @GuardedBy("mLock") void noteInstantaneousEventLocked(final int userId, @NonNull final String pkgName, final int eventId, @Nullable String tag) { - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); final Ledger ledger = getLedgerLocked(userId, pkgName); final int eventType = getEventType(eventId); @@ -278,7 +279,7 @@ class Agent { @GuardedBy("mLock") void onDeviceStateChangedLocked() { - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); final long nowElapsed = SystemClock.elapsedRealtime(); mCurrentOngoingEvents.forEach((userId, pkgName, ongoingEvents) -> { @@ -326,7 +327,7 @@ class Agent { @GuardedBy("mLock") void onAppStatesChangedLocked(final int userId, @NonNull ArraySet<String> pkgNames) { - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); final long nowElapsed = SystemClock.elapsedRealtime(); for (int i = 0; i < pkgNames.size(); ++i) { @@ -477,7 +478,7 @@ class Agent { // The earliest transaction won't change until we clean up the ledger, so no point // continuing to reschedule an existing cleanup. final long cleanupAlarmElapsed = SystemClock.elapsedRealtime() + MAX_TRANSACTION_AGE_MS - - (System.currentTimeMillis() - ledger.getEarliestTransaction().endTimeMs); + - (getCurrentTimeMillis() - ledger.getEarliestTransaction().endTimeMs); mLedgerCleanupAlarmListener.addAlarmLocked(userId, pkgName, cleanupAlarmElapsed); } // TODO: save changes to disk in a background thread @@ -509,7 +510,7 @@ class Agent { @GuardedBy("mLock") void reclaimUnusedAssetsLocked(double percentage) { final List<PackageInfo> pkgs = mIrs.getInstalledPackages(); - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); for (int i = 0; i < pkgs.size(); ++i) { final int userId = UserHandle.getUserId(pkgs.get(i).applicationInfo.uid); final String pkgName = pkgs.get(i).packageName; @@ -543,7 +544,7 @@ class Agent { @GuardedBy("mLock") void distributeBasicIncomeLocked(int batteryLevel) { List<PackageInfo> pkgs = mIrs.getInstalledPackages(); - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); for (int i = 0; i < pkgs.size(); ++i) { final PackageInfo pkgInfo = pkgs.get(i); final int userId = UserHandle.getUserId(pkgInfo.applicationInfo.uid); @@ -578,7 +579,7 @@ class Agent { List<PackageInfo> pkgs = packageManager.getInstalledPackagesAsUser(0, userId); final long maxBirthright = mIrs.getMaxCirculationLocked() / mIrs.getInstalledPackages().size(); - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); for (int i = 0; i < pkgs.size(); ++i) { final PackageInfo packageInfo = pkgs.get(i); @@ -609,7 +610,7 @@ class Agent { List<PackageInfo> pkgs = mIrs.getInstalledPackages(); final int numPackages = pkgs.size(); final long maxBirthright = mIrs.getMaxCirculationLocked() / numPackages; - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); recordTransactionLocked(userId, pkgName, ledger, new Ledger.Transaction(now, now, REGULATION_BIRTHRIGHT, null, diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java index 26577b833d7c..aa11add587af 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java @@ -19,6 +19,8 @@ package com.android.server.tare; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static com.android.server.tare.TareUtils.getCurrentTimeMillis; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; @@ -158,7 +160,7 @@ public class InternalResourceService extends SystemService { public void onAlarm() { synchronized (mLock) { mAgent.reclaimUnusedAssetsLocked(DEFAULT_UNUSED_RECLAMATION_PERCENTAGE); - mLastUnusedReclamationTime = System.currentTimeMillis(); + mLastUnusedReclamationTime = getCurrentTimeMillis(); scheduleUnusedWealthReclamationLocked(); } } @@ -341,7 +343,7 @@ public class InternalResourceService extends SystemService { @GuardedBy("mLock") private void scheduleUnusedWealthReclamationLocked() { - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); final long nextReclamationTime = Math.max(mLastUnusedReclamationTime + UNUSED_RECLAMATION_PERIOD_MS, now + 30_000); mHandler.post(() -> { @@ -612,7 +614,7 @@ public class InternalResourceService extends SystemService { return; } final long nowElapsed = SystemClock.elapsedRealtime(); - final long now = System.currentTimeMillis(); + final long now = getCurrentTimeMillis(); synchronized (mLock) { mAgent.stopOngoingActionLocked(userId, pkgName, eventId, tag, nowElapsed, now); } diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java index ae1bf26f36f2..76543d74f15e 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java @@ -19,6 +19,7 @@ package com.android.server.tare; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static com.android.server.tare.TareUtils.dumpTime; +import static com.android.server.tare.TareUtils.getCurrentTimeMillis; import static com.android.server.tare.TareUtils.narcToString; import android.annotation.NonNull; @@ -109,8 +110,8 @@ class Ledger { /** Deletes transactions that are older than {@code minAgeMs}. */ void removeOldTransactions(long minAgeMs) { - final long cutoff = System.currentTimeMillis() - minAgeMs; - while (mTransactions.get(0).endTimeMs <= cutoff) { + final long cutoff = getCurrentTimeMillis() - minAgeMs; + while (mTransactions.size() > 0 && mTransactions.get(0).endTimeMs <= cutoff) { mTransactions.remove(0); } } diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java index 2d72f5688688..3c79bb3a796d 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java @@ -20,7 +20,10 @@ import android.annotation.NonNull; import android.annotation.SuppressLint; import android.util.IndentingPrintWriter; +import com.android.internal.annotations.VisibleForTesting; + import java.text.SimpleDateFormat; +import java.time.Clock; class TareUtils { private static final long NARC_IN_ARC = 1_000_000_000L; @@ -29,6 +32,9 @@ class TareUtils { private static final SimpleDateFormat sDumpDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + @VisibleForTesting + static Clock sSystemClock = Clock.systemUTC(); + static long arcToNarc(int arcs) { return arcs * NARC_IN_ARC; } @@ -37,6 +43,10 @@ class TareUtils { pw.print(sDumpDateFormat.format(time)); } + static long getCurrentTimeMillis() { + return sSystemClock.millis(); + } + static int narcToArc(long narcs) { return (int) (narcs / NARC_IN_ARC); } diff --git a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java index 65a97596cd73..4a253234b59e 100644 --- a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java +++ b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java @@ -19,19 +19,31 @@ package com.android.server.tare; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static com.android.server.tare.TareUtils.getCurrentTimeMillis; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.time.Clock; +import java.time.ZoneOffset; + /** Test that the ledger records transactions correctly. */ @RunWith(AndroidJUnit4.class) @SmallTest public class LedgerTest { + @Before + public void setUp() { + TareUtils.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC); + } + @Test public void testInitialState() { final Ledger ledger = new Ledger(); @@ -72,4 +84,45 @@ public class LedgerTest { assertEquals(1, ledger.get24HourSum(1, 27 * HOUR_IN_MILLIS)); assertEquals(0, ledger.get24HourSum(1, 28 * HOUR_IN_MILLIS)); } + + @Test + public void testRemoveOldTransactions() { + final Ledger ledger = new Ledger(); + ledger.removeOldTransactions(24 * HOUR_IN_MILLIS); + assertNull(ledger.getEarliestTransaction()); + + final long now = getCurrentTimeMillis(); + Ledger.Transaction transaction1 = new Ledger.Transaction( + now - 48 * HOUR_IN_MILLIS, now - 40 * HOUR_IN_MILLIS, 1, null, 4800); + Ledger.Transaction transaction2 = new Ledger.Transaction( + now - 24 * HOUR_IN_MILLIS, now - 23 * HOUR_IN_MILLIS, 1, null, 600); + Ledger.Transaction transaction3 = new Ledger.Transaction( + now - 22 * HOUR_IN_MILLIS, now - 21 * HOUR_IN_MILLIS, 1, null, 600); + // Instant event + Ledger.Transaction transaction4 = new Ledger.Transaction( + now - 20 * HOUR_IN_MILLIS, now - 20 * HOUR_IN_MILLIS, 1, null, 500); + // Recent event + Ledger.Transaction transaction5 = new Ledger.Transaction( + now - 5 * MINUTE_IN_MILLIS, now - MINUTE_IN_MILLIS, 1, null, 400); + ledger.recordTransaction(transaction1); + ledger.recordTransaction(transaction2); + ledger.recordTransaction(transaction3); + ledger.recordTransaction(transaction4); + ledger.recordTransaction(transaction5); + + assertEquals(transaction1, ledger.getEarliestTransaction()); + ledger.removeOldTransactions(24 * HOUR_IN_MILLIS); + assertEquals(transaction2, ledger.getEarliestTransaction()); + ledger.removeOldTransactions(23 * HOUR_IN_MILLIS); + assertEquals(transaction3, ledger.getEarliestTransaction()); + // Shouldn't delete transaction3 yet since there's still a piece of it within the min age + // window. + ledger.removeOldTransactions(21 * HOUR_IN_MILLIS + 30 * MINUTE_IN_MILLIS); + assertEquals(transaction3, ledger.getEarliestTransaction()); + // Instant event should be removed as soon as we hit the exact threshold. + ledger.removeOldTransactions(20 * HOUR_IN_MILLIS); + assertEquals(transaction5, ledger.getEarliestTransaction()); + ledger.removeOldTransactions(0); + assertNull(ledger.getEarliestTransaction()); + } } |