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 
22 #include <cstring>
23 
24 #include "MultiStateCounter.h"
25 #include "core_jni_helpers.h"
26 
27 namespace android {
28 
29 namespace battery {
30 
31 typedef battery::MultiStateCounter<int64_t> LongMultiStateCounter;
32 
33 template <>
delta(const int64_t & previousValue,const int64_t & newValue,int64_t * outValue) const34 bool LongMultiStateCounter::delta(const int64_t &previousValue, const int64_t &newValue,
35                                   int64_t *outValue) const {
36     *outValue = newValue - previousValue;
37     return *outValue >= 0;
38 }
39 
40 template <>
add(int64_t * value1,const int64_t & value2,const uint64_t numerator,const uint64_t denominator) const41 void LongMultiStateCounter::add(int64_t *value1, const int64_t &value2, const uint64_t numerator,
42                                 const uint64_t denominator) const {
43     if (numerator != denominator) {
44         // The caller ensures that denominator != 0
45         *value1 += value2 * numerator / denominator;
46     } else {
47         *value1 += value2;
48     }
49 }
50 
51 template <>
valueToString(const int64_t & v) const52 std::string LongMultiStateCounter::valueToString(const int64_t &v) const {
53     return std::to_string(v);
54 }
55 
56 } // namespace battery
57 
asLongMultiStateCounter(const jlong nativePtr)58 static inline battery::LongMultiStateCounter *asLongMultiStateCounter(const jlong nativePtr) {
59     return reinterpret_cast<battery::LongMultiStateCounter *>(nativePtr);
60 }
61 
native_init(jint stateCount)62 static jlong native_init(jint stateCount) {
63     battery::LongMultiStateCounter *counter = new battery::LongMultiStateCounter(stateCount, 0);
64     return reinterpret_cast<jlong>(counter);
65 }
66 
native_dispose(void * nativePtr)67 static void native_dispose(void *nativePtr) {
68     delete reinterpret_cast<battery::LongMultiStateCounter *>(nativePtr);
69 }
70 
native_getReleaseFunc()71 static jlong native_getReleaseFunc() {
72     return reinterpret_cast<jlong>(native_dispose);
73 }
74 
native_setEnabled(jlong nativePtr,jboolean enabled,jlong timestamp)75 static void native_setEnabled(jlong nativePtr, jboolean enabled, jlong timestamp) {
76     asLongMultiStateCounter(nativePtr)->setEnabled(enabled, timestamp);
77 }
78 
native_setState(jlong nativePtr,jint state,jlong timestamp)79 static void native_setState(jlong nativePtr, jint state, jlong timestamp) {
80     asLongMultiStateCounter(nativePtr)->setState(state, timestamp);
81 }
82 
native_updateValue(jlong nativePtr,jlong value,jlong timestamp)83 static jlong native_updateValue(jlong nativePtr, jlong value, jlong timestamp) {
84     return (jlong)asLongMultiStateCounter(nativePtr)->updateValue((int64_t)value, timestamp);
85 }
86 
native_incrementValue(jlong nativePtr,jlong count,jlong timestamp)87 static void native_incrementValue(jlong nativePtr, jlong count, jlong timestamp) {
88     asLongMultiStateCounter(nativePtr)->incrementValue(count, timestamp);
89 }
90 
native_addCount(jlong nativePtr,jlong count)91 static void native_addCount(jlong nativePtr, jlong count) {
92     asLongMultiStateCounter(nativePtr)->addValue(count);
93 }
94 
native_reset(jlong nativePtr)95 static void native_reset(jlong nativePtr) {
96     asLongMultiStateCounter(nativePtr)->reset();
97 }
98 
native_getCount(jlong nativePtr,jint state)99 static jlong native_getCount(jlong nativePtr, jint state) {
100     return asLongMultiStateCounter(nativePtr)->getCount(state);
101 }
102 
native_toString(JNIEnv * env,jobject self,jlong nativePtr)103 static jobject native_toString(JNIEnv *env, jobject self, jlong nativePtr) {
104     return env->NewStringUTF(asLongMultiStateCounter(nativePtr)->toString().c_str());
105 }
106 
throwWriteRE(JNIEnv * env,binder_status_t status)107 static void throwWriteRE(JNIEnv *env, binder_status_t status) {
108     ALOGE("Could not write LongMultiStateCounter to Parcel, status = %d", status);
109     jniThrowRuntimeException(env, "Could not write LongMultiStateCounter to Parcel");
110 }
111 
112 #define THROW_AND_RETURN_ON_WRITE_ERROR(expr) \
113     {                                         \
114         binder_status_t status = expr;        \
115         if (status != STATUS_OK) {            \
116             throwWriteRE(env, status);        \
117             return;                           \
118         }                                     \
119     }
120 
native_writeToParcel(JNIEnv * env,jobject self,jlong nativePtr,jobject jParcel,jint flags)121 static void native_writeToParcel(JNIEnv *env, jobject self, jlong nativePtr, jobject jParcel,
122                                  jint flags) {
123     battery::LongMultiStateCounter *counter = asLongMultiStateCounter(nativePtr);
124     ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel));
125 
126     uint16_t stateCount = counter->getStateCount();
127     THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt32(parcel.get(), stateCount));
128 
129     for (battery::state_t state = 0; state < stateCount; state++) {
130         THROW_AND_RETURN_ON_WRITE_ERROR(AParcel_writeInt64(parcel.get(), counter->getCount(state)));
131     }
132 }
133 
throwReadException(JNIEnv * env,binder_status_t status)134 static void throwReadException(JNIEnv *env, binder_status_t status) {
135     ALOGE("Could not read LongMultiStateCounter from Parcel, status = %d", status);
136     jniThrowException(env, "android.os.BadParcelableException",
137                       "Could not read LongMultiStateCounter from Parcel");
138 }
139 
140 #define THROW_AND_RETURN_ON_READ_ERROR(expr) \
141     {                                        \
142         binder_status_t status = expr;       \
143         if (status != STATUS_OK) {           \
144             throwReadException(env, status); \
145             return 0L;                       \
146         }                                    \
147     }
148 
native_initFromParcel(JNIEnv * env,jclass theClass,jobject jParcel)149 static jlong native_initFromParcel(JNIEnv *env, jclass theClass, jobject jParcel) {
150     ndk::ScopedAParcel parcel(AParcel_fromJavaParcel(env, jParcel));
151 
152     int32_t stateCount;
153     THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &stateCount));
154 
155     if (stateCount < 0 || stateCount > 0xEFFF) {
156         throwReadException(env, STATUS_INVALID_OPERATION);
157         return 0L;
158     }
159 
160     auto counter = std::make_unique<battery::LongMultiStateCounter>(stateCount, 0);
161 
162     for (battery::state_t state = 0; state < stateCount; state++) {
163         int64_t value;
164         THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt64(parcel.get(), &value));
165         counter->setValue(state, value);
166     }
167 
168     return reinterpret_cast<jlong>(counter.release());
169 }
170 
native_getStateCount(jlong nativePtr)171 static jint native_getStateCount(jlong nativePtr) {
172     return asLongMultiStateCounter(nativePtr)->getStateCount();
173 }
174 
175 static const JNINativeMethod g_methods[] = {
176         // @CriticalNative
177         {"native_init", "(I)J", (void *)native_init},
178         // @CriticalNative
179         {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc},
180         // @CriticalNative
181         {"native_setEnabled", "(JZJ)V", (void *)native_setEnabled},
182         // @CriticalNative
183         {"native_setState", "(JIJ)V", (void *)native_setState},
184         // @CriticalNative
185         {"native_updateValue", "(JJJ)J", (void *)native_updateValue},
186         // @CriticalNative
187         {"native_incrementValue", "(JJJ)V", (void *)native_incrementValue},
188         // @CriticalNative
189         {"native_addCount", "(JJ)V", (void *)native_addCount},
190         // @CriticalNative
191         {"native_reset", "(J)V", (void *)native_reset},
192         // @CriticalNative
193         {"native_getCount", "(JI)J", (void *)native_getCount},
194         // @FastNative
195         {"native_toString", "(J)Ljava/lang/String;", (void *)native_toString},
196         // @FastNative
197         {"native_writeToParcel", "(JLandroid/os/Parcel;I)V", (void *)native_writeToParcel},
198         // @FastNative
199         {"native_initFromParcel", "(Landroid/os/Parcel;)J", (void *)native_initFromParcel},
200         // @CriticalNative
201         {"native_getStateCount", "(J)I", (void *)native_getStateCount},
202 };
203 
register_com_android_internal_os_LongMultiStateCounter(JNIEnv * env)204 int register_com_android_internal_os_LongMultiStateCounter(JNIEnv *env) {
205     return RegisterMethodsOrDie(env, "com/android/internal/os/LongMultiStateCounter", g_methods,
206                                 NELEM(g_methods));
207 }
208 
209 } // namespace android
210