Merge "Add new script to analyze static/shared library usage"
diff --git a/core/board_config.mk b/core/board_config.mk
index c8ec5a9..f459d83 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -1000,6 +1000,14 @@
   TARGET_FLATTEN_APEX := $(OVERRIDE_TARGET_FLATTEN_APEX)
 endif
 
+# TODO(b/278826656) Remove the following message
+ifeq (true,$(TARGET_FLATTEN_APEX))
+  $(warning ********************************************************************************)
+  $(warning Flattened APEX will be deprecated soon. Please stop using flattened APEX and use)
+  $(warning "image" APEX instead.)
+  $(warning ********************************************************************************)
+endif
+
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
 ifdef PRODUCT_EXTRA_VNDK_VERSIONS
   $(foreach v,$(PRODUCT_EXTRA_VNDK_VERSIONS),$(call check_vndk_version,$(v)))
diff --git a/core/config.mk b/core/config.mk
index 5457fd2..c549296 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -43,6 +43,8 @@
 CHANGES_URL := https://android.googlesource.com/platform/build/+/master/Changes.md
 .KATI_READONLY := CHANGES_URL
 $(KATI_deprecated_var TARGET_USES_64_BIT_BINDER,All devices use 64-bit binder by default now. Uses of TARGET_USES_64_BIT_BINDER should be removed.)
+$(KATI_deprecated_var PRODUCT_SEPOLICY_SPLIT,All devices are built with split sepolicy.)
+$(KATI_deprecated_var PRODUCT_SEPOLICY_SPLIT_OVERRIDE,All devices are built with split sepolicy.)
 $(KATI_obsolete_var PATH,Do not use PATH directly. See $(CHANGES_URL)#PATH)
 $(KATI_obsolete_var PYTHONPATH,Do not use PYTHONPATH directly. See $(CHANGES_URL)#PYTHONPATH)
 $(KATI_obsolete_var OUT,Use OUT_DIR instead. See $(CHANGES_URL)#OUT)
@@ -739,7 +741,6 @@
 
 requirements := \
     PRODUCT_TREBLE_LINKER_NAMESPACES \
-    PRODUCT_SEPOLICY_SPLIT \
     PRODUCT_ENFORCE_VINTF_MANIFEST \
     PRODUCT_NOTICE_SPLIT
 
@@ -754,14 +755,6 @@
 PRODUCT_FULL_TREBLE_OVERRIDE ?=
 $(foreach req,$(requirements),$(eval $(req)_OVERRIDE ?=))
 
-ifneq ($(PRODUCT_SEPOLICY_SPLIT),true)
-# WARNING: DO NOT CHANGE: if you are downstream of AOSP, and you change this, without
-# letting upstream know it's important to you, we may do cleanup which breaks this
-# significantly. Please let us know if you are changing this.
-# TODO(b/257176017) - unsplit sepolicy is no longer supported
-PRODUCT_SEPOLICY_SPLIT := true
-endif
-
 # TODO(b/114488870): disallow PRODUCT_FULL_TREBLE_OVERRIDE from being used.
 .KATI_READONLY := \
     PRODUCT_FULL_TREBLE_OVERRIDE \
@@ -1267,6 +1260,9 @@
 
 .KATI_READONLY := JAVAC_NINJA_POOL R8_NINJA_POOL D8_NINJA_POOL
 
+# Soong modules that are known to have broken optional_uses_libs dependencies.
+BUILD_WARNING_BAD_OPTIONAL_USES_LIBS_ALLOWLIST := LegacyCamera Gallery2
+
 # These goals don't need to collect and include Android.mks/CleanSpec.mks
 # in the source tree.
 dont_bother_goals := out product-graph
diff --git a/core/main.mk b/core/main.mk
index 2281b7a..40e690d 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -180,9 +180,7 @@
 ADDITIONAL_SYSTEM_PROPERTIES += ro.treble.enabled=${PRODUCT_FULL_TREBLE}
 
 $(KATI_obsolete_var PRODUCT_FULL_TREBLE,\
-	Code should be written to work regardless of a device being Treble or \
-	variables like PRODUCT_SEPOLICY_SPLIT should be used until that is \
-	possible.)
+	Code should be written to work regardless of a device being Treble)
 
 # Sets ro.actionable_compatible_property.enabled to know on runtime whether the
 # allowed list of actionable compatible properties is enabled or not.
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 46f06f7..6383393 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -294,14 +294,14 @@
 $(call add_json_bool, BuildBrokenVendorPropertyNamespace, $(filter true,$(BUILD_BROKEN_VENDOR_PROPERTY_NAMESPACE)))
 $(call add_json_list, BuildBrokenInputDirModules, $(BUILD_BROKEN_INPUT_DIR_MODULES))
 
+$(call add_json_list, BuildWarningBadOptionalUsesLibsAllowlist,    $(BUILD_WARNING_BAD_OPTIONAL_USES_LIBS_ALLOWLIST))
+
 $(call add_json_bool, BuildDebugfsRestrictionsEnabled, $(filter true,$(PRODUCT_SET_DEBUGFS_RESTRICTIONS)))
 
 $(call add_json_bool, RequiresInsecureExecmemForSwiftshader, $(filter true,$(PRODUCT_REQUIRES_INSECURE_EXECMEM_FOR_SWIFTSHADER)))
 
 $(call add_json_bool, SelinuxIgnoreNeverallows, $(filter true,$(SELINUX_IGNORE_NEVERALLOWS)))
 
-$(call add_json_bool, SepolicySplit, $(filter true,$(PRODUCT_SEPOLICY_SPLIT)))
-
 $(call add_json_list, SepolicyFreezeTestExtraDirs,         $(SEPOLICY_FREEZE_TEST_EXTRA_DIRS))
 $(call add_json_list, SepolicyFreezeTestExtraPrebuiltDirs, $(SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS))
 
diff --git a/target/product/handheld_system.mk b/target/product/handheld_system.mk
index 41233b2..d965367 100644
--- a/target/product/handheld_system.mk
+++ b/target/product/handheld_system.mk
@@ -27,6 +27,7 @@
 $(call inherit-product-if-exists, external/google-fonts/source-sans-pro/fonts.mk)
 $(call inherit-product-if-exists, external/noto-fonts/fonts.mk)
 $(call inherit-product-if-exists, external/roboto-fonts/fonts.mk)
+$(call inherit-product-if-exists, external/roboto-flex-fonts/fonts.mk)
 $(call inherit-product-if-exists, external/hyphenation-patterns/patterns.mk)
 $(call inherit-product-if-exists, frameworks/base/data/keyboards/keyboards.mk)
 $(call inherit-product-if-exists, frameworks/webview/chromium/chromium.mk)
diff --git a/tools/aconfig/src/cache.rs b/tools/aconfig/src/cache.rs
index 44ad3dd..972ba41 100644
--- a/tools/aconfig/src/cache.rs
+++ b/tools/aconfig/src/cache.rs
@@ -179,7 +179,6 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::aconfig::{FlagState, Permission};
 
     #[test]
     fn test_add_flag_declaration() {
diff --git a/tools/aconfig/src/codegen_rust.rs b/tools/aconfig/src/codegen_rust.rs
index fe4231b..a48e464 100644
--- a/tools/aconfig/src/codegen_rust.rs
+++ b/tools/aconfig/src/codegen_rust.rs
@@ -79,28 +79,10 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::commands::{create_cache, Input, Source};
 
     #[test]
     fn test_generate_rust_code() {
-        let cache = create_cache(
-            "test",
-            vec![Input {
-                source: Source::File("testdata/test.aconfig".to_string()),
-                reader: Box::new(include_bytes!("../testdata/test.aconfig").as_slice()),
-            }],
-            vec![
-                Input {
-                    source: Source::File("testdata/first.values".to_string()),
-                    reader: Box::new(include_bytes!("../testdata/first.values").as_slice()),
-                },
-                Input {
-                    source: Source::File("testdata/test.aconfig".to_string()),
-                    reader: Box::new(include_bytes!("../testdata/second.values").as_slice()),
-                },
-            ],
-        )
-        .unwrap();
+        let cache = crate::test::create_cache();
         let generated = generate_rust_code(&cache).unwrap();
         assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
         let expected = r#"
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index cce1d7f..3ae72c6 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -22,8 +22,8 @@
 use std::io::Read;
 use std::path::PathBuf;
 
-use crate::aconfig::{FlagDeclarations, FlagValue};
-use crate::cache::{Cache, CacheBuilder};
+use crate::aconfig::{FlagDeclarations, FlagState, FlagValue, Permission};
+use crate::cache::{Cache, CacheBuilder, Item};
 use crate::codegen_cpp::generate_cpp_code;
 use crate::codegen_java::generate_java_code;
 use crate::codegen_rust::generate_rust_code;
@@ -93,16 +93,52 @@
     Ok(builder.build())
 }
 
-pub fn create_java_lib(cache: &Cache) -> Result<OutputFile> {
-    generate_java_code(cache)
+pub fn create_java_lib(cache: Cache) -> Result<OutputFile> {
+    generate_java_code(&cache)
 }
 
-pub fn create_cpp_lib(cache: &Cache) -> Result<OutputFile> {
-    generate_cpp_code(cache)
+pub fn create_cpp_lib(cache: Cache) -> Result<OutputFile> {
+    generate_cpp_code(&cache)
 }
 
-pub fn create_rust_lib(cache: &Cache) -> Result<OutputFile> {
-    generate_rust_code(cache)
+pub fn create_rust_lib(cache: Cache) -> Result<OutputFile> {
+    generate_rust_code(&cache)
+}
+
+pub fn create_device_config_defaults(caches: Vec<Cache>) -> Result<Vec<u8>> {
+    let mut output = Vec::new();
+    for item in sort_and_iter_items(caches).filter(|item| item.permission == Permission::ReadWrite)
+    {
+        let line = format!(
+            "{}/{}:{}\n",
+            item.namespace,
+            item.name,
+            match item.state {
+                FlagState::Enabled => "enabled",
+                FlagState::Disabled => "disabled",
+            }
+        );
+        output.extend_from_slice(line.as_bytes());
+    }
+    Ok(output)
+}
+
+pub fn create_device_config_sysprops(caches: Vec<Cache>) -> Result<Vec<u8>> {
+    let mut output = Vec::new();
+    for item in sort_and_iter_items(caches).filter(|item| item.permission == Permission::ReadWrite)
+    {
+        let line = format!(
+            "persist.device_config.{}.{}={}\n",
+            item.namespace,
+            item.name,
+            match item.state {
+                FlagState::Enabled => "true",
+                FlagState::Disabled => "false",
+            }
+        );
+        output.extend_from_slice(line.as_bytes());
+    }
+    Ok(output)
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
@@ -112,29 +148,26 @@
     Protobuf,
 }
 
-pub fn dump_cache(mut caches: Vec<Cache>, format: DumpFormat) -> Result<Vec<u8>> {
+pub fn dump_cache(caches: Vec<Cache>, format: DumpFormat) -> Result<Vec<u8>> {
     let mut output = Vec::new();
-    caches.sort_by_cached_key(|cache| cache.namespace().to_string());
-    for cache in caches.into_iter() {
-        match format {
-            DumpFormat::Text => {
-                let mut lines = vec![];
-                for item in cache.iter() {
-                    lines.push(format!(
-                        "{}/{}: {:?} {:?}\n",
-                        item.namespace, item.name, item.state, item.permission
-                    ));
-                }
-                output.append(&mut lines.concat().into());
+    match format {
+        DumpFormat::Text => {
+            for item in sort_and_iter_items(caches) {
+                let line = format!(
+                    "{}/{}: {:?} {:?}\n",
+                    item.namespace, item.name, item.state, item.permission
+                );
+                output.extend_from_slice(line.as_bytes());
             }
-            DumpFormat::Debug => {
-                let mut lines = vec![];
-                for item in cache.iter() {
-                    lines.push(format!("{:#?}\n", item));
-                }
-                output.append(&mut lines.concat().into());
+        }
+        DumpFormat::Debug => {
+            for item in sort_and_iter_items(caches) {
+                let line = format!("{:#?}\n", item);
+                output.extend_from_slice(line.as_bytes());
             }
-            DumpFormat::Protobuf => {
+        }
+        DumpFormat::Protobuf => {
+            for cache in sort_and_iter_caches(caches) {
                 let parsed_flags: ProtoParsedFlags = cache.into();
                 parsed_flags.write_to_vec(&mut output)?;
             }
@@ -143,6 +176,15 @@
     Ok(output)
 }
 
+fn sort_and_iter_items(caches: Vec<Cache>) -> impl Iterator<Item = Item> {
+    sort_and_iter_caches(caches).flat_map(|cache| cache.into_iter())
+}
+
+fn sort_and_iter_caches(mut caches: Vec<Cache>) -> impl Iterator<Item = Cache> {
+    caches.sort_by_cached_key(|cache| cache.namespace().to_string());
+    caches.into_iter()
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -203,6 +245,22 @@
     }
 
     #[test]
+    fn test_create_device_config_defaults() {
+        let caches = vec![crate::test::create_cache()];
+        let bytes = create_device_config_defaults(caches).unwrap();
+        let text = std::str::from_utf8(&bytes).unwrap();
+        assert_eq!("test/disabled_rw:disabled\ntest/enabled_rw:enabled\n", text);
+    }
+
+    #[test]
+    fn test_create_device_config_sysprops() {
+        let caches = vec![crate::test::create_cache()];
+        let bytes = create_device_config_sysprops(caches).unwrap();
+        let text = std::str::from_utf8(&bytes).unwrap();
+        assert_eq!("persist.device_config.test.disabled_rw=false\npersist.device_config.test.enabled_rw=true\n", text);
+    }
+
+    #[test]
     fn test_dump_text_format() {
         let caches = vec![create_test_cache_ns1()];
         let bytes = dump_cache(caches, DumpFormat::Text).unwrap();
diff --git a/tools/aconfig/src/main.rs b/tools/aconfig/src/main.rs
index 1d2ec95..dab0191 100644
--- a/tools/aconfig/src/main.rs
+++ b/tools/aconfig/src/main.rs
@@ -33,6 +33,9 @@
 mod commands;
 mod protos;
 
+#[cfg(test)]
+mod test;
+
 use crate::cache::Cache;
 use commands::{DumpFormat, Input, OutputFile, Source};
 
@@ -62,6 +65,16 @@
                 .arg(Arg::new("out").long("out").required(true)),
         )
         .subcommand(
+            Command::new("create-device-config-defaults")
+                .arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
+                .arg(Arg::new("out").long("out").default_value("-")),
+        )
+        .subcommand(
+            Command::new("create-device-config-sysprops")
+                .arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
+                .arg(Arg::new("out").long("out").default_value("-")),
+        )
+        .subcommand(
             Command::new("dump")
                 .arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
                 .arg(
@@ -108,6 +121,15 @@
     Ok(())
 }
 
+fn write_output_to_file_or_stdout(path: &str, data: &[u8]) -> Result<()> {
+    if path == "-" {
+        io::stdout().write_all(data)?;
+    } else {
+        fs::File::create(path)?.write_all(data)?;
+    }
+    Ok(())
+}
+
 fn main() -> Result<()> {
     let matches = cli().get_matches();
     match matches.subcommand() {
@@ -125,7 +147,7 @@
             let file = fs::File::open(path)?;
             let cache = Cache::read_from_reader(file)?;
             let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
-            let generated_file = commands::create_java_lib(&cache)?;
+            let generated_file = commands::create_java_lib(cache)?;
             write_output_file_realtive_to_dir(&dir, &generated_file)?;
         }
         Some(("create-cpp-lib", sub_matches)) => {
@@ -133,7 +155,7 @@
             let file = fs::File::open(path)?;
             let cache = Cache::read_from_reader(file)?;
             let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
-            let generated_file = commands::create_cpp_lib(&cache)?;
+            let generated_file = commands::create_cpp_lib(cache)?;
             write_output_file_realtive_to_dir(&dir, &generated_file)?;
         }
         Some(("create-rust-lib", sub_matches)) => {
@@ -141,9 +163,31 @@
             let file = fs::File::open(path)?;
             let cache = Cache::read_from_reader(file)?;
             let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
-            let generated_file = commands::create_rust_lib(&cache)?;
+            let generated_file = commands::create_rust_lib(cache)?;
             write_output_file_realtive_to_dir(&dir, &generated_file)?;
         }
+        Some(("create-device-config-defaults", sub_matches)) => {
+            let mut caches = Vec::new();
+            for path in sub_matches.get_many::<String>("cache").unwrap_or_default() {
+                let file = fs::File::open(path)?;
+                let cache = Cache::read_from_reader(file)?;
+                caches.push(cache);
+            }
+            let output = commands::create_device_config_defaults(caches)?;
+            let path = get_required_arg::<String>(sub_matches, "out")?;
+            write_output_to_file_or_stdout(path, &output)?;
+        }
+        Some(("create-device-config-sysprops", sub_matches)) => {
+            let mut caches = Vec::new();
+            for path in sub_matches.get_many::<String>("cache").unwrap_or_default() {
+                let file = fs::File::open(path)?;
+                let cache = Cache::read_from_reader(file)?;
+                caches.push(cache);
+            }
+            let output = commands::create_device_config_sysprops(caches)?;
+            let path = get_required_arg::<String>(sub_matches, "out")?;
+            write_output_to_file_or_stdout(path, &output)?;
+        }
         Some(("dump", sub_matches)) => {
             let mut caches = Vec::new();
             for path in sub_matches.get_many::<String>("cache").unwrap_or_default() {
@@ -154,12 +198,7 @@
             let format = get_required_arg::<DumpFormat>(sub_matches, "format")?;
             let output = commands::dump_cache(caches, *format)?;
             let path = get_required_arg::<String>(sub_matches, "out")?;
-            let mut file: Box<dyn Write> = if *path == "-" {
-                Box::new(io::stdout())
-            } else {
-                Box::new(fs::File::create(path)?)
-            };
-            file.write_all(&output)?;
+            write_output_to_file_or_stdout(path, &output)?;
         }
         _ => unreachable!(),
     }
diff --git a/tools/aconfig/src/test.rs b/tools/aconfig/src/test.rs
new file mode 100644
index 0000000..621381a
--- /dev/null
+++ b/tools/aconfig/src/test.rs
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#[cfg(test)]
+pub mod test_utils {
+    use crate::cache::Cache;
+    use crate::commands::{Input, Source};
+
+    pub fn create_cache() -> Cache {
+        crate::commands::create_cache(
+            "test",
+            vec![Input {
+                source: Source::File("testdata/test.aconfig".to_string()),
+                reader: Box::new(include_bytes!("../testdata/test.aconfig").as_slice()),
+            }],
+            vec![
+                Input {
+                    source: Source::File("testdata/first.values".to_string()),
+                    reader: Box::new(include_bytes!("../testdata/first.values").as_slice()),
+                },
+                Input {
+                    source: Source::File("testdata/test.aconfig".to_string()),
+                    reader: Box::new(include_bytes!("../testdata/second.values").as_slice()),
+                },
+            ],
+        )
+        .unwrap()
+    }
+}
+
+#[cfg(test)]
+pub use test_utils::*;
diff --git a/tools/compliance/cmd/sbom/sbom.go b/tools/compliance/cmd/sbom/sbom.go
index f61289e..a53741f 100644
--- a/tools/compliance/cmd/sbom/sbom.go
+++ b/tools/compliance/cmd/sbom/sbom.go
@@ -35,7 +35,7 @@
 	"github.com/google/blueprint/deptools"
 
 	"github.com/spdx/tools-golang/builder/builder2v2"
-	"github.com/spdx/tools-golang/json"
+	spdx_json "github.com/spdx/tools-golang/json"
 	"github.com/spdx/tools-golang/spdx/common"
 	spdx "github.com/spdx/tools-golang/spdx/v2_2"
 	"github.com/spdx/tools-golang/spdxlib"
@@ -274,7 +274,7 @@
 	tn *compliance.TargetNode) (*projectmetadata.ProjectMetadata, error) {
 	pms, err := pmix.MetadataForProjects(tn.Projects()...)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read projects for %q: %w\n", tn, err)
+		return nil, fmt.Errorf("Unable to read projects for %q: %w\n", tn.Name(), err)
 	}
 	if len(pms) == 0 {
 		return nil, nil
diff --git a/tools/compliance/cmd/sbom/sbom_test.go b/tools/compliance/cmd/sbom/sbom_test.go
index 8a62713..13ba66d 100644
--- a/tools/compliance/cmd/sbom/sbom_test.go
+++ b/tools/compliance/cmd/sbom/sbom_test.go
@@ -25,6 +25,7 @@
 	"time"
 
 	"android/soong/tools/compliance"
+
 	"github.com/spdx/tools-golang/builder/builder2v2"
 	"github.com/spdx/tools-golang/spdx/common"
 	spdx "github.com/spdx/tools-golang/spdx/v2_2"
@@ -2375,8 +2376,8 @@
 	if doc.DocumentName == "" {
 		return fmt.Errorf("DocumentName: got nothing, want Document Name")
 	}
-	if fmt.Sprintf("%v", doc.CreationInfo.Creators[1].Creator) != "Google LLC" {
-		return fmt.Errorf("Creator: got %v, want  'Google LLC'")
+	if c := fmt.Sprintf("%v", doc.CreationInfo.Creators[1].Creator); c != "Google LLC" {
+		return fmt.Errorf("Creator: got %v, want  'Google LLC'", c)
 	}
 	_, err := time.Parse(time.RFC3339, doc.CreationInfo.Created)
 	if err != nil {
diff --git a/tools/compliance/go.mod b/tools/compliance/go.mod
index 088915a..1928189 100644
--- a/tools/compliance/go.mod
+++ b/tools/compliance/go.mod
@@ -7,8 +7,11 @@
 require (
 	android/soong v0.0.0
 	github.com/google/blueprint v0.0.0
+	github.com/spdx/tools-golang v0.0.0
 )
 
+replace github.com/spdx/tools-golang v0.0.0 => ../../../../external/spdx-tools
+
 require golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
 
 replace android/soong v0.0.0 => ../../../soong
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 8d660f8..465d222 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -68,6 +68,7 @@
 from concurrent.futures import ThreadPoolExecutor
 from apex_utils import GetApexInfoFromTargetFiles
 from common import ZipDelete, PARTITIONS_WITH_CARE_MAP, ExternalError, RunAndCheckOutput, IsSparseImage, MakeTempFile, ZipWrite
+from build_image import FIXED_FILE_TIMESTAMP
 
 if sys.hexversion < 0x02070000:
   print("Python 2.7 or newer is required.", file=sys.stderr)
@@ -81,12 +82,6 @@
 OPTIONS.replace_updated_files_list = []
 OPTIONS.is_signing = False
 
-# Use a fixed timestamp (01/01/2009 00:00:00 UTC) for files when packaging
-# images. (b/24377993, b/80600931)
-FIXED_FILE_TIMESTAMP = int((
-    datetime.datetime(2009, 1, 1, 0, 0, 0, 0, None) -
-    datetime.datetime.utcfromtimestamp(0)).total_seconds())
-
 
 def ParseAvbFooter(img_path) -> avbtool.AvbFooter:
   with open(img_path, 'rb') as fp:
@@ -594,15 +589,6 @@
   if block_list:
     image_props["block_list"] = block_list.name
 
-  # Use repeatable ext4 FS UUID and hash_seed UUID (based on partition name and
-  # build fingerprint). Also use the legacy build id, because the vbmeta digest
-  # isn't available at this point.
-  build_info = common.BuildInfo(info_dict, use_legacy_id=True)
-  uuid_seed = what + "-" + build_info.GetPartitionFingerprint(what)
-  image_props["uuid"] = str(uuid.uuid5(uuid.NAMESPACE_URL, uuid_seed))
-  hash_seed = "hash_seed-" + uuid_seed
-  image_props["hash_seed"] = str(uuid.uuid5(uuid.NAMESPACE_URL, hash_seed))
-
   build_image.BuildImage(
       os.path.join(input_dir, what.upper()), image_props, output_file.name)
 
@@ -1144,14 +1130,18 @@
           item for item in vbmeta_partitions
           if item not in vbmeta_vendor.split()]
       vbmeta_partitions.append("vbmeta_vendor")
-    custom_avb_partitions = OPTIONS.info_dict.get("avb_custom_vbmeta_images_partition_list", "").strip().split()
+    custom_avb_partitions = OPTIONS.info_dict.get(
+        "avb_custom_vbmeta_images_partition_list", "").strip().split()
     if custom_avb_partitions:
       for avb_part in custom_avb_partitions:
         partition_name = "vbmeta_" + avb_part
-        included_partitions = OPTIONS.info_dict.get("avb_vbmeta_{}".format(avb_part), "").strip().split()
-        assert included_partitions, "Custom vbmeta partition {0} missing avb_vbmeta_{0} prop".format(avb_part)
+        included_partitions = OPTIONS.info_dict.get(
+            "avb_vbmeta_{}".format(avb_part), "").strip().split()
+        assert included_partitions, "Custom vbmeta partition {0} missing avb_vbmeta_{0} prop".format(
+            avb_part)
         banner(partition_name)
-        logger.info("VBMeta partition {} needs {}".format(partition_name, included_partitions))
+        logger.info("VBMeta partition {} needs {}".format(
+            partition_name, included_partitions))
         partitions[partition_name] = AddVBMeta(
             output_zip, partitions, partition_name, included_partitions)
         vbmeta_partitions = [
@@ -1159,7 +1149,6 @@
             if item not in included_partitions]
         vbmeta_partitions.append(partition_name)
 
-
     if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
       banner("vbmeta")
       AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 9064136..11bd784 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -23,24 +23,34 @@
 """
 
 from __future__ import print_function
+import datetime
 
 import glob
 import logging
 import os
 import os.path
 import re
+import shlex
 import shutil
 import sys
+import uuid
 
 import common
 import verity_utils
 
+
 logger = logging.getLogger(__name__)
 
 OPTIONS = common.OPTIONS
 BLOCK_SIZE = common.BLOCK_SIZE
 BYTES_IN_MB = 1024 * 1024
 
+# Use a fixed timestamp (01/01/2009 00:00:00 UTC) for files when packaging
+# images. (b/24377993, b/80600931)
+FIXED_FILE_TIMESTAMP = int((
+    datetime.datetime(2009, 1, 1, 0, 0, 0, 0, None) -
+    datetime.datetime.utcfromtimestamp(0)).total_seconds())
+
 
 class BuildImageError(Exception):
   """An Exception raised during image building."""
@@ -487,6 +497,20 @@
     raise
 
 
+def SetUUIDIfNotExist(image_props):
+
+  # Use repeatable ext4 FS UUID and hash_seed UUID (based on partition name and
+  # build fingerprint). Also use the legacy build id, because the vbmeta digest
+  # isn't available at this point.
+  what = image_props["mount_point"]
+  fingerprint = image_props.get("fingerprint", "")
+  uuid_seed = what + "-" + fingerprint
+  logger.info("Using fingerprint %s for partition %s", fingerprint, what)
+  image_props["uuid"] = str(uuid.uuid5(uuid.NAMESPACE_URL, uuid_seed))
+  hash_seed = "hash_seed-" + uuid_seed
+  image_props["hash_seed"] = str(uuid.uuid5(uuid.NAMESPACE_URL, hash_seed))
+
+
 def BuildImage(in_dir, prop_dict, out_file, target_out=None):
   """Builds an image for the files under in_dir and writes it to out_file.
 
@@ -504,6 +528,7 @@
     BuildImageError: On build image failures.
   """
   in_dir, fs_config = SetUpInDirAndFsConfig(in_dir, prop_dict)
+  SetUUIDIfNotExist(prop_dict)
 
   build_command = []
   fs_type = prop_dict.get("fs_type", "")
@@ -635,6 +660,19 @@
     verity_image_builder.Build(out_file)
 
 
+def TryParseFingerprint(glob_dict: dict):
+  for (key, val) in glob_dict.items():
+    if not key.endswith("_add_hashtree_footer_args") and not key.endswith("_add_hash_footer_args"):
+      continue
+    for arg in shlex.split(val):
+      m = re.match(r"^com\.android\.build\.\w+\.fingerprint:", arg)
+      if m is None:
+        continue
+      fingerprint = arg[len(m.group()):]
+      glob_dict["fingerprint"] = fingerprint
+      return
+
+
 def ImagePropFromGlobalDict(glob_dict, mount_point):
   """Build an image property dictionary from the global dictionary.
 
@@ -643,7 +681,9 @@
     mount_point: such as "system", "data" etc.
   """
   d = {}
+  TryParseFingerprint(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:
@@ -680,6 +720,7 @@
       "avb_enable",
       "avb_avbtool",
       "use_dynamic_partition_size",
+      "fingerprint",
   )
   for p in common_props:
     copy_prop(p, p)
@@ -870,10 +911,9 @@
           if item not in vbmeta_vendor.split()]
       vbmeta_partitions.append("vbmeta_vendor")
 
-
   partitions = {part: os.path.join(in_dir, part + ".img")
                 for part in vbmeta_partitions}
-  partitions = {part:path for (part, path) in partitions.items() if os.path.exists(path)}
+  partitions = {part: path for (part, path) in partitions.items() if os.path.exists(path)}
   common.BuildVBMeta(output_path, partitions, name, vbmeta_partitions)
 
 
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 7adc9fa..f92d67c 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -928,20 +928,7 @@
         input_file, partition, ramdisk_format=ramdisk_format)
   d["build.prop"] = d["system.build.prop"]
 
-  # Set up the salt (based on fingerprint) that will be used when adding AVB
-  # hash / hashtree footers.
   if d.get("avb_enable") == "true":
-    build_info = BuildInfo(d, use_legacy_id=True)
-    for partition in PARTITIONS_WITH_BUILD_PROP:
-      fingerprint = build_info.GetPartitionFingerprint(partition)
-      if fingerprint:
-        d["avb_{}_salt".format(partition)] = sha256(
-            fingerprint.encode()).hexdigest()
-
-    # Set up the salt for partitions without build.prop
-    if build_info.fingerprint:
-      d["avb_salt"] = sha256(build_info.fingerprint.encode()).hexdigest()
-
     # Set the vbmeta digest if exists
     try:
       d["vbmeta_digest"] = read_helper("META/vbmeta_digest.txt").rstrip()
@@ -2137,20 +2124,19 @@
         archvie. Non-matching patterns will be filtered out. If there's no match
         after the filtering, no file will be unzipped.
   """
-  cmd = ["unzip", "-o", "-q", filename, "-d", dirname]
-  if patterns is not None:
+  with zipfile.ZipFile(filename, allowZip64=True, mode="r") as input_zip:
     # Filter out non-matching patterns. unzip will complain otherwise.
-    with zipfile.ZipFile(filename, allowZip64=True) as input_zip:
+    if patterns is not None:
       names = input_zip.namelist()
-    filtered = [
-        pattern for pattern in patterns if fnmatch.filter(names, pattern)]
+      filtered = [name for name in names if any(
+          [fnmatch.fnmatch(name, p) for p in patterns])]
 
-    # There isn't any matching files. Don't unzip anything.
-    if not filtered:
-      return
-    cmd.extend(filtered)
-
-  RunAndCheckOutput(cmd)
+      # There isn't any matching files. Don't unzip anything.
+      if not filtered:
+        return
+      input_zip.extractall(dirname, filtered)
+    else:
+      input_zip.extractall(dirname)
 
 
 def UnzipTemp(filename, patterns=None):
diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
index 17f4cc5..fa53ad2 100755
--- a/tools/releasetools/img_from_target_files.py
+++ b/tools/releasetools/img_from_target_files.py
@@ -64,7 +64,7 @@
 OPTIONS.retrofit_dap = None
 OPTIONS.build_super = None
 OPTIONS.sparse_userimages = None
-
+OPTIONS.use_fastboot_info = False
 
 def LoadOptions(input_file):
   """Loads information from input_file to OPTIONS.
@@ -118,8 +118,9 @@
 
   entries = [
       'OTA/android-info.txt:android-info.txt',
-      'META/fastboot-info.txt:fastboot-info.txt',
   ]
+  if OPTIONS.use_fastboot_info:
+    entries.append('META/fastboot-info.txt:fastboot-info.txt')
   with zipfile.ZipFile(input_file) as input_zip:
     namelist = input_zip.namelist()
   if 'PREBUILT_IMAGES/kernel_16k' in namelist:
diff --git a/tools/releasetools/verity_utils.py b/tools/releasetools/verity_utils.py
index dddb7f4..7caeed4 100644
--- a/tools/releasetools/verity_utils.py
+++ b/tools/releasetools/verity_utils.py
@@ -31,6 +31,7 @@
 import common
 import sparse_img
 from rangelib import RangeSet
+from hashlib import sha256
 
 logger = logging.getLogger(__name__)
 
@@ -42,6 +43,7 @@
 MAX_VBMETA_SIZE = 64 * 1024
 MAX_FOOTER_SIZE = 4096
 
+
 class BuildVerityImageError(Exception):
   """An Exception raised during verity image building."""
 
@@ -64,6 +66,11 @@
   # partition_size could be None at this point, if using dynamic partitions.
   if partition_size:
     partition_size = int(partition_size)
+  # Set up the salt (based on fingerprint) that will be used when adding AVB
+  # hash / hashtree footers.
+  salt = prop_dict.get("avb_salt")
+  if salt is None:
+    salt = sha256(prop_dict.get("fingerprint", "").encode()).hexdigest()
 
   # Verified Boot 2.0
   if (prop_dict.get("avb_hash_enable") == "true" or
@@ -81,7 +88,7 @@
           prop_dict["avb_avbtool"],
           key_path,
           algorithm,
-          prop_dict.get("avb_salt"),
+          salt,
           prop_dict["avb_add_hash_footer_args"])
 
     # Image uses hashtree footer.
@@ -92,7 +99,7 @@
         prop_dict["avb_avbtool"],
         key_path,
         algorithm,
-        prop_dict.get("avb_salt"),
+        salt,
         prop_dict["avb_add_hashtree_footer_args"])
 
   return None
@@ -279,7 +286,7 @@
 
 
 def CreateCustomImageBuilder(info_dict, partition_name, partition_size,
-                            key_path, algorithm, signing_args):
+                             key_path, algorithm, signing_args):
   builder = None
   if info_dict.get("avb_enable") == "true":
     builder = VerifiedBootVersion2VerityImageBuilder(