• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.internal.os;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 import android.ravenwood.annotation.RavenwoodKeepWholeClass;
22 import android.ravenwood.annotation.RavenwoodRedirect;
23 import android.ravenwood.annotation.RavenwoodRedirectionClass;
24 import android.ravenwood.annotation.RavenwoodReplace;
25 
26 import com.android.internal.util.Preconditions;
27 
28 import dalvik.annotation.optimization.CriticalNative;
29 import dalvik.annotation.optimization.FastNative;
30 
31 import libcore.util.NativeAllocationRegistry;
32 
33 /**
34  * Performs per-state counting of long integers over time.  The tracked "value" is expected
35  * to increase monotonously. The counter keeps track of the current state.  When the
36  * updateValue method is called, the delta from the previous invocation of this method
37  * and the new value is added to the counter corresponding to the current state.  If the
38  * state changed in the interim, the delta is distributed proptionally.
39  *
40  * The class's behavior is illustrated by this example:
41  * <pre>
42  *   // At 0 ms, the state of the tracked object is 0 and the initial tracked value is 100
43  *   counter.setState(0, 0);
44  *   counter.updateValue(100, 0);
45  *
46  *   // At 1000 ms, the state changes to 1
47  *   counter.setState(1, 1000);
48  *
49  *   // At 3000 ms, the tracked value is updated to 130
50  *   counter.updateValue(130, 3000);
51  *
52  *   // The delta (130 - 100 = 30) is distributed between states 0 and 1 according to the time
53  *   // spent in those respective states; in this specific case, 1000 and 2000 ms.
54  *   long countForState0 == counter.getCount(0);  // 10
55  *   long countForState1 == counter.getCount(1);  // 20
56  * </pre>
57  *
58  * The tracked values are expected to increase monotonically.
59  *
60  * @hide
61  */
62 @RavenwoodKeepWholeClass
63 @RavenwoodRedirectionClass("LongMultiStateCounter_ravenwood")
64 public final class LongMultiStateCounter implements Parcelable {
65 
66     private static NativeAllocationRegistry sRegistry;
67 
68     private final int mStateCount;
69 
70     // Visible to other objects in this package so that it can be passed to @CriticalNative
71     // methods.
72     final long mNativeObject;
73 
LongMultiStateCounter(int stateCount)74     public LongMultiStateCounter(int stateCount) {
75         Preconditions.checkArgumentPositive(stateCount, "stateCount must be greater than 0");
76         mStateCount = stateCount;
77         mNativeObject = native_init(stateCount);
78         registerNativeAllocation();
79     }
80 
LongMultiStateCounter(Parcel in)81     private LongMultiStateCounter(Parcel in) {
82         mNativeObject = native_initFromParcel(in);
83         registerNativeAllocation();
84 
85         mStateCount = native_getStateCount(mNativeObject);
86     }
87 
88     @RavenwoodReplace
registerNativeAllocation()89     private void registerNativeAllocation() {
90         if (sRegistry == null) {
91             synchronized (LongMultiStateCounter.class) {
92                 if (sRegistry == null) {
93                     sRegistry = NativeAllocationRegistry.createMalloced(
94                             LongMultiStateCounter.class.getClassLoader(), native_getReleaseFunc());
95                 }
96             }
97         }
98         sRegistry.registerNativeAllocation(this, mNativeObject);
99     }
100 
registerNativeAllocation$ravenwood()101     private void registerNativeAllocation$ravenwood() {
102         // No-op under ravenwood
103     }
104 
getStateCount()105     public int getStateCount() {
106         return mStateCount;
107     }
108 
109     /**
110      * Enables or disables the counter.  When the counter is disabled, it does not
111      * accumulate counts supplied by the {@link #updateValue} method.
112      */
setEnabled(boolean enabled, long timestampMs)113     public void setEnabled(boolean enabled, long timestampMs) {
114         native_setEnabled(mNativeObject, enabled, timestampMs);
115     }
116 
117     /**
118      * Sets the current state to the supplied value.
119      *
120      * @param state The new state
121      * @param timestampMs The time when the state change occurred, e.g.
122      *                    SystemClock.elapsedRealtime()
123      */
setState(int state, long timestampMs)124     public void setState(int state, long timestampMs) {
125         if (state < 0 || state >= mStateCount) {
126             throw new IllegalArgumentException(
127                     "State: " + state + ", outside the range: [0-" + (mStateCount - 1) + "]");
128         }
129         native_setState(mNativeObject, state, timestampMs);
130     }
131 
132     /**
133      * Sets the new values.  The delta between the previously set value and this value
134      * is distributed among the state according to the time the object spent in those states
135      * since the previous call to updateValue.
136      *
137      * @return The delta between the previous value and the new value.
138      */
updateValue(long value, long timestampMs)139     public long updateValue(long value, long timestampMs) {
140         return native_updateValue(mNativeObject, value, timestampMs);
141     }
142 
143     /**
144      * Adds the supplied values to the current accumulated values in the counter.
145      */
incrementValue(long count, long timestampMs)146     public void incrementValue(long count, long timestampMs) {
147         native_incrementValue(mNativeObject, count, timestampMs);
148     }
149 
150     /**
151      * Adds the supplied values to the current accumulated values in the counter.
152      */
addCount(long count)153     public void addCount(long count) {
154         native_addCount(mNativeObject, count);
155     }
156 
157     /**
158      * Resets the accumulated counts to 0.
159      */
reset()160     public void reset() {
161         native_reset(mNativeObject);
162     }
163 
164     /**
165      * Returns the accumulated count for the specified state.
166      */
getCount(int state)167     public long getCount(int state) {
168         if (state < 0 || state >= mStateCount) {
169             throw new IllegalArgumentException(
170                     "State: " + state + ", outside the range: [0-" + mStateCount + "]");
171         }
172         return native_getCount(mNativeObject, state);
173     }
174 
175     /**
176      * Returns the total accumulated count across all states.
177      */
getTotalCount()178     public long getTotalCount() {
179         long total = 0;
180         for (int state = 0; state < mStateCount; state++) {
181             total += native_getCount(mNativeObject, state);
182         }
183         return total;
184     }
185 
186     @Override
toString()187     public String toString() {
188         return native_toString(mNativeObject);
189     }
190 
191     @Override
writeToParcel(Parcel dest, int flags)192     public void writeToParcel(Parcel dest, int flags) {
193         native_writeToParcel(mNativeObject, dest, flags);
194     }
195 
196     @Override
describeContents()197     public int describeContents() {
198         return 0;
199     }
200 
201     public static final Creator<LongMultiStateCounter> CREATOR =
202             new Creator<LongMultiStateCounter>() {
203                 @Override
204                 public LongMultiStateCounter createFromParcel(Parcel in) {
205                     return new LongMultiStateCounter(in);
206                 }
207 
208                 @Override
209                 public LongMultiStateCounter[] newArray(int size) {
210                     return new LongMultiStateCounter[size];
211                 }
212             };
213 
214 
215     @CriticalNative
216     @RavenwoodRedirect
native_init(int stateCount)217     private static native long native_init(int stateCount);
218 
219     @CriticalNative
220     @RavenwoodRedirect
native_getReleaseFunc()221     private static native long native_getReleaseFunc();
222 
223     @CriticalNative
224     @RavenwoodRedirect
native_setEnabled(long nativeObject, boolean enabled, long timestampMs)225     private static native void native_setEnabled(long nativeObject, boolean enabled,
226             long timestampMs);
227 
228     @CriticalNative
229     @RavenwoodRedirect
native_setState(long nativeObject, int state, long timestampMs)230     private static native void native_setState(long nativeObject, int state, long timestampMs);
231 
232     @CriticalNative
233     @RavenwoodRedirect
native_updateValue(long nativeObject, long value, long timestampMs)234     private static native long native_updateValue(long nativeObject, long value, long timestampMs);
235 
236     @CriticalNative
237     @RavenwoodRedirect
native_incrementValue(long nativeObject, long increment, long timestampMs)238     private static native void native_incrementValue(long nativeObject, long increment,
239             long timestampMs);
240 
241     @CriticalNative
242     @RavenwoodRedirect
native_addCount(long nativeObject, long count)243     private static native void native_addCount(long nativeObject, long count);
244 
245     @CriticalNative
246     @RavenwoodRedirect
native_reset(long nativeObject)247     private static native void native_reset(long nativeObject);
248 
249     @CriticalNative
250     @RavenwoodRedirect
native_getCount(long nativeObject, int state)251     private static native long native_getCount(long nativeObject, int state);
252 
253     @FastNative
254     @RavenwoodRedirect
native_toString(long nativeObject)255     private static native String native_toString(long nativeObject);
256 
257     @FastNative
258     @RavenwoodRedirect
native_writeToParcel(long nativeObject, Parcel dest, int flags)259     private static native void native_writeToParcel(long nativeObject, Parcel dest, int flags);
260 
261     @FastNative
262     @RavenwoodRedirect
native_initFromParcel(Parcel parcel)263     private static native long native_initFromParcel(Parcel parcel);
264 
265     @CriticalNative
266     @RavenwoodRedirect
native_getStateCount(long nativeObject)267     private static native int native_getStateCount(long nativeObject);
268 }
269