Tests to ensure native and java WorkSource are in sync
Bug: b/237719490 Test: atest WorkSourceParcelTest, atest PowerManagerTest Change-Id: Ia4bf8ad292e067e4e39b0b8627ef0d31105ba5c1
This commit is contained in:
committed by
Oleg Petšjonkin
parent
3c86862dd8
commit
a7ed3f3819
@@ -73,6 +73,7 @@ android_test {
|
||||
],
|
||||
jni_libs: [
|
||||
"libpowermanagertest_jni",
|
||||
"libworksourceparceltest_jni",
|
||||
],
|
||||
|
||||
sdk_version: "core_platform",
|
||||
|
||||
@@ -43,3 +43,27 @@ cc_test_library {
|
||||
],
|
||||
gtest: false,
|
||||
}
|
||||
|
||||
cc_test_library {
|
||||
name: "libworksourceparceltest_jni",
|
||||
srcs: [
|
||||
"NativeWorkSourceParcelTest.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libandroid",
|
||||
"libandroid_runtime_lazy",
|
||||
"libbase",
|
||||
"libbinder",
|
||||
"liblog",
|
||||
"libnativehelper",
|
||||
"libpowermanager",
|
||||
"libutils",
|
||||
],
|
||||
header_libs: ["jni_headers"],
|
||||
stl: "libc++_static",
|
||||
cflags: [
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
],
|
||||
gtest: false,
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define LOG_TAG "NativePowerManagerTest"
|
||||
|
||||
#include "jni.h"
|
||||
#include "ParcelHelper.h"
|
||||
|
||||
#include <android_util_Binder.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
@@ -36,21 +37,6 @@ 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;
|
||||
@@ -73,102 +59,6 @@ static struct BatterySaverPolicyConfigFieldId {
|
||||
jfieldID soundTriggerMode;
|
||||
} 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<Parcel*>(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<int32_t> uids;
|
||||
std::optional<std::vector<std::optional<String16>>> 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<int32_t>(ptr[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (nameArray != nullptr) {
|
||||
std::vector<std::optional<String16>> 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>(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<int32_t>(ptr[i])) {
|
||||
jniThrowException(env, "java/lang/IllegalArgumentException",
|
||||
StringPrintf("WorkSource uid not equal %d %d",
|
||||
ws.getUids().at(i), static_cast<int32_t>(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<std::optional<String16>> 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, jint soundTriggerMode, jfloat brightnessFactor) {
|
||||
@@ -305,10 +195,6 @@ 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", "(ZZIIF)Landroid/os/Parcel;",
|
||||
(void*) nativeObtainPowerSaveStateParcel },
|
||||
{ "nativeUnparcelAndVerifyPowerSaveState", "(Landroid/os/Parcel;ZZIIF)V",
|
||||
@@ -327,34 +213,40 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
|
||||
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.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");
|
||||
GET_FIELD_ID(gBSPCFieldIds.soundTriggerMode, bspcClazz, "mSoundTriggerMode", "I");
|
||||
loadParcelClass(env);
|
||||
|
||||
jclass bspcClazz = FindClassOrDie(env, "android/os/BatterySaverPolicyConfig");
|
||||
|
||||
gBSPCFieldIds.adjustBrightnessFactor =
|
||||
GetFieldIDOrDie(env, bspcClazz, "mAdjustBrightnessFactor", "F");
|
||||
gBSPCFieldIds.advertiseIsEnabled = GetFieldIDOrDie(env, bspcClazz, "mAdvertiseIsEnabled", "Z");
|
||||
gBSPCFieldIds.deferFullBackup = GetFieldIDOrDie(env, bspcClazz, "mDeferFullBackup", "Z");
|
||||
gBSPCFieldIds.deferKeyValueBackup =
|
||||
GetFieldIDOrDie(env, bspcClazz, "mDeferKeyValueBackup", "Z");
|
||||
gBSPCFieldIds.deviceSpecificSettings =
|
||||
GetFieldIDOrDie(env, bspcClazz, "mDeviceSpecificSettings", "Ljava/util/Map;");
|
||||
gBSPCFieldIds.disableAnimation = GetFieldIDOrDie(env, bspcClazz, "mDisableAnimation", "Z");
|
||||
gBSPCFieldIds.disableAod = GetFieldIDOrDie(env, bspcClazz, "mDisableAod", "Z");
|
||||
gBSPCFieldIds.disableLaunchBoost = GetFieldIDOrDie(env, bspcClazz, "mDisableLaunchBoost", "Z");
|
||||
gBSPCFieldIds.disableOptionalSensors =
|
||||
GetFieldIDOrDie(env, bspcClazz, "mDisableOptionalSensors", "Z");
|
||||
gBSPCFieldIds.disableVibration = GetFieldIDOrDie(env, bspcClazz, "mDisableVibration", "Z");
|
||||
gBSPCFieldIds.enableAdjustBrightness =
|
||||
GetFieldIDOrDie(env, bspcClazz, "mEnableAdjustBrightness", "Z");
|
||||
gBSPCFieldIds.enableDataSaver = GetFieldIDOrDie(env, bspcClazz, "mEnableDataSaver", "Z");
|
||||
gBSPCFieldIds.enableFirewall = GetFieldIDOrDie(env, bspcClazz, "mEnableFirewall", "Z");
|
||||
gBSPCFieldIds.enableNightMode = GetFieldIDOrDie(env, bspcClazz, "mEnableNightMode", "Z");
|
||||
gBSPCFieldIds.enableQuickDoze = GetFieldIDOrDie(env, bspcClazz, "mEnableQuickDoze", "Z");
|
||||
gBSPCFieldIds.forceAllAppsStandby =
|
||||
GetFieldIDOrDie(env, bspcClazz, "mForceAllAppsStandby", "Z");
|
||||
gBSPCFieldIds.forceBackgroundCheck =
|
||||
GetFieldIDOrDie(env, bspcClazz, "mForceBackgroundCheck", "Z");
|
||||
gBSPCFieldIds.locationMode = GetFieldIDOrDie(env, bspcClazz, "mLocationMode", "I");
|
||||
gBSPCFieldIds.soundTriggerMode = GetFieldIDOrDie(env, bspcClazz, "mSoundTriggerMode", "I");
|
||||
|
||||
jniRegisterNativeMethods(env, "android/os/PowerManagerTest", methodTable,
|
||||
sizeof(methodTable) / sizeof(JNINativeMethod));
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
|
||||
156
core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp
Normal file
156
core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 "NativeWorkSourceParcelTest"
|
||||
|
||||
#include "jni.h"
|
||||
#include "ParcelHelper.h"
|
||||
|
||||
#include <android_util_Binder.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
#include <nativehelper/ScopedPrimitiveArray.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <android/WorkSource.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
using namespace android::os;
|
||||
using android::base::StringPrintf;
|
||||
|
||||
namespace android {
|
||||
|
||||
static jobject nativeObtainWorkSourceParcel(JNIEnv* env, jobject /* obj */, jintArray uidArray,
|
||||
jobjectArray nameArray, jint parcelEndMarker) {
|
||||
std::vector<int32_t> uids;
|
||||
std::optional<std::vector<std::optional<String16>>> names = std::nullopt;
|
||||
|
||||
if (uidArray != nullptr) {
|
||||
ScopedIntArrayRO workSourceUids(env, uidArray);
|
||||
for (int i = 0; i < workSourceUids.size(); i++) {
|
||||
uids.push_back(static_cast<int32_t>(workSourceUids[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (nameArray != nullptr) {
|
||||
std::vector<std::optional<String16>> namesVec;
|
||||
for (jint i = 0; i < env->GetArrayLength(nameArray); i++) {
|
||||
jstring string = static_cast<jstring>(env->GetObjectArrayElement(nameArray, i));
|
||||
const char *rawString = env->GetStringUTFChars(string, 0);
|
||||
namesVec.push_back(std::make_optional<String16>(String16(rawString)));
|
||||
}
|
||||
names = std::make_optional(std::move(namesVec));
|
||||
}
|
||||
|
||||
WorkSource ws = WorkSource(uids, names);
|
||||
jobject wsParcel = nativeObtainParcel(env);
|
||||
Parcel* parcel = nativeGetParcelData(env, wsParcel);
|
||||
|
||||
// write WorkSource and if no error write end marker
|
||||
status_t err = ws.writeToParcel(parcel) ?: parcel->writeInt32(parcelEndMarker);
|
||||
|
||||
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, jint parcelEndMarker) {
|
||||
WorkSource ws = {};
|
||||
Parcel* parcel = nativeGetParcelData(env, wsParcel);
|
||||
int32_t endMarker;
|
||||
|
||||
// read WorkSource and if no error read end marker
|
||||
status_t err = ws.readFromParcel(parcel) ?: parcel->readInt32(&endMarker);
|
||||
int32_t dataAvailable = parcel->dataAvail();
|
||||
|
||||
if (err != OK) {
|
||||
ALOGE("WorkSource readFromParcel failed %d", err);
|
||||
}
|
||||
|
||||
// Now we have a native WorkSource object, verify it.
|
||||
if (dataAvailable > 0) { // not all data read from the parcel
|
||||
jniThrowException(env, "java/lang/IllegalArgumentException",
|
||||
StringPrintf("WorkSource contains more data than native read (%d)",
|
||||
dataAvailable).c_str());
|
||||
} else if (endMarker != parcelEndMarker) { // more date than available read from parcel
|
||||
jniThrowException(env, "java/lang/IllegalArgumentException",
|
||||
StringPrintf("WorkSource contains less data than native read").c_str());
|
||||
}
|
||||
|
||||
if (uidArray != nullptr) {
|
||||
ScopedIntArrayRO workSourceUids(env, uidArray);
|
||||
for (int i = 0; i < workSourceUids.size(); i++) {
|
||||
if (ws.getUids().at(i) != static_cast<int32_t>(workSourceUids[i])) {
|
||||
jniThrowException(env, "java/lang/IllegalArgumentException",
|
||||
StringPrintf("WorkSource uid not equal %d %d",
|
||||
ws.getUids().at(i), static_cast<int32_t>(workSourceUids[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<std::optional<String16>> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
|
||||
{
|
||||
JNIEnv* env;
|
||||
|
||||
const JNINativeMethod workSourceMethodTable[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{ "nativeObtainWorkSourceParcel", "([I[Ljava/lang/String;I)Landroid/os/Parcel;",
|
||||
(void*) nativeObtainWorkSourceParcel },
|
||||
{ "nativeUnparcelAndVerifyWorkSource", "(Landroid/os/Parcel;[I[Ljava/lang/String;I)V",
|
||||
(void*) nativeUnparcelAndVerifyWorkSource },
|
||||
};
|
||||
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
loadParcelClass(env);
|
||||
|
||||
jniRegisterNativeMethods(env, "android/os/WorkSourceParcelTest", workSourceMethodTable,
|
||||
sizeof(workSourceMethodTable) / sizeof(JNINativeMethod));
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
} /* namespace android */
|
||||
73
core/tests/coretests/jni/ParcelHelper.h
Normal file
73
core/tests/coretests/jni/ParcelHelper.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
#include <binder/Parcel.h>
|
||||
|
||||
namespace android {
|
||||
static jclass gParcelClazz;
|
||||
static jfieldID gParcelDataFieldID;
|
||||
static jmethodID gParcelObtainMethodID;
|
||||
|
||||
static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
|
||||
jclass clazz = env->FindClass(class_name);
|
||||
LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
static inline jfieldID GetFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
|
||||
const char* field_signature) {
|
||||
jfieldID res = env->GetFieldID(clazz, field_name, field_signature);
|
||||
LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find field %s with signature %s", field_name,
|
||||
field_signature);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline jmethodID GetStaticMethodIDOrDie(JNIEnv* env, jclass clazz,
|
||||
const char* method_name,
|
||||
const char* method_signature) {
|
||||
jmethodID res = env->GetStaticMethodID(clazz, method_name, method_signature);
|
||||
LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s with signature %s", method_name,
|
||||
method_signature);
|
||||
return res;
|
||||
}
|
||||
|
||||
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<Parcel*>(env->GetLongField(obj, gParcelDataFieldID));
|
||||
if (parcel && parcel->objectsCount() != 0) {
|
||||
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid parcel object.");
|
||||
}
|
||||
parcel->setDataPosition(0);
|
||||
return parcel;
|
||||
}
|
||||
|
||||
static void loadParcelClass(JNIEnv* env) {
|
||||
gParcelClazz = FindClassOrDie(env, "android/os/Parcel");
|
||||
gParcelDataFieldID = GetFieldIDOrDie(env, gParcelClazz, "mNativePtr", "J");
|
||||
gParcelObtainMethodID =
|
||||
GetStaticMethodIDOrDie(env, gParcelClazz, "obtain", "()Landroid/os/Parcel;");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,9 +49,6 @@ 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, int soundTriggerMode,
|
||||
float brightnessFactor);
|
||||
@@ -299,54 +296,6 @@ public class PowerManagerTest extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -421,43 +370,6 @@ public class PowerManagerTest extends AndroidTestCase {
|
||||
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.
|
||||
*
|
||||
|
||||
139
core/tests/coretests/src/android/os/WorkSourceParcelTest.java
Normal file
139
core/tests/coretests/src/android/os/WorkSourceParcelTest.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.
|
||||
*/
|
||||
|
||||
package android.os;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class WorkSourceParcelTest {
|
||||
/**
|
||||
* END_OF_PARCEL_MARKER is added at the end of Parcel on native or java side on write and
|
||||
* then read on java or native side on read. This way we can ensure that no extra data
|
||||
* is read from the parcel.
|
||||
*/
|
||||
private static final int END_OF_PARCEL_MARKER = 99;
|
||||
|
||||
private native Parcel nativeObtainWorkSourceParcel(int[] uids, String[] names,
|
||||
int parcelEndMarker);
|
||||
|
||||
private native void nativeUnparcelAndVerifyWorkSource(Parcel parcel, int[] uids,
|
||||
String[] names, int parcelEndMarker);
|
||||
|
||||
static {
|
||||
System.loadLibrary("worksourceparceltest_jni");
|
||||
}
|
||||
/**
|
||||
* Confirm that we can pass WorkSource from native to Java.
|
||||
*/
|
||||
@Test
|
||||
public void testWorkSourceNativeToJava() {
|
||||
final int[] uids1 = {1000};
|
||||
final int[] uids2 = {1000, 2000};
|
||||
final String[] names1 = {"testWorkSource1"};
|
||||
final String[] names2 = {"testWorkSource1", "testWorkSource2"};
|
||||
unparcelWorkSourceFromNativeAndVerify(/* uids= */ null , /* names= */ null);
|
||||
unparcelWorkSourceFromNativeAndVerify(uids1, /* names= */ null);
|
||||
unparcelWorkSourceFromNativeAndVerify(uids2, /* names= */ null);
|
||||
//TODO(b/273752423)
|
||||
unparcelWorkSourceFromNativeAndVerify(/* uids= */ null , names1);
|
||||
unparcelWorkSourceFromNativeAndVerify(uids1, names1);
|
||||
unparcelWorkSourceFromNativeAndVerify(uids2, names2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that we can pass WorkSource from Java to native.
|
||||
*/
|
||||
@Test
|
||||
public void testWorkSourceJavaToNative() {
|
||||
final int[] uids1 = {1000};
|
||||
final int[] uids2 = {1000, 2000};
|
||||
final String[] names1 = {"testGetWorkSource1"};
|
||||
final String[] names2 = {"testGetWorkSource1", "testGetWorkSource2"};
|
||||
//TODO(b/273752423)
|
||||
//parcelWorkSourceToNativeAndVerify(/* uids= */ null , /* names= */ null );
|
||||
parcelWorkSourceToNativeAndVerify(uids1, /* names= */ null);
|
||||
parcelWorkSourceToNativeAndVerify(uids2, /* names= */ null);
|
||||
parcelWorkSourceToNativeAndVerify(uids1, names1);
|
||||
parcelWorkSourceToNativeAndVerify(uids2, names2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
// END_OF_PARCEL_MARKER is written at the end of parcel
|
||||
Parcel wsParcel = nativeObtainWorkSourceParcel(uids, names, END_OF_PARCEL_MARKER);
|
||||
// read WorkSource created on native side
|
||||
WorkSource ws = WorkSource.CREATOR.createFromParcel(wsParcel);
|
||||
// read end marker written on native side
|
||||
int endMarker = wsParcel.readInt();
|
||||
|
||||
assertEquals(0, wsParcel.dataAvail()); // we have read everything
|
||||
assertEquals(END_OF_PARCEL_MARKER, endMarker); // endMarkers match
|
||||
|
||||
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.getPackageName(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 uid : uids) {
|
||||
ws.add(uid);
|
||||
}
|
||||
} else {
|
||||
assertEquals(uids.length, names.length);
|
||||
for (int i = 0; i < uids.length; i++) {
|
||||
ws.add(uids[i], names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Parcel wsParcel = Parcel.obtain();
|
||||
// write WorkSource on java side
|
||||
ws.writeToParcel(wsParcel, 0 /* flags */);
|
||||
// write end marker on java side
|
||||
wsParcel.writeInt(END_OF_PARCEL_MARKER);
|
||||
wsParcel.setDataPosition(0);
|
||||
//Verify parcel and end marker on native side
|
||||
nativeUnparcelAndVerifyWorkSource(wsParcel, uids, names, END_OF_PARCEL_MARKER);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user