Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7e45e22 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Add LongMultiStateCounter"

parents 1054f7e5 fef64cca
Loading
Loading
Loading
Loading
+210 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.os;

import android.os.Parcel;
import android.os.Parcelable;

import com.android.internal.util.Preconditions;

import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;

import libcore.util.NativeAllocationRegistry;

/**
 * Performs per-state counting of long integers over time.  The tracked "value" is expected
 * to increase monotonously. The counter keeps track of the current state.  When the
 * updateValue method is called, the delta from the previous invocation of this method
 * and the new value is added to the counter corresponding to the current state.  If the
 * state changed in the interim, the delta is distributed proptionally.
 *
 * The class's behavior is illustrated by this example:
 * <pre>
 *   // At 0 ms, the state of the tracked object is 0 and the initial tracked value is 100
 *   counter.setState(0, 0);
 *   counter.updateValue(100, 0);
 *
 *   // At 1000 ms, the state changes to 1
 *   counter.setState(1, 1000);
 *
 *   // At 3000 ms, the tracked value is updated to 130
 *   counter.updateValue(130, 3000);
 *
 *   // The delta (130 - 100 = 30) is distributed between states 0 and 1 according to the time
 *   // spent in those respective states; in this specific case, 1000 and 2000 ms.
 *   long countForState0 == counter.getCount(0);  // 10
 *   long countForState1 == counter.getCount(1);  // 20
 * </pre>
 *
 * The tracked values are expected to increase monotonically.
 *
 * @hide
 */
public final class LongMultiStateCounter implements Parcelable {

    private static final NativeAllocationRegistry sRegistry =
            NativeAllocationRegistry.createMalloced(
                    LongMultiStateCounter.class.getClassLoader(), native_getReleaseFunc());

    private final int mStateCount;

    // Visible to other objects in this package so that it can be passed to @CriticalNative
    // methods.
    final long mNativeObject;

    public LongMultiStateCounter(int stateCount) {
        Preconditions.checkArgumentPositive(stateCount, "stateCount must be greater than 0");
        mStateCount = stateCount;
        mNativeObject = native_init(stateCount);
        sRegistry.registerNativeAllocation(this, mNativeObject);
    }

    private LongMultiStateCounter(Parcel in) {
        mNativeObject = native_initFromParcel(in);
        sRegistry.registerNativeAllocation(this, mNativeObject);

        mStateCount = native_getStateCount(mNativeObject);
    }

    public int getStateCount() {
        return mStateCount;
    }

    /**
     * Enables or disables the counter.  When the counter is disabled, it does not
     * accumulate counts supplied by the {@link #updateValue} method.
     */
    public void setEnabled(boolean enabled, long timestampMs) {
        native_setEnabled(mNativeObject, enabled, timestampMs);
    }

    /**
     * Sets the current state to the supplied value.
     *
     * @param state The new state
     * @param timestampMs The time when the state change occurred, e.g.
     *                    SystemClock.elapsedRealtime()
     */
    public void setState(int state, long timestampMs) {
        if (state < 0 || state >= mStateCount) {
            throw new IllegalArgumentException(
                    "State: " + state + ", outside the range: [0-" + (mStateCount - 1) + "]");
        }
        native_setState(mNativeObject, state, timestampMs);
    }

    /**
     * Sets the new values.  The delta between the previously set values and these values
     * is distributed among the state according to the time the object spent in those states
     * since the previous call to updateValues.
     */
    public void updateValue(long value, long timestampMs) {
        native_updateValue(mNativeObject, value, timestampMs);
    }

    /**
     * Adds the supplied values to the current accumulated values in the counter.
     */
    public void addCount(long count) {
        native_addCount(mNativeObject, count);
    }

    /**
     * Resets the accumulated counts to 0.
     */
    public void reset() {
        native_reset(mNativeObject);
    }

    /**
     * Returns the accumulated count for the specified state.
     */
    public long getCount(int state) {
        if (state < 0 || state >= mStateCount) {
            throw new IllegalArgumentException(
                    "State: " + state + ", outside the range: [0-" + mStateCount + "]");
        }
        return native_getCount(mNativeObject, state);
    }

    @Override
    public String toString() {
        return native_toString(mNativeObject);
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        native_writeToParcel(mNativeObject, dest, flags);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<LongMultiStateCounter> CREATOR =
            new Creator<LongMultiStateCounter>() {
                @Override
                public LongMultiStateCounter createFromParcel(Parcel in) {
                    return new LongMultiStateCounter(in);
                }

                @Override
                public LongMultiStateCounter[] newArray(int size) {
                    return new LongMultiStateCounter[size];
                }
            };


    @CriticalNative
    private static native long native_init(int stateCount);

    @CriticalNative
    private static native long native_getReleaseFunc();

    @CriticalNative
    private static native void native_setEnabled(long nativeObject, boolean enabled,
            long timestampMs);

    @CriticalNative
    private static native void native_setState(long nativeObject, int state, long timestampMs);

    @CriticalNative
    private static native void native_updateValue(long nativeObject, long value, long timestampMs);

    @CriticalNative
    private static native void native_addCount(long nativeObject, long count);

    @CriticalNative
    private static native void native_reset(long nativeObject);

    @CriticalNative
    private static native long native_getCount(long nativeObject, int state);

    @FastNative
    private native String native_toString(long nativeObject);

    @FastNative
    private native void native_writeToParcel(long nativeObject, Parcel dest, int flags);

    @FastNative
    private static native long native_initFromParcel(Parcel parcel);

    @CriticalNative
    private static native int native_getStateCount(long nativeObject);
}
+1 −0
Original line number Diff line number Diff line
@@ -218,6 +218,7 @@ cc_library_shared {
                "com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp",
                "com_android_internal_os_KernelSingleUidTimeReader.cpp",
                "com_android_internal_os_LongArrayMultiStateCounter.cpp",
                "com_android_internal_os_LongMultiStateCounter.cpp",
                "com_android_internal_os_Zygote.cpp",
                "com_android_internal_os_ZygoteCommandBuffer.cpp",
                "com_android_internal_os_ZygoteInit.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -205,6 +205,7 @@ extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env
extern int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv* env);
extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env);
extern int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv* env);
extern int register_com_android_internal_os_LongMultiStateCounter(JNIEnv* env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
@@ -1588,6 +1589,7 @@ static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
        REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
        REG_JNI(register_com_android_internal_os_LongArrayMultiStateCounter),
        REG_JNI(register_com_android_internal_os_LongMultiStateCounter),
        REG_JNI(register_com_android_internal_os_Zygote),
        REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),
        REG_JNI(register_com_android_internal_os_ZygoteInit),
+195 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <android/binder_parcel.h>
#include <android/binder_parcel_jni.h>
#include <android/binder_parcel_utils.h>
#include <android_runtime/Log.h>

#include <cstring>

#include "MultiStateCounter.h"
#include "core_jni_helpers.h"

namespace android {

namespace battery {

typedef battery::MultiStateCounter<int64_t> LongMultiStateCounter;

template <>
bool LongMultiStateCounter::delta(const int64_t &previousValue, const int64_t &newValue,
                                  int64_t *outValue) const {
    *outValue = newValue - previousValue;
    return *outValue >= 0;
}

template <>
void LongMultiStateCounter::add(int64_t *value1, const int64_t &value2, const uint64_t numerator,
                                const uint64_t denominator) const {
    if (numerator != denominator) {
        // The caller ensures that denominator != 0
        *value1 += value2 * numerator / denominator;
    } else {
        *value1 += value2;
    }
}

template <>
std::string LongMultiStateCounter::valueToString(const int64_t &v) const {
    return std::to_string(v);
}

} // namespace battery

static inline battery::LongMultiStateCounter *asLongMultiStateCounter(const jlong nativePtr) {
    return reinterpret_cast<battery::LongMultiStateCounter *>(nativePtr);
}

static jlong native_init(jint stateCount) {
    battery::LongMultiStateCounter *counter = new battery::LongMultiStateCounter(stateCount, 0);
    return reinterpret_cast<jlong>(counter);
}

static void native_dispose(void *nativePtr) {
    delete reinterpret_cast<battery::LongMultiStateCounter *>(nativePtr);
}

static jlong native_getReleaseFunc() {
    return reinterpret_cast<jlong>(native_dispose);
}

static void native_setEnabled(jlong nativePtr, jboolean enabled, jlong timestamp) {
    asLongMultiStateCounter(nativePtr)->setEnabled(enabled, timestamp);
}

static void native_setState(jlong nativePtr, jint state, jlong timestamp) {
    asLongMultiStateCounter(nativePtr)->setState(state, timestamp);
}

static void native_updateValue(jlong nativePtr, jlong value, jlong timestamp) {
    asLongMultiStateCounter(nativePtr)->updateValue((int64_t)value, timestamp);
}

static void native_addCount(jlong nativePtr, jlong count) {
    asLongMultiStateCounter(nativePtr)->addValue(count);
}

static void native_reset(jlong nativePtr) {
    asLongMultiStateCounter(nativePtr)->reset();
}

static jlong native_getCount(jlong nativePtr, jint state) {
    return asLongMultiStateCounter(nativePtr)->getCount(state);
}

static jobject native_toString(JNIEnv *env, jobject self, jlong nativePtr) {
    return env->NewStringUTF(asLongMultiStateCounter(nativePtr)->toString().c_str());
}

static void throwWriteRE(JNIEnv *env, binder_status_t status) {
    ALOGE("Could not write LongMultiStateCounter to Parcel, status = %d", status);
    jniThrowRuntimeException(env, "Could not write LongMultiStateCounter to Parcel");
}

#define THROW_ON_WRITE_ERROR(expr)     \
    {                                  \
        binder_status_t status = expr; \
        if (status != STATUS_OK) {     \
            throwWriteRE(env, status); \
        }                              \
    }

static void native_writeToParcel(JNIEnv *env, jobject self, jlong nativePtr, jobject jParcel,
                                 jint flags) {
    battery::LongMultiStateCounter *counter = asLongMultiStateCounter(nativePtr);
    AParcel *parcel = AParcel_fromJavaParcel(env, jParcel);

    uint16_t stateCount = counter->getStateCount();
    THROW_ON_WRITE_ERROR(AParcel_writeInt32(parcel, stateCount));

    for (battery::state_t state = 0; state < stateCount; state++) {
        THROW_ON_WRITE_ERROR(AParcel_writeInt64(parcel, counter->getCount(state)));
    }
}

static void throwReadRE(JNIEnv *env, binder_status_t status) {
    ALOGE("Could not read LongMultiStateCounter from Parcel, status = %d", status);
    jniThrowRuntimeException(env, "Could not read LongMultiStateCounter from Parcel");
}

#define THROW_ON_READ_ERROR(expr)      \
    {                                  \
        binder_status_t status = expr; \
        if (status != STATUS_OK) {     \
            throwReadRE(env, status);  \
        }                              \
    }

static jlong native_initFromParcel(JNIEnv *env, jclass theClass, jobject jParcel) {
    AParcel *parcel = AParcel_fromJavaParcel(env, jParcel);

    int32_t stateCount;
    THROW_ON_READ_ERROR(AParcel_readInt32(parcel, &stateCount));

    battery::LongMultiStateCounter *counter = new battery::LongMultiStateCounter(stateCount, 0);

    for (battery::state_t state = 0; state < stateCount; state++) {
        int64_t value;
        THROW_ON_READ_ERROR(AParcel_readInt64(parcel, &value));
        counter->setValue(state, value);
    }

    return reinterpret_cast<jlong>(counter);
}

static jint native_getStateCount(jlong nativePtr) {
    return asLongMultiStateCounter(nativePtr)->getStateCount();
}

static const JNINativeMethod g_methods[] = {
        // @CriticalNative
        {"native_init", "(I)J", (void *)native_init},
        // @CriticalNative
        {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc},
        // @CriticalNative
        {"native_setEnabled", "(JZJ)V", (void *)native_setEnabled},
        // @CriticalNative
        {"native_setState", "(JIJ)V", (void *)native_setState},
        // @CriticalNative
        {"native_updateValue", "(JJJ)V", (void *)native_updateValue},
        // @CriticalNative
        {"native_addCount", "(JJ)V", (void *)native_addCount},
        // @CriticalNative
        {"native_reset", "(J)V", (void *)native_reset},
        // @CriticalNative
        {"native_getCount", "(JI)J", (void *)native_getCount},
        // @FastNative
        {"native_toString", "(J)Ljava/lang/String;", (void *)native_toString},
        // @FastNative
        {"native_writeToParcel", "(JLandroid/os/Parcel;I)V", (void *)native_writeToParcel},
        // @FastNative
        {"native_initFromParcel", "(Landroid/os/Parcel;)J", (void *)native_initFromParcel},
        // @CriticalNative
        {"native_getStateCount", "(J)I", (void *)native_getStateCount},
};

int register_com_android_internal_os_LongMultiStateCounter(JNIEnv *env) {
    return RegisterMethodsOrDie(env, "com/android/internal/os/LongMultiStateCounter", g_methods,
                                NELEM(g_methods));
}

} // namespace android
+2 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ import org.junit.runners.Suite;
        KernelSingleProcessCpuThreadReaderTest.class,
        KernelSingleUidTimeReaderTest.class,
        KernelWakelockReaderTest.class,
        LongArrayMultiStateCounterTest.class,
        LongMultiStateCounterTest.class,
        LongSamplingCounterTest.class,
        LongSamplingCounterArrayTest.class,
        MobileRadioPowerCalculatorTest.class,
Loading