1 /*
2  * Copyright (C) 2020 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "NativePowerManagerTest"
19 
20 #include "jni.h"
21 #include "ParcelHelper.h"
22 
23 #include <android_util_Binder.h>
24 #include <binder/IServiceManager.h>
25 #include <nativehelper/JNIHelp.h>
26 #include <utils/Log.h>
27 
28 #include <android/os/IPowerManager.h>
29 #include <android/WorkSource.h>
30 #include <android/PowerSaveState.h>
31 #include <android/BatterySaverPolicyConfig.h>
32 #include <android-base/stringprintf.h>
33 #include <android-base/strings.h>
34 
35 using namespace android::os;
36 using android::base::StringPrintf;
37 
38 namespace android {
39 
40 static struct BatterySaverPolicyConfigFieldId {
41     jfieldID adjustBrightnessFactor;
42     jfieldID advertiseIsEnabled;
43     jfieldID deferFullBackup;
44     jfieldID deferKeyValueBackup;
45     jfieldID deviceSpecificSettings;
46     jfieldID disableAnimation;
47     jfieldID disableAod;
48     jfieldID disableLaunchBoost;
49     jfieldID disableOptionalSensors;
50     jfieldID disableVibration;
51     jfieldID enableAdjustBrightness;
52     jfieldID enableDataSaver;
53     jfieldID enableFirewall;
54     jfieldID enableNightMode;
55     jfieldID enableQuickDoze;
56     jfieldID forceAllAppsStandby;
57     jfieldID forceBackgroundCheck;
58     jfieldID locationMode;
59     jfieldID soundTriggerMode;
60 } gBSPCFieldIds;
61 
nativeObtainPowerSaveStateParcel(JNIEnv * env,jobject,jboolean batterySaverEnabled,jboolean globalBatterySaverEnabled,jint locationMode,jint soundTriggerMode,jfloat brightnessFactor)62 static jobject nativeObtainPowerSaveStateParcel(JNIEnv* env, jobject /* obj */,
63         jboolean batterySaverEnabled, jboolean globalBatterySaverEnabled,
64         jint locationMode, jint soundTriggerMode, jfloat brightnessFactor) {
65     PowerSaveState ps = PowerSaveState(static_cast<bool>(batterySaverEnabled),
66             static_cast<bool>(globalBatterySaverEnabled),
67             static_cast<LocationMode>(locationMode),
68             static_cast<SoundTriggerMode>(soundTriggerMode),
69             static_cast<float>(brightnessFactor));
70     jobject psParcel = nativeObtainParcel(env);
71     Parcel* parcel = nativeGetParcelData(env, psParcel);
72     status_t err = ps.writeToParcel(parcel);
73     if (err != OK) {
74         jniThrowException(env, "java/lang/IllegalArgumentException",
75                             StringPrintf("WorkSource writeToParcel failed %d", err).c_str());
76     }
77     parcel->setDataPosition(0);
78     return psParcel;
79 }
80 
nativeUnparcelAndVerifyPowerSaveState(JNIEnv * env,jobject,jobject psParcel,jboolean batterySaverEnabled,jboolean globalBatterySaverEnabled,jint locationMode,jint soundTriggerMode,jfloat brightnessFactor)81 static void nativeUnparcelAndVerifyPowerSaveState(JNIEnv* env, jobject /* obj */, jobject psParcel,
82         jboolean batterySaverEnabled, jboolean globalBatterySaverEnabled,
83         jint locationMode, jint soundTriggerMode, jfloat brightnessFactor) {
84     PowerSaveState ps = {};
85     Parcel* parcel = nativeGetParcelData(env, psParcel);
86     status_t err = ps.readFromParcel(parcel);
87     if (err != OK) {
88         ALOGE("WorkSource writeToParcel failed %d", err);
89     }
90     // Now we have a native PowerSaveState object, verify it.
91     PowerSaveState psOrig = PowerSaveState(static_cast<bool>(batterySaverEnabled),
92             static_cast<bool>(globalBatterySaverEnabled),
93             static_cast<LocationMode>(locationMode),
94             static_cast<SoundTriggerMode>(soundTriggerMode),
95             static_cast<float>(brightnessFactor));
96     if (ps == psOrig) {
97         return;
98     } else {
99         jniThrowException(env, "java/lang/IllegalArgumentException",
100                             "PowerSaveState not equal with origin");
101     }
102 }
103 
nativeObtainBSPConfigParcel(JNIEnv * env,jobject,jobject bsObj,jobjectArray keyArray,jobjectArray valueArray)104 static jobject nativeObtainBSPConfigParcel(JNIEnv* env, jobject /* obj */,
105         jobject bsObj, jobjectArray keyArray, jobjectArray valueArray) {
106     std::vector<std::pair<String16, String16>> deviceSpecificSettings;
107     for (jint i = 0; i < env->GetArrayLength(keyArray); i++) {
108         jstring keyString = (jstring) (env->GetObjectArrayElement(keyArray, i));
109         jstring valueString = (jstring) (env->GetObjectArrayElement(valueArray, i));
110         deviceSpecificSettings.push_back({String16(env->GetStringUTFChars(keyString, 0)),
111                         String16(env->GetStringUTFChars(valueString, 0))});
112     }
113 
114     BatterySaverPolicyConfig bs = BatterySaverPolicyConfig(
115         env->GetFloatField(bsObj, gBSPCFieldIds.adjustBrightnessFactor),
116         env->GetBooleanField(bsObj, gBSPCFieldIds.advertiseIsEnabled),
117         env->GetBooleanField(bsObj, gBSPCFieldIds.deferFullBackup),
118         env->GetBooleanField(bsObj, gBSPCFieldIds.deferKeyValueBackup),
119         deviceSpecificSettings,
120         env->GetBooleanField(bsObj, gBSPCFieldIds.disableAnimation),
121         env->GetBooleanField(bsObj, gBSPCFieldIds.disableAod),
122         env->GetBooleanField(bsObj, gBSPCFieldIds.disableLaunchBoost),
123         env->GetBooleanField(bsObj, gBSPCFieldIds.disableOptionalSensors),
124         env->GetBooleanField(bsObj, gBSPCFieldIds.disableVibration),
125         env->GetBooleanField(bsObj, gBSPCFieldIds.enableAdjustBrightness),
126         env->GetBooleanField(bsObj, gBSPCFieldIds.enableDataSaver),
127         env->GetBooleanField(bsObj, gBSPCFieldIds.enableFirewall),
128         env->GetBooleanField(bsObj, gBSPCFieldIds.enableNightMode),
129         env->GetBooleanField(bsObj, gBSPCFieldIds.enableQuickDoze),
130         env->GetBooleanField(bsObj, gBSPCFieldIds.forceAllAppsStandby),
131         env->GetBooleanField(bsObj, gBSPCFieldIds.forceBackgroundCheck),
132         static_cast<LocationMode>(env->GetIntField(bsObj, gBSPCFieldIds.locationMode)),
133         static_cast<SoundTriggerMode>(env->GetIntField(bsObj, gBSPCFieldIds.soundTriggerMode)));
134 
135     jobject bsParcel = nativeObtainParcel(env);
136     Parcel* parcel = nativeGetParcelData(env, bsParcel);
137     status_t err = bs.writeToParcel(parcel);
138     if (err != OK) {
139         jniThrowException(env, "java/lang/IllegalArgumentException",
140                         StringPrintf("WorkSource writeToParcel failed %d", err).c_str());
141     }
142     parcel->setDataPosition(0);
143     return bsParcel;
144 }
145 
nativeUnparcelAndVerifyBSPConfig(JNIEnv * env,jobject,jobject bsParcel,jobject bsObj,jobjectArray keyArray,jobjectArray valueArray)146 static void nativeUnparcelAndVerifyBSPConfig(JNIEnv* env, jobject /* obj */,
147         jobject bsParcel, jobject bsObj, jobjectArray keyArray, jobjectArray valueArray) {
148     BatterySaverPolicyConfig bs = {};
149     Parcel* parcel = nativeGetParcelData(env, bsParcel);
150     status_t err = bs.readFromParcel(parcel);
151     if (err != OK) {
152         ALOGE("WorkSource writeToParcel failed %d", err);
153     }
154 
155     // Get the device settings from Java
156     std::vector<std::pair<String16, String16>> deviceSpecificSettings;
157     for (jint i = 0; i < env->GetArrayLength(keyArray); i++) {
158         jstring keyString = (jstring) (env->GetObjectArrayElement(keyArray, i));
159         jstring valueString = (jstring) (env->GetObjectArrayElement(valueArray, i));
160         deviceSpecificSettings.push_back({String16(env->GetStringUTFChars(keyString, 0)),
161                         String16(env->GetStringUTFChars(valueString, 0))});
162     }
163     // Now we have a native BatterySaverPolicyConfig object, verify it.
164     BatterySaverPolicyConfig bsOrig = BatterySaverPolicyConfig(
165         env->GetFloatField(bsObj, gBSPCFieldIds.adjustBrightnessFactor),
166         env->GetBooleanField(bsObj, gBSPCFieldIds.advertiseIsEnabled),
167         env->GetBooleanField(bsObj, gBSPCFieldIds.deferFullBackup),
168         env->GetBooleanField(bsObj, gBSPCFieldIds.deferKeyValueBackup),
169         deviceSpecificSettings,
170         env->GetBooleanField(bsObj, gBSPCFieldIds.disableAnimation),
171         env->GetBooleanField(bsObj, gBSPCFieldIds.disableAod),
172         env->GetBooleanField(bsObj, gBSPCFieldIds.disableLaunchBoost),
173         env->GetBooleanField(bsObj, gBSPCFieldIds.disableOptionalSensors),
174         env->GetBooleanField(bsObj, gBSPCFieldIds.disableVibration),
175         env->GetBooleanField(bsObj, gBSPCFieldIds.enableAdjustBrightness),
176         env->GetBooleanField(bsObj, gBSPCFieldIds.enableDataSaver),
177         env->GetBooleanField(bsObj, gBSPCFieldIds.enableFirewall),
178         env->GetBooleanField(bsObj, gBSPCFieldIds.enableNightMode),
179         env->GetBooleanField(bsObj, gBSPCFieldIds.enableQuickDoze),
180         env->GetBooleanField(bsObj, gBSPCFieldIds.forceAllAppsStandby),
181         env->GetBooleanField(bsObj, gBSPCFieldIds.forceBackgroundCheck),
182         static_cast<LocationMode>(env->GetIntField(bsObj, gBSPCFieldIds.locationMode)),
183         static_cast<SoundTriggerMode>(env->GetIntField(bsObj, gBSPCFieldIds.soundTriggerMode)));
184 
185     if (bs == bsOrig) {
186         return;
187     } else {
188         jniThrowException(env, "java/lang/IllegalArgumentException",
189                             "BatterySaverPolicyConfig not equal with origin");
190     }
191 }
192 
JNI_OnLoad(JavaVM * vm,void *)193 extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
194 {
195     JNIEnv* env;
196     const JNINativeMethod methodTable[] = {
197         /* name, signature, funcPtr */
198         { "nativeObtainPowerSaveStateParcel", "(ZZIIF)Landroid/os/Parcel;",
199                 (void*) nativeObtainPowerSaveStateParcel },
200         { "nativeUnparcelAndVerifyPowerSaveState", "(Landroid/os/Parcel;ZZIIF)V",
201                 (void*) nativeUnparcelAndVerifyPowerSaveState },
202         { "nativeObtainBSPConfigParcel",
203                 "(Landroid/os/BatterySaverPolicyConfig;"
204                 "[Ljava/lang/String;[Ljava/lang/String;)Landroid/os/Parcel;",
205                 (void*) nativeObtainBSPConfigParcel },
206         { "nativeUnparcelAndVerifyBSPConfig",
207                 "(Landroid/os/Parcel;Landroid/os/BatterySaverPolicyConfig;"
208                 "[Ljava/lang/String;[Ljava/lang/String;)V",
209                 (void*) nativeUnparcelAndVerifyBSPConfig },
210     };
211 
212     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
213         return JNI_ERR;
214     }
215 
216     loadParcelClass(env);
217 
218     jclass bspcClazz = FindClassOrDie(env, "android/os/BatterySaverPolicyConfig");
219 
220     gBSPCFieldIds.adjustBrightnessFactor =
221             GetFieldIDOrDie(env, bspcClazz, "mAdjustBrightnessFactor", "F");
222     gBSPCFieldIds.advertiseIsEnabled = GetFieldIDOrDie(env, bspcClazz, "mAdvertiseIsEnabled", "Z");
223     gBSPCFieldIds.deferFullBackup = GetFieldIDOrDie(env, bspcClazz, "mDeferFullBackup", "Z");
224     gBSPCFieldIds.deferKeyValueBackup =
225             GetFieldIDOrDie(env, bspcClazz, "mDeferKeyValueBackup", "Z");
226     gBSPCFieldIds.deviceSpecificSettings =
227             GetFieldIDOrDie(env, bspcClazz, "mDeviceSpecificSettings", "Ljava/util/Map;");
228     gBSPCFieldIds.disableAnimation = GetFieldIDOrDie(env, bspcClazz, "mDisableAnimation", "Z");
229     gBSPCFieldIds.disableAod = GetFieldIDOrDie(env, bspcClazz, "mDisableAod", "Z");
230     gBSPCFieldIds.disableLaunchBoost = GetFieldIDOrDie(env, bspcClazz, "mDisableLaunchBoost", "Z");
231     gBSPCFieldIds.disableOptionalSensors =
232             GetFieldIDOrDie(env, bspcClazz, "mDisableOptionalSensors", "Z");
233     gBSPCFieldIds.disableVibration = GetFieldIDOrDie(env, bspcClazz, "mDisableVibration", "Z");
234     gBSPCFieldIds.enableAdjustBrightness =
235             GetFieldIDOrDie(env, bspcClazz, "mEnableAdjustBrightness", "Z");
236     gBSPCFieldIds.enableDataSaver = GetFieldIDOrDie(env, bspcClazz, "mEnableDataSaver", "Z");
237     gBSPCFieldIds.enableFirewall = GetFieldIDOrDie(env, bspcClazz, "mEnableFirewall", "Z");
238     gBSPCFieldIds.enableNightMode = GetFieldIDOrDie(env, bspcClazz, "mEnableNightMode", "Z");
239     gBSPCFieldIds.enableQuickDoze = GetFieldIDOrDie(env, bspcClazz, "mEnableQuickDoze", "Z");
240     gBSPCFieldIds.forceAllAppsStandby =
241             GetFieldIDOrDie(env, bspcClazz, "mForceAllAppsStandby", "Z");
242     gBSPCFieldIds.forceBackgroundCheck =
243             GetFieldIDOrDie(env, bspcClazz, "mForceBackgroundCheck", "Z");
244     gBSPCFieldIds.locationMode = GetFieldIDOrDie(env, bspcClazz, "mLocationMode", "I");
245     gBSPCFieldIds.soundTriggerMode = GetFieldIDOrDie(env, bspcClazz, "mSoundTriggerMode", "I");
246 
247     jniRegisterNativeMethods(env, "android/os/PowerManagerTest", methodTable,
248                 sizeof(methodTable) / sizeof(JNINativeMethod));
249 
250     return JNI_VERSION_1_6;
251 }
252 
253 } /* namespace android */
254