Loading core/java/android/os/WorkSource.java +27 −36 Original line number Diff line number Diff line Loading @@ -12,11 +12,11 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** * Describes the source of some work that may be done by someone else. Loading @@ -29,9 +29,13 @@ public class WorkSource implements Parcelable { @UnsupportedAppUsage int mNum; @UnsupportedAppUsage int[] mUids; @NonNull int[] mUids = new int[0]; @UnsupportedAppUsage @Nullable String[] mNames; private ArrayList<WorkChain> mChains; Loading Loading @@ -73,13 +77,8 @@ public class WorkSource implements Parcelable { return; } mNum = orig.mNum; if (orig.mUids != null) { mUids = orig.mUids.clone(); mNames = orig.mNames != null ? orig.mNames.clone() : null; } else { mUids = null; mNames = null; } if (orig.mChains != null) { // Make a copy of all WorkChains that exist on |orig| since they are mutable. Loading Loading @@ -114,7 +113,7 @@ public class WorkSource implements Parcelable { */ @SystemApi public WorkSource(int uid, @NonNull String packageName) { Preconditions.checkNotNull(packageName, "packageName can't be null"); Objects.requireNonNull(packageName, "packageName can't be null"); mNum = 1; mUids = new int[] { uid, 0 }; mNames = new String[] { packageName, null }; Loading @@ -124,7 +123,7 @@ public class WorkSource implements Parcelable { @UnsupportedAppUsage WorkSource(Parcel in) { mNum = in.readInt(); mUids = in.createIntArray(); mUids = Objects.requireNonNullElse(in.createIntArray(), new int[0]); mNames = in.createStringArray(); int numChains = in.readInt(); Loading Loading @@ -318,15 +317,11 @@ public class WorkSource implements Parcelable { */ public void set(WorkSource other) { if (other == null) { mNum = 0; if (mChains != null) { mChains.clear(); } clear(); return; } mNum = other.mNum; if (other.mUids != null) { if (mUids != null && mUids.length >= mNum) { if (mUids.length >= mNum) { // this has more data than other System.arraycopy(other.mUids, 0, mUids, 0, mNum); } else { mUids = other.mUids.clone(); Loading @@ -340,10 +335,6 @@ public class WorkSource implements Parcelable { } else { mNames = null; } } else { mUids = null; mNames = null; } if (other.mChains != null) { if (mChains != null) { Loading @@ -361,7 +352,7 @@ public class WorkSource implements Parcelable { /** @hide */ public void set(int uid) { mNum = 1; if (mUids == null) mUids = new int[2]; if (mUids.length == 0) mUids = new int[2]; mUids[0] = uid; mNames = null; if (mChains != null) { Loading @@ -375,7 +366,7 @@ public class WorkSource implements Parcelable { throw new NullPointerException("Name can't be null"); } mNum = 1; if (mUids == null) { if (mUids.length == 0) { mUids = new int[2]; mNames = new String[2]; } Loading Loading @@ -727,7 +718,7 @@ public class WorkSource implements Parcelable { if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": insert " + uids2[i2]); changed = true; if (uids1 == null) { if (uids1.length == 0) { uids1 = new int[4]; uids1[0] = uids2[i2]; } else if (N1 >= uids1.length) { Loading Loading @@ -866,7 +857,7 @@ public class WorkSource implements Parcelable { private void insert(int index, int uid) { if (DEBUG) Log.d(TAG, "Insert in " + this + " @ " + index + " uid " + uid); if (mUids == null) { if (mUids.length == 0) { mUids = new int[4]; mUids[0] = uid; mNum = 1; Loading @@ -891,7 +882,7 @@ public class WorkSource implements Parcelable { } private void insert(int index, int uid, String name) { if (mUids == null) { if (mNum == 0) { mUids = new int[4]; mUids[0] = uid; mNames = new String[4]; Loading Loading @@ -1244,8 +1235,8 @@ public class WorkSource implements Parcelable { proto.end(workSourceToken); } public static final @android.annotation.NonNull Parcelable.Creator<WorkSource> CREATOR = new Parcelable.Creator<WorkSource>() { @NonNull public static final Parcelable.Creator<WorkSource> CREATOR = new Parcelable.Creator<>() { public WorkSource createFromParcel(Parcel in) { return new WorkSource(in); } Loading core/tests/coretests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ android_test { ], jni_libs: [ "libpowermanagertest_jni", "libworksourceparceltest_jni", ], sdk_version: "core_platform", Loading core/tests/coretests/jni/Android.bp +24 −0 Original line number Diff line number Diff line Loading @@ -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, } core/tests/coretests/jni/NativePowerManagerTest.cpp +32 −140 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define LOG_TAG "NativePowerManagerTest" #include "jni.h" #include "ParcelHelper.h" #include <android_util_Binder.h> #include <binder/IServiceManager.h> Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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", Loading @@ -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; } Loading core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * 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 */ Loading
core/java/android/os/WorkSource.java +27 −36 Original line number Diff line number Diff line Loading @@ -12,11 +12,11 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** * Describes the source of some work that may be done by someone else. Loading @@ -29,9 +29,13 @@ public class WorkSource implements Parcelable { @UnsupportedAppUsage int mNum; @UnsupportedAppUsage int[] mUids; @NonNull int[] mUids = new int[0]; @UnsupportedAppUsage @Nullable String[] mNames; private ArrayList<WorkChain> mChains; Loading Loading @@ -73,13 +77,8 @@ public class WorkSource implements Parcelable { return; } mNum = orig.mNum; if (orig.mUids != null) { mUids = orig.mUids.clone(); mNames = orig.mNames != null ? orig.mNames.clone() : null; } else { mUids = null; mNames = null; } if (orig.mChains != null) { // Make a copy of all WorkChains that exist on |orig| since they are mutable. Loading Loading @@ -114,7 +113,7 @@ public class WorkSource implements Parcelable { */ @SystemApi public WorkSource(int uid, @NonNull String packageName) { Preconditions.checkNotNull(packageName, "packageName can't be null"); Objects.requireNonNull(packageName, "packageName can't be null"); mNum = 1; mUids = new int[] { uid, 0 }; mNames = new String[] { packageName, null }; Loading @@ -124,7 +123,7 @@ public class WorkSource implements Parcelable { @UnsupportedAppUsage WorkSource(Parcel in) { mNum = in.readInt(); mUids = in.createIntArray(); mUids = Objects.requireNonNullElse(in.createIntArray(), new int[0]); mNames = in.createStringArray(); int numChains = in.readInt(); Loading Loading @@ -318,15 +317,11 @@ public class WorkSource implements Parcelable { */ public void set(WorkSource other) { if (other == null) { mNum = 0; if (mChains != null) { mChains.clear(); } clear(); return; } mNum = other.mNum; if (other.mUids != null) { if (mUids != null && mUids.length >= mNum) { if (mUids.length >= mNum) { // this has more data than other System.arraycopy(other.mUids, 0, mUids, 0, mNum); } else { mUids = other.mUids.clone(); Loading @@ -340,10 +335,6 @@ public class WorkSource implements Parcelable { } else { mNames = null; } } else { mUids = null; mNames = null; } if (other.mChains != null) { if (mChains != null) { Loading @@ -361,7 +352,7 @@ public class WorkSource implements Parcelable { /** @hide */ public void set(int uid) { mNum = 1; if (mUids == null) mUids = new int[2]; if (mUids.length == 0) mUids = new int[2]; mUids[0] = uid; mNames = null; if (mChains != null) { Loading @@ -375,7 +366,7 @@ public class WorkSource implements Parcelable { throw new NullPointerException("Name can't be null"); } mNum = 1; if (mUids == null) { if (mUids.length == 0) { mUids = new int[2]; mNames = new String[2]; } Loading Loading @@ -727,7 +718,7 @@ public class WorkSource implements Parcelable { if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": insert " + uids2[i2]); changed = true; if (uids1 == null) { if (uids1.length == 0) { uids1 = new int[4]; uids1[0] = uids2[i2]; } else if (N1 >= uids1.length) { Loading Loading @@ -866,7 +857,7 @@ public class WorkSource implements Parcelable { private void insert(int index, int uid) { if (DEBUG) Log.d(TAG, "Insert in " + this + " @ " + index + " uid " + uid); if (mUids == null) { if (mUids.length == 0) { mUids = new int[4]; mUids[0] = uid; mNum = 1; Loading @@ -891,7 +882,7 @@ public class WorkSource implements Parcelable { } private void insert(int index, int uid, String name) { if (mUids == null) { if (mNum == 0) { mUids = new int[4]; mUids[0] = uid; mNames = new String[4]; Loading Loading @@ -1244,8 +1235,8 @@ public class WorkSource implements Parcelable { proto.end(workSourceToken); } public static final @android.annotation.NonNull Parcelable.Creator<WorkSource> CREATOR = new Parcelable.Creator<WorkSource>() { @NonNull public static final Parcelable.Creator<WorkSource> CREATOR = new Parcelable.Creator<>() { public WorkSource createFromParcel(Parcel in) { return new WorkSource(in); } Loading
core/tests/coretests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ android_test { ], jni_libs: [ "libpowermanagertest_jni", "libworksourceparceltest_jni", ], sdk_version: "core_platform", Loading
core/tests/coretests/jni/Android.bp +24 −0 Original line number Diff line number Diff line Loading @@ -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, }
core/tests/coretests/jni/NativePowerManagerTest.cpp +32 −140 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define LOG_TAG "NativePowerManagerTest" #include "jni.h" #include "ParcelHelper.h" #include <android_util_Binder.h> #include <binder/IServiceManager.h> Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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", Loading @@ -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; } Loading
core/tests/coretests/jni/NativeWorkSourceParcelTest.cpp 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * 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 */