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

Commit d274a8df authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Increase app updater balances."

parents 39837234 89b2cfa3
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));