• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base;
6 
7 import org.jni_zero.JNINamespace;
8 import org.jni_zero.NativeMethods;
9 
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.Map;
13 
14 /**
15  * Java accessor for state of feature flags and their field trial parameters.
16  *
17  * This class provides methods to access values of feature flags listed in a native feature list
18  * and to access their field trial parameters.
19  *
20  * This class needs to be derived for each native feature list (such as a component's feature list)
21  * and the derived class must implement the abstract {@link #getNativeMap()} by calling a JNI method
22  * to get the pointer to the base::android::FeatureMap. The derived class will provide Java code
23  * access to the list of base::Features passed to the base::android::FeatureMap.
24  */
25 @JNINamespace("base::android")
26 public abstract class FeatureMap {
27     private long mNativeMapPtr;
28 
FeatureMap()29     protected FeatureMap() {}
30 
31     /**
32      * Should return the native pointer to the specific base::FeatureMap for the component/layer.
33      */
getNativeMap()34     protected abstract long getNativeMap();
35 
36     /**
37      * Returns whether the specified feature is enabled or not.
38      *
39      * Calling this has the side effect of bucketing this client, which may cause an experiment to
40      * be marked as active.
41      *
42      * Should be called only after native is loaded. If {@link FeatureList#isInitialized()} returns
43      * true, this method is safe to call.  In tests, this will return any values set through
44      * {@link FeatureList#setTestFeatures(Map)}, even before native is loaded.
45      *
46      * @param featureName The name of the feature to query.
47      * @return Whether the feature is enabled or not.
48      */
isEnabledInNative(String featureName)49     public boolean isEnabledInNative(String featureName) {
50         Boolean testValue = FeatureList.getTestValueForFeature(featureName);
51         if (testValue != null) return testValue;
52         ensureNativeMapInit();
53         return FeatureMapJni.get().isEnabled(mNativeMapPtr, featureName);
54     }
55 
56     /**
57      * Returns a field trial param for the specified feature.
58      *
59      * @param featureName The name of the feature to retrieve a param for.
60      * @param paramName The name of the param for which to get as an integer.
61      * @return The parameter value as a String. The string is empty if the feature does not exist or
62      *   the specified parameter does not exist.
63      */
getFieldTrialParamByFeature(String featureName, String paramName)64     public String getFieldTrialParamByFeature(String featureName, String paramName) {
65         String testValue = FeatureList.getTestValueForFieldTrialParam(featureName, paramName);
66         if (testValue != null) return testValue;
67         if (FeatureList.hasTestFeatures()) return "";
68         ensureNativeMapInit();
69         return FeatureMapJni.get()
70                 .getFieldTrialParamByFeature(mNativeMapPtr, featureName, paramName);
71     }
72 
73     /**
74      * Returns a field trial param as a boolean for the specified feature.
75      *
76      * @param featureName The name of the feature to retrieve a param for.
77      * @param paramName The name of the param for which to get as an integer.
78      * @param defaultValue The boolean value to use if the param is not available.
79      * @return The parameter value as a boolean. Default value if the feature does not exist or the
80      *         specified parameter does not exist or its string value is neither "true" nor "false".
81      */
getFieldTrialParamByFeatureAsBoolean( String featureName, String paramName, boolean defaultValue)82     public boolean getFieldTrialParamByFeatureAsBoolean(
83             String featureName, String paramName, boolean defaultValue) {
84         String testValue = FeatureList.getTestValueForFieldTrialParam(featureName, paramName);
85         if (testValue != null) return Boolean.valueOf(testValue);
86         if (FeatureList.hasTestFeatures()) return defaultValue;
87         ensureNativeMapInit();
88         return FeatureMapJni.get()
89                 .getFieldTrialParamByFeatureAsBoolean(
90                         mNativeMapPtr, featureName, paramName, defaultValue);
91     }
92 
93     /**
94      * Returns a field trial param as an int for the specified feature.
95      *
96      * @param featureName The name of the feature to retrieve a param for.
97      * @param paramName The name of the param for which to get as an integer.
98      * @param defaultValue The integer value to use if the param is not available.
99      * @return The parameter value as an int. Default value if the feature does not exist or the
100      *         specified parameter does not exist or its string value does not represent an int.
101      */
getFieldTrialParamByFeatureAsInt( String featureName, String paramName, int defaultValue)102     public int getFieldTrialParamByFeatureAsInt(
103             String featureName, String paramName, int defaultValue) {
104         String testValue = FeatureList.getTestValueForFieldTrialParam(featureName, paramName);
105         if (testValue != null) return Integer.valueOf(testValue);
106         if (FeatureList.hasTestFeatures()) return defaultValue;
107         ensureNativeMapInit();
108         return FeatureMapJni.get()
109                 .getFieldTrialParamByFeatureAsInt(
110                         mNativeMapPtr, featureName, paramName, defaultValue);
111     }
112 
113     /**
114      * Returns a field trial param as a double for the specified feature.
115      *
116      * @param featureName The name of the feature to retrieve a param for.
117      * @param paramName The name of the param for which to get as an integer.
118      * @param defaultValue The double value to use if the param is not available.
119      * @return The parameter value as a double. Default value if the feature does not exist or the
120      *         specified parameter does not exist or its string value does not represent a double.
121      */
getFieldTrialParamByFeatureAsDouble( String featureName, String paramName, double defaultValue)122     public double getFieldTrialParamByFeatureAsDouble(
123             String featureName, String paramName, double defaultValue) {
124         String testValue = FeatureList.getTestValueForFieldTrialParam(featureName, paramName);
125         if (testValue != null) return Double.valueOf(testValue);
126         if (FeatureList.hasTestFeatures()) return defaultValue;
127         ensureNativeMapInit();
128         return FeatureMapJni.get()
129                 .getFieldTrialParamByFeatureAsDouble(
130                         mNativeMapPtr, featureName, paramName, defaultValue);
131     }
132 
133     /** Returns all the field trial parameters for the specified feature. */
getFieldTrialParamsForFeature(String featureName)134     public Map<String, String> getFieldTrialParamsForFeature(String featureName) {
135         Map<String, String> testValues =
136                 FeatureList.getTestValuesForAllFieldTrialParamsForFeature(featureName);
137         if (testValues != null) return testValues;
138         if (FeatureList.hasTestFeatures()) return Collections.emptyMap();
139 
140         ensureNativeMapInit();
141         Map<String, String> result = new HashMap<>();
142         String[] flattenedParams =
143                 FeatureMapJni.get()
144                         .getFlattedFieldTrialParamsForFeature(mNativeMapPtr, featureName);
145         for (int i = 0; i < flattenedParams.length; i += 2) {
146             result.put(flattenedParams[i], flattenedParams[i + 1]);
147         }
148         return result;
149     }
150 
151     /** Create a {@link MutableFlagWithSafeDefault} in this FeatureMap. */
mutableFlagWithSafeDefault( String featureName, boolean defaultValue)152     public MutableFlagWithSafeDefault mutableFlagWithSafeDefault(
153             String featureName, boolean defaultValue) {
154         return new MutableFlagWithSafeDefault(this, featureName, defaultValue);
155     }
156 
ensureNativeMapInit()157     private void ensureNativeMapInit() {
158         assert FeatureList.isNativeInitialized();
159 
160         if (mNativeMapPtr == 0) {
161             mNativeMapPtr = getNativeMap();
162             assert mNativeMapPtr != 0;
163         }
164     }
165 
166     @NativeMethods
167     interface Natives {
isEnabled(long featureMap, String featureName)168         boolean isEnabled(long featureMap, String featureName);
169 
getFieldTrialParamByFeature(long featureMap, String featureName, String paramName)170         String getFieldTrialParamByFeature(long featureMap, String featureName, String paramName);
171 
getFieldTrialParamByFeatureAsInt( long featureMap, String featureName, String paramName, int defaultValue)172         int getFieldTrialParamByFeatureAsInt(
173                 long featureMap, String featureName, String paramName, int defaultValue);
174 
getFieldTrialParamByFeatureAsDouble( long featureMap, String featureName, String paramName, double defaultValue)175         double getFieldTrialParamByFeatureAsDouble(
176                 long featureMap, String featureName, String paramName, double defaultValue);
177 
getFieldTrialParamByFeatureAsBoolean( long featureMap, String featureName, String paramName, boolean defaultValue)178         boolean getFieldTrialParamByFeatureAsBoolean(
179                 long featureMap, String featureName, String paramName, boolean defaultValue);
180 
getFlattedFieldTrialParamsForFeature(long featureMap, String featureName)181         String[] getFlattedFieldTrialParamsForFeature(long featureMap, String featureName);
182     }
183 }
184