1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.tare; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.tare.EconomyManager; 22 import android.provider.DeviceConfig; 23 import android.util.ArraySet; 24 import android.util.IndentingPrintWriter; 25 import android.util.Slog; 26 import android.util.SparseArray; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.internal.util.ArrayUtils; 30 31 import libcore.util.EmptyArray; 32 33 /** Combines all enabled policies into one. */ 34 public class CompleteEconomicPolicy extends EconomicPolicy { 35 private static final String TAG = "TARE-" + CompleteEconomicPolicy.class.getSimpleName(); 36 37 private final CompleteInjector mInjector; 38 private final ArraySet<EconomicPolicy> mEnabledEconomicPolicies = new ArraySet<>(); 39 /** Lazily populated set of actions covered by this policy. */ 40 private final SparseArray<Action> mActions = new SparseArray<>(); 41 /** Lazily populated set of rewards covered by this policy. */ 42 private final SparseArray<Reward> mRewards = new SparseArray<>(); 43 private int mEnabledEconomicPolicyIds = 0; 44 private int[] mCostModifiers = EmptyArray.INT; 45 private long mInitialConsumptionLimit; 46 private long mMinConsumptionLimit; 47 private long mMaxConsumptionLimit; 48 CompleteEconomicPolicy(@onNull InternalResourceService irs)49 CompleteEconomicPolicy(@NonNull InternalResourceService irs) { 50 this(irs, new CompleteInjector()); 51 } 52 53 @VisibleForTesting CompleteEconomicPolicy(@onNull InternalResourceService irs, @NonNull CompleteInjector injector)54 CompleteEconomicPolicy(@NonNull InternalResourceService irs, 55 @NonNull CompleteInjector injector) { 56 super(irs); 57 mInjector = injector; 58 59 if (mInjector.isPolicyEnabled(POLICY_ALARM, null)) { 60 mEnabledEconomicPolicyIds |= POLICY_ALARM; 61 mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(mIrs, mInjector)); 62 } 63 if (mInjector.isPolicyEnabled(POLICY_JOB, null)) { 64 mEnabledEconomicPolicyIds |= POLICY_JOB; 65 mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(mIrs, mInjector)); 66 } 67 } 68 69 @Override setup(@onNull DeviceConfig.Properties properties)70 void setup(@NonNull DeviceConfig.Properties properties) { 71 super.setup(properties); 72 73 mActions.clear(); 74 mRewards.clear(); 75 76 mEnabledEconomicPolicies.clear(); 77 mEnabledEconomicPolicyIds = 0; 78 if (mInjector.isPolicyEnabled(POLICY_ALARM, properties)) { 79 mEnabledEconomicPolicyIds |= POLICY_ALARM; 80 mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(mIrs, mInjector)); 81 } 82 if (mInjector.isPolicyEnabled(POLICY_JOB, properties)) { 83 mEnabledEconomicPolicyIds |= POLICY_JOB; 84 mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(mIrs, mInjector)); 85 } 86 87 ArraySet<Integer> costModifiers = new ArraySet<>(); 88 for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { 89 final int[] sm = mEnabledEconomicPolicies.valueAt(i).getCostModifiers(); 90 for (int s : sm) { 91 costModifiers.add(s); 92 } 93 } 94 mCostModifiers = ArrayUtils.convertToIntArray(costModifiers); 95 96 for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { 97 mEnabledEconomicPolicies.valueAt(i).setup(properties); 98 } 99 updateLimits(); 100 } 101 updateLimits()102 private void updateLimits() { 103 long initialConsumptionLimit = 0; 104 long minConsumptionLimit = 0; 105 long maxConsumptionLimit = 0; 106 for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { 107 final EconomicPolicy economicPolicy = mEnabledEconomicPolicies.valueAt(i); 108 initialConsumptionLimit += economicPolicy.getInitialSatiatedConsumptionLimit(); 109 minConsumptionLimit += economicPolicy.getMinSatiatedConsumptionLimit(); 110 maxConsumptionLimit += economicPolicy.getMaxSatiatedConsumptionLimit(); 111 } 112 mInitialConsumptionLimit = initialConsumptionLimit; 113 mMinConsumptionLimit = minConsumptionLimit; 114 mMaxConsumptionLimit = maxConsumptionLimit; 115 } 116 117 @Override getMinSatiatedBalance(final int userId, @NonNull final String pkgName)118 long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) { 119 long min = 0; 120 for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { 121 min += mEnabledEconomicPolicies.valueAt(i).getMinSatiatedBalance(userId, pkgName); 122 } 123 return min; 124 } 125 126 @Override getMaxSatiatedBalance(int userId, @NonNull String pkgName)127 long getMaxSatiatedBalance(int userId, @NonNull String pkgName) { 128 long max = 0; 129 for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { 130 max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedBalance(userId, pkgName); 131 } 132 return max; 133 } 134 135 @Override getInitialSatiatedConsumptionLimit()136 long getInitialSatiatedConsumptionLimit() { 137 return mInitialConsumptionLimit; 138 } 139 140 @Override getMinSatiatedConsumptionLimit()141 long getMinSatiatedConsumptionLimit() { 142 return mMinConsumptionLimit; 143 } 144 145 @Override getMaxSatiatedConsumptionLimit()146 long getMaxSatiatedConsumptionLimit() { 147 return mMaxConsumptionLimit; 148 } 149 150 @NonNull 151 @Override getCostModifiers()152 int[] getCostModifiers() { 153 return mCostModifiers == null ? EmptyArray.INT : mCostModifiers; 154 } 155 156 @Nullable 157 @Override getAction(@ppAction int actionId)158 Action getAction(@AppAction int actionId) { 159 if (mActions.contains(actionId)) { 160 return mActions.get(actionId); 161 } 162 163 long ctp = 0, price = 0; 164 boolean exists = false; 165 for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { 166 Action a = mEnabledEconomicPolicies.valueAt(i).getAction(actionId); 167 if (a != null) { 168 exists = true; 169 ctp += a.costToProduce; 170 price += a.basePrice; 171 } 172 } 173 final Action action = exists ? new Action(actionId, ctp, price) : null; 174 mActions.put(actionId, action); 175 return action; 176 } 177 178 @Nullable 179 @Override getReward(@tilityReward int rewardId)180 Reward getReward(@UtilityReward int rewardId) { 181 if (mRewards.contains(rewardId)) { 182 return mRewards.get(rewardId); 183 } 184 185 long instantReward = 0, ongoingReward = 0, maxReward = 0; 186 boolean exists = false; 187 for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { 188 Reward r = mEnabledEconomicPolicies.valueAt(i).getReward(rewardId); 189 if (r != null) { 190 exists = true; 191 instantReward += r.instantReward; 192 ongoingReward += r.ongoingRewardPerSecond; 193 maxReward += r.maxDailyReward; 194 } 195 } 196 final Reward reward = exists 197 ? new Reward(rewardId, instantReward, ongoingReward, maxReward) : null; 198 mRewards.put(rewardId, reward); 199 return reward; 200 } 201 isPolicyEnabled(@olicy int policyId)202 boolean isPolicyEnabled(@Policy int policyId) { 203 return (mEnabledEconomicPolicyIds & policyId) == policyId; 204 } 205 getEnabledPolicyIds()206 int getEnabledPolicyIds() { 207 return mEnabledEconomicPolicyIds; 208 } 209 210 @VisibleForTesting 211 static class CompleteInjector extends Injector { 212 isPolicyEnabled(int policy, @Nullable DeviceConfig.Properties properties)213 boolean isPolicyEnabled(int policy, @Nullable DeviceConfig.Properties properties) { 214 final String key; 215 final boolean defaultEnable; 216 switch (policy) { 217 case POLICY_ALARM: 218 key = EconomyManager.KEY_ENABLE_POLICY_ALARM; 219 defaultEnable = EconomyManager.DEFAULT_ENABLE_POLICY_ALARM; 220 break; 221 case POLICY_JOB: 222 key = EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER; 223 defaultEnable = EconomyManager.DEFAULT_ENABLE_POLICY_JOB_SCHEDULER; 224 break; 225 default: 226 Slog.wtf(TAG, "Unknown policy: " + policy); 227 return false; 228 } 229 if (properties == null) { 230 return defaultEnable; 231 } 232 return properties.getBoolean(key, defaultEnable); 233 } 234 } 235 236 @Override dump(IndentingPrintWriter pw)237 void dump(IndentingPrintWriter pw) { 238 dumpActiveModifiers(pw); 239 240 pw.println(); 241 pw.println(getClass().getSimpleName() + ":"); 242 pw.increaseIndent(); 243 244 pw.println("Cached actions:"); 245 pw.increaseIndent(); 246 for (int i = 0; i < mActions.size(); ++i) { 247 final Action action = mActions.valueAt(i); 248 if (action != null) { 249 dumpAction(pw, action); 250 } 251 } 252 pw.decreaseIndent(); 253 254 pw.println(); 255 pw.println("Cached rewards:"); 256 pw.increaseIndent(); 257 for (int i = 0; i < mRewards.size(); ++i) { 258 final Reward reward = mRewards.valueAt(i); 259 if (reward != null) { 260 dumpReward(pw, reward); 261 } 262 } 263 pw.decreaseIndent(); 264 265 for (int i = 0; i < mEnabledEconomicPolicies.size(); i++) { 266 final EconomicPolicy economicPolicy = mEnabledEconomicPolicies.valueAt(i); 267 pw.println(); 268 pw.print("(Includes) "); 269 pw.println(economicPolicy.getClass().getSimpleName() + ":"); 270 pw.increaseIndent(); 271 economicPolicy.dump(pw); 272 pw.decreaseIndent(); 273 } 274 pw.decreaseIndent(); 275 } 276 } 277