From 0fa3b6eb2ad4c6c50b8125879c2ffbb9412978fb Mon Sep 17 00:00:00 2001 From: Chris Ye Date: Wed, 1 Apr 2020 16:16:42 -0700 Subject: [PATCH] Add PowerManger testcases for parceable objects parceling/unparceling. Test and veify the java to native and native to java parceling/unparceling for: android.os.PowerSaveState android.os.BatterySaverPolicyConfig android.os.WorkSource Bug: 149479744 Test: atest PowerManagerTest Change-Id: Idc5c4639d9a963476e7ee789be451e4db98b1735 --- core/tests/coretests/Android.bp | 3 + core/tests/coretests/jni/Android.bp | 36 ++ .../coretests/jni/NativePowerManagerTest.cpp | 359 ++++++++++++++++++ .../src/android/os/PowerManagerTest.java | 255 +++++++++++++ 4 files changed, 653 insertions(+) create mode 100644 core/tests/coretests/jni/Android.bp create mode 100644 core/tests/coretests/jni/NativePowerManagerTest.cpp diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index b039af38ff9af..78e1c4178c59a 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -58,6 +58,9 @@ android_test { "ext", "framework-res", ], + jni_libs: [ + "libpowermanagertest_jni", + ], platform_apis: true, sdk_version: "core_platform", diff --git a/core/tests/coretests/jni/Android.bp b/core/tests/coretests/jni/Android.bp new file mode 100644 index 0000000000000..bb090e2a3408d --- /dev/null +++ b/core/tests/coretests/jni/Android.bp @@ -0,0 +1,36 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_test_library { + name: "libpowermanagertest_jni", + srcs: [ + "NativePowerManagerTest.cpp", + ], + shared_libs: [ + "libandroid", + "libandroid_runtime_lazy", + "libbase", + "libbinder", + "liblog", + "libnativehelper", + "libpowermanager", + "libutils", + ], + stl: "libc++_static", + cflags: [ + "-Werror", + "-Wall", + ], + gtest: false, +} diff --git a/core/tests/coretests/jni/NativePowerManagerTest.cpp b/core/tests/coretests/jni/NativePowerManagerTest.cpp new file mode 100644 index 0000000000000..50fb31ba085ad --- /dev/null +++ b/core/tests/coretests/jni/NativePowerManagerTest.cpp @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "NativePowerManagerTest" + +#include "jni.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace android::os; +using android::base::StringPrintf; + +namespace android { + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(!(var), "Unable to find class %s", className); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(!(var), "Unable to find field %s", fieldName); + +#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(!(var), "Unable to find method %s", fieldName); + +static jclass gParcelClazz; +static jfieldID gParcelDataFieldID; +static jmethodID gParcelObtainMethodID; +static struct BatterySaverPolicyConfigFieldId { + jfieldID adjustBrightnessFactor; + jfieldID advertiseIsEnabled; + jfieldID deferFullBackup; + jfieldID deferKeyValueBackup; + jfieldID deviceSpecificSettings; + jfieldID disableAnimation; + jfieldID disableAod; + jfieldID disableLaunchBoost; + jfieldID disableOptionalSensors; + jfieldID disableSoundTrigger; + jfieldID disableVibration; + jfieldID enableAdjustBrightness; + jfieldID enableDataSaver; + jfieldID enableFirewall; + jfieldID enableNightMode; + jfieldID enableQuickDoze; + jfieldID forceAllAppsStandby; + jfieldID forceBackgroundCheck; + jfieldID locationMode; +} gBSPCFieldIds; + +static jobject nativeObtainParcel(JNIEnv* env) { + jobject parcel = env->CallStaticObjectMethod(gParcelClazz, gParcelObtainMethodID); + if (parcel == nullptr) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Obtain parcel failed."); + } + return parcel; +} + +static Parcel* nativeGetParcelData(JNIEnv* env, jobject obj) { + Parcel* parcel = reinterpret_cast(env->GetLongField(obj, gParcelDataFieldID)); + if (parcel && parcel->objectsCount() != 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid parcel object."); + } + parcel->setDataPosition(0); + return parcel; +} + +static jobject nativeObtainWorkSourceParcel(JNIEnv* env, jobject /* obj */, jintArray uidArray, + jobjectArray nameArray) { + std::vector uids; + std::optional>> names = std::nullopt; + + if (uidArray != nullptr) { + jint *ptr = env->GetIntArrayElements(uidArray, 0); + for (jint i = 0; i < env->GetArrayLength(uidArray); i++) { + uids.push_back(static_cast(ptr[i])); + } + } + + if (nameArray != nullptr) { + std::vector> namesVec; + for (jint i = 0; i < env->GetArrayLength(nameArray); i++) { + jstring string = (jstring) (env->GetObjectArrayElement(nameArray, i)); + const char *rawString = env->GetStringUTFChars(string, 0); + namesVec.push_back(std::make_optional(String16(rawString))); + } + names = std::make_optional(std::move(namesVec)); + } + + WorkSource ws = WorkSource(uids, names); + jobject wsParcel = nativeObtainParcel(env); + Parcel* parcel = nativeGetParcelData(env, wsParcel); + status_t err = ws.writeToParcel(parcel); + if (err != OK) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource writeToParcel failed %d", err).c_str()); + } + parcel->setDataPosition(0); + return wsParcel; +} + +static void nativeUnparcelAndVerifyWorkSource(JNIEnv* env, jobject /* obj */, jobject wsParcel, + jintArray uidArray, jobjectArray nameArray) { + WorkSource ws = {}; + Parcel* parcel = nativeGetParcelData(env, wsParcel); + + status_t err = ws.readFromParcel(parcel); + if (err != OK) { + ALOGE("WorkSource writeToParcel failed %d", err); + } + + // Now we have a native WorkSource object, verify it. + if (uidArray != nullptr) { + jint *ptr = env->GetIntArrayElements(uidArray, 0); + for (jint i = 0; i < env->GetArrayLength(uidArray); i++) { + if (ws.getUids().at(i) != static_cast(ptr[i])) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource uid not equal %d %d", + ws.getUids().at(i), static_cast(ptr[i])).c_str()); + } + } + } else { + if (ws.getUids().size() != 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource parcel size not 0").c_str()); + } + } + + if (nameArray != nullptr) { + std::vector> namesVec; + for (jint i = 0; i < env->GetArrayLength(nameArray); i++) { + jstring string = (jstring) (env->GetObjectArrayElement(nameArray, i)); + const char *rawString = env->GetStringUTFChars(string, 0); + if (String16(rawString) != ws.getNames()->at(i)) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource uid not equal %s", rawString).c_str()); + } + } + } else { + if (ws.getNames() != std::nullopt) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource parcel name not empty").c_str()); + } + } +} + +static jobject nativeObtainPowerSaveStateParcel(JNIEnv* env, jobject /* obj */, + jboolean batterySaverEnabled, jboolean globalBatterySaverEnabled, + jint locationMode, jfloat brightnessFactor) { + PowerSaveState ps = PowerSaveState(static_cast(batterySaverEnabled), + static_cast(globalBatterySaverEnabled), + static_cast(locationMode), + static_cast(brightnessFactor)); + jobject psParcel = nativeObtainParcel(env); + Parcel* parcel = nativeGetParcelData(env, psParcel); + status_t err = ps.writeToParcel(parcel); + if (err != OK) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource writeToParcel failed %d", err).c_str()); + } + parcel->setDataPosition(0); + return psParcel; +} + +static void nativeUnparcelAndVerifyPowerSaveState(JNIEnv* env, jobject /* obj */, jobject psParcel, + jboolean batterySaverEnabled, jboolean globalBatterySaverEnabled, + jint locationMode, jfloat brightnessFactor) { + PowerSaveState ps = {}; + Parcel* parcel = nativeGetParcelData(env, psParcel); + status_t err = ps.readFromParcel(parcel); + if (err != OK) { + ALOGE("WorkSource writeToParcel failed %d", err); + } + // Now we have a native PowerSaveState object, verify it. + PowerSaveState psOrig = PowerSaveState(static_cast(batterySaverEnabled), + static_cast(globalBatterySaverEnabled), + static_cast(locationMode), + static_cast(brightnessFactor)); + if (ps == psOrig) { + return; + } else { + jniThrowException(env, "java/lang/IllegalArgumentException", + "PowerSaveState not equal with origin"); + } +} + +static jobject nativeObtainBSPConfigParcel(JNIEnv* env, jobject /* obj */, + jobject bsObj, jobjectArray keyArray, jobjectArray valueArray) { + std::vector> deviceSpecificSettings; + for (jint i = 0; i < env->GetArrayLength(keyArray); i++) { + jstring keyString = (jstring) (env->GetObjectArrayElement(keyArray, i)); + jstring valueString = (jstring) (env->GetObjectArrayElement(valueArray, i)); + deviceSpecificSettings.push_back({String16(env->GetStringUTFChars(keyString, 0)), + String16(env->GetStringUTFChars(valueString, 0))}); + } + + BatterySaverPolicyConfig bs = BatterySaverPolicyConfig( + env->GetFloatField(bsObj, gBSPCFieldIds.adjustBrightnessFactor), + env->GetBooleanField(bsObj, gBSPCFieldIds.advertiseIsEnabled), + env->GetBooleanField(bsObj, gBSPCFieldIds.deferFullBackup), + env->GetBooleanField(bsObj, gBSPCFieldIds.deferKeyValueBackup), + deviceSpecificSettings, + env->GetBooleanField(bsObj, gBSPCFieldIds.disableAnimation), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableAod), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableLaunchBoost), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableOptionalSensors), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableSoundTrigger), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableVibration), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableAdjustBrightness), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableDataSaver), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableFirewall), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableNightMode), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableQuickDoze), + env->GetBooleanField(bsObj, gBSPCFieldIds.forceAllAppsStandby), + env->GetBooleanField(bsObj, gBSPCFieldIds.forceBackgroundCheck), + static_cast(env->GetIntField(bsObj, gBSPCFieldIds.locationMode))); + + jobject bsParcel = nativeObtainParcel(env); + Parcel* parcel = nativeGetParcelData(env, bsParcel); + status_t err = bs.writeToParcel(parcel); + if (err != OK) { + jniThrowException(env, "java/lang/IllegalArgumentException", + StringPrintf("WorkSource writeToParcel failed %d", err).c_str()); + } + parcel->setDataPosition(0); + return bsParcel; +} + +static void nativeUnparcelAndVerifyBSPConfig(JNIEnv* env, jobject /* obj */, + jobject bsParcel, jobject bsObj, jobjectArray keyArray, jobjectArray valueArray) { + BatterySaverPolicyConfig bs = {}; + Parcel* parcel = nativeGetParcelData(env, bsParcel); + status_t err = bs.readFromParcel(parcel); + if (err != OK) { + ALOGE("WorkSource writeToParcel failed %d", err); + } + + // Get the device settings from Java + std::vector> deviceSpecificSettings; + for (jint i = 0; i < env->GetArrayLength(keyArray); i++) { + jstring keyString = (jstring) (env->GetObjectArrayElement(keyArray, i)); + jstring valueString = (jstring) (env->GetObjectArrayElement(valueArray, i)); + deviceSpecificSettings.push_back({String16(env->GetStringUTFChars(keyString, 0)), + String16(env->GetStringUTFChars(valueString, 0))}); + } + // Now we have a native BatterySaverPolicyConfig object, verify it. + BatterySaverPolicyConfig bsOrig = BatterySaverPolicyConfig( + env->GetFloatField(bsObj, gBSPCFieldIds.adjustBrightnessFactor), + env->GetBooleanField(bsObj, gBSPCFieldIds.advertiseIsEnabled), + env->GetBooleanField(bsObj, gBSPCFieldIds.deferFullBackup), + env->GetBooleanField(bsObj, gBSPCFieldIds.deferKeyValueBackup), + deviceSpecificSettings, + env->GetBooleanField(bsObj, gBSPCFieldIds.disableAnimation), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableAod), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableLaunchBoost), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableOptionalSensors), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableSoundTrigger), + env->GetBooleanField(bsObj, gBSPCFieldIds.disableVibration), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableAdjustBrightness), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableDataSaver), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableFirewall), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableNightMode), + env->GetBooleanField(bsObj, gBSPCFieldIds.enableQuickDoze), + env->GetBooleanField(bsObj, gBSPCFieldIds.forceAllAppsStandby), + env->GetBooleanField(bsObj, gBSPCFieldIds.forceBackgroundCheck), + static_cast(env->GetIntField(bsObj, gBSPCFieldIds.locationMode))); + + if (bs == bsOrig) { + return; + } else { + jniThrowException(env, "java/lang/IllegalArgumentException", + "BatterySaverPolicyConfig not equal with origin"); + } +} + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) +{ + JNIEnv* env; + const JNINativeMethod methodTable[] = { + /* name, signature, funcPtr */ + { "nativeObtainWorkSourceParcel", "([I[Ljava/lang/String;)Landroid/os/Parcel;", + (void*) nativeObtainWorkSourceParcel }, + { "nativeUnparcelAndVerifyWorkSource", "(Landroid/os/Parcel;[I[Ljava/lang/String;)V", + (void*) nativeUnparcelAndVerifyWorkSource }, + { "nativeObtainPowerSaveStateParcel", "(ZZIF)Landroid/os/Parcel;", + (void*) nativeObtainPowerSaveStateParcel }, + { "nativeUnparcelAndVerifyPowerSaveState", "(Landroid/os/Parcel;ZZIF)V", + (void*) nativeUnparcelAndVerifyPowerSaveState }, + { "nativeObtainBSPConfigParcel", + "(Landroid/os/BatterySaverPolicyConfig;" + "[Ljava/lang/String;[Ljava/lang/String;)Landroid/os/Parcel;", + (void*) nativeObtainBSPConfigParcel }, + { "nativeUnparcelAndVerifyBSPConfig", + "(Landroid/os/Parcel;Landroid/os/BatterySaverPolicyConfig;" + "[Ljava/lang/String;[Ljava/lang/String;)V", + (void*) nativeUnparcelAndVerifyBSPConfig }, + }; + + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + return JNI_ERR; + } + + jclass bspcClazz; + FIND_CLASS(gParcelClazz, "android/os/Parcel"); + GET_FIELD_ID(gParcelDataFieldID, gParcelClazz, "mNativePtr", "J"); + GET_STATIC_METHOD_ID(gParcelObtainMethodID, gParcelClazz, "obtain", "()Landroid/os/Parcel;"); + FIND_CLASS(bspcClazz, "android/os/BatterySaverPolicyConfig"); + GET_FIELD_ID(gBSPCFieldIds.adjustBrightnessFactor, bspcClazz, "mAdjustBrightnessFactor", "F"); + GET_FIELD_ID(gBSPCFieldIds.advertiseIsEnabled, bspcClazz, "mAdvertiseIsEnabled", "Z"); + GET_FIELD_ID(gBSPCFieldIds.deferFullBackup, bspcClazz, "mDeferFullBackup", "Z"); + GET_FIELD_ID(gBSPCFieldIds.deferKeyValueBackup, bspcClazz, "mDeferKeyValueBackup", "Z"); + GET_FIELD_ID(gBSPCFieldIds.deviceSpecificSettings, bspcClazz, "mDeviceSpecificSettings", + "Ljava/util/Map;"); + GET_FIELD_ID(gBSPCFieldIds.disableAnimation, bspcClazz, "mDisableAnimation", "Z"); + GET_FIELD_ID(gBSPCFieldIds.disableAod, bspcClazz, "mDisableAod", "Z"); + GET_FIELD_ID(gBSPCFieldIds.disableLaunchBoost, bspcClazz, "mDisableLaunchBoost", "Z"); + GET_FIELD_ID(gBSPCFieldIds.disableOptionalSensors, bspcClazz, "mDisableOptionalSensors", "Z"); + GET_FIELD_ID(gBSPCFieldIds.disableSoundTrigger, bspcClazz, "mDisableSoundTrigger", "Z"); + GET_FIELD_ID(gBSPCFieldIds.disableVibration, bspcClazz, "mDisableVibration", "Z"); + GET_FIELD_ID(gBSPCFieldIds.enableAdjustBrightness, bspcClazz, "mEnableAdjustBrightness", "Z"); + GET_FIELD_ID(gBSPCFieldIds.enableDataSaver, bspcClazz, "mEnableDataSaver", "Z"); + GET_FIELD_ID(gBSPCFieldIds.enableFirewall, bspcClazz, "mEnableFirewall", "Z"); + GET_FIELD_ID(gBSPCFieldIds.enableNightMode, bspcClazz, "mEnableNightMode", "Z"); + GET_FIELD_ID(gBSPCFieldIds.enableQuickDoze, bspcClazz, "mEnableQuickDoze", "Z"); + GET_FIELD_ID(gBSPCFieldIds.forceAllAppsStandby, bspcClazz, "mForceAllAppsStandby", "Z"); + GET_FIELD_ID(gBSPCFieldIds.forceBackgroundCheck, bspcClazz, "mForceBackgroundCheck", "Z"); + GET_FIELD_ID(gBSPCFieldIds.locationMode, bspcClazz, "mLocationMode", "I"); + + jniRegisterNativeMethods(env, "android/os/PowerManagerTest", methodTable, + sizeof(methodTable) / sizeof(JNINativeMethod)); + return JNI_VERSION_1_6; +} + +} /* namespace android */ diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java index 37e8d5937bc51..d3baed34509ea 100644 --- a/core/tests/coretests/src/android/os/PowerManagerTest.java +++ b/core/tests/coretests/src/android/os/PowerManagerTest.java @@ -16,6 +16,9 @@ package android.os; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; @@ -37,6 +40,7 @@ import java.util.concurrent.Executors; public class PowerManagerTest extends AndroidTestCase { + private static final String TAG = "PowerManagerTest"; private PowerManager mPm; private UiDevice mUiDevice; private Executor mExec = Executors.newSingleThreadExecutor(); @@ -45,6 +49,22 @@ public class PowerManagerTest extends AndroidTestCase { @Mock private PowerManager.OnThermalStatusChangedListener mListener2; private static final long CALLBACK_TIMEOUT_MILLI_SEC = 5000; + private native Parcel nativeObtainWorkSourceParcel(int[] uids, String[] names); + private native void nativeUnparcelAndVerifyWorkSource(Parcel parcel, int[] uids, + String[] names); + private native Parcel nativeObtainPowerSaveStateParcel(boolean batterySaverEnabled, + boolean globalBatterySaverEnabled, int locationMode, float brightnessFactor); + private native void nativeUnparcelAndVerifyPowerSaveState(Parcel parcel, + boolean batterySaverEnabled, boolean globalBatterySaverEnabled, + int locationMode, float brightnessFactor); + private native Parcel nativeObtainBSPConfigParcel(BatterySaverPolicyConfig bs, + String[] keys, String[] values); + private native void nativeUnparcelAndVerifyBSPConfig(Parcel parcel, BatterySaverPolicyConfig bs, + String[] keys, String[] values); + + static { + System.loadLibrary("powermanagertest_jni"); + } /** * Setup any common data for the upcoming tests. @@ -277,4 +297,239 @@ public class PowerManagerTest extends AndroidTestCase { } catch (UnsupportedOperationException expected) { } } + + /** + * Helper function to obtain a WorkSource object as parcel from native, with + * specified uids and names and verify the WorkSource object created from the parcel. + */ + private void unparcelWorkSourceFromNativeAndVerify(int[] uids, String[] names) { + // Obtain WorkSource as parcel from native, with uids and names. + Parcel wsParcel = nativeObtainWorkSourceParcel(uids, names); + WorkSource ws = WorkSource.CREATOR.createFromParcel(wsParcel); + if (uids == null) { + assertEquals(ws.size(), 0); + } else { + assertEquals(uids.length, ws.size()); + for (int i = 0; i < ws.size(); i++) { + assertEquals(ws.getUid(i), uids[i]); + } + } + if (names != null) { + for (int i = 0; i < names.length; i++) { + assertEquals(ws.getName(i), names[i]); + } + } + } + + /** + * Helper function to send a WorkSource as parcel from java to native. + * Native will verify the WorkSource in native is expected. + */ + private void parcelWorkSourceToNativeAndVerify(int[] uids, String[] names) { + WorkSource ws = new WorkSource(); + if (uids != null) { + if (names == null) { + for (int i = 0; i < uids.length; i++) { + ws.add(uids[i]); + } + } else { + assertEquals(uids.length, names.length); + for (int i = 0; i < uids.length; i++) { + ws.add(uids[i], names[i]); + } + } + } + Parcel wsParcel = Parcel.obtain(); + ws.writeToParcel(wsParcel, 0 /* flags */); + wsParcel.setDataPosition(0); + //Set the WorkSource as parcel to native and verify. + nativeUnparcelAndVerifyWorkSource(wsParcel, uids, names); + } + + /** + * Helper function to obtain a PowerSaveState as parcel from native, with + * specified parameters, and verify the PowerSaveState object created from the parcel. + */ + private void unparcelPowerSaveStateFromNativeAndVerify(boolean batterySaverEnabled, + boolean globalBatterySaverEnabled, int locationMode, float brightnessFactor) { + // Obtain PowerSaveState as parcel from native, with parameters. + Parcel psParcel = nativeObtainPowerSaveStateParcel(batterySaverEnabled, + globalBatterySaverEnabled, locationMode, brightnessFactor); + // Verify the parcel. + PowerSaveState ps = PowerSaveState.CREATOR.createFromParcel(psParcel); + assertEquals(ps.batterySaverEnabled, batterySaverEnabled); + assertEquals(ps.globalBatterySaverEnabled, globalBatterySaverEnabled); + assertEquals(ps.locationMode, locationMode); + assertEquals(ps.brightnessFactor, brightnessFactor, 0.01f); + } + + /** + * Helper function to send a PowerSaveState as parcel to native, with + * specified parameters. Native will verify the PowerSaveState in native is expected. + */ + private void parcelPowerSaveStateToNativeAndVerify(boolean batterySaverEnabled, + boolean globalBatterySaverEnabled, int locationMode, float brightnessFactor) { + Parcel psParcel = Parcel.obtain(); + // PowerSaveState API blocks Builder.build(), generate a parcel instead of object. + PowerSaveState ps = new PowerSaveState.Builder() + .setBatterySaverEnabled(batterySaverEnabled) + .setGlobalBatterySaverEnabled(globalBatterySaverEnabled) + .setLocationMode(locationMode) + .setBrightnessFactor(brightnessFactor).build(); + ps.writeToParcel(psParcel, 0 /* flags */); + psParcel.setDataPosition(0); + //Set the PowerSaveState as parcel to native and verify in native space. + nativeUnparcelAndVerifyPowerSaveState(psParcel, batterySaverEnabled, + globalBatterySaverEnabled, locationMode, brightnessFactor); + } + + /** + * Helper function to obtain a BatterySaverPolicyConfig as parcel from native, with + * specified parameters, and verify the BatterySaverPolicyConfig object created from the parcel. + */ + private void unparcelBatterySaverPolicyFromNativeAndVerify(BatterySaverPolicyConfig bsIn) { + // Obtain BatterySaverPolicyConfig as parcel from native, with parameters. + String[] keys = bsIn.getDeviceSpecificSettings().keySet().toArray( + new String[bsIn.getDeviceSpecificSettings().keySet().size()]); + String[] values = bsIn.getDeviceSpecificSettings().values().toArray( + new String[bsIn.getDeviceSpecificSettings().values().size()]); + Parcel bsParcel = nativeObtainBSPConfigParcel(bsIn, keys, values); + BatterySaverPolicyConfig bsOut = + BatterySaverPolicyConfig.CREATOR.createFromParcel(bsParcel); + assertEquals(bsIn.toString(), bsOut.toString()); + } + + /** + * Helper function to send a BatterySaverPolicyConfig as parcel to native, with + * specified parameters. + * Native will verify BatterySaverPolicyConfig from native is expected. + */ + private void parcelBatterySaverPolicyConfigToNativeAndVerify(BatterySaverPolicyConfig bsIn) { + Parcel bsParcel = Parcel.obtain(); + bsIn.writeToParcel(bsParcel, 0 /* flags */); + bsParcel.setDataPosition(0); + // Set the BatterySaverPolicyConfig as parcel to native. + String[] keys = bsIn.getDeviceSpecificSettings().keySet().toArray( + new String[bsIn.getDeviceSpecificSettings().keySet().size()]); + String[] values = bsIn.getDeviceSpecificSettings().values().toArray( + new String[bsIn.getDeviceSpecificSettings().values().size()]); + // Set the BatterySaverPolicyConfig as parcel to native and verify in native space. + nativeUnparcelAndVerifyBSPConfig(bsParcel, bsIn, keys, values); + } + + /** + * Confirm that we can pass WorkSource from native to Java. + * + * @throws Exception + */ + @Test + public void testWorkSourceNativeToJava() { + final int[] uids1 = {1000}; + final int[] uids2 = {1000, 2000}; + final String[] names1 = {"testWorkSource1"}; + final String[] names2 = {"testWorkSource1", "testWorkSource2"}; + unparcelWorkSourceFromNativeAndVerify(null /* uids */, null /* names */); + unparcelWorkSourceFromNativeAndVerify(uids1, null /* names */); + unparcelWorkSourceFromNativeAndVerify(uids2, null /* names */); + unparcelWorkSourceFromNativeAndVerify(null /* uids */, names1); + unparcelWorkSourceFromNativeAndVerify(uids1, names1); + unparcelWorkSourceFromNativeAndVerify(uids2, names2); + } + + /** + * Confirm that we can pass WorkSource from Java to native. + * + * @throws Exception + */ + @Test + public void testWorkSourceJavaToNative() { + final int[] uids1 = {1000}; + final int[] uids2 = {1000, 2000}; + final String[] names1 = {"testGetWorkSource1"}; + final String[] names2 = {"testGetWorkSource1", "testGetWorkSource2"}; + parcelWorkSourceToNativeAndVerify(null /* uids */, null /* names */); + parcelWorkSourceToNativeAndVerify(uids1, null /* names */); + parcelWorkSourceToNativeAndVerify(uids2, null /* names */); + parcelWorkSourceToNativeAndVerify(uids1, names1); + parcelWorkSourceToNativeAndVerify(uids2, names2); + } + + /** + * Confirm that we can pass PowerSaveState from native to Java. + * + * @throws Exception + */ + @Test + public void testPowerSaveStateNativeToJava() { + unparcelPowerSaveStateFromNativeAndVerify(false /* batterySaverEnabled */, + false /* globalBatterySaverEnabled */, + PowerManager.LOCATION_MODE_FOREGROUND_ONLY, 0.3f /* brightnessFactor */); + unparcelPowerSaveStateFromNativeAndVerify(true /* batterySaverEnabled */, + true /* globalBatterySaverEnabled */, + PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF, + 0.5f /* brightnessFactor */); + } + + /** + * Confirm that we can pass PowerSaveState from Java to native. + * + * @throws Exception + */ + @Test + public void testSetPowerSaveStateJavaToNative() { + parcelPowerSaveStateToNativeAndVerify(false /* batterySaverEnabled */, + false /* globalBatterySaverEnabled */, + PowerManager.LOCATION_MODE_FOREGROUND_ONLY, 0.3f /* brightnessFactor */); + parcelPowerSaveStateToNativeAndVerify(true /* batterySaverEnabled */, + true /* globalBatterySaverEnabled */, + PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF, + 0.5f /* brightnessFactor */); + } + + /** + * Confirm that we can pass BatterySaverPolicyConfig from native to Java. + * + * @throws Exception + */ + @Test + public void testBatterySaverPolicyConfigNativeToJava() { + BatterySaverPolicyConfig bs1 = new BatterySaverPolicyConfig.Builder() + .setAdjustBrightnessFactor(0.55f) + .setAdvertiseIsEnabled(true) + .setDeferFullBackup(true) + .setForceBackgroundCheck(true) + .setLocationMode(PowerManager.LOCATION_MODE_FOREGROUND_ONLY).build(); + BatterySaverPolicyConfig bs2 = new BatterySaverPolicyConfig.Builder() + .setAdjustBrightnessFactor(0.55f) + .setAdvertiseIsEnabled(true) + .setLocationMode(PowerManager.LOCATION_MODE_FOREGROUND_ONLY) + .addDeviceSpecificSetting("Key1" /* key */, "Value1" /* value */) + .addDeviceSpecificSetting("Key2" /* key */, "Value2" /* value */) + .setDeferFullBackup(true).build(); + + unparcelBatterySaverPolicyFromNativeAndVerify(bs1); + unparcelBatterySaverPolicyFromNativeAndVerify(bs2); + } + + /** + * Confirm that we can pass BatterySaverPolicyConfig from Java to native. + * + * @throws Exception + */ + @Test + public void testBatterySaverPolicyConfigFromJavaToNative() { + BatterySaverPolicyConfig bs1 = new BatterySaverPolicyConfig.Builder() + .setAdjustBrightnessFactor(0.55f) + .setAdvertiseIsEnabled(true) + .setDeferFullBackup(true).build(); + BatterySaverPolicyConfig bs2 = new BatterySaverPolicyConfig.Builder() + .setAdjustBrightnessFactor(0.55f) + .setAdvertiseIsEnabled(true) + .addDeviceSpecificSetting("Key1" /* key */, "Value1" /* value */) + .addDeviceSpecificSetting("Key2" /* key */, "Value2" /* value */) + .setDeferFullBackup(true).build(); + parcelBatterySaverPolicyConfigToNativeAndVerify(bs1); + parcelBatterySaverPolicyConfigToNativeAndVerify(bs2); + } + }