Commit graph

401 commits

Author SHA1 Message Date
Dennis Shen
a8e28dfe87 aconfig: update java read api for performance
With this update, cold flag read (first flag in a namespace) is now 6x
faster compared to device config.

Bug: b/321077378
Test: atest -c
Change-Id: I52ffd897fdd487b2a44d07be50f2975f0ef5b9b3
2024-06-04 17:24:53 +00:00
Dennis Shen
e5dd91bca7 aconfig: create first implementation of aconfig storage java read api
1, See AconfigStorageReadAPI.java to see java APIs to map storage files
and read flag values. It is using fast native annotation, in theory it
should be faster than regular JNI without much of the overhead.

2, The java api calls into Rust wrapper in srcs/lib.rs, note that
MappedByteBuffer is not copied during JNI. In the rust side
implementation we get the underlying raw pointer and buffer size and
reconstruct a rust slice. However, at current implmentation, the string
input such as package name and flag name are most likely copied. They
are converted from JStirng to JavaStr first without copy, then the
into() call to convert it to Rust string. We could potentially optimize
it to without copy.

3, Add an android_test target to lock down the API behaviors.

Bug: b/321077378
Test: atest -c
Change-Id: I8915fe70e8eb341be563c70f85e19e644e8aa6be
2024-05-30 00:32:42 +00:00
Dennis Shen
a0624828b2 aconfig: remove read api lib's dependency on libbase and liblog
Bug: b/321077378
Test: atest -c
Change-Id: I0bc7780de2123021e1cc9f7a29ca3f7dabebcd40
2024-05-23 12:30:31 +00:00
Dennis Shen
7b09e95c89 Merge "aconfig: update storage read api" into main 2024-05-22 20:52:40 +00:00
Dennis Shen
70208daaaa aconfig: update storage read api
Bug: b/321077378
Test atest -c

Change-Id: I53fe6c34466f32d5283d0bdbf4736c8ecd20ef99
2024-05-22 19:25:35 +00:00
Dennis Shen
5590478580 aconfig: update storage read api
Update storage read api to not find storage file location from a pb
file, instead directly read from /metadata copy. Previously for
package.map and flag.map, we are reading from the respective RO
partition. Now we are reading from /metadata/maps dir. This has a few
advantages:

1, early flag availability, since /metadata can be mounted much earlier
than mainline modules, so it would make mainline flags availabile even
before mainline modules are mounted.

2, we no longer need to read from a pb file to find where package.map
and flag.map are. Thus the read api can be further simplified and
downsized. With this change, we are able to shrink the cc flag read api
lib size from 171k to 120k.

Bug: b/321077378
Test atest -c

Change-Id: Ic9086fe4c49c139a4d1c66a8d472023a88c9dd17
2024-05-22 19:25:17 +00:00
Ted Bauer
aeb96092af Add filter by container to aflags
Test: m -j120 && acloud create --local-image && adb shell aflags list --c system
Test: cargo t
Bug: 340840507
Change-Id: I5db7f204673accdbd3c4ad62e88b213028a8d5ab
2024-05-15 10:06:25 -04:00
Mark Punzalan
5529e36e88 Add a nano proto version of aconfig protos
Framework already has nano protos, and reusing them won't
introduce extra dependencies for the apps
This is setting up the resources flagging in the framework

Bug: 297373084
Test: Built with related changes
Change-Id: I518bd56f56c42e0adef0002e95f8948e0904fb43
2024-05-15 06:18:23 +00:00
Ted Bauer
1f9d55d2ab Fix bug in device path proto reading
aconfig_device_paths uses `include_str!` to include a text file
containing comma-separated strings with each partition aconfig file.
The lib does not handle the escaped newlines and quotation marks.
Adds proper handling.

Test: cargo t  && m -j120 && acloud create --local-image && adb shell aflags list
Bug: 340514768
Change-Id: I75214bf02dd962d8291f1654ade8cbce1cda9fde
2024-05-14 15:49:14 -04:00
Dennis Shen
db0c8d7986 Merge "aconfig: simply proto" into main 2024-05-13 15:26:26 +00:00
Dennis Shen
a2fb60b822 aconfig: simply proto
Bug: b/339514174, b/312444587
Test: atest -c
Change-Id: I5511efd04af9f57b22e4c89bd2db65496aaf4398
2024-05-11 15:51:14 +00:00
Treehugger Robot
8211cb24a5 Merge "Replace impl ToString with impl Display" into main 2024-05-10 18:32:41 +00:00
Chris Wailes
e6bb2e951d Replace impl ToString with impl Display
If the Display interface is implemented the compiler will automatically
derive an implementation of ToString.

Test: m aflags
Bug: 333887339
Change-Id: I861a3065edbef0da1684a6ea28cc374acd0d774a
2024-05-09 15:14:22 -07:00
Dennis Shen
9d21525b85 Merge "aconfig: add list_flag api cxx interlop" into main 2024-05-09 21:13:17 +00:00
Dennis Shen
e1949a6563 aconfig: add list_flag api cxx interlop
Bug: 312444587
Test: atest -c
Change-Id: I3e3bc511c370fbcdfa6dcf7942377dd9b544c647
2024-05-09 17:37:36 +00:00
Treehugger Robot
c0c2e5f278 Merge "Add a Java lib to read on-device proto paths" into main 2024-05-09 15:05:28 +00:00
Ted Bauer
3cf7c0a2c0 Add a Java lib to read on-device proto paths
Bug: 337911453
Test: m aconfig_on_device_protos_java
Change-Id: Iac8d671acee070ed041927028ec80c7aa371bd61

Change-Id: I19e0e52d8de71207c9858305e6248b6251a20989
2024-05-08 16:05:00 -04:00
Dennis Shen
d772eb3edc aconfig: make MutableMappedStorageFiles inherit MappedStoargeFiles
Bug: b/321077378
Test: atest -c
Change-Id: Ib052df74bf79b5bc2a0f8c793701e3ff18f4aa30
2024-05-07 15:28:09 +00:00
Dennis Shen
a49f1ba5c5 aconfig: update storage file mapping api
Return a pointer of MappedStorageFile/MutableMappedStorageFile instead
of an object of MappedStorageFile/MutableMappedStorageFile. Now added
destructor for MappedStorageFile/MutableMappedStorageFile to unmap the
in memory file to free up memory.

Bug: b/321077378
Test: atest -c
Change-Id: Iaa02696feb07ff383f0c7e46b645d82e57c38254
2024-05-06 17:25:59 +00:00
Ted Bauer
daa3c71739 Merge "Update dependencies for new aconfig flag storage" into main 2024-05-01 15:37:20 +00:00
Ted Bauer
4560e3ae8f Update dependencies for new aconfig flag storage
Bug: 328444881
Test: m
Change-Id: I3685a74e9e93a6ecb89a054e243b48b67f470d55
2024-04-30 23:57:51 +00:00
Dennis Shen
c0102331c8 Merge "aconfig: add a new aconfig storage file flag listing api" into main 2024-04-30 23:06:18 +00:00
Dennis Shen
45c94c6421 aconfig: add a new aconfig storage file flag listing api
added a new function called list_flag_with_info to list all the flags
given all four storage files (package.map, flag.map, flag.val, flag.info).
also exported this api thru cxx interface so aconfigd can use it.

Bug: b/312444587
Test: atest -c
Change-Id: Ibbfe657b980d40e25e5e28962b930338192e2d98
2024-04-30 17:52:44 +00:00
Ted Bauer
d724dd04e2 Add cc_defaults containing libs needed for static linking
Bug: 328444881
Test: m
Change-Id: I35cbce94301415381b3ad38d7e5c697f9c010856
2024-04-29 23:41:52 +00:00
Ted Bauer
d19d351148 Drive instrumentation with build flag
Bug: 328444881
Test: m
Change-Id: Iebb250e8a836c77b14fcc6b9536eba90f9da7a4b
2024-04-29 20:12:27 +00:00
Treehugger Robot
80c40c4d91 Merge "FakeFeatureFlagsImpl optionally takes defaults via a FeatureFlags." into main 2024-04-29 16:53:28 +00:00
Ted Bauer
d475818504 Merge "Read from new storage in C++ aconfig codegen" into main 2024-04-29 16:47:45 +00:00
Jeff DeCew
23fbd1e2f6 FakeFeatureFlagsImpl optionally takes defaults via a FeatureFlags.
Bug: 337449122
Flag: test_only
Test: presubmit
Change-Id: I45e2a523b36a6b14627c89ee7deffda711a32f5e
2024-04-27 18:08:45 +00:00
Jared Duke
a97d385b69 Restrict aconfig version script to linux
Avoid breakage on other platforms.
Bug: 336657207
Test: m

Change-Id: I167dbbe934a133e8f08f630846707870404f62fd
2024-04-26 20:22:12 +00:00
Treehugger Robot
d2469987ce Merge "Use a version script for libaconfig_storage_read_api_cc" into main 2024-04-26 19:35:54 +00:00
Ted Bauer
8e7cfad672 Read from new storage in C++ aconfig codegen
Read from the new aconfig storage backing in C++ aconfig codegen, for
READ_ONLY flags. Log if there is a match with the legacy storage, or a
mismatch, or a failure.

Only enabled if instrumentation is enabled, which will be enabled by a
build flag in a follow-up CL.

Test: m && cargo t
Bug: 328444881
Change-Id: I691dfad8860d8f917e93c5d56dac19f8791de943
2024-04-26 18:45:31 +00:00
Jeff DeCew
cfd7b0df36 Merge "Generate CustomFeatureFlags" into main 2024-04-26 18:39:43 +00:00
Jared Duke
8782e1e858 Use a version script for libaconfig_storage_read_api_cc
Restrict the set of exported symbols to those in the aconfig_storage
namespace by way of a version script. This shrinks the shared lib size
by ~75%, from ~800KB to <200KB.

Bug: 336657207
Test: m
Change-Id: I56044fe667a713cf1d94f96c992f379a5725850f
2024-04-26 17:43:14 +00:00
Ted Bauer
966e558e9f Merge "Prune unnecessary symbols from read API" into main 2024-04-25 16:59:05 +00:00
Ted Bauer
ad07bd54f6 Prune unnecessary symbols from read API
Bug: 328444881
Test: m
Change-Id: I3b730a6c3390a5d116d467f15f17e74a9096961d
2024-04-25 15:51:15 +00:00
Dennis Shen
fe5065705c aconfig: update aconfig storage write api and test update
Simplify storage write api so that we don't need the storage records pb
file.

Bug: b/312444587
Test: atest -c
Change-Id: I7e336b1d7766983364715dae15786b91b0c0743f
2024-04-25 13:40:07 +00:00
Jeff DeCew
c3bc24f33b Generate CustomFeatureFlags
* Creates a new general-purpose CustomFeatureFlags class
* Simplifies FakeFeatureFlagsImpl to be based on that
* This allows teams to fake FeatureFlags without having to make changes per flag.
* This allows SetFlagsRule to inject an instance of FeatureFlags that would detect if a flag has been read.

Bug: 336768870
Flag: none
Test: presubmit
Change-Id: Id3c2530d484fa5584c46d11381fcfc0ab294f33f

NOTE FOR REVIEWERS - original patch and result patch are not identical.
PLEASE REVIEW CAREFULLY.
Diffs between the patches:
     "CustomFeatureFlags.java",
> +        include_str!("../../templates/CustomFeatureFlags.java.template"),
> +    )?;
> +    template.add_template(
> -    ["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"]
> -        .iter()
> -        .map(|file| {
> -            Ok(OutputFile {
> -                contents: template.render(file, &context)?.into(),
> -                path: path.join(file),
> -            })
> -        })
> -        .collect::<Result<Vec<OutputFile>>>()
> +    [
> +        "Flags.java",
> +        "FeatureFlags.java",
> +        "FeatureFlagsImpl.java",
> +        "CustomFeatureFlags.java",
> +        "FakeFeatureFlagsImpl.java",
> +    ]
> +    .iter()
> +    .map(|file| {
> +        Ok(OutputFile { contents: template.render(file, &context)?.into(), path: path.join(file) })
> +    })
> +    .collect::<Result<Vec<OutputFile>>>()
> -    const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#"
> +    const EXPECTED_CUSTOMFEATUREFLAGS_CONTENT: &str = r#"
> +
> -    import java.util.HashMap;
> -    import java.util.Map;
> +    import java.util.List;
> +    import java.util.function.BiPredicate;
> +    import java.util.function.Predicate;
> +
> -    public class FakeFeatureFlagsImpl implements FeatureFlags {
> -        public FakeFeatureFlagsImpl() {
> -            resetAll();
> +    public class CustomFeatureFlags implements FeatureFlags {
> +
> +        private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
> +
> +        public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
> +            mGetValueImpl = getValueImpl;
> +
> -            return getValue(Flags.FLAG_DISABLED_RO);
> +            return getValue(Flags.FLAG_DISABLED_RO,
> +                    FeatureFlags::disabledRo);
> -            return getValue(Flags.FLAG_DISABLED_RW);
> +            return getValue(Flags.FLAG_DISABLED_RW,
> +                FeatureFlags::disabledRw);
> -            return getValue(Flags.FLAG_DISABLED_RW_EXPORTED);
> +            return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
> +                FeatureFlags::disabledRwExported);
> -            return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE);
> +            return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
> +                FeatureFlags::disabledRwInOtherNamespace);
> -            return getValue(Flags.FLAG_ENABLED_FIXED_RO);
> +            return getValue(Flags.FLAG_ENABLED_FIXED_RO,
> +                FeatureFlags::enabledFixedRo);
> -            return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED);
> +            return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
> +                FeatureFlags::enabledFixedRoExported);
> -            return getValue(Flags.FLAG_ENABLED_RO);
> +            return getValue(Flags.FLAG_ENABLED_RO,
> +                FeatureFlags::enabledRo);
> -            return getValue(Flags.FLAG_ENABLED_RO_EXPORTED);
> +            return getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
> +                FeatureFlags::enabledRoExported);
> -            return getValue(Flags.FLAG_ENABLED_RW);
> +            return getValue(Flags.FLAG_ENABLED_RW,
> +                FeatureFlags::enabledRw);
> -        public void setFlag(String flagName, boolean value) {
> -            if (!this.mFlagMap.containsKey(flagName)) {
> -                throw new IllegalArgumentException("no such flag " + flagName);
> -            }
> -            this.mFlagMap.put(flagName, value);
> -        }
> -        public void resetAll() {
> -            for (Map.Entry entry : mFlagMap.entrySet()) {
> -                entry.setValue(null);
> -            }
> -        }
> +
> +
> -        private boolean getValue(String flagName) {
> -            Boolean value = this.mFlagMap.get(flagName);
> -            if (value == null) {
> -                throw new IllegalArgumentException(flagName + " is not set");
> -            }
> -            return value;
> +
> +        protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
> +            return mGetValueImpl.test(flagName, getter);
> -        private Map<String, Boolean> mFlagMap = new HashMap<>(
> -            Map.ofEntries(
> -                Map.entry(Flags.FLAG_DISABLED_RO, false),
> -                Map.entry(Flags.FLAG_DISABLED_RW, false),
> -                Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false),
> -                Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false),
> -                Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false),
> -                Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false),
> -                Map.entry(Flags.FLAG_ENABLED_RO, false),
> -                Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false),
> -                Map.entry(Flags.FLAG_ENABLED_RW, false)
> -            )
> -        );
> +
> +        public List<String> getFlagNames() {
> +            return Arrays.asList(
> +                Flags.FLAG_DISABLED_RO,
> +                Flags.FLAG_DISABLED_RW,
> +                Flags.FLAG_DISABLED_RW_EXPORTED,
> +                Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
> +                Flags.FLAG_ENABLED_FIXED_RO,
> +                Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
> +                Flags.FLAG_ENABLED_RO,
> +                Flags.FLAG_ENABLED_RO_EXPORTED,
> +                Flags.FLAG_ENABLED_RW
> +            );
> +        }
> +
> +    const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#"
> +    package com.android.aconfig.test;
> +
> +    import java.util.HashMap;
> +    import java.util.Map;
> +    import java.util.function.Predicate;
> +
> +    /** @hide */
> +    public class FakeFeatureFlagsImpl extends CustomFeatureFlags {
> +        private Map<String, Boolean> mFlagMap = new HashMap<>();
> +
> +        public FakeFeatureFlagsImpl() {
> +            super(null);
> +            // Initialize the map with null values
> +            for (String flagName : getFlagNames()) {
> +                mFlagMap.put(flagName, null);
> +            }
> +        }
> +
> +        @Override
> +        protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
> +            Boolean value = this.mFlagMap.get(flagName);
> +            if (value == null) {
> +                throw new IllegalArgumentException(flagName + " is not set");
> +            }
> +            return value;
> +        }
> +
> +        public void setFlag(String flagName, boolean value) {
> +            if (!this.mFlagMap.containsKey(flagName)) {
> +                throw new IllegalArgumentException("no such flag " + flagName);
> +            }
> +            this.mFlagMap.put(flagName, value);
> +        }
> +
> +        public void resetAll() {
> +            for (Map.Entry entry : mFlagMap.entrySet()) {
> +                entry.setValue(null);
> +            }
> +        }
> +    }
> +    "#;
> +
> +                "com/android/aconfig/test/CustomFeatureFlags.java",
> +                EXPECTED_CUSTOMFEATUREFLAGS_CONTENT,
> +            ),
> +            (
> -        let expect_fake_feature_flags_impl_content = r#"
> +        let expect_custom_feature_flags_content = r#"
> +
> -        import java.util.HashMap;
> -        import java.util.Map;
> +        import java.util.List;
> +        import java.util.function.BiPredicate;
> +        import java.util.function.Predicate;
> +
> -        public class FakeFeatureFlagsImpl implements FeatureFlags {
> -            public FakeFeatureFlagsImpl() {
> -                resetAll();
> +        public class CustomFeatureFlags implements FeatureFlags {
> +
> +            private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
> +
> +            public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
> +                mGetValueImpl = getValueImpl;
> +
> -                return getValue(Flags.FLAG_DISABLED_RW_EXPORTED);
> +                return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
> +                    FeatureFlags::disabledRwExported);
> -                return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED);
> +                return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
> +                    FeatureFlags::enabledFixedRoExported);
> -                return getValue(Flags.FLAG_ENABLED_RO_EXPORTED);
> +                return getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
> +                    FeatureFlags::enabledRoExported);
> -            public void setFlag(String flagName, boolean value) {
> -                if (!this.mFlagMap.containsKey(flagName)) {
> -                    throw new IllegalArgumentException("no such flag " + flagName);
> -                }
> -                this.mFlagMap.put(flagName, value);
> +
> +            protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
> +                return mGetValueImpl.test(flagName, getter);
> -            public void resetAll() {
> -                for (Map.Entry entry : mFlagMap.entrySet()) {
> -                    entry.setValue(null);
> -                }
> +
> +            public List<String> getFlagNames() {
> +                return Arrays.asList(
> +                    Flags.FLAG_DISABLED_RW_EXPORTED,
> +                    Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
> +                    Flags.FLAG_ENABLED_RO_EXPORTED
> +                );
> -            private boolean getValue(String flagName) {
> -                Boolean value = this.mFlagMap.get(flagName);
> -                if (value == null) {
> -                    throw new IllegalArgumentException(flagName + " is not set");
> -                }
> -                return value;
> -            }
> -            private Map<String, Boolean> mFlagMap = new HashMap<>(
> -                Map.ofEntries(
> -                    Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false),
> -                    Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false),
> -                    Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false)
> -                )
> -            );
> +
> +                "com/android/aconfig/test/CustomFeatureFlags.java",
> +                expect_custom_feature_flags_content,
> +            ),
> +            (
> -                expect_fake_feature_flags_impl_content,
> +                EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
> +                "com/android/aconfig/test/CustomFeatureFlags.java",
> +                EXPECTED_CUSTOMFEATUREFLAGS_CONTENT,
> +            ),
> +            (
> -        let expect_fakefeatureflags_content = r#"
> +        let expect_customfeatureflags_content = r#"
> +
> -        import java.util.HashMap;
> -        import java.util.Map;
> +        import java.util.List;
> +        import java.util.function.BiPredicate;
> +        import java.util.function.Predicate;
> +
> -        public class FakeFeatureFlagsImpl implements FeatureFlags {
> -            public FakeFeatureFlagsImpl() {
> -                resetAll();
> +        public class CustomFeatureFlags implements FeatureFlags {
> +
> +            private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
> +
> +            public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
> +                mGetValueImpl = getValueImpl;
> +
> -                return getValue(Flags.FLAG_DISABLED_RO);
> +                return getValue(Flags.FLAG_DISABLED_RO,
> +                        FeatureFlags::disabledRo);
> -                return getValue(Flags.FLAG_DISABLED_RW);
> +                return getValue(Flags.FLAG_DISABLED_RW,
> +                    FeatureFlags::disabledRw);
> -                return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE);
> +                return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
> +                    FeatureFlags::disabledRwInOtherNamespace);
> -                return getValue(Flags.FLAG_ENABLED_FIXED_RO);
> +                return getValue(Flags.FLAG_ENABLED_FIXED_RO,
> +                    FeatureFlags::enabledFixedRo);
> -                return getValue(Flags.FLAG_ENABLED_RO);
> +                return getValue(Flags.FLAG_ENABLED_RO,
> +                    FeatureFlags::enabledRo);
> -                return getValue(Flags.FLAG_ENABLED_RW);
> +                return getValue(Flags.FLAG_ENABLED_RW,
> +                    FeatureFlags::enabledRw);
> -            public void setFlag(String flagName, boolean value) {
> -                if (!this.mFlagMap.containsKey(flagName)) {
> -                    throw new IllegalArgumentException("no such flag " + flagName);
> -                }
> -                this.mFlagMap.put(flagName, value);
> -            }
> -            public void resetAll() {
> -                for (Map.Entry entry : mFlagMap.entrySet()) {
> -                    entry.setValue(null);
> -                }
> -            }
> +
> +
> -            private boolean getValue(String flagName) {
> -                Boolean value = this.mFlagMap.get(flagName);
> -                if (value == null) {
> -                    throw new IllegalArgumentException(flagName + " is not set");
> -                }
> -                return value;
> +
> +            protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
> +                return mGetValueImpl.test(flagName, getter);
> -            private Map<String, Boolean> mFlagMap = new HashMap<>(
> -                Map.ofEntries(
> -                    Map.entry(Flags.FLAG_DISABLED_RO, false),
> -                    Map.entry(Flags.FLAG_DISABLED_RW, false),
> -                    Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false),
> -                    Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false),
> -                    Map.entry(Flags.FLAG_ENABLED_RO, false),
> -                    Map.entry(Flags.FLAG_ENABLED_RW, false)
> -                )
> -            );
> +
> +            public List<String> getFlagNames() {
> +                return Arrays.asList(
> +                    Flags.FLAG_DISABLED_RO,
> +                    Flags.FLAG_DISABLED_RW,
> +                    Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
> +                    Flags.FLAG_ENABLED_FIXED_RO,
> +                    Flags.FLAG_ENABLED_RO,
> +                    Flags.FLAG_ENABLED_RW
> +                );
> +            }
> +
> +
> -            ("com/android/aconfig/test/FakeFeatureFlagsImpl.java", expect_fakefeatureflags_content),
> +            ("com/android/aconfig/test/CustomFeatureFlags.java", expect_customfeatureflags_content),
> +            (
> +                "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
> +                EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
> +            ),
> --- /dev/null
> +++ tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template
> +package {package_name};
> +
> +{{ if not library_exported- }}
> +// TODO(b/303773055): Remove the annotation after access issue is resolved.
> +import android.compat.annotation.UnsupportedAppUsage;
> +{{ -endif }}
> +import java.util.Arrays;
> +import java.util.HashSet;
> +import java.util.List;
> +import java.util.Set;
> +import java.util.function.BiPredicate;
> +import java.util.function.Predicate;
> +
> +/** @hide */
> +public class CustomFeatureFlags implements FeatureFlags \{
> +
> +    private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
> +
> +    public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) \{
> +        mGetValueImpl = getValueImpl;
> +    }
> +
> +{{ -for item in flag_elements}}
> +    @Override
> +{{ if not library_exported }}    @UnsupportedAppUsage{{ -endif }}
> +    public boolean {item.method_name}() \{
> +        return getValue(Flags.FLAG_{item.flag_name_constant_suffix},
> +            FeatureFlags::{item.method_name});
> +    }
> +{{ endfor }}
> +
> +{{ -if not library_exported }}
> +    public boolean isFlagReadOnlyOptimized(String flagName) \{
> +        if (mReadOnlyFlagsSet.contains(flagName) &&
> +            isOptimizationEnabled()) \{
> +                return true;
> +        }
> +        return false;
> +    }
> +
> +    @com.android.aconfig.annotations.AssumeTrueForR8
> +    private boolean isOptimizationEnabled() \{
> +        return false;
> +    }
> +{{ -endif }}
> +
> +    protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{
> +        return mGetValueImpl.test(flagName, getter);
> +    }
> +
> +    public List<String> getFlagNames() \{
> +        return Arrays.asList(
> +            {{ -for item in flag_elements }}
> +            Flags.FLAG_{item.flag_name_constant_suffix}
> +            {{ -if not @last }},{{ endif }}
> +            {{ -endfor }}
> +        );
> +    }
> +
> +    private Set<String> mReadOnlyFlagsSet = new HashSet<>(
> +        Arrays.asList(
> +            {{ -for item in flag_elements }}
> +            {{ -if not item.is_read_write }}
> +            Flags.FLAG_{item.flag_name_constant_suffix},
> +            {{ -endif }}
> +            {{ -endfor }}
> +            ""{# The empty string here is to resolve the ending comma #}
> +        )
> +    );
> +}
> --- tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template
> +++ tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template
> -{{ if not library_exported- }}
> -// TODO(b/303773055): Remove the annotation after access issue is resolved.
> -import android.compat.annotation.UnsupportedAppUsage;
> -{{ -endif }}
> -import java.util.Arrays;
> +
> -import java.util.HashSet;
> -import java.util.Set;
> +import java.util.function.Predicate;
> -public class FakeFeatureFlagsImpl implements FeatureFlags \{
> +public class FakeFeatureFlagsImpl extends CustomFeatureFlags \{
> +    private Map<String, Boolean> mFlagMap = new HashMap<>();
> +
> -        resetAll();
> +        super(null);
> +        // Initialize the map with null values
> +        for (String flagName : getFlagNames()) \{
> +            mFlagMap.put(flagName, null);
> +        }
> -{{ for item in flag_elements}}
> -{{ if not library_exported }}    @UnsupportedAppUsage{{ -endif }}
> -    public boolean {item.method_name}() \{
> -        return getValue(Flags.FLAG_{item.flag_name_constant_suffix});
> +    protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{
> +        Boolean value = this.mFlagMap.get(flagName);
> +        if (value == null) \{
> +            throw new IllegalArgumentException(flagName + " is not set");
> +        }
> +        return value;
> -{{ endfor}}
> +
> -{{ if not library_exported }}
> -    public boolean isFlagReadOnlyOptimized(String flagName) \{
> -        if (mReadOnlyFlagsSet.contains(flagName) &&
> -            isOptimizationEnabled()) \{
> -                return true;
> -        }
> -        return false;
> -    }
> -
> -    @com.android.aconfig.annotations.AssumeTrueForR8
> -    private boolean isOptimizationEnabled() \{
> -        return false;
> -    }
> -{{ -endif }}
> -    private boolean getValue(String flagName) \{
> -        Boolean value = this.mFlagMap.get(flagName);
> -        if (value == null) \{
> -            throw new IllegalArgumentException(flagName + " is not set");
> -        }
> -        return value;
> -    }
> -
> -
> -    private Map<String, Boolean> mFlagMap = new HashMap<>(
> -        Map.ofEntries(
> -            {{ -for item in flag_elements }}
> -            Map.entry(Flags.FLAG_{item.flag_name_constant_suffix}, false)
> -            {{ -if not @last }},{{ endif }}
> -            {{ -endfor }}
> -        )
> -    );
> -
> -    private Set<String> mReadOnlyFlagsSet = new HashSet<>(
> -        Arrays.asList(
> -            {{ -for item in flag_elements }}
> -            {{ -if not item.is_read_write }}
> -            Flags.FLAG_{item.flag_name_constant_suffix},
> -            {{ -endif }}
> -            {{ -endfor }}
> -            ""{# The empty string here is to resolve the ending comma #}
> -        )
> -    );

Original patch:
 diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
old mode 100644
new mode 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -63,21 +63,28 @@
         "FeatureFlags.java",
         include_str!("../../templates/FeatureFlags.java.template"),
     )?;
+    template.add_template(
+        "CustomFeatureFlags.java",
+        include_str!("../../templates/CustomFeatureFlags.java.template"),
+    )?;
     template.add_template(
         "FakeFeatureFlagsImpl.java",
         include_str!("../../templates/FakeFeatureFlagsImpl.java.template"),
     )?;
 
     let path: PathBuf = package.split('.').collect();
-    ["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"]
-        .iter()
-        .map(|file| {
-            Ok(OutputFile {
-                contents: template.render(file, &context)?.into(),
-                path: path.join(file),
-            })
-        })
-        .co
[[[Original patch trimmed due to size. Decoded string size: 26318. Decoded string SHA1: 7db34b7baf0a0bbaa1cff48b6ccab9c65408e743.]]]

Result patch:
 diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index 18a4be5..9abc892 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -64,20 +64,27 @@
         include_str!("../../templates/FeatureFlags.java.template"),
     )?;
     template.add_template(
+        "CustomFeatureFlags.java",
+        include_str!("../../templates/CustomFeatureFlags.java.template"),
+    )?;
+    template.add_template(
         "FakeFeatureFlagsImpl.java",
         include_str!("../../templates/FakeFeatureFlagsImpl.java.template"),
     )?;
 
     let path: PathBuf = package.split('.').collect();
-    ["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"]
-        .iter()
-        .map(|file| {
-            Ok(OutputFile {
-                contents: template.render(file, &context)?.into(),
-                path: path.join(file),
-            })
-        })
-        .collect::<Result<Vec<OutputFile>>>
[[[Result patch trimmed due to size. Decoded string size: 26308. Decoded string SHA1: bb07ee948a630a6bc4cfbbf2a8df178f3e6d3103.]]]

Change-Id: I94184633303b9d76f7943451fb3b2c93d071ec1c
2024-04-24 14:43:27 +00:00
Ted Bauer
171944d88a Merge "Update aconfig storage deps for CPP codegen" into main 2024-04-23 22:56:50 +00:00
Ted Bauer
8d20d51bf8 Update aconfig storage deps for CPP codegen
Bug: 328444881
Test: m AconfigDemoActivity
Change-Id: I12d746d3270dce39533e1afd213343e232044161
2024-04-23 18:07:40 +00:00
Dennis Shen
1ebcd017ae aconfig: remove cache filtering by container
No need for cache filtering based on container anymore. This is now
performed by build system automatically. The caches feed into storage
generation command are automatically filtered based on owning
container.

Bug: b/312444587
Test: atest aconfig.test
Change-Id: I44f3ac03d50b77a191a82ff7ed4d02766012492d
2024-04-19 21:44:32 +00:00
Dennis Shen
6f4c692948 aconfig: update flag info storage file
previously we store three bits per flag: is sticky, is read write, has
override. so when a local override arrives, is sticky bit as well has
override bit are set to true. this becomes problematic when the local
override is removed. we are not sure if we should remove has override
bit as well (server override could still be in place).

therefore restructuring the flag info for each flag into new three bits:
is read write, has server override and has local override. so now server
override and local override bits are independent from each other.

Bug: b/312444587
Test: atest -c
Change-Id: I03b2bb7312480773236c95f2b39f2589fee41924
2024-04-18 21:22:49 +00:00
Ted Bauer
206d44aff5 aflags: read protos from all containers
Create one library for reading protos from all containers, instead of
having numerous libraries perform the same logic. For Java, we will
create a similar library reusing the same
partition_aconfig_flags_paths.txt.

Bug: 324436145
Test: adb shell aflags list # Confirm that various containers appear
Change-Id: I924e281a50f9a609e1c07c03267eebe3dce52752
2024-04-18 14:38:41 +00:00
Dennis Shen
e6b424ad4a Merge "aconfig: add support for local override" into main 2024-04-17 19:07:56 +00:00
Dennis Shen
9f236037a2 aconfig: add support for local override
1, add a new field in storage metadata proto, for each container, there
is a local override file.

2, update write api to expose the api to map a writable file given the
specific path. the cannonical api will require a storage metadata proto,
and then find the right file path and map it.

3, minor update to make the proto lib cc_library instead of
cc_library_static

Bug: b/312444587
Test: atest -c
Change-Id: Iaf0aff44c1ca3ad4bffc5e06bb99bb276b9069c5
2024-04-17 12:25:11 +00:00
Ted Bauer
8f9ca8075f Merge "aconfig: switch read api lib to cc_library" into main 2024-04-15 17:22:00 +00:00
Dennis Shen
36661d4cd0 aconfig: switch read api lib to cc_library
Bug: b/321077378
Test: atest -c
Change-Id: I8d64396797b01a8ce2f4bee165596701940836e4
2024-04-12 21:21:44 +00:00
Dennis Shen
7d642b10df Merge "aconfig: add write api cpp test to presubmit" into main 2024-04-12 18:26:55 +00:00
Dennis Shen
e8fa42f45a aconfig: add write api cpp test to presubmit
Bug: b/321077378
Test atest -c

Change-Id: Ib04280f25eb6c4de6ff1523579e6ac96a868ff1d
2024-04-12 16:57:28 +00:00
Dennis Shen
f17dbcd8b7 aconfig: update flag info query api
Currently flag info query api is called get_boolean_flag_attribute, in
this change, we switched it over to a flag value type generic
implementation get_flag_attribute. So in the future we want to add more flag value types, this api can stay the same.

Bug: b/312444587
Test: atest -c
Change-Id: I2b272f3fa3cb1d0edc8b77a44bf37752ffe95925
2024-04-12 16:28:10 +00:00
Dennis Shen
d74941b42d aconfig: create flag info file write c api
Bug: b/312444587
Test: atest -c
Change-Id: I310e1ed727ced454bec2016afe48f7a29561fac3
2024-04-11 20:23:22 +00:00