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