| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.base; |
| |
| import org.jni_zero.JNINamespace; |
| import org.jni_zero.NativeMethods; |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * Java accessor for state of feature flags and their field trial parameters. |
| * |
| * This class provides methods to access values of feature flags listed in a native feature list |
| * and to access their field trial parameters. |
| * |
| * This class needs to be derived for each native feature list (such as a component's feature list) |
| * and the derived class must implement the abstract {@link #getNativeMap()} by calling a JNI method |
| * to get the pointer to the base::android::FeatureMap. The derived class will provide Java code |
| * access to the list of base::Features passed to the base::android::FeatureMap. |
| */ |
| @JNINamespace("base::android") |
| public abstract class FeatureMap { |
| private long mNativeMapPtr; |
| |
| protected FeatureMap() {} |
| |
| /** |
| * Should return the native pointer to the specific base::FeatureMap for the component/layer. |
| */ |
| protected abstract long getNativeMap(); |
| |
| /** |
| * Returns whether the specified feature is enabled or not. |
| * |
| * Calling this has the side effect of bucketing this client, which may cause an experiment to |
| * be marked as active. |
| * |
| * Should be called only after native is loaded. If {@link FeatureList#isInitialized()} returns |
| * true, this method is safe to call. In tests, this will return any values set through |
| * {@link FeatureList#setTestFeatures(Map)}, even before native is loaded. |
| * |
| * @param featureName The name of the feature to query. |
| * @return Whether the feature is enabled or not. |
| */ |
| public boolean isEnabledInNative(String featureName) { |
| Boolean testValue = FeatureList.getTestValueForFeature(featureName); |
| if (testValue != null) return testValue; |
| ensureNativeMapInit(); |
| return FeatureMapJni.get().isEnabled(mNativeMapPtr, featureName); |
| } |
| |
| /** |
| * Returns a field trial param for the specified feature. |
| * |
| * @param featureName The name of the feature to retrieve a param for. |
| * @param paramName The name of the param for which to get as an integer. |
| * @return The parameter value as a String. The string is empty if the feature does not exist or |
| * the specified parameter does not exist. |
| */ |
| public String getFieldTrialParamByFeature(String featureName, String paramName) { |
| String testValue = FeatureList.getTestValueForFieldTrialParam(featureName, paramName); |
| if (testValue != null) return testValue; |
| if (FeatureList.hasTestFeatures()) return ""; |
| ensureNativeMapInit(); |
| return FeatureMapJni.get() |
| .getFieldTrialParamByFeature(mNativeMapPtr, featureName, paramName); |
| } |
| |
| /** |
| * Returns a field trial param as a boolean for the specified feature. |
| * |
| * @param featureName The name of the feature to retrieve a param for. |
| * @param paramName The name of the param for which to get as an integer. |
| * @param defaultValue The boolean value to use if the param is not available. |
| * @return The parameter value as a boolean. Default value if the feature does not exist or the |
| * specified parameter does not exist or its string value is neither "true" nor "false". |
| */ |
| public boolean getFieldTrialParamByFeatureAsBoolean( |
| String featureName, String paramName, boolean defaultValue) { |
| String testValue = FeatureList.getTestValueForFieldTrialParam(featureName, paramName); |
| if (testValue != null) return Boolean.valueOf(testValue); |
| if (FeatureList.hasTestFeatures()) return defaultValue; |
| ensureNativeMapInit(); |
| return FeatureMapJni.get() |
| .getFieldTrialParamByFeatureAsBoolean( |
| mNativeMapPtr, featureName, paramName, defaultValue); |
| } |
| |
| /** |
| * Returns a field trial param as an int for the specified feature. |
| * |
| * @param featureName The name of the feature to retrieve a param for. |
| * @param paramName The name of the param for which to get as an integer. |
| * @param defaultValue The integer value to use if the param is not available. |
| * @return The parameter value as an int. Default value if the feature does not exist or the |
| * specified parameter does not exist or its string value does not represent an int. |
| */ |
| public int getFieldTrialParamByFeatureAsInt( |
| String featureName, String paramName, int defaultValue) { |
| String testValue = FeatureList.getTestValueForFieldTrialParam(featureName, paramName); |
| if (testValue != null) return Integer.valueOf(testValue); |
| if (FeatureList.hasTestFeatures()) return defaultValue; |
| ensureNativeMapInit(); |
| return FeatureMapJni.get() |
| .getFieldTrialParamByFeatureAsInt( |
| mNativeMapPtr, featureName, paramName, defaultValue); |
| } |
| |
| /** |
| * Returns a field trial param as a double for the specified feature. |
| * |
| * @param featureName The name of the feature to retrieve a param for. |
| * @param paramName The name of the param for which to get as an integer. |
| * @param defaultValue The double value to use if the param is not available. |
| * @return The parameter value as a double. Default value if the feature does not exist or the |
| * specified parameter does not exist or its string value does not represent a double. |
| */ |
| public double getFieldTrialParamByFeatureAsDouble( |
| String featureName, String paramName, double defaultValue) { |
| String testValue = FeatureList.getTestValueForFieldTrialParam(featureName, paramName); |
| if (testValue != null) return Double.valueOf(testValue); |
| if (FeatureList.hasTestFeatures()) return defaultValue; |
| ensureNativeMapInit(); |
| return FeatureMapJni.get() |
| .getFieldTrialParamByFeatureAsDouble( |
| mNativeMapPtr, featureName, paramName, defaultValue); |
| } |
| |
| /** Returns all the field trial parameters for the specified feature. */ |
| public Map<String, String> getFieldTrialParamsForFeature(String featureName) { |
| Map<String, String> testValues = |
| FeatureList.getTestValuesForAllFieldTrialParamsForFeature(featureName); |
| if (testValues != null) return testValues; |
| if (FeatureList.hasTestFeatures()) return Collections.emptyMap(); |
| |
| ensureNativeMapInit(); |
| Map<String, String> result = new HashMap<>(); |
| String[] flattenedParams = |
| FeatureMapJni.get() |
| .getFlattedFieldTrialParamsForFeature(mNativeMapPtr, featureName); |
| for (int i = 0; i < flattenedParams.length; i += 2) { |
| result.put(flattenedParams[i], flattenedParams[i + 1]); |
| } |
| return result; |
| } |
| |
| /** Create a {@link MutableFlagWithSafeDefault} in this FeatureMap. */ |
| public MutableFlagWithSafeDefault mutableFlagWithSafeDefault( |
| String featureName, boolean defaultValue) { |
| return new MutableFlagWithSafeDefault(this, featureName, defaultValue); |
| } |
| |
| private void ensureNativeMapInit() { |
| assert FeatureList.isNativeInitialized(); |
| |
| if (mNativeMapPtr == 0) { |
| mNativeMapPtr = getNativeMap(); |
| assert mNativeMapPtr != 0; |
| } |
| } |
| |
| @NativeMethods |
| interface Natives { |
| boolean isEnabled(long featureMap, String featureName); |
| |
| String getFieldTrialParamByFeature(long featureMap, String featureName, String paramName); |
| |
| int getFieldTrialParamByFeatureAsInt( |
| long featureMap, String featureName, String paramName, int defaultValue); |
| |
| double getFieldTrialParamByFeatureAsDouble( |
| long featureMap, String featureName, String paramName, double defaultValue); |
| |
| boolean getFieldTrialParamByFeatureAsBoolean( |
| long featureMap, String featureName, String paramName, boolean defaultValue); |
| |
| String[] getFlattedFieldTrialParamsForFeature(long featureMap, String featureName); |
| } |
| } |