[coastguard skipped] Merge sparse cherrypicks from sparse-11704978-L55100030003094529 into 24Q3-release.

COASTGUARD_SKIP: I3cd81b65f943d4ab6c5d981dbe6e9d5bf336e612
COASTGUARD_SKIP: I12bca400bbed2f0cb05a4d0645c4d2172b1259d2

Change-Id: I12bb951fb88f82c434333c70019b1222c709e0a2
diff --git a/common/utils.cc b/common/utils.cc
index 1fa2d41..c2c72d4 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -412,6 +412,9 @@
 }
 
 bool DeleteDirectory(const char* dirname) {
+  if (!std::filesystem::exists(dirname)) {
+    return true;
+  }
   const std::string tmpdir = std::string(dirname) + "_deleted";
   std::filesystem::remove_all(tmpdir);
   if (rename(dirname, tmpdir.c_str()) != 0) {
@@ -620,7 +623,8 @@
    */
   rc = ioctl(fd, BLKROGET, &read_only_flag);
   if (rc != 0) {
-    PLOG(ERROR) << "Failed to read back block device read-only value:" << device;
+    PLOG(ERROR) << "Failed to read back block device read-only value:"
+                << device;
     return false;
   }
   if (read_only_flag == expected_flag) {
@@ -628,20 +632,20 @@
   }
 
   std::array<char, PATH_MAX> device_name;
-  char *pdevice = realpath(device.c_str(), device_name.data());
+  char* pdevice = realpath(device.c_str(), device_name.data());
   TEST_AND_RETURN_FALSE_ERRNO(pdevice);
 
   std::string real_path(pdevice);
   std::size_t offset = real_path.find_last_of('/');
-  if (offset == std::string::npos){
+  if (offset == std::string::npos) {
     LOG(ERROR) << "Could not find partition name from " << real_path;
     return false;
   }
   const std::string partition_name = real_path.substr(offset + 1);
 
   std::string force_ro_file = "/sys/block/" + partition_name + "/force_ro";
-  android::base::unique_fd fd_force_ro {
-    HANDLE_EINTR(open(force_ro_file.c_str(), O_WRONLY | O_CLOEXEC))};
+  android::base::unique_fd fd_force_ro{
+      HANDLE_EINTR(open(force_ro_file.c_str(), O_WRONLY | O_CLOEXEC))};
   TEST_AND_RETURN_FALSE_ERRNO(fd_force_ro >= 0);
 
   rc = write(fd_force_ro, expected_flag ? "1" : "0", 1);
@@ -650,12 +654,13 @@
   // Read back again
   rc = ioctl(fd, BLKROGET, &read_only_flag);
   if (rc != 0) {
-    PLOG(ERROR) << "Failed to read back block device read-only value:" << device;
+    PLOG(ERROR) << "Failed to read back block device read-only value:"
+                << device;
     return false;
   }
   if (read_only_flag != expected_flag) {
     LOG(ERROR) << "After modifying force_ro, marking block device " << device
-                << " as read_only=" << expected_flag;
+               << " as read_only=" << expected_flag;
     return false;
   }
   return true;
diff --git a/payload_generator/xz_android.cc b/payload_generator/xz_android.cc
index 97e2c32..9d157c4 100644
--- a/payload_generator/xz_android.cc
+++ b/payload_generator/xz_android.cc
@@ -16,6 +16,9 @@
 
 #include "update_engine/payload_generator/xz.h"
 
+#include <elf.h>
+#include <endian.h>
+
 #include <algorithm>
 
 #include <7zCrc.h>
@@ -65,6 +68,37 @@
   brillo::Blob* data_;
 };
 
+// Returns the filter id to be used to compress |data|.
+// Only BCJ filter for x86 and ARM ELF file are supported, returns 0 otherwise.
+int GetFilterID(const brillo::Blob& data) {
+  if (data.size() < sizeof(Elf32_Ehdr) ||
+      memcmp(data.data(), ELFMAG, SELFMAG) != 0)
+    return 0;
+
+  const Elf32_Ehdr* header = reinterpret_cast<const Elf32_Ehdr*>(data.data());
+
+  // Only little-endian is supported.
+  if (header->e_ident[EI_DATA] != ELFDATA2LSB)
+    return 0;
+
+  switch (le16toh(header->e_machine)) {
+    case EM_386:
+    case EM_X86_64:
+      return XZ_ID_X86;
+    case EM_ARM:
+      // Both ARM and ARM Thumb instructions could be found in the same ARM ELF
+      // file. We choose to use the ARM Thumb filter here because testing shows
+      // that it usually works better than the ARM filter.
+      return XZ_ID_ARMT;
+#ifdef EM_AARCH64
+    case EM_AARCH64:
+      // Neither the ARM nor the ARM Thumb filter works well with AArch64.
+      return 0;
+#endif
+  }
+  return 0;
+}
+
 }  // namespace
 
 namespace chromeos_update_engine {
@@ -105,8 +139,7 @@
   Lzma2EncProps_Normalize(&lzma2Props);
   props.lzma2Props = lzma2Props;
 
-  // We do not use xz's BCJ filters (http://b/329112384).
-  props.filterProps.id = 0;
+  props.filterProps.id = GetFilterID(in);
 
   BlobWriterStream out_writer(out);
   BlobReaderStream in_reader(in);