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