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 
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.List;
27 
28 /**
29  * Interface for the system server to deal with the resource economy subsystem.
30  *
31  * @hide
32  */
33 public interface EconomyManagerInternal {
34     /**
35      * Used to indicate a future action an app is expected to take.
36      */
37     final class AnticipatedAction {
38         public final int actionId;
39         public final int numInstantaneousCalls;
40         public final long ongoingDurationMs;
41         private final int mHashCode;
42 
43         /**
44          * @param actionId              The expected action
45          * @param numInstantaneousCalls How many instantaneous times the action will be performed
46          * @param ongoingDurationMs     An estimate of how long the ongoing event will go on for
47          */
AnticipatedAction(@conomicPolicy.AppAction int actionId, int numInstantaneousCalls, long ongoingDurationMs)48         public AnticipatedAction(@EconomicPolicy.AppAction int actionId,
49                 int numInstantaneousCalls, long ongoingDurationMs) {
50             this.actionId = actionId;
51             this.numInstantaneousCalls = numInstantaneousCalls;
52             this.ongoingDurationMs = ongoingDurationMs;
53 
54             int hash = 0;
55             hash = 31 * hash + actionId;
56             hash = 31 * hash + numInstantaneousCalls;
57             hash = 31 * hash + (int) (ongoingDurationMs ^ (ongoingDurationMs >>> 32));
58             mHashCode = hash;
59         }
60 
61         @Override
equals(Object o)62         public boolean equals(Object o) {
63             if (this == o) return true;
64             if (o == null || getClass() != o.getClass()) return false;
65             AnticipatedAction that = (AnticipatedAction) o;
66             return actionId == that.actionId
67                     && numInstantaneousCalls == that.numInstantaneousCalls
68                     && ongoingDurationMs == that.ongoingDurationMs;
69         }
70 
71         @Override
hashCode()72         public int hashCode() {
73             return mHashCode;
74         }
75     }
76 
77     /**
78      * A collection of {@link AnticipatedAction AnticipatedActions} that will be performed together.
79      */
80     final class ActionBill {
81         private static final Comparator<AnticipatedAction>
82                 sAnticipatedActionComparator = Comparator.comparingInt(aa -> aa.actionId);
83 
84         private final List<AnticipatedAction> mAnticipatedActions;
85         private final int mHashCode;
86 
ActionBill(@onNull List<AnticipatedAction> anticipatedActions)87         public ActionBill(@NonNull List<AnticipatedAction> anticipatedActions) {
88             List<AnticipatedAction> actions = new ArrayList<>(anticipatedActions);
89             actions.sort(sAnticipatedActionComparator);
90             mAnticipatedActions = Collections.unmodifiableList(actions);
91 
92             int hash = 0;
93             for (int i = 0; i < mAnticipatedActions.size(); ++i) {
94                 hash = 31 * hash + mAnticipatedActions.get(i).hashCode();
95             }
96             mHashCode = hash;
97         }
98 
getAnticipatedActions()99         List<AnticipatedAction> getAnticipatedActions() {
100             return mAnticipatedActions;
101         }
102 
103         @Override
equals(Object o)104         public boolean equals(Object o) {
105             if (this == o) return true;
106             if (o == null || getClass() != o.getClass()) return false;
107             ActionBill that = (ActionBill) o;
108             return mAnticipatedActions.equals(that.mAnticipatedActions);
109         }
110 
111         @Override
hashCode()112         public int hashCode() {
113             return mHashCode;
114         }
115     }
116 
117     /** Listener for when an app's ability to afford a bill changes. */
118     interface AffordabilityChangeListener {
onAffordabilityChanged(int userId, @NonNull String pkgName, @NonNull ActionBill bill, boolean canAfford)119         void onAffordabilityChanged(int userId, @NonNull String pkgName, @NonNull ActionBill bill,
120                 boolean canAfford);
121     }
122 
123     /** Listener for various TARE state changes. */
124     interface TareStateChangeListener {
onTareEnabledModeChanged(@conomyManager.EnabledMode int tareEnabledMode)125         void onTareEnabledModeChanged(@EconomyManager.EnabledMode int tareEnabledMode);
126     }
127 
128     /**
129      * Return {@code true} if the app is able to pay for the anticipated actions.
130      */
canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill)131     boolean canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill);
132 
133     /**
134      * Returns the maximum duration (in milliseconds) that the specified app can afford the bill,
135      * based on current prices.
136      */
getMaxDurationMs(int userId, @NonNull String pkgName, @NonNull ActionBill bill)137     long getMaxDurationMs(int userId, @NonNull String pkgName, @NonNull ActionBill bill);
138 
139     /** Returns the current TARE enabled mode. */
140     @EconomyManager.EnabledMode
getEnabledMode()141     int getEnabledMode();
142 
143     /** Returns the current TARE enabled mode for the specified policy. */
144     @EconomyManager.EnabledMode
getEnabledMode(@conomicPolicy.Policy int policyId)145     int getEnabledMode(@EconomicPolicy.Policy int policyId);
146 
147     /**
148      * Register an {@link AffordabilityChangeListener} to track when an app's ability to afford the
149      * indicated bill changes.
150      */
registerAffordabilityChangeListener(int userId, @NonNull String pkgName, @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill)151     void registerAffordabilityChangeListener(int userId, @NonNull String pkgName,
152             @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill);
153 
154     /**
155      * Unregister a {@link AffordabilityChangeListener} from being notified of any changes to an
156      * app's ability to afford the specified bill.
157      */
unregisterAffordabilityChangeListener(int userId, @NonNull String pkgName, @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill)158     void unregisterAffordabilityChangeListener(int userId, @NonNull String pkgName,
159             @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill);
160 
161     /**
162      * Register a {@link TareStateChangeListener} to track when TARE's state changes.
163      */
registerTareStateChangeListener(@onNull TareStateChangeListener listener, @EconomicPolicy.Policy int policyId)164     void registerTareStateChangeListener(@NonNull TareStateChangeListener listener,
165             @EconomicPolicy.Policy int policyId);
166 
167     /**
168      * Unregister a {@link TareStateChangeListener} from being notified when TARE's state changes.
169      */
unregisterTareStateChangeListener(@onNull TareStateChangeListener listener)170     void unregisterTareStateChangeListener(@NonNull TareStateChangeListener listener);
171 
172     /**
173      * Note that an instantaneous event has occurred. The event must be specified in one of the
174      * EconomicPolicies.
175      *
176      * @param tag An optional tag that can be used to differentiate the same event for the same app.
177      */
noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId, @Nullable String tag)178     void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
179             @Nullable String tag);
180 
181     /**
182      * Note that a long-running event is starting. The event must be specified in one of the
183      * EconomicPolicies. You must always call
184      * {@link #noteOngoingEventStopped(int, String, int, String)} to end the event. Ongoing
185      * events will be separated and grouped by event-tag combinations. There must be an equal
186      * number of start() and stop() calls for the same event-tag combination in order for the
187      * tracking to finally stop (ie. ongoing events are ref-counted).
188      *
189      * @param tag An optional tag that can be used to differentiate the same event for the same app.
190      */
noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId, @Nullable String tag)191     void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
192             @Nullable String tag);
193 
194     /**
195      * Note that a long-running event has stopped. The event must be specified in one of the
196      * EconomicPolicies. Ongoing events are separated and grouped by event-tag combinations.
197      * There must be an equal number of start() and stop() calls for the same event-tag combination
198      * in order for the tracking to finally stop (ie. ongoing events are ref-counted).
199      *
200      * @param tag An optional tag that can be used to differentiate the same event for the same app.
201      */
noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId, @Nullable String tag)202     void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
203             @Nullable String tag);
204 }
205