[automerged blank] Import translations. DO NOT MERGE ANYWHERE 2p: ed227bcb35

Blank merge reason: commit message contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/bootable/recovery/+/22974437

Change-Id: I80322b3043af3e8976946bbc1162a63c362eda4f
diff --git a/Android.bp b/Android.bp
index bd95705..fba358f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -94,6 +94,8 @@
     shared_libs: [
         "android.hardware.boot@1.0",
         "android.hardware.boot@1.1",
+        "android.hardware.boot-V1-ndk",
+        "libboot_control_client",
         "libbase",
         "libbootloader_message",
         "libcrypto",
@@ -113,6 +115,9 @@
         "librecovery_utils",
         "libotautil",
         "libsnapshot_nobinder",
+        "libsnapshot_cow",
+        "liblz4",
+        "libzstd",
         "update_metadata-protos",
     ],
 }
@@ -157,7 +162,8 @@
     ],
 
     shared_libs: [
-        "android.hardware.health-V1-ndk", // from librecovery_utils
+        "android.hardware.health-V2-ndk", // from librecovery_utils
+        "android.hardware.boot-V1-ndk",
         "librecovery_ui",
     ],
 
diff --git a/README.md b/README.md
index 5ab19d1..507b2bd 100644
--- a/README.md
+++ b/README.md
@@ -137,7 +137,7 @@
 Note that this mechanism applies to both of normal boot and recovery modes.
 
  * **Option 2:** Allow `adbd` to connect without authentication.
-   * `adbd` is compiled with `ALLOW_ADBD_NO_AUTH` (only on debuggable builds).
+   * bootloader is unlocked (`ro.boot.verifiedbootstate` is `orange`) or debuggable build.
    * `ro.adb.secure` has a value of `0`.
 
 Both of the two conditions need to be satisfied. Although `ro.adb.secure` is a runtime property, its
diff --git a/bootloader_message/Android.bp b/bootloader_message/Android.bp
index 778fdb9..7622677 100644
--- a/bootloader_message/Android.bp
+++ b/bootloader_message/Android.bp
@@ -45,6 +45,7 @@
         "libbootloader_message_defaults",
     ],
     recovery_available: true,
+    vendor_available: true,
     host_supported: true,
 
     target: {
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
index d58158d..8fba101 100644
--- a/bootloader_message/include/bootloader_message/bootloader_message.h
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -109,6 +109,7 @@
 #define MISC_MEMTAG_MODE_MEMTAG_ONCE 0x2
 #define MISC_MEMTAG_MODE_MEMTAG_KERNEL 0x4
 #define MISC_MEMTAG_MODE_MEMTAG_KERNEL_ONCE 0x8
+#define MISC_MEMTAG_MODE_MEMTAG_OFF 0x10
 
 #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
 static_assert(sizeof(struct misc_virtual_ab_message) == 64,
diff --git a/etc/init.rc b/etc/init.rc
index e4afecf..c7ff2b2 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -102,7 +102,7 @@
 on fs && property:sys.usb.configfs=1
     mount configfs none /config
     mkdir /config/usb_gadget/g1 0770 shell shell
-    write /config/usb_gadget/g1/idVendor 0x18D1
+    write /config/usb_gadget/g1/idVendor 0x${ro.recovery.usb.vid}
     mkdir /config/usb_gadget/g1/strings/0x409 0770
     write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
     write /config/usb_gadget/g1/strings/0x409/manufacturer ${ro.product.manufacturer}
@@ -110,11 +110,13 @@
     mkdir /config/usb_gadget/g1/functions/ffs.adb
     mkdir /config/usb_gadget/g1/functions/ffs.fastboot
     mkdir /config/usb_gadget/g1/configs/b.1 0777 shell shell
+    # Set current limit to 900mA (b/277022505)
+    write /config/usb_gadget/g1/configs/b.1/MaxPower 0x384
     mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770 shell shell
 
 on fs && property:sys.usb.configfs=0
     write /sys/class/android_usb/android0/f_ffs/aliases adb,fastboot
-    write /sys/class/android_usb/android0/idVendor 18D1
+    write /sys/class/android_usb/android0/idVendor ${ro.recovery.usb.vid}
     write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer}
     write /sys/class/android_usb/android0/iProduct ${ro.product.model}
     write /sys/class/android_usb/android0/iSerial ${ro.serialno}
@@ -139,19 +141,19 @@
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=adb && property:sys.usb.configfs=0
-    write /sys/class/android_usb/android0/idProduct D001
+    write /sys/class/android_usb/android0/idProduct ${ro.recovery.usb.adb.pid}
     write /sys/class/android_usb/android0/functions adb
     write /sys/class/android_usb/android0/enable 1
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=sideload && property:sys.usb.configfs=0
-    write /sys/class/android_usb/android0/idProduct D001
+    write /sys/class/android_usb/android0/idProduct ${ro.recovery.usb.adb.pid}
     write /sys/class/android_usb/android0/functions adb
     write /sys/class/android_usb/android0/enable 1
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=fastboot && property:sys.usb.configfs=0
-    write /sys/class/android_usb/android0/idProduct 4EE0
+    write /sys/class/android_usb/android0/idProduct ${ro.recovery.usb.fastboot.pid}
     write /sys/class/android_usb/android0/functions fastboot
     write /sys/class/android_usb/android0/enable 1
     setprop sys.usb.state ${sys.usb.config}
@@ -166,21 +168,21 @@
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=sideload && property:sys.usb.ffs.ready=1 && property:sys.usb.configfs=1
-    write /config/usb_gadget/g1/idProduct 0xD001
+    write /config/usb_gadget/g1/idProduct 0x${ro.recovery.usb.adb.pid}
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb"
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=adb && property:sys.usb.ffs.ready=1 && property:sys.usb.configfs=1
-    write /config/usb_gadget/g1/idProduct 0xD001
+    write /config/usb_gadget/g1/idProduct 0x${ro.recovery.usb.adb.pid}
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb"
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
 on property:sys.usb.config=fastboot && property:sys.usb.ffs.ready=1 && property:sys.usb.configfs=1
-    write /config/usb_gadget/g1/idProduct 0x4EE0
+    write /config/usb_gadget/g1/idProduct 0x${ro.recovery.usb.fastboot.pid}
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "fastboot"
     symlink /config/usb_gadget/g1/functions/ffs.fastboot /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
diff --git a/install/include/install/wipe_device.h b/install/include/install/wipe_device.h
index 903ddfd..19e7c65 100644
--- a/install/include/install/wipe_device.h
+++ b/install/include/install/wipe_device.h
@@ -24,6 +24,7 @@
 
 // Wipes the current A/B device, with a secure wipe of all the partitions in RECOVERY_WIPE.
 bool WipeAbDevice(Device* device, size_t wipe_package_size);
+bool WipeAbDevice(Device* device, Package* wipe_package);
 
 // Reads the "recovery.wipe" entry in the zip archive returns a list of partitions to wipe.
 std::vector<std::string> GetWipePartitionList(Package* wipe_package);
diff --git a/install/install.cpp b/install/install.cpp
index 83f3cad..a9786cf 100644
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -48,6 +48,7 @@
 
 #include "install/spl_check.h"
 #include "install/wipe_data.h"
+#include "install/wipe_device.h"
 #include "otautil/error_code.h"
 #include "otautil/package.h"
 #include "otautil/paths.h"
@@ -70,6 +71,10 @@
 static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25;
 // The charater used to separate dynamic fingerprints. e.x. sargo|aosp-sargo
 static const char* FINGERPRING_SEPARATOR = "|";
+static constexpr auto&& RELEASE_KEYS_TAG = "release-keys";
+// If brick packages are smaller than |MEMORY_PACKAGE_LIMIT|, read the entire package into memory
+static constexpr size_t MEMORY_PACKAGE_LIMIT = 1024 * 1024;
+
 static std::condition_variable finish_log_temperature;
 static bool isInStringList(const std::string& target_token, const std::string& str_list,
                            const std::string& deliminator);
@@ -213,6 +218,7 @@
   // We allow the package to not have any serialno; and we also allow it to carry multiple serial
   // numbers split by "|"; e.g. serialno=serialno1|serialno2|serialno3 ... We will fail the
   // verification if the device's serialno doesn't match any of these carried numbers.
+
   auto pkg_serial_no = get_value(metadata, "serialno");
   if (!pkg_serial_no.empty()) {
     auto device_serial_no = android::base::GetProperty("ro.serialno", "");
@@ -226,6 +232,21 @@
       LOG(ERROR) << "Package is for serial " << pkg_serial_no;
       return false;
     }
+  } else if (ota_type == OtaType::BRICK) {
+    const auto device_build_tag = android::base::GetProperty("ro.build.tags", "");
+    if (device_build_tag.empty()) {
+      LOG(ERROR) << "Unable to determine device build tags, serial number is missing from package. "
+                    "Rejecting the brick OTA package.";
+      return false;
+    }
+    if (device_build_tag == RELEASE_KEYS_TAG) {
+      LOG(ERROR) << "Device is release key build, serial number is missing from package. "
+                    "Rejecting the brick OTA package.";
+      return false;
+    }
+    LOG(INFO)
+        << "Serial number is missing from brick OTA package, permitting anyway because device is "
+        << device_build_tag;
   }
 
   if (ota_type == OtaType::AB) {
@@ -364,7 +385,20 @@
     return INSTALL_CORRUPT;
   }
 
-  bool package_is_ab = get_value(metadata, "ota-type") == OtaTypeToString(OtaType::AB);
+  const bool package_is_ab = get_value(metadata, "ota-type") == OtaTypeToString(OtaType::AB);
+  const bool package_is_brick = get_value(metadata, "ota-type") == OtaTypeToString(OtaType::BRICK);
+  if (package_is_brick) {
+    LOG(INFO) << "Installing a brick package";
+    if (package->GetType() == PackageType::kFile &&
+        package->GetPackageSize() < MEMORY_PACKAGE_LIMIT) {
+      std::vector<uint8_t> content(package->GetPackageSize());
+      if (package->ReadFullyAtOffset(content.data(), content.size(), 0)) {
+        auto memory_package = Package::CreateMemoryPackage(std::move(content), {});
+        return WipeAbDevice(device, memory_package.get()) ? INSTALL_SUCCESS : INSTALL_ERROR;
+      }
+    }
+    return WipeAbDevice(device, package) ? INSTALL_SUCCESS : INSTALL_ERROR;
+  }
   bool device_supports_ab = android::base::GetBoolProperty("ro.build.ab_update", false);
   bool ab_device_supports_nonab =
       android::base::GetBoolProperty("ro.virtual_ab.allow_non_ab", false);
@@ -551,7 +585,9 @@
   } else {
     LOG(FATAL) << "Invalid status code " << status;
   }
-  PerformPowerwashIfRequired(zip, device);
+  if (package_is_ab) {
+    PerformPowerwashIfRequired(zip, device);
+  }
 
   return INSTALL_SUCCESS;
 }
diff --git a/install/wipe_data.cpp b/install/wipe_data.cpp
index 024c1e1..c65e6f4 100644
--- a/install/wipe_data.cpp
+++ b/install/wipe_data.cpp
@@ -25,6 +25,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
+#include "bootloader_message/bootloader_message.h"
 #include "install/snapshot_utils.h"
 #include "otautil/dirutil.h"
 #include "recovery_ui/ui.h"
@@ -100,6 +101,12 @@
       success &= EraseVolume(METADATA_ROOT, ui);
     }
   }
+  ui->Print("Resetting memtag message...\n");
+  std::string err;
+  if (!WriteMiscMemtagMessage({}, &err)) {
+    ui->Print("Failed to reset memtag message: %s\n", err.c_str());
+    success = false;
+  }
   if (success) {
     success &= device->PostWipeData();
   }
diff --git a/install/wipe_device.cpp b/install/wipe_device.cpp
index 0a525fa..2656580 100644
--- a/install/wipe_device.cpp
+++ b/install/wipe_device.cpp
@@ -182,13 +182,17 @@
     LOG(ERROR) << "Failed to open wipe package";
     return false;
   }
+  return WipeAbDevice(device, wipe_package.get());
+}
 
-  if (!CheckWipePackage(wipe_package.get(), ui)) {
+bool WipeAbDevice(Device* device, Package* wipe_package) {
+  auto ui = device->GetUI();
+  if (!CheckWipePackage(wipe_package, ui)) {
     LOG(ERROR) << "Failed to verify wipe package";
     return false;
   }
 
-  auto partition_list = GetWipePartitionList(wipe_package.get());
+  auto partition_list = GetWipePartitionList(wipe_package);
   if (partition_list.empty()) {
     LOG(ERROR) << "Empty wipe ab partition list";
     return false;
diff --git a/minadbd/Android.bp b/minadbd/Android.bp
index 9d3f733..c664d74 100644
--- a/minadbd/Android.bp
+++ b/minadbd/Android.bp
@@ -97,7 +97,7 @@
     ],
 
     shared_libs: [
-        "android.hardware.health-V1-ndk", // from librecovery_utils
+        "android.hardware.health-V2-ndk", // from librecovery_utils
         "libbase",
         "libcrypto",
     ],
@@ -129,7 +129,7 @@
     ],
 
     static_libs: [
-        "android.hardware.health-V1-ndk", // from librecovery_utils
+        "android.hardware.health-V2-ndk", // from librecovery_utils
         "libminadbd_services",
         "libfusesideload",
         "librecovery_utils",
diff --git a/minadbd/OWNERS b/minadbd/OWNERS
new file mode 100644
index 0000000..8ee79dd
--- /dev/null
+++ b/minadbd/OWNERS
@@ -0,0 +1,2 @@
+enh@google.com
+shaju@google.com
diff --git a/minadbd/minadbd_services.cpp b/minadbd/minadbd_services.cpp
index 0abe867..16bcb5e 100644
--- a/minadbd/minadbd_services.cpp
+++ b/minadbd/minadbd_services.cpp
@@ -305,7 +305,7 @@
   }
 }
 
-asocket* daemon_service_to_socket(std::string_view) {
+asocket* daemon_service_to_socket(std::string_view, atransport*) {
   return nullptr;
 }
 
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index b24c2b1..41a3661 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -502,3 +502,7 @@
 void gr_rotate(GRRotation rot) {
   rotation = rot;
 }
+
+bool gr_has_multiple_connectors() {
+  return gr_backend->HasMultipleConnectors();
+}
diff --git a/minui/graphics.h b/minui/graphics.h
index 5408c93..ff063ae 100644
--- a/minui/graphics.h
+++ b/minui/graphics.h
@@ -40,8 +40,11 @@
   // Blank (or unblank) the specific screen.
   virtual void Blank(bool blank, DrmConnector index) = 0;
 
+  // Return true if the device supports multiple connectors.
+  virtual bool HasMultipleConnectors() = 0;
+
   // Device cleanup when drawing is done.
-  virtual ~MinuiBackend() {};
+  virtual ~MinuiBackend() = default;
 };
 
 #endif  // _GRAPHICS_H_
diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp
index c557022..6c3a5bd 100644
--- a/minui/graphics_drm.cpp
+++ b/minui/graphics_drm.cpp
@@ -200,6 +200,10 @@
   }
 }
 
+bool MinuiBackendDrm::HasMultipleConnectors() {
+  return (drm[DRM_SEC].GRSurfaceDrms[0] && drm[DRM_SEC].GRSurfaceDrms[1]);
+}
+
 static drmModeCrtc* find_crtc_for_connector(int fd, drmModeRes* resources,
                                             drmModeConnector* connector) {
   // Find the encoder. If we already have one, just use it.
diff --git a/minui/graphics_drm.h b/minui/graphics_drm.h
index fe3beaf..a8c9886 100644
--- a/minui/graphics_drm.h
+++ b/minui/graphics_drm.h
@@ -60,6 +60,7 @@
   GRSurface* Flip() override;
   void Blank(bool) override;
   void Blank(bool blank, DrmConnector index) override;
+  bool HasMultipleConnectors() override;
 
  private:
   void DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc);
diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp
index 1cb0c0a..2711af7 100644
--- a/minui/graphics_fbdev.cpp
+++ b/minui/graphics_fbdev.cpp
@@ -44,7 +44,16 @@
 }
 
 void MinuiBackendFbdev::Blank(bool blank, DrmConnector index) {
-  fprintf(stderr, "Unsupported multiple connectors, blank = %d, index = %d\n", blank, index);
+  if (index == DRM_MAIN) {
+    MinuiBackendFbdev::Blank(blank);
+  } else {
+    fprintf(stderr, "Unsupported multiple connectors, blank = %d, index = %d\n", blank, index);
+  }
+}
+
+bool MinuiBackendFbdev::HasMultipleConnectors() {
+  fprintf(stderr, "Unsupported multiple connectors\n");
+  return false;
 }
 
 void MinuiBackendFbdev::SetDisplayedFramebuffer(size_t n) {
diff --git a/minui/graphics_fbdev.h b/minui/graphics_fbdev.h
index 7e193c4..c772428 100644
--- a/minui/graphics_fbdev.h
+++ b/minui/graphics_fbdev.h
@@ -57,6 +57,7 @@
   GRSurface* Flip() override;
   void Blank(bool) override;
   void Blank(bool blank, DrmConnector index) override;
+  bool HasMultipleConnectors() override;
 
  private:
   void SetDisplayedFramebuffer(size_t n);
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index f9be82f..2353ed3 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -129,6 +129,7 @@
 void gr_flip();
 void gr_fb_blank(bool blank);
 void gr_fb_blank(bool blank, int index);
+bool gr_has_multiple_connectors();
 
 // Clears entire surface to current color.
 void gr_clear();
diff --git a/otautil/verifier.cpp b/otautil/verifier.cpp
index 8a65566..83ad708 100644
--- a/otautil/verifier.cpp
+++ b/otautil/verifier.cpp
@@ -309,13 +309,15 @@
 }
 
 static std::vector<Certificate> IterateZipEntriesAndSearchForKeys(const ZipArchiveHandle& handle) {
-  void* cookie;
+  void* cookie{};
+
   int32_t iter_status = StartIteration(handle, &cookie, "", "x509.pem");
   if (iter_status != 0) {
     LOG(ERROR) << "Failed to iterate over entries in the certificate zipfile: "
                << ErrorCodeString(iter_status);
     return {};
   }
+  std::unique_ptr<void, decltype(&EndIteration)> cookie_guard(cookie, &EndIteration);
 
   std::vector<Certificate> result;
 
diff --git a/recovery-persist.cpp b/recovery-persist.cpp
index ad101ed..55699b2 100644
--- a/recovery-persist.cpp
+++ b/recovery-persist.cpp
@@ -77,6 +77,10 @@
   }
 }
 
+static bool file_exists(const char* filename) {
+  return access(filename, R_OK) == 0;
+}
+
 static bool rotated = false;
 
 ssize_t logsave(
@@ -141,7 +145,7 @@
     if (has_cache) {
       // Collects and reports the non-a/b update metrics from last_install; and removes the file
       // to avoid duplicate report.
-      if (access(LAST_INSTALL_FILE_IN_CACHE, F_OK) && unlink(LAST_INSTALL_FILE_IN_CACHE) == -1) {
+      if (file_exists(LAST_INSTALL_FILE_IN_CACHE) && unlink(LAST_INSTALL_FILE_IN_CACHE) == -1) {
         PLOG(ERROR) << "Failed to unlink " << LAST_INSTALL_FILE_IN_CACHE;
       }
 
@@ -152,9 +156,9 @@
       }
     }
 
-    /* Is there something in pmsg? */
-    if (access(LAST_PMSG_FILE, R_OK)) {
-        return 0;
+    /* Is there something in pmsg? If not, no need to proceed. */
+    if (!file_exists(LAST_PMSG_FILE)) {
+      return 0;
     }
 
     // Take last pmsg file contents and send it off to the logsave
@@ -164,18 +168,18 @@
     // For those device without /cache, the last_install file has been copied to
     // /data/misc/recovery from pmsg. Looks for the sideload history only.
     if (!has_cache) {
-      if (access(LAST_INSTALL_FILE, F_OK) && unlink(LAST_INSTALL_FILE) == -1) {
+      if (file_exists(LAST_INSTALL_FILE) && unlink(LAST_INSTALL_FILE) == -1) {
         PLOG(ERROR) << "Failed to unlink " << LAST_INSTALL_FILE;
       }
     }
 
     /* Is there a last console log too? */
     if (rotated) {
-        if (!access(LAST_CONSOLE_FILE, R_OK)) {
-            copy_file(LAST_CONSOLE_FILE, LAST_KMSG_FILE);
-        } else if (!access(ALT_LAST_CONSOLE_FILE, R_OK)) {
-            copy_file(ALT_LAST_CONSOLE_FILE, LAST_KMSG_FILE);
-        }
+      if (file_exists(LAST_CONSOLE_FILE)) {
+        copy_file(LAST_CONSOLE_FILE, LAST_KMSG_FILE);
+      } else if (file_exists(ALT_LAST_CONSOLE_FILE)) {
+        copy_file(ALT_LAST_CONSOLE_FILE, LAST_KMSG_FILE);
+      }
     }
 
     return 0;
diff --git a/recovery_ui/include/recovery_ui/screen_ui.h b/recovery_ui/include/recovery_ui/screen_ui.h
index 92b3c25..99ad534 100644
--- a/recovery_ui/include/recovery_ui/screen_ui.h
+++ b/recovery_ui/include/recovery_ui/screen_ui.h
@@ -245,6 +245,9 @@
       const std::vector<std::string>& backup_headers, const std::vector<std::string>& backup_items,
       const std::function<int(int, bool)>& key_handler) override;
 
+  // For Lid switch handle
+  int SetSwCallback(int code, int value) override;
+
  protected:
   static constexpr int kMenuIndent = 4;
 
@@ -404,6 +407,9 @@
 
   std::mutex updateMutex;
 
+  // Switch the display to active one after graphics is ready
+  bool is_graphics_available;
+
  private:
   void SetLocale(const std::string&);
 
diff --git a/recovery_ui/include/recovery_ui/stub_ui.h b/recovery_ui/include/recovery_ui/stub_ui.h
index 511b131..49689ba 100644
--- a/recovery_ui/include/recovery_ui/stub_ui.h
+++ b/recovery_ui/include/recovery_ui/stub_ui.h
@@ -80,6 +80,10 @@
   }
 
   void SetTitle(const std::vector<std::string>& /* lines */) override {}
+
+  int SetSwCallback(int /* code */, int /* value */) override {
+    return 0;
+  }
 };
 
 #endif  // RECOVERY_STUB_UI_H
diff --git a/recovery_ui/include/recovery_ui/ui.h b/recovery_ui/include/recovery_ui/ui.h
index 512732f..c3e3ee2 100644
--- a/recovery_ui/include/recovery_ui/ui.h
+++ b/recovery_ui/include/recovery_ui/ui.h
@@ -231,6 +231,8 @@
   bool InitScreensaver();
   void SetScreensaverState(ScreensaverState state);
 
+  virtual int SetSwCallback(int code, int value) = 0;
+
   // Key event input queue
   std::mutex key_queue_mutex;
   std::condition_variable key_queue_cond;
diff --git a/recovery_ui/screen_ui.cpp b/recovery_ui/screen_ui.cpp
index b2c828f..ee3cbb1 100644
--- a/recovery_ui/screen_ui.cpp
+++ b/recovery_ui/screen_ui.cpp
@@ -48,6 +48,11 @@
 #include "recovery_ui/device.h"
 #include "recovery_ui/ui.h"
 
+enum DirectRenderManager {
+    DRM_INNER,
+    DRM_OUTER,
+};
+
 // Return the current time as a double (including fractions of a second).
 static double now() {
   struct timeval tv;
@@ -334,7 +339,8 @@
       stage(-1),
       max_stage(-1),
       locale_(""),
-      rtl_locale_(false) {}
+      rtl_locale_(false),
+      is_graphics_available(false) {}
 
 ScreenRecoveryUI::~ScreenRecoveryUI() {
   progress_thread_stopped_ = true;
@@ -906,6 +912,7 @@
   if (!InitGraphics()) {
     return false;
   }
+  is_graphics_available = true;
 
   if (!InitTextParams()) {
     return false;
@@ -950,6 +957,9 @@
   // Keep the progress bar updated, even when the process is otherwise busy.
   progress_thread_ = std::thread(&ScreenRecoveryUI::ProgressThreadLoop, this);
 
+  // set the callback for hall sensor event
+  (void)ev_sync_sw_state([this](auto&& a, auto&& b) { return this->SetSwCallback(a, b);});
+
   return true;
 }
 
@@ -1367,3 +1377,45 @@
     }
   }
 }
+
+int ScreenRecoveryUI::SetSwCallback(int code, int value) {
+  if (!is_graphics_available) { return -1; }
+  if (code > SW_MAX) { return -1; }
+  if (code != SW_LID) { return 0; }
+
+  /* detect dual display */
+  if (!gr_has_multiple_connectors()) { return -1; }
+
+  /* turn off all screen */
+  gr_fb_blank(true, DirectRenderManager::DRM_INNER);
+  gr_fb_blank(true, DirectRenderManager::DRM_OUTER);
+  gr_color(0, 0, 0, 255);
+  gr_clear();
+
+  /* turn on the screen */
+  gr_fb_blank(false, value);
+  gr_flip();
+
+  /* set the retation */
+  std::string rotation_str;
+  if (value == DirectRenderManager::DRM_OUTER) {
+    rotation_str =
+      android::base::GetProperty("ro.minui.second_rotation", "ROTATION_NONE");
+  } else {
+    rotation_str =
+      android::base::GetProperty("ro.minui.default_rotation", "ROTATION_NONE");
+  }
+
+  if (rotation_str == "ROTATION_RIGHT") {
+    gr_rotate(GRRotation::RIGHT);
+  } else if (rotation_str == "ROTATION_DOWN") {
+    gr_rotate(GRRotation::DOWN);
+  } else if (rotation_str == "ROTATION_LEFT") {
+    gr_rotate(GRRotation::LEFT);
+  } else {  // "ROTATION_NONE" or unknown string
+    gr_rotate(GRRotation::NONE);
+  }
+  Redraw();
+
+  return 0;
+}
diff --git a/recovery_ui/ui.cpp b/recovery_ui/ui.cpp
index 6e67b1d..eb87f52 100644
--- a/recovery_ui/ui.cpp
+++ b/recovery_ui/ui.cpp
@@ -341,6 +341,11 @@
     ProcessKey(ev.code, ev.value);
   }
 
+  // For Lid switch handle
+  if (ev.type == EV_SW) {
+    SetSwCallback(ev.code, ev.value);
+  }
+
   return 0;
 }
 
diff --git a/recovery_utils/Android.bp b/recovery_utils/Android.bp
index 9bd66c5..74392c5 100644
--- a/recovery_utils/Android.bp
+++ b/recovery_utils/Android.bp
@@ -75,11 +75,11 @@
 
     shared_libs: [
         // The following cannot be placed in librecovery_utils_defaults,
-        // because at the time of writing, android.hardware.health-V1-ndk.so
+        // because at the time of writing, android.hardware.health-V2-ndk.so
         // is not installed to the system image yet. (It is installed
         // to the recovery ramdisk.) Hence, minadbd_test must link to it
         // statically.
-        "android.hardware.health-V1-ndk",
+        "android.hardware.health-V2-ndk",
     ],
 
     export_include_dirs: [
diff --git a/tests/Android.bp b/tests/Android.bp
index 0708e85..b888d47 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -148,7 +148,7 @@
 
     static_libs: libapplypatch_static_libs + librecovery_static_libs + [
         "android.hardware.health-translate-ndk",
-        "android.hardware.health-V1-ndk",
+        "android.hardware.health-V2-ndk",
         "libhealthshim",
         "librecovery_ui",
         "libfusesideload",
diff --git a/tools/image_generator/ImageGenerator.java b/tools/image_generator/ImageGenerator.java
index 6c5ea4b..00264b1 100644
--- a/tools/image_generator/ImageGenerator.java
+++ b/tools/image_generator/ImageGenerator.java
@@ -16,6 +16,8 @@
 
 package com.android.recovery.tools;
 
+import static java.util.Map.entry;
+
 import com.ibm.icu.text.BreakIterator;
 
 import org.apache.commons.cli.CommandLine;
@@ -111,49 +113,43 @@
     // https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
     private static final String DEFAULT_FONT_NAME = "Roboto-Regular";
     private static final Map<String, String> LANGUAGE_TO_FONT_MAP =
-            new TreeMap<String, String>() {
-                {
-                    put("am", "NotoSansEthiopic-VF");
-                    put("ar", "NotoNaskhArabicUI-Regular");
-                    put("as", "NotoSansBengaliUI-VF");
-                    put("bn", "NotoSansBengaliUI-VF");
-                    put("fa", "NotoNaskhArabicUI-Regular");
-                    put("gu", "NotoSansGujaratiUI-Regular");
-                    put("hi", "NotoSansDevanagariUI-VF");
-                    put("hy", "NotoSansArmenian-VF");
-                    put("iw", "NotoSansHebrew-Regular");
-                    put("ja", "NotoSansCJK-Regular");
-                    put("ka", "NotoSansGeorgian-VF");
-                    put("ko", "NotoSansCJK-Regular");
-                    put("km", "NotoSansKhmerUI-Regular");
-                    put("kn", "NotoSansKannadaUI-VF");
-                    put("lo", "NotoSansLaoUI-Regular");
-                    put("ml", "NotoSansMalayalamUI-VF");
-                    put("mr", "NotoSansDevanagariUI-VF");
-                    put("my", "NotoSansMyanmarUI-Regular");
-                    put("ne", "NotoSansDevanagariUI-VF");
-                    put("or", "NotoSansOriya-Regular");
-                    put("pa", "NotoSansGurmukhiUI-VF");
-                    put("si", "NotoSansSinhalaUI-VF");
-                    put("ta", "NotoSansTamilUI-VF");
-                    put("te", "NotoSansTeluguUI-VF");
-                    put("th", "NotoSansThaiUI-Regular");
-                    put("ur", "NotoNaskhArabicUI-Regular");
-                    put("zh", "NotoSansCJK-Regular");
-                }
-            };
+            Map.ofEntries(
+                entry("am", "NotoSansEthiopic-VF"),
+                entry("ar", "NotoNaskhArabicUI-Regular"),
+                entry("as", "NotoSansBengaliUI-VF"),
+                entry("bn", "NotoSansBengaliUI-VF"),
+                entry("fa", "NotoNaskhArabicUI-Regular"),
+                entry("gu", "NotoSansGujaratiUI-Regular"),
+                entry("hi", "NotoSansDevanagariUI-VF"),
+                entry("hy", "NotoSansArmenian-VF"),
+                entry("iw", "NotoSansHebrew-Regular"),
+                entry("ja", "NotoSansCJK-Regular"),
+                entry("ka", "NotoSansGeorgian-VF"),
+                entry("ko", "NotoSansCJK-Regular"),
+                entry("km", "NotoSansKhmerUI-Regular"),
+                entry("kn", "NotoSansKannadaUI-VF"),
+                entry("lo", "NotoSansLaoUI-Regular"),
+                entry("ml", "NotoSansMalayalamUI-VF"),
+                entry("mr", "NotoSansDevanagariUI-VF"),
+                entry("my", "NotoSansMyanmarUI-Regular"),
+                entry("ne", "NotoSansDevanagariUI-VF"),
+                entry("or", "NotoSansOriya-Regular"),
+                entry("pa", "NotoSansGurmukhiUI-VF"),
+                entry("si", "NotoSansSinhalaUI-VF"),
+                entry("ta", "NotoSansTamilUI-VF"),
+                entry("te", "NotoSansTeluguUI-VF"),
+                entry("th", "NotoSansThaiUI-Regular"),
+                entry("ur", "NotoNaskhArabicUI-Regular"),
+                entry("zh", "NotoSansCJK-Regular"));
 
     // Languages that write from right to left.
     private static final Set<String> RTL_LANGUAGE =
-            new HashSet<String>() {
-                {
-                    add("ar"); // Arabic
-                    add("fa"); // Persian
-                    add("he"); // Hebrew
-                    add("iw"); // Hebrew
-                    add("ur"); // Urdu
-                }
-            };
+            Set.of(
+                "ar",  // Arabic
+                "fa",  // Persian
+                "he",  // Hebrew
+                "iw",  // Hebrew
+                "ur"); // Urdu
 
     /** Exception to indicate the failure to find the translated text strings. */
     public static class LocalizedStringNotFoundException extends Exception {
diff --git a/tools/recovery_l10n/res/values-as/strings.xml b/tools/recovery_l10n/res/values-as/strings.xml
index 8119090..d956b9a 100644
--- a/tools/recovery_l10n/res/values-as/strings.xml
+++ b/tools/recovery_l10n/res/values-as/strings.xml
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="2013591905463558223">"আপডে’ট ইনষ্টল কৰি থকা হৈছে"</string>
+    <string name="recovery_installing" msgid="2013591905463558223">"আপডেইট ইনষ্টল কৰি থকা হৈছে"</string>
     <string name="recovery_erasing" msgid="7334826894904037088">"মচি থকা হৈছে"</string>
     <string name="recovery_no_command" msgid="4465476568623024327">"কোনো আদেশ নাই"</string>
     <string name="recovery_error" msgid="5748178989622716736">"ত্ৰুটি!"</string>
-    <string name="recovery_installing_security" msgid="9184031299717114342">"সুৰক্ষা আপডে’ট ইনষ্টল কৰি থকা হৈছে"</string>
+    <string name="recovery_installing_security" msgid="9184031299717114342">"সুৰক্ষা আপডেইট ইনষ্টল কৰি থকা হৈছে"</string>
     <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Android ছিষ্টেম ল\'ড কৰিব নোৱাৰি। আপোনাৰ ডেটাত কিবা আসোঁৱাহ থকা যেন লাগিছে। আপুনি যদি এই বাৰ্তাটো পায়েই থাকে, আপুনি নিজৰ ডিভাইচটো ফেক্টৰী ডেটা ৰিছেট কৰি সেইটোত থকা ব্যৱহাৰকাৰীৰ আটাইবোৰ ডেটা মচিব লগা হ\'ব পাৰে।"</string>
     <string name="recovery_try_again" msgid="7168248750158873496">"আকৌ চেষ্টা কৰক"</string>
     <string name="recovery_factory_data_reset" msgid="7321351565602894783">"ফেক্টৰী ডেটা ৰিছেট"</string>
diff --git a/update_verifier/Android.bp b/update_verifier/Android.bp
index 220b007..26ff530 100644
--- a/update_verifier/Android.bp
+++ b/update_verifier/Android.bp
@@ -39,14 +39,6 @@
         "care_map.proto",
     ],
     proto: {type: "lite", canonical_path_from_root: false},
-    version: {
-        py2: {
-            enabled: true,
-        },
-        py3: {
-            enabled: true,
-        },
-    },
     visibility: [
         "//build/make/tools/releasetools:__subpackages__",
     ],
@@ -73,8 +65,13 @@
         "libvold_binder",
     ],
 
+    whole_static_libs: [
+        "libsnapshot_snapuserd",
+    ],
+
     shared_libs: [
         "android.hardware.boot@1.0",
+        "libboot_control_client",
         "libbase",
         "libcutils",
         "libbinder",
@@ -114,6 +111,7 @@
         "libprotobuf-cpp-lite",
         "libbinder",
         "libutils",
+        "libboot_control_client",
     ],
 
     init_rc: [
@@ -139,12 +137,7 @@
     },
 
     version: {
-        py2: {
-            enabled: false,
-            embedded_launcher: false,
-        },
         py3: {
-            enabled: true,
             embedded_launcher: true,
         },
     },
diff --git a/update_verifier/include/update_verifier/update_verifier.h b/update_verifier/include/update_verifier/update_verifier.h
index 4c64b1e..0cccc90 100644
--- a/update_verifier/include/update_verifier/update_verifier.h
+++ b/update_verifier/include/update_verifier/update_verifier.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <vector>
 
+#include <snapuserd/snapuserd_client.h>
 #include "otautil/rangeset.h"
 
 // The update verifier performs verification upon the first boot to a new slot on A/B devices.
@@ -68,4 +69,8 @@
 
   // The function to read the device property; default value: android::base::GetProperty()
   std::function<std::string(const std::string&)> property_reader_;
+
+  // Check if snapuserd daemon has already completed the update verification
+  // Applicable only for VABC with userspace snapshots
+  bool CheckVerificationStatus();
 };
diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp
index a042f90..a0160e2 100644
--- a/update_verifier/update_verifier.cpp
+++ b/update_verifier/update_verifier.cpp
@@ -52,13 +52,14 @@
 #include <future>
 #include <thread>
 
+#include <BootControlClient.h>
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <android/hardware/boot/1.0/IBootControl.h>
 #include <android/os/IVold.h>
 #include <binder/BinderService.h>
 #include <binder/Status.h>
@@ -66,11 +67,6 @@
 
 #include "care_map.pb.h"
 
-using android::sp;
-using android::hardware::boot::V1_0::IBootControl;
-using android::hardware::boot::V1_0::BoolResult;
-using android::hardware::boot::V1_0::CommandResult;
-
 // TODO(xunchang) remove the prefix and use a default path instead.
 constexpr const char* kDefaultCareMapPrefix = "/data/ota_package/care_map";
 
@@ -91,7 +87,7 @@
 // partition's integrity.
 std::map<std::string, std::string> UpdateVerifier::FindDmPartitions() {
   static constexpr auto DM_PATH_PREFIX = "/sys/block/";
-  dirent** namelist;
+  dirent** namelist = nullptr;
   int n = scandir(DM_PATH_PREFIX, &namelist, dm_name_filter, alphasort);
   if (n == -1) {
     PLOG(ERROR) << "Failed to scan dir " << DM_PATH_PREFIX;
@@ -154,7 +150,6 @@
       static constexpr size_t kBlockSize = 4096;
       std::vector<uint8_t> buf(1024 * kBlockSize);
 
-      size_t block_count = 0;
       for (const auto& [range_start, range_end] : group) {
         if (lseek64(fd.get(), static_cast<off64_t>(range_start) * kBlockSize, SEEK_SET) == -1) {
           PLOG(ERROR) << "lseek to " << range_start << " failed";
@@ -170,9 +165,7 @@
           }
           remain -= to_read;
         }
-        block_count += (range_end - range_start);
       }
-      LOG(INFO) << "Finished reading " << block_count << " blocks on " << dm_block_device;
       return true;
     };
 
@@ -183,12 +176,33 @@
   for (auto& t : threads) {
     ret = t.get() && ret;
   }
-  LOG(INFO) << "Finished reading blocks on " << dm_block_device << " with " << thread_num
-            << " threads.";
+  LOG(INFO) << "Finished reading blocks on partition " << partition_name << " @ " << dm_block_device
+            << " with " << thread_num << " threads.";
   return ret;
 }
 
+bool UpdateVerifier::CheckVerificationStatus() {
+  auto client =
+      android::snapshot::SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 5s);
+  if (!client) {
+    LOG(ERROR) << "Unable to connect to snapuserd";
+    return false;
+  }
+
+  return client->QueryUpdateVerification();
+}
+
 bool UpdateVerifier::VerifyPartitions() {
+  const bool userspace_snapshots =
+      android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
+
+  if (userspace_snapshots && CheckVerificationStatus()) {
+    LOG(INFO) << "Partitions verified by snapuserd daemon";
+    return true;
+  }
+
+  LOG(INFO) << "Partitions not verified by snapuserd daemon";
+
   auto dm_block_devices = FindDmPartitions();
   if (dm_block_devices.empty()) {
     LOG(ERROR) << "No dm-enabled block device is found.";
@@ -307,18 +321,21 @@
     LOG(INFO) << "Started with arg " << i << ": " << argv[i];
   }
 
-  sp<IBootControl> module = IBootControl::getService();
+  const auto module = android::hal::BootControlClient::WaitForService();
   if (module == nullptr) {
     LOG(ERROR) << "Error getting bootctrl module.";
     return reboot_device();
   }
 
-  uint32_t current_slot = module->getCurrentSlot();
-  BoolResult is_successful = module->isSlotMarkedSuccessful(current_slot);
-  LOG(INFO) << "Booting slot " << current_slot << ": isSlotMarkedSuccessful="
-            << static_cast<int32_t>(is_successful);
-
-  if (is_successful == BoolResult::FALSE) {
+  uint32_t current_slot = module->GetCurrentSlot();
+  const auto is_successful = module->IsSlotMarkedSuccessful(current_slot);
+  if (!is_successful.has_value()) {
+    LOG(INFO) << "Booting slot " << current_slot << " failed";
+  } else {
+    LOG(INFO) << "Booting slot " << current_slot
+              << ": isSlotMarkedSuccessful=" << is_successful.value();
+  }
+  if (is_successful.has_value() && !is_successful.value()) {
     // The current slot has not booted successfully.
 
     bool skip_verification = false;
@@ -364,8 +381,7 @@
     }
 
     if (!supports_checkpoint) {
-      CommandResult cr;
-      module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
+      const auto cr = module->MarkBootSuccessful();
       if (!cr.success) {
         LOG(ERROR) << "Error marking booted successfully: " << cr.errMsg;
         return reboot_device();