Merge "Parse RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION" into main
diff --git a/backported_fixes/Android.bp b/backported_fixes/Android.bp
new file mode 100644
index 0000000..a20f3fc
--- /dev/null
+++ b/backported_fixes/Android.bp
@@ -0,0 +1,115 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+ default_team: "trendy_team_android_media_reliability",
+}
+
+genrule {
+ name: "applied_backported_fixes",
+ tools: ["applied_backported_fixes_main"],
+ srcs: [":applied_backported_fix_binpbs"],
+ out: ["applied_backported_fixes.prop"],
+ cmd: "$(location applied_backported_fixes_main)" +
+ " -p $(location applied_backported_fixes.prop)" +
+ " $(in)",
+}
+
+java_library {
+ name: "backported_fixes_proto",
+ srcs: [
+ "backported_fixes.proto",
+ ],
+ host_supported: true,
+}
+
+java_library {
+ name: "backported_fixes_common",
+ srcs: ["src/java/com/android/build/backportedfixes/common/*.java"],
+ static_libs: [
+ "backported_fixes_proto",
+ "guava",
+ ],
+ host_supported: true,
+}
+
+java_test_host {
+ name: "backported_fixes_common_test",
+ srcs: ["tests/java/com/android/build/backportedfixes/common/*.java"],
+ static_libs: [
+ "backported_fixes_common",
+ "backported_fixes_proto",
+ "junit",
+ "truth",
+ "truth-liteproto-extension",
+ "truth-proto-extension",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ test_suites: ["general-tests"],
+}
+
+java_library {
+ name: "applied_backported_fixes_lib",
+ srcs: ["src/java/com/android/build/backportedfixes/*.java"],
+ static_libs: [
+ "backported_fixes_common",
+ "backported_fixes_proto",
+ "jcommander",
+ "guava",
+ ],
+ host_supported: true,
+}
+
+java_binary_host {
+ name: "applied_backported_fixes_main",
+ main_class: "com.android.build.backportedfixes.Main",
+ static_libs: [
+ "applied_backported_fixes_lib",
+ ],
+}
+
+java_test_host {
+ name: "applied_backported_fixes_test",
+ srcs: ["tests/java/com/android/build/backportedfixes/*.java"],
+ static_libs: [
+ "applied_backported_fixes_lib",
+ "backported_fixes_proto",
+ "junit",
+ "truth",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ test_suites: ["general-tests"],
+}
+
+gensrcs {
+ name: "applied_backported_fix_binpbs",
+ tools: ["aprotoc"],
+ srcs: [
+ "applied_fixes/*.txtpb",
+ ],
+ tool_files: [
+ "backported_fixes.proto",
+ ],
+ output_extension: "binpb",
+ cmd: "$(location aprotoc) " +
+ " --encode=com.android.build.backportedfixes.BackportedFix" +
+ " $(location backported_fixes.proto)" +
+ " < $(in)" +
+ " > $(out); echo $(out)",
+}
diff --git a/backported_fixes/OWNERS b/backported_fixes/OWNERS
new file mode 100644
index 0000000..ac176bf
--- /dev/null
+++ b/backported_fixes/OWNERS
@@ -0,0 +1,3 @@
+essick@google.com
+nchalko@google.com
+portmannc@google.com
diff --git a/backported_fixes/applied_fixes/ki350037023.txtpb b/backported_fixes/applied_fixes/ki350037023.txtpb
new file mode 100644
index 0000000..456a7ae
--- /dev/null
+++ b/backported_fixes/applied_fixes/ki350037023.txtpb
@@ -0,0 +1,19 @@
+# Copyright (C) 2024 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.
+#
+# proto-file: ../backported_fixes.proto
+# proto-message: BackportedFix
+
+known_issue: 350037023
+alias: 1
diff --git a/backported_fixes/backported_fixes.proto b/backported_fixes/backported_fixes.proto
new file mode 100644
index 0000000..91618ee
--- /dev/null
+++ b/backported_fixes/backported_fixes.proto
@@ -0,0 +1,37 @@
+// Copyright (C) 2024 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.
+
+syntax = "proto2";
+
+package com.android.build.backportedfixes;
+
+option java_multiple_files = true;
+
+// A list of backported fixes.
+message BackportedFixes {
+ repeated BackportedFix fixes = 1;
+}
+
+// A known issue approved for reporting Build.getBackportedFixStatus
+message BackportedFix {
+
+ // The issue id from the public bug tracker
+ // https://issuetracker.google.com/issues/{known_issue}
+ optional int64 known_issue = 1;
+ // The alias for the known issue.
+ // 1 - 1023 are valid aliases
+ // Must be unique across all backported fixes.
+ optional int32 alias = 2;
+}
+
diff --git a/backported_fixes/src/java/com/android/build/backportedfixes/Main.java b/backported_fixes/src/java/com/android/build/backportedfixes/Main.java
new file mode 100644
index 0000000..79148cc
--- /dev/null
+++ b/backported_fixes/src/java/com/android/build/backportedfixes/Main.java
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright (C) 2024 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 com.android.build.backportedfixes;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.android.build.backportedfixes.common.ClosableCollection;
+import com.android.build.backportedfixes.common.Parser;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.converters.FileConverter;
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public final class Main {
+ @Parameter(description = "BackportedFix proto binary files", converter = FileConverter.class,
+ required = true)
+ List<File> fixFiles;
+ @Parameter(description = "The file to write the property value to.",
+ names = {"--property_file", "-p"}, converter = FileConverter.class, required = true)
+ File propertyFile;
+
+ public static void main(String... argv) throws Exception {
+ Main main = new Main();
+ JCommander.newBuilder().addObject(main).build().parse(argv);
+ main.run();
+ }
+
+ Main() {
+ }
+
+ private void run() throws Exception {
+ try (var fixStreams = ClosableCollection.wrap(Parser.getFileInputStreams(fixFiles));
+ var out = Files.newWriter(propertyFile, UTF_8)) {
+ var fixes = Parser.parseBackportedFixes(fixStreams.getCollection());
+ writeFixesAsAliasBitSet(fixes, out);
+ }
+ }
+
+ static void writeFixesAsAliasBitSet(BackportedFixes fixes, Writer out) {
+ PrintWriter printWriter = new PrintWriter(out);
+ printWriter.println("# The following backported fixes have been applied");
+ for (var f : fixes.getFixesList()) {
+ printWriter.printf("# https://issuetracker.google.com/issues/%d with alias %d",
+ f.getKnownIssue(), f.getAlias());
+ printWriter.println();
+ }
+ var bsArray = Parser.getBitSetArray(
+ fixes.getFixesList().stream().mapToInt(BackportedFix::getAlias).toArray());
+ String bsString = Arrays.stream(bsArray).mapToObj(Long::toString).collect(
+ Collectors.joining(","));
+ printWriter.printf("ro.build.backported_fixes.alias_bitset.long_list=%s", bsString);
+ printWriter.println();
+ if (printWriter.checkError()) {
+ throw new RuntimeException("There was an error writing to " + out.toString());
+ }
+ }
+}
diff --git a/backported_fixes/src/java/com/android/build/backportedfixes/common/ClosableCollection.java b/backported_fixes/src/java/com/android/build/backportedfixes/common/ClosableCollection.java
new file mode 100644
index 0000000..75b6730
--- /dev/null
+++ b/backported_fixes/src/java/com/android/build/backportedfixes/common/ClosableCollection.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2024 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 com.android.build.backportedfixes.common;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/** An AutoCloseable holder for a collection of AutoCloseables. */
+public final class ClosableCollection<T extends AutoCloseable, C extends Collection<T>> implements
+ AutoCloseable {
+ C source;
+
+ /** Makes the collection AutoCloseable. */
+ public static <T extends AutoCloseable, C extends Collection<T>> ClosableCollection<T, C> wrap(
+ C source) {
+ return new ClosableCollection<>(source);
+ }
+
+ private ClosableCollection(C source) {
+ this.source = source;
+ }
+
+ /** Get the source collection. */
+ public C getCollection() {
+ return source;
+ }
+
+ /**
+ * Closes each item in the collection.
+ *
+ * @throws Exception if any close throws an an exception, a new exception is thrown with
+ * all the exceptions thrown closing the streams added as a suppressed
+ * exceptions.
+ */
+ @Override
+ public void close() throws Exception {
+ var failures = new ArrayList<Exception>();
+ for (T t : source) {
+ try {
+ t.close();
+ } catch (Exception e) {
+ failures.add(e);
+ }
+ }
+ if (!failures.isEmpty()) {
+ Exception e = new Exception(
+ "%d of %d failed while closing".formatted(failures.size(), source.size()));
+ failures.forEach(e::addSuppressed);
+ throw e;
+ }
+ }
+}
diff --git a/backported_fixes/src/java/com/android/build/backportedfixes/common/Parser.java b/backported_fixes/src/java/com/android/build/backportedfixes/common/Parser.java
new file mode 100644
index 0000000..6b08b8f
--- /dev/null
+++ b/backported_fixes/src/java/com/android/build/backportedfixes/common/Parser.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 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 com.android.build.backportedfixes.common;
+
+import com.android.build.backportedfixes.BackportedFix;
+import com.android.build.backportedfixes.BackportedFixes;
+
+import com.google.common.collect.ImmutableList;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.BitSet;
+import java.util.List;
+
+
+/** Static utilities for working with {@link BackportedFixes}. */
+public final class Parser {
+
+ /** Creates list of FileInputStreams for a list of files. */
+ public static ImmutableList<FileInputStream> getFileInputStreams(List<File> fixFiles) throws
+ FileNotFoundException {
+ var streams = ImmutableList.<FileInputStream>builder();
+ for (var f : fixFiles) {
+ streams.add(new FileInputStream(f));
+ }
+ return streams.build();
+ }
+
+ /** Converts a list of backported fix aliases into a long array representing a {@link BitSet} */
+ public static long[] getBitSetArray(int[] aliases) {
+ BitSet bs = new BitSet();
+ for (int a : aliases) {
+ bs.set(a);
+ }
+ return bs.toLongArray();
+ }
+
+ /**
+ * Creates a {@link BackportedFixes} from a list of {@link BackportedFix} binary proto streams.
+ */
+ public static BackportedFixes parseBackportedFixes(List<? extends InputStream> fixStreams)
+ throws
+ IOException {
+ var fixes = BackportedFixes.newBuilder();
+ for (var s : fixStreams) {
+ BackportedFix fix = BackportedFix.parseFrom(s);
+ fixes.addFixes(fix);
+ s.close();
+ }
+ return fixes.build();
+ }
+
+ private Parser() {
+ }
+}
diff --git a/backported_fixes/tests/java/com/android/build/backportedfixes/MainTest.java b/backported_fixes/tests/java/com/android/build/backportedfixes/MainTest.java
new file mode 100644
index 0000000..84061e1
--- /dev/null
+++ b/backported_fixes/tests/java/com/android/build/backportedfixes/MainTest.java
@@ -0,0 +1,64 @@
+
+/*
+ * Copyright (C) 2024 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 com.android.build.backportedfixes;
+
+import com.google.common.truth.Truth;
+
+import org.junit.Test;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/** Tests for {@link Main}. */
+public class MainTest {
+
+
+ @Test
+ public void writeFixesAsAliasBitSet_default() {
+ BackportedFixes fixes = BackportedFixes.newBuilder().build();
+ var result = new StringWriter();
+
+ Main.writeFixesAsAliasBitSet(fixes, new PrintWriter(result));
+
+ Truth.assertThat(result.toString())
+ .isEqualTo("""
+ # The following backported fixes have been applied
+ ro.build.backported_fixes.alias_bitset.long_list=
+ """);
+ }
+
+ @Test
+ public void writeFixesAsAliasBitSet_some() {
+ BackportedFixes fixes = BackportedFixes.newBuilder()
+ .addFixes(BackportedFix.newBuilder().setKnownIssue(1234L).setAlias(1))
+ .addFixes(BackportedFix.newBuilder().setKnownIssue(3L).setAlias(65))
+ .addFixes(BackportedFix.newBuilder().setKnownIssue(4L).setAlias(67))
+ .build();
+ var result = new StringWriter();
+
+ Main.writeFixesAsAliasBitSet(fixes, new PrintWriter(result));
+
+ Truth.assertThat(result.toString())
+ .isEqualTo("""
+ # The following backported fixes have been applied
+ # https://issuetracker.google.com/issues/1234 with alias 1
+ # https://issuetracker.google.com/issues/3 with alias 65
+ # https://issuetracker.google.com/issues/4 with alias 67
+ ro.build.backported_fixes.alias_bitset.long_list=2,10
+ """);
+ }
+}
diff --git a/backported_fixes/tests/java/com/android/build/backportedfixes/common/CloseableCollectionTest.java b/backported_fixes/tests/java/com/android/build/backportedfixes/common/CloseableCollectionTest.java
new file mode 100644
index 0000000..d3d84a8
--- /dev/null
+++ b/backported_fixes/tests/java/com/android/build/backportedfixes/common/CloseableCollectionTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 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 com.android.build.backportedfixes.common;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.truth.Correspondence;
+import com.google.common.truth.Truth;
+
+import org.junit.Test;
+
+/** Tests for {@link ClosableCollection}. */
+public class CloseableCollectionTest {
+
+ private static class FakeCloseable implements AutoCloseable {
+ private final boolean throwOnClose;
+ private final String name;
+
+
+ private boolean isClosed = false;
+
+ private FakeCloseable(String name, boolean throwOnClose) {
+ this.name = name;
+ this.throwOnClose = throwOnClose;
+
+ }
+
+ private static FakeCloseable named(String name) {
+ return new FakeCloseable(name, false);
+ }
+
+ private static FakeCloseable failing(String name) {
+ return new FakeCloseable(name, true);
+ }
+
+ public boolean isClosed() {
+ return isClosed;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (throwOnClose) {
+ throw new Exception(name + " close failed");
+ }
+ isClosed = true;
+ }
+ }
+
+
+ @Test
+ public void bothClosed() throws Exception {
+ var c = ImmutableSet.of(FakeCloseable.named("foo"), FakeCloseable.named("bar"));
+ try (var cc = ClosableCollection.wrap(c);) {
+ Truth.assertThat(cc.getCollection()).isSameInstanceAs(c);
+ }
+ Truth.assertThat(c)
+ .comparingElementsUsing(
+ Correspondence.transforming(FakeCloseable::isClosed, "is closed"))
+ .containsExactly(true, true);
+ }
+
+ @Test
+ public void bothFailed() {
+ var c = ImmutableSet.of(FakeCloseable.failing("foo"), FakeCloseable.failing("bar"));
+
+ try {
+ try (var cc = ClosableCollection.wrap(c);) {
+ Truth.assertThat(cc.getCollection()).isSameInstanceAs(c);
+ }
+ } catch (Exception e) {
+ Truth.assertThat(e).hasMessageThat().isEqualTo("2 of 2 failed while closing");
+ Truth.assertThat(e.getSuppressed())
+ .asList()
+ .comparingElementsUsing(
+ Correspondence.transforming(Exception::getMessage, "has a message of "))
+ .containsExactly("foo close failed", "bar close failed");
+ }
+ }
+}
diff --git a/backported_fixes/tests/java/com/android/build/backportedfixes/common/ParserTest.java b/backported_fixes/tests/java/com/android/build/backportedfixes/common/ParserTest.java
new file mode 100644
index 0000000..444e694
--- /dev/null
+++ b/backported_fixes/tests/java/com/android/build/backportedfixes/common/ParserTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 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 com.android.build.backportedfixes.common;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
+
+import com.android.build.backportedfixes.BackportedFix;
+import com.android.build.backportedfixes.BackportedFixes;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+
+/** Tests for {@link Parser}.*/
+public class ParserTest {
+
+ @Test
+ public void getFileInputStreams() throws IOException {
+ var results = Parser.getFileInputStreams(
+ ImmutableList.of(Files.createTempFile("test", null).toFile()));
+ assertThat(results).isNotEmpty();
+ }
+
+
+ @Test
+ public void getBitSetArray_empty() {
+ var results = Parser.getBitSetArray(new int[]{});
+ assertThat(results).isEmpty();
+ }
+
+ @Test
+ public void getBitSetArray_2_3_64() {
+ var results = Parser.getBitSetArray(new int[]{2,3,64});
+ assertThat(results).asList().containsExactly(12L,1L).inOrder();
+ }
+
+ @Test
+ public void parseBackportedFixes_empty() throws IOException {
+ var result = Parser.parseBackportedFixes(ImmutableList.of());
+ assertThat(result).isEqualTo(BackportedFixes.getDefaultInstance());
+ }
+
+ @Test
+ public void parseBackportedFixes_oneBlank() throws IOException {
+ var result = Parser.parseBackportedFixes(
+ ImmutableList.of(inputStream(BackportedFix.getDefaultInstance())));
+
+ assertThat(result).isEqualTo(
+ BackportedFixes.newBuilder()
+ .addFixes(BackportedFix.getDefaultInstance())
+ .build());
+ }
+
+ @Test
+ public void parseBackportedFixes_two() throws IOException {
+ BackportedFix ki123 = BackportedFix.newBuilder()
+ .setKnownIssue(123)
+ .setAlias(1)
+ .build();
+ BackportedFix ki456 = BackportedFix.newBuilder()
+ .setKnownIssue(456)
+ .setAlias(2)
+ .build();
+ var result = Parser.parseBackportedFixes(
+ ImmutableList.of(inputStream(ki123), inputStream(ki456)));
+ assertThat(result).isEqualTo(
+ BackportedFixes.newBuilder()
+ .addFixes(ki123)
+ .addFixes(ki456)
+ .build());
+ }
+
+ private static ByteArrayInputStream inputStream(BackportedFix f) {
+ return new ByteArrayInputStream(f.toByteArray());
+ }
+}
diff --git a/ci/Android.bp b/ci/Android.bp
index 0dfbd37..3f28be4 100644
--- a/ci/Android.bp
+++ b/ci/Android.bp
@@ -25,7 +25,7 @@
"build_test_suites_test.py",
],
libs: [
- "build_test_suites",
+ "build_test_suites_lib",
"pyfakefs",
"ci_test_lib",
],
@@ -56,7 +56,7 @@
"build_test_suites_local_test.py",
],
libs: [
- "build_test_suites",
+ "build_test_suites_lib",
"pyfakefs",
"ci_test_lib",
],
@@ -79,7 +79,7 @@
"optimized_targets_test.py",
],
libs: [
- "build_test_suites",
+ "build_test_suites_lib",
"pyfakefs",
],
test_options: {
@@ -95,7 +95,7 @@
},
}
-python_library_host {
+python_binary_host {
name: "build_test_suites",
srcs: [
"build_test_suites.py",
@@ -103,6 +103,28 @@
"test_mapping_module_retriever.py",
"build_context.py",
"test_discovery_agent.py",
+ "metrics_agent.py",
+ "buildbot.py",
+ ],
+ main: "build_test_suites.py",
+ libs: [
+ "soong-metrics-proto-py",
+ ],
+}
+
+python_library_host {
+ name: "build_test_suites_lib",
+ srcs: [
+ "build_test_suites.py",
+ "optimized_targets.py",
+ "test_mapping_module_retriever.py",
+ "build_context.py",
+ "test_discovery_agent.py",
+ "metrics_agent.py",
+ "buildbot.py",
+ ],
+ libs: [
+ "soong-metrics-proto-py",
],
}
diff --git a/ci/build_context.py b/ci/build_context.py
index cc48d53..c7a1def 100644
--- a/ci/build_context.py
+++ b/ci/build_context.py
@@ -47,6 +47,9 @@
self.is_test_mapping = False
self.test_mapping_test_groups = set()
self.file_download_options = set()
+ self.name = test_info_dict.get('name')
+ self.command = test_info_dict.get('command')
+ self.extra_options = test_info_dict.get('extraOptions')
for opt in test_info_dict.get('extraOptions', []):
key = opt.get('key')
if key == 'test-mapping-test-group':
diff --git a/ci/build_device_and_tests b/ci/build_device_and_tests
new file mode 100755
index 0000000..9d11268
--- /dev/null
+++ b/ci/build_device_and_tests
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+#
+# Copyright 2024, 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.
+
+build/soong/soong_ui.bash --make-mode build_test_suites || exit $?
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@ || exit $?
diff --git a/ci/build_test_suites b/ci/build_test_suites
index 5aaf2f4..9d11268 100755
--- a/ci/build_test_suites
+++ b/ci/build_test_suites
@@ -1,4 +1,4 @@
-#!prebuilts/build-tools/linux-x86/bin/py3-cmd -B
+#!/usr/bin/env bash
#
# Copyright 2024, The Android Open Source Project
#
@@ -14,7 +14,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import build_test_suites
-import sys
-
-build_test_suites.main(sys.argv[1:])
+build/soong/soong_ui.bash --make-mode build_test_suites || exit $?
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@ || exit $?
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index b8c4a38..4d3b546 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -20,11 +20,14 @@
import logging
import os
import pathlib
+import re
import subprocess
import sys
from typing import Callable
from build_context import BuildContext
import optimized_targets
+import metrics_agent
+import test_discovery_agent
REQUIRED_ENV_VARS = frozenset(['TARGET_PRODUCT', 'TARGET_RELEASE', 'TOP'])
@@ -70,7 +73,26 @@
build_targets = set()
packaging_commands_getters = []
+ test_discovery_zip_regexes = set()
+ optimization_rationale = ''
+ try:
+ # Do not use these regexes for now, only run this to collect data on what
+ # would be optimized.
+ test_discovery_zip_regexes = self._get_test_discovery_zip_regexes()
+ logging.info(f'Discovered test discovery regexes: {test_discovery_zip_regexes}')
+ except test_discovery_agent.TestDiscoveryError as e:
+ optimization_rationale = e.message
+ logging.warning(f'Unable to perform test discovery: {optimization_rationale}')
for target in self.args.extra_targets:
+ if optimization_rationale:
+ get_metrics_agent().report_unoptimized_target(target, optimization_rationale)
+ else:
+ regex = r'\b(%s)\b' % re.escape(target)
+ if any(re.search(regex, opt) for opt in test_discovery_zip_regexes):
+ get_metrics_agent().report_unoptimized_target(target, 'Test artifact used.')
+ else:
+ get_metrics_agent().report_optimized_target(target)
+
if self._unused_target_exclusion_enabled(
target
) and not self.build_context.build_target_used(target):
@@ -97,6 +119,34 @@
in self.build_context.enabled_build_features
)
+ def _get_test_discovery_zip_regexes(self) -> set[str]:
+ build_target_regexes = set()
+ for test_info in self.build_context.test_infos:
+ tf_command = self._build_tf_command(test_info)
+ discovery_agent = test_discovery_agent.TestDiscoveryAgent(tradefed_args=tf_command)
+ for regex in discovery_agent.discover_test_zip_regexes():
+ build_target_regexes.add(regex)
+ return build_target_regexes
+
+
+ def _build_tf_command(self, test_info) -> list[str]:
+ command = [test_info.command]
+ for extra_option in test_info.extra_options:
+ if not extra_option.get('key'):
+ continue
+ arg_key = '--' + extra_option.get('key')
+ if arg_key == '--build-id':
+ command.append(arg_key)
+ command.append(os.environ.get('BUILD_NUMBER'))
+ continue
+ if extra_option.get('values'):
+ for value in extra_option.get('values'):
+ command.append(arg_key)
+ command.append(value)
+ else:
+ command.append(arg_key)
+
+ return command
@dataclass(frozen=True)
class BuildPlan:
@@ -113,19 +163,27 @@
Returns:
The exit code of the build.
"""
- args = parse_args(argv)
- check_required_env()
- build_context = BuildContext(load_build_context())
- build_planner = BuildPlanner(
- build_context, args, optimized_targets.OPTIMIZED_BUILD_TARGETS
- )
- build_plan = build_planner.create_build_plan()
+ get_metrics_agent().analysis_start()
+ try:
+ args = parse_args(argv)
+ check_required_env()
+ build_context = BuildContext(load_build_context())
+ build_planner = BuildPlanner(
+ build_context, args, optimized_targets.OPTIMIZED_BUILD_TARGETS
+ )
+ build_plan = build_planner.create_build_plan()
+ except:
+ raise
+ finally:
+ get_metrics_agent().analysis_end()
try:
execute_build_plan(build_plan)
except BuildFailureError as e:
logging.error('Build command failed! Check build_log for details.')
return e.return_code
+ finally:
+ get_metrics_agent().end_reporting()
return 0
@@ -183,12 +241,15 @@
except subprocess.CalledProcessError as e:
raise BuildFailureError(e.returncode) from e
- for packaging_commands_getter in build_plan.packaging_commands_getters:
- try:
+ get_metrics_agent().packaging_start()
+ try:
+ for packaging_commands_getter in build_plan.packaging_commands_getters:
for packaging_command in packaging_commands_getter():
run_command(packaging_command)
- except subprocess.CalledProcessError as e:
- raise BuildFailureError(e.returncode) from e
+ except subprocess.CalledProcessError as e:
+ raise BuildFailureError(e.returncode) from e
+ finally:
+ get_metrics_agent().packaging_end()
def get_top() -> pathlib.Path:
@@ -199,6 +260,10 @@
subprocess.run(args=args, check=True, stdout=stdout)
+def get_metrics_agent():
+ return metrics_agent.MetricsAgent.instance()
+
+
def main(argv):
dist_dir = os.environ.get('DIST_DIR')
if dist_dir:
@@ -209,3 +274,7 @@
filename=log_file,
)
sys.exit(build_test_suites(argv))
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/ci/build_test_suites_test.py b/ci/build_test_suites_test.py
index 2afaab7..26f4316 100644
--- a/ci/build_test_suites_test.py
+++ b/ci/build_test_suites_test.py
@@ -37,6 +37,8 @@
import ci_test_lib
import optimized_targets
from pyfakefs import fake_filesystem_unittest
+import metrics_agent
+import test_discovery_agent
class BuildTestSuitesTest(fake_filesystem_unittest.TestCase):
@@ -52,6 +54,10 @@
self.addCleanup(subprocess_run_patcher.stop)
self.mock_subprocess_run = subprocess_run_patcher.start()
+ metrics_agent_finalize_patcher = mock.patch('metrics_agent.MetricsAgent.end_reporting')
+ self.addCleanup(metrics_agent_finalize_patcher.stop)
+ self.mock_metrics_agent_end = metrics_agent_finalize_patcher.start()
+
self._setup_working_build_env()
def test_missing_target_release_env_var_raises(self):
@@ -256,6 +262,12 @@
def get_enabled_flag(self):
return f'{self.target}_enabled'
+ def setUp(self):
+ test_discovery_agent_patcher = mock.patch('test_discovery_agent.TestDiscoveryAgent.discover_test_zip_regexes')
+ self.addCleanup(test_discovery_agent_patcher.stop)
+ self.mock_test_discovery_agent_end = test_discovery_agent_patcher.start()
+
+
def test_build_optimization_off_builds_everything(self):
build_targets = {'target_1', 'target_2'}
build_planner = self.create_build_planner(
diff --git a/ci/metrics_agent.py b/ci/metrics_agent.py
new file mode 100644
index 0000000..bc2479e
--- /dev/null
+++ b/ci/metrics_agent.py
@@ -0,0 +1,116 @@
+# Copyright 2024, 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.
+
+"""MetricsAgent is a singleton class that collects metrics for optimized build."""
+
+from enum import Enum
+import time
+import metrics_pb2
+import os
+import logging
+
+
+class MetricsAgent:
+ _SOONG_METRICS_PATH = 'logs/soong_metrics'
+ _DIST_DIR = 'DIST_DIR'
+ _instance = None
+
+ def __init__(self):
+ raise RuntimeError(
+ 'MetricsAgent cannot be instantialized, use instance() instead'
+ )
+
+ @classmethod
+ def instance(cls):
+ if not cls._instance:
+ cls._instance = cls.__new__(cls)
+ cls._instance._proto = metrics_pb2.OptimizedBuildMetrics()
+ cls._instance._init_proto()
+ cls._instance._target_results = dict()
+
+ return cls._instance
+
+ def _init_proto(self):
+ self._proto.analysis_perf.name = 'Optimized build analysis time.'
+ self._proto.packaging_perf.name = 'Optimized build total packaging time.'
+
+ def analysis_start(self):
+ self._proto.analysis_perf.start_time = time.time_ns()
+
+ def analysis_end(self):
+ self._proto.analysis_perf.real_time = (
+ time.time_ns() - self._proto.analysis_perf.start_time
+ )
+
+ def packaging_start(self):
+ self._proto.packaging_perf.start_time = time.time_ns()
+
+ def packaging_end(self):
+ self._proto.packaging_perf.real_time = (
+ time.time_ns() - self._proto.packaging_perf.start_time
+ )
+
+ def report_optimized_target(self, name: str):
+ target_result = metrics_pb2.OptimizedBuildMetrics.TargetOptimizationResult()
+ target_result.name = name
+ target_result.optimized = True
+ self._target_results[name] = target_result
+
+ def report_unoptimized_target(self, name: str, optimization_rationale: str):
+ target_result = metrics_pb2.OptimizedBuildMetrics.TargetOptimizationResult()
+ target_result.name = name
+ target_result.optimization_rationale = optimization_rationale
+ target_result.optimized = False
+ self._target_results[name] = target_result
+
+ def target_packaging_start(self, name: str):
+ target_result = self._target_results.get(name)
+ target_result.packaging_perf.start_time = time.time_ns()
+ self._target_results[name] = target_result
+
+ def target_packaging_end(self, name: str):
+ target_result = self._target_results.get(name)
+ target_result.packaging_perf.real_time = (
+ time.time_ns() - target_result.packaging_perf.start_time
+ )
+
+ def add_target_artifact(
+ self,
+ target_name: str,
+ artifact_name: str,
+ size: int,
+ included_modules: set[str],
+ ):
+ target_result = self.target_results.get(target_name)
+ artifact = (
+ metrics_pb2.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact()
+ )
+ artifact.name = artifact_name
+ artifact.size = size
+ for module in included_modules:
+ artifact.included_modules.add(module)
+ target_result.output_artifacts.add(artifact)
+
+ def end_reporting(self):
+ for target_result in self._target_results.values():
+ self._proto.target_result.append(target_result)
+ soong_metrics_proto = metrics_pb2.MetricsBase()
+ # Read in existing metrics that should have been written out by the soong
+ # build command so that we don't overwrite them.
+ with open(os.path.join(os.environ[self._DIST_DIR], self._SOONG_METRICS_PATH), 'rb') as f:
+ soong_metrics_proto.ParseFromString(f.read())
+ soong_metrics_proto.optimized_build_metrics.CopyFrom(self._proto)
+ logging.info(soong_metrics_proto)
+ with open(os.path.join(os.environ[self._DIST_DIR], self._SOONG_METRICS_PATH), 'wb') as f:
+ f.write(soong_metrics_proto.SerializeToString())
diff --git a/ci/test_discovery_agent.py b/ci/test_discovery_agent.py
index 4eed28d..008ee47 100644
--- a/ci/test_discovery_agent.py
+++ b/ci/test_discovery_agent.py
@@ -17,7 +17,6 @@
import logging
import os
import subprocess
-import buildbot
class TestDiscoveryAgent:
@@ -50,7 +49,7 @@
A list of test zip regexes that TF is going to try to pull files from.
"""
test_discovery_output_file_name = os.path.join(
- buildbot.OutDir(), self._TRADEFED_DISCOVERY_OUTPUT_FILE_NAME
+ os.environ.get('TOP'), 'out', self._TRADEFED_DISCOVERY_OUTPUT_FILE_NAME
)
with open(
test_discovery_output_file_name, mode="w+t"
diff --git a/core/Makefile b/core/Makefile
index ab96f87..35a8a89 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -192,6 +192,34 @@
unique_product_copy_files_pairs :=
unique_product_copy_files_destinations :=
+
+# Returns a list of EXTRA_INSTALL_ZIPS trios whose primary file is contained within $(1)
+# The trios will contain the primary installed file : the directory to unzip the zip to : the zip
+define relevant-extra-install-zips
+$(strip $(foreach p,$(EXTRA_INSTALL_ZIPS), \
+ $(if $(filter $(call word-colon,1,$(p)),$(1)), \
+ $(p))))
+endef
+
+# Writes a text file that contains all of the files that will be inside a partition.
+# All the file paths will be relative to the partition's staging directory.
+# It will also take into account files inside zips listed in EXTRA_INSTALL_ZIPS.
+#
+# Arguments:
+# $(1): Output file
+# $(2): The partition's staging directory
+# $(3): Files to include in the partition
+define write-partition-file-list
+$(1): PRIVATE_FILES := $(subst $(2)/,,$(filter $(2)/%,$(3)))
+$(1): PRIVATE_EXTRA_INSTALL_ZIPS := $(call relevant-extra-install-zips,$(filter $(2)/%,$(3)))
+$(1): $$(HOST_OUT_EXECUTABLES)/extra_install_zips_file_list $(foreach p,$(call relevant-extra-install-zips,$(filter $(2)/%,$(3))),$(call word-colon,3,$(p)))
+ @echo Writing $$@
+ rm -f $$@
+ echo -n > $$@
+ $$(foreach f,$$(PRIVATE_FILES),echo "$$(f)" >> $$@$$(newline))
+ $$(HOST_OUT_EXECUTABLES)/extra_install_zips_file_list $(2) $$(PRIVATE_EXTRA_INSTALL_ZIPS) >> $$@
+endef
+
# -----------------------------------------------------------------
# Returns the max allowed size for an image suitable for hash verification
# (e.g., boot.img, recovery.img, etc).
@@ -692,7 +720,7 @@
BOARD_KERNEL_MODULE_DIRS += top
-# Default to not generating modules.dep for kernel modules on system
+# Default to not generating modules.load for kernel modules on system
# side. We should only load these modules if they are depended by vendor
# side modules.
ifeq ($(BOARD_SYSTEM_KERNEL_MODULES_LOAD),)
@@ -1267,6 +1295,10 @@
endif
+
+ramdisk_intermediates :=$= $(call intermediates-dir-for,PACKAGING,ramdisk)
+$(eval $(call write-partition-file-list,$(ramdisk_intermediates)/file_list.txt,$(TARGET_RAMDISK_OUT),$(INTERNAL_RAMDISK_FILES)))
+
# The value of RAMDISK_NODE_LIST is defined in system/core/rootdir/Android.bp.
# This file contains /dev nodes description added to the generic ramdisk
@@ -1564,6 +1596,7 @@
$(AVBTOOL) add_hash_footer \
--image $@ \
$(call get-partition-size-argument,$(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE)) \
+ --salt $$(sha256sum $(BUILD_NUMBER_FILE) $(BUILD_DATETIME_FILE) | cut -d " " -f 1 | tr -d '\n') \
--partition_name init_boot $(INTERNAL_AVB_INIT_BOOT_SIGNING_ARGS) \
$(BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS)
@@ -1622,6 +1655,8 @@
$(ALL_DEFAULT_INSTALLED_MODULES))
INTERNAL_VENDOR_RAMDISK_TARGET := $(call intermediates-dir-for,PACKAGING,vendor_boot)/vendor_ramdisk.cpio$(RAMDISK_EXT)
+vendor_ramdisk_intermediates :=$= $(call intermediates-dir-for,PACKAGING,vendor_ramdisk)
+$(eval $(call write-partition-file-list,$(vendor_ramdisk_intermediates)/file_list.txt,$(TARGET_VENDOR_RAMDISK_OUT),$(INTERNAL_VENDOR_RAMDISK_FILES)))
# Exclude recovery files in the default vendor ramdisk if including a standalone
# recovery ramdisk in vendor_boot.
@@ -1737,6 +1772,7 @@
$(AVBTOOL) add_hash_footer \
--image $@ \
$(call get-partition-size-argument,$(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE)) \
+ --salt $$(sha256sum $(BUILD_NUMBER_FILE) $(BUILD_DATETIME_FILE) | cut -d " " -f 1 | tr -d '\n') \
--partition_name vendor_boot $(INTERNAL_AVB_VENDOR_BOOT_SIGNING_ARGS) \
$(BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS)
else
@@ -3472,33 +3508,6 @@
FULL_SYSTEMIMAGE_DEPS += $(INTERNAL_ROOT_FILES) $(INSTALLED_FILES_FILE_ROOT)
-# Returns a list of EXTRA_INSTALL_ZIPS trios whose primary file is contained within $(1)
-# The trios will contain the primary installed file : the directory to unzip the zip to : the zip
-define relevant-extra-install-zips
-$(strip $(foreach p,$(EXTRA_INSTALL_ZIPS), \
- $(if $(filter $(call word-colon,1,$(p)),$(1)), \
- $(p))))
-endef
-
-# Writes a text file that contains all of the files that will be inside a partition.
-# All the file paths will be relative to the partition's staging directory.
-# It will also take into account files inside zips listed in EXTRA_INSTALL_ZIPS.
-#
-# Arguments:
-# $(1): Output file
-# $(2): The partition's staging directory
-# $(3): Files to include in the partition
-define write-partition-file-list
-$(1): PRIVATE_FILES := $(subst $(2)/,,$(filter $(2)/%,$(3)))
-$(1): PRIVATE_EXTRA_INSTALL_ZIPS := $(call relevant-extra-install-zips,$(filter $(2)/%,$(3)))
-$(1): $$(HOST_OUT_EXECUTABLES)/extra_install_zips_file_list $(foreach p,$(call relevant-extra-install-zips,$(filter $(2)/%,$(3))),$(call word-colon,3,$(p)))
- @echo Writing $$@
- rm -f $$@
- echo -n > $$@
- $$(foreach f,$$(PRIVATE_FILES),echo "$$(f)" >> $$@$$(newline))
- $$(HOST_OUT_EXECUTABLES)/extra_install_zips_file_list $(2) $$(PRIVATE_EXTRA_INSTALL_ZIPS) >> $$@
-endef
-
# -----------------------------------------------------------------
ifdef BUILDING_SYSTEM_IMAGE
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 26fe1da..092ddb0 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -39,6 +39,7 @@
$(call add_soong_config_var,ANDROID,TARGET_DYNAMIC_64_32_DRMSERVER)
$(call add_soong_config_var,ANDROID,TARGET_ENABLE_MEDIADRM_64)
$(call add_soong_config_var,ANDROID,TARGET_DYNAMIC_64_32_MEDIASERVER)
+$(call add_soong_config_var,ANDROID,BOARD_GENFS_LABELS_VERSION)
$(call add_soong_config_var,ANDROID,ADDITIONAL_M4DEFS,$(if $(BOARD_SEPOLICY_M4DEFS),$(addprefix -D,$(BOARD_SEPOLICY_M4DEFS))))
@@ -47,6 +48,11 @@
RECOVERY_FSTAB_VERSION := 2
$(call soong_config_set, recovery, recovery_api_version, $(RECOVERY_API_VERSION))
$(call soong_config_set, recovery, recovery_fstab_version, $(RECOVERY_FSTAB_VERSION))
+$(call soong_config_set_bool, recovery ,target_userimages_use_f2fs ,$(if $(TARGET_USERIMAGES_USE_F2FS),true,false))
+$(call soong_config_set_bool, recovery ,has_board_cacheimage_partition_size ,$(if $(BOARD_CACHEIMAGE_PARTITION_SIZE),true,false))
+ifdef TARGET_RECOVERY_UI_LIB
+ $(call soong_config_set_string_list, recovery, target_recovery_ui_lib, $(TARGET_RECOVERY_UI_LIB))
+endif
# For Sanitizers
$(call soong_config_set_bool,ANDROID,ASAN_ENABLED,$(if $(filter address,$(SANITIZE_TARGET)),true,false))
@@ -229,21 +235,6 @@
$(call soong_config_set_bool,google_graphics,board_uses_scaler_m2m1shot,$(if $(filter true,$(BOARD_USES_SCALER_M2M1SHOT)),true,false))
$(call soong_config_set_bool,google_graphics,board_uses_align_restriction,$(if $(filter true,$(BOARD_USES_ALIGN_RESTRICTION)),true,false))
-# Export video_codec variables to soong for exynos modules
-$(call soong_config_set,video_codec,target_soc_name,$(TARGET_SOC_NAME))
-$(call soong_config_set_bool,video_codec,board_use_codec2_hidl_1_2,$(if $(filter true,$(BOARD_USE_CODEC2_HIDL_1_2)),true,false))
-$(call soong_config_set_bool,video_codec,board_support_mfc_enc_bt2020,$(if $(filter true,$(BOARD_SUPPORT_MFC_ENC_BT2020)),true,false))
-$(call soong_config_set_bool,video_codec,board_support_flexible_p010,$(if $(filter true,$(BOARD_SUPPORT_FLEXIBLE_P010)),true,false))
-$(call soong_config_set_bool,video_codec,board_use_codec2_aidl,$(if $(BOARD_USE_CODEC2_AIDL),true,false))
-$(call soong_config_set,video_codec,board_gpu_type,$(BOARD_GPU_TYPE))
-$(call soong_config_set_bool,video_codec,board_use_small_secure_memory,$(if $(filter true,$(BOARD_USE_SMALL_SECURE_MEMORY)),true,false))
-ifdef BOARD_SUPPORT_MFC_VERSION
- $(call soong_config_set,video_codec,board_support_mfc_version,$(BOARD_SUPPORT_MFC_VERSION))
-endif
-ifdef BOARD_USE_MAX_SECURE_RESOURCE
- $(call soong_config_set,video_codec,board_use_max_secure_resource,$(BOARD_USE_MAX_SECURE_RESOURCE))
-endif
-
# Export related variables to soong for hardware/google/graphics/common/libacryl:libacryl
ifdef BOARD_LIBACRYL_DEFAULT_COMPOSITOR
$(call soong_config_set,acryl,libacryl_default_compositor,$(BOARD_LIBACRYL_DEFAULT_COMPOSITOR))
@@ -276,3 +267,8 @@
$(call soong_config_set_bool,fs_config,vendor_dlkm,$(if $(BOARD_USES_VENDOR_DLKMIMAGE)$(BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE),true,false))
$(call soong_config_set_bool,fs_config,odm_dlkm,$(if $(BOARD_USES_ODM_DLKMIMAGE)$(BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE),true,false))
$(call soong_config_set_bool,fs_config,system_dlkm,$(if $(BOARD_USES_SYSTEM_DLKMIMAGE)$(BOARD_SYSTEM_DLKMIMAGE_FILE_SYSTEM_TYPE),true,false))
+
+# Variables for telephony
+$(call soong_config_set_bool,telephony,sec_cp_secure_boot,$(if $(filter true,$(SEC_CP_SECURE_BOOT)),true,false))
+$(call soong_config_set_bool,telephony,cbd_protocol_sit,$(if $(filter true,$(CBD_PROTOCOL_SIT)),true,false))
+$(call soong_config_set_bool,telephony,use_radioexternal_hal_aidl,$(if $(filter true,$(USE_RADIOEXTERNAL_HAL_AIDL)),true,false))
diff --git a/core/config.mk b/core/config.mk
index f9ba38c..d62b86d 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -330,6 +330,18 @@
$(eval SOONG_CONFIG_TYPE_$(strip $1)_$(strip $2):=bool)
endef
+# soong_config_set_string_list is the same as soong_config_set, but it will
+# also type the variable as a list of strings, so that when using select() expressions
+# in blueprint files they can use list values instead of strings.
+# The values of the list must be space-separated.
+# $1 is the namespace. $2 is the variable name. $3 is the variable value.
+# Ex: $(call soong_config_set_string_list,acme,COOL_LIBS,a b)
+define soong_config_set_string_list
+$(call soong_config_define_internal,$1,$2) \
+$(eval SOONG_CONFIG_$(strip $1)_$(strip $2):=$(strip $3))
+$(eval SOONG_CONFIG_TYPE_$(strip $1)_$(strip $2):=string_list)
+endef
+
# soong_config_append appends to the value of the variable in the given Soong
# config namespace. If the variable does not exist, it will be defined. If the
# namespace does not exist, it will be defined.
@@ -894,6 +906,11 @@
PLATFORM_SEPOLICY_COMPAT_VERSIONS \
PLATFORM_SEPOLICY_VERSION \
+BOARD_GENFS_LABELS_VERSION ?= $(BOARD_API_LEVEL)
+ifeq ($(call math_gt,$(BOARD_API_LEVEL),$(BOARD_GENFS_LABELS_VERSION)),true)
+ $(error BOARD_GENFS_LABELS_VERSION ($(BOARD_GENFS_LABELS_VERSION)) must be greater than or equal to BOARD_API_LEVEL ($(BOARD_API_LEVEL)))
+endif
+
ifeq ($(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS),true)
ifneq ($(PRODUCT_USE_DYNAMIC_PARTITIONS),true)
$(error PRODUCT_USE_DYNAMIC_PARTITIONS must be true when PRODUCT_RETROFIT_DYNAMIC_PARTITIONS \
@@ -1302,10 +1319,6 @@
SOONG_VARIABLES :=
SOONG_EXTRA_VARIABLES :=
--include external/ltp/android/ltp_package_list.mk
-DEFAULT_DATA_OUT_MODULES := ltp $(ltp_packages)
-.KATI_READONLY := DEFAULT_DATA_OUT_MODULES
-
include $(BUILD_SYSTEM)/dumpvar.mk
ifdef BOARD_VNDK_VERSION
diff --git a/core/definitions.mk b/core/definitions.mk
index cd1b36e..adb35e0 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2605,7 +2605,87 @@
@$(call emit-line,$(wordlist 108501,109000,$(1)),$(2))
@$(call emit-line,$(wordlist 109001,109500,$(1)),$(2))
@$(call emit-line,$(wordlist 109501,110000,$(1)),$(2))
- @$(if $(wordlist 110001,110002,$(1)),$(error dump-words-to-file: Too many words ($(words $(1)))))
+ @$(call emit-line,$(wordlist 110001,110500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 110501,111000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 111001,111500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 111501,112000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 112001,112500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 112501,113000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 113001,113500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 113501,114000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 114001,114500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 114501,115000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 115001,115500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 115501,116000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 116001,116500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 116501,117000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 117001,117500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 117501,118000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 118001,118500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 118501,119000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 119001,119500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 119501,120000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 120001,120500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 120501,121000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 121001,121500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 121501,122000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 122001,122500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 122501,123000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 123001,123500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 123501,124000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 124001,124500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 124501,125000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 125001,125500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 125501,126000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 126001,126500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 126501,127000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 127001,127500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 127501,128000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 128001,128500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 128501,129000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 129001,129500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 129501,130000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 130001,130500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 130501,131000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 131001,131500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 131501,132000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 132001,132500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 132501,133000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 133001,133500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 133501,134000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 134001,134500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 134501,135000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 135001,135500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 135501,136000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 136001,136500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 136501,137000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 137001,137500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 137501,138000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 138001,138500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 138501,139000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 139001,139500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 139501,140000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 140001,140500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 140501,141000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 141001,141500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 141501,142000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 142001,142500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 142501,143000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 143001,143500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 143501,144000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 144001,144500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 144501,145000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 145001,145500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 145501,146000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 146001,146500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 146501,147000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 147001,147500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 147501,148000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 148001,148500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 148501,149000,$(1)),$(2))
+ @$(call emit-line,$(wordlist 149001,149500,$(1)),$(2))
+ @$(call emit-line,$(wordlist 149501,150000,$(1)),$(2))
+ @$(if $(wordlist 150001,150002,$(1)),$(error dump-words-to-file: Too many words ($(words $(1)))))
endef
# Return jar arguments to compress files in a given directory
# $(1): directory
diff --git a/core/java_common.mk b/core/java_common.mk
index a21f062..f574b76 100644
--- a/core/java_common.mk
+++ b/core/java_common.mk
@@ -32,7 +32,7 @@
else ifneq (,$(LOCAL_SDK_VERSION)$(TARGET_BUILD_USE_PREBUILT_SDKS))
# TODO(ccross): allow 1.9 for current and unbundled once we have SDK system modules
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
- else ifeq ($(EXPERIMENTAL_TARGET_JAVA_VERSION_21),true)
+ else ifeq ($(RELEASE_TARGET_JAVA_21),true)
LOCAL_JAVA_LANGUAGE_VERSION := 21
else
LOCAL_JAVA_LANGUAGE_VERSION := 17
diff --git a/core/layoutlib_data.mk b/core/layoutlib_data.mk
index e420a00..dabcfb2 100644
--- a/core/layoutlib_data.mk
+++ b/core/layoutlib_data.mk
@@ -31,8 +31,18 @@
$(hide) mkdir -p $(dir $@)
$(hide) cp -vf $< $@
-# List of all data files - font files, font configuration files, key character map files
-LAYOUTLIB_FILES := $(fonts_device) $(font_config) $(keyboards)
+HYPHEN_TEMP := $(call intermediates-dir-for,PACKAGING,hyphen,HOST,COMMON)
+
+# The hyphenation pattern files needed to support text hyphenation
+hyphen := $(filter $(TARGET_OUT)/usr/hyphen-data/%.hyb, $(INTERNAL_SYSTEMIMAGE_FILES))
+hyphen := $(addprefix $(HYPHEN_TEMP)/, $(notdir $(hyphen)))
+
+$(hyphen): $(HYPHEN_TEMP)/%: $(TARGET_OUT)/usr/hyphen-data/%
+ $(hide) mkdir -p $(dir $@)
+ $(hide) cp -vf $< $@
+
+# List of all data files - font files, font configuration files, key character map files, hyphenation pattern files
+LAYOUTLIB_FILES := $(fonts_device) $(font_config) $(keyboards) $(hyphen)
.PHONY: layoutlib layoutlib-tests
layoutlib layoutlib-tests: $(LAYOUTLIB_FILES)
@@ -40,6 +50,7 @@
$(call dist-for-goals, layoutlib, $(foreach m,$(fonts_device), $(m):layoutlib_native/fonts/$(notdir $(m))))
$(call dist-for-goals, layoutlib, $(foreach m,$(font_config), $(m):layoutlib_native/fonts/$(notdir $(m))))
$(call dist-for-goals, layoutlib, $(foreach m,$(keyboards), $(m):layoutlib_native/keyboards/$(notdir $(m))))
+$(call dist-for-goals, layoutlib, $(foreach m,$(hyphen), $(m):layoutlib_native/hyphen-data/$(notdir $(m))))
FONT_TEMP :=
font_config :=
@@ -95,6 +106,7 @@
_layoutlib_font_config_files := $(sort $(wildcard frameworks/base/data/fonts/*.xml))
_layoutlib_fonts_files := $(filter $(TARGET_OUT)/fonts/%.ttf $(TARGET_OUT)/fonts/%.ttc $(TARGET_OUT)/fonts/%.otf, $(INTERNAL_SYSTEMIMAGE_FILES))
_layoutlib_keyboard_files := $(sort $(wildcard frameworks/base/data/keyboards/*.kcm))
+_layoutlib_hyphen_files := $(filter $(TARGET_OUT)/usr/hyphen-data/%.hyb, $(INTERNAL_SYSTEMIMAGE_FILES))
# Find out files disted with layoutlib in Soong.
### Filter out static libraries for Windows and files already handled in make.
@@ -124,6 +136,13 @@
echo data/keyboards/$(notdir $f),frameworks/base/data/keyboards,prebuilt_etc,,,,,$f,,, >> $@; \
)
+ $(foreach f,$(_layoutlib_hyphen_files), \
+ $(eval _module_name := $(ALL_INSTALLED_FILES.$f)) \
+ $(eval _module_path := $(strip $(sort $(ALL_MODULES.$(_module_name).PATH)))) \
+ $(eval _soong_module_type := $(strip $(sort $(ALL_MODULES.$(_module_name).SOONG_MODULE_TYPE)))) \
+ echo data/hyphen-data/$(notdir $f),$(_module_path),$(_soong_module_type),,,,,$f,,, >> $@; \
+ )
+
$(foreach f,$(_layoutlib_files_disted_by_soong), \
$(eval _prebuilt_module_file := $(call word-colon,1,$f)) \
$(eval _dist_file := $(call word-colon,2,$f)) \
@@ -152,7 +171,7 @@
.PHONY: layoutlib-sbom
layoutlib-sbom: $(LAYOUTLIB_SBOM)/layoutlib.spdx.json
-$(LAYOUTLIB_SBOM)/layoutlib.spdx.json: $(PRODUCT_OUT)/always_dirty_file.txt $(GEN_SBOM) $(LAYOUTLIB_SBOM)/sbom-metadata.csv $(_layoutlib_font_config_files) $(_layoutlib_fonts_files) $(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop $(_layoutlib_keyboard_files) $(LAYOUTLIB_RES_FILES) $(EMULATED_OVERLAYS_FILES) $(DEVICE_OVERLAYS_FILES)
+$(LAYOUTLIB_SBOM)/layoutlib.spdx.json: $(PRODUCT_OUT)/always_dirty_file.txt $(GEN_SBOM) $(LAYOUTLIB_SBOM)/sbom-metadata.csv $(_layoutlib_font_config_files) $(_layoutlib_fonts_files) $(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop $(_layoutlib_keyboard_files) $(_layoutlib_hyphen_files) $(LAYOUTLIB_RES_FILES) $(EMULATED_OVERLAYS_FILES) $(DEVICE_OVERLAYS_FILES)
rm -rf $@
$(GEN_SBOM) --output_file $@ --metadata $(LAYOUTLIB_SBOM)/sbom-metadata.csv --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --module_name "layoutlib" --json
diff --git a/core/main.mk b/core/main.mk
index ce066cb..624df49 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -277,11 +277,24 @@
# Include all of the makefiles in the system
#
-subdir_makefiles := $(SOONG_OUT_DIR)/installs-$(TARGET_PRODUCT)$(COVERAGE_SUFFIX).mk $(SOONG_ANDROID_MK)
+subdir_makefiles := \
+ $(SOONG_OUT_DIR)/installs-$(TARGET_PRODUCT)$(COVERAGE_SUFFIX).mk \
+ $(SOONG_ANDROID_MK) \
+ build/make/target/board/android-info.mk
# Android.mk files are only used on Linux builds, Mac only supports Android.bp
ifeq ($(HOST_OS),linux)
- subdir_makefiles += $(file <$(OUT_DIR)/.module_paths/Android.mk.list)
+ ifeq ($(PRODUCT_IGNORE_ALL_ANDROIDMK),true)
+ allowed_androidmk_files :=
+ ifdef PRODUCT_ANDROIDMK_ALLOWLIST_FILE
+ -include $(PRODUCT_ANDROIDMK_ALLOWLIST_FILE)
+ endif
+ allowed_androidmk_files += $(PRODUCT_ALLOWED_ANDROIDMK_FILES)
+ subdir_makefiles += $(filter $(allowed_androidmk_files),$(file <$(OUT_DIR)/.module_paths/Android.mk.list))
+ allowed_androidmk_files :=
+ else
+ subdir_makefiles += $(file <$(OUT_DIR)/.module_paths/Android.mk.list)
+ endif
endif
subdir_makefiles += $(SOONG_OUT_DIR)/late-$(TARGET_PRODUCT)$(COVERAGE_SUFFIX).mk
@@ -305,9 +318,6 @@
# Create necessary directories and symlinks in the root filesystem
include system/core/rootdir/create_root_structure.mk
-# Rules to create android-info.txt and device sku manifest files
-include build/make/target/board/android-info.mk
-
endif # dont_bother
ifndef subdir_makefiles_total
@@ -1389,6 +1399,7 @@
$(INSTALLED_RAMDISK_TARGET) \
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_INIT_BOOT_IMAGE_TARGET) \
+ $(INSTALLED_DTBOIMAGE_TARGET) \
$(INSTALLED_RADIOIMAGE_TARGET) \
$(INSTALLED_DEBUG_RAMDISK_TARGET) \
$(INSTALLED_DEBUG_BOOTIMAGE_TARGET) \
diff --git a/core/product.mk b/core/product.mk
index 7cf4ec2..1b336b0 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -284,6 +284,9 @@
# Whether APEX should be compressed or not
_product_single_value_vars += PRODUCT_COMPRESSED_APEX
+# Default fs type for APEX payload image (apex_payload.img)
+_product_single_value_vars += PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE
+
# VNDK version of product partition. It can be 'current' if the product
# partitions uses PLATFORM_VNDK_VERSION.
_product_single_value_vars += PRODUCT_PRODUCT_VNDK_VERSION
@@ -492,6 +495,13 @@
# should be included in the system_linker_config.
_product_list_vars += PRODUCT_EXTRA_STUB_LIBRARIES
+# If set to true, all Android.mk files will be ignored.
+_product_single_value_vars += PRODUCT_IGNORE_ALL_ANDROIDMK
+# When PRODUCT_IGNORE_ALL_ANDROIDMK is set to true, this variable will be used to allow some Android.mk files.
+_product_list_vars += PRODUCT_ALLOWED_ANDROIDMK_FILES
+# When PRODUCT_IGNORE_ALL_ANDROIDMK is set to true, path of file that contains a list of allowed Android.mk files
+_product_single_value_vars += PRODUCT_ANDROIDMK_ALLOWLIST_FILE
+
.KATI_READONLY := _product_single_value_vars _product_list_vars
_product_var_list :=$= $(_product_single_value_vars) $(_product_list_vars)
diff --git a/core/product_config.mk b/core/product_config.mk
index abe6e38..692e375 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -534,6 +534,17 @@
PRODUCT_COMPRESSED_APEX := $(OVERRIDE_PRODUCT_COMPRESSED_APEX)
endif
+ifdef OVERRIDE_PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE
+ PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE := $(OVERRIDE_PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE)
+else ifeq ($(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE),)
+ # Use ext4 as a default payload fs type
+ PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE := ext4
+endif
+ifeq ($(filter ext4 erofs,$(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE)),)
+ $(error PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE should be either erofs or ext4,\
+ not $(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE).)
+endif
+
$(KATI_obsolete_var OVERRIDE_PRODUCT_EXTRA_VNDK_VERSIONS \
,Use PRODUCT_EXTRA_VNDK_VERSIONS instead)
diff --git a/core/robolectric_test_config_template.xml b/core/robolectric_test_config_template.xml
index 257c820..1956b6e 100644
--- a/core/robolectric_test_config_template.xml
+++ b/core/robolectric_test_config_template.xml
@@ -22,6 +22,13 @@
<option name="exclude-paths" value="java" />
<option name="use-robolectric-resources" value="true" />
+ <!-- attempt to always show Tradefed errors -->
+ <option name="do-not-swallow-runner-errors" value="true" />
+
+ <!-- prevent Tradefed from hanging indefinitely in CI -->
+ <option name="socket-timeout" value="600000" />
+ <option name="test-case-timeout" value="2m" />
+
{EXTRA_CONFIGS}
<test class="com.android.tradefed.testtype.IsolatedHostTest" >
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 83ca2cc..0dd91cc 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -274,10 +274,7 @@
$(call add_json_str, DeviceCurrentApiLevelForVendorModules, $(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES))
$(call add_json_bool, CompressedApex, $(filter true,$(PRODUCT_COMPRESSED_APEX)))
-
-ifndef APEX_BUILD_FOR_PRE_S_DEVICES
-$(call add_json_bool, TrimmedApex, $(filter true,$(PRODUCT_TRIMMED_APEX)))
-endif
+$(call add_json_str, DefaultApexPayloadType, $(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE))
$(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
@@ -383,7 +380,7 @@
$(call add_json_str, ProductDirectory, $(dir $(INTERNAL_PRODUCT)))
$(call add_json_map,PartitionQualifiedVariables)
- $(foreach image_type,SYSTEM VENDOR CACHE USERDATA PRODUCT SYSTEM_EXT OEM ODM VENDOR_DLKM ODM_DLKM SYSTEM_DLKM, \
+ $(foreach image_type,INIT_BOOT BOOT VENDOR_BOOT SYSTEM VENDOR CACHE USERDATA PRODUCT SYSTEM_EXT OEM ODM VENDOR_DLKM ODM_DLKM SYSTEM_DLKM, \
$(call add_json_map,$(call to-lower,$(image_type))) \
$(call add_json_bool, BuildingImage, $(filter true,$(BUILDING_$(image_type)_IMAGE))) \
$(call add_json_str, BoardErofsCompressor, $(BOARD_$(image_type)IMAGE_EROFS_COMPRESSOR)) \
@@ -401,6 +398,10 @@
$(call add_json_str, BoardSquashfsCompressor, $(BOARD_$(image_type)IMAGE_SQUASHFS_COMPRESSOR)) \
$(call add_json_str, BoardSquashfsCompressorOpt, $(BOARD_$(image_type)IMAGE_SQUASHFS_COMPRESSOR_OPT)) \
$(call add_json_str, BoardSquashfsDisable4kAlign, $(BOARD_$(image_type)IMAGE_SQUASHFS_DISABLE_4K_ALIGN)) \
+ $(call add_json_str, BoardAvbKeyPath, $(BOARD_AVB_$(image_type)_KEY_PATH)) \
+ $(call add_json_str, BoardAvbAlgorithm, $(BOARD_AVB_$(image_type)_ALGORITHM)) \
+ $(call add_json_str, BoardAvbRollbackIndex, $(BOARD_AVB_$(image_type)_ROLLBACK_INDEX)) \
+ $(call add_json_str, BoardAvbRollbackIndexLocation, $(BOARD_AVB_$(image_type)_ROLLBACK_INDEX_LOCATION)) \
$(call add_json_str, ProductBaseFsPath, $(PRODUCT_$(image_type)_BASE_FS_PATH)) \
$(call add_json_str, ProductHeadroom, $(PRODUCT_$(image_type)_HEADROOM)) \
$(call add_json_str, ProductVerityPartition, $(PRODUCT_$(image_type)_VERITY_PARTITION)) \
@@ -426,6 +427,29 @@
$(call add_json_str, BoardFlashLogicalBlockSize, $(BOARD_FLASH_LOGICAL_BLOCK_SIZE))
$(call add_json_str, BoardFlashEraseBlockSize, $(BOARD_FLASH_ERASE_BLOCK_SIZE))
$(call add_json_bool, BuildingVbmetaImage, $(BUILDING_VBMETA_IMAGE))
+
+ # boot image stuff
+ $(call add_json_bool, BuildingRamdiskImage, $(filter true,$(BUILDING_RAMDISK_IMAGE)))
+ $(call add_json_bool, ProductBuildBootImage, $(filter true,$(PRODUCT_BUILD_BOOT_IMAGE)))
+ $(call add_json_str, ProductBuildVendorBootImage, $(PRODUCT_BUILD_VENDOR_BOOT_IMAGE))
+ $(call add_json_bool, ProductBuildInitBootImage, $(filter true,$(PRODUCT_BUILD_INIT_BOOT_IMAGE)))
+ $(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
+ $(call add_json_str, BoardPrebuiltBootimage, $(BOARD_PREBUILT_BOOT_IMAGE))
+ $(call add_json_str, BoardPrebuiltInitBootimage, $(BOARD_PREBUILT_INIT_BOOT_IMAGE))
+ $(call add_json_str, BoardBootimagePartitionSize, $(BOARD_BOOTIMAGE_PARTITION_SIZE))
+ $(call add_json_str, BoardInitBootimagePartitionSize, $(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE))
+ $(call add_json_str, BoardBootHeaderVersion, $(BOARD_BOOT_HEADER_VERSION))
+ $(call add_json_str, TargetKernelPath, $(TARGET_KERNEL_PATH))
+ $(call add_json_bool, BoardUsesGenericKernelImage, $(BOARD_USES_GENERIC_KERNEL_IMAGE))
+ $(call add_json_str, BootSecurityPatch, $(BOOT_SECURITY_PATCH))
+ $(call add_json_str, InitBootSecurityPatch, $(INIT_BOOT_SECURITY_PATCH))
+ $(call add_json_str, VendorSecurityPatch, $(VENDOR_SECURITY_PATCH))
+ $(call add_json_bool, BoardIncludeDtbInBootimg, $(BOARD_INCLUDE_DTB_IN_BOOTIMG))
+ $(call add_json_list, InternalKernelCmdline, $(INTERNAL_KERNEL_CMDLINE))
+ $(call add_json_list, InternalBootconfig, $(INTERNAL_BOOTCONFIG))
+ $(call add_json_str, InternalBootconfigFile, $(INTERNAL_BOOTCONFIG_FILE))
+
+ # Avb (android verified boot) stuff
$(call add_json_bool, BoardAvbEnable, $(filter true,$(BOARD_AVB_ENABLE)))
$(call add_json_str, BoardAvbAlgorithm, $(BOARD_AVB_ALGORITHM))
$(call add_json_str, BoardAvbKeyPath, $(BOARD_AVB_KEY_PATH))
@@ -441,7 +465,6 @@
$(call end_json_map))
$(call end_json_map)
- $(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
$(call add_json_bool, ProductUseDynamicPartitionSize, $(filter true,$(PRODUCT_USE_DYNAMIC_PARTITION_SIZE)))
$(call add_json_bool, CopyImagesForTargetFilesZip, $(filter true,$(COPY_IMAGES_FOR_TARGET_FILES_ZIP)))
@@ -455,15 +478,24 @@
# Used to generate _dlkm partitions
$(call add_json_bool, BuildingSystemDlkmImage, $(BUILDING_SYSTEM_DLKM_IMAGE))
$(call add_json_list, SystemKernelModules, $(BOARD_SYSTEM_KERNEL_MODULES))
+ $(call add_json_str, SystemKernelBlocklistFile, $(BOARD_SYSTEM_KERNEL_MODULES_BLOCKLIST_FILE))
+ $(call add_json_list, SystemKernelLoadModules, $(BOARD_SYSTEM_KERNEL_MODULES_LOAD))
+ $(call add_json_bool, BuildingVendorDlkmImage, $(BUILDING_VENDOR_DLKM_IMAGE))
+ $(call add_json_list, VendorKernelModules, $(BOARD_VENDOR_KERNEL_MODULES))
+ $(call add_json_str, VendorKernelBlocklistFile, $(BOARD_VENDOR_KERNEL_MODULES_BLOCKLIST_FILE))
+ $(call add_json_bool, BuildingOdmDlkmImage, $(BUILDING_ODM_DLKM_IMAGE))
+ $(call add_json_list, OdmKernelModules, $(BOARD_ODM_KERNEL_MODULES))
+ $(call add_json_str, OdmKernelBlocklistFile, $(BOARD_ODM_KERNEL_MODULES_BLOCKLIST_FILE))
+ $(call add_json_list, VendorRamdiskKernelModules, $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES))
+ $(call add_json_str, VendorRamdiskKernelBlocklistFile, $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_BLOCKLIST_FILE))
+ $(call add_json_list, VendorRamdiskKernelLoadModules, $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD))
+ $(call add_json_str, VendorRamdiskKernelOptionsFile, $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_OPTIONS_FILE))
# Used to generate /vendor/build.prop
$(call add_json_list, BoardInfoFiles, $(if $(TARGET_BOARD_INFO_FILES),$(TARGET_BOARD_INFO_FILES),$(firstword $(TARGET_BOARD_INFO_FILE) $(wildcard $(TARGET_DEVICE_DIR)/board-info.txt))))
$(call add_json_str, BootLoaderBoardName, $(TARGET_BOOTLOADER_BOARD_NAME))
- $(call add_json_map, ProductCopyFiles)
- $(foreach pair,$(PRODUCT_COPY_FILES),\
- $(call add_json_str,$(word 1,$(subst :, ,$(pair))),$(word 2,$(subst :, ,$(pair)))))
- $(call end_json_map)
+ $(call add_json_list, ProductCopyFiles, $(PRODUCT_COPY_FILES))
$(call end_json_map)
diff --git a/core/sysprop.mk b/core/sysprop.mk
index 9b70d1c..255b699 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -301,22 +301,12 @@
INSTALLED_SYSTEM_EXT_BUILD_PROP_TARGET := $(TARGET_OUT_SYSTEM_EXT)/etc/build.prop
-# ----------------------------------------------------------------
-# ramdisk/boot/etc/build.prop
-#
-
RAMDISK_BUILD_PROP_REL_PATH := system/etc/ramdisk/build.prop
+ifeq (true,$(BOARD_USES_RECOVERY_AS_BOOT))
+INSTALLED_RAMDISK_BUILD_PROP_TARGET := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/$(RAMDISK_BUILD_PROP_REL_PATH)
+else
INSTALLED_RAMDISK_BUILD_PROP_TARGET := $(TARGET_RAMDISK_OUT)/$(RAMDISK_BUILD_PROP_REL_PATH)
-$(eval $(call build-properties,\
- bootimage,\
- $(INSTALLED_RAMDISK_BUILD_PROP_TARGET),\
- $(empty),\
- $(empty),\
- $(empty),\
- $(empty),\
- $(empty)))
-
-$(eval $(call declare-1p-target,$(INSTALLED_RAMDISK_BUILD_PROP_TARGET)))
+endif
ALL_INSTALLED_BUILD_PROP_FILES := \
$(INSTALLED_BUILD_PROP_TARGET) \
diff --git a/core/tasks/general-tests.mk b/core/tasks/general-tests.mk
index d6fc072..1901ed5 100644
--- a/core/tasks/general-tests.mk
+++ b/core/tasks/general-tests.mk
@@ -27,21 +27,9 @@
# Create an artifact to include all test config files in general-tests.
general_tests_configs_zip := $(PRODUCT_OUT)/general-tests_configs.zip
-# Copy kernel test modules to testcases directories
-include $(BUILD_SYSTEM)/tasks/tools/vts-kernel-tests.mk
-ltp_copy_pairs := \
- $(call target-native-copy-pairs,$(kernel_ltp_modules),$(kernel_ltp_host_out))
-copy_ltp_tests := $(call copy-many-files,$(ltp_copy_pairs))
-
-# PHONY target to be used to build and test `vts_ltp_tests` without building full vts
-.PHONY: vts_kernel_ltp_tests
-vts_kernel_ltp_tests: $(copy_ltp_tests)
-
general_tests_shared_libs_zip := $(PRODUCT_OUT)/general-tests_host-shared-libs.zip
$(general_tests_zip) : $(general_tests_shared_libs_zip)
-$(general_tests_zip) : $(copy_ltp_tests)
-$(general_tests_zip) : PRIVATE_KERNEL_LTP_HOST_OUT := $(kernel_ltp_host_out)
$(general_tests_zip) : PRIVATE_general_tests_list_zip := $(general_tests_list_zip)
$(general_tests_zip) : .KATI_IMPLICIT_OUTPUTS := $(general_tests_list_zip) $(general_tests_configs_zip)
$(general_tests_zip) : PRIVATE_TOOLS := $(general_tests_tools)
@@ -52,7 +40,6 @@
rm -f $@ $(PRIVATE_general_tests_list_zip)
mkdir -p $(PRIVATE_INTERMEDIATES_DIR) $(PRIVATE_INTERMEDIATES_DIR)/tools
echo $(sort $(COMPATIBILITY.general-tests.FILES) $(COMPATIBILITY.general-tests.SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES)) | tr " " "\n" > $(PRIVATE_INTERMEDIATES_DIR)/list
- find $(PRIVATE_KERNEL_LTP_HOST_OUT) >> $(PRIVATE_INTERMEDIATES_DIR)/list
grep $(HOST_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/list > $(PRIVATE_INTERMEDIATES_DIR)/host.list || true
grep $(TARGET_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/list > $(PRIVATE_INTERMEDIATES_DIR)/target.list || true
grep -e .*\\.config$$ $(PRIVATE_INTERMEDIATES_DIR)/host.list > $(PRIVATE_INTERMEDIATES_DIR)/host-test-configs.list || true
diff --git a/core/tasks/tools/vts-kernel-tests.mk b/core/tasks/tools/vts-kernel-tests.mk
deleted file mode 100644
index e727dc1..0000000
--- a/core/tasks/tools/vts-kernel-tests.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2022 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.
-
--include external/ltp/android/ltp_package_list.mk
-
-include $(BUILD_SYSTEM)/tasks/tools/vts_package_utils.mk
-
-# Copy kernel test modules to testcases directories
-kernel_ltp_host_out := $(HOST_OUT_TESTCASES)/vts_kernel_ltp_tests
-kernel_ltp_vts_out := $(HOST_OUT)/$(test_suite_name)/android-$(test_suite_name)/testcases/vts_kernel_ltp_tests
-kernel_ltp_modules := \
- ltp \
- $(ltp_packages)
diff --git a/core/tasks/tools/vts_package_utils.mk b/core/tasks/tools/vts_package_utils.mk
deleted file mode 100644
index 1a819f2..0000000
--- a/core/tasks/tools/vts_package_utils.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Copyright (C) 2020 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.
-#
-
-# $(1): List of target native files to copy.
-# $(2): Copy destination directory.
-# Evaluates to a list of ":"-separated pairs src:dst.
-define target-native-copy-pairs
-$(foreach m,$(1),\
- $(eval _built_files := $(strip $(ALL_MODULES.$(m).BUILT_INSTALLED)\
- $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).BUILT_INSTALLED)))\
- $(foreach i, $(sort $(_built_files)),\
- $(eval bui_ins := $(subst :,$(space),$(i)))\
- $(eval ins := $(word 2,$(bui_ins)))\
- $(if $(filter $(TARGET_OUT_ROOT)/%,$(ins)),\
- $(eval bui := $(word 1,$(bui_ins)))\
- $(eval my_copy_dest := $(patsubst data/%,DATA/%,\
- $(patsubst system/%,DATA/%,\
- $(patsubst $(PRODUCT_OUT)/%,%,$(ins)))))\
- $(call declare-copy-target-license-metadata,$(2)/$(my_copy_dest),$(bui))\
- $(bui):$(2)/$(my_copy_dest))))
-endef
diff --git a/core/tasks/vts-core-tests.mk b/core/tasks/vts-core-tests.mk
index 1eeb078..11bb932 100644
--- a/core/tasks/vts-core-tests.mk
+++ b/core/tasks/vts-core-tests.mk
@@ -16,15 +16,6 @@
test_suite_tradefed := vts-tradefed
test_suite_readme := test/vts/tools/vts-core-tradefed/README
-include $(BUILD_SYSTEM)/tasks/tools/vts-kernel-tests.mk
-
-ltp_copy_pairs := \
- $(call target-native-copy-pairs,$(kernel_ltp_modules),$(kernel_ltp_vts_out))
-
-copy_ltp_tests := $(call copy-many-files,$(ltp_copy_pairs))
-
-test_suite_extra_deps := $(copy_ltp_tests)
-
include $(BUILD_SYSTEM)/tasks/tools/compatibility.mk
.PHONY: vts
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 9d6402e..b9b226b 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -17,7 +17,7 @@
# Base modules and settings for the system partition.
PRODUCT_PACKAGES += \
abx \
- aconfigd \
+ aconfigd-system \
adbd_system_api \
aflags \
am \
@@ -248,6 +248,7 @@
pintool \
platform.xml \
pm \
+ prefetch \
preinstalled-packages-asl-files.xml \
preinstalled-packages-platform.xml \
preinstalled-packages-strict-signature.xml \
diff --git a/target/product/generic/Android.bp b/target/product/generic/Android.bp
index c81e66c..bca4fcd 100644
--- a/target/product/generic/Android.bp
+++ b/target/product/generic/Android.bp
@@ -1,4 +1,4 @@
-android_rootdirs = [
+generic_rootdirs = [
"acct",
"apex",
"bootstrap-apex",
@@ -15,19 +15,22 @@
"oem",
"postinstall",
"proc",
- "product",
"second_stage_resources",
"storage",
"sys",
"system",
"system_dlkm",
- "system_ext",
"tmp",
"vendor",
"vendor_dlkm",
]
-android_symlinks = [
+android_rootdirs = [
+ "system_ext",
+ "product",
+]
+
+generic_symlinks = [
{
target: "/system/bin/init",
name: "init",
@@ -41,18 +44,10 @@
name: "bin",
},
{
- target: "/product",
- name: "system/product",
- },
- {
target: "/vendor",
name: "system/vendor",
},
{
- target: "/system_ext",
- name: "system/system_ext",
- },
- {
target: "/system_dlkm/lib/modules",
name: "system/lib/modules",
},
@@ -61,10 +56,6 @@
name: "bugreports",
},
{
- target: "/data/cache",
- name: "cache",
- },
- {
target: "/sys/kernel/debug",
name: "d",
},
@@ -121,6 +112,21 @@
},
]
+android_symlinks = [
+ {
+ target: "/product",
+ name: "system/product",
+ },
+ {
+ target: "/system_ext",
+ name: "system/system_ext",
+ },
+ {
+ target: "/data/cache",
+ name: "cache",
+ },
+]
+
filegroup {
name: "generic_system_sign_key",
srcs: [":avb_testkey_rsa4096"],
@@ -340,15 +346,17 @@
],
}
-android_system_image {
- name: "generic_system_image",
-
+android_filesystem_defaults {
+ name: "system_image_defaults",
partition_name: "system",
base_dir: "system",
- dirs: android_rootdirs,
- symlinks: android_symlinks,
+ dirs: generic_rootdirs,
+ symlinks: generic_symlinks,
file_contexts: ":plat_file_contexts",
- linker_config_src: ":system_linker_config_json_file",
+ linker_config: {
+ gen_linker_config: true,
+ linker_config_srcs: [":system_linker_config_json_file"],
+ },
fsverity: {
inputs: [
"etc/boot-image.prof",
@@ -361,11 +369,6 @@
],
libs: [":framework-res{.export-package.apk}"],
},
- type: "erofs",
- erofs: {
- compressor: "lz4hc,9",
- compress_hints: "erofs_compress_hints.txt",
- },
build_logtags: true,
gen_aconfig_flags_pb: true,
@@ -378,7 +381,7 @@
deps: [
"abx",
- "aconfigd",
+ "aconfigd-system",
"aflags",
"am",
"android.software.credentials.prebuilt.xml", // generic_system
@@ -496,6 +499,7 @@
"pintool", // base_system
"platform.xml", // base_system
"pm", // base_system
+ "prefetch", //base_system
"preinstalled-packages-asl-files.xml", // base_system
"preinstalled-packages-platform-generic-system.xml", // generic_system
"preinstalled-packages-platform-handheld-system.xml", // handheld_system
@@ -869,3 +873,15 @@
},
},
}
+
+android_system_image {
+ name: "aosp_shared_system_image",
+ defaults: ["system_image_defaults"],
+ dirs: android_rootdirs,
+ symlinks: android_symlinks,
+ type: "erofs",
+ erofs: {
+ compressor: "lz4hc,9",
+ compress_hints: "erofs_compress_hints.txt",
+ },
+}
diff --git a/target/product/generic_ramdisk.mk b/target/product/generic_ramdisk.mk
index 388b180..5ecb55f 100644
--- a/target/product/generic_ramdisk.mk
+++ b/target/product/generic_ramdisk.mk
@@ -23,6 +23,7 @@
PRODUCT_PACKAGES += \
init_first_stage \
snapuserd_ramdisk \
+ ramdisk-build.prop \
# Debug ramdisk
PRODUCT_PACKAGES += \
diff --git a/target/product/gsi/Android.bp b/target/product/gsi/Android.bp
index f18f35a..9e8946d 100644
--- a/target/product/gsi/Android.bp
+++ b/target/product/gsi/Android.bp
@@ -61,3 +61,149 @@
system_ext_specific: true,
relative_install_path: "gsi",
}
+
+gsi_symlinks = [
+ {
+ target: "/system/system_ext",
+ name: "system_ext",
+ },
+ {
+ target: "/system/product",
+ name: "product",
+ },
+ {
+ target: "/odm/odm_dlkm/etc",
+ name: "odm_dlkm/etc",
+ },
+ {
+ target: "/vendor/vendor_dlkm/etc",
+ name: "vendor_dlkm/etc",
+ },
+]
+
+android_system_image {
+ name: "android_gsi",
+ defaults: ["system_image_defaults"],
+ symlinks: gsi_symlinks,
+ dirs: ["cache"],
+ deps: [
+ ///////////////////////////////////////////
+ // gsi_system_ext
+ ///////////////////////////////////////////
+
+ // handheld packages
+ "Launcher3QuickStep",
+ "Provision",
+ "Settings",
+ "StorageManager",
+ "SystemUI",
+
+ // telephony packages
+ "CarrierConfig",
+
+ // Install a copy of the debug policy to the system_ext partition, and allow
+ // init-second-stage to load debug policy from system_ext.
+ // This option is only meant to be set by compliance GSI targets.
+ "system_ext_userdebug_plat_sepolicy.cil",
+
+ ///////////////////////////////////////////
+ // base_system_ext
+ ///////////////////////////////////////////
+ "build_flag_system_ext",
+ "fs_config_dirs_system_ext",
+ "fs_config_files_system_ext",
+ "group_system_ext",
+ "passwd_system_ext",
+ "SatelliteClient",
+ "selinux_policy_system_ext",
+ "system_ext_manifest.xml",
+ "system_ext-build.prop",
+ // Base modules when shipping api level is less than or equal to 34
+ "hwservicemanager",
+ "android.hidl.allocator@1.0-service",
+
+ ///////////////////////////////////////////
+ // window_extensions_base
+ ///////////////////////////////////////////
+ "androidx.window.extensions",
+ "androidx.window.sidecar",
+
+ ///////////////////////////////////////////
+ // gsi_release
+ ///////////////////////////////////////////
+ "gsi_skip_mount.cfg",
+ "init.gsi.rc",
+ "init.vndk-nodef.rc",
+ // Overlay the GSI specific setting for framework and SystemUI
+ "gsi_overlay_framework",
+ "gsi_overlay_systemui",
+
+ ///////////////////////////////////////////
+ // VNDK
+ ///////////////////////////////////////////
+ "com.android.vndk.v30",
+ "com.android.vndk.v31",
+ "com.android.vndk.v32",
+ "com.android.vndk.v33",
+ "com.android.vndk.v34",
+
+ ///////////////////////////////////////////
+ // AVF
+ ///////////////////////////////////////////
+ "com.android.compos",
+ "features_com.android.virt.xml",
+
+ ///////////////////////////////////////////
+ // gsi_product
+ ///////////////////////////////////////////
+ "Browser2",
+ "Camera2",
+ "Dialer",
+ "LatinIME",
+ "apns-full-conf.xml",
+
+ ///////////////////////////////////////////
+ // media_product
+ ///////////////////////////////////////////
+ "webview",
+
+ ///////////////////////////////////////////
+ // base_product
+ ///////////////////////////////////////////
+
+ // Base modules and settings for the product partition.
+ "build_flag_product",
+ "fs_config_dirs_product",
+ "fs_config_files_product",
+ "group_product",
+ "ModuleMetadata",
+ "passwd_product",
+ "product_compatibility_matrix.xml",
+ "product_manifest.xml",
+ "selinux_policy_product",
+ "product-build.prop",
+
+ // AUDIO
+ "frameworks_sounds",
+
+ ///////////////////////////////////////////
+ // base_system
+ ///////////////////////////////////////////
+ "charger",
+ ] + select(product_variable("debuggable"), {
+ // Packages included only for eng or userdebug builds, previously debug tagged
+ true: ["adb_keys"],
+ default: [],
+ }),
+ multilib: {
+ both: {
+ // PRODUCT_PACKAGES_SHIPPING_API_LEVEL_34
+ deps: ["android.hidl.memory@1.0-impl"],
+ },
+ },
+ enabled: select(soong_config_variable("ANDROID", "PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT"), {
+ "true": true,
+ default: false,
+ }),
+ type: "ext4",
+}
diff --git a/teams/Android.bp b/teams/Android.bp
index 21f5222..6307f5c 100644
--- a/teams/Android.bp
+++ b/teams/Android.bp
@@ -70,13 +70,6 @@
}
team {
- name: "trendy_team_wear_wear_cloud_platform",
-
- // go/trendy/manage/engineers/5917762526281728
- trendy_team_id: "5917762526281728",
-}
-
-team {
name: "trendy_team_pixel_system_software",
// go/trendy/manage/engineers/4856005120622592
@@ -518,13 +511,6 @@
}
team {
- name: "trendy_team_wear_wear_notifications_alerts_attention_management",
-
- // go/trendy/manage/engineers/6267643681996800
- trendy_team_id: "6267643681996800",
-}
-
-team {
name: "trendy_team_fwk_nfc",
// go/trendy/manage/engineers/5962312512864256
@@ -532,13 +518,6 @@
}
team {
- name: "trendy_team_wear_personalization_developer_surfaces",
-
- // go/trendy/manage/engineers/4819890988810240
- trendy_team_id: "4819890988810240",
-}
-
-team {
name: "trendy_team_srajkumar_team",
// go/trendy/manage/engineers/5170053894012928
@@ -693,13 +672,6 @@
}
team {
- name: "trendy_team_test_eng_android_wear",
-
- // go/trendy/manage/engineers/4979150422933504
- trendy_team_id: "4979150422933504",
-}
-
-team {
name: "trendy_team_mesch_team",
// go/trendy/manage/engineers/5205465899368448
@@ -721,13 +693,6 @@
}
team {
- name: "trendy_team_wear_wear_developer_devx",
-
- // go/trendy/manage/engineers/4894890764697600
- trendy_team_id: "4894890764697600",
-}
-
-team {
name: "trendy_team_android_rust",
// go/trendy/manage/engineers/4844600586305536
@@ -931,13 +896,6 @@
}
team {
- name: "trendy_team_wear_wallet_on_wear",
-
- // go/trendy/manage/engineers/5724960437731328
- trendy_team_id: "5724960437731328",
-}
-
-team {
name: "trendy_team_glanceables",
// go/trendy/manage/engineers/4658222004600832
@@ -1071,13 +1029,6 @@
}
team {
- name: "trendy_team_wear_3xp",
-
- // go/trendy/manage/engineers/5692317612539904
- trendy_team_id: "5692317612539904",
-}
-
-team {
name: "trendy_team_clockwork",
// go/trendy/manage/engineers/4908781678755840
@@ -1211,13 +1162,6 @@
}
team {
- name: "trendy_team_wear_software_nti",
-
- // go/trendy/manage/engineers/5164973558759424
- trendy_team_id: "5164973558759424",
-}
-
-team {
name: "trendy_team_machine_learning",
// go/trendy/manage/engineers/5276568318246912
@@ -1309,13 +1253,6 @@
}
team {
- name: "trendy_team_wear_wear_power_emulator",
-
- // go/trendy/manage/engineers/5160338936725504
- trendy_team_id: "5160338936725504",
-}
-
-team {
name: "trendy_team_deprecated_framework_svetoslavganov",
// go/trendy/manage/engineers/6404117492531200
@@ -1330,13 +1267,6 @@
}
team {
- name: "trendy_team_wear_opus",
-
- // go/trendy/manage/engineers/5098351636676608
- trendy_team_id: "5098351636676608",
-}
-
-team {
name: "trendy_team_text_to_speech",
// go/trendy/manage/engineers/6368933120442368
@@ -1442,13 +1372,6 @@
}
team {
- name: "trendy_team_wear_developer_foundation",
-
- // go/trendy/manage/engineers/5239127108648960
- trendy_team_id: "5239127108648960",
-}
-
-team {
name: "trendy_team_tpm_tvc",
// go/trendy/manage/engineers/5390683333230592
@@ -1456,13 +1379,6 @@
}
team {
- name: "trendy_team_wear_wear_ux",
-
- // go/trendy/manage/engineers/5782097411080192
- trendy_team_id: "5782097411080192",
-}
-
-team {
name: "trendy_team_lse_desktop_os_experience",
// go/trendy/manage/engineers/5125234900434944
@@ -1673,13 +1589,6 @@
}
team {
- name: "trendy_team_wear_wear_assistant",
-
- // go/trendy/manage/engineers/5848075306172416
- trendy_team_id: "5848075306172416",
-}
-
-team {
name: "trendy_team_android_power_and_comms_infra",
// go/trendy/manage/engineers/5325547653332992
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 15e4187..043a956 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -106,8 +106,12 @@
],
"postsubmit": [
{
- // aconfig_storage read api java integration tests
- "name": "aconfig_storage_read_api.test.java"
+ // aconfig_storage read functional test
+ "name": "aconfig_storage_read_functional"
+ },
+ {
+ // aconfig_storage read unit test
+ "name": "aconfig_storage_read_unit"
}
]
}
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index bfdf1a7..2f2889c 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -32,6 +32,7 @@
codegen_mode: CodegenMode,
flag_ids: HashMap<String, u16>,
allow_instrumentation: bool,
+ package_fingerprint: u64,
) -> Result<Vec<OutputFile>>
where
I: Iterator<Item = ProtoParsedFlag>,
@@ -46,6 +47,7 @@
let runtime_lookup_required =
flag_elements.iter().any(|elem| elem.is_read_write) || library_exported;
let container = (flag_elements.first().expect("zero template flags").container).to_string();
+ let is_platform_container = matches!(container.as_str(), "system" | "product" | "vendor");
let context = Context {
flag_elements,
namespace_flags,
@@ -56,6 +58,8 @@
library_exported,
allow_instrumentation,
container,
+ is_platform_container,
+ package_fingerprint: format!("0x{:X}L", package_fingerprint),
};
let mut template = TinyTemplate::new();
template.add_template("Flags.java", include_str!("../../templates/Flags.java.template"))?;
@@ -123,6 +127,8 @@
pub library_exported: bool,
pub allow_instrumentation: bool,
pub container: String,
+ pub is_platform_container: bool,
+ pub package_fingerprint: String,
}
#[derive(Serialize, Debug)]
@@ -502,6 +508,7 @@
mode,
flag_ids,
true,
+ 5801144784618221668,
)
.unwrap();
let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
@@ -513,86 +520,56 @@
package com.android.aconfig.test;
// TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage;
- import android.os.Binder;
- import android.provider.DeviceConfig;
- import android.provider.DeviceConfig.Properties;
- import android.aconfig.storage.StorageInternalReader;
- import java.nio.file.Files;
- import java.nio.file.Paths;
-
+ import android.os.Build;
+ import android.os.flagging.PlatformAconfigPackageInternal;
+ import android.os.flagging.AconfigStorageReadException;
+ import android.util.Log;
/** @hide */
public final class FeatureFlagsImpl implements FeatureFlags {
- private static final boolean isReadFromNew = Files.exists(Paths.get("/metadata/aconfig/boot/enable_only_new_storage"));
+ private static final String TAG = "com.android.aconfig.test.FeatureFlagsImpl";
private static volatile boolean isCached = false;
- private static volatile boolean aconfig_test_is_cached = false;
- private static volatile boolean other_namespace_is_cached = false;
private static boolean disabledRw = false;
private static boolean disabledRwExported = false;
private static boolean disabledRwInOtherNamespace = false;
private static boolean enabledRw = true;
private void init() {
- StorageInternalReader reader = null;
- boolean foundPackage = true;
try {
- reader = new StorageInternalReader("system", "com.android.aconfig.test");
+ PlatformAconfigPackageInternal reader = PlatformAconfigPackageInternal.load("system", "com.android.aconfig.test", 0x5081CE7221C77064L);
+ AconfigStorageReadException error = reader.getException();
+ if (error == null) {
+ disabledRw = reader.getBooleanFlagValue(1);
+ disabledRwExported = reader.getBooleanFlagValue(2);
+ enabledRw = reader.getBooleanFlagValue(8);
+ disabledRwInOtherNamespace = reader.getBooleanFlagValue(3);
+ } else if (Build.VERSION.SDK_INT > 35 && error.getErrorCode() == 5 /* fingerprint doesn't match*/) {
+ disabledRw = reader.getBooleanFlagValue("disabled_rw", false);
+ disabledRwExported = reader.getBooleanFlagValue("disabled_rw_exported", false);
+ enabledRw = reader.getBooleanFlagValue("enabled_rw", true);
+ disabledRwInOtherNamespace = reader.getBooleanFlagValue("disabled_rw_in_other_namespace", false);
+ } else {
+ if (error.getMessage() != null) {
+ Log.e(TAG, error.getMessage());
+ } else {
+ Log.e(TAG, "Encountered a null AconfigStorageReadException");
+ }
+ }
} catch (Exception e) {
- foundPackage = false;
+ if (e.getMessage() != null) {
+ Log.e(TAG, e.getMessage());
+ } else {
+ Log.e(TAG, "Encountered a null Exception");
+ }
+ } catch (NoClassDefFoundError e) {
+ // for mainline module running on older devices.
+ // This should be replaces to version check, after the version bump.
+ if (e.getMessage() != null) {
+ Log.e(TAG, e.getMessage());
+ } else {
+ Log.e(TAG, "Encountered a null NoClassDefFoundError");
+ }
}
- disabledRw = foundPackage ? reader.getBooleanFlagValue(1) : false;
- disabledRwExported = foundPackage ? reader.getBooleanFlagValue(2) : false;
- enabledRw = foundPackage ? reader.getBooleanFlagValue(8) : true;
- disabledRwInOtherNamespace = foundPackage ? reader.getBooleanFlagValue(3) : false;
isCached = true;
}
- private void load_overrides_aconfig_test() {
- final long ident = Binder.clearCallingIdentity();
- try {
- Properties properties = DeviceConfig.getProperties("aconfig_test");
- disabledRw =
- properties.getBoolean(Flags.FLAG_DISABLED_RW, false);
- disabledRwExported =
- properties.getBoolean(Flags.FLAG_DISABLED_RW_EXPORTED, false);
- enabledRw =
- properties.getBoolean(Flags.FLAG_ENABLED_RW, true);
- } catch (NullPointerException e) {
- throw new RuntimeException(
- "Cannot read value from namespace aconfig_test "
- + "from DeviceConfig. It could be that the code using flag "
- + "executed before SettingsProvider initialization. Please use "
- + "fixed read-only flag by adding is_fixed_read_only: true in "
- + "flag declaration.",
- e
- );
- } catch (SecurityException e) {
- // for isolated process case, skip loading flag value from the storage, use the default
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- aconfig_test_is_cached = true;
- }
-
- private void load_overrides_other_namespace() {
- final long ident = Binder.clearCallingIdentity();
- try {
- Properties properties = DeviceConfig.getProperties("other_namespace");
- disabledRwInOtherNamespace =
- properties.getBoolean(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false);
- } catch (NullPointerException e) {
- throw new RuntimeException(
- "Cannot read value from namespace other_namespace "
- + "from DeviceConfig. It could be that the code using flag "
- + "executed before SettingsProvider initialization. Please use "
- + "fixed read-only flag by adding is_fixed_read_only: true in "
- + "flag declaration.",
- e
- );
- } catch (SecurityException e) {
- // for isolated process case, skip loading flag value from the storage, use the default
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- other_namespace_is_cached = true;
- }
@Override
@com.android.aconfig.annotations.AconfigFlagAccessor
@@ -604,14 +581,8 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRw() {
- if (isReadFromNew) {
- if (!isCached) {
- init();
- }
- } else {
- if (!aconfig_test_is_cached) {
- load_overrides_aconfig_test();
- }
+ if (!isCached) {
+ init();
}
return disabledRw;
}
@@ -619,14 +590,8 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRwExported() {
- if (isReadFromNew) {
- if (!isCached) {
- init();
- }
- } else {
- if (!aconfig_test_is_cached) {
- load_overrides_aconfig_test();
- }
+ if (!isCached) {
+ init();
}
return disabledRwExported;
}
@@ -634,14 +599,8 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() {
- if (isReadFromNew) {
- if (!isCached) {
- init();
- }
- } else {
- if (!other_namespace_is_cached) {
- load_overrides_other_namespace();
- }
+ if (!isCached) {
+ init();
}
return disabledRwInOtherNamespace;
}
@@ -673,14 +632,8 @@
@com.android.aconfig.annotations.AconfigFlagAccessor
@UnsupportedAppUsage
public boolean enabledRw() {
- if (isReadFromNew) {
- if (!isCached) {
- init();
- }
- } else {
- if (!aconfig_test_is_cached) {
- load_overrides_aconfig_test();
- }
+ if (!isCached) {
+ init();
}
return enabledRw;
}
@@ -733,6 +686,7 @@
mode,
flag_ids,
true,
+ 5801144784618221668,
)
.unwrap();
@@ -931,6 +885,7 @@
mode,
flag_ids,
true,
+ 5801144784618221668,
)
.unwrap();
@@ -1052,6 +1007,7 @@
mode,
flag_ids,
true,
+ 5801144784618221668,
)
.unwrap();
let expect_featureflags_content = r#"
diff --git a/tools/aconfig/aconfig/src/codegen/rust.rs b/tools/aconfig/aconfig/src/codegen/rust.rs
index 569a34b..82a6ebc 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -259,10 +259,6 @@
/// flag provider
pub struct FlagProvider;
-static READ_FROM_NEW_STORAGE: LazyLock<bool> = LazyLock::new(|| unsafe {
- Path::new("/metadata/aconfig/boot/enable_only_new_storage").exists()
-});
-
static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe {
get_mapped_storage_file("system", StorageFileType::PackageMap)
.and_then(|package_map| get_package_read_context(&package_map, "com.android.aconfig.test"))
@@ -275,54 +271,46 @@
/// flag value cache for disabled_rw
static CACHED_disabled_rw: LazyLock<bool> = LazyLock::new(|| {
- if *READ_FROM_NEW_STORAGE {
- // This will be called multiple times. Subsequent calls after the first are noops.
- logger::init(
- logger::Config::default()
- .with_tag_on_device("aconfig_rust_codegen")
- .with_max_level(LevelFilter::Info));
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device("aconfig_rust_codegen")
+ .with_max_level(LevelFilter::Info));
- let flag_value_result = FLAG_VAL_MAP
- .as_ref()
- .map_err(|err| format!("failed to get flag val map: {err}"))
- .and_then(|flag_val_map| {
- PACKAGE_OFFSET
- .as_ref()
- .map_err(|err| format!("failed to get package read offset: {err}"))
- .and_then(|package_offset| {
- match package_offset {
- Some(offset) => {
- get_boolean_flag_value(&flag_val_map, offset + 1)
- .map_err(|err| format!("failed to get flag: {err}"))
- },
- None => {
- log!(Level::Error, "no context found for package com.android.aconfig.test");
- Err(format!("failed to flag package com.android.aconfig.test"))
- }
- }
- })
- });
+ let flag_value_result = FLAG_VAL_MAP
+ .as_ref()
+ .map_err(|err| format!("failed to get flag val map: {err}"))
+ .and_then(|flag_val_map| {
+ PACKAGE_OFFSET
+ .as_ref()
+ .map_err(|err| format!("failed to get package read offset: {err}"))
+ .and_then(|package_offset| {
+ match package_offset {
+ Some(offset) => {
+ get_boolean_flag_value(&flag_val_map, offset + 1)
+ .map_err(|err| format!("failed to get flag: {err}"))
+ },
+ None => {
+ log!(Level::Error, "no context found for package com.android.aconfig.test");
+ Err(format!("failed to flag package com.android.aconfig.test"))
+ }
+ }
+ })
+ });
- match flag_value_result {
- Ok(flag_value) => {
- return flag_value;
- },
- Err(err) => {
- log!(Level::Error, "aconfig_rust_codegen: error: {err}");
- return false;
- }
+ match flag_value_result {
+ Ok(flag_value) => {
+ return flag_value;
+ },
+ Err(err) => {
+ log!(Level::Error, "aconfig_rust_codegen: error: {err}");
+ return false;
}
- } else {
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.aconfig_test",
- "com.android.aconfig.test.disabled_rw",
- "false") == "true"
}
});
/// flag value cache for disabled_rw_exported
static CACHED_disabled_rw_exported: LazyLock<bool> = LazyLock::new(|| {
- if *READ_FROM_NEW_STORAGE {
// This will be called multiple times. Subsequent calls after the first are noops.
logger::init(
logger::Config::default()
@@ -359,17 +347,10 @@
return false;
}
}
- } else {
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.aconfig_test",
- "com.android.aconfig.test.disabled_rw_exported",
- "false") == "true"
- }
});
/// flag value cache for disabled_rw_in_other_namespace
static CACHED_disabled_rw_in_other_namespace: LazyLock<bool> = LazyLock::new(|| {
- if *READ_FROM_NEW_STORAGE {
// This will be called multiple times. Subsequent calls after the first are noops.
logger::init(
logger::Config::default()
@@ -406,18 +387,11 @@
return false;
}
}
- } else {
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.other_namespace",
- "com.android.aconfig.test.disabled_rw_in_other_namespace",
- "false") == "true"
- }
});
/// flag value cache for enabled_rw
static CACHED_enabled_rw: LazyLock<bool> = LazyLock::new(|| {
- if *READ_FROM_NEW_STORAGE {
// This will be called multiple times. Subsequent calls after the first are noops.
logger::init(
logger::Config::default()
@@ -454,12 +428,6 @@
return true;
}
}
- } else {
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.aconfig_test",
- "com.android.aconfig.test.enabled_rw",
- "true") == "true"
- }
});
impl FlagProvider {
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 0ad3d97..c1989a2 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -69,6 +69,7 @@
declarations: Vec<Input>,
values: Vec<Input>,
default_permission: ProtoFlagPermission,
+ allow_read_write: bool,
) -> Result<Vec<u8>> {
let mut parsed_flags = ProtoParsedFlags::new();
@@ -195,6 +196,16 @@
}
}
+ if !allow_read_write {
+ if let Some(pf) = parsed_flags
+ .parsed_flag
+ .iter()
+ .find(|pf| pf.permission() == ProtoFlagPermission::READ_WRITE)
+ {
+ bail!("flag {} has permission READ_WRITE, but allow_read_write is false", pf.name());
+ }
+ }
+
// Create a sorted parsed_flags
aconfig_protos::parsed_flags::sort_parsed_flags(&mut parsed_flags);
aconfig_protos::parsed_flags::verify_fields(&parsed_flags)?;
@@ -214,6 +225,9 @@
bail!("no parsed flags, or the parsed flags use different packages");
};
let package = package.to_string();
+ let mut flag_names =
+ modified_parsed_flags.iter().map(|pf| pf.name().to_string()).collect::<Vec<_>>();
+ let package_fingerprint = compute_flags_fingerprint(&mut flag_names);
let flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
generate_java_code(
&package,
@@ -221,6 +235,7 @@
codegen_mode,
flag_ids,
allow_instrumentation,
+ package_fingerprint,
)
}
@@ -427,14 +442,14 @@
// protect hardcoded offset reads.
// Creates a fingerprint of the flag names (which requires sorting the vector).
// Fingerprint is used by both codegen and storage files.
-pub fn compute_flags_fingerprint(flag_names: &mut Vec<String>) -> Result<u64> {
+pub fn compute_flags_fingerprint(flag_names: &mut Vec<String>) -> u64 {
flag_names.sort();
let mut hasher = SipHasher13::new();
for flag in flag_names {
hasher.write(flag.as_bytes());
}
- Ok(hasher.finish())
+ hasher.finish()
}
#[allow(dead_code)] // TODO: b/316357686 - Use fingerprint in codegen to
@@ -466,7 +481,7 @@
let mut extracted_flags = extract_flag_names(parsed_flags).unwrap();
let hash_result = compute_flags_fingerprint(&mut extracted_flags);
- assert_eq!(hash_result.unwrap(), expected_fingerprint);
+ assert_eq!(hash_result, expected_fingerprint);
}
#[test]
@@ -487,7 +502,7 @@
let result_from_names = compute_flags_fingerprint(&mut flag_names_vec);
// Assert the same hash is generated for each case.
- assert_eq!(result_from_parsed_flags.unwrap(), result_from_names.unwrap());
+ assert_eq!(result_from_parsed_flags, result_from_names);
}
#[test]
@@ -497,9 +512,9 @@
let second_parsed_flags = crate::test::parse_second_package_flags();
let mut extracted_flags = extract_flag_names(parsed_flags).unwrap();
- let result_from_parsed_flags = compute_flags_fingerprint(&mut extracted_flags).unwrap();
+ let result_from_parsed_flags = compute_flags_fingerprint(&mut extracted_flags);
let mut second_extracted_flags = extract_flag_names(second_parsed_flags).unwrap();
- let second_result = compute_flags_fingerprint(&mut second_extracted_flags).unwrap();
+ let second_result = compute_flags_fingerprint(&mut second_extracted_flags);
// Different flags should have a different fingerprint.
assert_ne!(result_from_parsed_flags, second_result);
@@ -576,6 +591,7 @@
declaration,
value,
ProtoFlagPermission::READ_ONLY,
+ true,
)
.unwrap();
let parsed_flags =
@@ -609,6 +625,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -640,6 +657,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -647,6 +665,121 @@
"failed to parse memory: expected container argument.container, got declaration.container"
);
}
+ #[test]
+ fn test_parse_flags_no_allow_read_write_default_error() {
+ let first_flag = r#"
+ package: "com.first"
+ container: "com.first.container"
+ flag {
+ name: "first"
+ namespace: "first_ns"
+ description: "This is the description of the first flag."
+ bug: "123"
+ }
+ "#;
+ let declaration =
+ vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+ let error = crate::commands::parse_flags(
+ "com.first",
+ Some("com.first.container"),
+ declaration,
+ vec![],
+ ProtoFlagPermission::READ_WRITE,
+ false,
+ )
+ .unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ "flag first has permission READ_WRITE, but allow_read_write is false"
+ );
+ }
+
+ #[test]
+ fn test_parse_flags_no_allow_read_write_value_error() {
+ let first_flag = r#"
+ package: "com.first"
+ container: "com.first.container"
+ flag {
+ name: "first"
+ namespace: "first_ns"
+ description: "This is the description of the first flag."
+ bug: "123"
+ }
+ "#;
+ let declaration =
+ vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+ let first_flag_value = r#"
+ flag_value {
+ package: "com.first"
+ name: "first"
+ state: DISABLED
+ permission: READ_WRITE
+ }
+ "#;
+ let value = vec![Input {
+ source: "memory".to_string(),
+ reader: Box::new(first_flag_value.as_bytes()),
+ }];
+ let error = crate::commands::parse_flags(
+ "com.first",
+ Some("com.first.container"),
+ declaration,
+ value,
+ ProtoFlagPermission::READ_ONLY,
+ false,
+ )
+ .unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ "flag first has permission READ_WRITE, but allow_read_write is false"
+ );
+ }
+
+ #[test]
+ fn test_parse_flags_no_allow_read_write_success() {
+ let first_flag = r#"
+ package: "com.first"
+ container: "com.first.container"
+ flag {
+ name: "first"
+ namespace: "first_ns"
+ description: "This is the description of the first flag."
+ bug: "123"
+ }
+ "#;
+ let declaration =
+ vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+ let first_flag_value = r#"
+ flag_value {
+ package: "com.first"
+ name: "first"
+ state: DISABLED
+ permission: READ_ONLY
+ }
+ "#;
+ let value = vec![Input {
+ source: "memory".to_string(),
+ reader: Box::new(first_flag_value.as_bytes()),
+ }];
+ let flags_bytes = crate::commands::parse_flags(
+ "com.first",
+ Some("com.first.container"),
+ declaration,
+ value,
+ ProtoFlagPermission::READ_ONLY,
+ false,
+ )
+ .unwrap();
+ let parsed_flags =
+ aconfig_protos::parsed_flags::try_from_binary_proto(&flags_bytes).unwrap();
+ assert_eq!(1, parsed_flags.parsed_flag.len());
+ let parsed_flag = parsed_flags.parsed_flag.first().unwrap();
+ assert_eq!(ProtoFlagState::DISABLED, parsed_flag.state());
+ assert_eq!(ProtoFlagPermission::READ_ONLY, parsed_flag.permission());
+ }
#[test]
fn test_parse_flags_override_fixed_read_only() {
@@ -682,6 +815,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -716,6 +850,7 @@
declaration,
value,
ProtoFlagPermission::READ_ONLY,
+ true,
)
.unwrap();
let parsed_flags =
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index e184efe..c390288 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -62,6 +62,12 @@
&commands::DEFAULT_FLAG_PERMISSION,
)),
)
+ .arg(
+ Arg::new("allow-read-write")
+ .long("allow-read-write")
+ .value_parser(clap::value_parser!(bool))
+ .default_value("true"),
+ )
.arg(Arg::new("cache").long("cache").required(true)),
)
.subcommand(
@@ -242,12 +248,15 @@
sub_matches,
"default-permission",
)?;
+ let allow_read_write = get_optional_arg::<bool>(sub_matches, "allow-read-write")
+ .expect("failed to parse allow-read-write");
let output = commands::parse_flags(
package,
container,
declarations,
values,
*default_permission,
+ *allow_read_write,
)
.context("failed to create cache")?;
let path = get_required_arg::<String>(sub_matches, "cache")?;
diff --git a/tools/aconfig/aconfig/src/storage/flag_info.rs b/tools/aconfig/aconfig/src/storage/flag_info.rs
index 2532609..0b5a67b 100644
--- a/tools/aconfig/aconfig/src/storage/flag_info.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_info.rs
@@ -73,7 +73,7 @@
pub fn create_test_flag_info_list_from_source() -> Result<FlagInfoList> {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
+ let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
create_flag_info("mockup", &packages, DEFAULT_FILE_VERSION)
}
@@ -83,7 +83,7 @@
let flag_info_list = create_test_flag_info_list_from_source();
assert!(flag_info_list.is_ok());
let expected_flag_info_list =
- aconfig_storage_file::test_utils::create_test_flag_info_list();
+ aconfig_storage_file::test_utils::create_test_flag_info_list(DEFAULT_FILE_VERSION);
assert_eq!(flag_info_list.unwrap(), expected_flag_info_list);
}
}
diff --git a/tools/aconfig/aconfig/src/storage/flag_table.rs b/tools/aconfig/aconfig/src/storage/flag_table.rs
index 6046d7e..ae5a16c 100644
--- a/tools/aconfig/aconfig/src/storage/flag_table.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_table.rs
@@ -148,7 +148,7 @@
fn create_test_flag_table_from_source() -> Result<FlagTable> {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
+ let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
create_flag_table("mockup", &packages, DEFAULT_FILE_VERSION)
}
@@ -157,7 +157,8 @@
fn test_table_contents() {
let flag_table = create_test_flag_table_from_source();
assert!(flag_table.is_ok());
- let expected_flag_table = aconfig_storage_file::test_utils::create_test_flag_table();
+ let expected_flag_table =
+ aconfig_storage_file::test_utils::create_test_flag_table(DEFAULT_FILE_VERSION);
assert_eq!(flag_table.unwrap(), expected_flag_table);
}
}
diff --git a/tools/aconfig/aconfig/src/storage/flag_value.rs b/tools/aconfig/aconfig/src/storage/flag_value.rs
index 6a655b9..065b7e3 100644
--- a/tools/aconfig/aconfig/src/storage/flag_value.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_value.rs
@@ -72,7 +72,7 @@
pub fn create_test_flag_value_list_from_source() -> Result<FlagValueList> {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
+ let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
create_flag_value("mockup", &packages, DEFAULT_FILE_VERSION)
}
@@ -82,7 +82,7 @@
let flag_value_list = create_test_flag_value_list_from_source();
assert!(flag_value_list.is_ok());
let expected_flag_value_list =
- aconfig_storage_file::test_utils::create_test_flag_value_list();
+ aconfig_storage_file::test_utils::create_test_flag_value_list(DEFAULT_FILE_VERSION);
assert_eq!(flag_value_list.unwrap(), expected_flag_value_list);
}
}
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index 9e5dad5..4bc72f7 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -22,6 +22,7 @@
use anyhow::Result;
use std::collections::{HashMap, HashSet};
+use crate::commands::compute_flags_fingerprint;
use crate::storage::{
flag_info::create_flag_info, flag_table::create_flag_table, flag_value::create_flag_value,
package_table::create_package_table,
@@ -32,6 +33,7 @@
pub struct FlagPackage<'a> {
pub package_name: &'a str,
pub package_id: u32,
+ pub fingerprint: u64,
pub flag_names: HashSet<&'a str>,
pub boolean_flags: Vec<&'a ProtoParsedFlag>,
// The index of the first boolean flag in this aconfig package among all boolean
@@ -44,6 +46,7 @@
FlagPackage {
package_name,
package_id,
+ fingerprint: 0,
flag_names: HashSet::new(),
boolean_flags: vec![],
boolean_start_index: 0,
@@ -57,7 +60,7 @@
}
}
-pub fn group_flags_by_package<'a, I>(parsed_flags_vec_iter: I) -> Vec<FlagPackage<'a>>
+pub fn group_flags_by_package<'a, I>(parsed_flags_vec_iter: I, version: u32) -> Vec<FlagPackage<'a>>
where
I: Iterator<Item = &'a ProtoParsedFlags>,
{
@@ -74,11 +77,18 @@
}
}
- // cacluate boolean flag start index for each package
+ // Calculate boolean flag start index for each package
let mut boolean_start_index = 0;
for p in packages.iter_mut() {
p.boolean_start_index = boolean_start_index;
boolean_start_index += p.boolean_flags.len() as u32;
+
+ if version >= 2 {
+ let mut flag_names_vec =
+ p.flag_names.clone().into_iter().map(String::from).collect::<Vec<_>>();
+ let fingerprint = compute_flags_fingerprint(&mut flag_names_vec);
+ p.fingerprint = fingerprint;
+ }
}
packages
@@ -93,7 +103,7 @@
where
I: Iterator<Item = &'a ProtoParsedFlags>,
{
- let packages = group_flags_by_package(parsed_flags_vec_iter);
+ let packages = group_flags_by_package(parsed_flags_vec_iter, version);
match file {
StorageFileType::PackageMap => {
@@ -117,6 +127,8 @@
#[cfg(test)]
mod tests {
+ use aconfig_storage_file::DEFAULT_FILE_VERSION;
+
use super::*;
use crate::Input;
@@ -159,6 +171,7 @@
reader: Box::new(value_content),
}],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -169,7 +182,7 @@
#[test]
fn test_flag_package() {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
+ let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
for pkg in packages.iter() {
let pkg_name = pkg.package_name;
@@ -189,6 +202,7 @@
assert!(packages[0].flag_names.contains("disabled_rw"));
assert!(packages[0].flag_names.contains("enabled_ro"));
assert_eq!(packages[0].boolean_start_index, 0);
+ assert_eq!(packages[0].fingerprint, 0);
assert_eq!(packages[1].package_name, "com.android.aconfig.storage.test_2");
assert_eq!(packages[1].package_id, 1);
@@ -197,6 +211,7 @@
assert!(packages[1].flag_names.contains("disabled_rw"));
assert!(packages[1].flag_names.contains("enabled_fixed_ro"));
assert_eq!(packages[1].boolean_start_index, 3);
+ assert_eq!(packages[0].fingerprint, 0);
assert_eq!(packages[2].package_name, "com.android.aconfig.storage.test_4");
assert_eq!(packages[2].package_id, 2);
@@ -204,5 +219,49 @@
assert!(packages[2].flag_names.contains("enabled_rw"));
assert!(packages[2].flag_names.contains("enabled_fixed_ro"));
assert_eq!(packages[2].boolean_start_index, 6);
+ assert_eq!(packages[2].fingerprint, 0);
+ }
+
+ #[test]
+ fn test_flag_package_with_fingerprint() {
+ let caches = parse_all_test_flags();
+ let packages = group_flags_by_package(caches.iter(), 2);
+
+ for pkg in packages.iter() {
+ let pkg_name = pkg.package_name;
+ assert_eq!(pkg.flag_names.len(), pkg.boolean_flags.len());
+ for pf in pkg.boolean_flags.iter() {
+ assert!(pkg.flag_names.contains(pf.name()));
+ assert_eq!(pf.package(), pkg_name);
+ }
+ }
+
+ assert_eq!(packages.len(), 3);
+
+ assert_eq!(packages[0].package_name, "com.android.aconfig.storage.test_1");
+ assert_eq!(packages[0].package_id, 0);
+ assert_eq!(packages[0].flag_names.len(), 3);
+ assert!(packages[0].flag_names.contains("enabled_rw"));
+ assert!(packages[0].flag_names.contains("disabled_rw"));
+ assert!(packages[0].flag_names.contains("enabled_ro"));
+ assert_eq!(packages[0].boolean_start_index, 0);
+ assert_eq!(packages[0].fingerprint, 15248948510590158086u64);
+
+ assert_eq!(packages[1].package_name, "com.android.aconfig.storage.test_2");
+ assert_eq!(packages[1].package_id, 1);
+ assert_eq!(packages[1].flag_names.len(), 3);
+ assert!(packages[1].flag_names.contains("enabled_ro"));
+ assert!(packages[1].flag_names.contains("disabled_rw"));
+ assert!(packages[1].flag_names.contains("enabled_fixed_ro"));
+ assert_eq!(packages[1].boolean_start_index, 3);
+ assert_eq!(packages[1].fingerprint, 4431940502274857964u64);
+
+ assert_eq!(packages[2].package_name, "com.android.aconfig.storage.test_4");
+ assert_eq!(packages[2].package_id, 2);
+ assert_eq!(packages[2].flag_names.len(), 2);
+ assert!(packages[2].flag_names.contains("enabled_rw"));
+ assert!(packages[2].flag_names.contains("enabled_fixed_ro"));
+ assert_eq!(packages[2].boolean_start_index, 6);
+ assert_eq!(packages[2].fingerprint, 16233229917711622375u64);
}
}
diff --git a/tools/aconfig/aconfig/src/storage/package_table.rs b/tools/aconfig/aconfig/src/storage/package_table.rs
index 56559f8..53daa7f 100644
--- a/tools/aconfig/aconfig/src/storage/package_table.rs
+++ b/tools/aconfig/aconfig/src/storage/package_table.rs
@@ -47,6 +47,7 @@
let node = PackageTableNode {
package_name: String::from(package.package_name),
package_id: package.package_id,
+ fingerprint: package.fingerprint,
boolean_start_index: package.boolean_start_index,
next_offset: None,
};
@@ -111,23 +112,59 @@
#[cfg(test)]
mod tests {
- use aconfig_storage_file::DEFAULT_FILE_VERSION;
+ use aconfig_storage_file::{DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION};
use super::*;
use crate::storage::{group_flags_by_package, tests::parse_all_test_flags};
- pub fn create_test_package_table_from_source() -> Result<PackageTable> {
+ pub fn create_test_package_table_from_source(version: u32) -> Result<PackageTable> {
let caches = parse_all_test_flags();
- let packages = group_flags_by_package(caches.iter());
- create_package_table("mockup", &packages, DEFAULT_FILE_VERSION)
+ let packages = group_flags_by_package(caches.iter(), version);
+ create_package_table("mockup", &packages, version)
}
#[test]
// this test point locks down the table creation and each field
- fn test_table_contents() {
- let package_table = create_test_package_table_from_source();
- assert!(package_table.is_ok());
- let expected_package_table = aconfig_storage_file::test_utils::create_test_package_table();
- assert_eq!(package_table.unwrap(), expected_package_table);
+ fn test_table_contents_default_version() {
+ let package_table_result = create_test_package_table_from_source(DEFAULT_FILE_VERSION);
+ assert!(package_table_result.is_ok());
+ let package_table = package_table_result.unwrap();
+
+ let expected_package_table =
+ aconfig_storage_file::test_utils::create_test_package_table(DEFAULT_FILE_VERSION);
+
+ assert_eq!(package_table.header, expected_package_table.header);
+ assert_eq!(package_table.buckets, expected_package_table.buckets);
+ for (node, expected_node) in
+ package_table.nodes.iter().zip(expected_package_table.nodes.iter())
+ {
+ assert_eq!(node.package_name, expected_node.package_name);
+ assert_eq!(node.package_id, expected_node.package_id);
+ assert_eq!(node.boolean_start_index, expected_node.boolean_start_index);
+ assert_eq!(node.next_offset, expected_node.next_offset);
+ }
+ }
+
+ #[test]
+ // this test point locks down the table creation and each field
+ fn test_table_contents_max_version() {
+ let package_table_result =
+ create_test_package_table_from_source(MAX_SUPPORTED_FILE_VERSION);
+ assert!(package_table_result.is_ok());
+ let package_table = package_table_result.unwrap();
+
+ let expected_package_table =
+ aconfig_storage_file::test_utils::create_test_package_table(MAX_SUPPORTED_FILE_VERSION);
+
+ assert_eq!(package_table.header, expected_package_table.header);
+ assert_eq!(package_table.buckets, expected_package_table.buckets);
+ for (node, expected_node) in
+ package_table.nodes.iter().zip(expected_package_table.nodes.iter())
+ {
+ assert_eq!(node.package_name, expected_node.package_name);
+ assert_eq!(node.package_id, expected_node.package_id);
+ assert_eq!(node.boolean_start_index, expected_node.boolean_start_index);
+ assert_eq!(node.next_offset, expected_node.next_offset);
+ }
}
}
diff --git a/tools/aconfig/aconfig/src/test.rs b/tools/aconfig/aconfig/src/test.rs
index a19b372..10da252 100644
--- a/tools/aconfig/aconfig/src/test.rs
+++ b/tools/aconfig/aconfig/src/test.rs
@@ -266,6 +266,7 @@
reader: Box::new(include_bytes!("../tests/read_only_test.values").as_slice()),
}],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -290,6 +291,7 @@
},
],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -308,6 +310,7 @@
reader: Box::new(include_bytes!("../tests/third.values").as_slice()),
}],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index cb52150..3fc444a 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -1,61 +1,109 @@
package {package_name};
{{ -if not is_test_mode }}
{{ -if allow_instrumentation }}
-{{ if not library_exported- }}
+{{ if not library_exported- }}{#- only new storage for prod mode #}
// TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage;
-{{ -endif }}
-
{{ -if runtime_lookup_required }}
-import android.os.Binder;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
-
-{{ -if not library_exported }}
-import android.aconfig.storage.StorageInternalReader;
-import java.nio.file.Files;
-import java.nio.file.Paths;
+import android.os.Build;
+{{ if is_platform_container }}
+import android.os.flagging.PlatformAconfigPackageInternal;
+{{ -else }}
+import android.os.flagging.AconfigPackageInternal;
{{ -endif }}
-
+import android.os.flagging.AconfigStorageReadException;
+import android.util.Log;
{{ -endif }}
/** @hide */
public final class FeatureFlagsImpl implements FeatureFlags \{
{{ -if runtime_lookup_required }}
-{{ -if not library_exported }}
- private static final boolean isReadFromNew = Files.exists(Paths.get("/metadata/aconfig/boot/enable_only_new_storage"));
+ private static final String TAG = "{package_name}.FeatureFlagsImpl";
private static volatile boolean isCached = false;
-{{ -endif }}
-{{ -for namespace_with_flags in namespace_flags }}
- private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
-{{ -endfor- }}
-
{{ for flag in flag_elements }}
{{ -if flag.is_read_write }}
private static boolean {flag.method_name} = {flag.default_value};
{{ -endif }}
{{ -endfor }}
-{{ if not library_exported }}
private void init() \{
- StorageInternalReader reader = null;
- boolean foundPackage = true;
try \{
- reader = new StorageInternalReader("{container}", "{package_name}");
+{{ if is_platform_container }}
+ PlatformAconfigPackageInternal reader = PlatformAconfigPackageInternal.load("{container}", "{package_name}", {package_fingerprint});
+{{ -else }}
+ AconfigPackageInternal reader = AconfigPackageInternal.load("{container}", "{package_name}", {package_fingerprint});
+{{ -endif }}
+ AconfigStorageReadException error = reader.getException();
+ if (error == null) \{
+ {{ for namespace_with_flags in namespace_flags }}
+ {{ -for flag in namespace_with_flags.flags }}
+ {{ -if flag.is_read_write }}
+ {flag.method_name} = reader.getBooleanFlagValue({flag.flag_offset});
+ {{ endif }}
+ {{ -endfor }}
+ {{ -endfor }}
+ } else if (Build.VERSION.SDK_INT > 35 && error.getErrorCode() == 5 /* fingerprint doesn't match*/) \{
+ {{ for namespace_with_flags in namespace_flags }}
+ {{ -for flag in namespace_with_flags.flags }}
+ {{ -if flag.is_read_write }}
+ {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
+ {{ -endif }}
+ {{ -endfor }}
+ {{ -endfor }}
+ } else \{
+ if (error.getMessage() != null) \{
+ Log.e(TAG, error.getMessage());
+ } else \{
+ Log.e(TAG, "Encountered a null AconfigStorageReadException");
+ }
+ }
} catch (Exception e) \{
- foundPackage = false;
+ if (e.getMessage() != null) \{
+ Log.e(TAG, e.getMessage());
+ } else \{
+ Log.e(TAG, "Encountered a null Exception");
+ }
+ } catch (NoClassDefFoundError e) \{
+ // for mainline module running on older devices.
+ // This should be replaces to version check, after the version bump.
+ if (e.getMessage() != null) \{
+ Log.e(TAG, e.getMessage());
+ } else \{
+ Log.e(TAG, "Encountered a null NoClassDefFoundError");
+ }
}
- {{ for namespace_with_flags in namespace_flags }}
- {{ -for flag in namespace_with_flags.flags }}
- {{ if flag.is_read_write }}
- {flag.method_name} = foundPackage ? reader.getBooleanFlagValue({flag.flag_offset}) : {flag.default_value};
- {{ endif }}
- {{ -endfor }}
- {{ -endfor }}
isCached = true;
}
-{{ endif }}
-
-
+{{ -endif }}{#- end of runtime_lookup_required #}
+{{ -for flag in flag_elements }}
+ @Override
+ @com.android.aconfig.annotations.AconfigFlagAccessor
+ @UnsupportedAppUsage
+ public boolean {flag.method_name}() \{
+{{ -if flag.is_read_write }}
+ if (!isCached) \{
+ init();
+ }
+ return {flag.method_name};
+{{ -else }}
+ return {flag.default_value};
+{{ -endif }}
+ }
+{{ endfor }}
+}
+{{ -else- }}{#- device config for exproted mode #}
+import android.os.Binder;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+/** @hide */
+public final class FeatureFlagsImpl implements FeatureFlags \{
+{{ -for namespace_with_flags in namespace_flags }}
+ private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
+{{ -endfor- }}
+{{ for flag in flag_elements }}
+{{ -if flag.is_read_write }}
+ private static boolean {flag.method_name} = {flag.default_value};
+{{ -endif }}
+{{ -endfor }}
{{ for namespace_with_flags in namespace_flags }}
private void load_overrides_{namespace_with_flags.namespace}() \{
final long ident = Binder.clearCallingIdentity();
@@ -84,40 +132,17 @@
{namespace_with_flags.namespace}_is_cached = true;
}
{{ endfor- }}
-
-{{ -endif }}{#- end of runtime_lookup_required #}
{{ -for flag in flag_elements }}
@Override
-{{ -if not library_exported }}
- @com.android.aconfig.annotations.AconfigFlagAccessor
- @UnsupportedAppUsage
-{{ -endif }}
public boolean {flag.method_name}() \{
-{{ -if not library_exported }}
-{{ -if flag.is_read_write }}
- if (isReadFromNew) \{
- if (!isCached) \{
- init();
- }
- } else \{
- if (!{flag.device_config_namespace}_is_cached) \{
- load_overrides_{flag.device_config_namespace}();
- }
- }
- return {flag.method_name};
-{{ -else }}
- return {flag.default_value};
-{{ -endif }}
-{{ else }}
if (!{flag.device_config_namespace}_is_cached) \{
load_overrides_{flag.device_config_namespace}();
}
return {flag.method_name};
-{{ -endif }}
}
{{ endfor }}
}
-
+{{ -endif- }} {#- end exported mode #}
{{ else }} {#- else for allow_instrumentation is not enabled #}
{{ if not library_exported- }}
// TODO(b/303773055): Remove the annotation after access issue is resolved.
diff --git a/tools/aconfig/aconfig/templates/cpp_source_file.template b/tools/aconfig/aconfig/templates/cpp_source_file.template
index df3b10d..9be59e0 100644
--- a/tools/aconfig/aconfig/templates/cpp_source_file.template
+++ b/tools/aconfig/aconfig/templates/cpp_source_file.template
@@ -76,17 +76,8 @@
: boolean_start_index_()
{{ -endif }}
, flag_value_file_(nullptr)
- , read_from_new_storage_(false)
, package_exists_in_storage_(true) \{
- if (access("/metadata/aconfig/boot/enable_only_new_storage", F_OK) == 0) \{
- read_from_new_storage_ = true;
- }
-
- if (!read_from_new_storage_) \{
- return;
- }
-
auto package_map_file = aconfig_storage::get_mapped_file(
"{container}",
aconfig_storage::StorageFileType::package_map);
@@ -137,26 +128,19 @@
{{ -if item.readwrite }}
if (cache_[{item.readwrite_idx}] == -1) \{
{{ if allow_instrumentation- }}
- if (read_from_new_storage_) \{
- if (!package_exists_in_storage_) \{
- return {item.default_value};
- }
-
- auto value = aconfig_storage::get_boolean_flag_value(
- *flag_value_file_,
- boolean_start_index_ + {item.flag_offset});
-
- if (!value.ok()) \{
- ALOGE("error: failed to read flag value: %s", value.error().c_str());
- }
-
- cache_[{item.readwrite_idx}] = *value;
- } else \{
- cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
- "aconfig_flags.{item.device_config_namespace}",
- "{item.device_config_flag}",
- "{item.default_value}") == "true";
+ if (!package_exists_in_storage_) \{
+ return {item.default_value};
}
+
+ auto value = aconfig_storage::get_boolean_flag_value(
+ *flag_value_file_,
+ boolean_start_index_ + {item.flag_offset});
+
+ if (!value.ok()) \{
+ ALOGE("error: failed to read flag value: %s", value.error().c_str());
+ }
+
+ cache_[{item.readwrite_idx}] = *value;
{{ -else- }}
cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
"aconfig_flags.{item.device_config_namespace}",
@@ -183,8 +167,6 @@
std::unique_ptr<aconfig_storage::MappedStorageFile> flag_value_file_;
- bool read_from_new_storage_;
-
bool package_exists_in_storage_;
{{ -endif }}
{{ -endif }}
diff --git a/tools/aconfig/aconfig/templates/rust.template b/tools/aconfig/aconfig/templates/rust.template
index d0079d4..e9e1032 100644
--- a/tools/aconfig/aconfig/templates/rust.template
+++ b/tools/aconfig/aconfig/templates/rust.template
@@ -10,10 +10,6 @@
{{ if has_readwrite- }}
{{ if allow_instrumentation }}
-static READ_FROM_NEW_STORAGE: LazyLock<bool> = LazyLock::new(|| unsafe \{
- Path::new("/metadata/aconfig/boot/enable_only_new_storage").exists()
-});
-
static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe \{
get_mapped_storage_file("{container}", StorageFileType::PackageMap)
.and_then(|package_map| get_package_read_context(&package_map, "{package}"))
@@ -31,48 +27,41 @@
{{ if allow_instrumentation }}
static CACHED_{flag.name}: LazyLock<bool> = LazyLock::new(|| \{
- if *READ_FROM_NEW_STORAGE \{
- // This will be called multiple times. Subsequent calls after the first are noops.
- logger::init(
- logger::Config::default()
- .with_tag_on_device("aconfig_rust_codegen")
- .with_max_level(LevelFilter::Info));
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device("aconfig_rust_codegen")
+ .with_max_level(LevelFilter::Info));
- let flag_value_result = FLAG_VAL_MAP
- .as_ref()
- .map_err(|err| format!("failed to get flag val map: \{err}"))
- .and_then(|flag_val_map| \{
- PACKAGE_OFFSET
- .as_ref()
- .map_err(|err| format!("failed to get package read offset: \{err}"))
- .and_then(|package_offset| \{
- match package_offset \{
- Some(offset) => \{
- get_boolean_flag_value(&flag_val_map, offset + {flag.flag_offset})
- .map_err(|err| format!("failed to get flag: \{err}"))
- },
- None => \{
- log!(Level::Error, "no context found for package {package}");
- Err(format!("failed to flag package {package}"))
- }
+ let flag_value_result = FLAG_VAL_MAP
+ .as_ref()
+ .map_err(|err| format!("failed to get flag val map: \{err}"))
+ .and_then(|flag_val_map| \{
+ PACKAGE_OFFSET
+ .as_ref()
+ .map_err(|err| format!("failed to get package read offset: \{err}"))
+ .and_then(|package_offset| \{
+ match package_offset \{
+ Some(offset) => \{
+ get_boolean_flag_value(&flag_val_map, offset + {flag.flag_offset})
+ .map_err(|err| format!("failed to get flag: \{err}"))
+ },
+ None => \{
+ log!(Level::Error, "no context found for package {package}");
+ Err(format!("failed to flag package {package}"))
}
- })
- });
+ }
+ })
+ });
- match flag_value_result \{
- Ok(flag_value) => \{
- return flag_value;
- },
- Err(err) => \{
- log!(Level::Error, "aconfig_rust_codegen: error: \{err}");
- return {flag.default_value};
- }
+ match flag_value_result \{
+ Ok(flag_value) => \{
+ return flag_value;
+ },
+ Err(err) => \{
+ log!(Level::Error, "aconfig_rust_codegen: error: \{err}");
+ return {flag.default_value};
}
- } else \{
- flags_rust::GetServerConfigurableFlag(
- "aconfig_flags.{flag.device_config_namespace}",
- "{flag.device_config_flag}",
- "{flag.default_value}") == "true"
}
});
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_info.rs b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
index f090396..cf16834 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_info.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
@@ -194,12 +194,15 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::test_utils::create_test_flag_info_list;
+ use crate::{
+ test_utils::create_test_flag_info_list, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION,
+ };
- #[test]
// this test point locks down the value list serialization
- fn test_serialization() {
- let flag_info_list = create_test_flag_info_list();
+ // TODO: b/376108268 - Use parameterized tests.
+ #[test]
+ fn test_serialization_default() {
+ let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
let header: &FlagInfoHeader = &flag_info_list.header;
let reinterpreted_header = FlagInfoHeader::from_bytes(&header.into_bytes());
@@ -220,20 +223,42 @@
}
#[test]
- // this test point locks down that version number should be at the top of serialized
- // bytes
- fn test_version_number() {
- let flag_info_list = create_test_flag_info_list();
- let bytes = &flag_info_list.into_bytes();
- let mut head = 0;
- let version = read_u32_from_bytes(bytes, &mut head).unwrap();
- assert_eq!(version, 1);
+ fn test_serialization_max() {
+ let flag_info_list = create_test_flag_info_list(MAX_SUPPORTED_FILE_VERSION);
+
+ let header: &FlagInfoHeader = &flag_info_list.header;
+ let reinterpreted_header = FlagInfoHeader::from_bytes(&header.into_bytes());
+ assert!(reinterpreted_header.is_ok());
+ assert_eq!(header, &reinterpreted_header.unwrap());
+
+ let nodes: &Vec<FlagInfoNode> = &flag_info_list.nodes;
+ for node in nodes.iter() {
+ let reinterpreted_node = FlagInfoNode::from_bytes(&node.into_bytes()).unwrap();
+ assert_eq!(node, &reinterpreted_node);
+ }
+
+ let flag_info_bytes = flag_info_list.into_bytes();
+ let reinterpreted_info_list = FlagInfoList::from_bytes(&flag_info_bytes);
+ assert!(reinterpreted_info_list.is_ok());
+ assert_eq!(&flag_info_list, &reinterpreted_info_list.unwrap());
+ assert_eq!(flag_info_bytes.len() as u32, header.file_size);
}
+ // this test point locks down that version number should be at the top of serialized
+ // bytes
#[test]
+ fn test_version_number() {
+ let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
+ let bytes = &flag_info_list.into_bytes();
+ let mut head = 0;
+ let version_from_file = read_u32_from_bytes(bytes, &mut head).unwrap();
+ assert_eq!(version_from_file, DEFAULT_FILE_VERSION);
+ }
+
// this test point locks down file type check
+ #[test]
fn test_file_type_check() {
- let mut flag_info_list = create_test_flag_info_list();
+ let mut flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
flag_info_list.header.file_type = 123u8;
let error = FlagInfoList::from_bytes(&flag_info_list.into_bytes()).unwrap_err();
assert_eq!(
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_table.rs b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
index 0588fe5..6fbee02 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
@@ -220,12 +220,15 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::test_utils::create_test_flag_table;
+ use crate::{
+ test_utils::create_test_flag_table, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION,
+ };
- #[test]
// this test point locks down the table serialization
- fn test_serialization() {
- let flag_table = create_test_flag_table();
+ // TODO: b/376108268 - Use parameterized tests.
+ #[test]
+ fn test_serialization_default() {
+ let flag_table = create_test_flag_table(DEFAULT_FILE_VERSION);
let header: &FlagTableHeader = &flag_table.header;
let reinterpreted_header = FlagTableHeader::from_bytes(&header.into_bytes());
@@ -246,20 +249,42 @@
}
#[test]
- // this test point locks down that version number should be at the top of serialized
- // bytes
- fn test_version_number() {
- let flag_table = create_test_flag_table();
- let bytes = &flag_table.into_bytes();
- let mut head = 0;
- let version = read_u32_from_bytes(bytes, &mut head).unwrap();
- assert_eq!(version, 1);
+ fn test_serialization_max() {
+ let flag_table = create_test_flag_table(MAX_SUPPORTED_FILE_VERSION);
+
+ let header: &FlagTableHeader = &flag_table.header;
+ let reinterpreted_header = FlagTableHeader::from_bytes(&header.into_bytes());
+ assert!(reinterpreted_header.is_ok());
+ assert_eq!(header, &reinterpreted_header.unwrap());
+
+ let nodes: &Vec<FlagTableNode> = &flag_table.nodes;
+ for node in nodes.iter() {
+ let reinterpreted_node = FlagTableNode::from_bytes(&node.into_bytes()).unwrap();
+ assert_eq!(node, &reinterpreted_node);
+ }
+
+ let flag_table_bytes = flag_table.into_bytes();
+ let reinterpreted_table = FlagTable::from_bytes(&flag_table_bytes);
+ assert!(reinterpreted_table.is_ok());
+ assert_eq!(&flag_table, &reinterpreted_table.unwrap());
+ assert_eq!(flag_table_bytes.len() as u32, header.file_size);
}
+ // this test point locks down that version number should be at the top of serialized
+ // bytes
#[test]
+ fn test_version_number() {
+ let flag_table = create_test_flag_table(DEFAULT_FILE_VERSION);
+ let bytes = &flag_table.into_bytes();
+ let mut head = 0;
+ let version_from_file = read_u32_from_bytes(bytes, &mut head).unwrap();
+ assert_eq!(version_from_file, DEFAULT_FILE_VERSION);
+ }
+
// this test point locks down file type check
+ #[test]
fn test_file_type_check() {
- let mut flag_table = create_test_flag_table();
+ let mut flag_table = create_test_flag_table(DEFAULT_FILE_VERSION);
flag_table.header.file_type = 123u8;
let error = FlagTable::from_bytes(&flag_table.into_bytes()).unwrap_err();
assert_eq!(
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_value.rs b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
index b64c10e..9a14bec 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_value.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
@@ -132,12 +132,32 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::test_utils::create_test_flag_value_list;
+ use crate::{
+ test_utils::create_test_flag_value_list, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION,
+ };
#[test]
// this test point locks down the value list serialization
- fn test_serialization() {
- let flag_value_list = create_test_flag_value_list();
+ // TODO: b/376108268 - Use parameterized tests.
+ fn test_serialization_default() {
+ let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
+
+ let header: &FlagValueHeader = &flag_value_list.header;
+ let reinterpreted_header = FlagValueHeader::from_bytes(&header.into_bytes());
+ assert!(reinterpreted_header.is_ok());
+ assert_eq!(header, &reinterpreted_header.unwrap());
+
+ let flag_value_bytes = flag_value_list.into_bytes();
+ let reinterpreted_value_list = FlagValueList::from_bytes(&flag_value_bytes);
+ assert!(reinterpreted_value_list.is_ok());
+ assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap());
+ assert_eq!(flag_value_bytes.len() as u32, header.file_size);
+ }
+
+ #[test]
+ // this test point locks down the value list serialization
+ fn test_serialization_max() {
+ let flag_value_list = create_test_flag_value_list(MAX_SUPPORTED_FILE_VERSION);
let header: &FlagValueHeader = &flag_value_list.header;
let reinterpreted_header = FlagValueHeader::from_bytes(&header.into_bytes());
@@ -155,17 +175,17 @@
// this test point locks down that version number should be at the top of serialized
// bytes
fn test_version_number() {
- let flag_value_list = create_test_flag_value_list();
+ let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
let bytes = &flag_value_list.into_bytes();
let mut head = 0;
- let version = read_u32_from_bytes(bytes, &mut head).unwrap();
- assert_eq!(version, 1);
+ let version_from_file = read_u32_from_bytes(bytes, &mut head).unwrap();
+ assert_eq!(version_from_file, DEFAULT_FILE_VERSION);
}
#[test]
// this test point locks down file type check
fn test_file_type_check() {
- let mut flag_value_list = create_test_flag_value_list();
+ let mut flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
flag_value_list.header.file_type = 123u8;
let error = FlagValueList::from_bytes(&flag_value_list.into_bytes()).unwrap_err();
assert_eq!(
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index 5dc5ef7..e991320 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -228,14 +228,10 @@
/// Read and parse bytes as u8
pub fn read_u8_from_bytes(buf: &[u8], head: &mut usize) -> Result<u8, AconfigStorageError> {
- let val = u8::from_le_bytes(
- buf.get(*head..*head + 1)
- .ok_or(AconfigStorageError::BytesParseFail(anyhow!(
- "fail to parse u8 from bytes: access out of bounds"
- )))?
- .try_into()
- .map_err(|errmsg| BytesParseFail(anyhow!("fail to parse u8 from bytes: {}", errmsg)))?,
- );
+ let val =
+ u8::from_le_bytes(buf[*head..*head + 1].try_into().map_err(|errmsg| {
+ BytesParseFail(anyhow!("fail to parse u8 from bytes: {}", errmsg))
+ })?);
*head += 1;
Ok(val)
}
@@ -245,16 +241,10 @@
buf: &[u8],
head: &mut usize,
) -> Result<u16, AconfigStorageError> {
- let val = u16::from_le_bytes(
- buf.get(*head..*head + 2)
- .ok_or(AconfigStorageError::BytesParseFail(anyhow!(
- "fail to parse u16 from bytes: access out of bounds"
- )))?
- .try_into()
- .map_err(|errmsg| {
- BytesParseFail(anyhow!("fail to parse u16 from bytes: {}", errmsg))
- })?,
- );
+ let val =
+ u16::from_le_bytes(buf[*head..*head + 2].try_into().map_err(|errmsg| {
+ BytesParseFail(anyhow!("fail to parse u16 from bytes: {}", errmsg))
+ })?);
*head += 2;
Ok(val)
}
@@ -266,32 +256,20 @@
/// Read and parse bytes as u32
pub fn read_u32_from_bytes(buf: &[u8], head: &mut usize) -> Result<u32, AconfigStorageError> {
- let val = u32::from_le_bytes(
- buf.get(*head..*head + 4)
- .ok_or(AconfigStorageError::BytesParseFail(anyhow!(
- "fail to parse u32 from bytes: access out of bounds"
- )))?
- .try_into()
- .map_err(|errmsg| {
- BytesParseFail(anyhow!("fail to parse u32 from bytes: {}", errmsg))
- })?,
- );
+ let val =
+ u32::from_le_bytes(buf[*head..*head + 4].try_into().map_err(|errmsg| {
+ BytesParseFail(anyhow!("fail to parse u32 from bytes: {}", errmsg))
+ })?);
*head += 4;
Ok(val)
}
// Read and parse bytes as u64
pub fn read_u64_from_bytes(buf: &[u8], head: &mut usize) -> Result<u64, AconfigStorageError> {
- let val = u64::from_le_bytes(
- buf.get(*head..*head + 8)
- .ok_or(AconfigStorageError::BytesParseFail(anyhow!(
- "fail to parse u64 from bytes: access out of bounds"
- )))?
- .try_into()
- .map_err(|errmsg| {
- BytesParseFail(anyhow!("fail to parse u64 from bytes: {}", errmsg))
- })?,
- );
+ let val =
+ u64::from_le_bytes(buf[*head..*head + 8].try_into().map_err(|errmsg| {
+ BytesParseFail(anyhow!("fail to parse u64 from bytes: {}", errmsg))
+ })?);
*head += 8;
Ok(val)
}
@@ -302,21 +280,8 @@
head: &mut usize,
) -> Result<String, AconfigStorageError> {
let num_bytes = read_u32_from_bytes(buf, head)? as usize;
- // TODO(opg): Document this limitation and check it when creating files.
- if num_bytes > 1024 {
- return Err(AconfigStorageError::BytesParseFail(anyhow!(
- "fail to parse string from bytes, string is too long (found {}, max is 1024)",
- num_bytes
- )));
- }
- let val = String::from_utf8(
- buf.get(*head..*head + num_bytes)
- .ok_or(AconfigStorageError::BytesParseFail(anyhow!(
- "fail to parse string from bytes: access out of bounds"
- )))?
- .to_vec(),
- )
- .map_err(|errmsg| BytesParseFail(anyhow!("fail to parse string from bytes: {}", errmsg)))?;
+ let val = String::from_utf8(buf[*head..*head + num_bytes].to_vec())
+ .map_err(|errmsg| BytesParseFail(anyhow!("fail to parse string from bytes: {}", errmsg)))?;
*head += num_bytes;
Ok(val)
}
@@ -568,41 +533,18 @@
};
#[test]
- fn test_list_flags_with_missing_files_error() {
- let flag_list_error = list_flags("does", "not", "exist").unwrap_err();
- assert_eq!(
- format!("{:?}", flag_list_error),
- format!(
- "FileReadFail(Failed to open file does: No such file or directory (os error 2))"
- )
- );
- }
-
- #[test]
- fn test_list_flags_with_invalid_files_error() {
- let invalid_bytes: [u8; 3] = [0; 3];
- let package_table = write_bytes_to_temp_file(&invalid_bytes).unwrap();
- let flag_table = write_bytes_to_temp_file(&invalid_bytes).unwrap();
- let flag_value_list = write_bytes_to_temp_file(&invalid_bytes).unwrap();
- let package_table_path = package_table.path().display().to_string();
- let flag_table_path = flag_table.path().display().to_string();
- let flag_value_list_path = flag_value_list.path().display().to_string();
- let flag_list_error =
- list_flags(&package_table_path, &flag_table_path, &flag_value_list_path).unwrap_err();
- assert_eq!(
- format!("{:?}", flag_list_error),
- format!("BytesParseFail(fail to parse u32 from bytes: access out of bounds)")
- );
- }
-
- #[test]
// this test point locks down the flag list api
fn test_list_flag() {
let package_table =
- write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
- let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
- let flag_value_list =
- write_bytes_to_temp_file(&create_test_flag_value_list().into_bytes()).unwrap();
+ write_bytes_to_temp_file(&create_test_package_table(DEFAULT_FILE_VERSION).into_bytes())
+ .unwrap();
+ let flag_table =
+ write_bytes_to_temp_file(&create_test_flag_table(DEFAULT_FILE_VERSION).into_bytes())
+ .unwrap();
+ let flag_value_list = write_bytes_to_temp_file(
+ &create_test_flag_value_list(DEFAULT_FILE_VERSION).into_bytes(),
+ )
+ .unwrap();
let package_table_path = package_table.path().display().to_string();
let flag_table_path = flag_table.path().display().to_string();
@@ -667,12 +609,19 @@
// this test point locks down the flag list with info api
fn test_list_flag_with_info() {
let package_table =
- write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
- let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
- let flag_value_list =
- write_bytes_to_temp_file(&create_test_flag_value_list().into_bytes()).unwrap();
- let flag_info_list =
- write_bytes_to_temp_file(&create_test_flag_info_list().into_bytes()).unwrap();
+ write_bytes_to_temp_file(&create_test_package_table(DEFAULT_FILE_VERSION).into_bytes())
+ .unwrap();
+ let flag_table =
+ write_bytes_to_temp_file(&create_test_flag_table(DEFAULT_FILE_VERSION).into_bytes())
+ .unwrap();
+ let flag_value_list = write_bytes_to_temp_file(
+ &create_test_flag_value_list(DEFAULT_FILE_VERSION).into_bytes(),
+ )
+ .unwrap();
+ let flag_info_list = write_bytes_to_temp_file(
+ &create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes(),
+ )
+ .unwrap();
let package_table_path = package_table.path().display().to_string();
let flag_table_path = flag_table.path().display().to_string();
diff --git a/tools/aconfig/aconfig_storage_file/src/package_table.rs b/tools/aconfig/aconfig_storage_file/src/package_table.rs
index af39fbc..21357c7 100644
--- a/tools/aconfig/aconfig_storage_file/src/package_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/package_table.rs
@@ -100,6 +100,7 @@
pub struct PackageTableNode {
pub package_name: String,
pub package_id: u32,
+ pub fingerprint: u64,
// The index of the first boolean flag in this aconfig package among all boolean
// flags in this container.
pub boolean_start_index: u32,
@@ -111,8 +112,12 @@
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
- "Package: {}, Id: {}, Boolean flag start index: {}, Next: {:?}",
- self.package_name, self.package_id, self.boolean_start_index, self.next_offset
+ "Package: {}, Id: {}, Fingerprint: {}, Boolean flag start index: {}, Next: {:?}",
+ self.package_name,
+ self.package_id,
+ self.fingerprint,
+ self.boolean_start_index,
+ self.next_offset
)?;
Ok(())
}
@@ -146,9 +151,7 @@
result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
result.extend_from_slice(name_bytes);
result.extend_from_slice(&self.package_id.to_le_bytes());
- // V2 storage files have a fingerprint. Current struct (v1) does not, so
- // we write 0.
- result.extend_from_slice(&0u64.to_le_bytes());
+ result.extend_from_slice(&self.fingerprint.to_le_bytes());
result.extend_from_slice(&self.boolean_start_index.to_le_bytes());
result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
result
@@ -172,13 +175,15 @@
let mut head = 0;
let package_name = read_str_from_bytes(bytes, &mut head)?;
let package_id = read_u32_from_bytes(bytes, &mut head)?;
+ // v1 does not have fingerprint, so just set to 0.
+ let fingerprint: u64 = 0;
let boolean_start_index = read_u32_from_bytes(bytes, &mut head)?;
let next_offset = match read_u32_from_bytes(bytes, &mut head)? {
0 => None,
val => Some(val),
};
- let node = Self { package_name, package_id, boolean_start_index, next_offset };
+ let node = Self { package_name, package_id, fingerprint, boolean_start_index, next_offset };
Ok(node)
}
@@ -186,18 +191,14 @@
let mut head = 0;
let package_name = read_str_from_bytes(bytes, &mut head)?;
let package_id = read_u32_from_bytes(bytes, &mut head)?;
-
- // Fingerprint is unused in the current struct (v1), but we need to read
- // the bytes if the storage file type is v2 or else the subsequent
- // fields will be inaccurate.
- let _fingerprint = read_u64_from_bytes(bytes, &mut head)?;
+ let fingerprint = read_u64_from_bytes(bytes, &mut head)?;
let boolean_start_index = read_u32_from_bytes(bytes, &mut head)?;
let next_offset = match read_u32_from_bytes(bytes, &mut head)? {
0 => None,
val => Some(val),
};
- let node = Self { package_name, package_id, boolean_start_index, next_offset };
+ let node = Self { package_name, package_id, fingerprint, boolean_start_index, next_offset };
Ok(node)
}
@@ -281,13 +282,37 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::read_u32_from_start_of_bytes;
- use crate::{test_utils::create_test_package_table, DEFAULT_FILE_VERSION};
+ use crate::test_utils::create_test_package_table;
+ use crate::{read_u32_from_start_of_bytes, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION};
#[test]
// this test point locks down the table serialization
- fn test_serialization() {
- let package_table = create_test_package_table();
+ // TODO: b/376108268 - Use parameterized tests.
+ fn test_serialization_default() {
+ let package_table = create_test_package_table(DEFAULT_FILE_VERSION);
+ let header: &PackageTableHeader = &package_table.header;
+ let reinterpreted_header = PackageTableHeader::from_bytes(&header.into_bytes());
+ assert!(reinterpreted_header.is_ok());
+ assert_eq!(header, &reinterpreted_header.unwrap());
+
+ let nodes: &Vec<PackageTableNode> = &package_table.nodes;
+ for node in nodes.iter() {
+ let reinterpreted_node =
+ PackageTableNode::from_bytes(&node.into_bytes(header.version), header.version)
+ .unwrap();
+ assert_eq!(node, &reinterpreted_node);
+ }
+
+ let package_table_bytes = package_table.into_bytes();
+ let reinterpreted_table = PackageTable::from_bytes(&package_table_bytes);
+ assert!(reinterpreted_table.is_ok());
+ assert_eq!(&package_table, &reinterpreted_table.unwrap());
+ assert_eq!(package_table_bytes.len() as u32, header.file_size);
+ }
+
+ #[test]
+ fn test_serialization_max() {
+ let package_table = create_test_package_table(MAX_SUPPORTED_FILE_VERSION);
let header: &PackageTableHeader = &package_table.header;
let reinterpreted_header = PackageTableHeader::from_bytes(&header.into_bytes());
assert!(reinterpreted_header.is_ok());
@@ -312,44 +337,36 @@
// this test point locks down that version number should be at the top of serialized
// bytes
fn test_version_number() {
- let package_table = create_test_package_table();
+ let package_table = create_test_package_table(DEFAULT_FILE_VERSION);
let bytes = &package_table.into_bytes();
- let version = read_u32_from_start_of_bytes(bytes).unwrap();
- assert_eq!(version, DEFAULT_FILE_VERSION);
+ let unpacked_version = read_u32_from_start_of_bytes(bytes).unwrap();
+ assert_eq!(unpacked_version, DEFAULT_FILE_VERSION);
}
#[test]
- fn test_round_trip_v1() {
- let table_v1: PackageTable = create_test_package_table();
- let table_bytes_v1 = table_v1.into_bytes();
+ fn test_round_trip_default() {
+ let table: PackageTable = create_test_package_table(DEFAULT_FILE_VERSION);
+ let table_bytes = table.into_bytes();
- // Will automatically read from version 2 as the version code is encoded
- // into the bytes.
- let reinterpreted_table = PackageTable::from_bytes(&table_bytes_v1).unwrap();
+ let reinterpreted_table = PackageTable::from_bytes(&table_bytes).unwrap();
- assert_eq!(table_v1, reinterpreted_table);
+ assert_eq!(table, reinterpreted_table);
}
#[test]
- fn test_round_trip_v2() {
- // Have to fake v2 because though we will set the version to v2
- // and write the bytes as v2, we don't have the ability to actually set
- // the fingerprint yet.
- let mut fake_table_v2 = create_test_package_table();
- fake_table_v2.header.version = 2;
- let table_bytes_v2 = fake_table_v2.into_bytes();
+ fn test_round_trip_max() {
+ let table: PackageTable = create_test_package_table(MAX_SUPPORTED_FILE_VERSION);
+ let table_bytes = table.into_bytes();
- // Will automatically read from version 2 as the version code is encoded
- // into the bytes.
- let reinterpreted_table = PackageTable::from_bytes(&table_bytes_v2).unwrap();
+ let reinterpreted_table = PackageTable::from_bytes(&table_bytes).unwrap();
- assert_eq!(fake_table_v2, reinterpreted_table);
+ assert_eq!(table, reinterpreted_table);
}
#[test]
// this test point locks down file type check
fn test_file_type_check() {
- let mut package_table = create_test_package_table();
+ let mut package_table = create_test_package_table(DEFAULT_FILE_VERSION);
package_table.header.file_type = 123u8;
let error = PackageTable::from_bytes(&package_table.into_bytes()).unwrap_err();
assert_eq!(
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
index 5c364f6..7c603df 100644
--- a/tools/aconfig/aconfig_storage_file/src/test_utils.rs
+++ b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
@@ -18,38 +18,65 @@
use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
use crate::flag_value::{FlagValueHeader, FlagValueList};
use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
-use crate::{AconfigStorageError, StorageFileType, StoredFlagType, DEFAULT_FILE_VERSION};
+use crate::{AconfigStorageError, StorageFileType, StoredFlagType};
use anyhow::anyhow;
use std::io::Write;
use tempfile::NamedTempFile;
-pub fn create_test_package_table() -> PackageTable {
+pub fn create_test_package_table(version: u32) -> PackageTable {
let header = PackageTableHeader {
- version: DEFAULT_FILE_VERSION,
+ version: version,
container: String::from("mockup"),
file_type: StorageFileType::PackageMap as u8,
- file_size: 209,
+ file_size: match version {
+ 1 => 209,
+ 2 => 233,
+ _ => panic!("Unsupported version."),
+ },
num_packages: 3,
bucket_offset: 31,
node_offset: 59,
};
- let buckets: Vec<Option<u32>> = vec![Some(59), None, None, Some(109), None, None, None];
+ let buckets: Vec<Option<u32>> = match version {
+ 1 => vec![Some(59), None, None, Some(109), None, None, None],
+ 2 => vec![Some(59), None, None, Some(117), None, None, None],
+ _ => panic!("Unsupported version."),
+ };
let first_node = PackageTableNode {
package_name: String::from("com.android.aconfig.storage.test_2"),
package_id: 1,
+ fingerprint: match version {
+ 1 => 0,
+ 2 => 4431940502274857964u64,
+ _ => panic!("Unsupported version."),
+ },
boolean_start_index: 3,
next_offset: None,
};
let second_node = PackageTableNode {
package_name: String::from("com.android.aconfig.storage.test_1"),
package_id: 0,
+ fingerprint: match version {
+ 1 => 0,
+ 2 => 15248948510590158086u64,
+ _ => panic!("Unsupported version."),
+ },
boolean_start_index: 0,
- next_offset: Some(159),
+ next_offset: match version {
+ 1 => Some(159),
+ 2 => Some(175),
+ _ => panic!("Unsupported version."),
+ },
};
let third_node = PackageTableNode {
package_name: String::from("com.android.aconfig.storage.test_4"),
package_id: 2,
+ fingerprint: match version {
+ 1 => 0,
+ 2 => 16233229917711622375u64,
+ _ => panic!("Unsupported version."),
+ },
boolean_start_index: 6,
next_offset: None,
};
@@ -76,9 +103,9 @@
}
}
-pub fn create_test_flag_table() -> FlagTable {
+pub fn create_test_flag_table(version: u32) -> FlagTable {
let header = FlagTableHeader {
- version: DEFAULT_FILE_VERSION,
+ version: version,
container: String::from("mockup"),
file_type: StorageFileType::FlagMap as u8,
file_size: 321,
@@ -118,9 +145,9 @@
FlagTable { header, buckets, nodes }
}
-pub fn create_test_flag_value_list() -> FlagValueList {
+pub fn create_test_flag_value_list(version: u32) -> FlagValueList {
let header = FlagValueHeader {
- version: DEFAULT_FILE_VERSION,
+ version: version,
container: String::from("mockup"),
file_type: StorageFileType::FlagVal as u8,
file_size: 35,
@@ -131,9 +158,9 @@
FlagValueList { header, booleans }
}
-pub fn create_test_flag_info_list() -> FlagInfoList {
+pub fn create_test_flag_info_list(version: u32) -> FlagInfoList {
let header = FlagInfoHeader {
- version: DEFAULT_FILE_VERSION,
+ version: version,
container: String::from("mockup"),
file_type: StorageFileType::FlagInfo as u8,
file_size: 35,
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
index b1c7ee7..324c55d 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
@@ -39,6 +39,8 @@
/** Error code indicating that there was an error reading the Aconfig Storage file. */
public static final int ERROR_CANNOT_READ_STORAGE_FILE = 4;
+ public static final int ERROR_FILE_FINGERPRINT_MISMATCH = 5;
+
private final int mErrorCode;
/**
@@ -126,6 +128,8 @@
return "ERROR_CONTAINER_NOT_FOUND";
case ERROR_CANNOT_READ_STORAGE_FILE:
return "ERROR_CANNOT_READ_STORAGE_FILE";
+ case ERROR_FILE_FINGERPRINT_MISMATCH:
+ return "ERROR_FILE_FINGERPRINT_MISMATCH";
default:
return "<Unknown error code " + mErrorCode + ">";
}
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
index b0b1b9b..c354873 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
@@ -42,4 +42,20 @@
return null;
}
}
+
+ @Override
+ public String toString() {
+ switch (type) {
+ case 0:
+ return "PACKAGE_MAP";
+ case 1:
+ return "FLAG_MAP";
+ case 2:
+ return "FLAG_VAL";
+ case 3:
+ return "FLAG_INFO";
+ default:
+ return "unrecognized type";
+ }
+ }
}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageFileProvider.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
similarity index 75%
rename from tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageFileProvider.java
rename to tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
index b28341e..f1a4e26 100644
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageFileProvider.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
@@ -21,11 +21,15 @@
import java.nio.channels.FileChannel;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/** @hide */
public class StorageFileProvider {
@@ -51,23 +55,23 @@
}
/** @hide */
- public boolean containerFileExists(String container) {
- if (container == null) {
- return Files.exists(Paths.get(mMapPath));
- }
- return Files.exists(Paths.get(mMapPath, container + PMAP_FILE_EXT));
- }
+ public List<String> listContainers(String[] excludes) {
+ List<String> result = new ArrayList<>();
+ Set<String> set = new HashSet<>(Arrays.asList(excludes));
- /** @hide */
- public List<Path> listPackageMapFiles() {
- List<Path> result = new ArrayList<>();
try {
DirectoryStream<Path> stream =
Files.newDirectoryStream(Paths.get(mMapPath), "*" + PMAP_FILE_EXT);
for (Path entry : stream) {
- result.add(entry);
- // sb.append(entry. toString());
+ String fileName = entry.getFileName().toString();
+ String container =
+ fileName.substring(0, fileName.length() - PMAP_FILE_EXT.length());
+ if (!set.contains(container)) {
+ result.add(container);
+ }
}
+ } catch (NoSuchFileException e) {
+ return result;
} catch (Exception e) {
throw new AconfigStorageException(
String.format("Fail to list map files in path %s", mMapPath), e);
@@ -83,22 +87,23 @@
/** @hide */
public FlagTable getFlagTable(String container) {
- return FlagTable.fromBytes(mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT)));
+ return FlagTable.fromBytes(
+ mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT), FileType.FLAG_MAP));
}
/** @hide */
public FlagValueList getFlagValueList(String container) {
return FlagValueList.fromBytes(
- mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT)));
+ mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT), FileType.FLAG_VAL));
}
/** @hide */
public static PackageTable getPackageTable(Path path) {
- return PackageTable.fromBytes(mapStorageFile(path));
+ return PackageTable.fromBytes(mapStorageFile(path, FileType.PACKAGE_MAP));
}
// Map a storage file given file path
- private static MappedByteBuffer mapStorageFile(Path file) {
+ private static MappedByteBuffer mapStorageFile(Path file, FileType type) {
FileChannel channel = null;
try {
channel = FileChannel.open(file, StandardOpenOption.READ);
@@ -106,7 +111,7 @@
} catch (Exception e) {
throw new AconfigStorageException(
AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
- String.format("Fail to mmap storage file %s", file),
+ String.format("Fail to mmap storage %s file %s", type.toString(), file),
e);
} finally {
quietlyDispose(channel);
diff --git a/tools/aconfig/aconfig_storage_file/tests/Android.bp b/tools/aconfig/aconfig_storage_file/tests/Android.bp
index 13d3214..bd46d5f 100644
--- a/tools/aconfig/aconfig_storage_file/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_file/tests/Android.bp
@@ -10,10 +10,14 @@
"libbase",
],
data: [
- "data/v1/package.map",
- "data/v1/flag.map",
- "data/v1/flag.val",
- "data/v1/flag.info",
+ "data/v1/package_v1.map",
+ "data/v1/flag_v1.map",
+ "data/v1/flag_v1.val",
+ "data/v1/flag_v1.info",
+ "data/v2/package_v2.map",
+ "data/v2/flag_v2.map",
+ "data/v2/flag_v2.val",
+ "data/v2/flag_v2.info",
],
test_suites: [
"device-tests",
@@ -35,10 +39,14 @@
test_config: "AndroidStorageJaveTest.xml",
sdk_version: "test_current",
data: [
- "data/v1/package.map",
- "data/v1/flag.map",
- "data/v1/flag.val",
- "data/v1/flag.info",
+ "data/v1/package_v1.map",
+ "data/v1/flag_v1.map",
+ "data/v1/flag_v1.val",
+ "data/v1/flag_v1.info",
+ "data/v2/package_v2.map",
+ "data/v2/flag_v2.map",
+ "data/v2/flag_v2.val",
+ "data/v2/flag_v2.info",
],
test_suites: [
"general-tests",
diff --git a/tools/aconfig/aconfig_storage_file/tests/AndroidStorageJaveTest.xml b/tools/aconfig/aconfig_storage_file/tests/AndroidStorageJaveTest.xml
index 2d52d44..bfc238e 100644
--- a/tools/aconfig/aconfig_storage_file/tests/AndroidStorageJaveTest.xml
+++ b/tools/aconfig/aconfig_storage_file/tests/AndroidStorageJaveTest.xml
@@ -21,13 +21,18 @@
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
- <option name="push" value="package.map->/data/local/tmp/aconfig_storage_file_test_java/testdata/package.map" />
- <option name="push" value="flag.map->/data/local/tmp/aconfig_storage_file_test_java/testdata/flag.map" />
- <option name="push" value="flag.val->/data/local/tmp/aconfig_storage_file_test_java/testdata/flag.val" />
- <option name="push" value="flag.info->/data/local/tmp/aconfig_storage_file_test_java/testdata/flag.info" />
+ <option name="push" value="package_v1.map->/data/local/tmp/aconfig_storage_file_test_java/testdata/mock.v1.package.map" />
+ <option name="push" value="flag_v1.map->/data/local/tmp/aconfig_storage_file_test_java/testdata/mock.v1.flag.map" />
+ <option name="push" value="flag_v1.val->/data/local/tmp/aconfig_storage_file_test_java/testdata/mock.v1.val" />
+ <option name="push" value="flag_v1.info->/data/local/tmp/aconfig_storage_file_test_java/testdata/mock.v1.info" />
+ <option name="push" value="package_v2.map->/data/local/tmp/aconfig_storage_file_test_java/testdata/mock.v2.package.map" />
+ <option name="push" value="flag_v2.map->/data/local/tmp/aconfig_storage_file_test_java/testdata/mock.v2.flag.map" />
+ <option name="push" value="flag_v2.val->/data/local/tmp/aconfig_storage_file_test_java/testdata/mock.v2.val" />
+ <option name="push" value="flag_v2.info->/data/local/tmp/aconfig_storage_file_test_java/testdata/mock.v2.info" />
+ <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_file_test_java/testdata/" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.aconfig.storage.test" />
<option name="runtime-hint" value="1m" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v1/flag.info b/tools/aconfig/aconfig_storage_file/tests/data/v1/flag_v1.info
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/tests/data/v1/flag.info
rename to tools/aconfig/aconfig_storage_file/tests/data/v1/flag_v1.info
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v1/flag.map b/tools/aconfig/aconfig_storage_file/tests/data/v1/flag_v1.map
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/tests/data/v1/flag.map
rename to tools/aconfig/aconfig_storage_file/tests/data/v1/flag_v1.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v1/flag.val b/tools/aconfig/aconfig_storage_file/tests/data/v1/flag_v1.val
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/tests/data/v1/flag.val
rename to tools/aconfig/aconfig_storage_file/tests/data/v1/flag_v1.val
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v1/package.map b/tools/aconfig/aconfig_storage_file/tests/data/v1/package_v1.map
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/tests/data/v1/package.map
rename to tools/aconfig/aconfig_storage_file/tests/data/v1/package_v1.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.info b/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.info
new file mode 100644
index 0000000..9db7fde
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.info
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.map b/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.map
new file mode 100644
index 0000000..cf4685c
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.val b/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.val
new file mode 100644
index 0000000..37d4750
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_file/tests/data/v2/flag_v2.val
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map b/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
new file mode 100644
index 0000000..0a9f95e
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/jarjar.txt b/tools/aconfig/aconfig_storage_file/tests/jarjar.txt
index a6c17fa..24952ec 100644
--- a/tools/aconfig/aconfig_storage_file/tests/jarjar.txt
+++ b/tools/aconfig/aconfig_storage_file/tests/jarjar.txt
@@ -7,6 +7,8 @@
rule android.aconfig.storage.FileType android.aconfig.storage.test.FileType
rule android.aconfig.storage.FlagValueList android.aconfig.storage.test.FlagValueList
rule android.aconfig.storage.TableUtils android.aconfig.storage.test.TableUtils
+rule android.aconfig.storage.AconfigPackageImpl android.aconfig.storage.test.AconfigPackageImpl
+rule android.aconfig.storage.StorageFileProvider android.aconfig.storage.test.StorageFileProvider
rule android.aconfig.storage.FlagTable$* android.aconfig.storage.test.FlagTable$@1
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java
index fd40d4c..dc465b6 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java
@@ -31,7 +31,7 @@
@Test
public void testFlagTable_rightHeader() throws Exception {
- FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer());
+ FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer(1));
FlagTable.Header header = flagTable.getHeader();
assertEquals(1, header.getVersion());
assertEquals("mockup", header.getContainer());
@@ -44,7 +44,7 @@
@Test
public void testFlagTable_rightNode() throws Exception {
- FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer());
+ FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer(1));
FlagTable.Node node1 = flagTable.get(0, "enabled_ro");
FlagTable.Node node2 = flagTable.get(0, "enabled_rw");
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/FlagValueListTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/FlagValueListTest.java
index 1b0de63..306df7d 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/FlagValueListTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/FlagValueListTest.java
@@ -34,7 +34,7 @@
@Test
public void testFlagValueList_rightHeader() throws Exception {
FlagValueList flagValueList =
- FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer());
+ FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer(1));
FlagValueList.Header header = flagValueList.getHeader();
assertEquals(1, header.getVersion());
assertEquals("mockup", header.getContainer());
@@ -47,7 +47,7 @@
@Test
public void testFlagValueList_rightNode() throws Exception {
FlagValueList flagValueList =
- FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer());
+ FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer(1));
boolean[] expected = new boolean[] {false, true, true, false, true, true, true, true};
assertEquals(expected.length, flagValueList.size());
@@ -60,11 +60,11 @@
@Test
public void testFlagValueList_getValue() throws Exception {
PackageTable packageTable =
- PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
- FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer());
+ PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(1));
+ FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer(1));
FlagValueList flagValueList =
- FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer());
+ FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer(1));
PackageTable.Node pNode = packageTable.get("com.android.aconfig.storage.test_1");
FlagTable.Node fNode = flagTable.get(pNode.getPackageId(), "enabled_rw");
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
index dc2ad92..5906d8b 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.aconfig.storage.FileType;
import android.aconfig.storage.PackageTable;
@@ -32,7 +33,7 @@
@Test
public void testPackageTable_rightHeader() throws Exception {
PackageTable packageTable =
- PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
+ PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(1));
PackageTable.Header header = packageTable.getHeader();
assertEquals(1, header.getVersion());
assertEquals("mockup", header.getContainer());
@@ -44,9 +45,23 @@
}
@Test
+ public void testPackageTable_rightHeader_v2() throws Exception {
+ PackageTable packageTable =
+ PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(2));
+ PackageTable.Header header = packageTable.getHeader();
+ assertEquals(2, header.getVersion());
+ assertEquals("mockup", header.getContainer());
+ assertEquals(FileType.PACKAGE_MAP, header.getFileType());
+ assertEquals(233, header.getFileSize());
+ assertEquals(3, header.getNumPackages());
+ assertEquals(31, header.getBucketOffset());
+ assertEquals(59, header.getNodeOffset());
+ }
+
+ @Test
public void testPackageTable_rightNode() throws Exception {
PackageTable packageTable =
- PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
+ PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(1));
PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
PackageTable.Node node2 = packageTable.get("com.android.aconfig.storage.test_2");
@@ -72,4 +87,38 @@
assertFalse(node2.hasPackageFingerprint());
assertFalse(node4.hasPackageFingerprint());
}
+
+ @Test
+ public void testPackageTable_rightNode_v2() throws Exception {
+ PackageTable packageTable =
+ PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(2));
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+ PackageTable.Node node2 = packageTable.get("com.android.aconfig.storage.test_2");
+ PackageTable.Node node4 = packageTable.get("com.android.aconfig.storage.test_4");
+
+ assertEquals("com.android.aconfig.storage.test_1", node1.getPackageName());
+ assertEquals("com.android.aconfig.storage.test_2", node2.getPackageName());
+ assertEquals("com.android.aconfig.storage.test_4", node4.getPackageName());
+
+ assertEquals(0, node1.getPackageId());
+ assertEquals(1, node2.getPackageId());
+ assertEquals(2, node4.getPackageId());
+
+ assertEquals(0, node1.getBooleanStartIndex());
+ assertEquals(3, node2.getBooleanStartIndex());
+ assertEquals(6, node4.getBooleanStartIndex());
+
+ assertEquals(175, node1.getNextOffset());
+ assertEquals(-1, node2.getNextOffset());
+ assertEquals(-1, node4.getNextOffset());
+
+ assertTrue(node1.hasPackageFingerprint());
+ assertTrue(node2.hasPackageFingerprint());
+ assertTrue(node4.hasPackageFingerprint());
+
+ assertEquals(-3197795563119393530L, node1.getPackageFingerprint());
+ assertEquals(4431940502274857964L, node2.getPackageFingerprint());
+ assertEquals(-2213514155997929241L, node4.getPackageFingerprint());
+ }
}
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
new file mode 100644
index 0000000..a820970
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 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.aconfig.storage.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.nio.file.Paths;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class StorageFileProviderTest {
+
+ @Test
+ public void testlistContainers() throws Exception {
+ StorageFileProvider p =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ String[] excludes = {};
+ List<String> containers = p.listContainers(excludes);
+ assertEquals(2, containers.size());
+
+ excludes = new String[] {"mock.v1"};
+ containers = p.listContainers(excludes);
+ assertEquals(1, containers.size());
+
+ p = new StorageFileProvider("fake/path/", "fake/path/");
+ containers = p.listContainers(excludes);
+ assertTrue(containers.isEmpty());
+ }
+
+ @Test
+ public void testLoadFiles() throws Exception {
+ StorageFileProvider p =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ PackageTable pt = p.getPackageTable("mock.v1");
+ assertNotNull(pt);
+ pt =
+ StorageFileProvider.getPackageTable(
+ Paths.get(TestDataUtils.TESTDATA_PATH, "mock.v1.package.map"));
+ assertNotNull(pt);
+ FlagTable f = p.getFlagTable("mock.v1");
+ assertNotNull(f);
+ FlagValueList v = p.getFlagValueList("mock.v1");
+ assertNotNull(v);
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/TestDataUtils.java b/tools/aconfig/aconfig_storage_file/tests/srcs/TestDataUtils.java
index f35952d..388971e 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/TestDataUtils.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/TestDataUtils.java
@@ -21,28 +21,27 @@
import java.nio.ByteBuffer;
public final class TestDataUtils {
- private static final String TEST_PACKAGE_MAP_PATH = "package.map";
- private static final String TEST_FLAG_MAP_PATH = "flag.map";
- private static final String TEST_FLAG_VAL_PATH = "flag.val";
- private static final String TEST_FLAG_INFO_PATH = "flag.info";
+ private static final String TEST_PACKAGE_MAP_PATH = "mock.v%d.package.map";
+ private static final String TEST_FLAG_MAP_PATH = "mock.v%d.flag.map";
+ private static final String TEST_FLAG_VAL_PATH = "mock.v%d.val";
+ private static final String TEST_FLAG_INFO_PATH = "mock.v%d.info";
- private static final String TESTDATA_PATH =
- "/data/local/tmp/aconfig_storage_file_test_java/testdata/";
+ public static final String TESTDATA_PATH = "/data/local/tmp/aconfig_storage_file_test_java/testdata/";
- public static ByteBuffer getTestPackageMapByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_PACKAGE_MAP_PATH);
+ public static ByteBuffer getTestPackageMapByteBuffer(int version) throws Exception {
+ return readFile(TESTDATA_PATH + String.format(TEST_PACKAGE_MAP_PATH, version));
}
- public static ByteBuffer getTestFlagMapByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_MAP_PATH);
+ public static ByteBuffer getTestFlagMapByteBuffer(int version) throws Exception {
+ return readFile(TESTDATA_PATH + String.format(TEST_FLAG_MAP_PATH, version));
}
- public static ByteBuffer getTestFlagValByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_VAL_PATH);
+ public static ByteBuffer getTestFlagValByteBuffer(int version) throws Exception {
+ return readFile(TESTDATA_PATH + String.format(TEST_FLAG_VAL_PATH, version));
}
- public static ByteBuffer getTestFlagInfoByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_INFO_PATH);
+ public static ByteBuffer getTestFlagInfoByteBuffer(int version) throws Exception {
+ return readFile(TESTDATA_PATH + String.format(TEST_FLAG_INFO_PATH, version));
}
private static ByteBuffer readFile(String fileName) throws Exception {
diff --git a/tools/aconfig/aconfig_storage_file/tests/storage_file_test.cpp b/tools/aconfig/aconfig_storage_file/tests/storage_file_test.cpp
index 3626f72..5c008af 100644
--- a/tools/aconfig/aconfig_storage_file/tests/storage_file_test.cpp
+++ b/tools/aconfig/aconfig_storage_file/tests/storage_file_test.cpp
@@ -24,10 +24,8 @@
using namespace android::base;
using namespace aconfig_storage;
-void verify_value(const FlagValueSummary& flag,
- const std::string& package_name,
- const std::string& flag_name,
- const std::string& flag_val,
+void verify_value(const FlagValueSummary& flag, const std::string& package_name,
+ const std::string& flag_name, const std::string& flag_val,
const std::string& value_type) {
ASSERT_EQ(flag.package_name, package_name);
ASSERT_EQ(flag.flag_name, flag_name);
@@ -39,10 +37,8 @@
const std::string& package_name,
const std::string& flag_name,
const std::string& flag_val,
- const std::string& value_type,
- bool is_readwrite,
- bool has_server_override,
- bool has_local_override) {
+ const std::string& value_type, bool is_readwrite,
+ bool has_server_override, bool has_local_override) {
ASSERT_EQ(flag.package_name, package_name);
ASSERT_EQ(flag.flag_name, flag_name);
ASSERT_EQ(flag.flag_value, flag_val);
@@ -52,63 +48,137 @@
ASSERT_EQ(flag.has_local_override, has_local_override);
}
-TEST(AconfigStorageFileTest, test_list_flag) {
+Result<std::vector<FlagValueSummary>> get_flag_list_result(
+ const std::string version) {
auto const test_base_dir = GetExecutableDirectory();
- auto const test_dir = test_base_dir + "/data/v1";
- auto const package_map = test_dir + "/package.map";
- auto const flag_map = test_dir + "/flag.map";
- auto const flag_val = test_dir + "/flag.val";
- auto flag_list_result = aconfig_storage::list_flags(
- package_map, flag_map, flag_val);
+ auto const test_dir = test_base_dir + "/data/v" + version;
+ auto const package_map = test_dir + "/package_v" + version + ".map";
+ auto const flag_map = test_dir + "/flag_v" + version + ".map";
+ auto const flag_val = test_dir + "/flag_v" + version + ".val";
+ return aconfig_storage::list_flags(package_map, flag_map, flag_val);
+}
+
+Result<std::vector<FlagValueAndInfoSummary>> get_flag_list_result_with_info(
+ const std::string version) {
+ auto const test_base_dir = GetExecutableDirectory();
+ auto const test_dir = test_base_dir + "/data/v" + version;
+ auto const package_map = test_dir + "/package_v" + version + ".map";
+ auto const flag_map = test_dir + "/flag_v" + version + ".map";
+ auto const flag_val = test_dir + "/flag_v" + version + ".val";
+ auto const flag_info = test_dir + "/flag_v" + version + ".info";
+ return aconfig_storage::list_flags_with_info(package_map, flag_map, flag_val,
+ flag_info);
+}
+
+TEST(AconfigStorageFileTest, test_list_flag) {
+ auto flag_list_result = get_flag_list_result("1");
ASSERT_TRUE(flag_list_result.ok());
auto const& flag_list = *flag_list_result;
ASSERT_EQ(flag_list.size(), 8);
- verify_value(flag_list[0], "com.android.aconfig.storage.test_1", "disabled_rw",
- "false", "ReadWriteBoolean");
+ verify_value(flag_list[0], "com.android.aconfig.storage.test_1",
+ "disabled_rw", "false", "ReadWriteBoolean");
verify_value(flag_list[1], "com.android.aconfig.storage.test_1", "enabled_ro",
"true", "ReadOnlyBoolean");
verify_value(flag_list[2], "com.android.aconfig.storage.test_1", "enabled_rw",
"true", "ReadWriteBoolean");
- verify_value(flag_list[3], "com.android.aconfig.storage.test_2", "disabled_rw",
- "false", "ReadWriteBoolean");
- verify_value(flag_list[4], "com.android.aconfig.storage.test_2", "enabled_fixed_ro",
- "true", "FixedReadOnlyBoolean");
+ verify_value(flag_list[3], "com.android.aconfig.storage.test_2",
+ "disabled_rw", "false", "ReadWriteBoolean");
+ verify_value(flag_list[4], "com.android.aconfig.storage.test_2",
+ "enabled_fixed_ro", "true", "FixedReadOnlyBoolean");
verify_value(flag_list[5], "com.android.aconfig.storage.test_2", "enabled_ro",
"true", "ReadOnlyBoolean");
- verify_value(flag_list[6], "com.android.aconfig.storage.test_4", "enabled_fixed_ro",
- "true", "FixedReadOnlyBoolean");
+ verify_value(flag_list[6], "com.android.aconfig.storage.test_4",
+ "enabled_fixed_ro", "true", "FixedReadOnlyBoolean");
+ verify_value(flag_list[7], "com.android.aconfig.storage.test_4", "enabled_rw",
+ "true", "ReadWriteBoolean");
+}
+
+// TODO: b/376256472 - Use parameterized tests.
+TEST(AconfigStorageFileTest, test_list_flag_v2) {
+ auto flag_list_result = get_flag_list_result("2");
+ ASSERT_TRUE(flag_list_result.ok());
+
+ auto const& flag_list = *flag_list_result;
+ ASSERT_EQ(flag_list.size(), 8);
+ verify_value(flag_list[0], "com.android.aconfig.storage.test_1",
+ "disabled_rw", "false", "ReadWriteBoolean");
+ verify_value(flag_list[1], "com.android.aconfig.storage.test_1", "enabled_ro",
+ "true", "ReadOnlyBoolean");
+ verify_value(flag_list[2], "com.android.aconfig.storage.test_1", "enabled_rw",
+ "true", "ReadWriteBoolean");
+ verify_value(flag_list[3], "com.android.aconfig.storage.test_2",
+ "disabled_rw", "false", "ReadWriteBoolean");
+ verify_value(flag_list[4], "com.android.aconfig.storage.test_2",
+ "enabled_fixed_ro", "true", "FixedReadOnlyBoolean");
+ verify_value(flag_list[5], "com.android.aconfig.storage.test_2", "enabled_ro",
+ "true", "ReadOnlyBoolean");
+ verify_value(flag_list[6], "com.android.aconfig.storage.test_4",
+ "enabled_fixed_ro", "true", "FixedReadOnlyBoolean");
verify_value(flag_list[7], "com.android.aconfig.storage.test_4", "enabled_rw",
"true", "ReadWriteBoolean");
}
TEST(AconfigStorageFileTest, test_list_flag_with_info) {
- auto const base_test_dir = GetExecutableDirectory();
- auto const test_dir = base_test_dir + "/data/v1";
- auto const package_map = test_dir + "/package.map";
- auto const flag_map = test_dir + "/flag.map";
- auto const flag_val = test_dir + "/flag.val";
- auto const flag_info = test_dir + "/flag.info";
- auto flag_list_result = aconfig_storage::list_flags_with_info(
- package_map, flag_map, flag_val, flag_info);
+ auto flag_list_result = get_flag_list_result_with_info("1");
ASSERT_TRUE(flag_list_result.ok());
auto const& flag_list = *flag_list_result;
ASSERT_EQ(flag_list.size(), 8);
- verify_value_info(flag_list[0], "com.android.aconfig.storage.test_1", "disabled_rw",
- "false", "ReadWriteBoolean", true, false, false);
- verify_value_info(flag_list[1], "com.android.aconfig.storage.test_1", "enabled_ro",
- "true", "ReadOnlyBoolean", false, false, false);
- verify_value_info(flag_list[2], "com.android.aconfig.storage.test_1", "enabled_rw",
- "true", "ReadWriteBoolean", true, false, false);
- verify_value_info(flag_list[3], "com.android.aconfig.storage.test_2", "disabled_rw",
- "false", "ReadWriteBoolean", true, false, false);
- verify_value_info(flag_list[4], "com.android.aconfig.storage.test_2", "enabled_fixed_ro",
- "true", "FixedReadOnlyBoolean", false, false, false);
- verify_value_info(flag_list[5], "com.android.aconfig.storage.test_2", "enabled_ro",
- "true", "ReadOnlyBoolean", false, false, false);
- verify_value_info(flag_list[6], "com.android.aconfig.storage.test_4", "enabled_fixed_ro",
- "true", "FixedReadOnlyBoolean", false, false, false);
- verify_value_info(flag_list[7], "com.android.aconfig.storage.test_4", "enabled_rw",
- "true", "ReadWriteBoolean", true, false, false);
+ verify_value_info(flag_list[0], "com.android.aconfig.storage.test_1",
+ "disabled_rw", "false", "ReadWriteBoolean", true, false,
+ false);
+ verify_value_info(flag_list[1], "com.android.aconfig.storage.test_1",
+ "enabled_ro", "true", "ReadOnlyBoolean", false, false,
+ false);
+ verify_value_info(flag_list[2], "com.android.aconfig.storage.test_1",
+ "enabled_rw", "true", "ReadWriteBoolean", true, false,
+ false);
+ verify_value_info(flag_list[3], "com.android.aconfig.storage.test_2",
+ "disabled_rw", "false", "ReadWriteBoolean", true, false,
+ false);
+ verify_value_info(flag_list[4], "com.android.aconfig.storage.test_2",
+ "enabled_fixed_ro", "true", "FixedReadOnlyBoolean", false,
+ false, false);
+ verify_value_info(flag_list[5], "com.android.aconfig.storage.test_2",
+ "enabled_ro", "true", "ReadOnlyBoolean", false, false,
+ false);
+ verify_value_info(flag_list[6], "com.android.aconfig.storage.test_4",
+ "enabled_fixed_ro", "true", "FixedReadOnlyBoolean", false,
+ false, false);
+ verify_value_info(flag_list[7], "com.android.aconfig.storage.test_4",
+ "enabled_rw", "true", "ReadWriteBoolean", true, false,
+ false);
+}
+
+TEST(AconfigStorageFileTest, test_list_flag_with_info_v2) {
+ auto flag_list_result = get_flag_list_result_with_info("2");
+ ASSERT_TRUE(flag_list_result.ok());
+
+ auto const& flag_list = *flag_list_result;
+ ASSERT_EQ(flag_list.size(), 8);
+ verify_value_info(flag_list[0], "com.android.aconfig.storage.test_1",
+ "disabled_rw", "false", "ReadWriteBoolean", true, false,
+ false);
+ verify_value_info(flag_list[1], "com.android.aconfig.storage.test_1",
+ "enabled_ro", "true", "ReadOnlyBoolean", false, false,
+ false);
+ verify_value_info(flag_list[2], "com.android.aconfig.storage.test_1",
+ "enabled_rw", "true", "ReadWriteBoolean", true, false,
+ false);
+ verify_value_info(flag_list[3], "com.android.aconfig.storage.test_2",
+ "disabled_rw", "false", "ReadWriteBoolean", true, false,
+ false);
+ verify_value_info(flag_list[4], "com.android.aconfig.storage.test_2",
+ "enabled_fixed_ro", "true", "FixedReadOnlyBoolean", false,
+ false, false);
+ verify_value_info(flag_list[5], "com.android.aconfig.storage.test_2",
+ "enabled_ro", "true", "ReadOnlyBoolean", false, false,
+ false);
+ verify_value_info(flag_list[6], "com.android.aconfig.storage.test_4",
+ "enabled_fixed_ro", "true", "FixedReadOnlyBoolean", false,
+ false, false);
+ verify_value_info(flag_list[7], "com.android.aconfig.storage.test_4",
+ "enabled_rw", "true", "ReadWriteBoolean", true, false,
+ false);
}
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 666c5ba..6214e2c 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -36,10 +36,10 @@
"librand",
],
data: [
- "tests/data/v1/package.map",
- "tests/data/v1/flag.map",
- "tests/data/v1/flag.val",
- "tests/data/v1/flag.info",
+ "tests/data/v1/package_v1.map",
+ "tests/data/v1/flag_v1.map",
+ "tests/data/v1/flag_v1.val",
+ "tests/data/v1/flag_v1.info",
],
}
@@ -154,41 +154,21 @@
java_library {
name: "aconfig_storage_reader_java",
srcs: [
- "srcs/android/aconfig/storage/AconfigPackageImpl.java",
- "srcs/android/aconfig/storage/StorageFileProvider.java",
"srcs/android/aconfig/storage/StorageInternalReader.java",
+ "srcs/android/os/flagging/PlatformAconfigPackageInternal.java",
],
libs: [
"unsupportedappusage",
"strict_mode_stub",
+ "aconfig_storage_stub",
],
static_libs: [
"aconfig_storage_file_java",
],
sdk_version: "core_current",
host_supported: true,
- min_sdk_version: "29",
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
+ visibility: [
+ "//frameworks/base",
+ "//build/make/tools/aconfig/aconfig_storage_read_api/tests",
],
}
-
-java_library {
- name: "aconfig_storage_reader_java_none",
- srcs: [
- "srcs/android/aconfig/storage/AconfigPackageImpl.java",
- "srcs/android/aconfig/storage/StorageFileProvider.java",
- "srcs/android/aconfig/storage/StorageInternalReader.java",
- ],
- libs: [
- "unsupportedappusage-sdk-none",
- "fake_device_config",
- ],
- static_libs: [
- "aconfig_storage_file_java_none",
- ],
- sdk_version: "none",
- system_modules: "core-all-system-modules",
- host_supported: true,
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
index fe57a6d..68b6193 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
@@ -55,12 +55,14 @@
#[cfg(test)]
mod tests {
use super::*;
- use aconfig_storage_file::{test_utils::create_test_flag_info_list, FlagInfoBit};
+ use aconfig_storage_file::{
+ test_utils::create_test_flag_info_list, FlagInfoBit, DEFAULT_FILE_VERSION,
+ };
#[test]
// this test point locks down query if flag has server override
fn test_is_flag_sticky() {
- let flag_info_list = create_test_flag_info_list().into_bytes();
+ let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes();
for offset in 0..8 {
let attribute =
find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, offset).unwrap();
@@ -71,7 +73,7 @@
#[test]
// this test point locks down query if flag is readwrite
fn test_is_flag_readwrite() {
- let flag_info_list = create_test_flag_info_list().into_bytes();
+ let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes();
let baseline: Vec<bool> = vec![true, false, true, true, false, false, false, true];
for offset in 0..8 {
let attribute =
@@ -86,7 +88,7 @@
#[test]
// this test point locks down query if flag has local override
fn test_flag_has_override() {
- let flag_info_list = create_test_flag_info_list().into_bytes();
+ let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes();
for offset in 0..8 {
let attribute =
find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, offset).unwrap();
@@ -97,7 +99,7 @@
#[test]
// this test point locks down query beyond the end of boolean section
fn test_boolean_out_of_range() {
- let flag_info_list = create_test_flag_info_list().into_bytes();
+ let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION).into_bytes();
let error =
find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, 8).unwrap_err();
assert_eq!(
@@ -109,7 +111,7 @@
#[test]
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
- let mut info_list = create_test_flag_info_list();
+ let mut info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
info_list.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let flag_info = info_list.into_bytes();
let error = find_flag_attribute(&flag_info[..], FlagValueType::Boolean, 4).unwrap_err();
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
index e9bc604..3e87acc 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
@@ -74,12 +74,12 @@
#[cfg(test)]
mod tests {
use super::*;
- use aconfig_storage_file::test_utils::create_test_flag_table;
+ use aconfig_storage_file::{test_utils::create_test_flag_table, DEFAULT_FILE_VERSION};
#[test]
// this test point locks down table query
fn test_flag_query() {
- let flag_table = create_test_flag_table().into_bytes();
+ let flag_table = create_test_flag_table(DEFAULT_FILE_VERSION).into_bytes();
let baseline = vec![
(0, "enabled_ro", StoredFlagType::ReadOnlyBoolean, 1u16),
(0, "enabled_rw", StoredFlagType::ReadWriteBoolean, 2u16),
@@ -101,7 +101,7 @@
#[test]
// this test point locks down table query of a non exist flag
fn test_not_existed_flag_query() {
- let flag_table = create_test_flag_table().into_bytes();
+ let flag_table = create_test_flag_table(DEFAULT_FILE_VERSION).into_bytes();
let flag_context = find_flag_read_context(&flag_table[..], 1, "disabled_fixed_ro").unwrap();
assert_eq!(flag_context, None);
let flag_context = find_flag_read_context(&flag_table[..], 2, "disabled_rw").unwrap();
@@ -111,7 +111,7 @@
#[test]
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
- let mut table = create_test_flag_table();
+ let mut table = create_test_flag_table(DEFAULT_FILE_VERSION);
table.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let flag_table = table.into_bytes();
let error = find_flag_read_context(&flag_table[..], 0, "enabled_ro").unwrap_err();
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
index 12c1e83..35f5692 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
@@ -48,12 +48,12 @@
#[cfg(test)]
mod tests {
use super::*;
- use aconfig_storage_file::test_utils::create_test_flag_value_list;
+ use aconfig_storage_file::{test_utils::create_test_flag_value_list, DEFAULT_FILE_VERSION};
#[test]
// this test point locks down flag value query
fn test_flag_value_query() {
- let flag_value_list = create_test_flag_value_list().into_bytes();
+ let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION).into_bytes();
let baseline: Vec<bool> = vec![false, true, true, false, true, true, true, true];
for (offset, expected_value) in baseline.into_iter().enumerate() {
let flag_value = find_boolean_flag_value(&flag_value_list[..], offset as u32).unwrap();
@@ -64,7 +64,7 @@
#[test]
// this test point locks down query beyond the end of boolean section
fn test_boolean_out_of_range() {
- let flag_value_list = create_test_flag_value_list().into_bytes();
+ let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION).into_bytes();
let error = find_boolean_flag_value(&flag_value_list[..], 8).unwrap_err();
assert_eq!(
format!("{:?}", error),
@@ -75,7 +75,7 @@
#[test]
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
- let mut value_list = create_test_flag_value_list();
+ let mut value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
value_list.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let flag_value = value_list.into_bytes();
let error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
diff --git a/tools/aconfig/aconfig_storage_read_api/src/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
index 5104cd0..d3cc9d4 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
@@ -413,10 +413,10 @@
let flag_map = storage_dir.clone() + "/maps/mockup.flag.map";
let flag_val = storage_dir.clone() + "/boot/mockup.val";
let flag_info = storage_dir.clone() + "/boot/mockup.info";
- fs::copy("./tests/data/v1/package.map", &package_map).unwrap();
- fs::copy("./tests/data/v1/flag.map", &flag_map).unwrap();
- fs::copy("./tests/data/v1/flag.val", &flag_val).unwrap();
- fs::copy("./tests/data/v1/flag.info", &flag_info).unwrap();
+ fs::copy("./tests/data/v1/package_v1.map", &package_map).unwrap();
+ fs::copy("./tests/data/v1/flag_v1.map", &flag_map).unwrap();
+ fs::copy("./tests/data/v1/flag_v1.val", &flag_val).unwrap();
+ fs::copy("./tests/data/v1/flag_v1.info", &flag_info).unwrap();
return storage_dir;
}
@@ -433,21 +433,24 @@
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
+ let expected_package_context =
+ PackageReadContext { package_id: 0, boolean_start_index: 0, fingerprint: 0 };
assert_eq!(package_context, expected_package_context);
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
+ let expected_package_context =
+ PackageReadContext { package_id: 1, boolean_start_index: 3, fingerprint: 0 };
assert_eq!(package_context, expected_package_context);
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
+ let expected_package_context =
+ PackageReadContext { package_id: 2, boolean_start_index: 6, fingerprint: 0 };
assert_eq!(package_context, expected_package_context);
}
@@ -508,9 +511,9 @@
#[test]
// this test point locks down flag storage file version number query api
fn test_storage_version_query() {
- assert_eq!(get_storage_file_version("./tests/data/v1/package.map").unwrap(), 1);
- assert_eq!(get_storage_file_version("./tests/data/v1/flag.map").unwrap(), 1);
- assert_eq!(get_storage_file_version("./tests/data/v1/flag.val").unwrap(), 1);
- assert_eq!(get_storage_file_version("./tests/data/v1/flag.info").unwrap(), 1);
+ assert_eq!(get_storage_file_version("./tests/data/v1/package_v1.map").unwrap(), 1);
+ assert_eq!(get_storage_file_version("./tests/data/v1/flag_v1.map").unwrap(), 1);
+ assert_eq!(get_storage_file_version("./tests/data/v1/flag_v1.val").unwrap(), 1);
+ assert_eq!(get_storage_file_version("./tests/data/v1/flag_v1.info").unwrap(), 1);
}
}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
index 2c1884a..f4e269e 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
@@ -97,10 +97,10 @@
let flag_map = storage_dir.clone() + "/maps/mockup.flag.map";
let flag_val = storage_dir.clone() + "/boot/mockup.val";
let flag_info = storage_dir.clone() + "/boot/mockup.info";
- fs::copy("./tests/data/v1/package.map", &package_map).unwrap();
- fs::copy("./tests/data/v1/flag.map", &flag_map).unwrap();
- fs::copy("./tests/data/v1/flag.val", &flag_val).unwrap();
- fs::copy("./tests/data/v1/flag.info", &flag_info).unwrap();
+ fs::copy("./tests/data/v1/package_v1.map", &package_map).unwrap();
+ fs::copy("./tests/data/v1/flag_v1.map", &flag_map).unwrap();
+ fs::copy("./tests/data/v1/flag_v1.val", &flag_val).unwrap();
+ fs::copy("./tests/data/v1/flag_v1.info", &flag_info).unwrap();
return storage_dir;
}
@@ -108,9 +108,9 @@
#[test]
fn test_mapped_file_contents() {
let storage_dir = create_test_storage_files();
- map_and_verify(&storage_dir, StorageFileType::PackageMap, "./tests/data/v1/package.map");
- map_and_verify(&storage_dir, StorageFileType::FlagMap, "./tests/data/v1/flag.map");
- map_and_verify(&storage_dir, StorageFileType::FlagVal, "./tests/data/v1/flag.val");
- map_and_verify(&storage_dir, StorageFileType::FlagInfo, "./tests/data/v1/flag.info");
+ map_and_verify(&storage_dir, StorageFileType::PackageMap, "./tests/data/v1/package_v1.map");
+ map_and_verify(&storage_dir, StorageFileType::FlagMap, "./tests/data/v1/flag_v1.map");
+ map_and_verify(&storage_dir, StorageFileType::FlagVal, "./tests/data/v1/flag_v1.val");
+ map_and_verify(&storage_dir, StorageFileType::FlagInfo, "./tests/data/v1/flag_v1.info");
}
}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
index acb60f6..b20668f 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
@@ -28,6 +28,7 @@
pub struct PackageReadContext {
pub package_id: u32,
pub boolean_start_index: u32,
+ pub fingerprint: u64,
}
/// Query package read context: package id and start index
@@ -62,6 +63,7 @@
return Ok(Some(PackageReadContext {
package_id: interpreted_node.package_id,
boolean_start_index: interpreted_node.boolean_start_index,
+ fingerprint: interpreted_node.fingerprint,
}));
}
match interpreted_node.next_offset {
@@ -74,29 +76,68 @@
#[cfg(test)]
mod tests {
use super::*;
- use aconfig_storage_file::test_utils::create_test_package_table;
+ use aconfig_storage_file::{test_utils::create_test_package_table, DEFAULT_FILE_VERSION};
#[test]
// this test point locks down table query
fn test_package_query() {
- let package_table = create_test_package_table().into_bytes();
+ let package_table = create_test_package_table(DEFAULT_FILE_VERSION).into_bytes();
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
+ let expected_package_context =
+ PackageReadContext { package_id: 0, boolean_start_index: 0, fingerprint: 0 };
assert_eq!(package_context, expected_package_context);
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_2")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
+ let expected_package_context =
+ PackageReadContext { package_id: 1, boolean_start_index: 3, fingerprint: 0 };
assert_eq!(package_context, expected_package_context);
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_4")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
+ let expected_package_context =
+ PackageReadContext { package_id: 2, boolean_start_index: 6, fingerprint: 0 };
+ assert_eq!(package_context, expected_package_context);
+ }
+
+ #[test]
+ // this test point locks down table query
+ fn test_package_query_v2() {
+ let package_table = create_test_package_table(2).into_bytes();
+ let package_context =
+ find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
+ .unwrap()
+ .unwrap();
+ let expected_package_context = PackageReadContext {
+ package_id: 0,
+ boolean_start_index: 0,
+ fingerprint: 15248948510590158086u64,
+ };
+ assert_eq!(package_context, expected_package_context);
+ let package_context =
+ find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_2")
+ .unwrap()
+ .unwrap();
+ let expected_package_context = PackageReadContext {
+ package_id: 1,
+ boolean_start_index: 3,
+ fingerprint: 4431940502274857964u64,
+ };
+ assert_eq!(package_context, expected_package_context);
+ let package_context =
+ find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_4")
+ .unwrap()
+ .unwrap();
+ let expected_package_context = PackageReadContext {
+ package_id: 2,
+ boolean_start_index: 6,
+ fingerprint: 16233229917711622375u64,
+ };
assert_eq!(package_context, expected_package_context);
}
@@ -104,7 +145,7 @@
// this test point locks down table query of a non exist package
fn test_not_existed_package_query() {
// this will land at an empty bucket
- let package_table = create_test_package_table().into_bytes();
+ let package_table = create_test_package_table(DEFAULT_FILE_VERSION).into_bytes();
let package_context =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_3")
.unwrap();
@@ -119,7 +160,7 @@
#[test]
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
- let mut table = create_test_package_table();
+ let mut table = create_test_package_table(DEFAULT_FILE_VERSION);
table.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let package_table = table.into_bytes();
let error =
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
deleted file mode 100644
index c2bef31..0000000
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2024 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.aconfig.storage;
-
-import android.os.StrictMode;
-
-import java.nio.file.Path;
-
-/** @hide */
-public class AconfigPackageImpl {
- private FlagTable mFlagTable;
- private FlagValueList mFlagValueList;
- private PackageTable.Node mPNode;
-
- /** @hide */
- private AconfigPackageImpl() {}
-
- /** @hide */
- public static AconfigPackageImpl load(String packageName, StorageFileProvider fileProvider) {
- AconfigPackageImpl impl = new AconfigPackageImpl();
- impl.init(null, packageName, fileProvider);
- return impl;
- }
-
- /** @hide */
- public static AconfigPackageImpl load(
- String container, String packageName, StorageFileProvider fileProvider) {
- if (container == null) {
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_CONTAINER_NOT_FOUND,
- "container null cannot be found on the device");
- }
- AconfigPackageImpl impl = new AconfigPackageImpl();
- impl.init(container, packageName, fileProvider);
- return impl;
- }
-
- /** @hide */
- public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
- FlagTable.Node fNode = mFlagTable.get(mPNode.getPackageId(), flagName);
- // no such flag in this package
- if (fNode == null) return defaultValue;
- int index = fNode.getFlagIndex() + mPNode.getBooleanStartIndex();
- return mFlagValueList.getBoolean(index);
- }
-
- /** @hide */
- public boolean getBooleanFlagValue(int index) {
- return mFlagValueList.getBoolean(index + mPNode.getBooleanStartIndex());
- }
-
- /** @hide */
- public long getPackageFingerprint() {
- return mPNode.getPackageFingerprint();
- }
-
- /** @hide */
- public boolean hasPackageFingerprint() {
- return mPNode.hasPackageFingerprint();
- }
-
- private void init(String containerName, String packageName, StorageFileProvider fileProvider) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- String container = containerName;
- try {
- // for devices don't have new storage directly return
- if (!fileProvider.containerFileExists(null)) {
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_STORAGE_SYSTEM_NOT_FOUND,
- "aconfig storage cannot be found on the device");
- }
- PackageTable.Node pNode = null;
-
- if (container == null) {
- // Check if the device has flag files on the system partition.
- // If the device does, search the system partition first.
- container = "system";
- if (fileProvider.containerFileExists(container)) {
- pNode = fileProvider.getPackageTable(container).get(packageName);
- }
-
- if (pNode == null) {
- // Search all package map files if not found in the system partition.
- for (Path p : fileProvider.listPackageMapFiles()) {
- PackageTable pTable = StorageFileProvider.getPackageTable(p);
- pNode = pTable.get(packageName);
- if (pNode != null) {
- container = pTable.getHeader().getContainer();
- break;
- }
- }
- }
- } else {
- if (!fileProvider.containerFileExists(container)) {
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_CONTAINER_NOT_FOUND,
- "container " + container + " cannot be found on the device");
- }
- pNode = fileProvider.getPackageTable(container).get(packageName);
- }
-
- if (pNode == null) {
- // for the case package is not found in all container, return instead of throwing
- // error
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
- "package "
- + packageName
- + " in container "
- + container
- + " cannot be found on the device");
- }
-
- mFlagTable = fileProvider.getFlagTable(container);
- mFlagValueList = fileProvider.getFlagValueList(container);
- mPNode = pNode;
- } catch (Exception e) {
- throw e;
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
new file mode 100644
index 0000000..e6b6db4
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2024 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.os.flagging;
+
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.StrictMode;
+
+/**
+ * An {@code aconfig} package containing the enabled state of its flags.
+ *
+ * <p><strong>Note: this is intended only to be used by generated code. To determine if a given flag
+ * is enabled in app code, the generated android flags should be used.</strong>
+ *
+ * <p>This class is not part of the public API and should be used by Acnofig Flag internally </b> It
+ * is intended for internal use only and will be changed or removed without notice.
+ *
+ * <p>This class is used to read the flag from Aconfig Package.Each instance of this class will
+ * cache information related to one package. To read flags from a different package, a new instance
+ * of this class should be {@link #load loaded}.
+ *
+ * @hide
+ */
+public class PlatformAconfigPackageInternal {
+
+ private final FlagTable mFlagTable;
+ private final FlagValueList mFlagValueList;
+ private final int mPackageId;
+ private final int mPackageBooleanStartOffset;
+ private final AconfigStorageReadException mException;
+
+ private PlatformAconfigPackageInternal(
+ FlagValueList flagValueList,
+ FlagTable flagTable,
+ int packageBooleanStartOffset,
+ int packageId,
+ AconfigStorageReadException exception) {
+ this.mFlagValueList = flagValueList;
+ this.mFlagTable = flagTable;
+ this.mPackageBooleanStartOffset = packageBooleanStartOffset;
+ this.mPackageId = packageId;
+ this.mException = exception;
+ }
+
+ /**
+ * Loads an Aconfig Package from platform Aconfig Storage.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method loads the specified Aconfig Package from the given container.
+ *
+ * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
+ * The specific error code can be got using {@link #getException()}.
+ *
+ * @param container The name of the container.
+ * @param packageName The name of the Aconfig package to load.
+ * @return An instance of {@link PlatformAconfigPackageInternal}
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static PlatformAconfigPackageInternal load(String container, String packageName) {
+ return load(container, packageName, StorageFileProvider.getDefaultProvider());
+ }
+
+ /** @hide */
+ public static PlatformAconfigPackageInternal load(
+ String container, String packageName, StorageFileProvider fileProvider) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
+
+ if (pNode == null) {
+ return createExceptionInstance(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ "package "
+ + packageName
+ + " in container "
+ + container
+ + " cannot be found on the device");
+ }
+
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ fileProvider.getFlagTable(container),
+ pNode.getBooleanStartIndex(),
+ pNode.getPackageId(),
+ null);
+
+ } catch (AconfigStorageException e) {
+ return createExceptionInstance(e.getErrorCode(), e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ /**
+ * Loads an Aconfig package from the specified container and verifies its fingerprint.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
+ * The specific error code can be got using {@link #getException()}.
+ *
+ * @param container The name of the container.
+ * @param packageName The name of the Aconfig package.
+ * @param packageFingerprint The expected fingerprint of the package.
+ * @return An instance of {@link PlatformAconfigPackageInternal} representing the loaded
+ * package.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static PlatformAconfigPackageInternal load(
+ String container, String packageName, long packageFingerprint) {
+ return load(
+ container,
+ packageName,
+ packageFingerprint,
+ StorageFileProvider.getDefaultProvider());
+ }
+
+ /** @hide */
+ public static PlatformAconfigPackageInternal load(
+ String container,
+ String packageName,
+ long packageFingerprint,
+ StorageFileProvider fileProvider) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
+
+ if (pNode == null) {
+ return createExceptionInstance(
+ AconfigStorageReadException.ERROR_PACKAGE_NOT_FOUND,
+ "package "
+ + packageName
+ + " in container "
+ + container
+ + " cannot be found on the device");
+ }
+
+ if (pNode.hasPackageFingerprint()
+ && packageFingerprint != pNode.getPackageFingerprint()) {
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ fileProvider.getFlagTable(container),
+ pNode.getBooleanStartIndex(),
+ pNode.getPackageId(),
+ new AconfigStorageReadException(
+ AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ "The fingerprint provided for the Aconfig package "
+ + packageName
+ + " in container "
+ + container
+ + " does not match"
+ + " the fingerprint of the package found on the device."));
+ }
+
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ null,
+ pNode.getBooleanStartIndex(),
+ 0,
+ null);
+
+ } catch (AconfigStorageException e) {
+ return createExceptionInstance(e.getErrorCode(), e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ /**
+ * Retrieves the value of a boolean flag using its index.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
+ * index. The index is generated at build time and may vary between builds.
+ *
+ * <p>To ensure you are using the correct index, verify that the package's fingerprint matches
+ * the expected fingerprint before calling this method. If the fingerprints do not match, use
+ * {@link #getBooleanFlagValue(String, boolean)} instead.
+ *
+ * @param index The index of the flag within the package.
+ * @return The boolean value of the flag.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public boolean getBooleanFlagValue(int index) {
+ return mFlagValueList.getBoolean(index + mPackageBooleanStartOffset);
+ }
+
+ /**
+ * Retrieves the value of a boolean flag using its name.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
+ * name.
+ *
+ * @param flagName The name of the flag.
+ * @param defaultValue The default value to return if the flag is not found.
+ * @return The boolean value of the flag.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
+ if (fNode == null) {
+ return defaultValue;
+ }
+ return mFlagValueList.getBoolean(fNode.getFlagIndex() + mPackageBooleanStartOffset);
+ }
+
+ /**
+ * Returns any exception that occurred during the loading of the Aconfig package.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * @return The exception that occurred, or {@code null} if no exception occurred.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public AconfigStorageReadException getException() {
+ return mException;
+ }
+
+ /**
+ * Creates a new {@link PlatformAconfigPackageInternal} instance with an {@link
+ * AconfigStorageException}.
+ *
+ * @param errorCode The error code for the exception.
+ * @param message The error message for the exception.
+ * @return A new {@link PlatformAconfigPackageInternal} instance with the specified exception.
+ */
+ private static PlatformAconfigPackageInternal createExceptionInstance(
+ int errorCode, String message) {
+ return new PlatformAconfigPackageInternal(
+ null, null, 0, 0, new AconfigStorageReadException(errorCode, message));
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
similarity index 89%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
index 99c9e25..ee50060 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
@@ -26,7 +26,7 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="aconfig_storage_read_api.test.java.apk" />
+ <option name="test-file-name" value="aconfig_storage_read_functional.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer" />
@@ -35,17 +35,17 @@
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="abort-on-push-failure" value="true" />
- <option name="push-file" key="package.map"
+ <option name="push-file" key="package_v1.map"
value="/data/local/tmp/aconfig_java_api_test/maps/mockup.package.map" />
- <option name="push-file" key="flag.map"
+ <option name="push-file" key="flag_v1.map"
value="/data/local/tmp/aconfig_java_api_test/maps/mockup.flag.map" />
- <option name="push-file" key="flag.val"
+ <option name="push-file" key="flag_v1.val"
value="/data/local/tmp/aconfig_java_api_test/boot/mockup.val" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <option name="package" value="android.aconfig_storage.test" />
+ <option name="package" value="android.aconfig.storage.test" />
<option name="runtime-hint" value="1m" />
</test>
-</configuration>
+</configuration>
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
similarity index 68%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
index 3d5bb8e..e528dd5 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
@@ -17,18 +17,18 @@
<configuration description="Test aconfig storage java tests">
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="aconfig_storage_package.apk" />
+ <option name="test-file-name" value="aconfig_storage_read_unit.apk" />
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
- <option name="push" value="package.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.package.map" />
- <option name="push" value="flag.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.flag.map" />
- <option name="push" value="flag.val->/data/local/tmp/aconfig_storage_package/testdata/mockup.val" />
- <option name="push" value="flag.info->/data/local/tmp/aconfig_storage_package/testdata/mockup.info" />
- <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_package/testdata/" />
+ <option name="push" value="package_v2.map->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.package.map" />
+ <option name="push" value="flag_v2.map->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.flag.map" />
+ <option name="push" value="flag_v2.val->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.val" />
+ <option name="push" value="flag_v2.info->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.info" />
+ <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_read_unit/testdata/" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.aconfig.storage.test" />
<option name="runtime-hint" value="1m" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
index b8e510d..702325d 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
@@ -1,10 +1,14 @@
filegroup {
name: "read_api_test_storage_files",
srcs: [
- "data/v1/package.map",
- "data/v1/flag.map",
- "data/v1/flag.val",
- "data/v1/flag.info",
+ "data/v1/package_v1.map",
+ "data/v1/flag_v1.map",
+ "data/v1/flag_v1.val",
+ "data/v1/flag_v1.info",
+ "data/v2/package_v2.map",
+ "data/v2/flag_v2.map",
+ "data/v2/flag_v2.val",
+ "data/v2/flag_v2.info",
],
}
@@ -44,3 +48,52 @@
"general-tests",
],
}
+
+android_test {
+ name: "aconfig_storage_read_functional",
+ srcs: [
+ "functional/srcs/**/*.java",
+ ],
+ static_libs: [
+ "aconfig_device_paths_java",
+ "aconfig_storage_file_java",
+ "androidx.test.rules",
+ "libaconfig_storage_read_api_java",
+ "junit",
+ ],
+ jni_libs: [
+ "libaconfig_storage_read_api_rust_jni",
+ ],
+ data: [
+ ":read_api_test_storage_files",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: [
+ "general-tests",
+ ],
+ test_config: "AconfigStorageReadFunctionalTest.xml",
+ team: "trendy_team_android_core_experiments",
+}
+
+android_test {
+ name: "aconfig_storage_read_unit",
+ team: "trendy_team_android_core_experiments",
+ srcs: [
+ "unit/srcs/**/*.java",
+ ],
+ static_libs: [
+ "androidx.test.runner",
+ "junit",
+ "aconfig_storage_reader_java",
+ ],
+ sdk_version: "test_current",
+ data: [
+ ":read_api_test_storage_files",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ test_config: "AconfigStorageReadUnitTest.xml",
+ jarjar_rules: "jarjar.txt",
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AndroidManifest.xml
similarity index 100%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AndroidManifest.xml
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag.info b/tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag_v1.info
similarity index 100%
rename from tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag.info
rename to tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag_v1.info
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag.map b/tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag_v1.map
similarity index 100%
rename from tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag.map
rename to tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag_v1.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag.val b/tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag_v1.val
similarity index 100%
rename from tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag.val
rename to tools/aconfig/aconfig_storage_read_api/tests/data/v1/flag_v1.val
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v1/package.map b/tools/aconfig/aconfig_storage_read_api/tests/data/v1/package_v1.map
similarity index 100%
rename from tools/aconfig/aconfig_storage_read_api/tests/data/v1/package.map
rename to tools/aconfig/aconfig_storage_read_api/tests/data/v1/package_v1.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.info b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.info
new file mode 100644
index 0000000..9db7fde
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.info
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.map b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.map
new file mode 100644
index 0000000..cf4685c
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.val b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.val
new file mode 100644
index 0000000..37d4750
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/flag_v2.val
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
new file mode 100644
index 0000000..0a9f95e
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
similarity index 99%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
rename to tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
index 191741e..6dd1bce 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
@@ -267,4 +267,4 @@
assertEquals(rVal, jVal);
}
}
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
new file mode 100644
index 0000000..c4a5560
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2024 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.aconfig.storage.test;
+
+import static android.aconfig.nano.Aconfig.ENABLED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.aconfig.DeviceProtos;
+import android.aconfig.nano.Aconfig.parsed_flag;
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.PlatformAconfigPackageInternal;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(JUnit4.class)
+public class PlatformAconfigPackageInternalTest {
+
+ private static final Set<String> PLATFORM_CONTAINERS = Set.of("system", "vendor", "product");
+
+ @Test
+ public void testAconfigPackageInternal_load() throws IOException {
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ for (parsed_flag flag : flags) {
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ String flagName = flag.name;
+ if (!PLATFORM_CONTAINERS.contains(container)) continue;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+ FlagTable fTable = fp.getFlagTable(container);
+ FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
+ FlagValueList fList = fp.getFlagValueList(container);
+
+ int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
+ boolean rVal = fList.getBoolean(index);
+
+ PlatformAconfigPackageInternal reader = readerMap.get(packageName);
+ if (reader == null) {
+ reader = PlatformAconfigPackageInternal.load(container, packageName);
+ assertNull(reader.getException());
+ readerMap.put(packageName, reader);
+ }
+ boolean jVal = reader.getBooleanFlagValue(flagName, !rVal);
+
+ assertEquals(rVal, jVal);
+ }
+ }
+
+ @Test
+ public void testPlatformAconfigPackageInternal_load_with_fingerprint() throws IOException {
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ for (parsed_flag flag : flags) {
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ String flagName = flag.name;
+ if (!PLATFORM_CONTAINERS.contains(container)) continue;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+ FlagTable fTable = fp.getFlagTable(container);
+ FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
+ FlagValueList fList = fp.getFlagValueList(container);
+
+ int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
+ boolean rVal = fList.getBoolean(index);
+
+ long fingerprint = pNode.getPackageFingerprint();
+
+ PlatformAconfigPackageInternal reader = readerMap.get(packageName);
+ if (reader == null) {
+ reader = PlatformAconfigPackageInternal.load(container, packageName, fingerprint);
+ assertNull(reader.getException());
+ readerMap.put(packageName, reader);
+ }
+ boolean jVal = reader.getBooleanFlagValue(fNode.getFlagIndex());
+
+ assertEquals(rVal, jVal);
+ }
+ }
+
+ @Test
+ public void testAconfigPackage_load_withError() throws IOException {
+ // container not found fake_container
+ PlatformAconfigPackageInternal aPackage =
+ PlatformAconfigPackageInternal.load("fake_container", "fake_package", 0);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ aPackage.getException().getErrorCode());
+
+ // package not found
+ aPackage = PlatformAconfigPackageInternal.load("system", "fake_container", 0);
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ aPackage.getException().getErrorCode());
+
+ // fingerprint doesn't match
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ parsed_flag flag = flags.get(0);
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ boolean value = flag.state == ENABLED;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+
+ if (pNode.hasPackageFingerprint()) {
+ long fingerprint = pNode.getPackageFingerprint();
+ aPackage = PlatformAconfigPackageInternal.load(container, packageName, fingerprint + 1);
+ assertEquals(
+ // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ 5, aPackage.getException().getErrorCode());
+ assertEquals(aPackage.getBooleanFlagValue(flag.name, !value), value);
+ }
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
similarity index 99%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
rename to tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
index 3a1bba0..8a8f054 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
@@ -42,4 +42,4 @@
assertFalse(reader.getBooleanFlagValue(0));
assertTrue(reader.getBooleanFlagValue(1));
}
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt b/tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
similarity index 91%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
rename to tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
index 24952ec..49250d4 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
+++ b/tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
@@ -15,3 +15,5 @@
rule android.aconfig.storage.PackageTable$* android.aconfig.storage.test.PackageTable$@1
rule android.aconfig.storage.FlagValueList$* android.aconfig.storage.test.FlagValueList@1
rule android.aconfig.storage.SipHasher13$* android.aconfig.storage.test.SipHasher13@1
+
+rule android.os.flagging.PlatformAconfigPackageInternal android.aconfig.storage.test.PlatformAconfigPackageInternal
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
deleted file mode 100644
index 18f70e8..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2024 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.aconfig.storage.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
-
-import android.aconfig.storage.AconfigPackageImpl;
-import android.aconfig.storage.AconfigStorageException;
-import android.aconfig.storage.StorageFileProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class AconfigPackageImplTest {
-
- private StorageFileProvider pr;
-
- @Before
- public void setup() {
- pr = new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- }
-
- @Test
- public void testLoad_onlyPackageName() throws Exception {
- AconfigPackageImpl p = AconfigPackageImpl.load("com.android.aconfig.storage.test_1", pr);
- assertNotNull(p);
- }
-
- @Test
- public void testLoad_groupNameFingerprint() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertNotNull(p);
- }
-
- @Test
- public void testLoad_error() throws Exception {
- AconfigPackageImpl p;
- AconfigStorageException e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "mockup", "com.android.aconfig.storage.test_10", pr));
- // cannot find package
- assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
- // cannot find package
- e =
- assertThrows(
- AconfigStorageException.class,
- () -> AconfigPackageImpl.load("com.android.aconfig.storage.test_10", pr));
- assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
- // cannot find container
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- null, "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CONTAINER_NOT_FOUND, e.getErrorCode());
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "test", "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CONTAINER_NOT_FOUND, e.getErrorCode());
-
- // new storage doesn't exist
- pr = new StorageFileProvider("fake/path/", "fake/path/");
- e =
- assertThrows(
- AconfigStorageException.class,
- () -> AconfigPackageImpl.load("fake_package", pr));
- assertEquals(AconfigStorageException.ERROR_STORAGE_SYSTEM_NOT_FOUND, e.getErrorCode());
-
- // file read issue
- pr = new StorageFileProvider(TestDataUtils.TESTDATA_PATH, "fake/path/");
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "mockup", "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
- }
-
- @Test
- public void testGetBooleanFlagValue_flagName() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertFalse(p.getBooleanFlagValue("disabled_rw", true));
- assertTrue(p.getBooleanFlagValue("enabled_ro", false));
- assertTrue(p.getBooleanFlagValue("enabled_rw", false));
- assertFalse(p.getBooleanFlagValue("fake", false));
- }
-
- @Test
- public void testGetBooleanFlagValue_index() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertFalse(p.getBooleanFlagValue(0));
- assertTrue(p.getBooleanFlagValue(1));
- assertTrue(p.getBooleanFlagValue(2));
- }
-
- @Test
- public void testHasPackageFingerprint() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertFalse(p.hasPackageFingerprint());
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
deleted file mode 100644
index 9c88122..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
+++ /dev/null
@@ -1,49 +0,0 @@
-android_test {
- name: "aconfig_storage_read_api.test.java",
- srcs: ["./**/*.java"],
- static_libs: [
- "aconfig_device_paths_java",
- "aconfig_storage_file_java",
- "aconfig_storage_reader_java",
- "androidx.test.rules",
- "libaconfig_storage_read_api_java",
- "junit",
- ],
- jni_libs: [
- "libaconfig_storage_read_api_rust_jni",
- ],
- data: [
- ":read_api_test_storage_files",
- ],
- platform_apis: true,
- certificate: "platform",
- test_suites: [
- "general-tests",
- ],
- team: "trendy_team_android_core_experiments",
-}
-
-android_test {
- name: "aconfig_storage_package",
- team: "trendy_team_android_core_experiments",
- srcs: [
- "AconfigPackageImplTest.java",
- "StorageFileProviderTest.java",
- "TestDataUtils.java",
- ],
- static_libs: [
- "androidx.test.runner",
- "junit",
- "aconfig_storage_reader_java",
- ],
- test_config: "AndroidStorageJaveTest.xml",
- manifest: "AndroidPackageTestManifest.xml",
- sdk_version: "test_current",
- data: [
- ":read_api_test_storage_files",
- ],
- test_suites: [
- "general-tests",
- ],
- jarjar_rules: "jarjar.txt",
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml
deleted file mode 100644
index 78bfb37..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2024 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.aconfig_storage.test">
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.aconfig_storage.test" />
-
-</manifest>
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageFileProviderTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/StorageFileProviderTest.java
deleted file mode 100644
index ba1ae9e..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageFileProviderTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2024 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.aconfig.storage.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.aconfig.storage.FlagTable;
-import android.aconfig.storage.FlagValueList;
-import android.aconfig.storage.PackageTable;
-import android.aconfig.storage.StorageFileProvider;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-
-@RunWith(JUnit4.class)
-public class StorageFileProviderTest {
-
- @Test
- public void testContainerFileExists() throws Exception {
- StorageFileProvider p =
- new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- assertTrue(p.containerFileExists(null));
- assertTrue(p.containerFileExists("mockup"));
- assertFalse(p.containerFileExists("fake"));
- }
-
- @Test
- public void testListpackageMapFiles() throws Exception {
- StorageFileProvider p =
- new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- // throw new Exception(Environment.getExternalStorageDirectory().getAbsolutePath());
- List<Path> file = p.listPackageMapFiles();
- assertEquals(1, file.size());
- assertTrue(
- file.get(0)
- .equals(
- Paths.get(
- TestDataUtils.TESTDATA_PATH,
- TestDataUtils.TEST_PACKAGE_MAP_PATH)));
- }
-
- @Test
- public void testLoadFiles() throws Exception {
- StorageFileProvider p =
- new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- PackageTable pt = p.getPackageTable("mockup");
- assertNotNull(pt);
- pt =
- StorageFileProvider.getPackageTable(
- Paths.get(
- TestDataUtils.TESTDATA_PATH, TestDataUtils.TEST_PACKAGE_MAP_PATH));
- assertNotNull(pt);
- FlagTable f = p.getFlagTable("mockup");
- assertNotNull(f);
- FlagValueList v = p.getFlagValueList("mockup");
- assertNotNull(v);
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java b/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
deleted file mode 100644
index d5cddc7..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2024 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.aconfig.storage.test;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-public final class TestDataUtils {
- public static final String TEST_PACKAGE_MAP_PATH = "mockup.package.map";
- public static final String TEST_FLAG_MAP_PATH = "mockup.flag.map";
- public static final String TEST_FLAG_VAL_PATH = "mockup.val";
- public static final String TEST_FLAG_INFO_PATH = "mockup.info";
-
- public static final String TESTDATA_PATH =
- "/data/local/tmp/aconfig_storage_package/testdata/";
-
- public static ByteBuffer getTestPackageMapByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_PACKAGE_MAP_PATH);
- }
-
- public static ByteBuffer getTestFlagMapByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_MAP_PATH);
- }
-
- public static ByteBuffer getTestFlagValByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_VAL_PATH);
- }
-
- public static ByteBuffer getTestFlagInfoByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_INFO_PATH);
- }
-
- private static ByteBuffer readFile(String fileName) throws Exception {
- InputStream input = new FileInputStream(fileName);
- return ByteBuffer.wrap(input.readAllBytes());
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
index 7537643..5289faa 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
@@ -56,10 +56,10 @@
flag_map = std::string(maps_dir) + "/mockup.flag.map";
flag_val = std::string(boot_dir) + "/mockup.val";
flag_info = std::string(boot_dir) + "/mockup.info";
- copy_file(test_dir + "/package.map", package_map);
- copy_file(test_dir + "/flag.map", flag_map);
- copy_file(test_dir + "/flag.val", flag_val);
- copy_file(test_dir + "/flag.info", flag_info);
+ copy_file(test_dir + "/package_v1.map", package_map);
+ copy_file(test_dir + "/flag_v1.map", flag_map);
+ copy_file(test_dir + "/flag_v1.val", flag_val);
+ copy_file(test_dir + "/flag_v1.info", flag_info);
}
void TearDown() override {
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
index 0d943f8..2a8edf3 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
+++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
@@ -9,7 +9,7 @@
use rand::Rng;
use std::fs;
- fn create_test_storage_files() -> String {
+ fn create_test_storage_files(version: u32) -> String {
let mut rng = rand::thread_rng();
let number: u32 = rng.gen();
let storage_dir = String::from("/tmp/") + &number.to_string();
@@ -26,17 +26,17 @@
let flag_map = storage_dir.clone() + "/maps/mockup.flag.map";
let flag_val = storage_dir.clone() + "/boot/mockup.val";
let flag_info = storage_dir.clone() + "/boot/mockup.info";
- fs::copy("./data/v1/package.map", package_map).unwrap();
- fs::copy("./data/v1/flag.map", flag_map).unwrap();
- fs::copy("./data/v1/flag.val", flag_val).unwrap();
- fs::copy("./data/v1/flag.info", flag_info).unwrap();
+ fs::copy(format!("./data/v{0}/package_v{0}.map", version), package_map).unwrap();
+ fs::copy(format!("./data/v{0}/flag_v{0}.map", version), flag_map).unwrap();
+ fs::copy(format!("./data/v{}/flag_v{0}.val", version), flag_val).unwrap();
+ fs::copy(format!("./data/v{}/flag_v{0}.info", version), flag_info).unwrap();
storage_dir
}
#[test]
- fn test_unavailable_stoarge() {
- let storage_dir = create_test_storage_files();
+ fn test_unavailable_storage() {
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let err = unsafe {
@@ -53,7 +53,7 @@
#[test]
fn test_package_context_query() {
- let storage_dir = create_test_storage_files();
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let package_mapped_file = unsafe {
@@ -64,27 +64,73 @@
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
+ let expected_package_context =
+ PackageReadContext { package_id: 0, boolean_start_index: 0, fingerprint: 0 };
assert_eq!(package_context, expected_package_context);
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
+ let expected_package_context =
+ PackageReadContext { package_id: 1, boolean_start_index: 3, fingerprint: 0 };
assert_eq!(package_context, expected_package_context);
let package_context =
get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
.unwrap()
.unwrap();
- let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
+ let expected_package_context =
+ PackageReadContext { package_id: 2, boolean_start_index: 6, fingerprint: 0 };
+ assert_eq!(package_context, expected_package_context);
+ }
+
+ #[test]
+ fn test_package_context_query_with_fingerprint() {
+ let storage_dir = create_test_storage_files(2);
+ // SAFETY:
+ // The safety here is ensured as the test process will not write to temp storage file
+ let package_mapped_file = unsafe {
+ get_mapped_file(&storage_dir, "mockup", StorageFileType::PackageMap).unwrap()
+ };
+
+ let package_context =
+ get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
+ .unwrap()
+ .unwrap();
+ let expected_package_context = PackageReadContext {
+ package_id: 0,
+ boolean_start_index: 0,
+ fingerprint: 15248948510590158086u64,
+ };
+ assert_eq!(package_context, expected_package_context);
+
+ let package_context =
+ get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
+ .unwrap()
+ .unwrap();
+ let expected_package_context = PackageReadContext {
+ package_id: 1,
+ boolean_start_index: 3,
+ fingerprint: 4431940502274857964u64,
+ };
+ assert_eq!(package_context, expected_package_context);
+
+ let package_context =
+ get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
+ .unwrap()
+ .unwrap();
+ let expected_package_context = PackageReadContext {
+ package_id: 2,
+ boolean_start_index: 6,
+ fingerprint: 16233229917711622375u64,
+ };
assert_eq!(package_context, expected_package_context);
}
#[test]
fn test_none_exist_package_context_query() {
- let storage_dir = create_test_storage_files();
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let package_mapped_file = unsafe {
@@ -99,7 +145,7 @@
#[test]
fn test_flag_context_query() {
- let storage_dir = create_test_storage_files();
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let flag_mapped_file =
@@ -125,7 +171,7 @@
#[test]
fn test_none_exist_flag_context_query() {
- let storage_dir = create_test_storage_files();
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let flag_mapped_file =
@@ -141,7 +187,7 @@
#[test]
fn test_boolean_flag_value_query() {
- let storage_dir = create_test_storage_files();
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let flag_value_file =
@@ -155,7 +201,7 @@
#[test]
fn test_invalid_boolean_flag_value_query() {
- let storage_dir = create_test_storage_files();
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let flag_value_file =
@@ -169,7 +215,7 @@
#[test]
fn test_flag_info_query() {
- let storage_dir = create_test_storage_files();
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let flag_info_file =
@@ -186,7 +232,7 @@
#[test]
fn test_invalid_boolean_flag_info_query() {
- let storage_dir = create_test_storage_files();
+ let storage_dir = create_test_storage_files(1);
// SAFETY:
// The safety here is ensured as the test process will not write to temp storage file
let flag_info_file =
@@ -199,10 +245,18 @@
}
#[test]
- fn test_storage_version_query() {
- assert_eq!(get_storage_file_version("./data/v1/package.map").unwrap(), 1);
- assert_eq!(get_storage_file_version("./data/v1/flag.map").unwrap(), 1);
- assert_eq!(get_storage_file_version("./data/v1/flag.val").unwrap(), 1);
- assert_eq!(get_storage_file_version("./data/v1/flag.info").unwrap(), 1);
+ fn test_storage_version_query_v1() {
+ assert_eq!(get_storage_file_version("./data/v1/package_v1.map").unwrap(), 1);
+ assert_eq!(get_storage_file_version("./data/v1/flag_v1.map").unwrap(), 1);
+ assert_eq!(get_storage_file_version("./data/v1/flag_v1.val").unwrap(), 1);
+ assert_eq!(get_storage_file_version("./data/v1/flag_v1.info").unwrap(), 1);
+ }
+
+ #[test]
+ fn test_storage_version_query_v2() {
+ assert_eq!(get_storage_file_version("./data/v2/package_v2.map").unwrap(), 2);
+ assert_eq!(get_storage_file_version("./data/v2/flag_v2.map").unwrap(), 2);
+ assert_eq!(get_storage_file_version("./data/v2/flag_v2.val").unwrap(), 2);
+ assert_eq!(get_storage_file_version("./data/v2/flag_v2.info").unwrap(), 2);
}
}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
new file mode 100644
index 0000000..ce3786a
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2024 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.aconfig.storage.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.PlatformAconfigPackageInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PlatformAconfigPackageInternalTest {
+
+ public static final String TESTDATA_PATH =
+ "/data/local/tmp/aconfig_storage_read_unit/testdata/";
+
+ private StorageFileProvider pr;
+
+ @Before
+ public void setup() {
+ pr = new StorageFileProvider(TESTDATA_PATH, TESTDATA_PATH);
+ }
+
+ @Test
+ public void testLoad_container_package() throws Exception {
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", pr);
+ assertNull(p.getException());
+ }
+
+ @Test
+ public void testLoad_container_package_error() throws Exception {
+ // cannot find package
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_10", pr);
+
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ p.getException().getErrorCode());
+
+ // cannot find container
+ p = PlatformAconfigPackageInternal.load(null, "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ p.getException().getErrorCode());
+ p = PlatformAconfigPackageInternal.load("test", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ p.getException().getErrorCode());
+
+ // new storage doesn't exist
+ pr = new StorageFileProvider("fake/path/", "fake/path/");
+ p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ p.getException().getErrorCode());
+
+ // file read issue
+ pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+ p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ p.getException().getErrorCode());
+ }
+
+ @Test
+ public void testLoad_container_package_fingerprint() throws Exception {
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertNull(p.getException());
+ }
+
+ @Test
+ public void testLoad_container_package_fingerprint_error() throws Exception {
+
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+
+ // cannot find package
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_10", fingerprint, pr);
+
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ p.getException().getErrorCode());
+
+ // cannot find container
+ p =
+ PlatformAconfigPackageInternal.load(
+ null, "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ p.getException().getErrorCode());
+ p =
+ PlatformAconfigPackageInternal.load(
+ "test", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ p.getException().getErrorCode());
+ // fingerprint doesn't match
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint + 1, pr);
+ assertEquals(
+ // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ 5, p.getException().getErrorCode());
+
+ // new storage doesn't exist
+ pr = new StorageFileProvider("fake/path/", "fake/path/");
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ p.getException().getErrorCode());
+
+ // file read issue
+ pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ p.getException().getErrorCode());
+ }
+
+ @Test
+ public void testGetBooleanFlagValue_flagName() throws Exception {
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", pr);
+ assertFalse(p.getBooleanFlagValue("disabled_rw", true));
+ assertTrue(p.getBooleanFlagValue("enabled_ro", false));
+ assertTrue(p.getBooleanFlagValue("enabled_rw", false));
+ assertFalse(p.getBooleanFlagValue("fake", false));
+ }
+
+ @Test
+ public void testGetBooleanFlagValue_index() throws Exception {
+
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertFalse(p.getBooleanFlagValue(0));
+ assertTrue(p.getBooleanFlagValue(1));
+ assertTrue(p.getBooleanFlagValue(2));
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs b/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs
index 5640922..5721105 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs
@@ -94,13 +94,13 @@
#[cfg(test)]
mod tests {
use super::*;
- use aconfig_storage_file::test_utils::create_test_flag_info_list;
+ use aconfig_storage_file::{test_utils::create_test_flag_info_list, DEFAULT_FILE_VERSION};
use aconfig_storage_read_api::flag_info_query::find_flag_attribute;
#[test]
// this test point locks down has server override update
fn test_update_flag_has_server_override() {
- let flag_info_list = create_test_flag_info_list();
+ let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
let mut buf = flag_info_list.into_bytes();
for i in 0..flag_info_list.header.num_flags {
update_flag_has_server_override(&mut buf, FlagValueType::Boolean, i, true).unwrap();
@@ -115,7 +115,7 @@
#[test]
// this test point locks down has local override update
fn test_update_flag_has_local_override() {
- let flag_info_list = create_test_flag_info_list();
+ let flag_info_list = create_test_flag_info_list(DEFAULT_FILE_VERSION);
let mut buf = flag_info_list.into_bytes();
for i in 0..flag_info_list.header.num_flags {
update_flag_has_local_override(&mut buf, FlagValueType::Boolean, i, true).unwrap();
diff --git a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
index 06a9b15..9772db9 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
@@ -49,12 +49,12 @@
#[cfg(test)]
mod tests {
use super::*;
- use aconfig_storage_file::test_utils::create_test_flag_value_list;
+ use aconfig_storage_file::{test_utils::create_test_flag_value_list, DEFAULT_FILE_VERSION};
#[test]
// this test point locks down flag value update
fn test_boolean_flag_value_update() {
- let flag_value_list = create_test_flag_value_list();
+ let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
let value_offset = flag_value_list.header.boolean_value_offset;
let mut content = flag_value_list.into_bytes();
let true_byte = u8::from(true).to_le_bytes()[0];
@@ -72,7 +72,7 @@
#[test]
// this test point locks down update beyond the end of boolean section
fn test_boolean_out_of_range() {
- let mut flag_value_list = create_test_flag_value_list().into_bytes();
+ let mut flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION).into_bytes();
let error = update_boolean_flag_value(&mut flag_value_list[..], 8, true).unwrap_err();
assert_eq!(
format!("{:?}", error),
@@ -83,7 +83,7 @@
#[test]
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
- let mut value_list = create_test_flag_value_list();
+ let mut value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
value_list.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let mut flag_value = value_list.into_bytes();
let error = update_boolean_flag_value(&mut flag_value[..], 4, true).unwrap_err();
diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs
index 68edf7d..aef7d7e 100644
--- a/tools/aconfig/aflags/src/aconfig_storage_source.rs
+++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs
@@ -93,7 +93,8 @@
special_fields: SpecialFields::new(),
};
- let mut socket = UnixStream::connect("/dev/socket/aconfigd")?;
+ let socket_name = "/dev/socket/aconfigd_system";
+ let mut socket = UnixStream::connect(socket_name)?;
let message_buffer = messages.write_to_bytes()?;
let mut message_length_buffer: [u8; 4] = [0; 4];
diff --git a/tools/aconfig/fake_device_config/Android.bp b/tools/aconfig/fake_device_config/Android.bp
index 1f17e6b..1c5b7c5 100644
--- a/tools/aconfig/fake_device_config/Android.bp
+++ b/tools/aconfig/fake_device_config/Android.bp
@@ -32,3 +32,24 @@
host_supported: true,
is_stubs_module: true,
}
+
+java_library {
+ name: "aconfig_storage_stub",
+ srcs: [
+ "src/android/os/flagging/**/*.java",
+ ],
+ sdk_version: "core_current",
+ host_supported: true,
+ is_stubs_module: true,
+}
+
+java_library {
+ name: "aconfig_storage_stub_none",
+ srcs: [
+ "src/android/os/flagging/**/*.java",
+ ],
+ sdk_version: "none",
+ system_modules: "core-all-system-modules",
+ host_supported: true,
+ is_stubs_module: true,
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/Build.java b/tools/aconfig/fake_device_config/src/android/os/Build.java
new file mode 100644
index 0000000..8ec72fb
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/Build.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.os;
+
+public class Build {
+ public static class VERSION {
+ public static final int SDK_INT = 0;
+ }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java
new file mode 100644
index 0000000..3cac516
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.os.flagging;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class AconfigPackage {
+ public static AconfigPackage load(String packageName) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
new file mode 100644
index 0000000..5f066a8
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 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.os.flagging;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class AconfigPackageInternal {
+
+ public static AconfigPackageInternal load(String container, String packageName) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public static AconfigPackageInternal load(
+ String container, String packageName, long packageFingerprint) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(int index) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException getException() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java
new file mode 100644
index 0000000..bfec98c
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.os.flagging;
+
+public class AconfigStorageReadException extends RuntimeException {
+
+ /** Generic error code indicating an unspecified Aconfig Storage error. */
+ public static final int ERROR_GENERIC = 0;
+
+ /** Error code indicating that the Aconfig Storage system is not found on the device. */
+ public static final int ERROR_STORAGE_SYSTEM_NOT_FOUND = 1;
+
+ /** Error code indicating that the requested configuration package is not found. */
+ public static final int ERROR_PACKAGE_NOT_FOUND = 2;
+
+ /** Error code indicating that the specified container is not found. */
+ public static final int ERROR_CONTAINER_NOT_FOUND = 3;
+
+ /** Error code indicating that there was an error reading the Aconfig Storage file. */
+ public static final int ERROR_CANNOT_READ_STORAGE_FILE = 4;
+
+ public static final int ERROR_FILE_FINGERPRINT_MISMATCH = 5;
+
+ public AconfigStorageReadException(int errorCode, String msg) {
+ super(msg);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException(int errorCode, String msg, Throwable cause) {
+ super(msg, cause);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException(int errorCode, Throwable cause) {
+ super(cause);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public int getErrorCode() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ @Override
+ public String getMessage() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
new file mode 100644
index 0000000..c1bc19b
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 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.os.flagging;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class PlatformAconfigPackageInternal {
+
+ public static PlatformAconfigPackageInternal load(String container, String packageName) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public static PlatformAconfigPackageInternal load(
+ String container, String packageName, long packageFingerprint) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(int index) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException getException() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/provider/AconfigPackage.java b/tools/aconfig/fake_device_config/src/android/provider/AconfigPackage.java
deleted file mode 100644
index 2f01b8c..0000000
--- a/tools/aconfig/fake_device_config/src/android/provider/AconfigPackage.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2024 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.provider;
-
-/*
- * This class allows generated aconfig code to compile independently of the framework.
- */
-public class AconfigPackage {
-
- /** Flag value is true */
- public static final int FLAG_BOOLEAN_VALUE_TRUE = 1;
-
- /** Flag value is false */
- public static final int FLAG_BOOLEAN_VALUE_FALSE = 0;
-
- /** Flag value doesn't exist */
- public static final int FLAG_BOOLEAN_VALUE_NOT_EXIST = 2;
-
- public static int getBooleanFlagValue(String packageName, String flagName) {
- return 0;
- }
-
- public AconfigPackage(String packageName) {}
-
- public int getBooleanFlagValue(String flagName) {
- return 0;
- }
-}
\ No newline at end of file
diff --git a/tools/edit_monitor/daemon_manager.py b/tools/edit_monitor/daemon_manager.py
index afdefc5..0c31ab8 100644
--- a/tools/edit_monitor/daemon_manager.py
+++ b/tools/edit_monitor/daemon_manager.py
@@ -33,7 +33,7 @@
DEFAULT_PROCESS_TERMINATION_TIMEOUT_SECONDS = 5
DEFAULT_MONITOR_INTERVAL_SECONDS = 5
-DEFAULT_MEMORY_USAGE_THRESHOLD = 2 * 1024 # 2GB
+DEFAULT_MEMORY_USAGE_THRESHOLD = 0.02 # 2% of total memory
DEFAULT_CPU_USAGE_THRESHOLD = 200
DEFAULT_REBOOT_TIMEOUT_SECONDS = 60 * 60 * 24
BLOCK_SIGN_FILE = "edit_monitor_block_sign"
@@ -70,6 +70,9 @@
self.max_memory_usage = 0
self.max_cpu_usage = 0
+ self.total_memory_size = os.sysconf("SC_PAGE_SIZE") * os.sysconf(
+ "SC_PHYS_PAGES"
+ )
pid_file_dir = pathlib.Path(tempfile.gettempdir()).joinpath("edit_monitor")
pid_file_dir.mkdir(parents=True, exist_ok=True)
@@ -84,7 +87,7 @@
"edit_monitor",
self.user_name,
"ENABLE_ANDROID_EDIT_MONITOR",
- 10,
+ 100,
):
logging.warning("Edit monitor is disabled, exiting...")
return
@@ -141,16 +144,20 @@
# Logging the error and continue.
logging.warning("Failed to monitor daemon process with error: %s", e)
- if (
- self.max_memory_usage >= memory_threshold
- or self.max_cpu_usage >= cpu_threshold
- ):
- logging.error(
- "Daemon process is consuming too much resource, killing..."
- ),
+ if self.max_memory_usage >= memory_threshold:
self._send_error_event_to_clearcut(
- edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_RESOURCE_USAGE
+ edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE
)
+ logging.error(
+ "Daemon process is consuming too much memory, rebooting...")
+ self.reboot()
+
+ if self.max_cpu_usage >= cpu_threshold:
+ self._send_error_event_to_clearcut(
+ edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_CPU_USAGE
+ )
+ logging.error(
+ "Daemon process is consuming too much cpu, killing...")
self._terminate_process(self.daemon_process.pid)
logging.info(
@@ -351,7 +358,13 @@
stat_data = f.readline().split()
# RSS is the 24th field in /proc/[pid]/stat
rss_pages = int(stat_data[23])
- return rss_pages * 4 / 1024 # Covert to MB
+ process_memory = rss_pages * 4 * 1024 # Convert to bytes
+
+ return (
+ process_memory / self.total_memory_size
+ if self.total_memory_size
+ else 0.0
+ )
def _get_process_cpu_percent(self, pid: int, interval: int = 1) -> float:
total_start_time = self._get_total_cpu_time(pid)
diff --git a/tools/edit_monitor/daemon_manager_test.py b/tools/edit_monitor/daemon_manager_test.py
index 8d18388..350739d 100644
--- a/tools/edit_monitor/daemon_manager_test.py
+++ b/tools/edit_monitor/daemon_manager_test.py
@@ -202,23 +202,31 @@
fake_cclient, edit_event_pb2.EditEvent.FAILED_TO_START_EDIT_MONITOR
)
- def test_monitor_daemon_subprocess_killed_high_memory_usage(self):
+ @mock.patch('os.execv')
+ def test_monitor_reboot_with_high_memory_usage(self, mock_execv):
fake_cclient = FakeClearcutClient()
+ binary_file = tempfile.NamedTemporaryFile(
+ dir=self.working_dir.name, delete=False
+ )
+
dm = daemon_manager.DaemonManager(
- TEST_BINARY_FILE,
+ binary_file.name,
daemon_target=memory_consume_daemon_target,
daemon_args=(2,),
cclient=fake_cclient,
)
+ # set the fake total_memory_size
+ dm.total_memory_size = 100 * 1024 *1024
dm.start()
- dm.monitor_daemon(interval=1, memory_threshold=2)
+ dm.monitor_daemon(interval=1)
- self.assertTrue(dm.max_memory_usage >= 2)
+ self.assertTrue(dm.max_memory_usage >= 0.02)
self.assert_no_subprocess_running()
self._assert_error_event_logged(
fake_cclient,
- edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_RESOURCE_USAGE,
+ edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE,
)
+ mock_execv.assert_called_once()
def test_monitor_daemon_subprocess_killed_high_cpu_usage(self):
fake_cclient = FakeClearcutClient()
@@ -235,7 +243,7 @@
self.assert_no_subprocess_running()
self._assert_error_event_logged(
fake_cclient,
- edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_RESOURCE_USAGE,
+ edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_CPU_USAGE,
)
@mock.patch('subprocess.check_output')
diff --git a/tools/edit_monitor/proto/edit_event.proto b/tools/edit_monitor/proto/edit_event.proto
index dc3d3f6..9acc2e7 100644
--- a/tools/edit_monitor/proto/edit_event.proto
+++ b/tools/edit_monitor/proto/edit_event.proto
@@ -16,8 +16,9 @@
FAILED_TO_START_EDIT_MONITOR = 1;
FAILED_TO_STOP_EDIT_MONITOR = 2;
FAILED_TO_REBOOT_EDIT_MONITOR = 3;
- KILLED_DUE_TO_EXCEEDED_RESOURCE_USAGE = 4;
+ KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE = 4;
FORCE_CLEANUP = 5;
+ KILLED_DUE_TO_EXCEEDED_CPU_USAGE = 6;
}
// Event that logs a single edit
diff --git a/tools/ide_query/prober_scripts/ide_query.out b/tools/ide_query/prober_scripts/ide_query.out
index cd7ce6d..be48da1 100644
--- a/tools/ide_query/prober_scripts/ide_query.out
+++ b/tools/ide_query/prober_scripts/ide_query.out
@@ -1,7 +1,9 @@
-outa
-8build/make/tools/ide_query/prober_scripts/cpp/general.cc8prebuilts/clang/host/linux-x86/clang-r522817/bin/clang++-mthumb-Os-fomit-frame-pointer-mllvm-enable-shrink-wrap=false-O2-Wall-Wextra-Winit-self-Wpointer-arith-Wunguarded-availability-Werror=date-time-Werror=int-conversion-Werror=pragma-pack&-Werror=pragma-pack-suspicious-include-Werror=sizeof-array-div-Werror=string-plus-int'-Werror=unreachable-code-loop-increment"-Wno-error=deprecated-declarations-Wno-c99-designator-Wno-gnu-folding-constant"-Wno-inconsistent-missing-override-Wno-error=reorder-init-list-Wno-reorder-init-list-Wno-sign-compare-Wno-unused -DANDROID-DNDEBUG-UDEBUG(-D__compiler_offsetof=__builtin_offsetof*-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__ -faddrsig-fdebug-default-version=5-fcolor-diagnostics-ffp-contract=off-fno-exceptions-fno-strict-aliasing-fmessage-length=0#-fno-relaxed-template-template-args-gsimple-template-names-gz=zstd-no-canonical-prefixes-Wno-error=format"-fdebug-prefix-map=/proc/self/cwd=-ftrivial-auto-var-init=zero-g-ffunction-sections-fdata-sections-fno-short-enums-funwind-tables-fstack-protector-strong-Wa,--noexecstack-D_FORTIFY_SOURCE=2-Wstrict-aliasing=2-Werror=return-type-Werror=non-virtual-dtor-Werror=address-Werror=sequence-point-Werror=format-security-nostdlibinc-fdebug-info-for-profiling-msoft-float-march=armv7-a-mfloat-abi=softfp
--mfpu=neon/-Ibuild/make/tools/ide_query/prober_scripts/cpp³-Iout/soong/.intermediates/build/make/tools/ide_query/prober_scripts/cpp/ide_query_proberscript_cc/android_arm_armv7-a-neon/gen/proto/build/make/tools/ide_query/prober_scripts/cpp
-Iout/soong/.intermediates/build/make/tools/ide_query/prober_scripts/cpp/ide_query_proberscript_cc/android_arm_armv7-a-neon/gen/proto-D__LIBC_API__=10000-D__LIBM_API__=10000-D__LIBDL_API__=10000-Iexternal/protobuf/srcY-Iprebuilts/clang/host/linux-x86/clang-r522817/android_libc++/platform/arm/include/c++/v1=-Iprebuilts/clang/host/linux-x86/clang-r522817/include/c++/v1 -Ibionic/libc/async_safe/include-Isystem/logging/liblog/include'-Ibionic/libc/system_properties/include<-Isystem/core/property_service/libpropertyinfoparser/include-isystembionic/libc/include-isystembionic/libc/kernel/uapi/asm-arm-isystembionic/libc/kernel/uapi-isystembionic/libc/kernel/android/scsi-isystembionic/libc/kernel/android/uapi-targetarmv7a-linux-androideabi10000-DANDROID_STRICT-fPIE-Werror-Wno-unused-parameter-DGOOGLE_PROTOBUF_NO_RTTI-Wimplicit-fallthrough*-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS-Wno-gnu-include-next-fvisibility-inlines-hidden-mllvm-enable-shrink-wrap=false-std=gnu++20 -fno-rtti-Isystem/core/include-Isystem/logging/liblog/include-Isystem/media/audio/include-Ihardware/libhardware/include%-Ihardware/libhardware_legacy/include-Ihardware/ril/include-Iframeworks/native/include"-Iframeworks/native/opengl/include-Iframeworks/av/include-Werror=bool-operation -Werror=format-insufficient-args%-Werror=implicit-int-float-conversion-Werror=int-in-bool-context-Werror=int-to-pointer-cast-Werror=pointer-to-int-cast-Werror=xor-used-as-pow-Wno-void-pointer-to-enum-cast-Wno-void-pointer-to-int-cast-Wno-pointer-to-int-cast-Werror=fortify-source-Wno-unused-variable-Wno-missing-field-initializers-Wno-packed-non-pod-Werror=address-of-temporary+-Werror=incompatible-function-pointer-types-Werror=null-dereference-Werror=return-type"-Wno-tautological-constant-compare$-Wno-tautological-type-limit-compare"-Wno-implicit-int-float-conversion!-Wno-tautological-overlap-compare-Wno-deprecated-copy-Wno-range-loop-construct"-Wno-zero-as-null-pointer-constant)-Wno-deprecated-anon-enum-enum-conversion$-Wno-deprecated-enum-enum-conversion-Wno-pessimizing-move-Wno-non-c-typedef-for-linkage-Wno-align-mismatch"-Wno-error=unused-but-set-variable#-Wno-error=unused-but-set-parameter-Wno-error=deprecated-builtins-Wno-error=deprecated2-Wno-error=single-bit-bitfield-constant-conversion$-Wno-error=enum-constexpr-conversion-Wno-error=invalid-offsetof&-Wno-deprecated-dynamic-exception-spec8build/make/tools/ide_query/prober_scripts/cpp/general.cc"Õ?
+out2x
+8build/make/tools/ide_query/prober_scripts/cpp/general.cc8build/make/tools/ide_query/prober_scripts/cpp/general.cc:"
+8build/make/tools/ide_query/prober_scripts/cpp/general.cc8build/make/tools/ide_query/prober_scripts/cpp/general.cc"8prebuilts/clang/host/linux-x86/clang-r530567/bin/clang++"-nostdlibinc"-mthumb"-Os"-fomit-frame-pointer"-mllvm"-enable-shrink-wrap=false"-O2"-Wall"-Wextra"-Winit-self"-Wpointer-arith"-Wunguarded-availability"-Werror=date-time"-Werror=int-conversion"-Werror=pragma-pack"&-Werror=pragma-pack-suspicious-include"-Werror=sizeof-array-div"-Werror=string-plus-int"'-Werror=unreachable-code-loop-increment""-Wno-error=deprecated-declarations"-Wno-c23-extensions"-Wno-c99-designator"-Wno-gnu-folding-constant""-Wno-inconsistent-missing-override"-Wno-error=reorder-init-list"-Wno-reorder-init-list"-Wno-sign-compare"-Wno-unused" -DANDROID"-DNDEBUG"-UDEBUG"(-D__compiler_offsetof=__builtin_offsetof"*-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__" -faddrsig"-fdebug-default-version=5"-fcolor-diagnostics"-ffp-contract=off"-fno-exceptions"-fno-strict-aliasing"-fmessage-length=0"-gsimple-template-names"-gz=zstd"-no-canonical-prefixes""-fdebug-prefix-map=/proc/self/cwd="-ftrivial-auto-var-init=zero"-g"-ffunction-sections"-fdata-sections"-fno-short-enums"-funwind-tables"-fstack-protector-strong"-Wa,--noexecstack"-D_FORTIFY_SOURCE=2"-Wstrict-aliasing=2"-Werror=return-type"-Werror=non-virtual-dtor"-Werror=address"-Werror=sequence-point"-Werror=format-security"-msoft-float"-march=armv7-a"-mfloat-abi=softfp"
+-mfpu=neon"/-Ibuild/make/tools/ide_query/prober_scripts/cpp"³-Iout/soong/.intermediates/build/make/tools/ide_query/prober_scripts/cpp/ide_query_proberscript_cc/android_arm_armv7-a-neon/gen/proto/build/make/tools/ide_query/prober_scripts/cpp"
-Iout/soong/.intermediates/build/make/tools/ide_query/prober_scripts/cpp/ide_query_proberscript_cc/android_arm_armv7-a-neon/gen/proto"-D__LIBC_API__=10000"-D__LIBM_API__=10000"-D__LIBDL_API__=10000"-Iexternal/protobuf/src"Y-Iprebuilts/clang/host/linux-x86/clang-r530567/android_libc++/platform/arm/include/c++/v1"=-Iprebuilts/clang/host/linux-x86/clang-r530567/include/c++/v1" -Ibionic/libc/async_safe/include"-Isystem/logging/liblog/include"'-Ibionic/libc/system_properties/include"<-Isystem/core/property_service/libpropertyinfoparser/include"-isystem"bionic/libc/include"-isystem"bionic/libc/kernel/uapi/asm-arm"-isystem"bionic/libc/kernel/uapi"-isystem"bionic/libc/kernel/android/scsi"-isystem"bionic/libc/kernel/android/uapi"-target"armv7a-linux-androideabi10000"-DANDROID_STRICT"-fPIE"-Werror"-Wno-unused-parameter"-DGOOGLE_PROTOBUF_NO_RTTI"-Wimplicit-fallthrough"*-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS"-Wno-gnu-include-next"-fvisibility-inlines-hidden"-mllvm"-enable-shrink-wrap=false"-std=gnu++20" -fno-rtti"-Isystem/core/include"-Isystem/logging/liblog/include"-Isystem/media/audio/include"-Ihardware/libhardware/include"%-Ihardware/libhardware_legacy/include"-Ihardware/ril/include"-Iframeworks/native/include""-Iframeworks/native/opengl/include"-Iframeworks/av/include"-Werror=bool-operation" -Werror=format-insufficient-args"%-Werror=implicit-int-float-conversion"-Werror=int-in-bool-context"-Werror=int-to-pointer-cast"-Werror=pointer-to-int-cast"-Werror=xor-used-as-pow"-Wno-void-pointer-to-enum-cast"-Wno-void-pointer-to-int-cast"-Wno-pointer-to-int-cast"-Werror=fortify-source"-Wno-unused-variable"-Wno-missing-field-initializers"-Wno-packed-non-pod"-Werror=address-of-temporary"+-Werror=incompatible-function-pointer-types"-Werror=null-dereference"-Werror=return-type""-Wno-tautological-constant-compare"$-Wno-tautological-type-limit-compare""-Wno-implicit-int-float-conversion"!-Wno-tautological-overlap-compare"-Wno-deprecated-copy"-Wno-range-loop-construct""-Wno-zero-as-null-pointer-constant")-Wno-deprecated-anon-enum-enum-conversion"$-Wno-deprecated-enum-enum-conversion"-Wno-error=pessimizing-move"-Wno-non-c-typedef-for-linkage"-Wno-align-mismatch""-Wno-error=unused-but-set-variable"#-Wno-error=unused-but-set-parameter"-Wno-error=deprecated-builtins"-Wno-error=deprecated"&-Wno-deprecated-dynamic-exception-spec"$-Wno-error=enum-constexpr-conversion"-Wno-error=invalid-offsetof")-Wno-error=thread-safety-reference-return"-Wno-vla-cxx-extension"8build/make/tools/ide_query/prober_scripts/cpp/general.cc2Egenfiles_for_build/make/tools/ide_query/prober_scripts/cpp/general.cc:@
+Egenfiles_for_build/make/tools/ide_query/prober_scripts/cpp/general.cc*Õ?
¶soong/.intermediates/build/make/tools/ide_query/prober_scripts/cpp/ide_query_proberscript_cc/android_arm_armv7-a-neon/gen/proto/build/make/tools/ide_query/prober_scripts/cpp/foo.pb.h>// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: build/make/tools/ide_query/prober_scripts/cpp/foo.proto
diff --git a/tools/ide_query/prober_scripts/regen.sh b/tools/ide_query/prober_scripts/regen.sh
index 2edfe53..04a0264 100755
--- a/tools/ide_query/prober_scripts/regen.sh
+++ b/tools/ide_query/prober_scripts/regen.sh
@@ -21,13 +21,8 @@
# ide_query.sh. The prober doesn't check-out the full source code, so it
# can't run ide_query.sh itself.
-cd $(dirname $BASH_SOURCE)
-source $(pwd)/../../../shell_utils.sh
-require_top
-
files_to_build=(
build/make/tools/ide_query/prober_scripts/cpp/general.cc
)
-cd ${TOP}
build/make/tools/ide_query/ide_query.sh --lunch_target=aosp_arm-trunk_staging-eng ${files_to_build[@]} > build/make/tools/ide_query/prober_scripts/ide_query.out
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index c25ff27..30a6acc 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -1100,7 +1100,7 @@
vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(avb_custom_partitions)
vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
- if vbmeta_system:
+ if vbmeta_system and set(vbmeta_system.split()).intersection(partitions):
banner("vbmeta_system")
partitions["vbmeta_system"] = AddVBMeta(
output_zip, partitions, "vbmeta_system", vbmeta_system.split())
@@ -1110,7 +1110,7 @@
vbmeta_partitions.append("vbmeta_system")
vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip()
- if vbmeta_vendor:
+ if vbmeta_vendor and set(vbmeta_vendor.split()).intersection(partitions):
banner("vbmeta_vendor")
partitions["vbmeta_vendor"] = AddVBMeta(
output_zip, partitions, "vbmeta_vendor", vbmeta_vendor.split())
@@ -1137,7 +1137,7 @@
if item not in included_partitions]
vbmeta_partitions.append(partition_name)
- if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
+ if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true" and set(vbmeta_partitions).intersection(partitions):
banner("vbmeta")
AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)