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 public final class LongMultiStateCounter implements Parcelable { 59 60 private static final NativeAllocationRegistry sRegistry = 61 NativeAllocationRegistry.createMalloced( 62 LongMultiStateCounter.class.getClassLoader(), native_getReleaseFunc()); 63 64 private final int mStateCount; 65 66 // Visible to other objects in this package so that it can be passed to @CriticalNative 67 // methods. 68 final long mNativeObject; 69 LongMultiStateCounter(int stateCount)70 public LongMultiStateCounter(int stateCount) { 71 Preconditions.checkArgumentPositive(stateCount, "stateCount must be greater than 0"); 72 mStateCount = stateCount; 73 mNativeObject = native_init(stateCount); 74 sRegistry.registerNativeAllocation(this, mNativeObject); 75 } 76 LongMultiStateCounter(Parcel in)77 private LongMultiStateCounter(Parcel in) { 78 mNativeObject = native_initFromParcel(in); 79 sRegistry.registerNativeAllocation(this, mNativeObject); 80 81 mStateCount = native_getStateCount(mNativeObject); 82 } 83 getStateCount()84 public int getStateCount() { 85 return mStateCount; 86 } 87 88 /** 89 * Enables or disables the counter. When the counter is disabled, it does not 90 * accumulate counts supplied by the {@link #updateValue} method. 91 */ setEnabled(boolean enabled, long timestampMs)92 public void setEnabled(boolean enabled, long timestampMs) { 93 native_setEnabled(mNativeObject, enabled, timestampMs); 94 } 95 96 /** 97 * Sets the current state to the supplied value. 98 * 99 * @param state The new state 100 * @param timestampMs The time when the state change occurred, e.g. 101 * SystemClock.elapsedRealtime() 102 */ setState(int state, long timestampMs)103 public void setState(int state, long timestampMs) { 104 if (state < 0 || state >= mStateCount) { 105 throw new IllegalArgumentException( 106 "State: " + state + ", outside the range: [0-" + (mStateCount - 1) + "]"); 107 } 108 native_setState(mNativeObject, state, timestampMs); 109 } 110 111 /** 112 * Sets the new values. The delta between the previously set value and this value 113 * is distributed among the state according to the time the object spent in those states 114 * since the previous call to updateValue. 115 * 116 * @return The delta between the previous value and the new value. 117 */ updateValue(long value, long timestampMs)118 public long updateValue(long value, long timestampMs) { 119 return native_updateValue(mNativeObject, value, timestampMs); 120 } 121 122 /** 123 * Adds the supplied values to the current accumulated values in the counter. 124 */ incrementValue(long count, long timestampMs)125 public void incrementValue(long count, long timestampMs) { 126 native_incrementValue(mNativeObject, count, timestampMs); 127 } 128 129 /** 130 * Adds the supplied values to the current accumulated values in the counter. 131 */ addCount(long count)132 public void addCount(long count) { 133 native_addCount(mNativeObject, count); 134 } 135 136 /** 137 * Resets the accumulated counts to 0. 138 */ reset()139 public void reset() { 140 native_reset(mNativeObject); 141 } 142 143 /** 144 * Returns the accumulated count for the specified state. 145 */ getCount(int state)146 public long getCount(int state) { 147 if (state < 0 || state >= mStateCount) { 148 throw new IllegalArgumentException( 149 "State: " + state + ", outside the range: [0-" + mStateCount + "]"); 150 } 151 return native_getCount(mNativeObject, state); 152 } 153 154 /** 155 * Returns the total accumulated count across all states. 156 */ getTotalCount()157 public long getTotalCount() { 158 long total = 0; 159 for (int state = 0; state < mStateCount; state++) { 160 total += native_getCount(mNativeObject, state); 161 } 162 return total; 163 } 164 165 @Override toString()166 public String toString() { 167 return native_toString(mNativeObject); 168 } 169 170 @Override writeToParcel(Parcel dest, int flags)171 public void writeToParcel(Parcel dest, int flags) { 172 native_writeToParcel(mNativeObject, dest, flags); 173 } 174 175 @Override describeContents()176 public int describeContents() { 177 return 0; 178 } 179 180 public static final Creator<LongMultiStateCounter> CREATOR = 181 new Creator<LongMultiStateCounter>() { 182 @Override 183 public LongMultiStateCounter createFromParcel(Parcel in) { 184 return new LongMultiStateCounter(in); 185 } 186 187 @Override 188 public LongMultiStateCounter[] newArray(int size) { 189 return new LongMultiStateCounter[size]; 190 } 191 }; 192 193 194 @CriticalNative native_init(int stateCount)195 private static native long native_init(int stateCount); 196 197 @CriticalNative native_getReleaseFunc()198 private static native long native_getReleaseFunc(); 199 200 @CriticalNative native_setEnabled(long nativeObject, boolean enabled, long timestampMs)201 private static native void native_setEnabled(long nativeObject, boolean enabled, 202 long timestampMs); 203 204 @CriticalNative native_setState(long nativeObject, int state, long timestampMs)205 private static native void native_setState(long nativeObject, int state, long timestampMs); 206 207 @CriticalNative native_updateValue(long nativeObject, long value, long timestampMs)208 private static native long native_updateValue(long nativeObject, long value, long timestampMs); 209 210 @CriticalNative native_incrementValue(long nativeObject, long increment, long timestampMs)211 private static native void native_incrementValue(long nativeObject, long increment, 212 long timestampMs); 213 214 @CriticalNative native_addCount(long nativeObject, long count)215 private static native void native_addCount(long nativeObject, long count); 216 217 @CriticalNative native_reset(long nativeObject)218 private static native void native_reset(long nativeObject); 219 220 @CriticalNative native_getCount(long nativeObject, int state)221 private static native long native_getCount(long nativeObject, int state); 222 223 @FastNative native_toString(long nativeObject)224 private native String native_toString(long nativeObject); 225 226 @FastNative native_writeToParcel(long nativeObject, Parcel dest, int flags)227 private native void native_writeToParcel(long nativeObject, Parcel dest, int flags); 228 229 @FastNative native_initFromParcel(Parcel parcel)230 private static native long native_initFromParcel(Parcel parcel); 231 232 @CriticalNative native_getStateCount(long nativeObject)233 private static native int native_getStateCount(long nativeObject); 234 } 235