xref: /aosp_15_r20/frameworks/base/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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 #include <android/binder_parcel.h>
18 #include <android/binder_parcel_jni.h>
19 #include <android/binder_parcel_utils.h>
20 #include <android_runtime/Log.h>
21 #include <nativehelper/ScopedPrimitiveArray.h>
22 
23 #include <cstring>
24 
25 #include "LongArrayMultiStateCounter.h"
26 #include "core_jni_helpers.h"
27 
28 namespace android {
29 namespace battery {
30 
31 /**
32  * Implementation of Uint64Array that wraps a Java long[]. Since it uses the "critical"
33  * version of JNI array access (halting GC), any usage of this class must be extra quick.
34  */
35 class JavaUint64Array : public Uint64Array {
36     JNIEnv *mEnv;
37     jlongArray mJavaArray;
38     uint64_t *mData;
39 
40 public:
JavaUint64Array(JNIEnv * env,jlongArray values)41     JavaUint64Array(JNIEnv *env, jlongArray values) : Uint64Array(env->GetArrayLength(values)) {
42         mEnv = env;
43         mJavaArray = values;
44         mData = reinterpret_cast<uint64_t *>(mEnv->GetPrimitiveArrayCritical(mJavaArray, nullptr));
45     }
46 
~JavaUint64Array()47     ~JavaUint64Array() override {
48         mEnv->ReleasePrimitiveArrayCritical(mJavaArray, mData, 0);
49     }
50 
data() const51     const uint64_t *data() const override {
52         return mData;
53     }
54 };
55 
native_init(jint stateCount,jint arrayLength)56 static jlong native_init(jint stateCount, jint arrayLength) {
57     auto *counter = new LongArrayMultiStateCounter(stateCount, Uint64Array(arrayLength));
58     return reinterpret_cast<jlong>(counter);
59 }
60 
native_dispose(void * nativePtr)61 static void native_dispose(void *nativePtr) {
62     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
63     delete counter;
64 }
65 
native_getReleaseFunc()66 static jlong native_getReleaseFunc() {
67     return reinterpret_cast<jlong>(native_dispose);
68 }
69 
native_setEnabled(jlong nativePtr,jboolean enabled,jlong timestamp)70 static void native_setEnabled(jlong nativePtr, jboolean enabled, jlong timestamp) {
71     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
72     counter->setEnabled(enabled, timestamp);
73 }
74 
native_setState(jlong nativePtr,jint state,jlong timestamp)75 static void native_setState(jlong nativePtr, jint state, jlong timestamp) {
76     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
77     counter->setState(state, timestamp);
78 }
79 
native_copyStatesFrom(jlong nativePtrTarget,jlong nativePtrSource)80 static void native_copyStatesFrom(jlong nativePtrTarget, jlong nativePtrSource) {
81     auto *counterTarget = reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtrTarget);
82     auto *counterSource = reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtrSource);
83     counterTarget->copyStatesFrom(*counterSource);
84 }
85 
native_setValues(JNIEnv * env,jclass,jlong nativePtr,jint state,jlongArray values)86 static void native_setValues(JNIEnv *env, jclass, jlong nativePtr, jint state, jlongArray values) {
87     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
88     counter->setValue(state, JavaUint64Array(env, values));
89 }
90 
native_updateValues(JNIEnv * env,jclass,jlong nativePtr,jlongArray values,jlong timestamp)91 static void native_updateValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray values,
92                                 jlong timestamp) {
93     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
94     counter->updateValue(JavaUint64Array(env, values), timestamp);
95 }
96 
native_incrementValues(JNIEnv * env,jclass,jlong nativePtr,jlongArray values,jlong timestamp)97 static void native_incrementValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray values,
98                                    jlong timestamp) {
99     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
100     counter->incrementValue(JavaUint64Array(env, values), timestamp);
101 }
102 
native_addCounts(JNIEnv * env,jclass,jlong nativePtr,jlongArray values)103 static void native_addCounts(JNIEnv *env, jclass, jlong nativePtr, jlongArray values) {
104     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
105     counter->addValue(JavaUint64Array(env, values));
106 }
107 
native_reset(jlong nativePtr)108 static void native_reset(jlong nativePtr) {
109     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
110     counter->reset();
111 }
112 
native_getCounts(JNIEnv * env,jclass,jlong nativePtr,jlongArray values,jint state)113 static void native_getCounts(JNIEnv *env, jclass, jlong nativePtr, jlongArray values, jint state) {
114     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
115     ScopedLongArrayRW scopedArray(env, values);
116     auto *data = counter->getCount(state).data();
117     auto size = env->GetArrayLength(values);
118     auto *outData = scopedArray.get();
119     if (data == nullptr) {
120         memset(outData, 0, size * sizeof(uint64_t));
121     } else {
122         memcpy(outData, data, size * sizeof(uint64_t));
123     }
124 }
125 
native_toString(JNIEnv * env,jclass,jlong nativePtr)126 static jobject native_toString(JNIEnv *env, jclass, jlong nativePtr) {
127     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
128     return env->NewStringUTF(counter->toString().c_str());
129 }
130 
throwWriteRE(JNIEnv * env,binder_status_t status)131 static void throwWriteRE(JNIEnv *env, binder_status_t status) {
132     ALOGE("Could not write LongArrayMultiStateCounter to Parcel, status = %d", status);
133     jniThrowRuntimeException(env, "Could not write LongArrayMultiStateCounter to Parcel");
134 }
135 
136 #define THROW_AND_RETURN_ON_WRITE_ERROR(expr) \
137     {                                         \
138         binder_status_t status = expr;        \
139         if (status != STATUS_OK) {            \
140             throwWriteRE(env, status);        \
141             return;                           \
142         }                                     \
143     }
144 
native_writeToParcel(JNIEnv * env,jclass,jlong nativePtr,jobject jParcel,jint flags)145 static void native_writeToParcel(JNIEnv *env, jclass, jlong nativePtr, jobject jParcel,
146                                  jint flags) {
147     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
148     ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel));
149 
150     uint16_t stateCount = counter->getStateCount();
151     THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), stateCount));
152 
153     // LongArrayMultiStateCounter has at least state 0
154     const Uint64Array &anyState = counter->getCount(0);
155     THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), anyState.size()));
156 
157     for (battery::state_t state = 0; state < stateCount; state++) {
158         const Uint64Array &value = counter->getCount(state);
159         if (value.data() == nullptr) {
160             THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeBool(parcel.get(), false));
161         } else {
162             THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeBool(parcel.get(), true));
163             for (size_t i = 0; i < anyState.size(); i++) {
164                 THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeUint64(parcel.get(), value.data()[i]));
165             }
166         }
167     }
168 }
169 
throwReadException(JNIEnv * env,binder_status_t status)170 static void throwReadException(JNIEnv *env, binder_status_t status) {
171     ALOGE("Could not read LongArrayMultiStateCounter from Parcel, status = %d", status);
172     jniThrowException(env, "android.os.BadParcelableException",
173                       "Could not read LongArrayMultiStateCounter from Parcel");
174 }
175 
176 #define THROW_AND_RETURN_ON_READ_ERROR(expr) \
177     {                                        \
178         binder_status_t status = expr;       \
179         if (status != STATUS_OK) {           \
180             throwReadException(env, status); \
181             return 0L;                       \
182         }                                    \
183     }
184 
native_initFromParcel(JNIEnv * env,jclass,jobject jParcel)185 static jlong native_initFromParcel(JNIEnv *env, jclass, jobject jParcel) {
186     ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel));
187 
188     int32_t stateCount;
189     THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &stateCount));
190 
191     if (stateCount < 0 || stateCount > 0xEFFF) {
192         throwReadException(env, STATUS_INVALID_OPERATION);
193         return 0L;
194     }
195 
196     int32_t arrayLength;
197     THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &arrayLength));
198 
199     auto counter =
200             std::make_unique<LongArrayMultiStateCounter>(stateCount, Uint64Array(arrayLength));
201     Uint64ArrayRW array(arrayLength);
202     for (battery::state_t state = 0; state < stateCount; state++) {
203         bool hasValues;
204         THROW_AND_RETURN_ON_READ_ERROR(AParcel_readBool(parcel.get(), &hasValues));
205         if (hasValues) {
206             for (int i = 0; i < arrayLength; i++) {
207                 THROW_AND_RETURN_ON_READ_ERROR(
208                         AParcel_readUint64(parcel.get(), &(array.dataRW()[i])));
209             }
210             counter->setValue(state, array);
211         }
212     }
213 
214     return reinterpret_cast<jlong>(counter.release());
215 }
216 
native_getStateCount(jlong nativePtr)217 static jint native_getStateCount(jlong nativePtr) {
218     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
219     return counter->getStateCount();
220 }
221 
native_getArrayLength(jlong nativePtr)222 static jint native_getArrayLength(jlong nativePtr) {
223     auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
224 
225     // LongArrayMultiStateCounter has at least state 0
226     const Uint64Array &anyState = counter->getCount(0);
227     return anyState.size();
228 }
229 
230 static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
231         // @CriticalNative
232         {"native_init", "(II)J", (void *)native_init},
233         // @CriticalNative
234         {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc},
235         // @CriticalNative
236         {"native_setEnabled", "(JZJ)V", (void *)native_setEnabled},
237         // @CriticalNative
238         {"native_setState", "(JIJ)V", (void *)native_setState},
239         // @CriticalNative
240         {"native_copyStatesFrom", "(JJ)V", (void *)native_copyStatesFrom},
241         // @FastNative
242         {"native_setValues", "(JI[J)V", (void *)native_setValues},
243         // @FastNative
244         {"native_updateValues", "(J[JJ)V", (void *)native_updateValues},
245         // @FastNative
246         {"native_incrementValues", "(J[JJ)V", (void *)native_incrementValues},
247         // @FastNative
248         {"native_addCounts", "(J[J)V", (void *)native_addCounts},
249         // @CriticalNative
250         {"native_reset", "(J)V", (void *)native_reset},
251         // @FastNative
252         {"native_getCounts", "(J[JI)V", (void *)native_getCounts},
253         // @FastNative
254         {"native_toString", "(J)Ljava/lang/String;", (void *)native_toString},
255         // @FastNative
256         {"native_writeToParcel", "(JLandroid/os/Parcel;I)V", (void *)native_writeToParcel},
257         // @FastNative
258         {"native_initFromParcel", "(Landroid/os/Parcel;)J", (void *)native_initFromParcel},
259         // @CriticalNative
260         {"native_getStateCount", "(J)I", (void *)native_getStateCount},
261         // @CriticalNative
262         {"native_getArrayLength", "(J)I", (void *)native_getArrayLength},
263 };
264 
265 } // namespace battery
266 
register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv * env)267 int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {
268     // 0 represents success, thus "|" and not "&"
269     return RegisterMethodsOrDie(env, "com/android/internal/os/LongArrayMultiStateCounter",
270                                 battery::g_LongArrayMultiStateCounter_methods,
271                                 NELEM(battery::g_LongArrayMultiStateCounter_methods));
272 }
273 } // namespace android
274