diff options
author | 2023-07-12 18:18:39 +0000 | |
---|---|---|
committer | 2023-07-12 18:18:39 +0000 | |
commit | 0f40cb16a7bd899545a398645856a2fe26022f66 (patch) | |
tree | 4d0ef973650e912cca25d81096e7f69400770ed3 | |
parent | c44e351a789e269038e771163e9e0a4a3f109253 (diff) |
Revert "Connect FeatureFlags with FeatureFlagsService."
Revert submission 23727772-b279054964-flag-api-udc-qpr-dev
Reason for revert: b/290929382
Reverted changes: /q/submissionid:23727772-b279054964-flag-api-udc-qpr-dev
Change-Id: I5ebfe5ac5ac518f33c4bd3beaa4cd018b43242cf
-rw-r--r-- | core/java/android/flags/BooleanFlag.java | 25 | ||||
-rw-r--r-- | core/java/android/flags/BooleanFlagBase.java | 54 | ||||
-rw-r--r-- | core/java/android/flags/DynamicBooleanFlag.java | 22 | ||||
-rw-r--r-- | core/java/android/flags/FeatureFlags.java | 279 | ||||
-rw-r--r-- | core/java/android/flags/FeatureFlagsFake.java | 78 | ||||
-rw-r--r-- | core/java/android/flags/FusedOffFlag.java | 31 | ||||
-rw-r--r-- | core/java/android/flags/FusedOnFlag.java | 31 | ||||
-rw-r--r-- | core/java/android/flags/SyncableFlag.java | 9 | ||||
-rw-r--r-- | core/tests/coretests/src/android/flags/FeatureFlagsTest.java | 127 | ||||
-rw-r--r-- | core/tests/coretests/src/android/flags/IFeatureFlagsFake.java | 63 | ||||
-rw-r--r-- | services/flags/java/com/android/server/flags/DynamicFlagBinderDelegate.java | 6 | ||||
-rw-r--r-- | services/flags/java/com/android/server/flags/FeatureFlagsBinder.java | 10 |
12 files changed, 143 insertions, 592 deletions
diff --git a/core/java/android/flags/BooleanFlag.java b/core/java/android/flags/BooleanFlag.java index ae9ccf8c52c3..5519961a917f 100644 --- a/core/java/android/flags/BooleanFlag.java +++ b/core/java/android/flags/BooleanFlag.java @@ -25,7 +25,9 @@ import android.annotation.NonNull; * * @hide */ -public class BooleanFlag extends BooleanFlagBase { +public class BooleanFlag implements Flag<Boolean> { + private final String mNamespace; + private final String mName; private final boolean mDefault; /** @@ -34,7 +36,8 @@ public class BooleanFlag extends BooleanFlagBase { * @param defaultValue The value of this flag if no other override is present. */ BooleanFlag(String namespace, String name, boolean defaultValue) { - super(namespace, name); + mNamespace = namespace; + mName = name; mDefault = defaultValue; } @@ -43,4 +46,22 @@ public class BooleanFlag extends BooleanFlagBase { public Boolean getDefault() { return mDefault; } + + @Override + @NonNull + public String getNamespace() { + return mNamespace; + } + + @Override + @NonNull + public String getName() { + return mName; + } + + @Override + @NonNull + public String toString() { + return getNamespace() + "." + getName() + "[" + getDefault() + "]"; + } } diff --git a/core/java/android/flags/BooleanFlagBase.java b/core/java/android/flags/BooleanFlagBase.java deleted file mode 100644 index f4141ecab01b..000000000000 --- a/core/java/android/flags/BooleanFlagBase.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.flags; - -import android.annotation.NonNull; - -abstract class BooleanFlagBase implements Flag<Boolean> { - - private final String mNamespace; - private final String mName; - - /** - * @param namespace A namespace for this flag. See {@link android.provider.DeviceConfig}. - * @param name A name for this flag. - */ - BooleanFlagBase(String namespace, String name) { - mNamespace = namespace; - mName = name; - } - - public abstract Boolean getDefault(); - - @Override - @NonNull - public String getNamespace() { - return mNamespace; - } - - @Override - @NonNull - public String getName() { - return mName; - } - - @Override - @NonNull - public String toString() { - return getNamespace() + "." + getName() + "[" + getDefault() + "]"; - } -} diff --git a/core/java/android/flags/DynamicBooleanFlag.java b/core/java/android/flags/DynamicBooleanFlag.java index 92009c60d91a..d76fd9ec9a3c 100644 --- a/core/java/android/flags/DynamicBooleanFlag.java +++ b/core/java/android/flags/DynamicBooleanFlag.java @@ -23,8 +23,10 @@ package android.flags; * * @hide */ -public class DynamicBooleanFlag extends BooleanFlagBase implements DynamicFlag<Boolean> { +public class DynamicBooleanFlag implements DynamicFlag<Boolean> { + private final String mNamespace; + private final String mName; private final boolean mDefault; /** @@ -33,12 +35,28 @@ public class DynamicBooleanFlag extends BooleanFlagBase implements DynamicFlag<B * @param defaultValue The value of this flag if no other override is present. */ DynamicBooleanFlag(String namespace, String name, boolean defaultValue) { - super(namespace, name); + mNamespace = namespace; + mName = name; mDefault = defaultValue; } @Override + public String getNamespace() { + return mNamespace; + } + + @Override + public String getName() { + return mName; + } + + @Override public Boolean getDefault() { return mDefault; } + + @Override + public String toString() { + return getNamespace() + "." + getName() + "[" + getDefault() + "]"; + } } diff --git a/core/java/android/flags/FeatureFlags.java b/core/java/android/flags/FeatureFlags.java index 2c722a486e81..c7d9d57e68b5 100644 --- a/core/java/android/flags/FeatureFlags.java +++ b/core/java/android/flags/FeatureFlags.java @@ -17,19 +17,8 @@ package android.flags; import android.annotation.NonNull; -import android.content.Context; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.util.ArraySet; -import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -43,20 +32,14 @@ import java.util.Set; * @hide */ public class FeatureFlags { - private static final String TAG = "FeatureFlags"; private static FeatureFlags sInstance; private static final Object sInstanceLock = new Object(); - private final Set<Flag<?>> mKnownFlags = new ArraySet<>(); - private final Set<Flag<?>> mDirtyFlags = new ArraySet<>(); - - private IFeatureFlags mIFeatureFlags; - private final Map<String, Map<String, Boolean>> mBooleanOverrides = new HashMap<>(); private final Set<ChangeListener> mListeners = new HashSet<>(); /** * Obtain a per-process instance of FeatureFlags. - * @return A singleton instance of {@link FeatureFlags}. + * @return */ @NonNull public static FeatureFlags getInstance() { @@ -69,124 +52,7 @@ public class FeatureFlags { return sInstance; } - /** See {@link FeatureFlagsFake}. */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public static void setInstance(FeatureFlags instance) { - synchronized (sInstanceLock) { - sInstance = instance; - } - } - - private final IFeatureFlagsCallback mIFeatureFlagsCallback = new IFeatureFlagsCallback.Stub() { - @Override - public void onFlagChange(SyncableFlag flag) { - for (Flag<?> f : mKnownFlags) { - if (flagEqualsSyncableFlag(f, flag)) { - if (f instanceof DynamicFlag<?>) { - if (f instanceof DynamicBooleanFlag) { - String value = flag.getValue(); - if (value == null) { // Null means any existing overrides were erased. - value = ((DynamicBooleanFlag) f).getDefault().toString(); - } - addBooleanOverride(flag.getNamespace(), flag.getName(), value); - } - FeatureFlags.this.onFlagChange((DynamicFlag<?>) f); - } - break; - } - } - } - }; - - private FeatureFlags() { - this(null); - } - - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public FeatureFlags(IFeatureFlags iFeatureFlags) { - mIFeatureFlags = iFeatureFlags; - - if (mIFeatureFlags != null) { - try { - mIFeatureFlags.registerCallback(mIFeatureFlagsCallback); - } catch (RemoteException e) { - // Won't happen in tests. - } - } - } - - /** - * Construct a new {@link BooleanFlag}. - * - * Use this instead of constructing a {@link BooleanFlag} directly, as it registers the flag - * with the internals of the flagging system. - */ - @NonNull - public static BooleanFlag booleanFlag( - @NonNull String namespace, @NonNull String name, boolean def) { - return getInstance().addFlag(new BooleanFlag(namespace, name, def)); - } - - /** - * Construct a new {@link FusedOffFlag}. - * - * Use this instead of constructing a {@link FusedOffFlag} directly, as it registers the - * flag with the internals of the flagging system. - */ - @NonNull - public static FusedOffFlag fusedOffFlag(@NonNull String namespace, @NonNull String name) { - return getInstance().addFlag(new FusedOffFlag(namespace, name)); - } - - /** - * Construct a new {@link FusedOnFlag}. - * - * Use this instead of constructing a {@link FusedOnFlag} directly, as it registers the flag - * with the internals of the flagging system. - */ - @NonNull - public static FusedOnFlag fusedOnFlag(@NonNull String namespace, @NonNull String name) { - return getInstance().addFlag(new FusedOnFlag(namespace, name)); - } - - /** - * Construct a new {@link DynamicBooleanFlag}. - * - * Use this instead of constructing a {@link DynamicBooleanFlag} directly, as it registers - * the flag with the internals of the flagging system. - */ - @NonNull - public static DynamicBooleanFlag dynamicBooleanFlag( - @NonNull String namespace, @NonNull String name, boolean def) { - return getInstance().addFlag(new DynamicBooleanFlag(namespace, name, def)); - } - - /** - * Add a listener to be alerted when a {@link DynamicFlag} changes. - * - * See also {@link #removeChangeListener(ChangeListener)}. - * - * @param listener The listener to add. - */ - public void addChangeListener(@NonNull ChangeListener listener) { - mListeners.add(listener); - } - - /** - * Remove a listener that was added earlier. - * - * See also {@link #addChangeListener(ChangeListener)}. - * - * @param listener The listener to remove. - */ - public void removeChangeListener(@NonNull ChangeListener listener) { - mListeners.remove(listener); - } - - protected void onFlagChange(@NonNull DynamicFlag<?> flag) { - for (ChangeListener l : mListeners) { - l.onFlagChanged(flag); - } + FeatureFlags() { } /** @@ -197,7 +63,7 @@ public class FeatureFlags { * The first time a flag is read, its value is cached for the lifetime of the process. */ public boolean isEnabled(@NonNull BooleanFlag flag) { - return getBooleanInternal(flag); + return flag.getDefault(); } /** @@ -224,138 +90,31 @@ public class FeatureFlags { * Can return a different value for the flag each time it is called if an override comes in. */ public boolean isCurrentlyEnabled(@NonNull DynamicBooleanFlag flag) { - return getBooleanInternal(flag); - } - - private boolean getBooleanInternal(Flag<Boolean> flag) { - sync(); - Map<String, Boolean> ns = mBooleanOverrides.get(flag.getNamespace()); - Boolean value = null; - if (ns != null) { - value = ns.get(flag.getName()); - } - if (value == null) { - throw new IllegalStateException("Boolean flag being read but was not synced: " + flag); - } - - return value; - } - - private <T extends Flag<?>> T addFlag(T flag) { - synchronized (FeatureFlags.class) { - mDirtyFlags.add(flag); - mKnownFlags.add(flag); - } - return flag; - } - - protected void sync() { - synchronized (FeatureFlags.class) { - if (mDirtyFlags.isEmpty()) { - return; - } - syncInternal(mDirtyFlags); - mDirtyFlags.clear(); - } + return flag.getDefault(); } /** - * Called when new flags have been declared. Gives the implementation a chance to act on them. + * Add a listener to be alerted when a {@link DynamicFlag} changes. + * + * See also {@link #removeChangeListener(ChangeListener)}. * - * Guaranteed to be called from a synchronized, thread-safe context. + * @param listener The listener to add. */ - protected void syncInternal(Set<Flag<?>> dirtyFlags) { - IFeatureFlags iFeatureFlags = bind(); - List<SyncableFlag> syncableFlags = new ArrayList<>(); - for (Flag<?> f : dirtyFlags) { - syncableFlags.add(flagToSyncableFlag(f)); - } - - List<SyncableFlag> serverFlags = List.of(); // Need to initialize the list with something. - try { - // New values come back from the service. - serverFlags = iFeatureFlags.syncFlags(syncableFlags); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - - for (Flag<?> f : dirtyFlags) { - boolean found = false; - for (SyncableFlag sf : serverFlags) { - if (flagEqualsSyncableFlag(f, sf)) { - if (f instanceof BooleanFlag || f instanceof DynamicBooleanFlag) { - addBooleanOverride(sf.getNamespace(), sf.getName(), sf.getValue()); - } - found = true; - break; - } - } - if (!found) { - if (f instanceof BooleanFlag) { - addBooleanOverride( - f.getNamespace(), - f.getName(), - ((BooleanFlag) f).getDefault() ? "true" : "false"); - } - } - } - } - - private void addBooleanOverride(String namespace, String name, String override) { - Map<String, Boolean> nsOverrides = mBooleanOverrides.get(namespace); - if (nsOverrides == null) { - nsOverrides = new HashMap<>(); - mBooleanOverrides.put(namespace, nsOverrides); - } - nsOverrides.put(name, parseBoolean(override)); - } - - private SyncableFlag flagToSyncableFlag(Flag<?> f) { - return new SyncableFlag( - f.getNamespace(), - f.getName(), - f.getDefault().toString(), - f instanceof DynamicFlag<?>); - } - - private IFeatureFlags bind() { - if (mIFeatureFlags == null) { - mIFeatureFlags = IFeatureFlags.Stub.asInterface( - ServiceManager.getService(Context.FEATURE_FLAGS_SERVICE)); - try { - mIFeatureFlags.registerCallback(mIFeatureFlagsCallback); - } catch (RemoteException e) { - Log.e(TAG, "Failed to listen for flag changes!"); - } - } - - return mIFeatureFlags; - } - - static boolean parseBoolean(String value) { - // Check for a truish string. - boolean result = value.equalsIgnoreCase("true") - || value.equals("1") - || value.equalsIgnoreCase("t") - || value.equalsIgnoreCase("on"); - if (!result) { // Expect a falsish string, else log an error. - if (!(value.equalsIgnoreCase("false") - || value.equals("0") - || value.equalsIgnoreCase("f") - || value.equalsIgnoreCase("off"))) { - Log.e(TAG, - "Tried parsing " + value + " as boolean but it doesn't look like one. " - + "Value expected to be one of true|false, 1|0, t|f, on|off."); - } - } - return result; + public void addChangeListener(@NonNull ChangeListener listener) { + mListeners.add(listener); } - private static boolean flagEqualsSyncableFlag(Flag<?> f, SyncableFlag sf) { - return f.getName().equals(sf.getName()) && f.getNamespace().equals(sf.getNamespace()); + /** + * Remove a listener that was added earlier. + * + * See also {@link #addChangeListener(ChangeListener)}. + * + * @param listener The listener to remove. + */ + public void removeChangeListener(@NonNull ChangeListener listener) { + mListeners.remove(listener); } - /** * A simpler listener that is alerted when a {@link DynamicFlag} changes. * diff --git a/core/java/android/flags/FeatureFlagsFake.java b/core/java/android/flags/FeatureFlagsFake.java index daedcdae0b5f..03bf2b6d33d2 100644 --- a/core/java/android/flags/FeatureFlagsFake.java +++ b/core/java/android/flags/FeatureFlagsFake.java @@ -18,98 +18,32 @@ package android.flags; import android.annotation.NonNull; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - /** * An implementation of {@link FeatureFlags} for testing. - * - * Before you read a flag from using this Fake, you must set that flag using - * {@link #setFlagValue(BooleanFlagBase, boolean)}. This ensures that your tests are deterministic. - * - * If you are relying on {@link FeatureFlags#getInstance()} to access FeatureFlags in your code - * under test, (instead of dependency injection), you can pass an instance of this fake to - * {@link FeatureFlags#setInstance(FeatureFlags)}. Be sure to call that method again, passing null, - * to ensure hermetic testing - you don't want static state persisting between your test methods. - * * @hide */ public class FeatureFlagsFake extends FeatureFlags { - private final Map<BooleanFlagBase, Boolean> mFlagValues = new HashMap<>(); - private final Set<BooleanFlagBase> mReadFlags = new HashSet<>(); - - public FeatureFlagsFake(IFeatureFlags iFeatureFlags) { - super(iFeatureFlags); + public FeatureFlagsFake() { + super(); } @Override public boolean isEnabled(@NonNull BooleanFlag flag) { - return requireFlag(flag); + return flag.getDefault(); } @Override public boolean isEnabled(@NonNull FusedOffFlag flag) { - return requireFlag(flag); + return false; } @Override public boolean isEnabled(@NonNull FusedOnFlag flag) { - return requireFlag(flag); + return true; } @Override public boolean isCurrentlyEnabled(@NonNull DynamicBooleanFlag flag) { - return requireFlag(flag); - } - - @Override - protected void syncInternal(Set<Flag<?>> dirtyFlags) { - } - - /** - * Explicitly set a flag's value for reading in tests. - * - * You _must_ call this for every flag your code-under-test will read. Otherwise, an - * {@link IllegalStateException} will be thrown. - * - * You are able to set values for {@link FusedOffFlag} and {@link FusedOnFlag}, despite those - * flags having a fixed value at compile time, since unit tests should still test the state of - * those flags as both true and false. I.e. a flag that is off might be turned on in a future - * build or vice versa. - * - * You can not call this method _after_ a non-dynamic flag has been read. Non-dynamic flags - * are held stable in the system, so changing a value after reading would not match - * real-implementation behavior. - * - * Calling this method will trigger any {@link android.flags.FeatureFlags.ChangeListener}s that - * are registered for the supplied flag if the flag is a {@link DynamicFlag}. - * - * @param flag The BooleanFlag that you want to set a value for. - * @param value The value that the flag should return when accessed. - */ - public void setFlagValue(@NonNull BooleanFlagBase flag, boolean value) { - if (!(flag instanceof DynamicBooleanFlag) && mReadFlags.contains(flag)) { - throw new RuntimeException( - "You can not set the value of a flag after it has been read. Tried to set " - + flag + " to " + value + " but it already " + mFlagValues.get(flag)); - } - mFlagValues.put(flag, value); - if (flag instanceof DynamicBooleanFlag) { - onFlagChange((DynamicFlag<?>) flag); - } + return flag.getDefault(); } - - private boolean requireFlag(BooleanFlagBase flag) { - if (!mFlagValues.containsKey(flag)) { - throw new IllegalStateException( - "Tried to access " + flag + " in test but no overrided specified. You must " - + "call #setFlagValue for each flag read in a test."); - } - mReadFlags.add(flag); - - return mFlagValues.get(flag); - } - } diff --git a/core/java/android/flags/FusedOffFlag.java b/core/java/android/flags/FusedOffFlag.java index 5f435beb2642..999d0f981780 100644 --- a/core/java/android/flags/FusedOffFlag.java +++ b/core/java/android/flags/FusedOffFlag.java @@ -17,7 +17,6 @@ package android.flags; import android.annotation.NonNull; -import android.provider.DeviceConfig; /** * A flag representing a false value. @@ -26,13 +25,13 @@ import android.provider.DeviceConfig; * * @hide */ -public final class FusedOffFlag extends BooleanFlagBase { - /** - * @param namespace A namespace for this flag. See {@link DeviceConfig}. - * @param name A name for this flag. - */ +public final class FusedOffFlag implements Flag<Boolean> { + private final String mNamespace; + private final String mName; + FusedOffFlag(String namespace, String name) { - super(namespace, name); + mNamespace = namespace; + mName = name; } @Override @@ -40,4 +39,22 @@ public final class FusedOffFlag extends BooleanFlagBase { public Boolean getDefault() { return false; } + + @Override + @NonNull + public String getNamespace() { + return mNamespace; + } + + @Override + @NonNull + public String getName() { + return mName; + } + + @Override + @NonNull + public String toString() { + return getNamespace() + "." + getName() + "[false]"; + } } diff --git a/core/java/android/flags/FusedOnFlag.java b/core/java/android/flags/FusedOnFlag.java index ea8d9b29b3ce..4f33bee8abe1 100644 --- a/core/java/android/flags/FusedOnFlag.java +++ b/core/java/android/flags/FusedOnFlag.java @@ -17,7 +17,6 @@ package android.flags; import android.annotation.NonNull; -import android.provider.DeviceConfig; /** * A flag representing a true value. @@ -26,13 +25,13 @@ import android.provider.DeviceConfig; * * @hide */ -public final class FusedOnFlag extends BooleanFlagBase { - /** - * @param namespace A namespace for this flag. See {@link DeviceConfig}. - * @param name A name for this flag. - */ +public final class FusedOnFlag implements Flag<Boolean> { + private final String mNamespace; + private final String mName; + FusedOnFlag(String namespace, String name) { - super(namespace, name); + mNamespace = namespace; + mName = name; } @Override @@ -40,4 +39,22 @@ public final class FusedOnFlag extends BooleanFlagBase { public Boolean getDefault() { return true; } + + @Override + @NonNull + public String getNamespace() { + return mNamespace; + } + + @Override + @NonNull + public String getName() { + return mName; + } + + @Override + @NonNull + public String toString() { + return getNamespace() + "." + getName() + "[true]"; + } } diff --git a/core/java/android/flags/SyncableFlag.java b/core/java/android/flags/SyncableFlag.java index 0b2a4d9e4f98..54c4c6d5fdf9 100644 --- a/core/java/android/flags/SyncableFlag.java +++ b/core/java/android/flags/SyncableFlag.java @@ -20,15 +20,18 @@ import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.annotations.VisibleForTesting; + /** * @hide */ public final class SyncableFlag implements Parcelable { private final String mNamespace; private final String mName; - private final String mValue; + private String mValue; private final boolean mDynamic; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public SyncableFlag( @NonNull String namespace, @NonNull String name, @@ -40,6 +43,10 @@ public final class SyncableFlag implements Parcelable { mDynamic = dynamic; } + public void setValue(@NonNull String value) { + mValue = value; + } + @NonNull public String getNamespace() { return mNamespace; diff --git a/core/tests/coretests/src/android/flags/FeatureFlagsTest.java b/core/tests/coretests/src/android/flags/FeatureFlagsTest.java index 3fc94394d12c..dc6006a8e5fa 100644 --- a/core/tests/coretests/src/android/flags/FeatureFlagsTest.java +++ b/core/tests/coretests/src/android/flags/FeatureFlagsTest.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package android.flags; import static com.google.common.truth.Truth.assertThat; @@ -21,135 +22,33 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; - -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - +import org.mockito.MockitoAnnotations; @SmallTest @Presubmit -public class FeatureFlagsTest { - - IFeatureFlagsFake mIFeatureFlagsFake = new IFeatureFlagsFake(); - FeatureFlags mFeatureFlags = new FeatureFlags(mIFeatureFlagsFake); +public final class FeatureFlagsTest { @Before public void setup() { - FeatureFlags.setInstance(mFeatureFlags); - } - - @Test - public void testFusedOff_Disabled() { - FusedOffFlag flag = FeatureFlags.fusedOffFlag("test", "a"); - assertThat(mFeatureFlags.isEnabled(flag)).isFalse(); - } - - @Test - public void testFusedOn_Enabled() { - FusedOnFlag flag = FeatureFlags.fusedOnFlag("test", "a"); - assertThat(mFeatureFlags.isEnabled(flag)).isTrue(); - } - - @Test - public void testBooleanFlag_DefaultDisabled() { - BooleanFlag flag = FeatureFlags.booleanFlag("test", "a", false); - assertThat(mFeatureFlags.isEnabled(flag)).isFalse(); - } - - @Test - public void testBooleanFlag_DefaultEnabled() { - BooleanFlag flag = FeatureFlags.booleanFlag("test", "a", true); - assertThat(mFeatureFlags.isEnabled(flag)).isTrue(); - } - - @Test - public void testDynamicBooleanFlag_DefaultDisabled() { - DynamicBooleanFlag flag = FeatureFlags.dynamicBooleanFlag("test", "a", false); - assertThat(mFeatureFlags.isCurrentlyEnabled(flag)).isFalse(); + MockitoAnnotations.initMocks(this); } - @Test - public void testDynamicBooleanFlag_DefaultEnabled() { - DynamicBooleanFlag flag = FeatureFlags.dynamicBooleanFlag("test", "a", true); - assertThat(mFeatureFlags.isCurrentlyEnabled(flag)).isTrue(); + @After + public void tearDown() { } @Test - public void testBooleanFlag_OverrideBeforeRead() { - BooleanFlag flag = FeatureFlags.booleanFlag("test", "a", false); - SyncableFlag syncableFlag = new SyncableFlag( - flag.getNamespace(), flag.getName(), "true", false); - - mIFeatureFlagsFake.setFlagOverrides(List.of(syncableFlag)); - - assertThat(mFeatureFlags.isEnabled(flag)).isTrue(); + public void testPass() { + assertThat(true).isTrue(); } + @Ignore @Test - public void testFusedOffFlag_OverrideHasNoEffect() { - FusedOffFlag flag = FeatureFlags.fusedOffFlag("test", "a"); - SyncableFlag syncableFlag = new SyncableFlag( - flag.getNamespace(), flag.getName(), "true", false); - - mIFeatureFlagsFake.setFlagOverrides(List.of(syncableFlag)); - - assertThat(mFeatureFlags.isEnabled(flag)).isFalse(); - } - - @Test - public void testFusedOnFlag_OverrideHasNoEffect() { - FusedOnFlag flag = FeatureFlags.fusedOnFlag("test", "a"); - SyncableFlag syncableFlag = new SyncableFlag( - flag.getNamespace(), flag.getName(), "false", false); - - mIFeatureFlagsFake.setFlagOverrides(List.of(syncableFlag)); - - assertThat(mFeatureFlags.isEnabled(flag)).isTrue(); - } - - @Test - public void testDynamicFlag_OverrideBeforeRead() { - DynamicBooleanFlag flag = FeatureFlags.dynamicBooleanFlag("test", "a", false); - SyncableFlag syncableFlag = new SyncableFlag( - flag.getNamespace(), flag.getName(), "true", true); - - mIFeatureFlagsFake.setFlagOverrides(List.of(syncableFlag)); - - // Changes to true - assertThat(mFeatureFlags.isCurrentlyEnabled(flag)).isTrue(); - } - - @Test - public void testDynamicFlag_OverrideAfterRead() { - DynamicBooleanFlag flag = FeatureFlags.dynamicBooleanFlag("test", "a", false); - SyncableFlag syncableFlag = new SyncableFlag( - flag.getNamespace(), flag.getName(), "true", true); - - // Starts false - assertThat(mFeatureFlags.isCurrentlyEnabled(flag)).isFalse(); - - mIFeatureFlagsFake.setFlagOverrides(List.of(syncableFlag)); - - // Changes to true - assertThat(mFeatureFlags.isCurrentlyEnabled(flag)).isTrue(); - } - - @Test - public void testDynamicFlag_FiresListener() { - DynamicBooleanFlag flag = FeatureFlags.dynamicBooleanFlag("test", "a", false); - AtomicBoolean called = new AtomicBoolean(false); - FeatureFlags.ChangeListener listener = flag1 -> called.set(true); - - mFeatureFlags.addChangeListener(listener); - - SyncableFlag syncableFlag = new SyncableFlag( - flag.getNamespace(), flag.getName(), flag.getDefault().toString(), true); - - mIFeatureFlagsFake.setFlagOverrides(List.of(syncableFlag)); - - // Fires listener. - assertThat(called.get()).isTrue(); + public void testFail() { + assertThat(false).isTrue(); } } diff --git a/core/tests/coretests/src/android/flags/IFeatureFlagsFake.java b/core/tests/coretests/src/android/flags/IFeatureFlagsFake.java deleted file mode 100644 index 70b65ce1eb57..000000000000 --- a/core/tests/coretests/src/android/flags/IFeatureFlagsFake.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.flags; - -import android.os.IBinder; -import android.os.RemoteException; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -class IFeatureFlagsFake implements IFeatureFlags { - - private final Set<IFeatureFlagsCallback> mCallbacks = new HashSet<>(); - - List<SyncableFlag> mOverrides; - - @Override - public IBinder asBinder() { - return null; - } - - @Override - public List<SyncableFlag> syncFlags(List<SyncableFlag> flagList) { - return mOverrides == null ? flagList : mOverrides; - } - - @Override - public void registerCallback(IFeatureFlagsCallback callback) { - mCallbacks.add(callback); - } - - @Override - public void unregisterCallback(IFeatureFlagsCallback callback) { - mCallbacks.remove(callback); - } - - public void setFlagOverrides(List<SyncableFlag> flagList) { - mOverrides = flagList; - for (SyncableFlag sf : flagList) { - for (IFeatureFlagsCallback cb : mCallbacks) { - try { - cb.onFlagChange(sf); - } catch (RemoteException e) { - // does not happen in fakes. - } - } - } - } -} diff --git a/services/flags/java/com/android/server/flags/DynamicFlagBinderDelegate.java b/services/flags/java/com/android/server/flags/DynamicFlagBinderDelegate.java index 8da5aae6abdd..322a52bf01cc 100644 --- a/services/flags/java/com/android/server/flags/DynamicFlagBinderDelegate.java +++ b/services/flags/java/com/android/server/flags/DynamicFlagBinderDelegate.java @@ -118,9 +118,9 @@ class DynamicFlagBinderDelegate { mFlagStore.setChangeCallback(mFlagChangeCallback); } - SyncableFlag syncDynamicFlag(int pid, SyncableFlag sf) { + void syncDynamicFlag(int pid, SyncableFlag sf) { if (!sf.isDynamic()) { - return sf; + return; } String ns = sf.getNamespace(); @@ -162,7 +162,7 @@ class DynamicFlagBinderDelegate { // to something. data.setDefaultValue(sf.getValue()); - return new SyncableFlag(sf.getNamespace(), sf.getName(), value, true); + sf.setValue(value); } diff --git a/services/flags/java/com/android/server/flags/FeatureFlagsBinder.java b/services/flags/java/com/android/server/flags/FeatureFlagsBinder.java index 86b464dbdf5d..dc97fde758dc 100644 --- a/services/flags/java/com/android/server/flags/FeatureFlagsBinder.java +++ b/services/flags/java/com/android/server/flags/FeatureFlagsBinder.java @@ -25,7 +25,6 @@ import android.os.Build; import android.os.ParcelFileDescriptor; import java.io.FileOutputStream; -import java.util.ArrayList; import java.util.List; class FeatureFlagsBinder extends IFeatureFlags.Stub { @@ -53,13 +52,11 @@ class FeatureFlagsBinder extends IFeatureFlags.Stub { @Override public List<SyncableFlag> syncFlags(List<SyncableFlag> incomingFlags) { int pid = getCallingPid(); - List<SyncableFlag> outputFlags = new ArrayList<>(); for (SyncableFlag sf : incomingFlags) { String ns = sf.getNamespace(); String name = sf.getName(); - SyncableFlag outFlag; if (sf.isDynamic()) { - outFlag = mDynamicFlagDelegate.syncDynamicFlag(pid, sf); + mDynamicFlagDelegate.syncDynamicFlag(pid, sf); } else { synchronized (mFlagCache) { String value = mFlagCache.getOrNull(ns, name); @@ -68,12 +65,11 @@ class FeatureFlagsBinder extends IFeatureFlags.Stub { value = overrideValue != null ? overrideValue : sf.getValue(); mFlagCache.setIfChanged(ns, name, value); } - outFlag = new SyncableFlag(sf.getNamespace(), sf.getName(), value, false); + sf.setValue(value); } } - outputFlags.add(outFlag); } - return outputFlags; + return incomingFlags; } @SystemApi |