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