blob: 76b05eac82af30cf035b2dd7ca7ce3bb5a923dd3 [file] [log] [blame]
/*
* 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 <nativehelper/ScopedPrimitiveArray.h>
#include <cstring>
#include "LongArrayMultiStateCounter.h"
#include "core_jni_helpers.h"
namespace android {
static jlong native_init(jint stateCount, jint arrayLength) {
battery::LongArrayMultiStateCounter *counter =
new battery::LongArrayMultiStateCounter(stateCount, std::vector<uint64_t>(arrayLength));
return reinterpret_cast<jlong>(counter);
}
static void native_dispose(void *nativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
delete counter;
}
static jlong native_getReleaseFunc() {
return reinterpret_cast<jlong>(native_dispose);
}
static void native_setEnabled(jlong nativePtr, jboolean enabled, jlong timestamp) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
counter->setEnabled(enabled, timestamp);
}
static void native_setState(jlong nativePtr, jint state, jlong timestamp) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
counter->setState(state, timestamp);
}
static void native_setValues(jlong nativePtr, jint state, jlong longArrayContainerNativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
std::vector<uint64_t> *vector =
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
counter->setValue(state, *vector);
}
static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativePtr,
jlong timestamp) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
std::vector<uint64_t> *vector =
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
counter->updateValue(*vector, timestamp);
}
static void native_incrementValues(jlong nativePtr, jlong longArrayContainerNativePtr,
jlong timestamp) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
std::vector<uint64_t> *vector =
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
counter->incrementValue(*vector, timestamp);
}
static void native_addCounts(jlong nativePtr, jlong longArrayContainerNativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
std::vector<uint64_t> *vector =
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
counter->addValue(*vector);
}
static void native_reset(jlong nativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
counter->reset();
}
static void native_getCounts(jlong nativePtr, jlong longArrayContainerNativePtr, jint state) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
std::vector<uint64_t> *vector =
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
*vector = counter->getCount(state);
}
static jobject native_toString(JNIEnv *env, jclass, jlong nativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
return env->NewStringUTF(counter->toString().c_str());
}
static void throwWriteRE(JNIEnv *env, binder_status_t status) {
ALOGE("Could not write LongArrayMultiStateCounter to Parcel, status = %d", status);
jniThrowRuntimeException(env, "Could not write LongArrayMultiStateCounter to Parcel");
}
#define THROW_AND_RETURN_ON_WRITE_ERROR(expr) \
{ \
binder_status_t status = expr; \
if (status != STATUS_OK) { \
throwWriteRE(env, status); \
return; \
} \
}
static void native_writeToParcel(JNIEnv *env, jclass, jlong nativePtr, jobject jParcel,
jint flags) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel));
uint16_t stateCount = counter->getStateCount();
THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), stateCount));
// LongArrayMultiStateCounter has at least state 0
const std::vector<uint64_t> &anyState = counter->getCount(0);
THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), anyState.size()));
for (battery::state_t state = 0; state < stateCount; state++) {
THROW_AND_RETURN_ON_WRITE_ERROR(
ndk::AParcel_writeVector(parcel.get(), counter->getCount(state)));
}
}
static void throwReadException(JNIEnv *env, binder_status_t status) {
ALOGE("Could not read LongArrayMultiStateCounter from Parcel, status = %d", status);
jniThrowException(env, "android.os.BadParcelableException",
"Could not read LongArrayMultiStateCounter from Parcel");
}
#define THROW_AND_RETURN_ON_READ_ERROR(expr) \
{ \
binder_status_t status = expr; \
if (status != STATUS_OK) { \
throwReadException(env, status); \
return 0L; \
} \
}
static jlong native_initFromParcel(JNIEnv *env, jclass, jobject jParcel) {
ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel));
int32_t stateCount;
THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &stateCount));
if (stateCount < 0 || stateCount > 0xEFFF) {
throwReadException(env, STATUS_INVALID_OPERATION);
return 0L;
}
int32_t arrayLength;
THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &arrayLength));
auto counter = std::make_unique<battery::LongArrayMultiStateCounter>(stateCount,
std::vector<uint64_t>(
arrayLength));
std::vector<uint64_t> value;
value.reserve(arrayLength);
for (battery::state_t state = 0; state < stateCount; state++) {
THROW_AND_RETURN_ON_READ_ERROR(ndk::AParcel_readVector(parcel.get(), &value));
counter->setValue(state, value);
}
return reinterpret_cast<jlong>(counter.release());
}
static jint native_getStateCount(jlong nativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
return counter->getStateCount();
}
static jint native_getArrayLength(jlong nativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
// LongArrayMultiStateCounter has at least state 0
const std::vector<uint64_t> &anyState = counter->getCount(0);
return anyState.size();
}
static jlong native_init_LongArrayContainer(jint length) {
return reinterpret_cast<jlong>(new std::vector<uint64_t>(length));
}
static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
// @CriticalNative
{"native_init", "(II)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_setValues", "(JIJ)V", (void *)native_setValues},
// @CriticalNative
{"native_updateValues", "(JJJ)V", (void *)native_updateValues},
// @CriticalNative
{"native_incrementValues", "(JJJ)V", (void *)native_incrementValues},
// @CriticalNative
{"native_addCounts", "(JJ)V", (void *)native_addCounts},
// @CriticalNative
{"native_reset", "(J)V", (void *)native_reset},
// @CriticalNative
{"native_getCounts", "(JJI)V", (void *)native_getCounts},
// @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},
// @CriticalNative
{"native_getArrayLength", "(J)I", (void *)native_getArrayLength},
};
/////////////////////// LongArrayMultiStateCounter.LongArrayContainer ////////////////////////
static void native_dispose_LongArrayContainer(jlong nativePtr) {
std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
delete vector;
}
static jlong native_getReleaseFunc_LongArrayContainer() {
return reinterpret_cast<jlong>(native_dispose_LongArrayContainer);
}
static void native_setValues_LongArrayContainer(JNIEnv *env, jclass, jlong nativePtr,
jlongArray jarray) {
std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
ScopedLongArrayRO scopedArray(env, jarray);
const uint64_t *array = reinterpret_cast<const uint64_t *>(scopedArray.get());
uint8_t size = scopedArray.size();
// Boundary checks are performed in the Java layer
std::copy(array, array + size, vector->data());
}
static void native_getValues_LongArrayContainer(JNIEnv *env, jclass, jlong nativePtr,
jlongArray jarray) {
std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
ScopedLongArrayRW scopedArray(env, jarray);
// Boundary checks are performed in the Java layer
std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get());
}
static jboolean native_combineValues_LongArrayContainer(JNIEnv *env, jclass, jlong nativePtr,
jlongArray jarray, jintArray jindexMap) {
std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
ScopedLongArrayRW scopedArray(env, jarray);
ScopedIntArrayRO scopedIndexMap(env, jindexMap);
const uint64_t *data = vector->data();
uint64_t *array = reinterpret_cast<uint64_t *>(scopedArray.get());
const uint8_t size = scopedArray.size();
for (int i = 0; i < size; i++) {
array[i] = 0;
}
bool nonZero = false;
for (size_t i = 0; i < vector->size(); i++) {
jint index = scopedIndexMap[i];
if (index < 0 || index >= size) {
jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException",
"Index %d is out of bounds: [0, %d]", index, size - 1);
return false;
}
if (data[i] != 0L) {
array[index] += data[i];
nonZero = true;
}
}
return nonZero;
}
static const JNINativeMethod g_LongArrayContainer_methods[] = {
// @CriticalNative
{"native_init", "(I)J", (void *)native_init_LongArrayContainer},
// @CriticalNative
{"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc_LongArrayContainer},
// @FastNative
{"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer},
// @FastNative
{"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer},
// @FastNative
{"native_combineValues", "(J[J[I)Z", (void *)native_combineValues_LongArrayContainer},
};
int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {
// 0 represents success, thus "|" and not "&"
return RegisterMethodsOrDie(env, "com/android/internal/os/LongArrayMultiStateCounter",
g_LongArrayMultiStateCounter_methods,
NELEM(g_LongArrayMultiStateCounter_methods)) |
RegisterMethodsOrDie(env,
"com/android/internal/os/LongArrayMultiStateCounter"
"$LongArrayContainer",
g_LongArrayContainer_methods, NELEM(g_LongArrayContainer_methods));
}
} // namespace android