Merge "Revert "Revert^7 "Rename build/make/target/board/Android.mk to a..."" into main
diff --git a/backported_fixes/Android.bp b/backported_fixes/Android.bp
new file mode 100644
index 0000000..243e77e
--- /dev/null
+++ b/backported_fixes/Android.bp
@@ -0,0 +1,143 @@
+// 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_property_writer"],
+ srcs: [":applied_backported_fix_binpbs"],
+ out: ["applied_backported_fixes.prop"],
+ cmd: "$(location applied_backported_fixes_property_writer)" +
+ " -p $(location applied_backported_fixes.prop)" +
+ " $(in)",
+}
+
+filegroup {
+ name: "backported_fixes_proto_file",
+ srcs: [
+ "backported_fixes.proto",
+ ],
+}
+
+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: "backported_fixes_main_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_property_writer",
+ main_class: "com.android.build.backportedfixes.WriteBackportedFixesPropFile",
+ static_libs: [
+ "backported_fixes_main_lib",
+ ],
+}
+
+java_binary_host {
+ name: "backported_fixes_combiner",
+ main_class: "com.android.build.backportedfixes.CombineBackportedFixes",
+ static_libs: [
+ "backported_fixes_main_lib",
+ ],
+}
+
+// Combines BackportedFix binary proto files into a single BackportedFixes binary proto file.
+genrule_defaults {
+ name: "default_backported_fixes_combiner",
+ tools: ["backported_fixes_combiner"],
+ cmd: "$(location backported_fixes_combiner)" +
+ " -o $(out)" +
+ " $(in)",
+}
+
+java_test_host {
+ name: "backported_fixes_main_lib_test",
+ srcs: ["tests/java/com/android/build/backportedfixes/*.java"],
+ static_libs: [
+ "backported_fixes_main_lib",
+ "backported_fixes_proto",
+ "junit",
+ "truth",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ test_suites: ["general-tests"],
+}
+
+// Converts BackprotedFix text protos to binary protos
+genrule_defaults {
+ name: "default_backported_fix_binpbs",
+ tools: ["aprotoc"],
+ tool_files: [
+ ":backported_fixes_proto_file",
+ ],
+ cmd: "$(location aprotoc) " +
+ " --encode=com.android.build.backportedfixes.BackportedFix" +
+ " $(location :backported_fixes_proto_file)" +
+ " < $(in)" +
+ " > $(out); echo $(out)",
+}
+
+gensrcs {
+ name: "applied_backported_fix_binpbs",
+ defaults: ["default_backported_fix_binpbs"],
+ output_extension: "binpb",
+ srcs: [
+ "applied_fixes/*.txtpb",
+ ],
+}
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/CombineBackportedFixes.java b/backported_fixes/src/java/com/android/build/backportedfixes/CombineBackportedFixes.java
new file mode 100644
index 0000000..0592cc1
--- /dev/null
+++ b/backported_fixes/src/java/com/android/build/backportedfixes/CombineBackportedFixes.java
@@ -0,0 +1,65 @@
+
+/*
+ * 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.android.build.backportedfixes.common.Parser;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.converters.FileConverter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+
+/** Creates a BackportedFixes binary proto file from a list of BackportedFix proto binary files. */
+public final class CombineBackportedFixes {
+
+ @Parameter(description = "BackportedFix proto binary files",
+ converter = FileConverter.class,
+ required = true)
+ List<File> fixFiles;
+ @Parameter(description = "Write the BackportedFixes proto binary to this file",
+ names = {"--out","-o"},
+ converter = FileConverter.class,
+ required = true)
+ File outFile;
+
+ public static void main(String... argv) throws Exception {
+ CombineBackportedFixes main = new CombineBackportedFixes();
+ JCommander.newBuilder().addObject(main).build().parse(argv);
+ main.run();
+ }
+
+ CombineBackportedFixes() {
+ }
+
+ private void run() throws Exception {
+ try (var out = new FileOutputStream(outFile)) {
+ var fixes = Parser.parseBackportedFixFiles(fixFiles);
+ writeBackportedFixes(fixes, out);
+ }
+ }
+
+ static void writeBackportedFixes(BackportedFixes fixes, OutputStream out)
+ throws IOException {
+ fixes.writeTo(out);
+ }
+}
diff --git a/backported_fixes/src/java/com/android/build/backportedfixes/WriteBackportedFixesPropFile.java b/backported_fixes/src/java/com/android/build/backportedfixes/WriteBackportedFixesPropFile.java
new file mode 100644
index 0000000..0ffb4ac
--- /dev/null
+++ b/backported_fixes/src/java/com/android/build/backportedfixes/WriteBackportedFixesPropFile.java
@@ -0,0 +1,89 @@
+
+/*
+ * 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.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;
+
+
+/**
+ * Creates backported fix properties file.
+ *
+ * <p>Writes BitSet of backported fix aliases from a list of BackportedFix proto binary files and
+ * writes the property {@value PROPERTY_NAME} to a file.
+ */
+public final class WriteBackportedFixesPropFile {
+
+ private static final String PROPERTY_NAME = "ro.build.backported_fixes.alias_bitset.long_list";
+ @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 {
+ WriteBackportedFixesPropFile main = new WriteBackportedFixesPropFile();
+ JCommander.newBuilder().addObject(main).build().parse(argv);
+ main.run();
+ }
+
+ WriteBackportedFixesPropFile() {
+ }
+
+ private void run() throws Exception {
+ try (var out = Files.newWriter(propertyFile, UTF_8)) {
+ var fixes = Parser.parseBackportedFixFiles(fixFiles);
+ 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("%s=%s", PROPERTY_NAME, 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/Parser.java b/backported_fixes/src/java/com/android/build/backportedfixes/common/Parser.java
new file mode 100644
index 0000000..6180fdc
--- /dev/null
+++ b/backported_fixes/src/java/com/android/build/backportedfixes/common/Parser.java
@@ -0,0 +1,140 @@
+/*
+ * 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.base.Preconditions.checkNotNull;
+
+import com.android.build.backportedfixes.BackportedFix;
+import com.android.build.backportedfixes.BackportedFixes;
+
+import com.google.common.base.Throwables;
+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.Comparator;
+import java.util.List;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+
+
+/** 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 parseBackportedFixFiles(List<File> fixFiles)
+ throws IOException {
+ try {
+ return fixFiles.stream().map(Parser::tunelFileInputStream)
+ .map(Parser::tunnelParse)
+ .sorted(Comparator.comparing(BackportedFix::getKnownIssue))
+ .collect(fixCollector());
+
+ } catch (TunnelException e) {
+ throw e.rethrow(FileNotFoundException.class, IOException.class);
+ }
+ }
+
+
+ private static Collector<BackportedFix, ?, BackportedFixes> fixCollector() {
+ return Collectors.collectingAndThen(Collectors.toList(), fixList -> {
+ var result = BackportedFixes.newBuilder();
+ result.addAllFixes(fixList);
+ return result.build();
+ });
+ }
+
+ private static FileInputStream tunelFileInputStream(File file) throws TunnelException {
+ try {
+ return new FileInputStream(file);
+ } catch (FileNotFoundException e) {
+ throw new TunnelException(e);
+ }
+ }
+
+ private static BackportedFix tunnelParse(InputStream s) throws TunnelException {
+ try {
+ var fix = BackportedFix.parseFrom(s);
+ s.close();
+ return fix;
+ } catch (IOException e) {
+ throw new TunnelException(e);
+ }
+ }
+
+ private static class TunnelException extends RuntimeException {
+ TunnelException(Exception cause) {
+ super("If you see this TunnelException something went wrong. It should always be rethrown as the cause.", cause);
+ }
+
+ <X extends Exception> RuntimeException rethrow(Class<X> exceptionClazz) throws X {
+ checkNotNull(exceptionClazz);
+ Throwables.throwIfInstanceOf(getCause(), exceptionClazz);
+ throw exception(
+ getCause(),
+ "rethrow(%s) doesn't match underlying exception", exceptionClazz);
+ }
+
+ public <X1 extends Exception, X2 extends Exception> RuntimeException rethrow(
+ Class<X1> exceptionClazz1, Class<X2> exceptionClazz2) throws X1, X2 {
+ checkNotNull(exceptionClazz1);
+ checkNotNull(exceptionClazz2);
+ Throwables.throwIfInstanceOf(getCause(), exceptionClazz1);
+ Throwables.throwIfInstanceOf(getCause(), exceptionClazz2);
+ throw exception(
+ getCause(),
+ "rethrow(%s, %s) doesn't match underlying exception",
+ exceptionClazz1,
+ exceptionClazz2);
+ }
+
+ private static ClassCastException exception(
+ Throwable cause, String message, Object... formatArgs) {
+ ClassCastException result = new ClassCastException(String.format(message, formatArgs));
+ result.initCause(cause);
+ return result;
+ }
+
+ }
+
+ private Parser() {
+ }
+}
diff --git a/backported_fixes/tests/java/com/android/build/backportedfixes/CombineBackportedFixesTest.java b/backported_fixes/tests/java/com/android/build/backportedfixes/CombineBackportedFixesTest.java
new file mode 100644
index 0000000..21d5f1e
--- /dev/null
+++ b/backported_fixes/tests/java/com/android/build/backportedfixes/CombineBackportedFixesTest.java
@@ -0,0 +1,41 @@
+
+/*
+ * 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.ByteArrayOutputStream;
+import java.io.IOException;
+
+/** Tests for {@link CombineBackportedFixes}. */
+public class CombineBackportedFixesTest {
+
+
+ @Test
+ public void writeBackportedFixes_default() throws IOException {
+ // Not much of a test, but there is not much to test.
+ BackportedFixes fixes = BackportedFixes.newBuilder()
+ .addFixes(BackportedFix.newBuilder().setKnownIssue(123).build())
+ .build();
+ var result = new ByteArrayOutputStream();
+ CombineBackportedFixes.writeBackportedFixes(fixes, result);
+ Truth.assertThat(BackportedFixes.parseFrom(result.toByteArray()))
+ .isEqualTo(fixes);
+ }
+}
diff --git a/backported_fixes/tests/java/com/android/build/backportedfixes/WriteBackportedFixesPropFileTest.java b/backported_fixes/tests/java/com/android/build/backportedfixes/WriteBackportedFixesPropFileTest.java
new file mode 100644
index 0000000..3209c15
--- /dev/null
+++ b/backported_fixes/tests/java/com/android/build/backportedfixes/WriteBackportedFixesPropFileTest.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 WriteBackportedFixesPropFile}. */
+public class WriteBackportedFixesPropFileTest {
+
+
+ @Test
+ public void writeFixesAsAliasBitSet_default() {
+ BackportedFixes fixes = BackportedFixes.newBuilder().build();
+ var result = new StringWriter();
+
+ WriteBackportedFixesPropFile.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();
+
+ WriteBackportedFixesPropFile.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/ParserTest.java b/backported_fixes/tests/java/com/android/build/backportedfixes/common/ParserTest.java
new file mode 100644
index 0000000..57a0a40
--- /dev/null
+++ b/backported_fixes/tests/java/com/android/build/backportedfixes/common/ParserTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+
+/** Tests for {@link Parser}.*/
+public class ParserTest {
+
+ @Rule
+ public TemporaryFolder mTempFolder = new TemporaryFolder();
+
+ @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 parseBackportedFixFiles_empty() throws IOException {
+ var result = Parser.parseBackportedFixFiles(ImmutableList.of());
+ assertThat(result).isEqualTo(BackportedFixes.getDefaultInstance());
+ }
+
+
+ @Test
+ public void parseBackportedFixFiles_oneBlank() throws IOException {
+ var result = Parser.parseBackportedFixFiles(ImmutableList.of(mTempFolder.newFile()));
+
+ assertThat(result).isEqualTo(
+ BackportedFixes.newBuilder()
+ .addFixes(BackportedFix.getDefaultInstance())
+ .build());
+ }
+
+ @Test
+ public void parseBackportedFixFiles_two() throws IOException {
+ BackportedFix ki123 = BackportedFix.newBuilder()
+ .setKnownIssue(123)
+ .setAlias(1)
+ .build();
+ BackportedFix ki456 = BackportedFix.newBuilder()
+ .setKnownIssue(456)
+ .setAlias(2)
+ .build();
+ var result = Parser.parseBackportedFixFiles(
+ ImmutableList.of(tempFile(ki456), tempFile(ki123)));
+ assertThat(result).isEqualTo(
+ BackportedFixes.newBuilder()
+ .addFixes(ki123)
+ .addFixes(ki456)
+ .build());
+ }
+
+ private File tempFile(BackportedFix fix) throws IOException {
+ File f = mTempFolder.newFile();
+ try (FileOutputStream out = new FileOutputStream(f)) {
+ fix.writeTo(out);
+ return f;
+ }
+ }
+}
diff --git a/ci/Android.bp b/ci/Android.bp
index 2407c51..3f28be4 100644
--- a/ci/Android.bp
+++ b/ci/Android.bp
@@ -103,13 +103,10 @@
"test_mapping_module_retriever.py",
"build_context.py",
"test_discovery_agent.py",
+ "metrics_agent.py",
+ "buildbot.py",
],
main: "build_test_suites.py",
- version: {
- py3: {
- embedded_launcher: true,
- },
- },
libs: [
"soong-metrics-proto-py",
],
@@ -123,6 +120,11 @@
"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..63d3ce3
--- /dev/null
+++ b/ci/build_device_and_tests
@@ -0,0 +1,19 @@
+#!/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.
+set -euo pipefail
+
+build/soong/soong_ui.bash --make-mode build_test_suites
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites --device-build $@
diff --git a/ci/build_metadata b/ci/build_metadata
index cd011c8..3e9218f 100755
--- a/ci/build_metadata
+++ b/ci/build_metadata
@@ -14,15 +14,31 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-set -ex
+set -x
+
+source build/make/shell_utils.sh
export TARGET_PRODUCT=aosp_arm64
export TARGET_RELEASE=trunk_staging
export TARGET_BUILD_VARIANT=eng
+import_build_vars \
+ OUT_DIR \
+ DIST_DIR \
+ HOST_OUT_EXECUTABLES \
+ || exit $?
+
TARGETS=(
all_teams
+ source_tree_size
release_config_metadata
)
-build/soong/bin/m dist ${TARGETS[@]}
+# Build modules
+build/soong/bin/m dist ${TARGETS[@]} || exit $?
+
+# List all source files in the tree
+( \
+ $HOST_OUT_EXECUTABLES/source_tree_size -o $DIST_DIR/all_source_tree_files.pb \
+ && gzip -fn $DIST_DIR/all_source_tree_files.pb \
+) || exit $?
diff --git a/ci/build_test_suites b/ci/build_test_suites
index 5aaf2f4..74470a8 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
#
@@ -13,8 +13,7 @@
# 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.
+set -euo pipefail
-import build_test_suites
-import sys
-
-build_test_suites.main(sys.argv[1:])
+build/soong/soong_ui.bash --make-mode build_test_suites
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index 9e56a20..addad15 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -20,16 +20,22 @@
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'])
+REQUIRED_ENV_VARS = frozenset(['TARGET_PRODUCT', 'TARGET_RELEASE', 'TOP', 'DIST_DIR'])
SOONG_UI_EXE_REL_PATH = 'build/soong/soong_ui.bash'
LOG_PATH = 'logs/build_test_suites.log'
+# Currently, this prevents the removal of those tags when they exist. In the future we likely
+# want the script to supply 'dist directly
+REQUIRED_BUILD_TARGETS = frozenset(['dist', 'droid', 'checkbuild'])
class Error(Exception):
@@ -68,14 +74,58 @@
if 'optimized_build' not in self.build_context.enabled_build_features:
return BuildPlan(set(self.args.extra_targets), set())
+ if not self.build_context.test_infos:
+ logging.warning('Build context has no test infos, skipping optimizations.')
+ for target in self.args.extra_targets:
+ get_metrics_agent().report_unoptimized_target(target, 'BUILD_CONTEXT has no test infos.')
+ return BuildPlan(set(self.args.extra_targets), set())
+
build_targets = set()
packaging_commands_getters = []
- for target in self.args.extra_targets:
- if self._unused_target_exclusion_enabled(
- target
- ) and not self.build_context.build_target_used(target):
- continue
+ # In order to roll optimizations out differently between test suites and
+ # device builds, we have separate flags.
+ if (
+ 'test_suites_zip_test_discovery'
+ in self.build_context.enabled_build_features
+ and not self.args.device_build
+ ) or (
+ 'device_zip_test_discovery'
+ in self.build_context.enabled_build_features
+ and self.args.device_build
+ ):
+ preliminary_build_targets = self._collect_preliminary_build_targets()
+ else:
+ preliminary_build_targets = self._legacy_collect_preliminary_build_targets()
+ # Keep reporting metrics when test discovery is disabled.
+ # To be removed once test discovery is fully rolled out.
+ optimization_rationale = ''
+ test_discovery_zip_regexes = set()
+ try:
+ 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)
+ continue
+ if target in REQUIRED_BUILD_TARGETS:
+ get_metrics_agent().report_unoptimized_target(target, 'Required build target.')
+ continue
+ try:
+ 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.')
+ continue
+ get_metrics_agent().report_optimized_target(target)
+ except Exception as e:
+ logging.error(f'unable to parse test discovery output: {repr(e)}')
+ get_metrics_agent().report_unoptimized_target(target, f'Error in parsing test discovery output for {target}: {repr(e)}')
+
+ for target in preliminary_build_targets:
target_optimizer_getter = self.target_optimizations.get(target, None)
if not target_optimizer_getter:
build_targets.add(target)
@@ -91,12 +141,86 @@
return BuildPlan(build_targets, packaging_commands_getters)
+ def _collect_preliminary_build_targets(self):
+ build_targets = set()
+ try:
+ 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:
+ get_metrics_agent().report_unoptimized_target(target, optimization_rationale)
+ return self._legacy_collect_preliminary_build_targets()
+
+ for target in self.args.extra_targets:
+ if target in REQUIRED_BUILD_TARGETS:
+ build_targets.add(target)
+ get_metrics_agent().report_unoptimized_target(target, 'Required build target.')
+ continue
+
+ regex = r'\b(%s.*)\b' % re.escape(target)
+ for opt in test_discovery_zip_regexes:
+ try:
+ if re.search(regex, opt):
+ get_metrics_agent().report_unoptimized_target(target, 'Test artifact used.')
+ build_targets.add(target)
+ continue
+ get_metrics_agent().report_optimized_target(target)
+ except Exception as e:
+ # In case of exception report as unoptimized
+ build_targets.add(target)
+ get_metrics_agent().report_unoptimized_target(target, f'Error in parsing test discovery output for {target}: {repr(e)}')
+ logging.error(f'unable to parse test discovery output: {repr(e)}')
+
+ return build_targets
+
+ def _legacy_collect_preliminary_build_targets(self):
+ build_targets = set()
+ for target in self.args.extra_targets:
+ if self._unused_target_exclusion_enabled(
+ target
+ ) and not self.build_context.build_target_used(target):
+ continue
+
+ build_targets.add(target)
+ return build_targets
+
def _unused_target_exclusion_enabled(self, target: str) -> bool:
return (
f'{target}_unused_exclusion'
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 +237,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
@@ -136,6 +268,11 @@
argparser.add_argument(
'extra_targets', nargs='*', help='Extra test suites to build.'
)
+ argparser.add_argument(
+ '--device-build',
+ action='store_true',
+ help='Flag to indicate running a device build.',
+ )
return argparser.parse_args(argv)
@@ -183,12 +320,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 +339,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:
diff --git a/ci/build_test_suites_test.py b/ci/build_test_suites_test.py
index 2afaab7..190740f 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):
@@ -72,6 +78,12 @@
with self.assert_raises_word(build_test_suites.Error, 'TOP'):
build_test_suites.main([])
+ def test_missing_dist_dir_env_var_raises(self):
+ del os.environ['DIST_DIR']
+
+ with self.assert_raises_word(build_test_suites.Error, 'DIST_DIR'):
+ build_test_suites.main([])
+
def test_invalid_arg_raises(self):
invalid_args = ['--invalid_arg']
@@ -108,6 +120,9 @@
self.soong_ui_dir = self.fake_top.joinpath('build/soong')
self.soong_ui_dir.mkdir(parents=True, exist_ok=True)
+ self.logs_dir = self.fake_top.joinpath('dist/logs')
+ self.logs_dir.mkdir(parents=True, exist_ok=True)
+
self.soong_ui = self.soong_ui_dir.joinpath('soong_ui.bash')
self.soong_ui.touch()
@@ -115,6 +130,7 @@
'TARGET_RELEASE': 'release',
'TARGET_PRODUCT': 'product',
'TOP': str(self.fake_top),
+ 'DIST_DIR': str(self.fake_top.joinpath('dist')),
})
self.mock_subprocess_run.return_value = 0
@@ -256,6 +272,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(
@@ -284,7 +306,8 @@
build_planner = self.create_build_planner(
build_targets=build_targets,
build_context=self.create_build_context(
- enabled_build_features=[{'name': self.get_target_flag('target_1')}]
+ enabled_build_features=[{'name': self.get_target_flag('target_1')}],
+ test_context=self.get_test_context('target_1'),
),
)
@@ -300,7 +323,8 @@
build_planner = self.create_build_planner(
build_targets=build_targets,
build_context=self.create_build_context(
- enabled_build_features=[{'name': self.get_target_flag('target_1')}]
+ enabled_build_features=[{'name': self.get_target_flag('target_1')}],
+ test_context=self.get_test_context('target_1'),
),
packaging_commands=packaging_commands,
)
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/BUILD.bazel b/core/BUILD.bazel
deleted file mode 100644
index f4869d4..0000000
--- a/core/BUILD.bazel
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-# Export tradefed templates for tests.
-exports_files(
- glob(["*.xml"]),
-)
-
-# Export proguard flag files for r8.
-filegroup(
- name = "global_proguard_flags",
- srcs = [
- "proguard.flags",
- "proguard_basic_keeps.flags",
- ],
- visibility = ["//visibility:public"],
-)
diff --git a/core/Makefile b/core/Makefile
index eaa3190..3ba931c 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).
@@ -844,6 +872,7 @@
SOONG_CONV_DATA := $(call intermediates-dir-for,PACKAGING,soong_conversion)/soong_conv_data
$(SOONG_CONV_DATA):
@rm -f $@
+ @touch $@ # This file must be present even if SOONG_CONV is empty.
@$(foreach s,$(SOONG_CONV),echo "$(s),$(SOONG_CONV.$(s).TYPE),$(sort $(SOONG_CONV.$(s).PROBLEMS)),$(sort $(filter-out $(SOONG_ALREADY_CONV),$(SOONG_CONV.$(s).DEPS))),$(sort $(SOONG_CONV.$(s).MAKEFILES)),$(sort $(SOONG_CONV.$(s).INSTALLED))" >>$@;)
$(call declare-1p-target,$(SOONG_CONV_DATA),build)
@@ -941,27 +970,12 @@
# -----------------------------------------------------------------
-.PHONY: event-log-tags
-
-# Produce an event logs tag file for everything we know about, in order
-# to properly allocate numbers. Then produce a file that's filtered
-# for what's going to be installed.
-
-all_event_log_tags_file := $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
-
event_log_tags_file := $(TARGET_OUT)/etc/event-log-tags
# Include tags from all packages that we know about
all_event_log_tags_src := \
$(sort $(foreach m, $(ALL_MODULES), $(ALL_MODULES.$(m).EVENT_LOG_TAGS)))
-$(all_event_log_tags_file): PRIVATE_SRC_FILES := $(all_event_log_tags_src)
-$(all_event_log_tags_file): $(all_event_log_tags_src) $(MERGETAGS) build/make/tools/event_log_tags.py
- $(hide) mkdir -p $(dir $@)
- $(hide) $(MERGETAGS) -o $@ $(PRIVATE_SRC_FILES)
-
-$(call declare-0p-target,$(all_event_log_tags_file))
-
# Include tags from all packages included in this product, plus all
# tags that are part of the system (ie, not in a vendor/ or device/
# directory).
@@ -973,13 +987,13 @@
$(filter-out vendor/% device/% out/%,$(all_event_log_tags_src)))
$(event_log_tags_file): PRIVATE_SRC_FILES := $(event_log_tags_src)
-$(event_log_tags_file): PRIVATE_MERGED_FILE := $(all_event_log_tags_file)
-$(event_log_tags_file): $(event_log_tags_src) $(all_event_log_tags_file) $(MERGETAGS) build/make/tools/event_log_tags.py
+$(event_log_tags_file): $(event_log_tags_src) $(MERGETAGS)
$(hide) mkdir -p $(dir $@)
- $(hide) $(MERGETAGS) -o $@ -m $(PRIVATE_MERGED_FILE) $(PRIVATE_SRC_FILES)
+ $(hide) $(MERGETAGS) -o $@ $(PRIVATE_SRC_FILES)
$(eval $(call declare-0p-target,$(event_log_tags_file)))
+.PHONY: event-log-tags
event-log-tags: $(event_log_tags_file)
ALL_DEFAULT_INSTALLED_MODULES += $(event_log_tags_file)
@@ -1267,33 +1281,6 @@
endif
-# 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
-
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)))
@@ -1595,6 +1582,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)
@@ -1653,6 +1641,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.
@@ -1768,6 +1758,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
@@ -2658,7 +2649,7 @@
TARGET_PRIVATE_RES_DIRS := $(wildcard $(TARGET_DEVICE_DIR)/recovery/res)
endif
recovery_resource_deps := $(shell find $(recovery_resources_common) \
- $(TARGET_PRIVATE_RES_DIRS) -type f)
+ $(TARGET_PRIVATE_RES_DIRS) -type f -not -name "*.bp")
recovery_resource_deps += $(generated_recovery_text_files)
@@ -2931,6 +2922,9 @@
$(error MTD device is no longer supported and thus BOARD_NAND_SPARE_SIZE is deprecated.)
endif
+recovery_intermediates := $(call intermediates-dir-for,PACKAGING,recovery)
+$(eval $(call write-partition-file-list,$(recovery_intermediates)/file_list.txt,$(TARGET_RECOVERY_OUT),$(INTERNAL_RECOVERYIMAGE_FILES)))
+
# -----------------------------------------------------------------
# Build debug ramdisk and debug boot image.
@@ -3510,18 +3504,20 @@
# Collect all available stub libraries installed in system and install with predefined linker configuration
# Also append LLNDK libraries in the APEX as required libs
SYSTEM_LINKER_CONFIG := $(TARGET_OUT)/etc/linker.config.pb
-SYSTEM_LINKER_CONFIG_SOURCE := $(call intermediates-dir-for,ETC,system_linker_config)/system_linker_config
+SYSTEM_LINKER_CONFIG_SOURCE := system/core/rootdir/etc/linker.config.json
$(SYSTEM_LINKER_CONFIG): PRIVATE_SYSTEM_LINKER_CONFIG_SOURCE := $(SYSTEM_LINKER_CONFIG_SOURCE)
$(SYSTEM_LINKER_CONFIG): $(INTERNAL_SYSTEMIMAGE_FILES) $(SYSTEM_LINKER_CONFIG_SOURCE) | conv_linker_config
@echo Creating linker config: $@
@mkdir -p $(dir $@)
- @rm -f $@
- $(HOST_OUT_EXECUTABLES)/conv_linker_config systemprovide --source $(PRIVATE_SYSTEM_LINKER_CONFIG_SOURCE) \
+ @rm -f $@ $@.step1
+ $(HOST_OUT_EXECUTABLES)/conv_linker_config proto --force -s $(PRIVATE_SYSTEM_LINKER_CONFIG_SOURCE) -o $@.step1
+ $(HOST_OUT_EXECUTABLES)/conv_linker_config systemprovide --source $@.step1 \
--output $@ --value "$(STUB_LIBRARIES)" --system "$(TARGET_OUT)"
$(HOST_OUT_EXECUTABLES)/conv_linker_config append --source $@ --output $@ --key requireLibs \
--value "$(foreach lib,$(LLNDK_MOVED_TO_APEX_LIBRARIES), $(lib).so)"
$(HOST_OUT_EXECUTABLES)/conv_linker_config append --source $@ --output $@ --key provideLibs \
--value "$(foreach lib,$(PRODUCT_EXTRA_STUB_LIBRARIES), $(lib).so)"
+ rm -f $@.step1
$(call declare-1p-target,$(SYSTEM_LINKER_CONFIG),)
$(call declare-license-deps,$(SYSTEM_LINKER_CONFIG),$(INTERNAL_SYSTEMIMAGE_FILES) $(SYSTEM_LINKER_CONFIG_SOURCE))
@@ -3562,7 +3558,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(systemimage_intermediates)/file_list.txt) \
- $(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1) $(TARGET_OUT) \
+ $(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1) $(TARGET_OUT) --build_datetime_file $(BUILD_DATETIME_FILE) \
|| ( mkdir -p $${DIST_DIR}; \
cp $(INSTALLED_FILES_FILE) $${DIST_DIR}/installed-files-rescued.txt; \
exit 1 )
@@ -3713,7 +3709,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(userdataimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_DATA) $(userdataimage_intermediates)/userdata_image_info.txt \
+ $(TARGET_OUT_DATA) $(userdataimage_intermediates)/userdata_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_USERDATAIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_USERDATAIMAGE_TARGET),$(BOARD_USERDATAIMAGE_PARTITION_SIZE))
endef
@@ -3775,7 +3771,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(cacheimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_CACHE) $(cacheimage_intermediates)/cache_image_info.txt \
+ $(TARGET_OUT_CACHE) $(cacheimage_intermediates)/cache_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_CACHEIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_CACHEIMAGE_TARGET),$(BOARD_CACHEIMAGE_PARTITION_SIZE))
endef
@@ -3862,7 +3858,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(systemotherimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_SYSTEM_OTHER) $(systemotherimage_intermediates)/system_other_image_info.txt \
+ $(TARGET_OUT_SYSTEM_OTHER) $(systemotherimage_intermediates)/system_other_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_SYSTEMOTHERIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_SYSTEMOTHERIMAGE_TARGET),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE))
endef
@@ -3968,7 +3964,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(vendorimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_VENDOR) $(vendorimage_intermediates)/vendor_image_info.txt \
+ $(TARGET_OUT_VENDOR) $(vendorimage_intermediates)/vendor_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_VENDORIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_VENDORIMAGE_TARGET) $(RECOVERY_FROM_BOOT_PATCH),$(BOARD_VENDORIMAGE_PARTITION_SIZE))
endef
@@ -4056,7 +4052,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(productimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_PRODUCT) $(productimage_intermediates)/product_image_info.txt \
+ $(TARGET_OUT_PRODUCT) $(productimage_intermediates)/product_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_PRODUCTIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_PRODUCTIMAGE_TARGET),$(BOARD_PRODUCTIMAGE_PARTITION_SIZE))
endef
@@ -4125,7 +4121,7 @@
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(system_extimage_intermediates)/file_list.txt) \
$(TARGET_OUT_SYSTEM_EXT) \
- $(system_extimage_intermediates)/system_ext_image_info.txt \
+ $(system_extimage_intermediates)/system_ext_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
$(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET),$(BOARD_PRODUCT_SERVICESIMAGE_PARTITION_SIZE))
@@ -4215,7 +4211,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(odmimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_ODM) $(odmimage_intermediates)/odm_image_info.txt \
+ $(TARGET_OUT_ODM) $(odmimage_intermediates)/odm_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_ODMIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_ODMIMAGE_TARGET),$(BOARD_ODMIMAGE_PARTITION_SIZE))
endef
@@ -4284,7 +4280,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(vendor_dlkmimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_VENDOR_DLKM) $(vendor_dlkmimage_intermediates)/vendor_dlkm_image_info.txt \
+ $(TARGET_OUT_VENDOR_DLKM) $(vendor_dlkmimage_intermediates)/vendor_dlkm_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_VENDOR_DLKMIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_VENDOR_DLKMIMAGE_TARGET),$(BOARD_VENDOR_DLKMIMAGE_PARTITION_SIZE))
endef
@@ -4353,7 +4349,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(odm_dlkmimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_ODM_DLKM) $(odm_dlkmimage_intermediates)/odm_dlkm_image_info.txt \
+ $(TARGET_OUT_ODM_DLKM) $(odm_dlkmimage_intermediates)/odm_dlkm_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_ODM_DLKMIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_ODM_DLKMIMAGE_TARGET),$(BOARD_ODM_DLKMIMAGE_PARTITION_SIZE))
endef
@@ -4424,7 +4420,7 @@
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
$(BUILD_IMAGE) \
$(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),,--input-directory-filter-file $(system_dlkmimage_intermediates)/file_list.txt) \
- $(TARGET_OUT_SYSTEM_DLKM) $(system_dlkmimage_intermediates)/system_dlkm_image_info.txt \
+ $(TARGET_OUT_SYSTEM_DLKM) $(system_dlkmimage_intermediates)/system_dlkm_image_info.txt --build_datetime_file $(BUILD_DATETIME_FILE) \
$(INSTALLED_SYSTEM_DLKMIMAGE_TARGET) $(TARGET_OUT)
$(call assert-max-image-size,$(INSTALLED_SYSTEM_DLKMIMAGE_TARGET),$(BOARD_SYSTEM_DLKMIMAGE_PARTITION_SIZE))
endef
@@ -5168,6 +5164,8 @@
# Run apex_sepolicy_tests for all installed APEXes
ifeq (,$(TARGET_BUILD_UNBUNDLED))
+# TODO(b/353896817) apex_sepolicy_tests supports only ext4
+ifeq (ext4,$(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE))
intermediate := $(call intermediates-dir-for,PACKAGING,apex_sepolicy_tests)
apex_dirs := \
$(TARGET_OUT)/apex/% \
@@ -5207,6 +5205,7 @@
apex_files :=
intermediate :=
+endif # PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE
endif # TARGET_BUILD_UNBUNDLED
# -----------------------------------------------------------------
@@ -5675,6 +5674,7 @@
brotli \
bsdiff \
build_image \
+ build_mixed_kernels_ramdisk_host \
build_super_image \
build_verity_metadata \
build_verity_tree \
@@ -6665,7 +6665,7 @@
@# Contents of the system image
ifneq ($(SOONG_DEFINED_SYSTEM_IMAGE_PATH),)
$(hide) $(call package_files-copy-root, \
- $(SOONG_DEFINED_SYSTEM_IMAGE_BASE)/root/system,$(zip_root)/SYSTEM)
+ $(SOONG_DEFINED_SYSTEM_IMAGE_BASE)/system/system,$(zip_root)/SYSTEM)
else
$(hide) $(call package_files-copy-root, \
$(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 6b83535..f17d8c6 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -48,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))
@@ -73,9 +78,10 @@
$(call soong_config_set_bool,art_module,art_build_host_debug,$(if $(filter false,$(ART_BUILD_HOST_DEBUG)),false,true))
# For chre
-$(call soong_config_set_bool,chre,chre_daemon_lama_enabled,$(if $(filter true,$(CHRE_DAEMON_LPMA_ENABLED)),true,false))
+$(call soong_config_set_bool,chre,chre_daemon_lpma_enabled,$(if $(filter true,$(CHRE_DAEMON_LPMA_ENABLED)),true,false))
$(call soong_config_set_bool,chre,chre_dedicated_transport_channel_enabled,$(if $(filter true,$(CHRE_DEDICATED_TRANSPORT_CHANNEL_ENABLED)),true,false))
$(call soong_config_set_bool,chre,chre_log_atom_extension_enabled,$(if $(filter true,$(CHRE_LOG_ATOM_EXTENSION_ENABLED)),true,false))
+$(call soong_config_set_bool,chre,building_vendor_image,$(if $(filter true,$(BUILDING_VENDOR_IMAGE)),true,false))
ifdef TARGET_BOARD_AUTO
$(call add_soong_config_var_value, ANDROID, target_board_auto, $(TARGET_BOARD_AUTO))
@@ -94,6 +100,9 @@
SYSTEMUI_OPTIMIZE_JAVA ?= true
$(call add_soong_config_var,ANDROID,SYSTEMUI_OPTIMIZE_JAVA)
+# Flag for enabling compose for Launcher.
+$(call soong_config_set,ANDROID,release_enable_compose_in_launcher,$(RELEASE_ENABLE_COMPOSE_IN_LAUNCHER))
+
ifdef PRODUCT_AVF_ENABLED
$(call add_soong_config_var_value,ANDROID,avf_enabled,$(PRODUCT_AVF_ENABLED))
endif
@@ -193,10 +202,24 @@
# Required as platform_bootclasspath is using this namespace
$(call soong_config_set,bootclasspath,release_crashrecovery_module,$(RELEASE_CRASHRECOVERY_MODULE))
+# Add uprobestats build flag to soong
+$(call soong_config_set,ANDROID,release_uprobestats_module,$(RELEASE_UPROBESTATS_MODULE))
+# Add uprobestats file move flags to soong, for both platform and module
+ifeq (true,$(RELEASE_UPROBESTATS_FILE_MOVE))
+ $(call soong_config_set,ANDROID,uprobestats_files_in_module,true)
+ $(call soong_config_set,ANDROID,uprobestats_files_in_platform,false)
+else
+ $(call soong_config_set,ANDROID,uprobestats_files_in_module,false)
+ $(call soong_config_set,ANDROID,uprobestats_files_in_platform,true)
+endif
+
# Enable Profiling module. Also used by platform_bootclasspath.
$(call soong_config_set,ANDROID,release_package_profiling_module,$(RELEASE_PACKAGE_PROFILING_MODULE))
$(call soong_config_set,bootclasspath,release_package_profiling_module,$(RELEASE_PACKAGE_PROFILING_MODULE))
+# Move VCN from platform to the Tethering module; used by both platform and module
+$(call soong_config_set,ANDROID,is_vcn_in_mainline,$(RELEASE_MOVE_VCN_TO_MAINLINE))
+
# Add perf-setup build flag to soong
# Note: BOARD_PERFSETUP_SCRIPT location must be under platform_testing/scripts/perf-setup/.
ifdef BOARD_PERFSETUP_SCRIPT
@@ -230,21 +253,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))
@@ -277,3 +285,18 @@
$(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))
+
+# Variables for hwcomposer.$(TARGET_BOARD_PLATFORM)
+$(call soong_config_set_bool,google_graphics,board_uses_hwc_services,$(if $(filter true,$(BOARD_USES_HWC_SERVICES)),true,false))
+
+# Variables for controlling android.hardware.composer.hwc3-service.pixel
+$(call soong_config_set,google_graphics,board_hwc_version,$(BOARD_HWC_VERSION))
+
+# Variables for extra branches
+# TODO(b/383238397): Use bootstrap_go_package to enable extra flags.
+-include vendor/google/build/extra_soong_config_vars.mk
diff --git a/core/board_config.mk b/core/board_config.mk
index ea0d022..ad89c03 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -291,6 +291,7 @@
include $(BUILD_SYSTEM)/board_config_wifi.mk
# Set up soong config for "soong_config_value_variable".
+-include hardware/interfaces/configstore/1.1/default/surfaceflinger.mk
-include vendor/google/build/soong/soong_config_namespace/camera.mk
# Default *_CPU_VARIANT_RUNTIME to CPU_VARIANT if unspecified.
diff --git a/core/config.mk b/core/config.mk
index 485e8cc..20ebeeb 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.
@@ -718,8 +730,8 @@
PROGUARD_HOME := external/proguard
PROGUARD := $(PROGUARD_HOME)/bin/proguard.sh
PROGUARD_DEPS := $(PROGUARD) $(PROGUARD_HOME)/lib/proguard.jar
-JAVATAGS := build/make/tools/java-event-log-tags.py
-MERGETAGS := build/make/tools/merge-event-log-tags.py
+JAVATAGS := $(HOST_OUT_EXECUTABLES)/java-event-log-tags
+MERGETAGS := $(HOST_OUT_EXECUTABLES)/merge-event-log-tags
APPEND2SIMG := $(HOST_OUT_EXECUTABLES)/append2simg
VERITY_SIGNER := $(HOST_OUT_EXECUTABLES)/verity_signer
BUILD_VERITY_METADATA := $(HOST_OUT_EXECUTABLES)/build_verity_metadata
@@ -1307,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..1ab6388 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -1555,7 +1555,7 @@
define transform-logtags-to-java
@mkdir -p $(dir $@)
@echo "logtags: $@ <= $<"
-$(hide) $(JAVATAGS) -o $@ $< $(PRIVATE_MERGED_TAG)
+$(hide) $(JAVATAGS) -o $@ $<
endef
@@ -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.mk b/core/java.mk
index 5fbc916..41a1b1b 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -140,8 +140,7 @@
logtags_java_sources := $(patsubst %.logtags,%.java,$(addprefix $(intermediates.COMMON)/logtags/, $(logtags_sources)))
logtags_sources := $(addprefix $(LOCAL_PATH)/, $(logtags_sources))
-$(logtags_java_sources): PRIVATE_MERGED_TAG := $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
-$(logtags_java_sources): $(intermediates.COMMON)/logtags/%.java: $(LOCAL_PATH)/%.logtags $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt $(JAVATAGS) build/make/tools/event_log_tags.py
+$(logtags_java_sources): $(intermediates.COMMON)/logtags/%.java: $(LOCAL_PATH)/%.logtags $(JAVATAGS)
$(transform-logtags-to-java)
else
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 06735df..dabcfb2 100644
--- a/core/layoutlib_data.mk
+++ b/core/layoutlib_data.mk
@@ -106,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.
@@ -135,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)) \
@@ -163,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 f96cf04..624df49 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1399,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/packaging/flags.mk b/core/packaging/flags.mk
index ccb502c..fd9dc9b 100644
--- a/core/packaging/flags.mk
+++ b/core/packaging/flags.mk
@@ -24,10 +24,11 @@
# -----------------------------------------------------------------
# Aconfig Flags
-# Create a summary file of build flags for each partition
+# Create a summary file of build flags for a single partition
# $(1): built aconfig flags file (out)
# $(2): installed aconfig flags file (out)
# $(3): the partition (in)
+# $(4): input aconfig files for the partition (in)
define generate-partition-aconfig-flag-file
$(eval $(strip $(1)): PRIVATE_OUT := $(strip $(1)))
$(eval $(strip $(1)): PRIVATE_IN := $(strip $(4)))
@@ -35,7 +36,8 @@
mkdir -p $$(dir $$(PRIVATE_OUT))
$$(if $$(PRIVATE_IN), \
$$(ACONFIG) dump --dedup --format protobuf --out $$(PRIVATE_OUT) \
- --filter container:$(strip $(3)) \
+ --filter container:$(strip $(3))+state:ENABLED \
+ --filter container:$(strip $(3))+permission:READ_WRITE \
$$(addprefix --cache ,$$(PRIVATE_IN)), \
echo -n > $$(PRIVATE_OUT) \
)
diff --git a/core/product.mk b/core/product.mk
index 9c567c3..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
diff --git a/core/product_config.mk b/core/product_config.mk
index abe6e38..f93b63c 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -468,17 +468,26 @@
$(eval SANITIZER.$(TARGET_PRODUCT).$(m).CONFIG := $(cf))))
_psmc_modules :=
-# Reset ADB keys for non-debuggable builds
-ifeq (,$(filter eng userdebug,$(TARGET_BUILD_VARIANT)))
+# Reset ADB keys. If RELEASE_BUILD_USE_VARIANT_FLAGS is set look for
+# the value of a dedicated flag. Otherwise check if build variant is
+# non-debuggable.
+ifneq (,$(RELEASE_BUILD_USE_VARIANT_FLAGS))
+ifneq (,$(RELEASE_BUILD_PURGE_PRODUCT_ADB_KEYS))
PRODUCT_ADB_KEYS :=
endif
+else ifeq (,$(filter eng userdebug,$(TARGET_BUILD_VARIANT)))
+ PRODUCT_ADB_KEYS :=
+endif
+
ifneq ($(filter-out 0 1,$(words $(PRODUCT_ADB_KEYS))),)
$(error Only one file may be in PRODUCT_ADB_KEYS: $(PRODUCT_ADB_KEYS))
endif
# Show a warning wall of text if non-compliance-GSI products set this option.
ifdef PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT
- ifeq (,$(filter gsi_arm gsi_arm64 gsi_x86 gsi_x86_64 gsi_car_arm64 gsi_car_x86_64 gsi_tv_arm gsi_tv_arm64,$(PRODUCT_NAME)))
+ ifeq (,$(filter gsi_arm gsi_arm64 gsi_arm64_soong_system gsi_x86 gsi_x86_64 \
+ gsi_x86_64_soong_system gsi_car_arm64 gsi_car_x86_64 \
+ gsi_tv_arm gsi_tv_arm64,$(PRODUCT_NAME)))
$(warning PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT is set but \
PRODUCT_NAME ($(PRODUCT_NAME)) doesn't look like a GSI for compliance \
testing. This is a special configuration for compliance GSI, so do make \
@@ -534,6 +543,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/release_config.mk b/core/release_config.mk
index fe2170e..68e115f 100644
--- a/core/release_config.mk
+++ b/core/release_config.mk
@@ -146,6 +146,9 @@
# This will also set ALL_RELEASE_CONFIGS_FOR_PRODUCT and _used_files for us.
$(eval include $(_flags_file))
$(KATI_extra_file_deps $(OUT_DIR)/release-config $(protobuf_map_files) $(_flags_file))
+ ifneq (,$(_disallow_lunch_use))
+ $(error Release config ${TARGET_RELEASE} is disallowed for build. Please use one of: $(ALL_RELEASE_CONFIGS_FOR_PRODUCT))
+ endif
else
# This is the first pass of product config.
$(eval include $(_flags_varmk))
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_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index df1cf2d..ab9227f 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -224,30 +224,6 @@
include $(BUILD_SYSTEM)/link_type.mk
endif # !LOCAL_IS_HOST_MODULE
-ifeq (,$(filter tests,$(LOCAL_MODULE_TAGS)))
- ifdef LOCAL_SOONG_DEVICE_RRO_DIRS
- $(call append_enforce_rro_sources, \
- $(my_register_name), \
- false, \
- $(LOCAL_FULL_MANIFEST_FILE), \
- $(if $(LOCAL_EXPORT_PACKAGE_RESOURCES),true,false), \
- $(LOCAL_SOONG_DEVICE_RRO_DIRS), \
- vendor \
- )
- endif
-
- ifdef LOCAL_SOONG_PRODUCT_RRO_DIRS
- $(call append_enforce_rro_sources, \
- $(my_register_name), \
- false, \
- $(LOCAL_FULL_MANIFEST_FILE), \
- $(if $(LOCAL_EXPORT_PACKAGE_RESOURCES),true,false), \
- $(LOCAL_SOONG_PRODUCT_RRO_DIRS), \
- product \
- )
- endif
-endif
-
ifdef LOCAL_PREBUILT_COVERAGE_ARCHIVE
my_coverage_dir := $(TARGET_OUT_COVERAGE)/$(patsubst $(PRODUCT_OUT)/%,%,$(my_module_path))
my_coverage_copy_pairs := $(foreach f,$(LOCAL_PREBUILT_COVERAGE_ARCHIVE),$(f):$(my_coverage_dir)/$(notdir $(f)))
diff --git a/core/soong_config.mk b/core/soong_config.mk
index ee6a9f6..ace025e 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -194,6 +194,8 @@
$(call add_json_str, SystemDlkmPath, $(TARGET_COPY_OUT_SYSTEM_DLKM))
$(call add_json_str, OemPath, $(TARGET_COPY_OUT_OEM))
$(call add_json_bool, MinimizeJavaDebugInfo, $(filter true,$(PRODUCT_MINIMIZE_JAVA_DEBUG_INFO)))
+$(call add_json_str, RecoveryPath, $(TARGET_COPY_OUT_RECOVERY))
+$(call add_json_bool, BuildingRecoveryImage, $(BUILDING_RECOVERY_IMAGE))
$(call add_json_bool, UseGoma, $(filter-out false,$(USE_GOMA)))
$(call add_json_bool, UseRBE, $(filter-out false,$(USE_RBE)))
@@ -274,6 +276,7 @@
$(call add_json_str, DeviceCurrentApiLevelForVendorModules, $(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES))
$(call add_json_bool, CompressedApex, $(filter true,$(PRODUCT_COMPRESSED_APEX)))
+$(call add_json_str, DefaultApexPayloadType, $(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE))
$(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
@@ -379,7 +382,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)) \
@@ -397,6 +400,11 @@
$(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, BoardAvbAddHashtreeFooterArgs, $(BOARD_AVB_$(image_type)_ADD_HASHTREE_FOOTER_ARGS)) \
$(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)) \
@@ -422,6 +430,52 @@
$(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_str, OdmSecurityPatch, $(ODM_SECURITY_PATCH))
+ $(call add_json_str, SystemDlkmSecurityPatch, $(SYSTEM_DLKM_SECURITY_PATCH))
+ $(call add_json_str, VendorDlkmSecurityPatch, $(VENDOR_DLKM_SECURITY_PATCH))
+ $(call add_json_str, OdmDlkmSecurityPatch, $(ODM_DLKM_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))
+
+ # super image stuff
+ $(call add_json_bool, ProductUseDynamicPartitions, $(filter true,$(PRODUCT_USE_DYNAMIC_PARTITIONS)))
+ $(call add_json_bool, ProductRetrofitDynamicPartitions, $(filter true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)))
+ $(call add_json_bool, ProductBuildSuperPartition, $(filter true,$(PRODUCT_BUILD_SUPER_PARTITION)))
+ $(call add_json_str, BoardSuperPartitionSize, $(BOARD_SUPER_PARTITION_SIZE))
+ $(call add_json_str, BoardSuperPartitionMetadataDevice, $(BOARD_SUPER_PARTITION_METADATA_DEVICE))
+ $(call add_json_list, BoardSuperPartitionBlockDevices, $(BOARD_SUPER_PARTITION_BLOCK_DEVICES))
+ $(call add_json_map, BoardSuperPartitionGroups)
+ $(foreach group, $(BOARD_SUPER_PARTITION_GROUPS), \
+ $(call add_json_map, $(group)) \
+ $(call add_json_str, GroupSize, $(BOARD_$(call to-upper,$(group))_SIZE)) \
+ $(if $(BOARD_$(call to-upper,$(group))_PARTITION_LIST), \
+ $(call add_json_list, PartitionList, $(BOARD_$(call to-upper,$(group))_PARTITION_LIST))) \
+ $(call end_json_map))
+ $(call end_json_map)
+ $(call add_json_bool, ProductVirtualAbOta, $(filter true,$(PRODUCT_VIRTUAL_AB_OTA)))
+ $(call add_json_bool, ProductVirtualAbOtaRetrofit, $(filter true,$(PRODUCT_VIRTUAL_AB_OTA_RETROFIT)))
+ $(call add_json_bool, AbOtaUpdater, $(filter true,$(AB_OTA_UPDATER)))
+
+ # 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))
@@ -437,7 +491,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)))
@@ -459,6 +512,10 @@
$(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))))
@@ -466,6 +523,28 @@
$(call add_json_list, ProductCopyFiles, $(PRODUCT_COPY_FILES))
+ # Used to generate fsv meta
+ $(call add_json_bool, ProductFsverityGenerateMetadata, $(PRODUCT_FSVERITY_GENERATE_METADATA))
+
+ # Used to generate recovery partition
+ $(call add_json_str, TargetScreenDensity, $(TARGET_SCREEN_DENSITY))
+
+ # Used to generate /recovery/root/build.prop
+ $(call add_json_map, PrivateRecoveryUiProperties)
+ $(call add_json_str, animation_fps, $(TARGET_RECOVERY_UI_ANIMATION_FPS))
+ $(call add_json_str, margin_height, $(TARGET_RECOVERY_UI_MARGIN_HEIGHT))
+ $(call add_json_str, margin_width, $(TARGET_RECOVERY_UI_MARGIN_WIDTH))
+ $(call add_json_str, menu_unusable_rows, $(TARGET_RECOVERY_UI_MENU_UNUSABLE_ROWS))
+ $(call add_json_str, progress_bar_baseline, $(TARGET_RECOVERY_UI_PROGRESS_BAR_BASELINE))
+ $(call add_json_str, touch_low_threshold, $(TARGET_RECOVERY_UI_TOUCH_LOW_THRESHOLD))
+ $(call add_json_str, touch_high_threshold, $(TARGET_RECOVERY_UI_TOUCH_HIGH_THRESHOLD))
+ $(call add_json_str, vr_stereo_offset, $(TARGET_RECOVERY_UI_VR_STEREO_OFFSET))
+ $(call add_json_str, brightness_file, $(TARGET_RECOVERY_UI_BRIGHTNESS_FILE))
+ $(call add_json_str, max_brightness_file, $(TARGET_RECOVERY_UI_MAX_BRIGHTNESS_FILE))
+ $(call add_json_str, brightness_normal_percent, $(TARGET_RECOVERY_UI_BRIGHTNESS_NORMAL))
+ $(call add_json_str, brightness_dimmed_percent, $(TARGET_RECOVERY_UI_BRIGHTNESS_DIMMED))
+ $(call end_json_map)
+
$(call end_json_map)
# For converting vintf_data
diff --git a/core/soong_extra_config.mk b/core/soong_extra_config.mk
index 2ff83a1..8eee50a 100644
--- a/core/soong_extra_config.mk
+++ b/core/soong_extra_config.mk
@@ -80,7 +80,7 @@
$(call add_json_str, ScreenDensity, $(TARGET_SCREEN_DENSITY))
-$(call add_json_bool, UsesVulkan, $(filter true,$(TARGET_USES_VULKAN)))
+$(call add_json_str, UsesVulkan, $(TARGET_USES_VULKAN))
$(call add_json_bool, ZygoteForce64, $(filter true,$(ZYGOTE_FORCE_64)))
diff --git a/core/sysprop.mk b/core/sysprop.mk
index 9b70d1c..c532dd1 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -122,11 +122,19 @@
ifneq ($(strip $(7)), true)
$(hide) $$(call generate-common-build-props,$(call to-lower,$(strip $(1))),$$@)
endif
+ # Make and Soong use different intermediate files to build vendor/build.prop.
+ # Although the sysprop contents are same, the absolute paths of android_info.prop are different.
+ # Print the filename for the intermediate files (files in OUT_DIR).
+ # This helps with validating mk->soong migration of android partitions.
$(hide) $(foreach file,$(strip $(3)),\
if [ -f "$(file)" ]; then\
echo "" >> $$@;\
echo "####################################" >> $$@;\
- echo "# from $(file)" >> $$@;\
+ $(if $(filter $(OUT_DIR)/%,$(file)), \
+ echo "# from $(notdir $(file))" >> $$@;\
+ ,\
+ echo "# from $(file)" >> $$@;\
+ )\
echo "####################################" >> $$@;\
cat $(file) >> $$@;\
fi;)
@@ -183,7 +191,7 @@
endif
BUILD_FINGERPRINT_FILE := $(PRODUCT_OUT)/build_fingerprint.txt
-ifneq (,$(shell mkdir -p $(PRODUCT_OUT) && echo $(BUILD_FINGERPRINT) >$(BUILD_FINGERPRINT_FILE) && grep " " $(BUILD_FINGERPRINT_FILE)))
+ifneq (,$(shell mkdir -p $(PRODUCT_OUT) && echo $(BUILD_FINGERPRINT) >$(BUILD_FINGERPRINT_FILE).tmp && (if ! cmp -s $(BUILD_FINGERPRINT_FILE).tmp $(BUILD_FINGERPRINT_FILE); then mv $(BUILD_FINGERPRINT_FILE).tmp $(BUILD_FINGERPRINT_FILE); else rm $(BUILD_FINGERPRINT_FILE).tmp; fi) && grep " " $(BUILD_FINGERPRINT_FILE)))
$(error BUILD_FINGERPRINT cannot contain spaces: "$(file <$(BUILD_FINGERPRINT_FILE))")
endif
BUILD_FINGERPRINT_FROM_FILE := $$(cat $(BUILD_FINGERPRINT_FILE))
@@ -301,22 +309,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/mcts.mk b/core/tasks/mcts.mk
index 09a4191..02e916a 100644
--- a/core/tasks/mcts.mk
+++ b/core/tasks/mcts.mk
@@ -15,7 +15,8 @@
ifneq ($(wildcard test/mts/README.md),)
mcts_test_suites :=
-mcts_test_suites += mcts
+mcts_all_test_suites :=
+mcts_all_test_suites += mcts
$(foreach module, $(mts_modules), $(eval mcts_test_suites += mcts-$(module)))
@@ -29,4 +30,14 @@
$(eval $(call dist-for-goals, $(suite), $(compatibility_zip))) \
)
+$(foreach suite, $(mcts_all_test_suites), \
+ $(eval test_suite_name := $(suite)) \
+ $(eval test_suite_tradefed := mcts-tradefed) \
+ $(eval test_suite_readme := test/mts/README.md) \
+ $(eval include $(BUILD_SYSTEM)/tasks/tools/compatibility.mk) \
+ $(eval .PHONY: $(suite)) \
+ $(eval $(suite): $(compatibility_zip)) \
+ $(eval $(call dist-for-goals, $(suite), $(compatibility_zip))) \
+)
+
endif
diff --git a/core/tasks/tools/compatibility.mk b/core/tasks/tools/compatibility.mk
index 9189c2d..f205cea 100644
--- a/core/tasks/tools/compatibility.mk
+++ b/core/tasks/tools/compatibility.mk
@@ -27,7 +27,6 @@
# compatibility_zip: the path to the output zip file.
special_mts_test_suites :=
-special_mts_test_suites += mcts
special_mts_test_suites += $(mts_modules)
ifneq ($(filter $(special_mts_test_suites),$(patsubst mcts-%,%,$(test_suite_name))),)
test_suite_subdir := android-mts
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/core/version_util.mk b/core/version_util.mk
index 0e34634..2bf41ec 100644
--- a/core/version_util.mk
+++ b/core/version_util.mk
@@ -23,6 +23,7 @@
# PLATFORM_DISPLAY_VERSION
# PLATFORM_SDK_VERSION
# PLATFORM_SDK_EXTENSION_VERSION
+# PLATFORM_BASE_SDK_EXTENSION_VERSION
# PLATFORM_VERSION_CODENAME
# DEFAULT_APP_TARGET_SDK
# BUILD_ID
@@ -67,8 +68,16 @@
PLATFORM_SDK_EXTENSION_VERSION := $(RELEASE_PLATFORM_SDK_EXTENSION_VERSION)
.KATI_READONLY := PLATFORM_SDK_EXTENSION_VERSION
-# This is the sdk extension version that PLATFORM_SDK_VERSION ships with.
-PLATFORM_BASE_SDK_EXTENSION_VERSION := $(PLATFORM_SDK_EXTENSION_VERSION)
+ifdef PLATFORM_BASE_SDK_EXTENSION_VERSION
+ $(error Do not set PLATFORM_BASE_SDK_EXTENSION_VERSION directly. Use RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION. value: $(PLATFORM_BASE_SDK_EXTENSION_VERSION))
+endif
+ifdef RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION
+ # This is the sdk extension version that PLATFORM_SDK_VERSION ships with.
+ PLATFORM_BASE_SDK_EXTENSION_VERSION := $(RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION)
+else
+ # Fallback to PLATFORM_SDK_EXTENSION_VERSION if RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION is undefined.
+ PLATFORM_BASE_SDK_EXTENSION_VERSION := $(PLATFORM_SDK_EXTENSION_VERSION)
+endif
.KATI_READONLY := PLATFORM_BASE_SDK_EXTENSION_VERSION
ifdef PLATFORM_VERSION_CODENAME
diff --git a/shell_utils.sh b/shell_utils.sh
index 9053c42..3124db5 100644
--- a/shell_utils.sh
+++ b/shell_utils.sh
@@ -214,3 +214,19 @@
' SIGINT SIGTERM SIGQUIT EXIT
}
+# Import the build variables supplied as arguments into this shell's environment.
+# For absolute variables, prefix the variable name with a '/'. For example:
+# import_build_vars OUT_DIR DIST_DIR /HOST_OUT_EXECUTABLES
+# Returns nonzero if the build command failed. Stderr is passed through.
+function import_build_vars()
+{
+ require_top
+ local script
+ script=$(cd $TOP && build/soong/bin/get_build_vars "$@")
+ local ret=$?
+ if [ $ret -ne 0 ] ; then
+ return $ret
+ fi
+ eval "$script"
+ return $?
+}
diff --git a/target/board/BoardConfigGsiCommon.mk b/target/board/BoardConfigGsiCommon.mk
index 67e31df..8a62796 100644
--- a/target/board/BoardConfigGsiCommon.mk
+++ b/target/board/BoardConfigGsiCommon.mk
@@ -69,6 +69,11 @@
BOARD_SUPER_PARTITION_GROUPS := gsi_dynamic_partitions
BOARD_GSI_DYNAMIC_PARTITIONS_PARTITION_LIST := system
BOARD_GSI_DYNAMIC_PARTITIONS_SIZE := 3221225472
+
+# Build pvmfw with GSI: b/376363989
+ifeq (true,$(PRODUCT_BUILD_PVMFW_IMAGE))
+BOARD_PVMFWIMAGE_PARTITION_SIZE := 0x00100000
+endif
endif
# TODO(b/123695868, b/146149698):
diff --git a/target/product/app_function_extensions.mk b/target/product/app_function_extensions.mk
new file mode 100644
index 0000000..a61afdc
--- /dev/null
+++ b/target/product/app_function_extensions.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+# The app function sidecar extensions
+
+# /system_ext packages
+PRODUCT_PACKAGES += \
+ com.google.android.appfunctions.sidecar \
+ appfunctions.sidecar.xml
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 3a7256e..52498ee 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -17,7 +17,6 @@
# Base modules and settings for the system partition.
PRODUCT_PACKAGES += \
abx \
- aconfigd \
aconfigd-system \
adbd_system_api \
aflags \
@@ -97,7 +96,6 @@
enhanced-confirmation.xml \
ExtShared \
flags_health_check \
- framework-connectivity-b \
framework-graphics \
framework-location \
framework-minus-apex \
@@ -180,6 +178,7 @@
libmedia \
libmedia_jni \
libmediandk \
+ libmonkey_jni \
libmtp \
libnetd_client \
libnetlink \
@@ -206,6 +205,7 @@
libstdc++ \
libsysutils \
libui \
+ libuprobestats_client \
libusbhost \
libutils \
libvintf_jni \
@@ -249,6 +249,7 @@
pintool \
platform.xml \
pm \
+ prefetch \
preinstalled-packages-asl-files.xml \
preinstalled-packages-platform.xml \
preinstalled-packages-strict-signature.xml \
@@ -294,7 +295,6 @@
uiautomator \
uinput \
uncrypt \
- uprobestats \
usbd \
vdc \
vintf \
@@ -312,6 +312,17 @@
endif
+# When we release uprobestats module
+ifeq ($(RELEASE_UPROBESTATS_MODULE),true)
+ PRODUCT_PACKAGES += \
+ com.android.uprobestats \
+
+else
+ PRODUCT_PACKAGES += \
+ uprobestats \
+
+endif
+
# These packages are not used on Android TV
ifneq ($(PRODUCT_IS_ATV),true)
PRODUCT_PACKAGES += \
@@ -348,6 +359,13 @@
com.android.webview.bootstrap
endif
+# Only add the jar when it is not in the Tethering module. Otherwise,
+# it will be added via com.android.tethering
+ifneq ($(RELEASE_MOVE_VCN_TO_MAINLINE),true)
+ PRODUCT_PACKAGES += \
+ framework-connectivity-b
+endif
+
ifneq (,$(RELEASE_RANGING_STACK))
PRODUCT_PACKAGES += \
com.android.ranging
diff --git a/target/product/build_variables.mk b/target/product/build_variables.mk
index 7661e06..e99ab06 100644
--- a/target/product/build_variables.mk
+++ b/target/product/build_variables.mk
@@ -20,6 +20,12 @@
# Control libbinder client caching
$(call soong_config_set, libbinder, release_libbinder_client_cache, $(RELEASE_LIBBINDER_CLIENT_CACHE))
+# Control caching while adding service in libbinder cache
+$(call soong_config_set, libbinder, release_libbinder_addservice_cache, $(RELEASE_LIBBINDER_ADDSERVICE_CACHE))
+
+# Remove static list in libbinder cache
+$(call soong_config_set, libbinder, release_libbinder_remove_cache_static_list, $(RELEASE_LIBBINDER_REMOVE_CACHE_STATIC_LIST))
+
# Use the configured release of sqlite
$(call soong_config_set, libsqlite3, release_package_libsqlite3, $(RELEASE_PACKAGE_LIBSQLITE3))
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index 83d9215..d857e04 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -51,7 +51,6 @@
framework-minus-apex \
framework-graphics \
framework-location \
- framework-connectivity-b \
ext \
telephony-common \
voip-common \
@@ -121,6 +120,17 @@
$(call soong_config_set,bootclasspath,release_ranging_stack,true)
endif
+# Check if VCN should be built into the tethering module or not
+ifeq ($(RELEASE_MOVE_VCN_TO_MAINLINE),true)
+ PRODUCT_APEX_BOOT_JARS += \
+ com.android.tethering:framework-connectivity-b \
+
+else
+ PRODUCT_BOOT_JARS += \
+ framework-connectivity-b \
+
+endif
+
# List of system_server classpath jars delivered via apex.
# Keep the list sorted by module names and then library names.
# Note: For modules available in Q, DO NOT add new entries here.
diff --git a/target/product/generic/Android.bp b/target/product/generic/Android.bp
index ea49af4..1b585d8 100644
--- a/target/product/generic/Android.bp
+++ b/target/product/generic/Android.bp
@@ -56,10 +56,6 @@
name: "bugreports",
},
{
- target: "/data/cache",
- name: "cache",
- },
- {
target: "/sys/kernel/debug",
name: "d",
},
@@ -125,6 +121,10 @@
target: "/system_ext",
name: "system/system_ext",
},
+ {
+ target: "/data/cache",
+ name: "cache",
+ },
]
filegroup {
@@ -346,11 +346,6 @@
],
}
-filegroup {
- name: "system_image_erofs_compress_hints.txt",
- srcs: ["erofs_compress_hints.txt"],
-}
-
android_filesystem_defaults {
name: "system_image_defaults",
partition_name: "system",
@@ -374,11 +369,6 @@
],
libs: [":framework-res{.export-package.apk}"],
},
- type: "erofs",
- erofs: {
- compressor: "lz4hc,9",
- compress_hints: ":system_image_erofs_compress_hints.txt",
- },
build_logtags: true,
gen_aconfig_flags_pb: true,
@@ -391,7 +381,6 @@
deps: [
"abx",
- "aconfigd",
"aconfigd-system",
"aflags",
"am",
@@ -510,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
@@ -715,7 +705,6 @@
"framework-graphics", // base_system
"framework-location", // base_system
"framework-minus-apex-install-dependencies", // base_system
- "framework-connectivity-b", // base_system
"framework_compatibility_matrix.device.xml",
"generic_system_fonts", // ok
"hwservicemanager_compat_symlink_module", // base_system
@@ -744,11 +733,21 @@
"com.android.profiling", // base_system (RELEASE_PACKAGE_PROFILING_MODULE)
],
default: [],
+ }) + select(release_flag("RELEASE_MOVE_VCN_TO_MAINLINE"), {
+ true: [],
+ default: [
+ "framework-connectivity-b", // base_system
+ ],
}) + select(release_flag("RELEASE_AVATAR_PICKER_APP"), {
true: [
"AvatarPicker", // generic_system (RELEASE_AVATAR_PICKER_APP)
],
default: [],
+ }) + select(release_flag("RELEASE_UPROBESTATS_MODULE"), {
+ true: [
+ "com.android.uprobestats", // base_system (RELEASE_UPROBESTATS_MODULE)
+ ],
+ default: [],
}),
},
prefer32: {
@@ -763,7 +762,12 @@
"android.system.virtualizationservice-ndk",
"libgsi",
"servicemanager",
- ],
+ ] + select(release_flag("RELEASE_UPROBESTATS_MODULE"), {
+ true: [],
+ default: [
+ "uprobestats", // base_system internal
+ ],
+ }),
},
both: {
deps: [
@@ -836,6 +840,7 @@
"libmedia_jni", // base_system
"libmediandk", // base_system
"libminui", // generic_system
+ "libmonkey_jni", // base_system - internal
"libmtp", // base_system
"libnetd_client", // base_system
"libnetlink", // base_system
@@ -879,14 +884,32 @@
}) + select(soong_config_variable("ANDROID", "TARGET_DYNAMIC_64_32_MEDIASERVER"), {
"true": ["mediaserver"],
default: [],
+ }) + select(release_flag("RELEASE_UPROBESTATS_MODULE"), {
+ true: [],
+ default: [
+ "libuprobestats_client", // base_system internal
+ ],
}),
},
},
+ arch: {
+ arm64: {
+ deps: [
+ "libclang_rt.hwasan",
+ "libc_hwasan",
+ ],
+ },
+ },
}
android_system_image {
- name: "generic_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 1b8f2d7..9e8946d 100644
--- a/target/product/gsi/Android.bp
+++ b/target/product/gsi/Android.bp
@@ -71,12 +71,21 @@
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
@@ -196,4 +205,5 @@
"true": true,
default: false,
}),
+ type: "ext4",
}
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index f771916..cbb8a0e 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -24,7 +24,7 @@
VNDK-SP: android.hardware.common-V2-ndk.so
VNDK-SP: android.hardware.common.fmq-V1-ndk.so
VNDK-SP: android.hardware.graphics.allocator-V2-ndk.so
-VNDK-SP: android.hardware.graphics.common-V5-ndk.so
+VNDK-SP: android.hardware.graphics.common-V6-ndk.so
VNDK-SP: android.hardware.graphics.common@1.0.so
VNDK-SP: android.hardware.graphics.common@1.1.so
VNDK-SP: android.hardware.graphics.common@1.2.so
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index 39428d2..115b355 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -79,9 +79,15 @@
PRODUCT_BUILD_SYSTEM_DLKM_IMAGE := false
PRODUCT_EXPORT_BOOT_IMAGE_TO_DIST := true
+# Build pvmfw with GSI: b/376363989, pvmfw currently only supports AArch64
+ifneq (,$(filter %_arm64,$(TARGET_PRODUCT)))
+PRODUCT_BUILD_PVMFW_IMAGE := true
+endif
+
# Additional settings used in all GSI builds
PRODUCT_PRODUCT_PROPERTIES += \
ro.crypto.metadata_init_delete_all_keys.enabled=false \
+ debug.codec2.bqpool_dealloc_after_stop=1 \
# Window Extensions
ifneq ($(PRODUCT_IS_ATV),true)
diff --git a/target/product/handheld_system.mk b/target/product/handheld_system.mk
index 546bbe7..2b055c7 100644
--- a/target/product/handheld_system.mk
+++ b/target/product/handheld_system.mk
@@ -69,13 +69,19 @@
SharedStorageBackup \
SimAppDialog \
Telecom \
- TelephonyProvider \
TeleService \
Traceur \
UserDictionaryProvider \
VpnDialogs \
vr \
+# Choose the correct products based on HSUM status
+ifeq ($(PRODUCT_USE_HSUM),true)
+ PRODUCT_PACKAGES += TelephonyProviderHsum
+else
+ PRODUCT_PACKAGES += TelephonyProvider
+endif
+
PRODUCT_PACKAGES += $(RELEASE_PACKAGE_VIRTUAL_CAMERA)
# Set virtual_camera_service_enabled soong config variable based on the
# RELEASE_PACKAGE_VIRTUAL_CAMERA build. virtual_camera_service_enabled soong config
diff --git a/target/product/hsum_common.mk b/target/product/hsum_common.mk
new file mode 100644
index 0000000..b19bc65
--- /dev/null
+++ b/target/product/hsum_common.mk
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+# Contains common default elements for devices running in Headless System User Mode.
+
+# Should generally be inherited first as using an HSUM configuration can affect downstream choices
+# (such as ensuring that the HSUM-variants of packages are selected).
+
+PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
+ ro.fw.mu.headless_system_user=true
+
+# Variable for elsewhere choosing the appropriate products based on HSUM status.
+PRODUCT_USE_HSUM := true
+
+PRODUCT_PACKAGES += \
+ HsumDefaultConfigOverlay
diff --git a/target/product/media_system_ext.mk b/target/product/media_system_ext.mk
index e79a7eb..1179966 100644
--- a/target/product/media_system_ext.mk
+++ b/target/product/media_system_ext.mk
@@ -22,3 +22,8 @@
# Window Extensions
$(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions_base.mk)
+
+# AppFunction Extensions
+ifneq (,$(RELEASE_APPFUNCTION_SIDECAR))
+ $(call inherit-product, $(SRC_TARGET_DIR)/product/app_function_extensions.mk)
+endif
diff --git a/target/product/security/Android.bp b/target/product/security/Android.bp
index ffbec06..214c009 100644
--- a/target/product/security/Android.bp
+++ b/target/product/security/Android.bp
@@ -33,7 +33,13 @@
// image
otacerts_zip {
name: "otacerts",
- recovery_available: true,
+ relative_install_path: "security",
+ filename: "otacerts.zip",
+}
+
+otacerts_zip {
+ name: "otacerts.recovery",
+ recovery: true,
relative_install_path: "security",
filename: "otacerts.zip",
}
diff --git a/target/product/security/BUILD.bazel b/target/product/security/BUILD.bazel
deleted file mode 100644
index c12be79..0000000
--- a/target/product/security/BUILD.bazel
+++ /dev/null
@@ -1,8 +0,0 @@
-filegroup(
- name = "android_certificate_directory",
- srcs = glob([
- "*.pk8",
- "*.pem",
- ]),
- visibility = ["//visibility:public"],
-)
diff --git a/teams/Android.bp b/teams/Android.bp
index 21f5222..a2b0d14 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
@@ -3458,6 +3367,13 @@
}
team {
+ name: "trendy_team_aaos_display_safety_triage",
+
+ // go/trendy/manage/engineers/6522093663780864
+ trendy_team_id: "6522093663780864",
+}
+
+team {
name: "trendy_team_camera_htc_lg_qualcomm",
// go/trendy/manage/engineers/6332099480911872
diff --git a/tools/Android.bp b/tools/Android.bp
index 59831a6..243cb56 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -123,3 +123,11 @@
"merge-event-log-tags.py",
],
}
+
+python_binary_host {
+ name: "java-event-log-tags",
+ srcs: [
+ "event_log_tags.py",
+ "java-event-log-tags.py",
+ ],
+}
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel
deleted file mode 100644
index 9ec0dce..0000000
--- a/tools/BUILD.bazel
+++ /dev/null
@@ -1,35 +0,0 @@
-py_library(
- name = "event_log_tags",
- srcs = ["event_log_tags.py"],
- imports = ["."],
-)
-
-py_binary(
- name = "java-event-log-tags",
- srcs = ["java-event-log-tags.py"],
- python_version = "PY3",
- visibility = ["//visibility:public"],
- deps = [":event_log_tags"],
-)
-
-py_binary(
- name = "merge-event-log-tags",
- srcs = ["merge-event-log-tags.py"],
- python_version = "PY3",
- visibility = ["//visibility:public"],
- deps = [":event_log_tags"],
-)
-
-py_binary(
- name = "check_elf_file",
- srcs = ["check_elf_file.py"],
- python_version = "PY3",
- visibility = ["//visibility:public"],
-)
-
-py_binary(
- name = "auto_gen_test_config",
- srcs = ["auto_gen_test_config.py"],
- python_version = "PY3",
- visibility = ["//visibility:public"],
-)
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 15e4187..a7f0a4f 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -102,12 +102,14 @@
{
// aconfig_storage file java integration tests
"name": "aconfig_storage_file.test.java"
- }
- ],
- "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/cpp.rs b/tools/aconfig/aconfig/src/codegen/cpp.rs
index 7a9c382..ae18679 100644
--- a/tools/aconfig/aconfig/src/codegen/cpp.rs
+++ b/tools/aconfig/aconfig/src/codegen/cpp.rs
@@ -127,6 +127,26 @@
flag_ids: HashMap<String, u16>,
rw_count: &mut i32,
) -> ClassElement {
+ let no_assigned_offset =
+ (pf.container() == "system" || pf.container() == "vendor" || pf.container() == "product")
+ && pf.permission() == ProtoFlagPermission::READ_ONLY
+ && pf.state() == ProtoFlagState::DISABLED;
+
+ let flag_offset = match flag_ids.get(pf.name()) {
+ Some(offset) => offset,
+ None => {
+ // System/vendor/product RO+disabled flags have no offset in storage files.
+ // Assign placeholder value.
+ if no_assigned_offset {
+ &0
+ }
+ // All other flags _must_ have an offset.
+ else {
+ panic!("{}", format!("missing flag offset for {}", pf.name()));
+ }
+ }
+ };
+
ClassElement {
readwrite_idx: if pf.permission() == ProtoFlagPermission::READ_WRITE {
let index = *rw_count;
@@ -144,7 +164,7 @@
},
flag_name: pf.name().to_string(),
flag_macro: pf.name().to_uppercase(),
- flag_offset: *flag_ids.get(pf.name()).expect("values checked at flag parse time"),
+ flag_offset: *flag_offset,
device_config_namespace: pf.namespace().to_string(),
device_config_flag: codegen::create_device_config_ident(package, pf.name())
.expect("values checked at flag parse time"),
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index bfdf1a7..0d528d2 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -32,6 +32,8 @@
codegen_mode: CodegenMode,
flag_ids: HashMap<String, u16>,
allow_instrumentation: bool,
+ package_fingerprint: u64,
+ new_exported: bool,
) -> Result<Vec<OutputFile>>
where
I: Iterator<Item = ProtoParsedFlag>,
@@ -46,6 +48,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 +59,9 @@
library_exported,
allow_instrumentation,
container,
+ is_platform_container,
+ package_fingerprint: format!("0x{:X}L", package_fingerprint),
+ new_exported,
};
let mut template = TinyTemplate::new();
template.add_template("Flags.java", include_str!("../../templates/Flags.java.template"))?;
@@ -123,6 +129,9 @@
pub library_exported: bool,
pub allow_instrumentation: bool,
pub container: String,
+ pub is_platform_container: bool,
+ pub package_fingerprint: String,
+ pub new_exported: bool,
}
#[derive(Serialize, Debug)]
@@ -152,6 +161,27 @@
) -> FlagElement {
let device_config_flag = codegen::create_device_config_ident(package, pf.name())
.expect("values checked at flag parse time");
+
+ let no_assigned_offset =
+ (pf.container() == "system" || pf.container() == "vendor" || pf.container() == "product")
+ && pf.permission() == ProtoFlagPermission::READ_ONLY
+ && pf.state() == ProtoFlagState::DISABLED;
+
+ let flag_offset = match flag_offsets.get(pf.name()) {
+ Some(offset) => offset,
+ None => {
+ // System/vendor/product RO+disabled flags have no offset in storage files.
+ // Assign placeholder value.
+ if no_assigned_offset {
+ &0
+ }
+ // All other flags _must_ have an offset.
+ else {
+ panic!("{}", format!("missing flag offset for {}", pf.name()));
+ }
+ }
+ };
+
FlagElement {
container: pf.container().to_string(),
default_value: pf.state() == ProtoFlagState::ENABLED,
@@ -159,7 +189,7 @@
device_config_flag,
flag_name: pf.name().to_string(),
flag_name_constant_suffix: pf.name().to_ascii_uppercase(),
- flag_offset: *flag_offsets.get(pf.name()).expect("didnt find package offset :("),
+ flag_offset: *flag_offset,
is_read_write: pf.permission() == ProtoFlagPermission::READ_WRITE,
method_name: format_java_method_name(pf.name()),
properties: format_property_name(pf.namespace()),
@@ -502,6 +532,8 @@
mode,
flag_ids,
true,
+ 5801144784618221668,
+ false,
)
.unwrap();
let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
@@ -513,86 +545,33 @@
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.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);
+ disabledRw = reader.getBooleanFlagValue(0);
+ disabledRwExported = reader.getBooleanFlagValue(1);
+ enabledRw = reader.getBooleanFlagValue(7);
+ disabledRwInOtherNamespace = reader.getBooleanFlagValue(2);
} catch (Exception e) {
- foundPackage = false;
+ Log.e(TAG, e.toString());
+ } catch (NoClassDefFoundError e) {
+ // for mainline module running on older devices.
+ // This should be replaces to version check, after the version bump.
+ Log.e(TAG, e.toString());
}
- 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 +583,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 +592,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 +601,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 +634,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 +688,8 @@
mode,
flag_ids,
true,
+ 5801144784618221668,
+ false,
)
.unwrap();
@@ -918,6 +875,195 @@
}
#[test]
+ fn test_generate_java_code_new_exported() {
+ let parsed_flags = crate::test::parse_test_flags();
+ let mode = CodegenMode::Exported;
+ let modified_parsed_flags =
+ crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
+ let flag_ids =
+ assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap();
+ let generated_files = generate_java_code(
+ crate::test::TEST_PACKAGE,
+ modified_parsed_flags.into_iter(),
+ mode,
+ flag_ids,
+ true,
+ 5801144784618221668,
+ true,
+ )
+ .unwrap();
+
+ let expect_flags_content = r#"
+ package com.android.aconfig.test;
+ /** @hide */
+ public final class Flags {
+ /** @hide */
+ public static final String FLAG_DISABLED_RW_EXPORTED = "com.android.aconfig.test.disabled_rw_exported";
+ /** @hide */
+ public static final String FLAG_ENABLED_FIXED_RO_EXPORTED = "com.android.aconfig.test.enabled_fixed_ro_exported";
+ /** @hide */
+ public static final String FLAG_ENABLED_RO_EXPORTED = "com.android.aconfig.test.enabled_ro_exported";
+ public static boolean disabledRwExported() {
+ return FEATURE_FLAGS.disabledRwExported();
+ }
+ public static boolean enabledFixedRoExported() {
+ return FEATURE_FLAGS.enabledFixedRoExported();
+ }
+ public static boolean enabledRoExported() {
+ return FEATURE_FLAGS.enabledRoExported();
+ }
+ private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
+ }
+ "#;
+
+ let expect_feature_flags_content = r#"
+ package com.android.aconfig.test;
+ /** @hide */
+ public interface FeatureFlags {
+ boolean disabledRwExported();
+ boolean enabledFixedRoExported();
+ boolean enabledRoExported();
+ }
+ "#;
+
+ let expect_feature_flags_impl_content = r#"
+ package com.android.aconfig.test;
+ import android.os.flagging.AconfigPackage;
+ import android.util.Log;
+ /** @hide */
+ public final class FeatureFlagsImpl implements FeatureFlags {
+ private static final String TAG = "com.android.aconfig.test.FeatureFlagsImpl_exported";
+ private static volatile boolean isCached = false;
+ private static boolean disabledRwExported = false;
+ private static boolean enabledFixedRoExported = false;
+ private static boolean enabledRoExported = false;
+ private void init() {
+ try {
+ AconfigPackage reader = AconfigPackage.load("com.android.aconfig.test");
+ disabledRwExported = reader.getBooleanFlagValue("disabled_rw_exported", false);
+ enabledFixedRoExported = reader.getBooleanFlagValue("enabled_fixed_ro_exported", false);
+ enabledRoExported = reader.getBooleanFlagValue("enabled_ro_exported", false);
+ } catch (Exception e) {
+ // pass
+ Log.e(TAG, e.toString());
+ } catch (NoClassDefFoundError e) {
+ // for mainline module running on older devices.
+ // This should be replaces to version check, after the version bump.
+ Log.e(TAG, e.toString());
+ }
+ isCached = true;
+ }
+ @Override
+ public boolean disabledRwExported() {
+ if (!isCached) {
+ init();
+ }
+ return disabledRwExported;
+ }
+ @Override
+ public boolean enabledFixedRoExported() {
+ if (!isCached) {
+ init();
+ }
+ return enabledFixedRoExported;
+ }
+ @Override
+ public boolean enabledRoExported() {
+ if (!isCached) {
+ init();
+ }
+ return enabledRoExported;
+ }
+ }"#;
+
+ let expect_custom_feature_flags_content = r#"
+ package com.android.aconfig.test;
+
+ import java.util.Arrays;
+ import java.util.HashSet;
+ import java.util.List;
+ import java.util.Set;
+ import java.util.function.BiPredicate;
+ import java.util.function.Predicate;
+
+ /** @hide */
+ public class CustomFeatureFlags implements FeatureFlags {
+
+ private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
+
+ public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
+ mGetValueImpl = getValueImpl;
+ }
+
+ @Override
+ public boolean disabledRwExported() {
+ return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
+ FeatureFlags::disabledRwExported);
+ }
+ @Override
+ public boolean enabledFixedRoExported() {
+ return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+ FeatureFlags::enabledFixedRoExported);
+ }
+ @Override
+ public boolean enabledRoExported() {
+ return getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
+ FeatureFlags::enabledRoExported);
+ }
+
+ protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
+ return mGetValueImpl.test(flagName, getter);
+ }
+
+ public List<String> getFlagNames() {
+ return Arrays.asList(
+ Flags.FLAG_DISABLED_RW_EXPORTED,
+ Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+ Flags.FLAG_ENABLED_RO_EXPORTED
+ );
+ }
+
+ private Set<String> mReadOnlyFlagsSet = new HashSet<>(
+ Arrays.asList(
+ ""
+ )
+ );
+ }
+ "#;
+
+ let mut file_set = HashMap::from([
+ ("com/android/aconfig/test/Flags.java", expect_flags_content),
+ ("com/android/aconfig/test/FeatureFlags.java", expect_feature_flags_content),
+ ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_feature_flags_impl_content),
+ (
+ "com/android/aconfig/test/CustomFeatureFlags.java",
+ expect_custom_feature_flags_content,
+ ),
+ (
+ "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
+ EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
+ ),
+ ]);
+
+ for file in generated_files {
+ let file_path = file.path.to_str().unwrap();
+ assert!(file_set.contains_key(file_path), "Cannot find {}", file_path);
+ assert_eq!(
+ None,
+ crate::test::first_significant_code_diff(
+ file_set.get(file_path).unwrap(),
+ &String::from_utf8(file.contents).unwrap()
+ ),
+ "File {} content is not correct",
+ file_path
+ );
+ file_set.remove(file_path);
+ }
+
+ assert!(file_set.is_empty());
+ }
+
+ #[test]
fn test_generate_java_code_test() {
let parsed_flags = crate::test::parse_test_flags();
let mode = CodegenMode::Test;
@@ -931,6 +1077,8 @@
mode,
flag_ids,
true,
+ 5801144784618221668,
+ false,
)
.unwrap();
@@ -1052,6 +1200,8 @@
mode,
flag_ids,
true,
+ 5801144784618221668,
+ false,
)
.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..2bf565a 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -88,6 +88,27 @@
impl TemplateParsedFlag {
#[allow(clippy::nonminimal_bool)]
fn new(package: &str, flag_offsets: HashMap<String, u16>, pf: &ProtoParsedFlag) -> Self {
+ let no_assigned_offset = (pf.container() == "system"
+ || pf.container() == "vendor"
+ || pf.container() == "product")
+ && pf.permission() == ProtoFlagPermission::READ_ONLY
+ && pf.state() == ProtoFlagState::DISABLED;
+
+ let flag_offset = match flag_offsets.get(pf.name()) {
+ Some(offset) => offset,
+ None => {
+ // System/vendor/product RO+disabled flags have no offset in storage files.
+ // Assign placeholder value.
+ if no_assigned_offset {
+ &0
+ }
+ // All other flags _must_ have an offset.
+ else {
+ panic!("{}", format!("missing flag offset for {}", pf.name()));
+ }
+ }
+ };
+
Self {
readwrite: pf.permission() == ProtoFlagPermission::READ_WRITE,
default_value: match pf.state() {
@@ -96,7 +117,7 @@
},
name: pf.name().to_string(),
container: pf.container().to_string(),
- flag_offset: *flag_offsets.get(pf.name()).expect("didnt find package offset :("),
+ flag_offset: *flag_offset,
device_config_namespace: pf.namespace().to_string(),
device_config_flag: codegen::create_device_config_ident(package, pf.name())
.expect("values checked at flag parse time"),
@@ -259,10 +280,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,7 +292,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));
+
+ 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 + 0)
+ .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;
+ }
+ }
+});
+
+/// flag value cache for disabled_rw_exported
+static CACHED_disabled_rw_exported: LazyLock<bool> = LazyLock::new(|| {
// This will be called multiple times. Subsequent calls after the first are noops.
logger::init(
logger::Config::default()
@@ -312,17 +368,10 @@
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 {
+/// flag value cache for disabled_rw_in_other_namespace
+static CACHED_disabled_rw_in_other_namespace: LazyLock<bool> = LazyLock::new(|| {
// This will be called multiple times. Subsequent calls after the first are noops.
logger::init(
logger::Config::default()
@@ -359,65 +408,11 @@
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()
- .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 + 3)
- .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;
- }
- }
- } 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()
@@ -434,7 +429,7 @@
.and_then(|package_offset| {
match package_offset {
Some(offset) => {
- get_boolean_flag_value(&flag_val_map, offset + 8)
+ get_boolean_flag_value(&flag_val_map, offset + 7)
.map_err(|err| format!("failed to get flag: {err}"))
},
None => {
@@ -454,12 +449,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..4c06462 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)?;
@@ -207,6 +218,7 @@
mut input: Input,
codegen_mode: CodegenMode,
allow_instrumentation: bool,
+ new_exported: bool,
) -> Result<Vec<OutputFile>> {
let parsed_flags = input.try_parse_flags()?;
let modified_parsed_flags = modify_parsed_flags_based_on_mode(parsed_flags, codegen_mode)?;
@@ -214,6 +226,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 +236,8 @@
codegen_mode,
flag_ids,
allow_instrumentation,
+ package_fingerprint,
+ new_exported,
)
}
@@ -408,17 +425,28 @@
{
assert!(parsed_flags_iter.clone().tuple_windows().all(|(a, b)| a.name() <= b.name()));
let mut flag_ids = HashMap::new();
- for (id_to_assign, pf) in (0_u32..).zip(parsed_flags_iter) {
+ let mut flag_idx = 0;
+ for pf in parsed_flags_iter {
if package != pf.package() {
return Err(anyhow::anyhow!("encountered a flag not in current package"));
}
// put a cap on how many flags a package can contain to 65535
- if id_to_assign > u16::MAX as u32 {
+ if flag_idx > u16::MAX as u32 {
return Err(anyhow::anyhow!("the number of flags in a package cannot exceed 65535"));
}
- flag_ids.insert(pf.name().to_string(), id_to_assign as u16);
+ // Exclude system/vendor/product flags that are RO+disabled.
+ let should_filter_container = pf.container == Some("vendor".to_string())
+ || pf.container == Some("system".to_string())
+ || pf.container == Some("vendor".to_string());
+ if !(should_filter_container
+ && pf.state == Some(ProtoFlagState::DISABLED.into())
+ && pf.permission == Some(ProtoFlagPermission::READ_ONLY.into()))
+ {
+ flag_ids.insert(pf.name().to_string(), flag_idx as u16);
+ flag_idx += 1;
+ }
}
Ok(flag_ids)
}
@@ -427,14 +455,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 +494,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 +515,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 +525,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 +604,7 @@
declaration,
value,
ProtoFlagPermission::READ_ONLY,
+ true,
)
.unwrap();
let parsed_flags =
@@ -609,6 +638,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -640,6 +670,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -647,6 +678,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 +828,7 @@
declaration,
value,
ProtoFlagPermission::READ_WRITE,
+ true,
)
.unwrap_err();
assert_eq!(
@@ -716,6 +863,7 @@
declaration,
value,
ProtoFlagPermission::READ_ONLY,
+ true,
)
.unwrap();
let parsed_flags =
@@ -756,6 +904,30 @@
}
#[test]
+ fn test_dump_multiple_filters() {
+ let input = parse_test_flags_as_input();
+ let bytes = dump_parsed_flags(
+ vec![input],
+ DumpFormat::Custom("{fully_qualified_name}".to_string()),
+ &["container:system+state:ENABLED", "container:system+permission:READ_WRITE"],
+ false,
+ )
+ .unwrap();
+ let text = std::str::from_utf8(&bytes).unwrap();
+ let expected_flag_list = &[
+ "com.android.aconfig.test.disabled_rw",
+ "com.android.aconfig.test.disabled_rw_exported",
+ "com.android.aconfig.test.disabled_rw_in_other_namespace",
+ "com.android.aconfig.test.enabled_fixed_ro",
+ "com.android.aconfig.test.enabled_fixed_ro_exported",
+ "com.android.aconfig.test.enabled_ro",
+ "com.android.aconfig.test.enabled_ro_exported",
+ "com.android.aconfig.test.enabled_rw",
+ ];
+ assert_eq!(expected_flag_list.map(|s| format!("{}\n", s)).join(""), text);
+ }
+
+ #[test]
fn test_dump_textproto_format_dedup() {
let input = parse_test_flags_as_input();
let input2 = parse_test_flags_as_input();
@@ -817,15 +989,14 @@
let package = find_unique_package(&parsed_flags.parsed_flag).unwrap().to_string();
let flag_ids = assign_flag_ids(&package, parsed_flags.parsed_flag.iter()).unwrap();
let expected_flag_ids = HashMap::from([
- (String::from("disabled_ro"), 0_u16),
- (String::from("disabled_rw"), 1_u16),
- (String::from("disabled_rw_exported"), 2_u16),
- (String::from("disabled_rw_in_other_namespace"), 3_u16),
- (String::from("enabled_fixed_ro"), 4_u16),
- (String::from("enabled_fixed_ro_exported"), 5_u16),
- (String::from("enabled_ro"), 6_u16),
- (String::from("enabled_ro_exported"), 7_u16),
- (String::from("enabled_rw"), 8_u16),
+ (String::from("disabled_rw"), 0_u16),
+ (String::from("disabled_rw_exported"), 1_u16),
+ (String::from("disabled_rw_in_other_namespace"), 2_u16),
+ (String::from("enabled_fixed_ro"), 3_u16),
+ (String::from("enabled_fixed_ro_exported"), 4_u16),
+ (String::from("enabled_ro"), 5_u16),
+ (String::from("enabled_ro_exported"), 6_u16),
+ (String::from("enabled_rw"), 7_u16),
]);
assert_eq!(flag_ids, expected_flag_ids);
}
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index e184efe..288786b 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(
@@ -79,6 +85,12 @@
.long("allow-instrumentation")
.value_parser(clap::value_parser!(bool))
.default_value("false"),
+ )
+ .arg(
+ Arg::new("new-exported")
+ .long("new-exported")
+ .value_parser(clap::value_parser!(bool))
+ .default_value("false"),
),
)
.subcommand(
@@ -242,12 +254,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")?;
@@ -258,8 +273,10 @@
let mode = get_required_arg::<CodegenMode>(sub_matches, "mode")?;
let allow_instrumentation =
get_required_arg::<bool>(sub_matches, "allow-instrumentation")?;
- let generated_files = commands::create_java_lib(cache, *mode, *allow_instrumentation)
- .context("failed to create java lib")?;
+ let new_exported = get_required_arg::<bool>(sub_matches, "new-exported")?;
+ let generated_files =
+ commands::create_java_lib(cache, *mode, *allow_instrumentation, *new_exported)
+ .context("failed to create java lib")?;
let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
generated_files
.iter()
diff --git a/tools/aconfig/aconfig/src/storage/flag_info.rs b/tools/aconfig/aconfig/src/storage/flag_info.rs
index 5d565e8..0943daa 100644
--- a/tools/aconfig/aconfig/src/storage/flag_info.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_info.rs
@@ -16,7 +16,7 @@
use crate::commands::assign_flag_ids;
use crate::storage::FlagPackage;
-use aconfig_protos::ProtoFlagPermission;
+use aconfig_protos::{ProtoFlagPermission, ProtoFlagState};
use aconfig_storage_file::{FlagInfoHeader, FlagInfoList, FlagInfoNode, StorageFileType};
use anyhow::{anyhow, Result};
@@ -36,14 +36,24 @@
packages: &[FlagPackage],
version: u32,
) -> Result<FlagInfoList> {
- // create list
- let num_flags = packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
+ // Exclude system/vendor/product flags that are RO+disabled.
+ let mut filtered_packages = packages.to_vec();
+ if container == "system" || container == "vendor" || container == "product" {
+ for package in filtered_packages.iter_mut() {
+ package.boolean_flags.retain(|b| {
+ !(b.state == Some(ProtoFlagState::DISABLED.into())
+ && b.permission == Some(ProtoFlagPermission::READ_ONLY.into()))
+ });
+ }
+ }
+
+ let num_flags = filtered_packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
let mut is_flag_rw = vec![false; num_flags as usize];
- for pkg in packages.iter() {
+ for pkg in filtered_packages {
let start_index = pkg.boolean_start_index as usize;
let flag_ids = assign_flag_ids(pkg.package_name, pkg.boolean_flags.iter().copied())?;
- for pf in pkg.boolean_flags.iter() {
+ for pf in pkg.boolean_flags {
let fid = flag_ids
.get(pf.name())
.ok_or(anyhow!(format!("missing flag id for {}", pf.name())))?;
@@ -73,7 +83,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)
}
diff --git a/tools/aconfig/aconfig/src/storage/flag_table.rs b/tools/aconfig/aconfig/src/storage/flag_table.rs
index 8856eb6..3b245a7 100644
--- a/tools/aconfig/aconfig/src/storage/flag_table.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_table.rs
@@ -16,7 +16,7 @@
use crate::commands::assign_flag_ids;
use crate::storage::FlagPackage;
-use aconfig_protos::ProtoFlagPermission;
+use aconfig_protos::{ProtoFlagPermission, ProtoFlagState};
use aconfig_storage_file::{
get_table_size, FlagTable, FlagTableHeader, FlagTableNode, StorageFileType, StoredFlagType,
};
@@ -62,9 +62,19 @@
}
fn create_nodes(package: &FlagPackage, num_buckets: u32) -> Result<Vec<Self>> {
+ // Exclude system/vendor/product flags that are RO+disabled.
+ let mut filtered_package = package.clone();
+ filtered_package.boolean_flags.retain(|f| {
+ !((f.container == Some("system".to_string())
+ || f.container == Some("vendor".to_string())
+ || f.container == Some("product".to_string()))
+ && f.permission == Some(ProtoFlagPermission::READ_ONLY.into())
+ && f.state == Some(ProtoFlagState::DISABLED.into()))
+ });
+
let flag_ids =
- assign_flag_ids(package.package_name, package.boolean_flags.iter().copied())?;
- package
+ assign_flag_ids(package.package_name, filtered_package.boolean_flags.iter().copied())?;
+ filtered_package
.boolean_flags
.iter()
.map(|&pf| {
@@ -148,7 +158,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)
}
diff --git a/tools/aconfig/aconfig/src/storage/flag_value.rs b/tools/aconfig/aconfig/src/storage/flag_value.rs
index 0dd5a9d..3cfa447 100644
--- a/tools/aconfig/aconfig/src/storage/flag_value.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_value.rs
@@ -16,7 +16,7 @@
use crate::commands::assign_flag_ids;
use crate::storage::FlagPackage;
-use aconfig_protos::ProtoFlagState;
+use aconfig_protos::{ProtoFlagPermission, ProtoFlagState};
use aconfig_storage_file::{FlagValueHeader, FlagValueList, StorageFileType};
use anyhow::{anyhow, Result};
@@ -36,15 +36,22 @@
packages: &[FlagPackage],
version: u32,
) -> Result<FlagValueList> {
- // create list
- let num_flags = packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
-
+ // Exclude system/vendor/product flags that are RO+disabled.
+ let mut filtered_packages = packages.to_vec();
+ if container == "system" || container == "vendor" || container == "product" {
+ for package in filtered_packages.iter_mut() {
+ package.boolean_flags.retain(|b| {
+ !(b.state == Some(ProtoFlagState::DISABLED.into())
+ && b.permission == Some(ProtoFlagPermission::READ_ONLY.into()))
+ });
+ }
+ }
+ let num_flags = filtered_packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
let mut list = FlagValueList {
header: new_header(container, num_flags, version),
booleans: vec![false; num_flags as usize],
};
-
- for pkg in packages.iter() {
+ for pkg in filtered_packages {
let start_index = pkg.boolean_start_index as usize;
let flag_ids = assign_flag_ids(pkg.package_name, pkg.boolean_flags.iter().copied())?;
for pf in pkg.boolean_flags.iter() {
@@ -72,7 +79,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)
}
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index c7fd55a..61e65d1 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -22,13 +22,15 @@
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,
};
-use aconfig_protos::{ProtoParsedFlag, ProtoParsedFlags};
+use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag, ProtoParsedFlags};
use aconfig_storage_file::StorageFileType;
+#[derive(Clone)]
pub struct FlagPackage<'a> {
pub package_name: &'a str,
pub package_id: u32,
@@ -59,7 +61,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>,
{
@@ -72,17 +74,33 @@
if index == packages.len() {
packages.push(FlagPackage::new(parsed_flag.package(), index as u32));
}
+
+ // Exclude system/vendor/product flags that are RO+disabled.
+ if (parsed_flag.container == Some("system".to_string())
+ || parsed_flag.container == Some("vendor".to_string())
+ || parsed_flag.container == Some("product".to_string()))
+ && parsed_flag.permission == Some(ProtoFlagPermission::READ_ONLY.into())
+ && parsed_flag.state == Some(ProtoFlagState::DISABLED.into())
+ {
+ continue;
+ }
+
packages[index].insert(parsed_flag);
}
}
- // 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;
- // TODO: b/316357686 - Calculate fingerprint and add to package.
+ 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
@@ -97,7 +115,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 => {
@@ -121,6 +139,8 @@
#[cfg(test)]
mod tests {
+ use aconfig_storage_file::DEFAULT_FILE_VERSION;
+
use super::*;
use crate::Input;
@@ -163,6 +183,7 @@
reader: Box::new(value_content),
}],
crate::commands::DEFAULT_FLAG_PERMISSION,
+ true,
)
.unwrap();
aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -173,7 +194,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;
@@ -193,6 +214,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);
@@ -201,6 +223,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);
@@ -208,5 +231,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 e46607b..53daa7f 100644
--- a/tools/aconfig/aconfig/src/storage/package_table.rs
+++ b/tools/aconfig/aconfig/src/storage/package_table.rs
@@ -112,24 +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());
+ 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.unwrap(), expected_package_table);
+
+ 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..8b3d3e1 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -1,61 +1,122 @@
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.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}");
- } catch (Exception e) \{
- foundPackage = false;
- }
- {{ for namespace_with_flags in namespace_flags }}
+{{ if is_platform_container }}
+ PlatformAconfigPackageInternal reader = PlatformAconfigPackageInternal.load("{container}", "{package_name}", {package_fingerprint});
+{{ -else }}
+ AconfigPackageInternal reader = AconfigPackageInternal.load("{container}", "{package_name}", {package_fingerprint});
+{{ -endif }}
+ {{ -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 }}
+ {{ -if flag.is_read_write }}
+ {flag.method_name} = reader.getBooleanFlagValue({flag.flag_offset});
+ {{ -endif }}
{{ -endfor }}
{{ -endfor }}
+ } catch (Exception e) \{
+ Log.e(TAG, e.toString());
+ } catch (NoClassDefFoundError e) \{
+ // for mainline module running on older devices.
+ // This should be replaces to version check, after the version bump.
+ Log.e(TAG, e.toString());
+ }
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 #}
+{{ -if new_exported }}
+import android.os.flagging.AconfigPackage;
+import android.util.Log;
+/** @hide */
+public final class FeatureFlagsImpl implements FeatureFlags \{
+ private static final String TAG = "{package_name}.FeatureFlagsImpl_exported";
+ private static volatile boolean isCached = false;
+{{ for flag in flag_elements }}
+ private static boolean {flag.method_name} = {flag.default_value};
+{{ -endfor }}
+ private void init() \{
+ try \{
+ AconfigPackage reader = AconfigPackage.load("{package_name}");
+ {{ -for namespace_with_flags in namespace_flags }}
+ {{ -for flag in namespace_with_flags.flags }}
+ {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
+ {{ -endfor }}
+ {{ -endfor }}
+ } catch (Exception e) \{
+ // pass
+ Log.e(TAG, e.toString());
+ } catch (NoClassDefFoundError e) \{
+ // for mainline module running on older devices.
+ // This should be replaces to version check, after the version bump.
+ Log.e(TAG, e.toString());
+ }
+ isCached = true;
+ }
+{{ -for flag in flag_elements }}
+ @Override
+ public boolean {flag.method_name}() \{
+ if (!isCached) \{
+ init();
+ }
+ return {flag.method_name};
+ }
+{{ endfor }}
+}
+{{ else }}
+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 +145,18 @@
{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 new_exported mode #}
+{{ -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_flags/flags.aconfig b/tools/aconfig/aconfig_flags/flags.aconfig
index b66d282..367a2d0 100644
--- a/tools/aconfig/aconfig_flags/flags.aconfig
+++ b/tools/aconfig/aconfig_flags/flags.aconfig
@@ -16,9 +16,8 @@
}
flag {
- name: "enable_system_aconfigd_rust"
+ name: "tools_read_from_new_storage"
namespace: "core_experiments_team_internal"
- bug: "378079539"
- description: "When enabled, the aconfigd cc_binary target becomes a no-op, and the rust_binary aconfigd-system target starts up."
- is_fixed_read_only: true
-}
+ bug: "370499640"
+ description: "When enabled, tools read directly from the new aconfig storage."
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_flags/src/lib.rs b/tools/aconfig/aconfig_flags/src/lib.rs
index b413c62..2e89127 100644
--- a/tools/aconfig/aconfig_flags/src/lib.rs
+++ b/tools/aconfig/aconfig_flags/src/lib.rs
@@ -39,11 +39,6 @@
pub fn enable_aconfigd_from_mainline() -> bool {
aconfig_flags_rust::enable_only_new_storage()
}
-
- /// Returns the value for the enable_system_aconfigd_rust flag.
- pub fn enable_system_aconfigd_rust() -> bool {
- aconfig_flags_rust::enable_system_aconfigd_rust()
- }
}
/// Module used when building with cargo
@@ -60,10 +55,4 @@
// Used only to enable typechecking and testing with cargo
true
}
-
- /// Returns a placeholder value for the enable_system_aconfigd_rust flag.
- pub fn enable_system_aconfigd_rust() -> bool {
- // Used only to enable typechecking and testing with cargo
- true
- }
}
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index 1e5b001..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,34 +533,6 @@
};
#[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 =
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
index 55780ed..7c603df 100644
--- a/tools/aconfig/aconfig_storage_file/src/test_utils.rs
+++ b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
@@ -46,14 +46,22 @@
let first_node = PackageTableNode {
package_name: String::from("com.android.aconfig.storage.test_2"),
package_id: 1,
- fingerprint: 0,
+ 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: 0,
+ fingerprint: match version {
+ 1 => 0,
+ 2 => 15248948510590158086u64,
+ _ => panic!("Unsupported version."),
+ },
boolean_start_index: 0,
next_offset: match version {
1 => Some(159),
@@ -64,7 +72,11 @@
let third_node = PackageTableNode {
package_name: String::from("com.android.aconfig.storage.test_4"),
package_id: 2,
- fingerprint: 0,
+ fingerprint: match version {
+ 1 => 0,
+ 2 => 16233229917711622375u64,
+ _ => panic!("Unsupported version."),
+ },
boolean_start_index: 6,
next_offset: None,
};
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/ByteBufferReader.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
index 9571568..1fbcb85 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
@@ -63,4 +63,8 @@
public void position(int newPosition) {
mByteBuffer.position(newPosition);
}
+
+ public int position() {
+ return mByteBuffer.position();
+ }
}
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_file/srcs/android/aconfig/storage/PackageTable.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
index a45d12a..1e7c2ca 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
@@ -19,10 +19,16 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
public class PackageTable {
+ private static final int FINGERPRINT_BYTES = 8;
+ // int: mPackageId + int: mBooleanStartIndex + int: mNextOffset
+ private static final int NODE_SKIP_BYTES = 12;
+
private Header mHeader;
private ByteBufferReader mReader;
@@ -60,6 +66,18 @@
return null;
}
+ public List<String> getPackageList() {
+ List<String> list = new ArrayList<>(mHeader.mNumPackages);
+ mReader.position(mHeader.mNodeOffset);
+ int fingerprintBytes = mHeader.mVersion == 1 ? 0 : FINGERPRINT_BYTES;
+ int skipBytes = fingerprintBytes + NODE_SKIP_BYTES;
+ for (int i = 0; i < mHeader.mNumPackages; i++) {
+ list.add(mReader.readString());
+ mReader.position(mReader.position() + skipBytes);
+ }
+ return list;
+ }
+
public Header getHeader() {
return mHeader;
}
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
index 8306cc6..f75ac36 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
@@ -26,7 +26,10 @@
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 {
@@ -36,13 +39,15 @@
private static final String PMAP_FILE_EXT = ".package.map";
private static final String FMAP_FILE_EXT = ".flag.map";
private static final String VAL_FILE_EXT = ".val";
+ private static final StorageFileProvider DEFAULT_INSTANCE =
+ new StorageFileProvider(DEFAULT_MAP_PATH, DEFAULT_BOOT_PATH);
private final String mMapPath;
private final String mBootPath;
/** @hide */
public static StorageFileProvider getDefaultProvider() {
- return new StorageFileProvider(DEFAULT_MAP_PATH, DEFAULT_BOOT_PATH);
+ return DEFAULT_INSTANCE;
}
/** @hide */
@@ -52,13 +57,20 @@
}
/** @hide */
- public List<Path> listPackageMapFiles() {
- List<Path> result = new ArrayList<>();
+ public List<String> listContainers(String[] excludes) {
+ List<String> result = new ArrayList<>();
+ Set<String> set = new HashSet<>(Arrays.asList(excludes));
+
try {
DirectoryStream<Path> stream =
Files.newDirectoryStream(Paths.get(mMapPath), "*" + PMAP_FILE_EXT);
for (Path entry : stream) {
- result.add(entry);
+ 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;
@@ -72,27 +84,25 @@
/** @hide */
public PackageTable getPackageTable(String container) {
- return getPackageTable(Paths.get(mMapPath, container + PMAP_FILE_EXT));
+ return PackageTable.fromBytes(
+ mapStorageFile(
+ Paths.get(mMapPath, container + PMAP_FILE_EXT), FileType.PACKAGE_MAP));
}
/** @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)));
- }
-
- /** @hide */
- public static PackageTable getPackageTable(Path path) {
- return PackageTable.fromBytes(mapStorageFile(path));
+ mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT), FileType.FLAG_VAL));
}
// 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);
@@ -100,7 +110,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/data/v2/package_v2.map b/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
index 16f4054..0a9f95e 100644
--- a/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
+++ b/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
index 4d7ab2a..812ce35 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
@@ -27,6 +27,9 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.HashSet;
+import java.util.Set;
+
@RunWith(JUnit4.class)
public class PackageTableTest {
@@ -116,5 +119,27 @@
assertTrue(node1.hasPackageFingerprint());
assertTrue(node2.hasPackageFingerprint());
assertTrue(node4.hasPackageFingerprint());
+
+ assertEquals(-3197795563119393530L, node1.getPackageFingerprint());
+ assertEquals(4431940502274857964L, node2.getPackageFingerprint());
+ assertEquals(-2213514155997929241L, node4.getPackageFingerprint());
+ }
+
+ @Test
+ public void testPackageTable_getPackageList() throws Exception {
+ PackageTable packageTable =
+ PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(2));
+ Set<String> packages = new HashSet<>(packageTable.getPackageList());
+ assertEquals(3, packages.size());
+ assertTrue(packages.contains("com.android.aconfig.storage.test_1"));
+ assertTrue(packages.contains("com.android.aconfig.storage.test_2"));
+ assertTrue(packages.contains("com.android.aconfig.storage.test_4"));
+
+ packageTable = PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(1));
+ packages = new HashSet<>(packageTable.getPackageList());
+ assertEquals(3, packages.size());
+ assertTrue(packages.contains("com.android.aconfig.storage.test_1"));
+ assertTrue(packages.contains("com.android.aconfig.storage.test_2"));
+ assertTrue(packages.contains("com.android.aconfig.storage.test_4"));
}
}
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
index 4e90e6c..c2720f9 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
@@ -29,7 +29,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
@@ -37,15 +36,20 @@
public class StorageFileProviderTest {
@Test
- public void testListpackageMapFiles() throws Exception {
+ public void testlistContainers() throws Exception {
StorageFileProvider p =
new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- List<Path> file = p.listPackageMapFiles();
- assertEquals(2, file.size());
+ 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/");
- file = p.listPackageMapFiles();
- assertTrue(file.isEmpty());
+ containers = p.listContainers(excludes);
+ assertTrue(containers.isEmpty());
}
@Test
@@ -54,11 +58,6 @@
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");
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 3238d79..fa41ff0 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -154,39 +154,20 @@
java_library {
name: "aconfig_storage_reader_java",
srcs: [
- "srcs/android/aconfig/storage/AconfigPackageImpl.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/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/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
index 6e98fe9..d3cc9d4 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
@@ -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);
}
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 a4b63ab..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 {
@@ -84,19 +86,58 @@
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);
}
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 6bf4e05..0000000
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
+++ /dev/null
@@ -1,122 +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;
- private final int mPackageId;
- private final int mBooleanStartIndex;
-
- private AconfigPackageImpl(
- FlagTable flagTable,
- FlagValueList flagValueList,
- int packageId,
- int booleanStartIndex) {
- this.mFlagTable = flagTable;
- this.mFlagValueList = flagValueList;
- this.mPackageId = packageId;
- this.mBooleanStartIndex = booleanStartIndex;
- }
-
- public static AconfigPackageImpl load(String packageName, StorageFileProvider fileProvider) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- PackageTable.Node pNode = null;
- try {
- // First try to find the package in the "system" container.
- pNode = fileProvider.getPackageTable("system").get(packageName);
- } catch (Exception e) {
- //
- }
- try {
- if (pNode != null) {
- return new AconfigPackageImpl(
- fileProvider.getFlagTable("system"),
- fileProvider.getFlagValueList("system"),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
-
- // If not found in "system", search all package map files.
- for (Path p : fileProvider.listPackageMapFiles()) {
- PackageTable pTable = fileProvider.getPackageTable(p);
- pNode = pTable.get(packageName);
- if (pNode != null) {
- return new AconfigPackageImpl(
- fileProvider.getFlagTable(pTable.getHeader().getContainer()),
- fileProvider.getFlagValueList(pTable.getHeader().getContainer()),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
- }
- } catch (AconfigStorageException e) {
- // Consider logging the exception.
- throw e;
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- // Package not found.
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
- "Package " + packageName + " not found.");
- }
-
- public static AconfigPackageImpl 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 new AconfigPackageImpl(
- fileProvider.getFlagTable(container),
- fileProvider.getFlagValueList(container),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
- } catch (AconfigStorageException e) {
- // Consider logging the exception.
- throw e;
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
-
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
- "package "
- + packageName
- + " in container "
- + container
- + " cannot be found on the device");
- }
-
- public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
- FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
- if (fNode == null) return defaultValue;
- return mFlagValueList.getBoolean(fNode.getFlagIndex() + mBooleanStartIndex);
- }
-
- public boolean getBooleanFlagValue(int index) {
- return mFlagValueList.getBoolean(index + mBooleanStartIndex);
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java
deleted file mode 100644
index 6fbcdb3..0000000
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java
+++ /dev/null
@@ -1,94 +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.compat.annotation.UnsupportedAppUsage;
-import android.os.StrictMode;
-
-import java.io.Closeable;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-
-/** @hide */
-public class StorageInternalReader {
-
- private static final String MAP_PATH = "/metadata/aconfig/maps/";
- private static final String BOOT_PATH = "/metadata/aconfig/boot/";
-
- private PackageTable mPackageTable;
- private FlagValueList mFlagValueList;
-
- private int mPackageBooleanStartOffset;
-
- @UnsupportedAppUsage
- public StorageInternalReader(String container, String packageName) {
- this(packageName, MAP_PATH + container + ".package.map", BOOT_PATH + container + ".val");
- }
-
- @UnsupportedAppUsage
- public StorageInternalReader(String packageName, String packageMapFile, String flagValueFile) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- mPackageTable = PackageTable.fromBytes(mapStorageFile(packageMapFile));
- mFlagValueList = FlagValueList.fromBytes(mapStorageFile(flagValueFile));
- StrictMode.setThreadPolicy(oldPolicy);
- mPackageBooleanStartOffset = getPackageBooleanStartOffset(packageName);
- }
-
- @UnsupportedAppUsage
- public boolean getBooleanFlagValue(int index) {
- index += mPackageBooleanStartOffset;
- return mFlagValueList.getBoolean(index);
- }
-
- private int getPackageBooleanStartOffset(String packageName) {
- PackageTable.Node pNode = mPackageTable.get(packageName);
- if (pNode == null) {
- PackageTable.Header header = mPackageTable.getHeader();
- throw new AconfigStorageException(
- String.format(
- "Fail to get package %s from container %s",
- packageName, header.getContainer()));
- }
- return pNode.getBooleanStartIndex();
- }
-
- // Map a storage file given file path
- private static MappedByteBuffer mapStorageFile(String file) {
- FileChannel channel = null;
- try {
- channel = FileChannel.open(Paths.get(file), StandardOpenOption.READ);
- return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
- } catch (Exception e) {
- throw new AconfigStorageException(
- String.format("Fail to mmap storage file %s", file), e);
- } finally {
- quietlyDispose(channel);
- }
- }
-
- private static void quietlyDispose(Closeable closable) {
- try {
- if (closable != null) {
- closable.close();
- }
- } catch (Exception e) {
- // no need to care, at least as of now
- }
- }
-}
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..854e68b
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,133 @@
+/*
+ * 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.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 FlagValueList mFlagValueList;
+ private final int mPackageBooleanStartOffset;
+
+ private PlatformAconfigPackageInternal(
+ FlagValueList flagValueList, int packageBooleanStartOffset) {
+ this.mFlagValueList = flagValueList;
+ this.mPackageBooleanStartOffset = packageBooleanStartOffset;
+ }
+
+ /**
+ * 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.
+ *
+ * @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();
+ PackageTable.Node pNode = null;
+ FlagValueList vList = null;
+ try {
+ pNode = fileProvider.getPackageTable(container).get(packageName);
+ vList = fileProvider.getFlagValueList(container);
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+
+ if (pNode == null || vList == null) {
+ throw new AconfigStorageException(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ String.format(
+ "package "
+ + packageName
+ + " in container "
+ + container
+ + " cannot be found on the device"));
+ }
+
+ if (pNode.hasPackageFingerprint() && packageFingerprint != pNode.getPackageFingerprint()) {
+ throw new AconfigStorageException(
+ AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ String.format(
+ "package "
+ + packageName
+ + " in container "
+ + container
+ + " cannot be found on the device"));
+ }
+
+ return new PlatformAconfigPackageInternal(vList, pNode.getBooleanStartIndex());
+ }
+
+ /**
+ * 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.
+ *
+ * @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);
+ }
+}
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 95%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
index 7ffa18c..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" />
@@ -45,7 +45,7 @@
<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 69%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
index 861b9b5..e528dd5 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
@@ -17,15 +17,15 @@
<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_v1.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.package.map" />
- <option name="push" value="flag_v1.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.flag.map" />
- <option name="push" value="flag_v1.val->/data/local/tmp/aconfig_storage_package/testdata/mockup.val" />
- <option name="push" value="flag_v1.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" />
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
index 6b8942b..702325d 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
@@ -48,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/v2/package_v2.map b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
index 16f4054..0a9f95e 100644
--- 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
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 82%
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..2557048 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
@@ -26,7 +26,6 @@
import android.aconfig.storage.FlagReadContext.StoredFlagType;
import android.aconfig.storage.PackageReadContext;
import android.aconfig.storage.SipHasher13;
-import android.aconfig.storage.StorageInternalReader;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -225,46 +224,4 @@
assertEquals(rHash, jHash);
}
}
-
- @Test
- public void testRustJavaEqualFlag() throws IOException {
- List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
-
- String mapPath = "/metadata/aconfig/maps/";
- String flagsPath = "/metadata/aconfig/boot/";
-
- for (parsed_flag flag : flags) {
-
- String container = flag.container;
- String packageName = flag.package_;
- String flagName = flag.name;
- String fullFlagName = packageName + "/" + flagName;
-
- MappedByteBuffer packageMap =
- AconfigStorageReadAPI.mapStorageFile(mapPath + container + ".package.map");
- MappedByteBuffer flagMap =
- AconfigStorageReadAPI.mapStorageFile(mapPath + container + ".flag.map");
- MappedByteBuffer flagValList =
- AconfigStorageReadAPI.mapStorageFile(flagsPath + container + ".val");
-
- PackageReadContext packageContext =
- AconfigStorageReadAPI.getPackageReadContext(packageMap, packageName);
-
- FlagReadContext flagContext =
- AconfigStorageReadAPI.getFlagReadContext(
- flagMap, packageContext.mPackageId, flagName);
-
- boolean rVal =
- AconfigStorageReadAPI.getBooleanFlagValue(
- flagValList,
- packageContext.mBooleanStartIndex + flagContext.mFlagIndex);
-
- StorageInternalReader reader = new StorageInternalReader(container, packageName);
- boolean jVal = reader.getBooleanFlagValue(flagContext.mFlagIndex);
-
- long rHash = AconfigStorageReadAPI.hash(packageName);
- long jHash = SipHasher13.hash(packageName.getBytes());
- assertEquals(rVal, jVal);
- }
- }
}
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..2b0aeae
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.assertThrows;
+
+import android.aconfig.DeviceProtos;
+import android.aconfig.nano.Aconfig;
+import android.aconfig.nano.Aconfig.parsed_flag;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.internal.aconfig.storage.AconfigStorageException;
+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) {
+ if (flag.permission == Aconfig.READ_ONLY && flag.state == Aconfig.DISABLED) {
+ continue;
+ }
+ 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);
+ 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
+ AconfigStorageException e =
+ assertThrows(
+ AconfigStorageException.class,
+ () ->
+ PlatformAconfigPackageInternal.load(
+ "fake_container", "fake_package", 0));
+ assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
+
+ // package not found
+ e =
+ assertThrows(
+ AconfigStorageException.class,
+ () -> PlatformAconfigPackageInternal.load("system", "fake_container", 0));
+ assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.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 == Aconfig.ENABLED;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+
+ if (pNode.hasPackageFingerprint()) {
+ long fingerprint = pNode.getPackageFingerprint();
+ e =
+ assertThrows(
+ AconfigStorageException.class,
+ () ->
+ PlatformAconfigPackageInternal.load(
+ container, packageName, fingerprint + 1));
+ assertEquals(AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH, e.getErrorCode());
+ }
+ }
+}
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 80c0994..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
+++ /dev/null
@@ -1,127 +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;
- // cannot find package
- AconfigStorageException e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "mockup", "com.android.aconfig.storage.test_10", pr));
- 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_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "test", "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, 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_PACKAGE_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));
- }
-}
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 0de34a6..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
+++ /dev/null
@@ -1,48 +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",
- "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/StorageInternalReaderTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
deleted file mode 100644
index 3a1bba0..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
+++ /dev/null
@@ -1,45 +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.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.aconfig.storage.StorageInternalReader;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class StorageInternalReaderTest {
-
- private String mStorageDir = "/data/local/tmp/aconfig_java_api_test";
-
- @Test
- public void testStorageInternalReader_getFlag() {
-
- String packageMapFile = mStorageDir + "/maps/mockup.package.map";
- String flagValueFile = mStorageDir + "/boot/mockup.val";
-
- StorageInternalReader reader =
- new StorageInternalReader(
- "com.android.aconfig.storage.test_1", packageMapFile, flagValueFile);
- assertFalse(reader.getBooleanFlagValue(0));
- assertTrue(reader.getBooleanFlagValue(1));
- }
-}
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.rs b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
index 5605a41..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
@@ -64,21 +64,67 @@
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);
}
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..cac3de2
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.assertThrows;
+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 {
+ 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);
+ }
+
+ @Test
+ public void testLoad_container_package_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
+ AconfigStorageException e =
+ assertThrows(
+ AconfigStorageException.class,
+ () ->
+ PlatformAconfigPackageInternal.load(
+ "mockup",
+ "com.android.aconfig.storage.test_10",
+ fingerprint,
+ pr));
+ assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
+
+ // cannot find container
+ e =
+ assertThrows(
+ AconfigStorageException.class,
+ () ->
+ PlatformAconfigPackageInternal.load(
+ null,
+ "com.android.aconfig.storage.test_1",
+ fingerprint,
+ pr));
+ assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
+
+ e =
+ assertThrows(
+ AconfigStorageException.class,
+ () ->
+ PlatformAconfigPackageInternal.load(
+ "test",
+ "com.android.aconfig.storage.test_1",
+ fingerprint,
+ pr));
+ assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
+
+ // fingerprint doesn't match
+ e =
+ assertThrows(
+ AconfigStorageException.class,
+ () ->
+ PlatformAconfigPackageInternal.load(
+ "mockup",
+ "com.android.aconfig.storage.test_1",
+ fingerprint + 1,
+ pr));
+ assertEquals(
+ // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ 5, e.getErrorCode());
+
+ // new storage doesn't exist
+ pr = new StorageFileProvider("fake/path/", "fake/path/");
+ e =
+ assertThrows(
+ AconfigStorageException.class,
+ () ->
+ PlatformAconfigPackageInternal.load(
+ "mockup",
+ "com.android.aconfig.storage.test_1",
+ fingerprint,
+ pr));
+ assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
+
+ // file read issue
+ pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+ e =
+ assertThrows(
+ AconfigStorageException.class,
+ () ->
+ PlatformAconfigPackageInternal.load(
+ "mockup",
+ "com.android.aconfig.storage.test_1",
+ fingerprint,
+ pr));
+ assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
+ }
+
+ @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/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs
index 3f593fe..766807a 100644
--- a/tools/aconfig/aflags/src/aconfig_storage_source.rs
+++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs
@@ -17,6 +17,23 @@
pub struct AconfigStorageSource {}
+static ACONFIGD_SYSTEM_SOCKET_NAME: &str = "/dev/socket/aconfigd_system";
+static ACONFIGD_MAINLINE_SOCKET_NAME: &str = "/dev/socket/aconfigd_mainline";
+
+enum AconfigdSocket {
+ System,
+ Mainline,
+}
+
+impl AconfigdSocket {
+ pub fn name(&self) -> &str {
+ match self {
+ AconfigdSocket::System => ACONFIGD_SYSTEM_SOCKET_NAME,
+ AconfigdSocket::Mainline => ACONFIGD_MAINLINE_SOCKET_NAME,
+ }
+ }
+}
+
fn load_flag_to_container() -> Result<HashMap<String, String>> {
Ok(load_protos::load()?.into_iter().map(|p| (p.qualified_name(), p.container)).collect())
}
@@ -81,7 +98,7 @@
})
}
-fn read_from_socket() -> Result<Vec<ProtoFlagQueryReturnMessage>> {
+fn read_from_socket(socket: AconfigdSocket) -> Result<Vec<ProtoFlagQueryReturnMessage>> {
let messages = ProtoStorageRequestMessages {
msgs: vec![ProtoStorageRequestMessage {
msg: Some(ProtoStorageRequestMessageMsg::ListStorageMessage(ProtoListStorageMessage {
@@ -93,12 +110,7 @@
special_fields: SpecialFields::new(),
};
- let socket_name = if aconfig_flags::auto_generated::enable_system_aconfigd_rust() {
- "/dev/socket/aconfigd_system"
- } else {
- "/dev/socket/aconfigd"
- };
- let mut socket = UnixStream::connect(socket_name)?;
+ let mut socket = UnixStream::connect(socket.name())?;
let message_buffer = messages.write_to_bytes()?;
let mut message_length_buffer: [u8; 4] = [0; 4];
@@ -132,14 +144,20 @@
impl FlagSource for AconfigStorageSource {
fn list_flags() -> Result<Vec<Flag>> {
let containers = load_flag_to_container()?;
- read_from_socket()
- .map(|query_messages| {
- query_messages
- .iter()
- .map(|message| convert(message.clone(), &containers))
- .collect::<Vec<_>>()
- })?
+ let system_messages = read_from_socket(AconfigdSocket::System);
+ let mainline_messages = read_from_socket(AconfigdSocket::Mainline);
+
+ let mut all_messages = vec![];
+ if let Ok(system_messages) = system_messages {
+ all_messages.extend_from_slice(&system_messages);
+ }
+ if let Ok(mainline_messages) = mainline_messages {
+ all_messages.extend_from_slice(&mainline_messages);
+ }
+
+ all_messages
.into_iter()
+ .map(|query_message| convert(query_message.clone(), &containers))
.collect()
}
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..d084048
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
@@ -0,0 +1,32 @@
+/*
+ * 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, long packageFingerprint) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(int index) {
+ 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..283b251
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,32 @@
+/*
+ * 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, long packageFingerprint) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public boolean getBooleanFlagValue(int index) {
+ 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..7d666fe 100644
--- a/tools/edit_monitor/daemon_manager.py
+++ b/tools/edit_monitor/daemon_manager.py
@@ -13,6 +13,8 @@
# limitations under the License.
+import errno
+import fcntl
import getpass
import hashlib
import logging
@@ -33,7 +35,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 +72,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 +89,7 @@
"edit_monitor",
self.user_name,
"ENABLE_ANDROID_EDIT_MONITOR",
- 10,
+ 100,
):
logging.warning("Edit monitor is disabled, exiting...")
return
@@ -97,16 +102,32 @@
logging.warning("Edit monitor for cog is not supported, exiting...")
return
- try:
- self._stop_any_existing_instance()
- self._write_pid_to_pidfile()
- self._start_daemon_process()
- except Exception as e:
- logging.exception("Failed to start daemon manager with error %s", e)
- self._send_error_event_to_clearcut(
- edit_event_pb2.EditEvent.FAILED_TO_START_EDIT_MONITOR
- )
- raise e
+ setup_lock_file = pathlib.Path(tempfile.gettempdir()).joinpath(
+ self.pid_file_path.name + ".setup"
+ )
+ logging.info("setup lock file: %s", setup_lock_file)
+ with open(setup_lock_file, "w") as f:
+ try:
+ # Acquire an exclusive lock
+ fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ self._stop_any_existing_instance()
+ self._write_pid_to_pidfile()
+ self._start_daemon_process()
+ except Exception as e:
+ if (
+ isinstance(e, IOError) and e.errno == errno.EAGAIN
+ ): # Failed to acquire the file lock.
+ logging.warning("Another edit monitor is starting, exitinng...")
+ return
+ else:
+ logging.exception("Failed to start daemon manager with error %s", e)
+ self._send_error_event_to_clearcut(
+ edit_event_pb2.EditEvent.FAILED_TO_START_EDIT_MONITOR
+ )
+ raise e
+ finally:
+ # Release the lock
+ fcntl.flock(f, fcntl.LOCK_UN)
def monitor_daemon(
self,
@@ -141,16 +162,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(
@@ -172,7 +197,7 @@
self._wait_for_process_terminate(self.daemon_process.pid, 1)
if self.daemon_process.is_alive():
self._terminate_process(self.daemon_process.pid)
- self._remove_pidfile()
+ self._remove_pidfile(self.pid)
logging.info("Successfully stopped daemon manager.")
except Exception as e:
logging.exception("Failed to stop daemon manager with error %s", e)
@@ -246,11 +271,15 @@
if ex_pid:
logging.info("Found another instance with pid %d.", ex_pid)
self._terminate_process(ex_pid)
- self._remove_pidfile()
+ self._remove_pidfile(ex_pid)
- def _read_pid_from_pidfile(self):
- with open(self.pid_file_path, "r") as f:
- return int(f.read().strip())
+ def _read_pid_from_pidfile(self) -> int | None:
+ try:
+ with open(self.pid_file_path, "r") as f:
+ return int(f.read().strip())
+ except FileNotFoundError as e:
+ logging.warning("pidfile %s does not exist.", self.pid_file_path)
+ return None
def _write_pid_to_pidfile(self):
"""Creates a pidfile and writes the current pid to the file.
@@ -326,7 +355,23 @@
)
return True
- def _remove_pidfile(self):
+ def _remove_pidfile(self, expected_pid: int):
+ recorded_pid = self._read_pid_from_pidfile()
+
+ if recorded_pid is None:
+ logging.info("pid file %s already removed.", self.pid_file_path)
+ return
+
+ if recorded_pid != expected_pid:
+ logging.warning(
+ "pid file contains pid from a different process, expected pid: %d,"
+ " actual pid: %d.",
+ expected_pid,
+ recorded_pid,
+ )
+ return
+
+ logging.debug("removing pidfile written by process %s", expected_pid)
try:
os.remove(self.pid_file_path)
except FileNotFoundError:
@@ -351,7 +396,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)
@@ -365,9 +416,7 @@
uptime_end = float(f.readline().split()[0])
return (
- (total_end_time - total_start_time)
- / (uptime_end - uptime_start)
- * 100
+ (total_end_time - total_start_time) / (uptime_end - uptime_start) * 100
)
def _get_total_cpu_time(self, pid: int) -> float:
@@ -382,13 +431,19 @@
def _find_all_instances_pids(self) -> list[int]:
pids = []
- for file in os.listdir(self.pid_file_path.parent):
- if file.endswith(".lock"):
- try:
- with open(self.pid_file_path.parent.joinpath(file), "r") as f:
- pids.append(int(f.read().strip()))
- except (FileNotFoundError, IOError, ValueError, TypeError):
- logging.exception("Failed to get pid from file path: %s", file)
+ try:
+ output = subprocess.check_output(["ps", "-ef", "--no-headers"], text=True)
+ for line in output.splitlines():
+ parts = line.split()
+ process_path = parts[7]
+ if pathlib.Path(process_path).name == "edit_monitor":
+ pid = int(parts[1])
+ if pid != self.pid: # exclude the current process
+ pids.append(pid)
+ except Exception:
+ logging.exception(
+ "Failed to get pids of existing edit monitors from ps command."
+ )
return pids
diff --git a/tools/edit_monitor/daemon_manager_test.py b/tools/edit_monitor/daemon_manager_test.py
index 8d18388..be28965 100644
--- a/tools/edit_monitor/daemon_manager_test.py
+++ b/tools/edit_monitor/daemon_manager_test.py
@@ -14,6 +14,7 @@
"""Unittests for DaemonManager."""
+import fcntl
import logging
import multiprocessing
import os
@@ -82,7 +83,8 @@
# tests will be cleaned.
tempfile.tempdir = self.working_dir.name
self.patch = mock.patch.dict(
- os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'true'})
+ os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'true'}
+ )
self.patch.start()
def tearDown(self):
@@ -102,6 +104,7 @@
p = self._create_fake_deamon_process()
self.assert_run_simple_daemon_success()
+ self.assert_no_subprocess_running()
def test_start_success_with_existing_instance_already_dead(self):
# Create a pidfile with pid that does not exist.
@@ -137,7 +140,9 @@
# Verify no daemon process is started.
self.assertIsNone(dm.daemon_process)
- @mock.patch.dict(os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'false'}, clear=True)
+ @mock.patch.dict(
+ os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'false'}, clear=True
+ )
def test_start_return_directly_if_disabled(self):
dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
dm.start()
@@ -154,6 +159,25 @@
# Verify no daemon process is started.
self.assertIsNone(dm.daemon_process)
+ def test_start_failed_other_instance_is_starting(self):
+ f = open(
+ pathlib.Path(self.working_dir.name).joinpath(
+ TEST_PID_FILE_PATH + '.setup'
+ ),
+ 'w',
+ )
+ # Acquire an exclusive lock
+ fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+
+ dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
+ dm.start()
+
+ # Release the lock
+ fcntl.flock(f, fcntl.LOCK_UN)
+ f.close()
+ # Verify no daemon process is started.
+ self.assertIsNone(dm.daemon_process)
+
@mock.patch('os.kill')
def test_start_failed_to_kill_existing_instance(self, mock_kill):
mock_kill.side_effect = OSError('Unknown OSError')
@@ -177,6 +201,7 @@
'edit_monitor'
)
pid_file_path_dir.mkdir(parents=True, exist_ok=True)
+
# Makes the directory read-only so write pidfile will fail.
os.chmod(pid_file_path_dir, 0o555)
@@ -202,23 +227,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 +268,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')
@@ -359,6 +392,26 @@
fake_cclient, edit_event_pb2.EditEvent.FAILED_TO_REBOOT_EDIT_MONITOR
)
+ @mock.patch('subprocess.check_output')
+ def test_cleanup_success(self, mock_check_output):
+ p = self._create_fake_deamon_process()
+ fake_cclient = FakeClearcutClient()
+ mock_check_output.return_value = f'user {p.pid} 1 1 1 1 1 edit_monitor arg'
+
+ dm = daemon_manager.DaemonManager(
+ TEST_BINARY_FILE,
+ daemon_target=long_running_daemon,
+ cclient=fake_cclient,
+ )
+ dm.cleanup()
+
+ self.assertFalse(p.is_alive())
+ self.assertTrue(
+ pathlib.Path(self.working_dir.name)
+ .joinpath(daemon_manager.BLOCK_SIGN_FILE)
+ .exists()
+ )
+
def assert_run_simple_daemon_success(self):
damone_output_file = tempfile.NamedTemporaryFile(
dir=self.working_dir.name, delete=False
@@ -424,7 +477,7 @@
pass
def _create_fake_deamon_process(
- self, name: str = ''
+ self, name: str = TEST_PID_FILE_PATH
) -> multiprocessing.Process:
# Create a long running subprocess
p = multiprocessing.Process(target=long_running_daemon)
@@ -435,7 +488,7 @@
'edit_monitor'
)
pid_file_path_dir.mkdir(parents=True, exist_ok=True)
- with open(pid_file_path_dir.joinpath(name + 'pid.lock'), 'w') as f:
+ with open(pid_file_path_dir.joinpath(name), 'w') as f:
f.write(str(p.pid))
return p
diff --git a/tools/edit_monitor/edit_monitor_integration_test.py b/tools/edit_monitor/edit_monitor_integration_test.py
index 3d28274..f39b936 100644
--- a/tools/edit_monitor/edit_monitor_integration_test.py
+++ b/tools/edit_monitor/edit_monitor_integration_test.py
@@ -15,6 +15,7 @@
"""Integration tests for Edit Monitor."""
import glob
+from importlib import resources
import logging
import os
import pathlib
@@ -25,8 +26,6 @@
import tempfile
import time
import unittest
-
-from importlib import resources
from unittest import mock
@@ -49,7 +48,8 @@
self.root_monitoring_path.mkdir()
self.edit_monitor_binary_path = self._import_executable("edit_monitor")
self.patch = mock.patch.dict(
- os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'true'})
+ os.environ, {"ENABLE_ANDROID_EDIT_MONITOR": "true"}
+ )
self.patch.start()
def tearDown(self):
@@ -83,7 +83,21 @@
self.assertEqual(self._get_logged_events_num(), 4)
- def _start_edit_monitor_process(self):
+ def test_start_multiple_edit_monitor_only_one_started(self):
+ p1 = self._start_edit_monitor_process(wait_for_observer_start=False)
+ p2 = self._start_edit_monitor_process(wait_for_observer_start=False)
+ p3 = self._start_edit_monitor_process(wait_for_observer_start=False)
+
+ live_processes = self._get_live_processes([p1, p2, p3])
+
+ # Cleanup all live processes.
+ for p in live_processes:
+ os.kill(p.pid, signal.SIGINT)
+ p.communicate()
+
+ self.assertEqual(len(live_processes), 1)
+
+ def _start_edit_monitor_process(self, wait_for_observer_start=True):
command = f"""
export TMPDIR="{self.working_dir.name}"
{self.edit_monitor_binary_path} --path={self.root_monitoring_path} --dry_run"""
@@ -94,7 +108,9 @@
start_new_session=True,
executable="/bin/bash",
)
- self._wait_for_observer_start(time_out=5)
+ if wait_for_observer_start:
+ self._wait_for_observer_start(time_out=5)
+
return p
def _wait_for_observer_start(self, time_out):
@@ -125,6 +141,18 @@
return 0
+ def _get_live_processes(self, processes):
+ live_processes = []
+ for p in processes:
+ try:
+ p.wait(timeout=5)
+ except subprocess.TimeoutExpired as e:
+ live_processes.append(p)
+ logging.info("process: %d still alive.", p.pid)
+ else:
+ logging.info("process: %d stopped.", p.pid)
+ return live_processes
+
def _import_executable(self, executable_name: str) -> pathlib.Path:
binary_dir = pathlib.Path(self.working_dir.name).joinpath("binary")
binary_dir.mkdir()
diff --git a/tools/edit_monitor/main.py b/tools/edit_monitor/main.py
index 49385f1..3c2d183 100644
--- a/tools/edit_monitor/main.py
+++ b/tools/edit_monitor/main.py
@@ -72,7 +72,8 @@
root_logging_dir = tempfile.mkdtemp(prefix='edit_monitor_')
_, log_path = tempfile.mkstemp(dir=root_logging_dir, suffix='.log')
- log_fmt = '%(asctime)s %(filename)s:%(lineno)s:%(levelname)s: %(message)s'
+
+ log_fmt = '%(asctime)s.%(msecs)03d %(filename)s:%(lineno)s:%(levelname)s: %(message)s'
date_fmt = '%Y-%m-%d %H:%M:%S'
log_level = logging.DEBUG if verbose else logging.INFO
@@ -101,12 +102,12 @@
daemon_args=(args.path, args.dry_run),
)
- if args.force_cleanup:
- dm.cleanup()
-
try:
- dm.start()
- dm.monitor_daemon()
+ if args.force_cleanup:
+ dm.cleanup()
+ else:
+ dm.start()
+ dm.monitor_daemon()
except Exception:
logging.exception('Unexpected exception raised when run daemon.')
finally:
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/event_log_tags.py b/tools/event_log_tags.py
index a6ae9f1..e859b6b 100644
--- a/tools/event_log_tags.py
+++ b/tools/event_log_tags.py
@@ -14,21 +14,21 @@
"""A module for reading and parsing event-log-tags files."""
+import dataclasses
import re
import sys
+from typing import Optional
-class Tag(object):
- __slots__ = ["tagnum", "tagname", "description", "filename", "linenum"]
-
- def __init__(self, tagnum, tagname, description, filename, linenum):
- self.tagnum = tagnum
- self.tagname = tagname
- self.description = description
- self.filename = filename
- self.linenum = linenum
+@dataclasses.dataclass
+class Tag:
+ tagnum: int
+ tagname: str
+ description: Optional[str]
+ filename: str
+ linenum: int
-class TagFile(object):
+class TagFile:
"""Read an input event-log-tags file."""
def AddError(self, msg, linenum=None):
if linenum is None:
@@ -76,14 +76,11 @@
self.options[parts[1]] = parts[2:]
continue
- if parts[0] == "?":
- tag = None
- else:
- try:
- tag = int(parts[0])
- except ValueError:
- self.AddError("\"%s\" isn't an integer tag or '?'" % (parts[0],))
- continue
+ try:
+ tag = int(parts[0])
+ except ValueError:
+ self.AddError("\"%s\" isn't an integer tag" % (parts[0],))
+ continue
tagname = parts[1]
if len(parts) == 3:
@@ -128,8 +125,8 @@
out = sys.stdout
output_file = "<stdout>"
else:
- out = open(output_file, "wb")
- out.write(str.encode(data))
+ out = open(output_file, "w")
+ out.write(data)
out.close()
except (IOError, OSError) as e:
print("failed to write %s: %s" % (output_file, e), file=sys.stderr)
diff --git a/tools/finalization/build-step-0-and-m.sh b/tools/finalization/build-step-0-and-m.sh
new file mode 100755
index 0000000..4843800
--- /dev/null
+++ b/tools/finalization/build-step-0-and-m.sh
@@ -0,0 +1,20 @@
+
+#!/bin/bash
+# Copyright 2024 Google Inc. All rights reserved.
+set -ex
+function help() {
+ echo "Finalize VINTF and build a target for test."
+ echo "usage: $(basename "$0") target [goals...]"
+}
+function finalize_main_step0_and_m() {
+ if [ $# == 0 ] ; then
+ help
+ exit 1
+ fi;
+ local top="$(dirname "$0")"/../../../..
+ source $top/build/make/tools/finalization/build-step-0.sh
+ local m="$top/build/soong/soong_ui.bash --make-mode TARGET_PRODUCT=$1 TARGET_RELEASE=fina_0 TARGET_BUILD_VARIANT=userdebug"
+ # This command tests the release state for AIDL.
+ AIDL_FROZEN_REL=true $m ${@:2}
+}
+finalize_main_step0_and_m $@
diff --git a/tools/finalization/build-step-0.sh b/tools/finalization/build-step-0.sh
index f81b720..8826b35 100755
--- a/tools/finalization/build-step-0.sh
+++ b/tools/finalization/build-step-0.sh
@@ -7,11 +7,26 @@
local top="$(dirname "$0")"/../../../..
source $top/build/make/tools/finalization/environment.sh
+ local need_vintf_finalize=false
if [ "$FINAL_STATE" = "unfinalized" ] ; then
- # VINTF finalization
+ need_vintf_finalize=true
+ else
+ # build-step-0.sh tests the vintf finalization step (step-0) when the
+ # FINAL_BOARD_API_LEVEL is the same as the RELEASE_BOARD_API_LEVEL; and
+ # RELEASE_BOARD_API_LEVEL_FROZEN is not true from the fina_0 configuration.
+ # The FINAL_BOARD_API_LEVEL must be the next vendor API level to be finalized.
+ local board_api_level_vars=$(TARGET_RELEASE=fina_0 $top/build/soong/soong_ui.bash --dumpvars-mode -vars "RELEASE_BOARD_API_LEVEL_FROZEN RELEASE_BOARD_API_LEVEL")
+ local target_board_api_level_vars="RELEASE_BOARD_API_LEVEL_FROZEN=''
+RELEASE_BOARD_API_LEVEL='$FINAL_BOARD_API_LEVEL'"
+ if [ "$board_api_level_vars" = "$target_board_api_level_vars" ] ; then
+ echo The target is a finalization candidate.
+ need_vintf_finalize=true
+ fi;
+ fi;
+
+ if [ "$need_vintf_finalize" = true ] ; then # VINTF finalization
source $top/build/make/tools/finalization/finalize-vintf-resources.sh
fi;
}
finalize_main_step0
-
diff --git a/tools/finalization/environment.sh b/tools/finalization/environment.sh
index f68a68b..cf3e61b 100755
--- a/tools/finalization/environment.sh
+++ b/tools/finalization/environment.sh
@@ -29,4 +29,8 @@
# FINAL versions for VINTF
# TODO(b/323985297): The version must match with that from the release configuration.
# Instead of hardcoding the version here, read it from a release configuration.
-export FINAL_BOARD_API_LEVEL='202404'
+export FINAL_BOARD_API_LEVEL='202504'
+export FINAL_CORRESPONDING_VERSION_LETTER='W'
+export FINAL_CORRESPONDING_PLATFORM_VERSION='16'
+export FINAL_NEXT_BOARD_API_LEVEL='202604'
+export FINAL_NEXT_CORRESPONDING_VERSION_LETTER='X'
diff --git a/tools/finalization/finalize-vintf-resources.sh b/tools/finalization/finalize-vintf-resources.sh
index d532b25..6f1a6f6 100755
--- a/tools/finalization/finalize-vintf-resources.sh
+++ b/tools/finalization/finalize-vintf-resources.sh
@@ -33,18 +33,18 @@
function create_new_compat_matrix_and_kernel_configs() {
# The compatibility matrix versions are bumped during vFRC
# These will change every time we have a new vFRC
- local CURRENT_COMPATIBILITY_MATRIX_LEVEL='202404'
- local NEXT_COMPATIBILITY_MATRIX_LEVEL='202504'
+ local CURRENT_COMPATIBILITY_MATRIX_LEVEL="$FINAL_BOARD_API_LEVEL"
+ local NEXT_COMPATIBILITY_MATRIX_LEVEL="$FINAL_NEXT_BOARD_API_LEVEL"
# The kernel configs need the letter of the Android release
- local CURRENT_RELEASE_LETTER='v'
- local NEXT_RELEASE_LETTER='w'
+ local CURRENT_RELEASE_LETTER="$FINAL_CORRESPONDING_VERSION_LETTER"
+ local NEXT_RELEASE_LETTER="$FINAL_NEXT_CORRESPONDING_VERSION_LETTER"
# build the targets required before touching the Android.bp/Android.mk files
local build_cmd="$top/build/soong/soong_ui.bash --make-mode"
$build_cmd bpmodify
- "$top/prebuilts/build-tools/path/linux-x86/python3" "$top/hardware/interfaces/compatibility_matrices/bump.py" "$CURRENT_COMPATIBILITY_MATRIX_LEVEL" "$NEXT_COMPATIBILITY_MATRIX_LEVEL" "$CURRENT_RELEASE_LETTER" "$NEXT_RELEASE_LETTER"
+ "$top/prebuilts/build-tools/path/linux-x86/python3" "$top/hardware/interfaces/compatibility_matrices/bump.py" "$CURRENT_COMPATIBILITY_MATRIX_LEVEL" "$NEXT_COMPATIBILITY_MATRIX_LEVEL" "$CURRENT_RELEASE_LETTER" "$NEXT_RELEASE_LETTER" "$FINAL_CORRESPONDING_PLATFORM_VERSION"
# Freeze the current framework manifest file. This relies on the
# aosp_cf_x86_64-trunk_staging build target to get the right manifest
diff --git a/tools/java-event-log-tags.py b/tools/java-event-log-tags.py
index bbd65fa..e3dc07e 100755
--- a/tools/java-event-log-tags.py
+++ b/tools/java-event-log-tags.py
@@ -15,16 +15,12 @@
# limitations under the License.
"""
-Usage: java-event-log-tags.py [-o output_file] <input_file> <merged_tags_file>
-
Generate a java class containing constants for each of the event log
tags in the given input file.
-
--h to display this usage message and exit.
"""
from io import StringIO
-import getopt
+import argparse
import os
import os.path
import re
@@ -32,57 +28,14 @@
import event_log_tags
-output_file = None
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('-o', dest='output_file')
+parser.add_argument('file')
+args = parser.parse_args()
-try:
- opts, args = getopt.getopt(sys.argv[1:], "ho:")
-except getopt.GetoptError as err:
- print(str(err))
- print(__doc__)
- sys.exit(2)
-
-for o, a in opts:
- if o == "-h":
- print(__doc__)
- sys.exit(2)
- elif o == "-o":
- output_file = a
- else:
- print("unhandled option %s" % (o,), file=sys.stderr)
- sys.exit(1)
-
-if len(args) != 1 and len(args) != 2:
- print("need one or two input files, not %d" % (len(args),))
- print(__doc__)
- sys.exit(1)
-
-fn = args[0]
+fn = args.file
tagfile = event_log_tags.TagFile(fn)
-if len(args) > 1:
- # Load the merged tag file (which should have numbers assigned for all
- # tags. Use the numbers from the merged file to fill in any missing
- # numbers from the input file.
- merged_fn = args[1]
- merged_tagfile = event_log_tags.TagFile(merged_fn)
- merged_by_name = dict([(t.tagname, t) for t in merged_tagfile.tags])
- for t in tagfile.tags:
- if t.tagnum is None:
- if t.tagname in merged_by_name:
- t.tagnum = merged_by_name[t.tagname].tagnum
- else:
- # We're building something that's not being included in the
- # product, so its tags don't appear in the merged file. Assign
- # them all an arbitrary number so we can emit the java and
- # compile the (unused) package.
- t.tagnum = 999999
-else:
- # Not using the merged tag file, so all tags must have manually assigned
- # numbers
- for t in tagfile.tags:
- if t.tagnum is None:
- tagfilef.AddError("tag \"%s\" has no number" % (tagname,), tag.linenum)
-
if "java_package" not in tagfile.options:
tagfile.AddError("java_package option not specified", linenum=0)
@@ -141,11 +94,11 @@
for t in tagfile.tags:
methodName = javaName("write_" + t.tagname)
if t.description:
- args = [arg.strip("() ").split("|") for arg in t.description.split(",")]
+ fn_args = [arg.strip("() ").split("|") for arg in t.description.split(",")]
else:
- args = []
- argTypesNames = ", ".join([javaTypes[int(arg[1])] + " " + javaName(arg[0]) for arg in args])
- argNames = "".join([", " + javaName(arg[0]) for arg in args])
+ fn_args = []
+ argTypesNames = ", ".join([javaTypes[int(arg[1])] + " " + javaName(arg[0]) for arg in fn_args])
+ argNames = "".join([", " + javaName(arg[0]) for arg in fn_args])
buffer.write("\n public static void %s(%s) {" % (methodName, argTypesNames))
buffer.write("\n android.util.EventLog.writeEvent(%s%s);" % (t.tagname.upper(), argNames))
buffer.write("\n }\n")
@@ -153,8 +106,8 @@
buffer.write("}\n");
-output_dir = os.path.dirname(output_file)
+output_dir = os.path.dirname(args.output_file)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
-event_log_tags.WriteOutput(output_file, buffer)
+event_log_tags.WriteOutput(args.output_file, buffer)
diff --git a/tools/merge-event-log-tags.py b/tools/merge-event-log-tags.py
index 292604c..5730c11 100755
--- a/tools/merge-event-log-tags.py
+++ b/tools/merge-event-log-tags.py
@@ -15,22 +15,13 @@
# limitations under the License.
"""
-Usage: merge-event-log-tags.py [-o output_file] [input_files...]
-
Merge together zero or more event-logs-tags files to produce a single
output file, stripped of comments. Checks that no tag numbers conflict
and fails if they do.
-
--h to display this usage message and exit.
"""
from io import StringIO
-import getopt
-try:
- import hashlib
-except ImportError:
- import md5 as hashlib
-import struct
+import argparse
import sys
import event_log_tags
@@ -38,32 +29,10 @@
errors = []
warnings = []
-output_file = None
-pre_merged_file = None
-
-# Tags with a tag number of ? are assigned a tag in the range
-# [ASSIGN_START, ASSIGN_LIMIT).
-ASSIGN_START = 900000
-ASSIGN_LIMIT = 1000000
-
-try:
- opts, args = getopt.getopt(sys.argv[1:], "ho:m:")
-except getopt.GetoptError as err:
- print(str(err))
- print(__doc__)
- sys.exit(2)
-
-for o, a in opts:
- if o == "-h":
- print(__doc__)
- sys.exit(2)
- elif o == "-o":
- output_file = a
- elif o == "-m":
- pre_merged_file = a
- else:
- print("unhandled option %s" % (o,), file=sys.stderr)
- sys.exit(1)
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('-o', dest='output_file')
+parser.add_argument('files', nargs='*')
+args = parser.parse_args()
# Restrictions on tags:
#
@@ -77,12 +46,7 @@
by_tagname = {}
by_tagnum = {}
-pre_merged_tags = {}
-if pre_merged_file:
- for t in event_log_tags.TagFile(pre_merged_file).tags:
- pre_merged_tags[t.tagname] = t
-
-for fn in args:
+for fn in args.files:
tagfile = event_log_tags.TagFile(fn)
for t in tagfile.tags:
@@ -93,12 +57,6 @@
if t.tagname in by_tagname:
orig = by_tagname[t.tagname]
- # Allow an explicit tag number to define an implicit tag number
- if orig.tagnum is None:
- orig.tagnum = t.tagnum
- elif t.tagnum is None:
- t.tagnum = orig.tagnum
-
if (t.tagnum == orig.tagnum and
t.description == orig.description):
# if the name and description are identical, issue a warning
@@ -114,7 +72,7 @@
linenum=t.linenum)
continue
- if t.tagnum is not None and t.tagnum in by_tagnum:
+ if t.tagnum in by_tagnum:
orig = by_tagnum[t.tagnum]
if t.tagname != orig.tagname:
@@ -125,8 +83,7 @@
continue
by_tagname[t.tagname] = t
- if t.tagnum is not None:
- by_tagnum[t.tagnum] = t
+ by_tagnum[t.tagnum] = t
errors.extend(tagfile.errors)
warnings.extend(tagfile.warnings)
@@ -140,38 +97,6 @@
for fn, ln, msg in warnings:
print("%s:%d: warning: %s" % (fn, ln, msg), file=sys.stderr)
-# Python's hash function (a) isn't great and (b) varies between
-# versions of python. Using md5 is overkill here but is the same from
-# platform to platform and speed shouldn't matter in practice.
-def hashname(str):
- d = hashlib.md5(str).digest()[:4]
- return struct.unpack("!I", d)[0]
-
-# Assign a tag number to all the entries that say they want one
-# assigned. We do this based on a hash of the tag name so that the
-# numbers should stay relatively stable as tags are added.
-
-# If we were provided pre-merged tags (w/ the -m option), then don't
-# ever try to allocate one, just fail if we don't have a number
-
-for name, t in sorted(by_tagname.items()):
- if t.tagnum is None:
- if pre_merged_tags:
- try:
- t.tagnum = pre_merged_tags[t.tagname]
- except KeyError:
- print("Error: Tag number not defined for tag `%s'. Have you done a full build?" % t.tagname,
- file=sys.stderr)
- sys.exit(1)
- else:
- while True:
- x = (hashname(name) % (ASSIGN_LIMIT - ASSIGN_START - 1)) + ASSIGN_START
- if x not in by_tagnum:
- t.tagnum = x
- by_tagnum[x] = t
- break
- name = "_" + name
-
# by_tagnum should be complete now; we've assigned numbers to all tags.
buffer = StringIO()
@@ -181,4 +106,4 @@
else:
buffer.write("%d %s\n" % (t.tagnum, t.tagname))
-event_log_tags.WriteOutput(output_file, buffer)
+event_log_tags.WriteOutput(args.output_file, buffer)
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)
diff --git a/tools/releasetools/apex_utils.py b/tools/releasetools/apex_utils.py
index 54df955..08f2b83 100644
--- a/tools/releasetools/apex_utils.py
+++ b/tools/releasetools/apex_utils.py
@@ -79,15 +79,10 @@
Returns:
The repacked apex file containing the signed apk files.
"""
- if not os.path.exists(self.debugfs_path):
- raise ApexSigningError(
- "Couldn't find location of debugfs_static: " +
- "Path {} does not exist. ".format(self.debugfs_path) +
- "Make sure bin/debugfs_static can be found in -p <path>")
- list_cmd = ['deapexer', '--debugfs_path', self.debugfs_path,
- 'list', self.apex_path]
- entries_names = common.RunAndCheckOutput(list_cmd).split()
- apk_entries = [name for name in entries_names if name.endswith('.apk')]
+ payload_dir = self.ExtractApexPayload(self.apex_path)
+ apk_entries = []
+ for base_dir, _, files in os.walk(payload_dir):
+ apk_entries.extend(os.path.join(base_dir, file) for file in files if file.endswith('.apk'))
# No need to sign and repack, return the original apex path.
if not apk_entries and self.sign_tool is None:
@@ -105,16 +100,16 @@
logger.warning('Apk path does not contain the intended directory name:'
' %s', entry)
- payload_dir, has_signed_content = self.ExtractApexPayloadAndSignContents(
- apk_entries, apk_keys, payload_key, signing_args)
+ has_signed_content = self.SignContentsInPayload(
+ payload_dir, apk_entries, apk_keys, payload_key, signing_args)
if not has_signed_content:
logger.info('No contents has been signed in %s', self.apex_path)
return self.apex_path
return self.RepackApexPayload(payload_dir, payload_key, signing_args)
- def ExtractApexPayloadAndSignContents(self, apk_entries, apk_keys, payload_key, signing_args):
- """Extracts the payload image and signs the containing apk files."""
+ def ExtractApexPayload(self, apex_path):
+ """Extracts the contents of an APEX and returns the directory of the contents"""
if not os.path.exists(self.debugfs_path):
raise ApexSigningError(
"Couldn't find location of debugfs_static: " +
@@ -129,9 +124,12 @@
extract_cmd = ['deapexer', '--debugfs_path', self.debugfs_path,
'--fsckerofs_path', self.fsckerofs_path,
'extract',
- self.apex_path, payload_dir]
+ apex_path, payload_dir]
common.RunAndCheckOutput(extract_cmd)
+ return payload_dir
+ def SignContentsInPayload(self, payload_dir, apk_entries, apk_keys, payload_key, signing_args):
+ """Signs the contents in payload."""
has_signed_content = False
for entry in apk_entries:
apk_path = os.path.join(payload_dir, entry)
@@ -163,7 +161,7 @@
common.RunAndCheckOutput(cmd)
has_signed_content = True
- return payload_dir, has_signed_content
+ return has_signed_content
def RepackApexPayload(self, payload_dir, payload_key, signing_args=None):
"""Rebuilds the apex file with the updated payload directory."""
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 464ad9b..25bcb52 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -677,6 +677,21 @@
glob_dict["fingerprint"] = fingerprint
return
+def TryParseFingerprintAndTimestamp(glob_dict):
+ """Helper function that parses fingerprint and timestamp from the global dictionary.
+
+ Args:
+ glob_dict: the global dictionary from the build system.
+ """
+ TryParseFingerprint(glob_dict)
+
+ # Set fixed timestamp for building the OTA package.
+ if "use_fixed_timestamp" in glob_dict:
+ glob_dict["timestamp"] = FIXED_FILE_TIMESTAMP
+ if "build.prop" in glob_dict:
+ timestamp = glob_dict["build.prop"].GetProp("ro.build.date.utc")
+ if timestamp:
+ glob_dict["timestamp"] = timestamp
def ImagePropFromGlobalDict(glob_dict, mount_point):
"""Build an image property dictionary from the global dictionary.
@@ -686,15 +701,7 @@
mount_point: such as "system", "data" etc.
"""
d = {}
- TryParseFingerprint(glob_dict)
-
- # Set fixed timestamp for building the OTA package.
- if "use_fixed_timestamp" in glob_dict:
- d["timestamp"] = FIXED_FILE_TIMESTAMP
- if "build.prop" in glob_dict:
- timestamp = glob_dict["build.prop"].GetProp("ro.build.date.utc")
- if timestamp:
- d["timestamp"] = timestamp
+ TryParseFingerprintAndTimestamp(glob_dict)
def copy_prop(src_p, dest_p):
"""Copy a property from the global dictionary.
@@ -730,6 +737,7 @@
"avb_avbtool",
"use_dynamic_partition_size",
"fingerprint",
+ "timestamp",
)
for p in common_props:
copy_prop(p, p)
@@ -969,6 +977,8 @@
"will install in by default, so there could be files in the input_directory that are not "
"actually supposed to be part of the partition. The paths in this file must be relative to "
"input_directory.")
+ parser.add_argument("--build_datetime_file",
+ help="a file containing the build id timestamp")
parser.add_argument("input_directory",
help="the staging directory to be converted to an image file")
parser.add_argument("properties_file",
@@ -988,10 +998,16 @@
common.InitLogging()
glob_dict = LoadGlobalDict(args.properties_file)
+ if args.build_datetime_file:
+ # Parse the timestamp from build_datetime_file.
+ with open(args.build_datetime_file, "r") as f:
+ glob_dict["timestamp"] = int(f.read())
+
if "mount_point" in glob_dict:
# The caller knows the mount point and provides a dictionary needed by
# BuildImage().
image_properties = glob_dict
+ TryParseFingerprintAndTimestamp(image_properties)
else:
image_filename = os.path.basename(args.out_file)
mount_point = ""
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 6446e1f..76d168c 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -1039,6 +1039,9 @@
# Prepare custom images.
if OPTIONS.custom_images:
+ if source_file is not None:
+ source_file = GetTargetFilesZipForCustomImagesUpdates(
+ source_file, OPTIONS.custom_images)
target_file = GetTargetFilesZipForCustomImagesUpdates(
target_file, OPTIONS.custom_images)
@@ -1121,17 +1124,18 @@
additional_args += ["--enable_lz4diff=" +
str(OPTIONS.enable_lz4diff).lower()]
+ env_override = {}
if source_file and OPTIONS.enable_lz4diff:
- input_tmp = common.UnzipTemp(source_file, ["META/liblz4.so"])
- liblz4_path = os.path.join(input_tmp, "META", "liblz4.so")
+ liblz4_path = os.path.join(source_file, "META", "liblz4.so")
assert os.path.exists(
liblz4_path), "liblz4.so not found in META/ dir of target file {}".format(liblz4_path)
logger.info("Enabling lz4diff %s", liblz4_path)
- additional_args += ["--liblz4_path", liblz4_path]
erofs_compression_param = OPTIONS.target_info_dict.get(
"erofs_default_compressor")
assert erofs_compression_param is not None, "'erofs_default_compressor' not found in META/misc_info.txt of target build. This is required to enable lz4diff."
additional_args += ["--erofs_compression_param", erofs_compression_param]
+ env_override["LD_PRELOAD"] = liblz4_path + \
+ ":" + os.environ.get("LD_PRELOAD", "")
if OPTIONS.disable_vabc:
additional_args += ["--disable_vabc=true"]
@@ -1141,10 +1145,15 @@
additional_args += ["--compressor_types", OPTIONS.compressor_types]
additional_args += ["--max_timestamp", max_timestamp]
+ env = dict(os.environ)
+ if env_override:
+ logger.info("Using environment variables %s", env_override)
+ env.update(env_override)
payload.Generate(
target_file,
source_file,
- additional_args + partition_timestamps_flags
+ additional_args + partition_timestamps_flags,
+ env=env
)
# Sign the payload.
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
index 81b53dc..852d62b 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -845,16 +845,16 @@
self.is_partial_update = is_partial_update
self.spl_downgrade = spl_downgrade
- def _Run(self, cmd): # pylint: disable=no-self-use
+ def _Run(self, cmd, **kwargs): # pylint: disable=no-self-use
# Don't pipe (buffer) the output if verbose is set. Let
# brillo_update_payload write to stdout/stderr directly, so its progress can
# be monitored.
if OPTIONS.verbose:
- common.RunAndCheckOutput(cmd, stdout=None, stderr=None)
+ common.RunAndCheckOutput(cmd, stdout=None, stderr=None, **kwargs)
else:
- common.RunAndCheckOutput(cmd)
+ common.RunAndCheckOutput(cmd, **kwargs)
- def Generate(self, target_file, source_file=None, additional_args=None):
+ def Generate(self, target_file, source_file=None, additional_args=None, **kwargs):
"""Generates a payload from the given target-files zip(s).
Args:
@@ -863,6 +863,7 @@
generating a full OTA.
additional_args: A list of additional args that should be passed to
delta_generator binary; or None.
+ kwargs: Any additional args to pass to subprocess.Popen
"""
if additional_args is None:
additional_args = []
@@ -918,7 +919,7 @@
if self.is_partial_update:
cmd.extend(["--is_partial_update=true"])
cmd.extend(additional_args)
- self._Run(cmd)
+ self._Run(cmd, **kwargs)
self.payload_file = payload_file
self.payload_properties = None