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