Merge "Account for the power allowlist."

This commit is contained in:
Kweku Adams
2021-11-10 16:27:01 +00:00
committed by Android (Google) Code Review
5 changed files with 207 additions and 13 deletions

View File

@@ -16,8 +16,12 @@
package com.android.server.tare;
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_BIRTHRIGHT;
import static com.android.server.tare.EconomicPolicy.REGULATION_DEMOTION;
import static com.android.server.tare.EconomicPolicy.REGULATION_PROMOTION;
import static com.android.server.tare.EconomicPolicy.REGULATION_WEALTH_RECLAMATION;
import static com.android.server.tare.EconomicPolicy.TYPE_ACTION;
import static com.android.server.tare.EconomicPolicy.TYPE_REWARD;
@@ -603,6 +607,51 @@ class Agent {
}
}
/**
* Reclaim a percentage of unused ARCs from an app that was just removed from an exemption list.
* The amount reclaimed will depend on how recently the app was used. The reclamation will not
* reduce an app's balance below its current minimum balance.
*/
@GuardedBy("mLock")
void onAppUnexemptedLocked(final int userId, @NonNull final String pkgName) {
final long curBalance = getBalanceLocked(userId, pkgName);
final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
if (curBalance <= minBalance) {
return;
}
// AppStandby only counts elapsed time for things like this
// TODO: should we use clock time instead?
final long timeSinceLastUsedMs =
mAppStandbyInternal.getTimeSinceLastUsedByUser(pkgName, userId);
// The app is no longer exempted. We should take away some of credits so it's more in line
// with other non-exempt apps. However, don't take away as many credits if the app was used
// recently.
final double percentageToReclaim;
if (timeSinceLastUsedMs < DAY_IN_MILLIS) {
percentageToReclaim = .25;
} else if (timeSinceLastUsedMs < 2 * DAY_IN_MILLIS) {
percentageToReclaim = .5;
} else if (timeSinceLastUsedMs < 3 * DAY_IN_MILLIS) {
percentageToReclaim = .75;
} else {
percentageToReclaim = 1;
}
final long overage = curBalance - minBalance;
final long toReclaim = (long) (overage * percentageToReclaim);
if (toReclaim > 0) {
if (DEBUG) {
Slog.i(TAG, "Reclaiming bonus wealth! Taking " + toReclaim
+ " 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_DEMOTION, null, -toReclaim),
true);
}
}
/** Returns true if an app should be given credits in the general distributions. */
private boolean shouldGiveCredits(@NonNull PackageInfo packageInfo) {
final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
@@ -700,6 +749,21 @@ class Agent {
Math.min(maxBirthright, mIrs.getMinBalanceLocked(userId, pkgName))), true);
}
@GuardedBy("mLock")
void onAppExemptedLocked(final int userId, @NonNull final String pkgName) {
final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
final long missing = minBalance - getBalanceLocked(userId, pkgName);
if (missing <= 0) {
return;
}
final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
final long now = getCurrentTimeMillis();
recordTransactionLocked(userId, pkgName, ledger,
new Ledger.Transaction(now, now, REGULATION_PROMOTION, null, missing), true);
}
@GuardedBy("mLock")
void onPackageRemovedLocked(final int userId, @NonNull final String pkgName) {
reclaimAssetsLocked(userId, pkgName);

View File

@@ -35,6 +35,7 @@ import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WA
import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_CIRCULATION;
import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE;
import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED;
import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP;
import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
@@ -71,6 +72,7 @@ import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP
import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
import static android.app.tare.EconomyManager.KEY_AM_MAX_CIRCULATION;
import static android.app.tare.EconomyManager.KEY_AM_MAX_SATIATED_BALANCE;
import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED;
import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP;
import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
@@ -138,7 +140,8 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
COST_MODIFIER_PROCESS_STATE
};
private long mMinSatiatedBalance;
private long mMinSatiatedBalanceExempted;
private long mMinSatiatedBalanceOther;
private long mMaxSatiatedBalance;
private long mMaxSatiatedCirculation;
@@ -163,8 +166,11 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
@Override
long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
// TODO: take exemption into account
return mMinSatiatedBalance;
if (mInternalResourceService.isPackageExempted(userId, pkgName)) {
return mMinSatiatedBalanceExempted;
}
// TODO: take other exemptions into account
return mMinSatiatedBalanceOther;
}
@Override
@@ -205,7 +211,9 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
Slog.e(TAG, "Global setting key incorrect: ", e);
}
mMinSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
mMinSatiatedBalanceExempted = arcToNarc(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED,
DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED));
mMinSatiatedBalanceOther = arcToNarc(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP));
mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MAX_SATIATED_BALANCE,
DEFAULT_AM_MAX_SATIATED_BALANCE));
@@ -343,7 +351,11 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
@Override
void dump(IndentingPrintWriter pw) {
pw.print("Min satiated balance", narcToString(mMinSatiatedBalance)).println();
pw.println("Min satiated balances:");
pw.increaseIndent();
pw.print("Exempted", narcToString(mMinSatiatedBalanceExempted)).println();
pw.print("Other", narcToString(mMinSatiatedBalanceOther)).println();
pw.decreaseIndent();
pw.print("Max satiated balance", narcToString(mMaxSatiatedBalance)).println();
pw.print("Min satiated circulation", narcToString(mMaxSatiatedCirculation)).println();

View File

@@ -57,6 +57,8 @@ public abstract class EconomicPolicy {
static final int REGULATION_BASIC_INCOME = TYPE_REGULATION | 0;
static final int REGULATION_BIRTHRIGHT = TYPE_REGULATION | 1;
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;
static final int REWARD_NOTIFICATION_SEEN = TYPE_REWARD | 0;
static final int REWARD_NOTIFICATION_INTERACTION = TYPE_REWARD | 1;
@@ -363,6 +365,10 @@ public abstract class EconomicPolicy {
return "BIRTHRIGHT";
case REGULATION_WEALTH_RECLAMATION:
return "WEALTH_RECLAMATION";
case REGULATION_PROMOTION:
return "PROMOTION";
case REGULATION_DEMOTION:
return "DEMOTION";
}
return "UNKNOWN_REGULATION:" + Integer.toHexString(eventId);
}

View File

@@ -45,8 +45,12 @@ import android.net.Uri;
import android.os.BatteryManagerInternal;
import android.os.Binder;
import android.os.Handler;
import android.os.IDeviceIdleController;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -105,6 +109,8 @@ public class InternalResourceService extends SystemService {
private final PackageManager mPackageManager;
private final PackageManagerInternal mPackageManagerInternal;
private IDeviceIdleController mDeviceIdleController;
private final Agent mAgent;
private final ConfigObserver mConfigObserver;
private final EconomyManagerStub mEconomyManagerStub;
@@ -163,8 +169,14 @@ public class InternalResourceService extends SystemService {
@GuardedBy("mPackageToUidCache")
private final SparseArrayMap<String, Integer> mPackageToUidCache = new SparseArrayMap<>();
/** List of packages that are "exempted" from battery restrictions. */
// TODO(144864180): include userID
@GuardedBy("mLock")
private ArraySet<String> mExemptedApps = new ArraySet<>();
private volatile boolean mIsEnabled;
private volatile int mBootPhase;
private volatile boolean mExemptListLoaded;
// In the range [0,100] to represent 0% to 100% battery.
@GuardedBy("mLock")
private int mCurrentBatteryLevel;
@@ -213,6 +225,9 @@ public class InternalResourceService extends SystemService {
onUserRemoved(userId);
}
break;
case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
onExemptionListChanged();
break;
}
}
};
@@ -285,7 +300,22 @@ public class InternalResourceService extends SystemService {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
mConfigObserver.start();
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
setupEverything();
} else if (PHASE_BOOT_COMPLETED == phase) {
if (!mExemptListLoaded) {
synchronized (mLock) {
try {
mExemptedApps =
new ArraySet<>(mDeviceIdleController.getFullPowerWhitelist());
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, e);
}
mExemptListLoaded = true;
}
}
}
}
@@ -350,6 +380,12 @@ public class InternalResourceService extends SystemService {
return mIsEnabled;
}
boolean isPackageExempted(final int userId, @NonNull String pkgName) {
synchronized (mLock) {
return mExemptedApps.contains(pkgName);
}
}
boolean isSystem(final int userId, @NonNull String pkgName) {
if ("android".equals(pkgName)) {
return true;
@@ -375,6 +411,53 @@ public class InternalResourceService extends SystemService {
}
}
void onExemptionListChanged() {
final int[] userIds = LocalServices.getService(UserManagerInternal.class).getUserIds();
synchronized (mLock) {
final ArraySet<String> removed = mExemptedApps;
final ArraySet<String> added = new ArraySet<>();
try {
mExemptedApps = new ArraySet<>(mDeviceIdleController.getFullPowerWhitelist());
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, e);
return;
}
for (int i = mExemptedApps.size() - 1; i >= 0; --i) {
final String pkg = mExemptedApps.valueAt(i);
if (!removed.contains(pkg)) {
added.add(pkg);
}
removed.remove(pkg);
}
for (int a = added.size() - 1; a >= 0; --a) {
final String pkgName = added.valueAt(a);
for (int userId : userIds) {
// Since the exemption list doesn't specify user ID and we track by user ID,
// we need to see if the app exists on the user before talking to the agent.
// Otherwise, we may end up with invalid ledgers.
final boolean appExists = getUid(userId, pkgName) >= 0;
if (appExists) {
mAgent.onAppExemptedLocked(userId, pkgName);
}
}
}
for (int r = removed.size() - 1; r >= 0; --r) {
final String pkgName = removed.valueAt(r);
for (int userId : userIds) {
// Since the exemption list doesn't specify user ID and we track by user ID,
// we need to see if the app exists on the user before talking to the agent.
// Otherwise, we may end up with invalid ledgers.
final boolean appExists = getUid(userId, pkgName) >= 0;
if (appExists) {
mAgent.onAppUnexemptedLocked(userId, pkgName);
}
}
}
}
}
void onPackageAdded(final int uid, @NonNull final String pkgName) {
final int userId = UserHandle.getUserId(uid);
final PackageInfo packageInfo;
@@ -602,6 +685,7 @@ public class InternalResourceService extends SystemService {
private void registerListeners() {
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
final IntentFilter pkgFilter = new IntentFilter();
@@ -625,6 +709,15 @@ public class InternalResourceService extends SystemService {
private void setupHeavyWork() {
synchronized (mLock) {
loadInstalledPackageListLocked();
if (mBootPhase >= PHASE_BOOT_COMPLETED && !mExemptListLoaded) {
try {
mExemptedApps = new ArraySet<>(mDeviceIdleController.getFullPowerWhitelist());
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, e);
}
mExemptListLoaded = true;
}
final boolean isFirstSetup = !mScribe.recordExists();
if (isFirstSetup) {
mAgent.grantBirthrightsLocked();
@@ -654,6 +747,8 @@ public class InternalResourceService extends SystemService {
synchronized (mLock) {
mAgent.tearDownLocked();
mCompleteEconomicPolicy.tearDown();
mExemptedApps.clear();
mExemptListLoaded = false;
mHandler.post(() -> {
// Never call out to AlarmManager with the lock held. This sits below AM.
AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
@@ -953,9 +1048,9 @@ public class InternalResourceService extends SystemService {
pw.print("Current battery level: ");
pw.println(mCurrentBatteryLevel);
final long maxCircluation = getMaxCirculationLocked();
final long maxCirculation = getMaxCirculationLocked();
pw.print("Max circulation (current/satiated): ");
pw.print(narcToString(maxCircluation));
pw.print(narcToString(maxCirculation));
pw.print("/");
pw.println(narcToString(mCompleteEconomicPolicy.getMaxSatiatedCirculation()));
@@ -963,9 +1058,13 @@ public class InternalResourceService extends SystemService {
pw.print("Current GDP: ");
pw.print(narcToString(currentCirculation));
pw.print(" (");
pw.print(String.format("%.2f", 100f * currentCirculation / maxCircluation));
pw.print(String.format("%.2f", 100f * currentCirculation / maxCirculation));
pw.println("% of current max)");
pw.println();
pw.print("Exempted apps", mExemptedApps);
pw.println();
pw.println();
mCompleteEconomicPolicy.dump(pw);

View File

@@ -40,6 +40,7 @@ import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENA
import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_CIRCULATION;
import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP;
import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
@@ -80,6 +81,7 @@ import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_
import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
import static android.app.tare.EconomyManager.KEY_JS_MAX_CIRCULATION;
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_OTHER_APP;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
@@ -140,7 +142,8 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
COST_MODIFIER_PROCESS_STATE
};
private long mMinSatiatedBalance;
private long mMinSatiatedBalanceExempted;
private long mMinSatiatedBalanceOther;
private long mMaxSatiatedBalance;
private long mMaxSatiatedCirculation;
@@ -165,8 +168,11 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
@Override
long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
// TODO: incorporate time since usage
return mMinSatiatedBalance;
if (mInternalResourceService.isPackageExempted(userId, pkgName)) {
return mMinSatiatedBalanceExempted;
}
// TODO: take other exemptions into account
return mMinSatiatedBalanceOther;
}
@Override
@@ -207,7 +213,10 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
Slog.e(TAG, "Global setting key incorrect: ", e);
}
mMinSatiatedBalance = arcToNarc(
mMinSatiatedBalanceExempted = arcToNarc(
mParser.getInt(KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED,
DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED));
mMinSatiatedBalanceOther = arcToNarc(
mParser.getInt(KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP,
DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP));
mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_JS_MAX_SATIATED_BALANCE,
@@ -317,7 +326,11 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
@Override
void dump(IndentingPrintWriter pw) {
pw.print("Min satiated balance", narcToString(mMinSatiatedBalance)).println();
pw.println("Min satiated balances:");
pw.increaseIndent();
pw.print("Exempted", narcToString(mMinSatiatedBalanceExempted)).println();
pw.print("Other", narcToString(mMinSatiatedBalanceOther)).println();
pw.decreaseIndent();
pw.print("Max satiated balance", narcToString(mMaxSatiatedBalance)).println();
pw.print("Min satiated circulation", narcToString(mMaxSatiatedCirculation)).println();