• 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 
22 import com.android.internal.util.Preconditions;
23 
24 import dalvik.annotation.optimization.CriticalNative;
25 import dalvik.annotation.optimization.FastNative;
26 
27 import libcore.util.NativeAllocationRegistry;
28 
29 import java.util.Arrays;
30 import java.util.concurrent.atomic.AtomicReference;
31 
32 /**
33  * Performs per-state counting of multi-element values over time. The class' behavior is illustrated
34  * by this example:
35  * <pre>
36  *   // At 0 ms, the state of the tracked object is 0
37  *   counter.setState(0, 0);
38  *
39  *   // At 1000 ms, the state changes to 1
40  *   counter.setState(1, 1000);
41  *
42  *   // At 3000 ms, the tracked values are updated to {30, 300}
43  *   arrayContainer.setValues(new long[]{{30, 300}};
44  *   counter.updateValues(arrayContainer, 3000);
45  *
46  *   // The values are distributed between states 0 and 1 according to the time
47  *   // spent in those respective states. In this specific case, 1000 and 2000 ms.
48  *   counter.getValues(arrayContainer, 0);
49  *   // arrayContainer now has values {10, 100}
50  *   counter.getValues(arrayContainer, 1);
51  *   // arrayContainer now has values {20, 200}
52  * </pre>
53  *
54  * The tracked values are expected to increase monotonically.
55  *
56  * @hide
57  */
58 public final class LongArrayMultiStateCounter implements Parcelable {
59 
60     /**
61      * Container for a native equivalent of a long[].
62      */
63     public static class LongArrayContainer {
64         private static final NativeAllocationRegistry sRegistry =
65                 NativeAllocationRegistry.createMalloced(
66                         LongArrayContainer.class.getClassLoader(), native_getReleaseFunc());
67 
68         // Visible to other objects in this package so that it can be passed to @CriticalNative
69         // methods.
70         final long mNativeObject;
71         private final int mLength;
72 
LongArrayContainer(int length)73         public LongArrayContainer(int length) {
74             mLength = length;
75             mNativeObject = native_init(length);
76             sRegistry.registerNativeAllocation(this, mNativeObject);
77         }
78 
79         /**
80          * Copies the supplied values into the underlying native array.
81          */
setValues(long[] array)82         public void setValues(long[] array) {
83             if (array.length != mLength) {
84                 throw new IllegalArgumentException(
85                         "Invalid array length: " + mLength + ", expected: " + mLength);
86             }
87             native_setValues(mNativeObject, array);
88         }
89 
90         /**
91          * Copies the underlying native array values to the supplied array.
92          */
getValues(long[] array)93         public void getValues(long[] array) {
94             if (array.length != mLength) {
95                 throw new IllegalArgumentException(
96                         "Invalid array length: " + mLength + ", expected: " + mLength);
97             }
98             native_getValues(mNativeObject, array);
99         }
100 
101         @Override
toString()102         public String toString() {
103             final long[] array = new long[mLength];
104             getValues(array);
105             return Arrays.toString(array);
106         }
107 
108         @CriticalNative
native_init(int length)109         private static native long native_init(int length);
110 
111         @CriticalNative
native_getReleaseFunc()112         private static native long native_getReleaseFunc();
113 
114         @FastNative
native_setValues(long nativeObject, long[] array)115         private native void native_setValues(long nativeObject, long[] array);
116 
117         @FastNative
native_getValues(long nativeObject, long[] array)118         private native void native_getValues(long nativeObject, long[] array);
119     }
120 
121     private static final NativeAllocationRegistry sRegistry =
122             NativeAllocationRegistry.createMalloced(
123                     LongArrayMultiStateCounter.class.getClassLoader(), native_getReleaseFunc());
124     private static final AtomicReference<LongArrayContainer> sTmpArrayContainer =
125             new AtomicReference<>();
126 
127     private final int mStateCount;
128     private final int mLength;
129 
130     // Visible to other objects in this package so that it can be passed to @CriticalNative
131     // methods.
132     final long mNativeObject;
133 
LongArrayMultiStateCounter(int stateCount, int arrayLength)134     public LongArrayMultiStateCounter(int stateCount, int arrayLength) {
135         Preconditions.checkArgumentPositive(stateCount, "stateCount must be greater than 0");
136         mStateCount = stateCount;
137         mLength = arrayLength;
138         mNativeObject = native_init(stateCount, arrayLength);
139         sRegistry.registerNativeAllocation(this, mNativeObject);
140     }
141 
LongArrayMultiStateCounter(Parcel in)142     private LongArrayMultiStateCounter(Parcel in) {
143         mNativeObject = native_initFromParcel(in);
144         sRegistry.registerNativeAllocation(this, mNativeObject);
145 
146         mStateCount = native_getStateCount(mNativeObject);
147         mLength = native_getArrayLength(mNativeObject);
148     }
149 
getStateCount()150     public int getStateCount() {
151         return mStateCount;
152     }
153 
getArrayLength()154     public int getArrayLength() {
155         return mLength;
156     }
157 
158     /**
159      * Enables or disables the counter.  When the counter is disabled, it does not
160      * accumulate counts supplied by the {@link #updateValues} method.
161      */
setEnabled(boolean enabled, long timestampMs)162     public void setEnabled(boolean enabled, long timestampMs) {
163         native_setEnabled(mNativeObject, enabled, timestampMs);
164     }
165 
166     /**
167      * Sets the current state to the supplied value.
168      */
setState(int state, long timestampMs)169     public void setState(int state, long timestampMs) {
170         if (state < 0 || state >= mStateCount) {
171             throw new IllegalArgumentException(
172                     "State: " + state + ", outside the range: [0-" + (mStateCount - 1) + "]");
173         }
174         native_setState(mNativeObject, state, timestampMs);
175     }
176 
177     /**
178      * Sets the new values.  The delta between the previously set values and these values
179      * is distributed among the state according to the time the object spent in those states
180      * since the previous call to updateValues.
181      */
updateValues(LongArrayContainer longArrayContainer, long timestampMs)182     public void updateValues(LongArrayContainer longArrayContainer, long timestampMs) {
183         if (longArrayContainer.mLength != mLength) {
184             throw new IllegalArgumentException(
185                     "Invalid array length: " + longArrayContainer.mLength + ", expected: "
186                             + mLength);
187         }
188         native_updateValues(mNativeObject, longArrayContainer.mNativeObject, timestampMs);
189     }
190 
191     /**
192      * Adds the supplied values to the current accumulated values in the counter.
193      */
addCounts(LongArrayContainer counts)194     public void addCounts(LongArrayContainer counts) {
195         if (counts.mLength != mLength) {
196             throw new IllegalArgumentException(
197                     "Invalid array length: " + counts.mLength + ", expected: " + mLength);
198         }
199         native_addCounts(mNativeObject, counts.mNativeObject);
200     }
201 
202     /**
203      * Resets the accumulated counts to 0.
204      */
reset()205     public void reset() {
206         native_reset(mNativeObject);
207     }
208 
209     /**
210      * Populates the array with the accumulated counts for the specified state.
211      */
getCounts(long[] counts, int state)212     public void getCounts(long[] counts, int state) {
213         LongArrayContainer container = sTmpArrayContainer.getAndSet(null);
214         if (container == null || container.mLength != counts.length) {
215             container = new LongArrayContainer(counts.length);
216         }
217         getCounts(container, state);
218         container.getValues(counts);
219         sTmpArrayContainer.set(container);
220     }
221 
222     /**
223      * Populates longArrayContainer with the accumulated counts for the specified state.
224      */
getCounts(LongArrayContainer longArrayContainer, int state)225     public void getCounts(LongArrayContainer longArrayContainer, int state) {
226         if (state < 0 || state >= mStateCount) {
227             throw new IllegalArgumentException(
228                     "State: " + state + ", outside the range: [0-" + mStateCount + "]");
229         }
230         native_getCounts(mNativeObject, longArrayContainer.mNativeObject, state);
231     }
232 
233     @Override
toString()234     public String toString() {
235         return native_toString(mNativeObject);
236     }
237 
238     @Override
writeToParcel(Parcel dest, int flags)239     public void writeToParcel(Parcel dest, int flags) {
240         native_writeToParcel(mNativeObject, dest, flags);
241     }
242 
243     @Override
describeContents()244     public int describeContents() {
245         return 0;
246     }
247 
248     public static final Creator<LongArrayMultiStateCounter> CREATOR =
249             new Creator<LongArrayMultiStateCounter>() {
250                 @Override
251                 public LongArrayMultiStateCounter createFromParcel(Parcel in) {
252                     return new LongArrayMultiStateCounter(in);
253                 }
254 
255                 @Override
256                 public LongArrayMultiStateCounter[] newArray(int size) {
257                     return new LongArrayMultiStateCounter[size];
258                 }
259             };
260 
261 
262     @CriticalNative
native_init(int stateCount, int arrayLength)263     private static native long native_init(int stateCount, int arrayLength);
264 
265     @CriticalNative
native_getReleaseFunc()266     private static native long native_getReleaseFunc();
267 
268     @CriticalNative
native_setEnabled(long nativeObject, boolean enabled, long timestampMs)269     private static native void native_setEnabled(long nativeObject, boolean enabled,
270             long timestampMs);
271 
272     @CriticalNative
native_setState(long nativeObject, int state, long timestampMs)273     private static native void native_setState(long nativeObject, int state, long timestampMs);
274 
275     @CriticalNative
native_updateValues(long nativeObject, long longArrayContainerNativeObject, long timestampMs)276     private static native void native_updateValues(long nativeObject,
277             long longArrayContainerNativeObject, long timestampMs);
278 
279     @CriticalNative
native_addCounts(long nativeObject, long longArrayContainerNativeObject)280     private static native void native_addCounts(long nativeObject,
281             long longArrayContainerNativeObject);
282 
283     @CriticalNative
native_reset(long nativeObject)284     private static native void native_reset(long nativeObject);
285 
286     @CriticalNative
native_getCounts(long nativeObject, long longArrayContainerNativeObject, int state)287     private static native void native_getCounts(long nativeObject,
288             long longArrayContainerNativeObject, int state);
289 
290     @FastNative
native_toString(long nativeObject)291     private native String native_toString(long nativeObject);
292 
293     @FastNative
native_writeToParcel(long nativeObject, Parcel dest, int flags)294     private native void native_writeToParcel(long nativeObject, Parcel dest, int flags);
295 
296     @FastNative
native_initFromParcel(Parcel parcel)297     private static native long native_initFromParcel(Parcel parcel);
298 
299     @CriticalNative
native_getStateCount(long nativeObject)300     private static native int native_getStateCount(long nativeObject);
301 
302     @CriticalNative
native_getArrayLength(long nativeObject)303     private static native int native_getArrayLength(long nativeObject);
304 }
305