blob: cf851dc6f2ff69a2f1e1b06e20d59a414d74000c [file] [log] [blame]
// 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);
}
}