Merge "Handle Background Restricted apps."
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 e23860c..d4a1cd2 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -19,6 +19,8 @@
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 
 import static com.android.server.tare.EconomicPolicy.REGULATION_BASIC_INCOME;
+import static com.android.server.tare.EconomicPolicy.REGULATION_BG_RESTRICTED;
+import static com.android.server.tare.EconomicPolicy.REGULATION_BG_UNRESTRICTED;
 import static com.android.server.tare.EconomicPolicy.REGULATION_BIRTHRIGHT;
 import static com.android.server.tare.EconomicPolicy.REGULATION_DEMOTION;
 import static com.android.server.tare.EconomicPolicy.REGULATION_PROMOTION;
@@ -510,12 +512,12 @@
         }
         final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
         final long originalBalance = ledger.getCurrentBalance();
+        final long maxBalance = economicPolicy.getMaxSatiatedBalance(userId, pkgName);
         if (transaction.delta > 0
-                && originalBalance + transaction.delta > economicPolicy.getMaxSatiatedBalance()) {
+                && originalBalance + transaction.delta > maxBalance) {
             // Set lower bound at 0 so we don't accidentally take away credits when we were trying
             // to _give_ the app credits.
-            final long newDelta =
-                    Math.max(0, economicPolicy.getMaxSatiatedBalance() - originalBalance);
+            final long newDelta = Math.max(0, maxBalance - originalBalance);
             Slog.i(TAG, "Would result in becoming too rich. Decreasing transaction "
                     + eventToString(transaction.eventId)
                     + (transaction.tag == null ? "" : ":" + transaction.tag)
@@ -660,6 +662,47 @@
         }
     }
 
+    /**
+     * Reclaim all ARCs from an app that was just restricted.
+     */
+    @GuardedBy("mLock")
+    void onAppRestrictedLocked(final int userId, @NonNull final String pkgName) {
+        final long curBalance = getBalanceLocked(userId, pkgName);
+        final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
+        if (curBalance <= minBalance) {
+            return;
+        }
+        if (DEBUG) {
+            Slog.i(TAG, "App restricted! Taking " + curBalance
+                    + " from " + appToString(userId, pkgName));
+        }
+
+        final long now = getCurrentTimeMillis();
+        final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
+        recordTransactionLocked(userId, pkgName, ledger,
+                new Ledger.Transaction(now, now, REGULATION_BG_RESTRICTED, null, -curBalance, 0),
+                true);
+    }
+
+    /**
+     * Give an app that was just unrestricted some ARCs.
+     */
+    @GuardedBy("mLock")
+    void onAppUnrestrictedLocked(final int userId, @NonNull final String pkgName) {
+        final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
+        if (ledger.getCurrentBalance() > 0) {
+            Slog.wtf(TAG, "App " + pkgName + " had credits while it was restricted");
+            // App already got credits somehow. Move along.
+            return;
+        }
+
+        final long now = getCurrentTimeMillis();
+
+        recordTransactionLocked(userId, pkgName, ledger,
+                new Ledger.Transaction(now, now, REGULATION_BG_UNRESTRICTED, null,
+                        mIrs.getMinBalanceLocked(userId, pkgName), 0), true);
+    }
+
     /** Returns true if an app should be given credits in the general distributions. */
     private boolean shouldGiveCredits(@NonNull InstalledPackageInfo packageInfo) {
         // Skip apps that wouldn't be doing any work. Giving them ARCs would be wasteful.
@@ -668,7 +711,8 @@
         }
         final int userId = UserHandle.getUserId(packageInfo.uid);
         // No point allocating ARCs to the system. It can do whatever it wants.
-        return !mIrs.isSystem(userId, packageInfo.packageName);
+        return !mIrs.isSystem(userId, packageInfo.packageName)
+                && !mIrs.isPackageRestricted(userId, packageInfo.packageName);
     }
 
     void onCreditSupplyChanged() {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
index aa66e92..e791e98 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -170,6 +170,9 @@
 
     @Override
     long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
+        if (mIrs.isPackageRestricted(userId, pkgName)) {
+            return 0;
+        }
         if (mIrs.isPackageExempted(userId, pkgName)) {
             return mMinSatiatedBalanceExempted;
         }
@@ -178,7 +181,10 @@
     }
 
     @Override
-    long getMaxSatiatedBalance() {
+    long getMaxSatiatedBalance(int userId, @NonNull String pkgName) {
+        if (mIrs.isPackageRestricted(userId, pkgName)) {
+            return 0;
+        }
         // TODO(230501287): adjust balance based on whether the app has the SCHEDULE_EXACT_ALARM
         // permission granted. Apps without the permission granted shouldn't need a high balance
         // since they won't be able to use exact alarms. Apps with the permission granted could
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
index 5d9cce8..625f99d 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -36,7 +36,6 @@
     /** Lazily populated set of rewards covered by this policy. */
     private final SparseArray<Reward> mRewards = new SparseArray<>();
     private final int[] mCostModifiers;
-    private long mMaxSatiatedBalance;
     private long mInitialConsumptionLimit;
     private long mHardConsumptionLimit;
 
@@ -80,16 +79,13 @@
     }
 
     private void updateLimits() {
-        long maxSatiatedBalance = 0;
         long initialConsumptionLimit = 0;
         long hardConsumptionLimit = 0;
         for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
             final EconomicPolicy economicPolicy = mEnabledEconomicPolicies.valueAt(i);
-            maxSatiatedBalance += economicPolicy.getMaxSatiatedBalance();
             initialConsumptionLimit += economicPolicy.getInitialSatiatedConsumptionLimit();
             hardConsumptionLimit += economicPolicy.getHardSatiatedConsumptionLimit();
         }
-        mMaxSatiatedBalance = maxSatiatedBalance;
         mInitialConsumptionLimit = initialConsumptionLimit;
         mHardConsumptionLimit = hardConsumptionLimit;
     }
@@ -104,8 +100,12 @@
     }
 
     @Override
-    long getMaxSatiatedBalance() {
-        return mMaxSatiatedBalance;
+    long getMaxSatiatedBalance(int userId, @NonNull String pkgName) {
+        long max = 0;
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+            max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedBalance(userId, pkgName);
+        }
+        return max;
     }
 
     @Override
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index 564ffb9..2fb0c1a 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -67,6 +67,9 @@
     static final int REGULATION_WEALTH_RECLAMATION = TYPE_REGULATION | 2;
     static final int REGULATION_PROMOTION = TYPE_REGULATION | 3;
     static final int REGULATION_DEMOTION = TYPE_REGULATION | 4;
+    /** App is fully restricted from running in the background. */
+    static final int REGULATION_BG_RESTRICTED = TYPE_REGULATION | 5;
+    static final int REGULATION_BG_UNRESTRICTED = TYPE_REGULATION | 6;
 
     static final int REWARD_NOTIFICATION_SEEN = TYPE_REWARD | 0;
     static final int REWARD_NOTIFICATION_INTERACTION = TYPE_REWARD | 1;
@@ -210,7 +213,7 @@
      * exists to ensure that no single app accumulate all available resources and increases fairness
      * for all apps.
      */
-    abstract long getMaxSatiatedBalance();
+    abstract long getMaxSatiatedBalance(int userId, @NonNull String pkgName);
 
     /**
      * Returns the maximum number of cakes that should be consumed during a full 100% discharge
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 7a7d669..da5a0c0 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -29,6 +29,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
+import android.app.AppOpsManager;
 import android.app.tare.IEconomyManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
@@ -64,6 +65,8 @@
 import android.util.SparseSetArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
@@ -119,6 +122,7 @@
     private final PackageManager mPackageManager;
     private final PackageManagerInternal mPackageManagerInternal;
 
+    private IAppOpsService mAppOpsService;
     private IDeviceIdleController mDeviceIdleController;
 
     private final Agent mAgent;
@@ -145,6 +149,12 @@
     private final CopyOnWriteArraySet<TareStateChangeListener> mStateChangeListeners =
             new CopyOnWriteArraySet<>();
 
+    /**
+     * List of packages that are fully restricted and shouldn't be allowed to run in the background.
+     */
+    @GuardedBy("mLock")
+    private final SparseSetArray<String> mRestrictedApps = new SparseSetArray<>();
+
     /** List of packages that are "exempted" from battery restrictions. */
     // TODO(144864180): include userID
     @GuardedBy("mLock")
@@ -160,6 +170,30 @@
     @GuardedBy("mLock")
     private int mCurrentBatteryLevel;
 
+    private final IAppOpsCallback mApbListener = new IAppOpsCallback.Stub() {
+        @Override
+        public void opChanged(int op, int uid, String packageName) {
+            boolean restricted = false;
+            try {
+                restricted = mAppOpsService.checkOperation(
+                        AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName)
+                        != AppOpsManager.MODE_ALLOWED;
+            } catch (RemoteException e) {
+                // Shouldn't happen
+            }
+            final int userId = UserHandle.getUserId(uid);
+            synchronized (mLock) {
+                if (restricted) {
+                    if (mRestrictedApps.add(userId, packageName)) {
+                        mAgent.onAppRestrictedLocked(userId, packageName);
+                    }
+                } else if (mRestrictedApps.remove(UserHandle.getUserId(uid), packageName)) {
+                    mAgent.onAppUnrestrictedLocked(userId, packageName);
+                }
+            }
+        }
+    };
+
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Nullable
         private String getPackageName(Intent intent) {
@@ -280,9 +314,11 @@
 
         switch (phase) {
             case PHASE_SYSTEM_SERVICES_READY:
-                mConfigObserver.start();
+                mAppOpsService = IAppOpsService.Stub.asInterface(
+                        ServiceManager.getService(Context.APP_OPS_SERVICE));
                 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
                         ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
+                mConfigObserver.start();
                 onBootPhaseSystemServicesReady();
                 break;
             case PHASE_THIRD_PARTY_APPS_CAN_START:
@@ -365,6 +401,12 @@
         }
     }
 
+    boolean isPackageRestricted(final int userId, @NonNull String pkgName) {
+        synchronized (mLock) {
+            return mRestrictedApps.contains(userId, pkgName);
+        }
+    }
+
     boolean isSystem(final int userId, @NonNull String pkgName) {
         if ("android".equals(pkgName)) {
             return true;
@@ -711,6 +753,13 @@
 
         UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
         usmi.registerListener(mSurveillanceAgent);
+
+        try {
+            mAppOpsService
+                    .startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null, mApbListener);
+        } catch (RemoteException e) {
+            // shouldn't happen.
+        }
     }
 
     /** Perform long-running and/or heavy setup work. This should be called off the main thread. */
@@ -815,6 +864,11 @@
             UsageStatsManagerInternal usmi =
                     LocalServices.getService(UsageStatsManagerInternal.class);
             usmi.unregisterListener(mSurveillanceAgent);
+            try {
+                mAppOpsService.stopWatchingMode(mApbListener);
+            } catch (RemoteException e) {
+                // shouldn't happen.
+            }
         }
         synchronized (mPackageToUidCache) {
             mPackageToUidCache.clear();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index 03c5fdd..cbb88c0 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -172,6 +172,9 @@
 
     @Override
     long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
+        if (mIrs.isPackageRestricted(userId, pkgName)) {
+            return 0;
+        }
         if (mIrs.isPackageExempted(userId, pkgName)) {
             return mMinSatiatedBalanceExempted;
         }
@@ -180,7 +183,10 @@
     }
 
     @Override
-    long getMaxSatiatedBalance() {
+    long getMaxSatiatedBalance(int userId, @NonNull String pkgName) {
+        if (mIrs.isPackageRestricted(userId, pkgName)) {
+            return 0;
+        }
         return mMaxSatiatedBalance;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index f9f6fe9..831a69a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -20,6 +20,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 
 import android.app.AlarmManager;
@@ -92,7 +94,7 @@
         Ledger ledger = new Ledger();
 
         doReturn(1_000_000L).when(mIrs).getConsumptionLimitLocked();
-        doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance();
+        doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
 
         Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
         agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
@@ -121,7 +123,7 @@
         Ledger ledger = new Ledger();
 
         doReturn(1000L).when(mIrs).getConsumptionLimitLocked();
-        doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance();
+        doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
 
         Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
         agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
@@ -168,7 +170,7 @@
         Ledger ledger = new Ledger();
 
         doReturn(1_000_000L).when(mIrs).getConsumptionLimitLocked();
-        doReturn(1000L).when(mEconomicPolicy).getMaxSatiatedBalance();
+        doReturn(1000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
 
         Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
         agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
@@ -187,7 +189,7 @@
         assertEquals(1_000, ledger.getCurrentBalance());
 
         // Shouldn't change in normal operation, but adding test case in case it does.
-        doReturn(900L).when(mEconomicPolicy).getMaxSatiatedBalance();
+        doReturn(900L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
 
         transaction = new Ledger.Transaction(0, 0, 0, null, 500, 0);
         agent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
index da7664b..2fac31e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
@@ -63,7 +63,7 @@
         }
 
         @Override
-        long getMaxSatiatedBalance() {
+        long getMaxSatiatedBalance(int userId, String pkgName) {
             return 0;
         }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
index 2e200c3..fb3e8f2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
@@ -134,8 +134,11 @@
                 mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
                 mEconomicPolicy.getHardSatiatedConsumptionLimit());
+        final String pkgRestricted = "com.pkg.restricted";
+        when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
+        assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
         assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
-                mEconomicPolicy.getMaxSatiatedBalance());
+                mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         final String pkgExempted = "com.pkg.exempted";
         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
         assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
@@ -154,7 +157,10 @@
 
         assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(arcToCake(25), mEconomicPolicy.getHardSatiatedConsumptionLimit());
-        assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance());
+        final String pkgRestricted = "com.pkg.restricted";
+        when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
+        assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
+        assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         final String pkgExempted = "com.pkg.exempted";
         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
         assertEquals(arcToCake(9), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
@@ -172,7 +178,10 @@
 
         assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(arcToCake(1), mEconomicPolicy.getHardSatiatedConsumptionLimit());
-        assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance());
+        final String pkgRestricted = "com.pkg.restricted";
+        when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
+        assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
+        assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         final String pkgExempted = "com.pkg.exempted";
         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
         assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
@@ -187,7 +196,8 @@
 
         assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(arcToCake(5), mEconomicPolicy.getHardSatiatedConsumptionLimit());
-        assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance());
+        assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
+        assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
         assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
index 45c97e4..47155a1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
@@ -142,9 +142,12 @@
         assertEquals(EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES
                 + EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
                 mEconomicPolicy.getHardSatiatedConsumptionLimit());
+        final String pkgRestricted = "com.pkg.restricted";
+        when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
+        assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
         assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES
                 + EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
-                mEconomicPolicy.getMaxSatiatedBalance());
+                mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         final String pkgExempted = "com.pkg.exempted";
         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
         assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES
@@ -170,7 +173,10 @@
 
         assertEquals(arcToCake(10), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(arcToCake(50), mEconomicPolicy.getHardSatiatedConsumptionLimit());
-        assertEquals(arcToCake(20), mEconomicPolicy.getMaxSatiatedBalance());
+        final String pkgRestricted = "com.pkg.restricted";
+        when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
+        assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
+        assertEquals(arcToCake(20), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         final String pkgExempted = "com.pkg.exempted";
         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
         assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
index 03ce91a..19b798d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
@@ -134,8 +134,11 @@
                 mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES,
                 mEconomicPolicy.getHardSatiatedConsumptionLimit());
+        final String pkgRestricted = "com.pkg.restricted";
+        when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
+        assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
         assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
-                mEconomicPolicy.getMaxSatiatedBalance());
+                mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         final String pkgExempted = "com.pkg.exempted";
         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
         assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
@@ -154,7 +157,10 @@
 
         assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(arcToCake(25), mEconomicPolicy.getHardSatiatedConsumptionLimit());
-        assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance());
+        final String pkgRestricted = "com.pkg.restricted";
+        when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
+        assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
+        assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         final String pkgExempted = "com.pkg.exempted";
         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
         assertEquals(arcToCake(9), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
@@ -172,7 +178,10 @@
 
         assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(arcToCake(1), mEconomicPolicy.getHardSatiatedConsumptionLimit());
-        assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance());
+        final String pkgRestricted = "com.pkg.restricted";
+        when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
+        assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
+        assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         final String pkgExempted = "com.pkg.exempted";
         when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
         assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
@@ -187,7 +196,8 @@
 
         assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
         assertEquals(arcToCake(5), mEconomicPolicy.getHardSatiatedConsumptionLimit());
-        assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance());
+        assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
+        assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
         assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
         assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
     }