Merge "Fix non-ab fuse ota fail bug"
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
index b70d54e..1ea56cd 100644
--- a/bootloader_message/bootloader_message.cpp
+++ b/bootloader_message/bootloader_message.cpp
@@ -304,6 +304,16 @@
                                        offsetof(misc_system_space_layout, virtual_ab_message), err);
 }
 
+bool ReadMiscMemtagMessage(misc_memtag_message* message, std::string* err) {
+  return ReadMiscPartitionSystemSpace(message, sizeof(*message),
+                                      offsetof(misc_system_space_layout, memtag_message), err);
+}
+
+bool WriteMiscMemtagMessage(const misc_memtag_message& message, std::string* err) {
+  return WriteMiscPartitionSystemSpace(&message, sizeof(message),
+                                       offsetof(misc_system_space_layout, memtag_message), err);
+}
+
 extern "C" bool write_reboot_bootloader(void) {
   std::string err;
   return write_reboot_bootloader(&err);
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
index e4cf09b..d58158d 100644
--- a/bootloader_message/include/bootloader_message/bootloader_message.h
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -93,18 +93,35 @@
   uint8_t reserved[57];
 } __attribute__((packed));
 
+struct misc_memtag_message {
+  uint8_t version;
+  uint32_t magic; // magic string for treble compat
+  uint32_t memtag_mode;
+  uint8_t reserved[55];
+} __attribute__((packed));
+
 #define MISC_VIRTUAL_AB_MESSAGE_VERSION 2
 #define MISC_VIRTUAL_AB_MAGIC_HEADER 0x56740AB0
 
+#define MISC_MEMTAG_MESSAGE_VERSION 1
+#define MISC_MEMTAG_MAGIC_HEADER 0x5afefe5a
+#define MISC_MEMTAG_MODE_MEMTAG 0x1
+#define MISC_MEMTAG_MODE_MEMTAG_ONCE 0x2
+#define MISC_MEMTAG_MODE_MEMTAG_KERNEL 0x4
+#define MISC_MEMTAG_MODE_MEMTAG_KERNEL_ONCE 0x8
+
 #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
 static_assert(sizeof(struct misc_virtual_ab_message) == 64,
               "struct misc_virtual_ab_message has wrong size");
+static_assert(sizeof(struct misc_memtag_message) == 64,
+              "struct misc_memtag_message has wrong size");
 #endif
 
 // This struct is not meant to be used directly, rather, it is to make
 // computation of offsets easier. New fields must be added to the end.
 struct misc_system_space_layout {
   misc_virtual_ab_message virtual_ab_message;
+  misc_memtag_message memtag_message;
 } __attribute__((packed));
 
 #ifdef __cplusplus
@@ -172,6 +189,9 @@
 bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err);
 bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err);
 
+// Read or write the memtag message from system space in /misc.
+bool ReadMiscMemtagMessage(misc_memtag_message* message, std::string* err);
+bool WriteMiscMemtagMessage(const misc_memtag_message& message, std::string* err);
 #else
 
 #include <stdbool.h>
diff --git a/edify/parser.yy b/edify/parser.yy
index 37bcdd0..5e1e847 100644
--- a/edify/parser.yy
+++ b/edify/parser.yy
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/install/adb_install.cpp b/install/adb_install.cpp
index ee79a32..5cba7b6 100644
--- a/install/adb_install.cpp
+++ b/install/adb_install.cpp
@@ -90,11 +90,12 @@
 
 // Installs the package from FUSE. Returns the installation result and whether it should continue
 // waiting for new commands.
-static auto AdbInstallPackageHandler(RecoveryUI* ui, InstallResult* result) {
+static auto AdbInstallPackageHandler(Device* device, InstallResult* result) {
   // How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long
   // because the minadbd service has already issued an install command. FUSE_SIDELOAD_HOST_PATHNAME
   // will start to exist once the host connects and starts serving a package. Poll for its
   // appearance. (Note that inotify doesn't work with FUSE.)
+  auto ui = device->GetUI();
   constexpr int ADB_INSTALL_TIMEOUT = 15;
   bool should_continue = true;
   *result = INSTALL_ERROR;
@@ -114,7 +115,7 @@
     auto package =
         Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME,
                                    std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
-    *result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0, ui);
+    *result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0, device);
     break;
   }
 
@@ -348,7 +349,7 @@
 
   InstallResult install_result = INSTALL_ERROR;
   std::map<MinadbdCommand, CommandFunction> command_map{
-    { MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, ui, &install_result) },
+    { MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, device, &install_result) },
     { MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid,
                                                 &install_result, reboot_action) },
     { MinadbdCommand::kRebootBootloader,
diff --git a/install/fuse_install.cpp b/install/fuse_install.cpp
index 143b5d3..197e1de 100644
--- a/install/fuse_install.cpp
+++ b/install/fuse_install.cpp
@@ -146,10 +146,11 @@
   return run_fuse_sideload(std::move(fuse_data_provider)) == 0;
 }
 
-InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui) {
+InstallResult InstallWithFuseFromPath(std::string_view path, Device* device) {
   // We used to use fuse in a thread as opposed to a process. Since accessing
   // through fuse involves going from kernel to userspace to kernel, it leads
   // to deadlock when a page fault occurs. (Bug: 26313124)
+  auto ui = device->GetUI();
   pid_t child;
   if ((child = fork()) == 0) {
     bool status = StartInstallPackageFuse(path);
@@ -183,8 +184,8 @@
     auto package =
         Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME,
                                    std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
-    result =
-        InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0 /* retry_count */, ui);
+    result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0 /* retry_count */,
+                            device);
     break;
   }
 
@@ -226,7 +227,7 @@
   ui->Print("\n-- Install %s ...\n", path.c_str());
   SetSdcardUpdateBootloaderMessage();
 
-  auto result = InstallWithFuseFromPath(path, ui);
+  auto result = InstallWithFuseFromPath(path, device);
   ensure_path_unmounted(SDCARD_ROOT);
   return result;
 }
diff --git a/install/include/install/fuse_install.h b/install/include/install/fuse_install.h
index 63b116a..29c283f 100644
--- a/install/include/install/fuse_install.h
+++ b/install/include/install/fuse_install.h
@@ -25,6 +25,6 @@
 // Starts FUSE with the package from |path| as the data source. And installs the package from
 // |FUSE_SIDELOAD_HOST_PATHNAME|. The |path| can point to the location of a package zip file or a
 // block map file with the prefix '@'; e.g. /sdcard/package.zip, @/cache/recovery/block.map.
-InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui);
+InstallResult InstallWithFuseFromPath(std::string_view path, Device* device);
 
 InstallResult ApplyFromSdcard(Device* device);
diff --git a/install/include/install/install.h b/install/include/install/install.h
index 704841f..0f5102f 100644
--- a/install/include/install/install.h
+++ b/install/include/install/install.h
@@ -25,6 +25,7 @@
 #include <ziparchive/zip_archive.h>
 
 #include "otautil/package.h"
+#include "recovery_ui/device.h"
 #include "recovery_ui/ui.h"
 
 enum InstallResult {
@@ -49,7 +50,8 @@
 // cache partition after a successful installation if |should_wipe_cache| is true or an updater
 // command asks to wipe the cache.
 InstallResult InstallPackage(Package* package, const std::string_view package_id,
-                             bool should_wipe_cache, int retry_count, RecoveryUI* ui);
+                             bool should_wipe_cache, int retry_count,
+                             Device* ui);
 
 // Verifies the package by ota keys. Returns true if the package is verified successfully,
 // otherwise returns false.
diff --git a/install/install.cpp b/install/install.cpp
index bb8c3b8..811bcb0 100644
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -235,30 +235,41 @@
   return true;
 }
 
-bool SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
-                           std::vector<std::string>* cmd) {
-  CHECK(cmd != nullptr);
-
+static std::string ExtractPayloadProperties(ZipArchiveHandle zip) {
   // For A/B updates we extract the payload properties to a buffer and obtain the RAW payload offset
   // in the zip file.
   static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt";
   ZipEntry64 properties_entry;
   if (FindEntry(zip, AB_OTA_PAYLOAD_PROPERTIES, &properties_entry) != 0) {
     LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD_PROPERTIES;
-    return false;
+    return {};
   }
   auto properties_entry_length = properties_entry.uncompressed_length;
   if (properties_entry_length > std::numeric_limits<size_t>::max()) {
     LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES
                << " because's uncompressed size exceeds size of address space. "
                << properties_entry_length;
-    return false;
+    return {};
   }
-  std::vector<uint8_t> payload_properties(properties_entry_length);
+  std::string payload_properties(properties_entry_length, '\0');
   int32_t err =
-      ExtractToMemory(zip, &properties_entry, payload_properties.data(), properties_entry_length);
+      ExtractToMemory(zip, &properties_entry, reinterpret_cast<uint8_t*>(payload_properties.data()),
+                      properties_entry_length);
   if (err != 0) {
     LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES << ": " << ErrorCodeString(err);
+    return {};
+  }
+  return payload_properties;
+}
+
+bool SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
+                           std::vector<std::string>* cmd) {
+  CHECK(cmd != nullptr);
+
+  // For A/B updates we extract the payload properties to a buffer and obtain the RAW payload offset
+  // in the zip file.
+  const auto payload_properties = ExtractPayloadProperties(zip);
+  if (payload_properties.empty()) {
     return false;
   }
 
@@ -332,10 +343,20 @@
   }
 }
 
+static bool PerformPowerwashIfRequired(ZipArchiveHandle zip, Device *device) {
+  const auto payload_properties = ExtractPayloadProperties(zip);
+  if (payload_properties.find("POWERWASH=1") != std::string::npos) {
+    LOG(INFO) << "Payload properties has POWERWASH=1, wiping userdata...";
+    return WipeData(device, true);
+  }
+  return true;
+}
+
 // If the package contains an update binary, extract it and run it.
 static InstallResult TryUpdateBinary(Package* package, bool* wipe_cache,
                                      std::vector<std::string>* log_buffer, int retry_count,
-                                     int* max_temperature, RecoveryUI* ui) {
+                                     int* max_temperature, Device* device) {
+  auto ui = device->GetUI();
   std::map<std::string, std::string> metadata;
   auto zip = package->GetZipArchiveHandle();
   if (!ReadMetadataFromPackage(zip, &metadata)) {
@@ -530,13 +551,15 @@
   } else {
     LOG(FATAL) << "Invalid status code " << status;
   }
+  PerformPowerwashIfRequired(zip, device);
 
   return INSTALL_SUCCESS;
 }
 
 static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
                                              std::vector<std::string>* log_buffer, int retry_count,
-                                             int* max_temperature, RecoveryUI* ui) {
+                                             int* max_temperature, Device* device) {
+  auto ui = device->GetUI();
   ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
   // Give verification half the progress bar...
   ui->SetProgressType(RecoveryUI::DETERMINATE);
@@ -554,7 +577,8 @@
     ui->Print("Retry attempt: %d\n", retry_count);
   }
   ui->SetEnableReboot(false);
-  auto result = TryUpdateBinary(package, wipe_cache, log_buffer, retry_count, max_temperature, ui);
+  auto result =
+      TryUpdateBinary(package, wipe_cache, log_buffer, retry_count, max_temperature, device);
   ui->SetEnableReboot(true);
   ui->Print("\n");
 
@@ -562,7 +586,8 @@
 }
 
 InstallResult InstallPackage(Package* package, const std::string_view package_id,
-                             bool should_wipe_cache, int retry_count, RecoveryUI* ui) {
+                             bool should_wipe_cache, int retry_count, Device* device) {
+  auto ui = device->GetUI();
   auto start = std::chrono::system_clock::now();
 
   int start_temperature = GetMaxValueFromThermalZone();
@@ -584,7 +609,7 @@
   } else {
     bool updater_wipe_cache = false;
     result = VerifyAndInstallPackage(package, &updater_wipe_cache, &log_buffer, retry_count,
-                                     &max_temperature, ui);
+                                     &max_temperature, device);
     should_wipe_cache = should_wipe_cache || updater_wipe_cache;
   }
 
diff --git a/minui/events.cpp b/minui/events.cpp
index 87f8112..b307a49 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -29,7 +29,9 @@
 
 #include <functional>
 #include <memory>
+#include <string>
 
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
 #include "minui/minui.h"
@@ -118,12 +120,12 @@
     }
     offset += sizeof(inotify_event) + pevent->len;
 
-    pevent->name[pevent->len] = '\0';
-    if (strncmp(pevent->name, "event", 5)) {
+    std::string event_name(pevent->name, pevent->len);
+    if (!android::base::StartsWith(event_name, "event")) {
       continue;
     }
 
-    android::base::unique_fd dfd(openat(dirfd(dir.get()), pevent->name, O_RDONLY));
+    android::base::unique_fd dfd(openat(dirfd(dir.get()), event_name.c_str(), O_RDONLY));
     if (dfd == -1) {
       break;
     }
@@ -265,6 +267,35 @@
   return -1;
 }
 
+int ev_sync_sw_state(const ev_set_sw_callback& set_sw_cb) {
+  // Use unsigned long to match ioctl's parameter type.
+  unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];  // NOLINT
+  unsigned long sw_bits[BITS_TO_LONGS(SW_MAX)];  // NOLINT
+
+  for (size_t i = 0; i < g_ev_dev_count; ++i) {
+    memset(ev_bits, 0, sizeof(ev_bits));
+    memset(sw_bits, 0, sizeof(sw_bits));
+
+    if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
+      continue;
+    }
+    if (!test_bit(EV_SW, ev_bits)) {
+      continue;
+    }
+    if (ioctl(ev_fdinfo[i].fd, EVIOCGSW(sizeof(sw_bits)), sw_bits) == -1) {
+      continue;
+    }
+
+    for (int code = 0; code <= SW_MAX; code++) {
+      if (test_bit(code, sw_bits)) {
+        set_sw_cb(code, 1);
+      }
+    }
+  }
+
+  return 0;
+}
+
 int ev_sync_key_state(const ev_set_key_callback& set_key_cb) {
   // Use unsigned long to match ioctl's parameter type.
   unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];    // NOLINT
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index f25694a..597f2ce 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -450,6 +450,10 @@
   gr_backend->Blank(blank);
 }
 
+void gr_fb_blank(bool blank, int index) {
+  gr_backend->Blank(blank, static_cast<MinuiBackend::DrmConnector>(index));
+}
+
 void gr_rotate(GRRotation rot) {
   rotation = rot;
 }
diff --git a/minui/graphics.h b/minui/graphics.h
index 3c45a40..5408c93 100644
--- a/minui/graphics.h
+++ b/minui/graphics.h
@@ -21,6 +21,12 @@
 
 class MinuiBackend {
  public:
+  enum DrmConnector {
+    DRM_MAIN = 0,
+    DRM_SEC,
+    DRM_MAX,
+  };
+
   // Initializes the backend and returns a GRSurface* to draw into.
   virtual GRSurface* Init() = 0;
 
@@ -28,9 +34,12 @@
   // be displayed, and returns a new drawing surface.
   virtual GRSurface* Flip() = 0;
 
-  // Blank (or unblank) the screen.
+  // Blank (or unblank) the default screen.
   virtual void Blank(bool) = 0;
 
+  // Blank (or unblank) the specific screen.
+  virtual void Blank(bool blank, DrmConnector index) = 0;
+
   // Device cleanup when drawing is done.
   virtual ~MinuiBackend() {};
 };
diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp
index 9d31ff7..c557022 100644
--- a/minui/graphics_drm.cpp
+++ b/minui/graphics_drm.cpp
@@ -153,22 +153,50 @@
 }
 
 bool MinuiBackendDrm::DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc,
-                                    const std::unique_ptr<GRSurfaceDrm>& surface) {
+                                    const std::unique_ptr<GRSurfaceDrm>& surface,
+                                    uint32_t* connector_id) {
   if (drmModeSetCrtc(drm_fd, crtc->crtc_id, surface->fb_id, 0, 0,  // x,y
-                     &main_monitor_connector->connector_id,
-                     1,  // connector_count
-                     &main_monitor_crtc->mode) != 0) {
-    perror("Failed to drmModeSetCrtc");
+                     connector_id, 1,                              // connector_count
+                     &crtc->mode) != 0) {
+    fprintf(stderr, "Failed to drmModeSetCrtc(%d)\n", *connector_id);
     return false;
   }
+
   return true;
 }
 
 void MinuiBackendDrm::Blank(bool blank) {
+  Blank(blank, DRM_MAIN);
+}
+
+void MinuiBackendDrm::Blank(bool blank, DrmConnector index) {
+  const auto* drmInterface = &drm[DRM_MAIN];
+
+  switch (index) {
+    case DRM_MAIN:
+      drmInterface = &drm[DRM_MAIN];
+      break;
+    case DRM_SEC:
+      drmInterface = &drm[DRM_SEC];
+      break;
+    default:
+      fprintf(stderr, "Invalid index: %d\n", index);
+      return;
+  }
+
+  if (!drmInterface->monitor_connector) {
+    fprintf(stderr, "Unsupported. index = %d\n", index);
+    return;
+  }
+
   if (blank) {
-    DrmDisableCrtc(drm_fd, main_monitor_crtc);
+    DrmDisableCrtc(drm_fd, drmInterface->monitor_crtc);
   } else {
-    DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]);
+    DrmEnableCrtc(drm_fd, drmInterface->monitor_crtc,
+                  drmInterface->GRSurfaceDrms[drmInterface->current_buffer],
+                  &drmInterface->monitor_connector->connector_id);
+
+    active_display = index;
   }
 }
 
@@ -210,18 +238,21 @@
   return nullptr;
 }
 
-static drmModeConnector* find_used_connector_by_type(int fd, drmModeRes* resources, unsigned type) {
+std::vector<drmModeConnector*> find_used_connector_by_type(int fd, drmModeRes* resources,
+                                                           unsigned type) {
+  std::vector<drmModeConnector*> drmConnectors;
   for (int i = 0; i < resources->count_connectors; i++) {
     drmModeConnector* connector = drmModeGetConnector(fd, resources->connectors[i]);
     if (connector) {
       if ((connector->connector_type == type) && (connector->connection == DRM_MODE_CONNECTED) &&
           (connector->count_modes > 0)) {
-        return connector;
+        drmConnectors.push_back(connector);
+      } else {
+        drmModeFreeConnector(connector);
       }
-      drmModeFreeConnector(connector);
     }
   }
-  return nullptr;
+  return drmConnectors;
 }
 
 static drmModeConnector* find_first_connected_connector(int fd, drmModeRes* resources) {
@@ -239,8 +270,7 @@
   return nullptr;
 }
 
-drmModeConnector* MinuiBackendDrm::FindMainMonitor(int fd, drmModeRes* resources,
-                                                   uint32_t* mode_index) {
+bool MinuiBackendDrm::FindAndSetMonitor(int fd, drmModeRes* resources) {
   /* Look for LVDS/eDP/DSI connectors. Those are the main screens. */
   static constexpr unsigned kConnectorPriority[] = {
     DRM_MODE_CONNECTOR_LVDS,
@@ -248,37 +278,41 @@
     DRM_MODE_CONNECTOR_DSI,
   };
 
-  drmModeConnector* main_monitor_connector = nullptr;
-  unsigned i = 0;
-  do {
-    main_monitor_connector = find_used_connector_by_type(fd, resources, kConnectorPriority[i]);
-    i++;
-  } while (!main_monitor_connector && i < arraysize(kConnectorPriority));
-
-  /* If we didn't find a connector, grab the first one that is connected. */
-  if (!main_monitor_connector) {
-    main_monitor_connector = find_first_connected_connector(fd, resources);
-  }
-
-  /* If we still didn't find a connector, give up and return. */
-  if (!main_monitor_connector) return nullptr;
-
-  for (int modes = 0; modes < main_monitor_connector->count_modes; modes++) {
-    printf("Display Mode %d resolution: %d x %d @ %d FPS\n", modes,
-           main_monitor_connector->modes[modes].hdisplay,
-           main_monitor_connector->modes[modes].vdisplay,
-           main_monitor_connector->modes[modes].vrefresh);
-  }
-  *mode_index = 0;
-  for (int modes = 0; modes < main_monitor_connector->count_modes; modes++) {
-    if (main_monitor_connector->modes[modes].type & DRM_MODE_TYPE_PREFERRED) {
-      printf("Choosing display mode #%d\n", modes);
-      *mode_index = modes;
-      break;
+  std::vector<drmModeConnector*> drmConnectors;
+  for (int i = 0; i < arraysize(kConnectorPriority) && drmConnectors.size() < DRM_MAX; i++) {
+    auto connectors = find_used_connector_by_type(fd, resources, kConnectorPriority[i]);
+    for (auto connector : connectors) {
+      drmConnectors.push_back(connector);
+      if (drmConnectors.size() >= DRM_MAX) break;
     }
   }
 
-  return main_monitor_connector;
+  /* If we didn't find a connector, grab the first one that is connected. */
+  if (drmConnectors.empty()) {
+    drmModeConnector* connector = find_first_connected_connector(fd, resources);
+    if (connector) {
+      drmConnectors.push_back(connector);
+    }
+  }
+
+  for (int drm_index = 0; drm_index < drmConnectors.size(); drm_index++) {
+    drm[drm_index].monitor_connector = drmConnectors[drm_index];
+
+    drm[drm_index].selected_mode = 0;
+    for (int modes = 0; modes < drmConnectors[drm_index]->count_modes; modes++) {
+      printf("Display Mode %d resolution: %d x %d @ %d FPS\n", modes,
+             drmConnectors[drm_index]->modes[modes].hdisplay,
+             drmConnectors[drm_index]->modes[modes].vdisplay,
+             drmConnectors[drm_index]->modes[modes].vrefresh);
+      if (drmConnectors[drm_index]->modes[modes].type & DRM_MODE_TYPE_PREFERRED) {
+        printf("Choosing display mode #%d\n", modes);
+        drm[drm_index].selected_mode = modes;
+        break;
+      }
+    }
+  }
+
+  return drmConnectors.size() > 0;
 }
 
 void MinuiBackendDrm::DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc) {
@@ -329,46 +363,49 @@
     return nullptr;
   }
 
-  uint32_t selected_mode;
-  main_monitor_connector = FindMainMonitor(drm_fd, res, &selected_mode);
-  if (!main_monitor_connector) {
-    fprintf(stderr, "Failed to find main_monitor_connector\n");
+  if (!FindAndSetMonitor(drm_fd, res)) {
+    fprintf(stderr, "Failed to find main monitor_connector\n");
     drmModeFreeResources(res);
-    close(drm_fd);
     return nullptr;
   }
 
-  main_monitor_crtc = find_crtc_for_connector(drm_fd, res, main_monitor_connector);
-  if (!main_monitor_crtc) {
-    fprintf(stderr, "Failed to find main_monitor_crtc\n");
-    drmModeFreeResources(res);
-    close(drm_fd);
-    return nullptr;
+  for (int i = 0; i < DRM_MAX; i++) {
+    if (drm[i].monitor_connector) {
+      drm[i].monitor_crtc = find_crtc_for_connector(drm_fd, res, drm[i].monitor_connector);
+      if (!drm[i].monitor_crtc) {
+        fprintf(stderr, "Failed to find monitor_crtc, drm index=%d\n", i);
+        drmModeFreeResources(res);
+        return nullptr;
+      }
+
+      drm[i].monitor_crtc->mode = drm[i].monitor_connector->modes[drm[i].selected_mode];
+
+      int width = drm[i].monitor_crtc->mode.hdisplay;
+      int height = drm[i].monitor_crtc->mode.vdisplay;
+
+      drm[i].GRSurfaceDrms[0] = GRSurfaceDrm::Create(drm_fd, width, height);
+      drm[i].GRSurfaceDrms[1] = GRSurfaceDrm::Create(drm_fd, width, height);
+      if (!drm[i].GRSurfaceDrms[0] || !drm[i].GRSurfaceDrms[1]) {
+        fprintf(stderr, "Failed to create GRSurfaceDrm, drm index=%d\n", i);
+        drmModeFreeResources(res);
+        return nullptr;
+      }
+
+      drm[i].current_buffer = 0;
+    }
   }
 
-  DisableNonMainCrtcs(drm_fd, res, main_monitor_crtc);
-
-  main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode];
-
-  int width = main_monitor_crtc->mode.hdisplay;
-  int height = main_monitor_crtc->mode.vdisplay;
+  DisableNonMainCrtcs(drm_fd, res, drm[DRM_MAIN].monitor_crtc);
 
   drmModeFreeResources(res);
 
-  GRSurfaceDrms[0] = GRSurfaceDrm::Create(drm_fd, width, height);
-  GRSurfaceDrms[1] = GRSurfaceDrm::Create(drm_fd, width, height);
-  if (!GRSurfaceDrms[0] || !GRSurfaceDrms[1]) {
-    return nullptr;
-  }
-
-  current_buffer = 0;
-
   // We will likely encounter errors in the backend functions (i.e. Flip) if EnableCrtc fails.
-  if (!DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1])) {
+  if (!DrmEnableCrtc(drm_fd, drm[DRM_MAIN].monitor_crtc, drm[DRM_MAIN].GRSurfaceDrms[1],
+                     &drm[DRM_MAIN].monitor_connector->connector_id)) {
     return nullptr;
   }
 
-  return GRSurfaceDrms[0].get();
+  return drm[DRM_MAIN].GRSurfaceDrms[0].get();
 }
 
 static void page_flip_complete(__unused int fd,
@@ -380,10 +417,19 @@
 }
 
 GRSurface* MinuiBackendDrm::Flip() {
+  GRSurface* surface = NULL;
+  DrmInterface* current_drm = &drm[active_display];
   bool ongoing_flip = true;
-  if (drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, GRSurfaceDrms[current_buffer]->fb_id,
+
+  if (!current_drm->monitor_connector) {
+    fprintf(stderr, "Unsupported. active_display = %d\n", active_display);
+    return nullptr;
+  }
+
+  if (drmModePageFlip(drm_fd, current_drm->monitor_crtc->crtc_id,
+                      current_drm->GRSurfaceDrms[current_drm->current_buffer]->fb_id,
                       DRM_MODE_PAGE_FLIP_EVENT, &ongoing_flip) != 0) {
-    perror("Failed to drmModePageFlip");
+    fprintf(stderr, "Failed to drmModePageFlip, active_display=%d", active_display);
     return nullptr;
   }
 
@@ -409,14 +455,19 @@
     }
   }
 
-  current_buffer = 1 - current_buffer;
-  return GRSurfaceDrms[current_buffer].get();
+  current_drm->current_buffer = 1 - current_drm->current_buffer;
+  surface = current_drm->GRSurfaceDrms[current_drm->current_buffer].get();
+  return surface;
 }
 
 MinuiBackendDrm::~MinuiBackendDrm() {
-  DrmDisableCrtc(drm_fd, main_monitor_crtc);
-  drmModeFreeCrtc(main_monitor_crtc);
-  drmModeFreeConnector(main_monitor_connector);
+  for (int i = 0; i < DRM_MAX; i++) {
+    if (drm[i].monitor_connector) {
+      DrmDisableCrtc(drm_fd, drm[i].monitor_crtc);
+      drmModeFreeCrtc(drm[i].monitor_crtc);
+      drmModeFreeConnector(drm[i].monitor_connector);
+    }
+  }
   close(drm_fd);
   drm_fd = -1;
 }
diff --git a/minui/graphics_drm.h b/minui/graphics_drm.h
index 57ba39b..fe3beaf 100644
--- a/minui/graphics_drm.h
+++ b/minui/graphics_drm.h
@@ -59,16 +59,23 @@
   GRSurface* Init() override;
   GRSurface* Flip() override;
   void Blank(bool) override;
+  void Blank(bool blank, DrmConnector index) override;
 
  private:
   void DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc);
-  bool DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, const std::unique_ptr<GRSurfaceDrm>& surface);
+  bool DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, const std::unique_ptr<GRSurfaceDrm>& surface,
+                     uint32_t* conntcors);
   void DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc);
-  drmModeConnector* FindMainMonitor(int fd, drmModeRes* resources, uint32_t* mode_index);
+  bool FindAndSetMonitor(int fd, drmModeRes* resources);
 
-  std::unique_ptr<GRSurfaceDrm> GRSurfaceDrms[2];
-  int current_buffer{ 0 };
-  drmModeCrtc* main_monitor_crtc{ nullptr };
-  drmModeConnector* main_monitor_connector{ nullptr };
+  struct DrmInterface {
+    std::unique_ptr<GRSurfaceDrm> GRSurfaceDrms[2];
+    int current_buffer{ 0 };
+    drmModeCrtc* monitor_crtc{ nullptr };
+    drmModeConnector* monitor_connector{ nullptr };
+    uint32_t selected_mode{ 0 };
+  } drm[DRM_MAX];
+
   int drm_fd{ -1 };
+  DrmConnector active_display = DRM_MAIN;
 };
diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp
index 0d0fabc..1cb0c0a 100644
--- a/minui/graphics_fbdev.cpp
+++ b/minui/graphics_fbdev.cpp
@@ -43,6 +43,10 @@
   if (ret < 0) perror("ioctl(): blank");
 }
 
+void MinuiBackendFbdev::Blank(bool blank, DrmConnector index) {
+  fprintf(stderr, "Unsupported multiple connectors, blank = %d, index = %d\n", blank, index);
+}
+
 void MinuiBackendFbdev::SetDisplayedFramebuffer(size_t n) {
   if (n > 1 || !double_buffered) return;
 
diff --git a/minui/graphics_fbdev.h b/minui/graphics_fbdev.h
index 596ba74..7e193c4 100644
--- a/minui/graphics_fbdev.h
+++ b/minui/graphics_fbdev.h
@@ -56,6 +56,7 @@
   GRSurface* Init() override;
   GRSurface* Flip() override;
   void Blank(bool) override;
+  void Blank(bool blank, DrmConnector index) override;
 
  private:
   void SetDisplayedFramebuffer(size_t n);
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index 5470457..a2f62f0 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -127,6 +127,7 @@
 
 void gr_flip();
 void gr_fb_blank(bool blank);
+void gr_fb_blank(bool blank, int index);
 
 // Clears entire surface to current color.
 void gr_clear();
@@ -161,6 +162,7 @@
 
 using ev_callback = std::function<int(int fd, uint32_t epevents)>;
 using ev_set_key_callback = std::function<int(int code, int value)>;
+using ev_set_sw_callback = std::function<int(int code, int value)>;
 
 int ev_init(ev_callback input_cb, bool allow_touch_inputs = false);
 void ev_exit();
@@ -168,6 +170,7 @@
 void ev_iterate_available_keys(const std::function<void(int)>& f);
 void ev_iterate_touch_inputs(const std::function<void(int)>& action);
 int ev_sync_key_state(const ev_set_key_callback& set_key_cb);
+int ev_sync_sw_state(const ev_set_sw_callback& set_sw_cb);
 
 // 'timeout' has the same semantics as poll(2).
 //    0 : don't block
diff --git a/otautil/verifier.cpp b/otautil/verifier.cpp
index 92b9faf..8a65566 100644
--- a/otautil/verifier.cpp
+++ b/otautil/verifier.cpp
@@ -257,8 +257,8 @@
 
   // Check to make sure at least one of the keys matches the signature. Since any key can match,
   // we need to try each before determining a verification failure has happened.
-  size_t i = 0;
-  for (const auto& key : keys) {
+  for (size_t i = 0; i < keys.size(); i++) {
+    const auto& key = keys[i];
     const uint8_t* hash;
     int hash_nid;
     switch (key.hash_len) {
@@ -296,7 +296,6 @@
     } else {
       LOG(INFO) << "Unknown key type " << key.key_type;
     }
-    i++;
   }
 
   if (need_sha1) {
diff --git a/recovery.cpp b/recovery.cpp
index 641fe47..0c977c3 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -752,20 +752,20 @@
         status = INSTALL_ERROR;
       } else if (install_with_fuse || should_use_fuse) {
         LOG(INFO) << "Installing package " << update_package << " with fuse";
-        status = InstallWithFuseFromPath(update_package, ui);
+        status = InstallWithFuseFromPath(update_package, device);
       } else if (auto memory_package = Package::CreateMemoryPackage(
                      update_package,
                      std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
                  memory_package != nullptr) {
         status = InstallPackage(memory_package.get(), update_package, should_wipe_cache,
-                                retry_count, ui);
+                                retry_count, device);
       } else {
         // We may fail to memory map the package on 32 bit builds for packages with 2GiB+ size.
         // In such cases, we will try to install the package with fuse. This is not the default
         // installation method because it introduces a layer of indirection from the kernel space.
         LOG(WARNING) << "Failed to memory map package " << update_package
                      << "; falling back to install with fuse";
-        status = InstallWithFuseFromPath(update_package, ui);
+        status = InstallWithFuseFromPath(update_package, device);
       }
       if (status != INSTALL_SUCCESS) {
         ui->Print("Installation aborted.\n");
diff --git a/recovery_ui/ethernet_device.cpp b/recovery_ui/ethernet_device.cpp
index d79f41d..0318db8 100644
--- a/recovery_ui/ethernet_device.cpp
+++ b/recovery_ui/ethernet_device.cpp
@@ -30,10 +30,12 @@
 #include "recovery_ui/ethernet_device.h"
 #include "recovery_ui/ethernet_ui.h"
 
-const std::string EthernetDevice::interface = "eth0";
+// Android TV defaults to eth0 for it's interface
+EthernetDevice::EthernetDevice(EthernetRecoveryUI* ui) : EthernetDevice(ui, "eth0") {}
 
-EthernetDevice::EthernetDevice(EthernetRecoveryUI* ui)
-    : Device(ui), ctl_sock_(socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) {
+// Allow future users to define the interface as they prefer
+EthernetDevice::EthernetDevice(EthernetRecoveryUI* ui, std::string interface)
+    : Device(ui), ctl_sock_(socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)), interface_(interface) {
   if (ctl_sock_ < 0) {
     PLOG(ERROR) << "Failed to open socket";
   }
@@ -63,7 +65,7 @@
   }
 
   memset(&ifr, 0, sizeof(struct ifreq));
-  strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ);
+  strncpy(ifr.ifr_name, interface_.c_str(), IFNAMSIZ);
   ifr.ifr_name[IFNAMSIZ - 1] = 0;
 
   if (ioctl(ctl_sock_, SIOCGIFFLAGS, &ifr) < 0) {
@@ -96,7 +98,7 @@
 
   std::unique_ptr<struct ifaddrs, decltype(&freeifaddrs)> guard{ ifaddr, freeifaddrs };
   for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
-    if (ifa->ifa_addr->sa_family != AF_INET6 || interface != ifa->ifa_name) {
+    if (ifa->ifa_addr->sa_family != AF_INET6 || interface_ != ifa->ifa_name) {
       continue;
     }
 
diff --git a/recovery_ui/include/recovery_ui/ethernet_device.h b/recovery_ui/include/recovery_ui/ethernet_device.h
index ea710ab..3aadea2 100644
--- a/recovery_ui/include/recovery_ui/ethernet_device.h
+++ b/recovery_ui/include/recovery_ui/ethernet_device.h
@@ -27,6 +27,7 @@
 class EthernetDevice : public Device {
  public:
   explicit EthernetDevice(EthernetRecoveryUI* ui);
+  explicit EthernetDevice(EthernetRecoveryUI* ui, std::string interface);
 
   void PreRecovery() override;
   void PreFastboot() override;
@@ -36,7 +37,7 @@
   void SetTitleIPv6LinkLocalAddress(const bool interface_up);
 
   android::base::unique_fd ctl_sock_;
-  static const std::string interface;
+  std::string interface_;
 };
 
 #endif  // _ETHERNET_RECOVERY_DEVICE_H
diff --git a/tests/Android.bp b/tests/Android.bp
index 7f00adc..9ad3d3b 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -134,6 +134,10 @@
 
     test_suites: ["device-tests"],
 
+    tidy_timeout_srcs: [
+        "unit/commands_test.cpp",
+    ],
+
     srcs: [
         "unit/*.cpp",
     ],
@@ -192,6 +196,10 @@
         "libupdater_defaults",
     ],
 
+    tidy_timeout_srcs: [
+        "unit/host/imgdiff_test.cpp",
+    ],
+
     srcs: [
         "unit/host/*",
     ],
diff --git a/tests/unit/host/update_simulator_test.cpp b/tests/unit/host/update_simulator_test.cpp
index fb12178..1603982 100644
--- a/tests/unit/host/update_simulator_test.cpp
+++ b/tests/unit/host/update_simulator_test.cpp
@@ -101,7 +101,7 @@
   // TODO(xunchang) check the recovery&system has the expected contents.
 }
 
-class UpdateSimulatorTest : public ::testing::Test {
+class DISABLED_UpdateSimulatorTest : public ::testing::Test {
  protected:
   void SetUp() override {
     std::vector<string> props = {
@@ -147,7 +147,7 @@
   string sparse_system_string_;
 };
 
-TEST_F(UpdateSimulatorTest, TargetFile_ExtractImage) {
+TEST_F(DISABLED_UpdateSimulatorTest, TargetFile_ExtractImage) {
   TemporaryFile zip_file;
   AddZipEntries(zip_file.release(), { { "META/misc_info.txt", "extfs_sparse_flag=-s" },
                                       { "IMAGES/system.img", sparse_system_string_ } });
@@ -166,7 +166,7 @@
   ASSERT_EQ(expected_content, content);
 }
 
-TEST_F(UpdateSimulatorTest, TargetFile_ParseFstabInfo) {
+TEST_F(DISABLED_UpdateSimulatorTest, TargetFile_ParseFstabInfo) {
   TemporaryFile zip_file;
   AddZipEntries(zip_file.release(),
                 { { "META/misc_info.txt", "" },
@@ -195,7 +195,7 @@
   EXPECT_EQ(expected, transformed);
 }
 
-TEST_F(UpdateSimulatorTest, BuildInfo_ParseTargetFile) {
+TEST_F(DISABLED_UpdateSimulatorTest, BuildInfo_ParseTargetFile) {
   std::map<string, string> entries = {
     { "META/misc_info.txt", "" },
     { "SYSTEM/build.prop", build_prop_string_ },
@@ -240,7 +240,7 @@
   }
 }
 
-TEST_F(UpdateSimulatorTest, RunUpdateSmoke) {
+TEST_F(DISABLED_UpdateSimulatorTest, RunUpdateSmoke) {
   string recovery_img_string = "recovery.img";
   string boot_img_string = "boot.img";
 
@@ -326,7 +326,7 @@
   RunSimulation(src_tf.path, ota_package.path, true);
 }
 
-TEST_F(UpdateSimulatorTest, RunUpdateUnrecognizedFunction) {
+TEST_F(DISABLED_UpdateSimulatorTest, RunUpdateUnrecognizedFunction) {
   std::map<string, string> src_entries{
     { "META/misc_info.txt", "extfs_sparse_flag=-s" },
     { "IMAGES/system.img", sparse_system_string_ },
@@ -350,7 +350,7 @@
   RunSimulation(src_tf.path, ota_package.path, false);
 }
 
-TEST_F(UpdateSimulatorTest, RunUpdateApplyPatchFailed) {
+TEST_F(DISABLED_UpdateSimulatorTest, RunUpdateApplyPatchFailed) {
   string recovery_img_string = "recovery.img";
   string boot_img_string = "boot.img";
 
diff --git a/tools/recovery_l10n/res/values-as/strings.xml b/tools/recovery_l10n/res/values-as/strings.xml
index 33a204d..d956b9a 100644
--- a/tools/recovery_l10n/res/values-as/strings.xml
+++ b/tools/recovery_l10n/res/values-as/strings.xml
@@ -6,9 +6,9 @@
     <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_wipe_data_menu_header" msgid="550255032058254478">"Android ছিষ্টেম ল\'ড কৰিব নোৱাৰি। আপোনাৰ ডেটাত কিবা আসোঁৱাহ থকা যেন লাগিছে। আপুনি যদি এই বাৰ্তাটো পায়েই থাকে, আপুনি নিজৰ ডিভাইচটো ফেক্টৰী ডেটা ৰিছেট কৰি সেইটোত থকা ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব লগা হ\'ব পাৰে।"</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>
-    <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিবনে?\n\n এইটো কৰাৰ পিছত আনডু কৰিব নোৱাৰি!"</string>
+    <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"ব্যৱহাৰকাৰীৰ আটাইবোৰ ডেটা মচিবনে?\n\n এইটো কৰাৰ পাছত আনডু কৰিব নোৱাৰি!"</string>
     <string name="recovery_cancel_wipe_data" msgid="66987687653647384">"বাতিল কৰক"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-kn/strings.xml b/tools/recovery_l10n/res/values-kn/strings.xml
index a98f469..eafd831 100644
--- a/tools/recovery_l10n/res/values-kn/strings.xml
+++ b/tools/recovery_l10n/res/values-kn/strings.xml
@@ -8,7 +8,7 @@
     <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>
+    <string name="recovery_factory_data_reset" msgid="7321351565602894783">"ಫ್ಯಾಕ್ಟರಿ ಡೇಟಾ ರೀಸೆಟ್"</string>
     <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"ಎಲ್ಲಾ ಬಳಕೆದಾರರ ಡೇಟಾವನ್ನು ಅಳಿಸುವುದೇ?\n\n ಇದನ್ನು ರದ್ದುಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ!"</string>
     <string name="recovery_cancel_wipe_data" msgid="66987687653647384">"ರದ್ದುಮಾಡಿ"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-sv/strings.xml b/tools/recovery_l10n/res/values-sv/strings.xml
index cf43b25..baf8e18 100644
--- a/tools/recovery_l10n/res/values-sv/strings.xml
+++ b/tools/recovery_l10n/res/values-sv/strings.xml
@@ -2,7 +2,7 @@
 <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">"Systemuppdatering installeras"</string>
-    <string name="recovery_erasing" msgid="7334826894904037088">"Rensar"</string>
+    <string name="recovery_erasing" msgid="7334826894904037088">"Raderar"</string>
     <string name="recovery_no_command" msgid="4465476568623024327">"Inget kommando"</string>
     <string name="recovery_error" msgid="5748178989622716736">"Fel!"</string>
     <string name="recovery_installing_security" msgid="9184031299717114342">"Säkerhetsuppdatering installeras"</string>
diff --git a/tools/recovery_l10n/res/values-te/strings.xml b/tools/recovery_l10n/res/values-te/strings.xml
index 4d52114..ecea432 100644
--- a/tools/recovery_l10n/res/values-te/strings.xml
+++ b/tools/recovery_l10n/res/values-te/strings.xml
@@ -1,12 +1,12 @@
 <?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_wipe_data_menu_header" msgid="550255032058254478">"Android సిస్టమ్‌ని లోడ్ చేయడం సాధ్యం కాదు. మీ డేటా పాడై ఉండవచ్చు. మీకు ఈ సందేశం వస్తూనే ఉంటే, మీరు ఫ్యాక్టరీ డేటా రీసెట్ చేసి, పరికరంలో నిల్వ అయిన వినియోగదారు డేటా మొత్తాన్ని తొలగించాల్సి రావచ్చు."</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>
     <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"వినియోగదారు డేటా మొత్తాన్ని తొలగించాలా?\n\n ఈ చర్యను రద్దు చేయలేరు!"</string>