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