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

Commit 89b2cfa3 authored by Kweku Adams's avatar Kweku Adams
Browse files

Increase app updater balances.

Increase the minimum balances of app updaters in proportion to the
number of apps they're responsible for updating so that it's easier for
them to do app updates in the background.

Bug: 243987091
Test: Manually check balances are adjusted in dump
Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/tare
Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/tare
Change-Id: I0d431f2308b8e4938437d3141318306f96296732
parent 2dcd1d7f
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -227,6 +227,9 @@ public class EconomyManager {
    public static final String KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP =
            "js_min_satiated_balance_other_app";
    /** @hide */
    public static final String KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER =
            "js_min_satiated_balance_increment_updater";
    /** @hide */
    public static final String KEY_JS_MAX_SATIATED_BALANCE =
            "js_max_satiated_balance";
    /** @hide */
@@ -509,6 +512,15 @@ public class EconomyManager {
    public static final long DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES = arcToCake(0);
    /** @hide */
    public static final long DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES = arcToCake(5000);
    /**
     * How many credits to increase the updating app's min satiated balance by for each app that it
     * is responsible for updating.
     * @hide
     */
    public static final long DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES =
            // Research indicates that the median time between popular app updates is 13-14 days,
            // so adjust by 14 to amortize over that time.
            DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES / 14;
    /** @hide */
    public static final long DEFAULT_JS_ACTION_JOB_MAX_START_CTP_CAKES = arcToCake(3);
    /** @hide */
+82 −4
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArraySet;

/**
@@ -164,6 +165,10 @@ public class InternalResourceService extends SystemService {
    @GuardedBy("mLock")
    private final SparseArrayMap<String, Boolean> mVipOverrides = new SparseArrayMap<>();

    /** Set of apps each installer is responsible for installing. */
    @GuardedBy("mLock")
    private final SparseArrayMap<String, ArraySet<String>> mInstallers = new SparseArrayMap<>();

    private volatile boolean mHasBattery = true;
    private volatile boolean mIsEnabled;
    private volatile int mBootPhase;
@@ -353,6 +358,14 @@ public class InternalResourceService extends SystemService {
        return mCompleteEconomicPolicy;
    }

    /** Returns the number of apps that this app is expected to update at some point. */
    int getAppUpdateResponsibilityCount(final int userId, @NonNull final String pkgName) {
        synchronized (mLock) {
            // TODO(248274798): return 0 if the app has lost the install permission
            return ArrayUtils.size(mInstallers.get(userId, pkgName));
        }
    }

    @NonNull
    SparseArrayMap<String, InstalledPackageInfo> getInstalledPackages() {
        synchronized (mLock) {
@@ -525,7 +538,8 @@ public class InternalResourceService extends SystemService {
        }
        synchronized (mLock) {
            final InstalledPackageInfo ipo = new InstalledPackageInfo(packageInfo);
            mPkgCache.add(userId, pkgName, ipo);
            final InstalledPackageInfo oldIpo = mPkgCache.add(userId, pkgName, ipo);
            maybeUpdateInstallerStatusLocked(oldIpo, ipo);
            mUidToPackageCache.add(uid, pkgName);
            // TODO: only do this when the user first launches the app (app leaves stopped state)
            mAgent.grantBirthrightLocked(userId, pkgName);
@@ -552,7 +566,14 @@ public class InternalResourceService extends SystemService {
        synchronized (mLock) {
            mUidToPackageCache.remove(uid, pkgName);
            mVipOverrides.delete(userId, pkgName);
            mPkgCache.delete(userId, pkgName);
            final InstalledPackageInfo ipo = mPkgCache.delete(userId, pkgName);
            mInstallers.delete(userId, pkgName);
            if (ipo != null && ipo.installerPackageName != null) {
                final ArraySet<String> list = mInstallers.get(userId, ipo.installerPackageName);
                if (list != null) {
                    list.remove(pkgName);
                }
            }
            mAgent.onPackageRemovedLocked(userId, pkgName);
        }
    }
@@ -574,7 +595,8 @@ public class InternalResourceService extends SystemService {
                    mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
            for (int i = pkgs.size() - 1; i >= 0; --i) {
                final InstalledPackageInfo ipo = new InstalledPackageInfo(pkgs.get(i));
                mPkgCache.add(userId, ipo.packageName, ipo);
                final InstalledPackageInfo oldIpo = mPkgCache.add(userId, ipo.packageName, ipo);
                maybeUpdateInstallerStatusLocked(oldIpo, ipo);
            }
            mAgent.grantBirthrightsLocked(userId);
        }
@@ -590,6 +612,7 @@ public class InternalResourceService extends SystemService {
                    mUidToPackageCache.remove(pkgInfo.uid);
                }
            }
            mInstallers.delete(userId);
            mPkgCache.delete(userId);
            mAgent.onUserRemovedLocked(userId);
        }
@@ -746,11 +769,49 @@ public class InternalResourceService extends SystemService {
                    mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
            for (int i = pkgs.size() - 1; i >= 0; --i) {
                final InstalledPackageInfo ipo = new InstalledPackageInfo(pkgs.get(i));
                mPkgCache.add(userId, ipo.packageName, ipo);
                final InstalledPackageInfo oldIpo = mPkgCache.add(userId, ipo.packageName, ipo);
                maybeUpdateInstallerStatusLocked(oldIpo, ipo);
            }
        }
    }

    /**
     * Used to update the set of installed apps for each installer. This only has an effect if the
     * installer package name is different between {@code oldIpo} and {@code newIpo}.
     */
    @GuardedBy("mLock")
    private void maybeUpdateInstallerStatusLocked(@Nullable InstalledPackageInfo oldIpo,
            @NonNull InstalledPackageInfo newIpo) {
        final boolean changed;
        if (oldIpo == null) {
            changed = newIpo.installerPackageName != null;
        } else {
            changed = !Objects.equals(oldIpo.installerPackageName, newIpo.installerPackageName);
        }
        if (!changed) {
            return;
        }
        // InstallSourceInfo doesn't track userId, so for now, assume the installer on the package's
        // user profile did the installation.
        // TODO(246640162): use the actual installer's user ID
        final int userId = UserHandle.getUserId(newIpo.uid);
        final String pkgName = newIpo.packageName;
        if (oldIpo != null) {
            final ArraySet<String> oldList = mInstallers.get(userId, oldIpo.installerPackageName);
            if (oldList != null) {
                oldList.remove(pkgName);
            }
        }
        if (newIpo.installerPackageName != null) {
            ArraySet<String> newList = mInstallers.get(userId, newIpo.installerPackageName);
            if (newList == null) {
                newList = new ArraySet<>();
                mInstallers.add(userId, newIpo.installerPackageName, newList);
            }
            newList.add(pkgName);
        }
    }

    private void registerListeners() {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
@@ -1359,6 +1420,23 @@ public class InternalResourceService extends SystemService {
            }
            pw.println();

            pw.println();
            pw.println("Installers:");
            pw.increaseIndent();
            for (int u = 0; u < mInstallers.numMaps(); ++u) {
                final int userId = mInstallers.keyAt(u);

                for (int p = 0; p < mInstallers.numElementsForKeyAt(u); ++p) {
                    final String pkgName = mInstallers.keyAt(u, p);

                    pw.print(appToString(userId, pkgName));
                    pw.print(": ");
                    pw.print(mInstallers.valueAt(u, p).size());
                    pw.println(" apps");
                }
            }
            pw.decreaseIndent();

            pw.println();
            mCompleteEconomicPolicy.dump(pw);

+20 −4
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import static android.app.tare.EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_
import static android.app.tare.EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES;
@@ -87,6 +88,7 @@ import static android.app.tare.EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT;
import static android.app.tare.EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT;
import static android.app.tare.EconomyManager.KEY_JS_MAX_SATIATED_BALANCE;
import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED;
import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER;
import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_INSTANT;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_MAX;
@@ -154,6 +156,7 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {

    private long mMinSatiatedBalanceExempted;
    private long mMinSatiatedBalanceOther;
    private long mMinSatiatedBalanceIncrementalAppUpdater;
    private long mMaxSatiatedBalance;
    private long mInitialSatiatedConsumptionLimit;
    private long mHardSatiatedConsumptionLimit;
@@ -183,11 +186,20 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
        if (mIrs.isPackageRestricted(userId, pkgName)) {
            return 0;
        }

        final long baseBalance;
        if (mIrs.isPackageExempted(userId, pkgName)) {
            return mMinSatiatedBalanceExempted;
            baseBalance = mMinSatiatedBalanceExempted;
        } else {
            baseBalance = mMinSatiatedBalanceOther;
        }
        // TODO: take other exemptions into account
        return mMinSatiatedBalanceOther;

        long minBalance = baseBalance;

        final int updateResponsibilityCount = mIrs.getAppUpdateResponsibilityCount(userId, pkgName);
        minBalance += updateResponsibilityCount * mMinSatiatedBalanceIncrementalAppUpdater;

        return Math.min(minBalance, mMaxSatiatedBalance);
    }

    @Override
@@ -242,6 +254,9 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
        mMinSatiatedBalanceExempted = getConstantAsCake(mParser, properties,
            KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
            mMinSatiatedBalanceOther);
        mMinSatiatedBalanceIncrementalAppUpdater = getConstantAsCake(mParser, properties,
                KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER,
                DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES);
        mMaxSatiatedBalance = getConstantAsCake(mParser, properties,
            KEY_JS_MAX_SATIATED_BALANCE, DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
            Math.max(arcToCake(1), mMinSatiatedBalanceExempted));
@@ -397,10 +412,11 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {

    @Override
    void dump(IndentingPrintWriter pw) {
        pw.println("Min satiated balances:");
        pw.println("Min satiated balance:");
        pw.increaseIndent();
        pw.print("Exempted", cakeToString(mMinSatiatedBalanceExempted)).println();
        pw.print("Other", cakeToString(mMinSatiatedBalanceOther)).println();
        pw.print("+App Updater", cakeToString(mMinSatiatedBalanceIncrementalAppUpdater)).println();
        pw.decreaseIndent();
        pw.print("Max satiated balance", cakeToString(mMaxSatiatedBalance)).println();
        pw.print("Consumption limits: [");
+1 −1
Original line number Diff line number Diff line
@@ -286,7 +286,7 @@ class Ledger {
            final int idx = (mRewardBucketIndex - b + NUM_REWARD_BUCKET_WINDOWS)
                    % NUM_REWARD_BUCKET_WINDOWS;
            final RewardBucket rewardBucket = mRewardBuckets[idx];
            if (rewardBucket == null) {
            if (rewardBucket == null || rewardBucket.startTimeMs == 0) {
                continue;
            }

+39 −6
Original line number Diff line number Diff line
@@ -134,15 +134,36 @@ public class JobSchedulerEconomicPolicyTest {
                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.getMinSatiatedBalance(0, pkgRestricted));
        assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
        assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
                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,
                mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
        assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
                mEconomicPolicy.getMaxSatiatedBalance(0, pkgExempted));

        final String pkgUpdater = "com.pkg.updater";
        when(mIrs.getAppUpdateResponsibilityCount(anyInt(), eq(pkgUpdater))).thenReturn(5);
        assertEquals(5 * EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES
                        + EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
                mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));
        assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
                mEconomicPolicy.getMaxSatiatedBalance(0, pkgUpdater));
        // Make sure it doesn't suggest a min balance greater than max.
        final int updateCount = (int) (EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES
                / EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES);
        when(mIrs.getAppUpdateResponsibilityCount(anyInt(), eq(pkgUpdater)))
                .thenReturn(updateCount);
        assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
                mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));

        assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
                mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
        assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
                mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
    }
@@ -152,8 +173,10 @@ public class JobSchedulerEconomicPolicyTest {
        setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
        setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(25));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(10));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(9));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(7));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(6));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(4));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER,
                arcToCake(1));

        assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
        assertEquals(arcToCake(25), mEconomicPolicy.getHardSatiatedConsumptionLimit());
@@ -163,8 +186,12 @@ public class JobSchedulerEconomicPolicyTest {
        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));
        assertEquals(arcToCake(7), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
        assertEquals(arcToCake(6), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
        assertEquals(arcToCake(4), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
        final String pkgUpdater = "com.pkg.updater";
        when(mIrs.getAppUpdateResponsibilityCount(anyInt(), eq(pkgUpdater))).thenReturn(3);
        assertEquals(arcToCake(4) + 3 * arcToCake(1),
                mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));
    }

    @Test
@@ -175,6 +202,8 @@ public class JobSchedulerEconomicPolicyTest {
        setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(-1));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(-2));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(-3));
        setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER,
                arcToCake(-4));

        assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
        assertEquals(arcToCake(1), mEconomicPolicy.getHardSatiatedConsumptionLimit());
@@ -186,6 +215,10 @@ public class JobSchedulerEconomicPolicyTest {
        when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
        assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
        assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
        final String pkgUpdater = "com.pkg.updater";
        when(mIrs.getAppUpdateResponsibilityCount(anyInt(), eq(pkgUpdater))).thenReturn(5);
        assertEquals(arcToCake(0) + 5 * arcToCake(0),
                mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));

        // Test min+max reversed.
        setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));