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
native_init(jint stateCount,jint arrayLength)30 static jlong native_init(jint stateCount, jint arrayLength) {
31 battery::LongArrayMultiStateCounter *counter =
32 new battery::LongArrayMultiStateCounter(stateCount, std::vector<uint64_t>(arrayLength));
33 return reinterpret_cast<jlong>(counter);
34 }
35
native_dispose(void * nativePtr)36 static void native_dispose(void *nativePtr) {
37 battery::LongArrayMultiStateCounter *counter =
38 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
39 delete counter;
40 }
41
native_getReleaseFunc()42 static jlong native_getReleaseFunc() {
43 return reinterpret_cast<jlong>(native_dispose);
44 }
45
native_setEnabled(jlong nativePtr,jboolean enabled,jlong timestamp)46 static void native_setEnabled(jlong nativePtr, jboolean enabled, jlong timestamp) {
47 battery::LongArrayMultiStateCounter *counter =
48 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
49 counter->setEnabled(enabled, timestamp);
50 }
51
native_setState(jlong nativePtr,jint state,jlong timestamp)52 static void native_setState(jlong nativePtr, jint state, jlong timestamp) {
53 battery::LongArrayMultiStateCounter *counter =
54 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
55 counter->setState(state, timestamp);
56 }
57
native_updateValues(jlong nativePtr,jlong longArrayContainerNativePtr,jlong timestamp)58 static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativePtr,
59 jlong timestamp) {
60 battery::LongArrayMultiStateCounter *counter =
61 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
62 std::vector<uint64_t> *vector =
63 reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
64
65 counter->updateValue(*vector, timestamp);
66 }
67
native_addCounts(jlong nativePtr,jlong longArrayContainerNativePtr)68 static void native_addCounts(jlong nativePtr, jlong longArrayContainerNativePtr) {
69 battery::LongArrayMultiStateCounter *counter =
70 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
71 std::vector<uint64_t> *vector =
72 reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
73 counter->addValue(*vector);
74 }
75
native_reset(jlong nativePtr)76 static void native_reset(jlong nativePtr) {
77 battery::LongArrayMultiStateCounter *counter =
78 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
79 counter->reset();
80 }
81
native_getCounts(jlong nativePtr,jlong longArrayContainerNativePtr,jint state)82 static void native_getCounts(jlong nativePtr, jlong longArrayContainerNativePtr, jint state) {
83 battery::LongArrayMultiStateCounter *counter =
84 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
85 std::vector<uint64_t> *vector =
86 reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
87
88 *vector = counter->getCount(state);
89 }
90
native_toString(JNIEnv * env,jobject self,jlong nativePtr)91 static jobject native_toString(JNIEnv *env, jobject self, jlong nativePtr) {
92 battery::LongArrayMultiStateCounter *counter =
93 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
94 return env->NewStringUTF(counter->toString().c_str());
95 }
96
throwWriteRE(JNIEnv * env,binder_status_t status)97 static void throwWriteRE(JNIEnv *env, binder_status_t status) {
98 ALOGE("Could not write LongArrayMultiStateCounter to Parcel, status = %d", status);
99 jniThrowRuntimeException(env, "Could not write LongArrayMultiStateCounter to Parcel");
100 }
101
102 #define THROW_AND_RETURN_ON_WRITE_ERROR(expr) \
103 { \
104 binder_status_t status = expr; \
105 if (status != STATUS_OK) { \
106 throwWriteRE(env, status); \
107 return; \
108 } \
109 }
110
native_writeToParcel(JNIEnv * env,jobject self,jlong nativePtr,jobject jParcel,jint flags)111 static void native_writeToParcel(JNIEnv *env, jobject self, jlong nativePtr, jobject jParcel,
112 jint flags) {
113 battery::LongArrayMultiStateCounter *counter =
114 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
115 ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel));
116
117 uint16_t stateCount = counter->getStateCount();
118 THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), stateCount));
119
120 // LongArrayMultiStateCounter has at least state 0
121 const std::vector<uint64_t> &anyState = counter->getCount(0);
122 THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), anyState.size()));
123
124 for (battery::state_t state = 0; state < stateCount; state++) {
125 THROW_AND_RETURN_ON_WRITE_ERROR(
126 ndk::AParcel_writeVector(parcel.get(), counter->getCount(state)));
127 }
128 }
129
throwReadException(JNIEnv * env,binder_status_t status)130 static void throwReadException(JNIEnv *env, binder_status_t status) {
131 ALOGE("Could not read LongArrayMultiStateCounter from Parcel, status = %d", status);
132 jniThrowException(env, "android.os.BadParcelableException",
133 "Could not read LongArrayMultiStateCounter from Parcel");
134 }
135
136 #define THROW_AND_RETURN_ON_READ_ERROR(expr) \
137 { \
138 binder_status_t status = expr; \
139 if (status != STATUS_OK) { \
140 throwReadException(env, status); \
141 return 0L; \
142 } \
143 }
144
native_initFromParcel(JNIEnv * env,jclass theClass,jobject jParcel)145 static jlong native_initFromParcel(JNIEnv *env, jclass theClass, jobject jParcel) {
146 ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel));
147
148 int32_t stateCount;
149 THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &stateCount));
150
151 if (stateCount < 0 || stateCount > 0xEFFF) {
152 throwReadException(env, STATUS_INVALID_OPERATION);
153 return 0L;
154 }
155
156 int32_t arrayLength;
157 THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &arrayLength));
158
159 auto counter = std::make_unique<battery::LongArrayMultiStateCounter>(stateCount,
160 std::vector<uint64_t>(
161 arrayLength));
162
163 std::vector<uint64_t> value;
164 value.reserve(arrayLength);
165
166 for (battery::state_t state = 0; state < stateCount; state++) {
167 THROW_AND_RETURN_ON_READ_ERROR(ndk::AParcel_readVector(parcel.get(), &value));
168 counter->setValue(state, value);
169 }
170
171 return reinterpret_cast<jlong>(counter.release());
172 }
173
native_getStateCount(jlong nativePtr)174 static jint native_getStateCount(jlong nativePtr) {
175 battery::LongArrayMultiStateCounter *counter =
176 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
177 return counter->getStateCount();
178 }
179
native_getArrayLength(jlong nativePtr)180 static jint native_getArrayLength(jlong nativePtr) {
181 battery::LongArrayMultiStateCounter *counter =
182 reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
183
184 // LongArrayMultiStateCounter has at least state 0
185 const std::vector<uint64_t> &anyState = counter->getCount(0);
186 return anyState.size();
187 }
188
native_init_LongArrayContainer(jint length)189 static jlong native_init_LongArrayContainer(jint length) {
190 return reinterpret_cast<jlong>(new std::vector<uint64_t>(length));
191 }
192
193 static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
194 // @CriticalNative
195 {"native_init", "(II)J", (void *)native_init},
196 // @CriticalNative
197 {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc},
198 // @CriticalNative
199 {"native_setEnabled", "(JZJ)V", (void *)native_setEnabled},
200 // @CriticalNative
201 {"native_setState", "(JIJ)V", (void *)native_setState},
202 // @CriticalNative
203 {"native_updateValues", "(JJJ)V", (void *)native_updateValues},
204 // @CriticalNative
205 {"native_addCounts", "(JJ)V", (void *)native_addCounts},
206 // @CriticalNative
207 {"native_reset", "(J)V", (void *)native_reset},
208 // @CriticalNative
209 {"native_getCounts", "(JJI)V", (void *)native_getCounts},
210 // @FastNative
211 {"native_toString", "(J)Ljava/lang/String;", (void *)native_toString},
212 // @FastNative
213 {"native_writeToParcel", "(JLandroid/os/Parcel;I)V", (void *)native_writeToParcel},
214 // @FastNative
215 {"native_initFromParcel", "(Landroid/os/Parcel;)J", (void *)native_initFromParcel},
216 // @CriticalNative
217 {"native_getStateCount", "(J)I", (void *)native_getStateCount},
218 // @CriticalNative
219 {"native_getArrayLength", "(J)I", (void *)native_getArrayLength},
220 };
221
222 /////////////////////// LongArrayMultiStateCounter.LongArrayContainer ////////////////////////
223
native_dispose_LongArrayContainer(jlong nativePtr)224 static void native_dispose_LongArrayContainer(jlong nativePtr) {
225 std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
226 delete vector;
227 }
228
native_getReleaseFunc_LongArrayContainer()229 static jlong native_getReleaseFunc_LongArrayContainer() {
230 return reinterpret_cast<jlong>(native_dispose_LongArrayContainer);
231 }
232
native_setValues_LongArrayContainer(JNIEnv * env,jobject self,jlong nativePtr,jlongArray jarray)233 static void native_setValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
234 jlongArray jarray) {
235 std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
236 ScopedLongArrayRO scopedArray(env, jarray);
237 const uint64_t *array = reinterpret_cast<const uint64_t *>(scopedArray.get());
238 uint8_t size = scopedArray.size();
239
240 // Boundary checks are performed in the Java layer
241 std::copy(array, array + size, vector->data());
242 }
243
native_getValues_LongArrayContainer(JNIEnv * env,jobject self,jlong nativePtr,jlongArray jarray)244 static void native_getValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
245 jlongArray jarray) {
246 std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
247 ScopedLongArrayRW scopedArray(env, jarray);
248
249 // Boundary checks are performed in the Java layer
250 std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get());
251 }
252
native_combineValues_LongArrayContainer(JNIEnv * env,jobject self,jlong nativePtr,jlongArray jarray,jintArray jindexMap)253 static jboolean native_combineValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
254 jlongArray jarray, jintArray jindexMap) {
255 std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
256 ScopedLongArrayRW scopedArray(env, jarray);
257 ScopedIntArrayRO scopedIndexMap(env, jindexMap);
258
259 const uint64_t *data = vector->data();
260 uint64_t *array = reinterpret_cast<uint64_t *>(scopedArray.get());
261 const uint8_t size = scopedArray.size();
262
263 for (int i = 0; i < size; i++) {
264 array[i] = 0;
265 }
266
267 bool nonZero = false;
268 for (int i = 0; i < vector->size(); i++) {
269 jint index = scopedIndexMap[i];
270 if (index < 0 || index >= size) {
271 jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException",
272 "Index %d is out of bounds: [0, %d]", index, size - 1);
273 return false;
274 }
275
276 if (data[i] != 0L) {
277 array[index] += data[i];
278 nonZero = true;
279 }
280 }
281
282 return nonZero;
283 }
284
285 static const JNINativeMethod g_LongArrayContainer_methods[] = {
286 // @CriticalNative
287 {"native_init", "(I)J", (void *)native_init_LongArrayContainer},
288 // @CriticalNative
289 {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc_LongArrayContainer},
290 // @FastNative
291 {"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer},
292 // @FastNative
293 {"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer},
294 // @FastNative
295 {"native_combineValues", "(J[J[I)Z", (void *)native_combineValues_LongArrayContainer},
296 };
297
register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv * env)298 int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {
299 // 0 represents success, thus "|" and not "&"
300 return RegisterMethodsOrDie(env, "com/android/internal/os/LongArrayMultiStateCounter",
301 g_LongArrayMultiStateCounter_methods,
302 NELEM(g_LongArrayMultiStateCounter_methods)) |
303 RegisterMethodsOrDie(env,
304 "com/android/internal/os/LongArrayMultiStateCounter"
305 "$LongArrayContainer",
306 g_LongArrayContainer_methods, NELEM(g_LongArrayContainer_methods));
307 }
308
309 } // namespace android
310