Loading apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java 0 → 100644 +121 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import static com.android.server.tare.TareUtils.arcToNarc; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; /** * Policy defining pricing information and daily ARC requirements and suggestions for * AlarmManager. */ public class AlarmManagerEconomicPolicy extends EconomicPolicy { public static final String ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE = "ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE"; public static final String ACTION_ALARM_WAKEUP_EXACT = "ALARM_WAKEUP_EXACT"; public static final String ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE = "ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE"; public static final String ACTION_ALARM_WAKEUP_INEXACT = "ALARM_WAKEUP_INEXACT"; public static final String ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE = "ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE"; public static final String ACTION_ALARM_NONWAKEUP_EXACT = "ALARM_NONWAKEUP_EXACT"; public static final String ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE = "ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE"; public static final String ACTION_ALARM_NONWAKEUP_INEXACT = "ALARM_NONWAKEUP_INEXACT"; public static final String ACTION_ALARM_CLOCK = "ALARM_CLOCK"; private final ArrayMap<String, Action> mActions = new ArrayMap<>(); private final ArrayMap<String, Reward> mRewards = new ArrayMap<>(); AlarmManagerEconomicPolicy(InternalResourceService irs) { super(irs); loadActions(); loadRewards(); } @Override long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) { // TODO: take exemption into account return arcToNarc(160); } @Override long getMaxSatiatedBalance() { return arcToNarc(1440); } @Override long getMaxSatiatedCirculation() { return arcToNarc(52000); } @Nullable @Override Action getAction(@NonNull String actionName) { return mActions.get(actionName); } @Nullable @Override Reward getReward(@NonNull String rewardName) { return mRewards.get(rewardName); } private void loadActions() { mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, arcToNarc(3), arcToNarc(5))); mActions.put(ACTION_ALARM_WAKEUP_EXACT, new Action(ACTION_ALARM_WAKEUP_EXACT, arcToNarc(3), arcToNarc(4))); mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE, new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE, arcToNarc(3), arcToNarc(4))); mActions.put(ACTION_ALARM_WAKEUP_INEXACT, new Action(ACTION_ALARM_WAKEUP_INEXACT, arcToNarc(3), arcToNarc(3))); mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE, new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE, arcToNarc(1), arcToNarc(3))); mActions.put(ACTION_ALARM_NONWAKEUP_EXACT, new Action(ACTION_ALARM_NONWAKEUP_EXACT, arcToNarc(1), arcToNarc(2))); mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE, new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE, arcToNarc(1), arcToNarc(2))); mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT, new Action(ACTION_ALARM_NONWAKEUP_INEXACT, arcToNarc(1), arcToNarc(1))); mActions.put(ACTION_ALARM_CLOCK, new Action(ACTION_ALARM_CLOCK, arcToNarc(5), arcToNarc(10))); } private void loadRewards() { mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY, arcToNarc(0), /* .01 arcs */ arcToNarc(1) / 100, arcToNarc(500))); mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(3), arcToNarc(0), arcToNarc(60))); mRewards.put(REWARD_NOTIFICATION_INTERACTION, new Reward(REWARD_NOTIFICATION_INTERACTION, arcToNarc(5), arcToNarc(0), arcToNarc(500))); mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(500))); mRewards.put(REWARD_OTHER_USER_INTERACTION, new Reward(REWARD_OTHER_USER_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(500))); } } apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java 0 → 100644 +117 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; import android.util.ArraySet; /** Combines all enabled policies into one. */ public class CompleteEconomicPolicy extends EconomicPolicy { private final ArraySet<EconomicPolicy> mEnabledEconomicPolicies = new ArraySet<>(); /** Lazily populated set of actions covered by this policy. */ private final ArrayMap<String, Action> mActions = new ArrayMap<>(); /** Lazily populated set of rewards covered by this policy. */ private final ArrayMap<String, Reward> mRewards = new ArrayMap<>(); private final long mMaxSatiatedBalance; private final long mMaxSatiatedCirculation; CompleteEconomicPolicy(@NonNull InternalResourceService irs) { super(irs); mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(irs)); mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(irs)); long max = 0; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedBalance(); } mMaxSatiatedBalance = max; max = 0; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedCirculation(); } mMaxSatiatedCirculation = max; } @Override public long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) { long min = 0; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { min += mEnabledEconomicPolicies.valueAt(i).getMinSatiatedBalance(userId, pkgName); } return min; } @Override public long getMaxSatiatedBalance() { return mMaxSatiatedBalance; } @Override public long getMaxSatiatedCirculation() { return mMaxSatiatedCirculation; } @Nullable @Override public Action getAction(@NonNull String actionName) { if (mActions.containsKey(actionName)) { return mActions.get(actionName); } long ctp = 0, price = 0; boolean exists = false; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { Action a = mEnabledEconomicPolicies.valueAt(i).getAction(actionName); if (a != null) { exists = true; ctp += a.costToProduce; price += a.basePrice; } } final Action action = exists ? new Action(actionName, ctp, price) : null; mActions.put(actionName, action); return action; } @Nullable @Override public Reward getReward(@NonNull String rewardName) { if (mRewards.containsKey(rewardName)) { return mRewards.get(rewardName); } long instantReward = 0, ongoingReward = 0, maxReward = 0; boolean exists = false; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { Reward r = mEnabledEconomicPolicies.valueAt(i).getReward(rewardName); if (r != null) { exists = true; instantReward += r.instantReward; ongoingReward += r.ongoingRewardPerSecond; maxReward += r.maxDailyReward; } } final Reward reward = exists ? new Reward(rewardName, instantReward, ongoingReward, maxReward) : null; mRewards.put(rewardName, reward); return reward; } } apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; import android.util.IndentingPrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * An EconomicPolicy includes pricing information and daily ARC requirements and suggestions. * Policies are defined per participating system service. This allows each service’s EconomicPolicy * to be isolated while allowing the core economic system to scale across policies to achieve a * logical system-wide value system. */ public abstract class EconomicPolicy { private static final String TAG = "TARE-" + EconomicPolicy.class.getSimpleName(); // fixme ensure actions and rewards never use the same strings static final String REWARD_TOP_ACTIVITY = "REWARD_TOP_ACTIVITY"; static final String REWARD_NOTIFICATION_SEEN = "REWARD_NOTIFICATION_SEEN"; static final String REWARD_NOTIFICATION_INTERACTION = "REWARD_NOTIFICATION_INTERACTION"; static final String REWARD_WIDGET_INTERACTION = "REWARD_WIDGET_INTERACTION"; static final String REWARD_OTHER_USER_INTERACTION = "REWARD_OTHER_USER_INTERACTION"; @StringDef({ REWARD_TOP_ACTIVITY, REWARD_NOTIFICATION_SEEN, REWARD_NOTIFICATION_INTERACTION, REWARD_WIDGET_INTERACTION, REWARD_OTHER_USER_INTERACTION, }) @Retention(RetentionPolicy.SOURCE) public @interface UtilityReward { } static class Action { @NonNull public final String name; /** * How many ARCs the system says it takes to perform this action. */ public final long costToProduce; /** * The base price to perform this action. If this is * less than the {@link #costToProduce}, then the system should not perform * the action unless a multiplier lowers the cost to produce. */ public final long basePrice; Action(@NonNull String name, long costToProduce, long basePrice) { this.name = name; this.costToProduce = costToProduce; this.basePrice = basePrice; } } static class Reward { @NonNull @UtilityReward public final String name; public final long instantReward; /** Reward credited per second of ongoing activity. */ public final long ongoingRewardPerSecond; /** The maximum amount an app can earn from this reward within a 24 hour period. */ public final long maxDailyReward; Reward(@NonNull String name, long instantReward, long ongoingReward, long maxDailyReward) { this.name = name; this.instantReward = instantReward; this.ongoingRewardPerSecond = ongoingReward; this.maxDailyReward = maxDailyReward; } } EconomicPolicy(@NonNull InternalResourceService irs) { } @CallSuper void onSystemServicesReady() { } /** * Returns the minimum suggested balance an app should have when the device is at 100% battery. * This takes into account any exemptions the app may have. */ abstract long getMinSatiatedBalance(int userId, @NonNull String pkgName); /** * Returns the maximum balance an app should have when the device is at 100% battery. This * exists to ensure that no single app accumulate all available resources and increases fairness * for all apps. */ abstract long getMaxSatiatedBalance(); /** * Returns the maximum number of narcs that should be in circulation at once when the device is * at 100% battery. */ abstract long getMaxSatiatedCirculation(); @Nullable abstract Action getAction(@NonNull String actionName); @Nullable abstract Reward getReward(@NonNull String rewardName); void dump(IndentingPrintWriter pw) { } } apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import static com.android.server.tare.TareUtils.arcToNarc; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; /** * Policy defining pricing information and daily ARC requirements and suggestions for * JobScheduler. */ public class JobSchedulerEconomicPolicy extends EconomicPolicy { public static final String ACTION_JOB_MAX_START = "JOB_MAX_START"; public static final String ACTION_JOB_MAX_RUNNING = "JOB_MAX_RUNNING"; public static final String ACTION_JOB_HIGH_START = "JOB_HIGH_START"; public static final String ACTION_JOB_HIGH_RUNNING = "JOB_HIGH_RUNNING"; public static final String ACTION_JOB_DEFAULT_START = "JOB_DEFAULT_START"; public static final String ACTION_JOB_DEFAULT_RUNNING = "JOB_DEFAULT_RUNNING"; public static final String ACTION_JOB_LOW_START = "JOB_LOW_START"; public static final String ACTION_JOB_LOW_RUNNING = "JOB_LOW_RUNNING"; public static final String ACTION_JOB_MIN_START = "JOB_MIN_START"; public static final String ACTION_JOB_MIN_RUNNING = "JOB_MIN_RUNNING"; public static final String ACTION_JOB_TIMEOUT = "JOB_TIMEOUT"; private final ArrayMap<String, Action> mActions = new ArrayMap<>(); private final ArrayMap<String, Reward> mRewards = new ArrayMap<>(); JobSchedulerEconomicPolicy(InternalResourceService irs) { super(irs); loadActions(); loadRewards(); } @Override long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) { // TODO: incorporate time since usage return arcToNarc(2000); } @Override long getMaxSatiatedBalance() { return arcToNarc(60000); } @Override long getMaxSatiatedCirculation() { return arcToNarc(691200); } @Nullable @Override Action getAction(@NonNull String actionName) { return mActions.get(actionName); } @Nullable @Override Reward getReward(@NonNull String rewardName) { return mRewards.get(rewardName); } private void loadActions() { mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START, arcToNarc(3), arcToNarc(10))); mActions.put(ACTION_JOB_MAX_RUNNING, new Action(ACTION_JOB_MAX_RUNNING, arcToNarc(2), arcToNarc(5))); mActions.put(ACTION_JOB_HIGH_START, new Action(ACTION_JOB_HIGH_START, arcToNarc(3), arcToNarc(8))); mActions.put(ACTION_JOB_HIGH_RUNNING, new Action(ACTION_JOB_HIGH_RUNNING, arcToNarc(2), arcToNarc(4))); mActions.put(ACTION_JOB_DEFAULT_START, new Action(ACTION_JOB_DEFAULT_START, arcToNarc(3), arcToNarc(6))); mActions.put(ACTION_JOB_DEFAULT_RUNNING, new Action(ACTION_JOB_DEFAULT_RUNNING, arcToNarc(2), arcToNarc(3))); mActions.put(ACTION_JOB_LOW_START, new Action(ACTION_JOB_LOW_START, arcToNarc(3), arcToNarc(4))); mActions.put(ACTION_JOB_LOW_RUNNING, new Action(ACTION_JOB_LOW_RUNNING, arcToNarc(2), arcToNarc(2))); mActions.put(ACTION_JOB_MIN_START, new Action(ACTION_JOB_MIN_START, arcToNarc(3), arcToNarc(2))); mActions.put(ACTION_JOB_MIN_RUNNING, new Action(ACTION_JOB_MIN_RUNNING, arcToNarc(2), arcToNarc(1))); mActions.put(ACTION_JOB_TIMEOUT, new Action(ACTION_JOB_TIMEOUT, arcToNarc(30), arcToNarc(60))); } private void loadRewards() { mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY, arcToNarc(0), /* .5 arcs */ arcToNarc(5) / 10, arcToNarc(15000))); mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(1), arcToNarc(0), arcToNarc(10))); mRewards.put(REWARD_NOTIFICATION_INTERACTION, new Reward(REWARD_NOTIFICATION_INTERACTION, arcToNarc(5), arcToNarc(0), arcToNarc(5000))); mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(5000))); mRewards.put(REWARD_OTHER_USER_INTERACTION, new Reward(REWARD_OTHER_USER_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(5000))); } } Loading
apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java 0 → 100644 +121 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import static com.android.server.tare.TareUtils.arcToNarc; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; /** * Policy defining pricing information and daily ARC requirements and suggestions for * AlarmManager. */ public class AlarmManagerEconomicPolicy extends EconomicPolicy { public static final String ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE = "ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE"; public static final String ACTION_ALARM_WAKEUP_EXACT = "ALARM_WAKEUP_EXACT"; public static final String ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE = "ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE"; public static final String ACTION_ALARM_WAKEUP_INEXACT = "ALARM_WAKEUP_INEXACT"; public static final String ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE = "ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE"; public static final String ACTION_ALARM_NONWAKEUP_EXACT = "ALARM_NONWAKEUP_EXACT"; public static final String ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE = "ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE"; public static final String ACTION_ALARM_NONWAKEUP_INEXACT = "ALARM_NONWAKEUP_INEXACT"; public static final String ACTION_ALARM_CLOCK = "ALARM_CLOCK"; private final ArrayMap<String, Action> mActions = new ArrayMap<>(); private final ArrayMap<String, Reward> mRewards = new ArrayMap<>(); AlarmManagerEconomicPolicy(InternalResourceService irs) { super(irs); loadActions(); loadRewards(); } @Override long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) { // TODO: take exemption into account return arcToNarc(160); } @Override long getMaxSatiatedBalance() { return arcToNarc(1440); } @Override long getMaxSatiatedCirculation() { return arcToNarc(52000); } @Nullable @Override Action getAction(@NonNull String actionName) { return mActions.get(actionName); } @Nullable @Override Reward getReward(@NonNull String rewardName) { return mRewards.get(rewardName); } private void loadActions() { mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, arcToNarc(3), arcToNarc(5))); mActions.put(ACTION_ALARM_WAKEUP_EXACT, new Action(ACTION_ALARM_WAKEUP_EXACT, arcToNarc(3), arcToNarc(4))); mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE, new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE, arcToNarc(3), arcToNarc(4))); mActions.put(ACTION_ALARM_WAKEUP_INEXACT, new Action(ACTION_ALARM_WAKEUP_INEXACT, arcToNarc(3), arcToNarc(3))); mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE, new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE, arcToNarc(1), arcToNarc(3))); mActions.put(ACTION_ALARM_NONWAKEUP_EXACT, new Action(ACTION_ALARM_NONWAKEUP_EXACT, arcToNarc(1), arcToNarc(2))); mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE, new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE, arcToNarc(1), arcToNarc(2))); mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT, new Action(ACTION_ALARM_NONWAKEUP_INEXACT, arcToNarc(1), arcToNarc(1))); mActions.put(ACTION_ALARM_CLOCK, new Action(ACTION_ALARM_CLOCK, arcToNarc(5), arcToNarc(10))); } private void loadRewards() { mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY, arcToNarc(0), /* .01 arcs */ arcToNarc(1) / 100, arcToNarc(500))); mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(3), arcToNarc(0), arcToNarc(60))); mRewards.put(REWARD_NOTIFICATION_INTERACTION, new Reward(REWARD_NOTIFICATION_INTERACTION, arcToNarc(5), arcToNarc(0), arcToNarc(500))); mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(500))); mRewards.put(REWARD_OTHER_USER_INTERACTION, new Reward(REWARD_OTHER_USER_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(500))); } }
apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java 0 → 100644 +117 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; import android.util.ArraySet; /** Combines all enabled policies into one. */ public class CompleteEconomicPolicy extends EconomicPolicy { private final ArraySet<EconomicPolicy> mEnabledEconomicPolicies = new ArraySet<>(); /** Lazily populated set of actions covered by this policy. */ private final ArrayMap<String, Action> mActions = new ArrayMap<>(); /** Lazily populated set of rewards covered by this policy. */ private final ArrayMap<String, Reward> mRewards = new ArrayMap<>(); private final long mMaxSatiatedBalance; private final long mMaxSatiatedCirculation; CompleteEconomicPolicy(@NonNull InternalResourceService irs) { super(irs); mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(irs)); mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(irs)); long max = 0; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedBalance(); } mMaxSatiatedBalance = max; max = 0; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedCirculation(); } mMaxSatiatedCirculation = max; } @Override public long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) { long min = 0; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { min += mEnabledEconomicPolicies.valueAt(i).getMinSatiatedBalance(userId, pkgName); } return min; } @Override public long getMaxSatiatedBalance() { return mMaxSatiatedBalance; } @Override public long getMaxSatiatedCirculation() { return mMaxSatiatedCirculation; } @Nullable @Override public Action getAction(@NonNull String actionName) { if (mActions.containsKey(actionName)) { return mActions.get(actionName); } long ctp = 0, price = 0; boolean exists = false; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { Action a = mEnabledEconomicPolicies.valueAt(i).getAction(actionName); if (a != null) { exists = true; ctp += a.costToProduce; price += a.basePrice; } } final Action action = exists ? new Action(actionName, ctp, price) : null; mActions.put(actionName, action); return action; } @Nullable @Override public Reward getReward(@NonNull String rewardName) { if (mRewards.containsKey(rewardName)) { return mRewards.get(rewardName); } long instantReward = 0, ongoingReward = 0, maxReward = 0; boolean exists = false; for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) { Reward r = mEnabledEconomicPolicies.valueAt(i).getReward(rewardName); if (r != null) { exists = true; instantReward += r.instantReward; ongoingReward += r.ongoingRewardPerSecond; maxReward += r.maxDailyReward; } } final Reward reward = exists ? new Reward(rewardName, instantReward, ongoingReward, maxReward) : null; mRewards.put(rewardName, reward); return reward; } }
apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; import android.util.IndentingPrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * An EconomicPolicy includes pricing information and daily ARC requirements and suggestions. * Policies are defined per participating system service. This allows each service’s EconomicPolicy * to be isolated while allowing the core economic system to scale across policies to achieve a * logical system-wide value system. */ public abstract class EconomicPolicy { private static final String TAG = "TARE-" + EconomicPolicy.class.getSimpleName(); // fixme ensure actions and rewards never use the same strings static final String REWARD_TOP_ACTIVITY = "REWARD_TOP_ACTIVITY"; static final String REWARD_NOTIFICATION_SEEN = "REWARD_NOTIFICATION_SEEN"; static final String REWARD_NOTIFICATION_INTERACTION = "REWARD_NOTIFICATION_INTERACTION"; static final String REWARD_WIDGET_INTERACTION = "REWARD_WIDGET_INTERACTION"; static final String REWARD_OTHER_USER_INTERACTION = "REWARD_OTHER_USER_INTERACTION"; @StringDef({ REWARD_TOP_ACTIVITY, REWARD_NOTIFICATION_SEEN, REWARD_NOTIFICATION_INTERACTION, REWARD_WIDGET_INTERACTION, REWARD_OTHER_USER_INTERACTION, }) @Retention(RetentionPolicy.SOURCE) public @interface UtilityReward { } static class Action { @NonNull public final String name; /** * How many ARCs the system says it takes to perform this action. */ public final long costToProduce; /** * The base price to perform this action. If this is * less than the {@link #costToProduce}, then the system should not perform * the action unless a multiplier lowers the cost to produce. */ public final long basePrice; Action(@NonNull String name, long costToProduce, long basePrice) { this.name = name; this.costToProduce = costToProduce; this.basePrice = basePrice; } } static class Reward { @NonNull @UtilityReward public final String name; public final long instantReward; /** Reward credited per second of ongoing activity. */ public final long ongoingRewardPerSecond; /** The maximum amount an app can earn from this reward within a 24 hour period. */ public final long maxDailyReward; Reward(@NonNull String name, long instantReward, long ongoingReward, long maxDailyReward) { this.name = name; this.instantReward = instantReward; this.ongoingRewardPerSecond = ongoingReward; this.maxDailyReward = maxDailyReward; } } EconomicPolicy(@NonNull InternalResourceService irs) { } @CallSuper void onSystemServicesReady() { } /** * Returns the minimum suggested balance an app should have when the device is at 100% battery. * This takes into account any exemptions the app may have. */ abstract long getMinSatiatedBalance(int userId, @NonNull String pkgName); /** * Returns the maximum balance an app should have when the device is at 100% battery. This * exists to ensure that no single app accumulate all available resources and increases fairness * for all apps. */ abstract long getMaxSatiatedBalance(); /** * Returns the maximum number of narcs that should be in circulation at once when the device is * at 100% battery. */ abstract long getMaxSatiatedCirculation(); @Nullable abstract Action getAction(@NonNull String actionName); @Nullable abstract Reward getReward(@NonNull String rewardName); void dump(IndentingPrintWriter pw) { } }
apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import static com.android.server.tare.TareUtils.arcToNarc; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; /** * Policy defining pricing information and daily ARC requirements and suggestions for * JobScheduler. */ public class JobSchedulerEconomicPolicy extends EconomicPolicy { public static final String ACTION_JOB_MAX_START = "JOB_MAX_START"; public static final String ACTION_JOB_MAX_RUNNING = "JOB_MAX_RUNNING"; public static final String ACTION_JOB_HIGH_START = "JOB_HIGH_START"; public static final String ACTION_JOB_HIGH_RUNNING = "JOB_HIGH_RUNNING"; public static final String ACTION_JOB_DEFAULT_START = "JOB_DEFAULT_START"; public static final String ACTION_JOB_DEFAULT_RUNNING = "JOB_DEFAULT_RUNNING"; public static final String ACTION_JOB_LOW_START = "JOB_LOW_START"; public static final String ACTION_JOB_LOW_RUNNING = "JOB_LOW_RUNNING"; public static final String ACTION_JOB_MIN_START = "JOB_MIN_START"; public static final String ACTION_JOB_MIN_RUNNING = "JOB_MIN_RUNNING"; public static final String ACTION_JOB_TIMEOUT = "JOB_TIMEOUT"; private final ArrayMap<String, Action> mActions = new ArrayMap<>(); private final ArrayMap<String, Reward> mRewards = new ArrayMap<>(); JobSchedulerEconomicPolicy(InternalResourceService irs) { super(irs); loadActions(); loadRewards(); } @Override long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) { // TODO: incorporate time since usage return arcToNarc(2000); } @Override long getMaxSatiatedBalance() { return arcToNarc(60000); } @Override long getMaxSatiatedCirculation() { return arcToNarc(691200); } @Nullable @Override Action getAction(@NonNull String actionName) { return mActions.get(actionName); } @Nullable @Override Reward getReward(@NonNull String rewardName) { return mRewards.get(rewardName); } private void loadActions() { mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START, arcToNarc(3), arcToNarc(10))); mActions.put(ACTION_JOB_MAX_RUNNING, new Action(ACTION_JOB_MAX_RUNNING, arcToNarc(2), arcToNarc(5))); mActions.put(ACTION_JOB_HIGH_START, new Action(ACTION_JOB_HIGH_START, arcToNarc(3), arcToNarc(8))); mActions.put(ACTION_JOB_HIGH_RUNNING, new Action(ACTION_JOB_HIGH_RUNNING, arcToNarc(2), arcToNarc(4))); mActions.put(ACTION_JOB_DEFAULT_START, new Action(ACTION_JOB_DEFAULT_START, arcToNarc(3), arcToNarc(6))); mActions.put(ACTION_JOB_DEFAULT_RUNNING, new Action(ACTION_JOB_DEFAULT_RUNNING, arcToNarc(2), arcToNarc(3))); mActions.put(ACTION_JOB_LOW_START, new Action(ACTION_JOB_LOW_START, arcToNarc(3), arcToNarc(4))); mActions.put(ACTION_JOB_LOW_RUNNING, new Action(ACTION_JOB_LOW_RUNNING, arcToNarc(2), arcToNarc(2))); mActions.put(ACTION_JOB_MIN_START, new Action(ACTION_JOB_MIN_START, arcToNarc(3), arcToNarc(2))); mActions.put(ACTION_JOB_MIN_RUNNING, new Action(ACTION_JOB_MIN_RUNNING, arcToNarc(2), arcToNarc(1))); mActions.put(ACTION_JOB_TIMEOUT, new Action(ACTION_JOB_TIMEOUT, arcToNarc(30), arcToNarc(60))); } private void loadRewards() { mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY, arcToNarc(0), /* .5 arcs */ arcToNarc(5) / 10, arcToNarc(15000))); mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(1), arcToNarc(0), arcToNarc(10))); mRewards.put(REWARD_NOTIFICATION_INTERACTION, new Reward(REWARD_NOTIFICATION_INTERACTION, arcToNarc(5), arcToNarc(0), arcToNarc(5000))); mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(5000))); mRewards.put(REWARD_OTHER_USER_INTERACTION, new Reward(REWARD_OTHER_USER_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(5000))); } }