[automerger skipped] Import translations. DO NOT MERGE ANYWHERE am: 6c8fb3fe72 -s ours am: e3ded1bab0 -s ours am: 7d0563803a -s ours am: f84ea231e3 -s ours

am skip reason: subject contains skip directive

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

Change-Id: Id382cdb113fb92d5b573ca1a038e3517ba78e175
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/METADATA b/METADATA
index 68bf6f8..d97975c 100644
--- a/METADATA
+++ b/METADATA
@@ -1,9 +1,3 @@
-# *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS.  PLEASE
-#     CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
-#     DEPENDING ON IT IN YOUR PROJECT. ***
 third_party {
-  license_note: "would be NOTICE save for OFL in:\n"
-  "   fonts/README\n"
-  "   fonts/OFL.txt\n"
-  license_type: BY_EXCEPTION_ONLY
+  license_type: NOTICE
 }
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index 376c511..33ed330 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -30,8 +30,8 @@
  *
  * To work well with this tool, the gzipped sections of the target image must have been generated
  * using the same deflate encoder that is available in applypatch, namely, the one in the zlib
- * library.  In practice this means that images should be compressed using the "minigzip" tool
- * included in the zlib distribution, not the GNU gzip program.
+ * library.  In practice this means that images should be compressed using the toybox "gzip" toy,
+ * not the GNU gzip program.
  *
  * An "imgdiff" patch consists of a header describing the chunk structure of the file and any
  * encoding parameters needed for the gzipped chunks, followed by N bsdiff patches, one per chunk.
diff --git a/applypatch/vendor_flash_recovery.rc b/applypatch/vendor_flash_recovery.rc
index 37a7c2b..a6003be 100644
--- a/applypatch/vendor_flash_recovery.rc
+++ b/applypatch/vendor_flash_recovery.rc
@@ -1,3 +1,4 @@
 service vendor_flash_recovery /vendor/bin/install-recovery.sh
     class main
     oneshot
+    user root
diff --git a/etc/init.rc b/etc/init.rc
index c7ff2b2..bdf9ec0 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -76,24 +76,29 @@
 service ueventd /system/bin/ueventd
     critical
     seclabel u:r:ueventd:s0
+    user root
 
 service charger /system/bin/charger
     critical
     seclabel u:r:charger:s0
+    user root
 
 service recovery /system/bin/recovery
     socket recovery stream 422 system system
     seclabel u:r:recovery:s0
+    user root
 
 service adbd /system/bin/adbd --root_seclabel=u:r:su:s0 --device_banner=recovery
     disabled
     socket adbd stream 660 system system
     seclabel u:r:adbd:s0
+    user root
 
 service fastbootd /system/bin/fastbootd
     disabled
     group system
     seclabel u:r:fastbootd:s0
+    user root
 
 # Restart adbd so it can run as root
 on property:service.adb.root=1
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index a093008..7806248 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -36,10 +36,8 @@
   { "Power off", Device::SHUTDOWN_FROM_FASTBOOT },
 };
 
-Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& /* args */) {
-  RecoveryUI* ui = device->GetUI();
-
-  std::vector<std::string> title_lines = { "Android Fastboot" };
+void FillDefaultFastbootLines(std::vector<std::string>& title_lines) {
+  title_lines.push_back("Android Fastboot");
   title_lines.push_back("Product name - " + android::base::GetProperty("ro.product.device", ""));
   title_lines.push_back("Bootloader version - " + android::base::GetProperty("ro.bootloader", ""));
   title_lines.push_back("Baseband version - " +
@@ -48,6 +46,32 @@
   title_lines.push_back(std::string("Secure boot - ") +
                         ((android::base::GetProperty("ro.secure", "") == "1") ? "yes" : "no"));
   title_lines.push_back("HW version - " + android::base::GetProperty("ro.revision", ""));
+}
+
+void FillWearableFastbootLines(std::vector<std::string>& title_lines) {
+  title_lines.push_back("Android Fastboot");
+  title_lines.push_back(android::base::GetProperty("ro.product.device", "") + " - " +
+                        android::base::GetProperty("ro.revision", ""));
+  title_lines.push_back(android::base::GetProperty("ro.bootloader", ""));
+
+  const size_t max_baseband_len = 24;
+  const std::string& baseband = android::base::GetProperty("ro.build.expect.baseband", "");
+  title_lines.push_back(baseband.length() > max_baseband_len
+                            ? baseband.substr(0, max_baseband_len - 3) + "..."
+                            : baseband);
+
+  title_lines.push_back("Serial #: " + android::base::GetProperty("ro.serialno", ""));
+}
+
+Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& /* args */) {
+  RecoveryUI* ui = device->GetUI();
+  std::vector<std::string> title_lines;
+
+  if (ui->IsWearable()) {
+    FillWearableFastbootLines(title_lines);
+  } else {
+    FillDefaultFastbootLines(title_lines);
+  }
 
   ui->ResetKeyInterruptStatus();
   ui->SetTitle(title_lines);
diff --git a/recovery-persist.cpp b/recovery-persist.cpp
index 55699b2..b5bb801 100644
--- a/recovery-persist.cpp
+++ b/recovery-persist.cpp
@@ -35,10 +35,12 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <array>
 #include <string>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <private/android_logger.h> /* private pmsg functions */
 
 #include "recovery_utils/logging.h"
@@ -114,6 +116,59 @@
     return android::base::WriteStringToFile(buffer, destination.c_str());
 }
 
+size_t file_size(const char* path) {
+    struct stat st {};
+    if (stat(path, &st) < 0) {
+        return 0;
+    }
+
+    return st.st_size;
+}
+
+bool compare_file(const char* file1, const char* file2) {
+    if (!file_exists(file1) || !file_exists(file2)) {
+        return false;
+    }
+    if (file_size(file1) != file_size(file2)) {
+        return false;
+    }
+    std::array<uint8_t, 1024 * 16> buf1{};
+    std::array<uint8_t, 1024 * 16> buf2{};
+    android::base::unique_fd fd1(open(file1, O_RDONLY));
+    android::base::unique_fd fd2(open(file2, O_RDONLY));
+    auto bytes_remain = file_size(file1);
+    while (bytes_remain > 0) {
+        const auto bytes_to_read = std::min<size_t>(bytes_remain, buf1.size());
+
+        if (!android::base::ReadFully(fd1, buf1.data(), bytes_to_read)) {
+            LOG(ERROR) << "Failed to read from " << file1;
+            return false;
+        }
+        if (!android::base::ReadFully(fd2, buf2.data(), bytes_to_read)) {
+            LOG(ERROR) << "Failed to read from " << file2;
+            return false;
+        }
+        if (memcmp(buf1.data(), buf2.data(), bytes_to_read) != 0) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void rotate_last_kmsg() {
+    if (rotated) {
+        return;
+    }
+    if (!file_exists(LAST_CONSOLE_FILE) && !file_exists(ALT_LAST_CONSOLE_FILE)) {
+        return;
+    }
+    if (!compare_file(LAST_KMSG_FILE, LAST_CONSOLE_FILE) &&
+        !compare_file(LAST_KMSG_FILE, ALT_LAST_CONSOLE_FILE)) {
+        rotate_logs(LAST_LOG_FILE, LAST_KMSG_FILE);
+        rotated = true;
+    }
+}
+
 int main(int argc, char **argv) {
 
     /* Is /cache a mount?, we have been delivered where we are not wanted */
@@ -131,7 +186,7 @@
     } else {
         char *line = NULL;
         size_t len = 0;
-        ssize_t read;
+        ssize_t read{};
         while ((read = getline(&line, &len, fp)) != -1) {
             if (strstr(line, " /cache ")) {
                 has_cache = true;
@@ -172,6 +227,7 @@
         PLOG(ERROR) << "Failed to unlink " << LAST_INSTALL_FILE;
       }
     }
+    rotate_last_kmsg();
 
     /* Is there a last console log too? */
     if (rotated) {
diff --git a/recovery_ui/include/recovery_ui/screen_ui.h b/recovery_ui/include/recovery_ui/screen_ui.h
index 99ad534..2e0fcc2 100644
--- a/recovery_ui/include/recovery_ui/screen_ui.h
+++ b/recovery_ui/include/recovery_ui/screen_ui.h
@@ -309,7 +309,7 @@
   void PutChar(char);
   void ClearText();
 
-  void LoadAnimation();
+  virtual void LoadAnimation();
   std::unique_ptr<GRSurface> LoadBitmap(const std::string& filename);
   std::unique_ptr<GRSurface> LoadLocalizedBitmap(const std::string& filename);
 
@@ -416,6 +416,7 @@
   // Display the background texts for "erasing", "error", "no_command" and "installing" for the
   // selected locale.
   void SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries, size_t sel);
+
 };
 
 #endif  // RECOVERY_UI_H
diff --git a/recovery_ui/include/recovery_ui/ui.h b/recovery_ui/include/recovery_ui/ui.h
index c3e3ee2..c3bb03f 100644
--- a/recovery_ui/include/recovery_ui/ui.h
+++ b/recovery_ui/include/recovery_ui/ui.h
@@ -177,6 +177,10 @@
       const std::vector<std::string>& backup_headers, const std::vector<std::string>& backup_items,
       const std::function<int(int, bool)>& key_handler) = 0;
 
+  virtual bool IsWearable() {
+    return false;
+  }
+
   // Set whether or not the fastbootd logo is displayed.
   void SetEnableFastbootdLogo(bool enable) {
     fastbootd_logo_enabled_ = enable;
diff --git a/recovery_ui/include/recovery_ui/wear_ui.h b/recovery_ui/include/recovery_ui/wear_ui.h
index 429af69..e27e940 100644
--- a/recovery_ui/include/recovery_ui/wear_ui.h
+++ b/recovery_ui/include/recovery_ui/wear_ui.h
@@ -29,6 +29,10 @@
   void SetStage(int current, int max) override;
 
  protected:
+  // curved progress bar frames for round screens
+  std::vector<std::unique_ptr<GRSurface>> progress_frames_;
+  std::vector<std::unique_ptr<GRSurface>> rtl_progress_frames_;
+
   // progress bar vertical position, it's centered horizontally
   const int progress_bar_baseline_;
 
@@ -36,17 +40,30 @@
   // Recovery, build id and etc) and the bottom lines that may otherwise go out of the screen.
   const int menu_unusable_rows_;
 
+  const bool is_screen_circle_;
+
   std::unique_ptr<Menu> CreateMenu(const std::vector<std::string>& text_headers,
                                    const std::vector<std::string>& text_items,
                                    size_t initial_selection) const override;
 
   int GetProgressBaseline() const override;
 
+  int GetTextBaseline() const override;
+
   void update_progress_locked() override;
 
+  void LoadAnimation() override;
+
+  bool IsWearable() override;
+
+  void SetProgress(float fraction) override;
+
  private:
   void draw_background_locked() override;
   void draw_screen_locked() override;
+  void draw_circle_foreground_locked();
+  size_t GetProgressFrameIndex(float fraction) const;
+
 };
 
 #endif  // RECOVERY_WEAR_UI_H
diff --git a/recovery_ui/ui.cpp b/recovery_ui/ui.cpp
index eb87f52..8bc0244 100644
--- a/recovery_ui/ui.cpp
+++ b/recovery_ui/ui.cpp
@@ -43,24 +43,30 @@
 using namespace std::chrono_literals;
 
 constexpr int UI_WAIT_KEY_TIMEOUT_SEC = 120;
-constexpr const char* BRIGHTNESS_FILE = "/sys/class/leds/lcd-backlight/brightness";
-constexpr const char* MAX_BRIGHTNESS_FILE = "/sys/class/leds/lcd-backlight/max_brightness";
+constexpr const char* DEFAULT_BRIGHTNESS_FILE = "/sys/class/leds/lcd-backlight/brightness";
+constexpr const char* DEFAULT_MAX_BRIGHTNESS_FILE = "/sys/class/leds/lcd-backlight/max_brightness";
 constexpr const char* BRIGHTNESS_FILE_SDM = "/sys/class/backlight/panel0-backlight/brightness";
 constexpr const char* MAX_BRIGHTNESS_FILE_SDM =
     "/sys/class/backlight/panel0-backlight/max_brightness";
-constexpr const char* BRIGHTNESS_FILE_PWM =
-    "/sys/class/backlight/pwm-backlight.0/brightness";
+constexpr const char* BRIGHTNESS_FILE_PWM = "/sys/class/backlight/pwm-backlight.0/brightness";
 constexpr const char* MAX_BRIGHTNESS_FILE_PWM =
     "/sys/class/backlight/pwm-backlight.0/max_brightness";
 
 constexpr int kDefaultTouchLowThreshold = 50;
 constexpr int kDefaultTouchHighThreshold = 90;
 
+constexpr int kDefaultNormalBrightnessPercent = 50;
+constexpr int kDefaultDimmedBrightnessPercent = 25;
+
 RecoveryUI::RecoveryUI()
-    : brightness_normal_(50),
-      brightness_dimmed_(25),
-      brightness_file_(BRIGHTNESS_FILE),
-      max_brightness_file_(MAX_BRIGHTNESS_FILE),
+    : brightness_normal_(android::base::GetIntProperty("ro.recovery.ui.brightness_normal_percent",
+                                                       kDefaultNormalBrightnessPercent)),
+      brightness_dimmed_(android::base::GetIntProperty("ro.recovery.ui.brightness_dimmed_percent",
+                                                       kDefaultDimmedBrightnessPercent)),
+      brightness_file_(
+          android::base::GetProperty("ro.recovery.ui.brightness_file", DEFAULT_BRIGHTNESS_FILE)),
+      max_brightness_file_(android::base::GetProperty("ro.recovery.ui.max_brightness_file",
+                                                      DEFAULT_MAX_BRIGHTNESS_FILE)),
       touch_screen_allowed_(false),
       fastbootd_logo_enabled_(false),
       touch_low_threshold_(android::base::GetIntProperty("ro.recovery.ui.touch_low_threshold",
diff --git a/recovery_ui/wear_ui.cpp b/recovery_ui/wear_ui.cpp
index 8d8108f..309891c 100644
--- a/recovery_ui/wear_ui.cpp
+++ b/recovery_ui/wear_ui.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "otautil/paths.h"
 #include "recovery_ui/wear_ui.h"
 
 #include <string.h>
@@ -23,24 +24,25 @@
 
 #include <android-base/properties.h>
 #include <android-base/strings.h>
+
 #include <minui/minui.h>
 
 constexpr int kDefaultProgressBarBaseline = 259;
 constexpr int kDefaultMenuUnusableRows = 9;
+constexpr int kProgressBarVerticalOffsetDp = 72;
+constexpr bool kDefaultIsScreenCircle = true;
 
 WearRecoveryUI::WearRecoveryUI()
     : ScreenRecoveryUI(true),
       progress_bar_baseline_(android::base::GetIntProperty("ro.recovery.ui.progress_bar_baseline",
                                                            kDefaultProgressBarBaseline)),
       menu_unusable_rows_(android::base::GetIntProperty("ro.recovery.ui.menu_unusable_rows",
-                                                        kDefaultMenuUnusableRows)) {
+                                                        kDefaultMenuUnusableRows)),
+      is_screen_circle_(android::base::GetBoolProperty("ro.recovery.ui.is_screen_circle",
+                                                             kDefaultIsScreenCircle)) {
   // TODO: menu_unusable_rows_ should be computed based on the lines in draw_screen_locked().
-
   touch_screen_allowed_ = true;
-}
-
-int WearRecoveryUI::GetProgressBaseline() const {
-  return progress_bar_baseline_;
+  SetEnableFastbootdLogo(false); // logo not required on Wear
 }
 
 // Draw background frame on the screen.  Does not flip pages.
@@ -51,40 +53,152 @@
   gr_color(0, 0, 0, 255);
   gr_fill(0, 0, gr_fb_width(), gr_fb_height());
 
-  if (current_icon_ != NONE) {
+  if (current_icon_ == ERROR) {
     const auto& frame = GetCurrentFrame();
     int frame_width = gr_get_width(frame);
     int frame_height = gr_get_height(frame);
     int frame_x = (gr_fb_width() - frame_width) / 2;
     int frame_y = (gr_fb_height() - frame_height) / 2;
     gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
+  }
 
-    // Draw recovery text on screen above progress bar.
+  if (current_icon_ != NONE) {
+    // Draw recovery text on screen centered
     const auto& text = GetCurrentText();
     int text_x = (ScreenWidth() - gr_get_width(text)) / 2;
-    int text_y = GetProgressBaseline() - gr_get_height(text) - 10;
+    int text_y = (ScreenHeight() - gr_get_height(text)) / 2;
     gr_color(255, 255, 255, 255);
     gr_texticon(text_x, text_y, text);
   }
 }
 
 void WearRecoveryUI::draw_screen_locked() {
-  draw_background_locked();
   if (!show_text) {
-    draw_foreground_locked();
-  } else {
-    SetColor(UIElement::TEXT_FILL);
-    gr_fill(0, 0, gr_fb_width(), gr_fb_height());
-
-    // clang-format off
-    static std::vector<std::string> SWIPE_HELP = {
-      "Swipe up/down to move.",
-      "Swipe left/right to select.",
-      "",
-    };
-    // clang-format on
-    draw_menu_and_text_buffer_locked(SWIPE_HELP);
+    draw_background_locked();
+    if (is_screen_circle_) {
+        draw_circle_foreground_locked();
+    } else {
+        draw_foreground_locked();
+    }
+    return;
   }
+
+  SetColor(UIElement::TEXT_FILL);
+  gr_clear();
+
+  // clang-format off
+  static std::vector<std::string> SWIPE_HELP = {
+    "Swipe up/down to move.",
+    "Swipe left/right to select.",
+    "",
+  };
+  // clang-format on
+  draw_menu_and_text_buffer_locked(SWIPE_HELP);
+}
+
+void WearRecoveryUI::draw_circle_foreground_locked() {
+    if (current_icon_ != NONE) {
+        const auto& frame = GetCurrentFrame();
+        int frame_width = gr_get_width(frame);
+        int frame_height = gr_get_height(frame);
+        int frame_x = (ScreenWidth() - frame_width) / 2;
+        int frame_y = GetAnimationBaseline();
+        DrawSurface(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
+      }
+
+    if (progressBarType == DETERMINATE) {
+        const auto& first_progress_frame = rtl_locale_ ? rtl_progress_frames_[0].get()
+                                                        :progress_frames_[0].get();
+        int width = gr_get_width(first_progress_frame);
+        int height = gr_get_height(first_progress_frame);
+
+        int progress_x = (ScreenWidth() - width) / 2;
+        int progress_y = GetProgressBaseline();
+
+        const auto index = GetProgressFrameIndex(progress);
+        const auto& frame = rtl_locale_ ? rtl_progress_frames_[index].get()
+                                        : progress_frames_[index].get();
+
+        DrawSurface(frame, 0, 0, width, height, progress_x, progress_y);
+    }
+}
+
+void WearRecoveryUI::LoadAnimation() {
+  ScreenRecoveryUI::LoadAnimation();
+  std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(Paths::Get().resource_dir().c_str()),
+                                                closedir);
+  dirent* de;
+  std::vector<std::string> progress_frame_names;
+  std::vector<std::string> rtl_progress_frame_names;
+
+  if(dir.get() == nullptr) abort();
+
+  while ((de = readdir(dir.get())) != nullptr) {
+    int value, num_chars;
+    if (sscanf(de->d_name, "progress%d%n.png", &value, &num_chars) == 1) {
+      progress_frame_names.emplace_back(de->d_name, num_chars);
+    } else if (sscanf(de->d_name, "rtl_progress%d%n.png", &value, &num_chars) == 1) {
+      rtl_progress_frame_names.emplace_back(de->d_name, num_chars);
+    }
+  }
+
+  size_t progress_frames = progress_frame_names.size();
+  size_t rtl_progress_frames = rtl_progress_frame_names.size();
+
+  // You must have an animation.
+  if (progress_frames == 0 || rtl_progress_frames == 0) abort();
+
+  std::sort(progress_frame_names.begin(), progress_frame_names.end());
+  std::sort(rtl_progress_frame_names.begin(), rtl_progress_frame_names.end());
+
+  progress_frames_.clear();
+  progress_frames_.reserve(progress_frames);
+  for (const auto& frame_name : progress_frame_names) {
+    progress_frames_.emplace_back(LoadBitmap(frame_name));
+  }
+
+  rtl_progress_frames_.clear();
+    rtl_progress_frames_.reserve(rtl_progress_frames);
+    for (const auto& frame_name : rtl_progress_frame_names) {
+      rtl_progress_frames_.emplace_back(LoadBitmap(frame_name));
+  }
+}
+
+void WearRecoveryUI::SetProgress(float fraction) {
+    if (is_screen_circle_) {
+       std::lock_guard<std::mutex> lg(updateMutex);
+       if (fraction < 0.0) fraction = 0.0;
+       if (fraction > 1.0) fraction = 1.0;
+       if (progressBarType == DETERMINATE && fraction > progress) {
+          // Skip updates that aren't visibly different.
+          if (GetProgressFrameIndex(fraction) != GetProgressFrameIndex(progress)) {
+              // circular display
+              progress = fraction;
+              update_progress_locked();
+          }
+       }
+    } else {
+        // rectangular display
+        ScreenRecoveryUI::SetProgress(fraction);
+    }
+}
+
+int WearRecoveryUI::GetProgressBaseline() const {
+  int progress_height = gr_get_height(progress_frames_[0].get());
+  return (ScreenHeight() - progress_height) / 2 + PixelsFromDp(kProgressBarVerticalOffsetDp);
+}
+
+int WearRecoveryUI::GetTextBaseline() const {
+  if (is_screen_circle_) {
+        return GetProgressBaseline() - PixelsFromDp(kProgressBarVerticalOffsetDp) -
+                                    gr_get_height(installing_text_.get());
+  } else {
+       return ScreenRecoveryUI::GetTextBaseline();
+  }
+}
+
+size_t WearRecoveryUI::GetProgressFrameIndex(float fraction) const {
+  return static_cast<size_t>(fraction * (progress_frames_.size() - 1));
 }
 
 // TODO merge drawing routines with screen_ui
@@ -93,6 +207,10 @@
   gr_flip();
 }
 
+bool WearRecoveryUI::IsWearable() {
+  return true;
+}
+
 void WearRecoveryUI::SetStage(int /* current */, int /* max */) {}
 
 std::unique_ptr<Menu> WearRecoveryUI::CreateMenu(const std::vector<std::string>& text_headers,
diff --git a/tests/Android.bp b/tests/Android.bp
index b888d47..cdfc091 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -107,15 +107,12 @@
 // ========================================================
 genrule {
     name: "recovery_image",
-    cmd: "cat $(location testdata/recovery_head) <(cat $(location testdata/recovery_body) | $(location minigzip)) $(location testdata/recovery_tail) > $(out)",
+    cmd: "cat $(location testdata/recovery_head) <(cat $(location testdata/recovery_body) | gzip) $(location testdata/recovery_tail) > $(out)",
     srcs: [
         "testdata/recovery_head",
         "testdata/recovery_body",
         "testdata/recovery_tail",
     ],
-    tools: [
-        "minigzip",
-    ],
     out: [
         "testdata/recovery.img",
     ],
diff --git a/tools/image_generator/draw-progress.sh b/tools/image_generator/draw-progress.sh
new file mode 100644
index 0000000..7462c4e
--- /dev/null
+++ b/tools/image_generator/draw-progress.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# arc central angle in degrees
+arc_size="64.5"
+
+arc_start=$(bc -l <<< "90 - $arc_size / 2")
+arc_end=$(bc -l <<< "90 + $arc_size / 2")
+
+N=100
+for ((i=0; i < $N; i++)); do
+	progress=$(bc -l <<< "$i / ($N - 1)")
+	fg_arc_start=$(bc -l <<< "$arc_end - $progress * $arc_size")
+
+	filename="progress$(printf "%02d" $i).png"
+	echo "-- Writing file: $filename"
+
+	convert -size 400x400 xc:black \
+		-draw "stroke-linecap round stroke-width 8 \
+				stroke gray ellipse 200,200 100,100 $arc_start,$arc_end \
+				stroke white ellipse 200,200 100,100 $fg_arc_start,$arc_end" "$filename"
+
+  echo "-- Writing file: rtl_$filename"
+  convert -size 400x400 xc:black \
+  		-draw "stroke-linecap round stroke-width 8 \
+  				stroke gray ellipse 200,200 100,100 $arc_start,$arc_end \
+  				stroke white ellipse 200,200 100,100 $fg_arc_start,$arc_end" "rtl_$filename"
+
+		mogrify -crop 120x30+140+280 "$filename"
+		mogrify -crop 120x30+140+280 "rtl_$filename"
+
+		# Use color format recovery can use
+		mogrify -define png:format=png24 -type TrueColor "$filename"
+    mogrify -define png:format=png24 -type TrueColor "rtl_$filename"
+
+		mogrify -flop "rtl_$filename"
+done
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/tools/recovery_l10n/res/values-pt-rPT/strings.xml b/tools/recovery_l10n/res/values-pt-rPT/strings.xml
index 8fd1d9b..08eb3c9 100644
--- a/tools/recovery_l10n/res/values-pt-rPT/strings.xml
+++ b/tools/recovery_l10n/res/values-pt-rPT/strings.xml
@@ -9,6 +9,6 @@
     <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Não é possível carregar o sistema Android. Os seus dados podem estar danificados. Se continuar a receber esta mensagem, pode ter de efetuar uma reposição de dados de fábrica e apagar todos os dados do utilizador armazenados neste dispositivo."</string>
     <string name="recovery_try_again" msgid="7168248750158873496">"Tentar novamente"</string>
     <string name="recovery_factory_data_reset" msgid="7321351565602894783">"Reposição de dados de fábrica"</string>
-    <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Quer limpar todos os dados do utilizador?\n\n NÃO É POSSÍVEL ANULAR ESTA AÇÃO."</string>
+    <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Pretende limpar todos os dados do utilizador?\n\n NÃO É POSSÍVEL ANULAR ESTA AÇÃO."</string>
     <string name="recovery_cancel_wipe_data" msgid="66987687653647384">"Cancelar"</string>
 </resources>
diff --git a/tools/recovery_l10n/res/values-zh-rHK/strings.xml b/tools/recovery_l10n/res/values-zh-rHK/strings.xml
index 0f5b7d9..55ce31e 100644
--- a/tools/recovery_l10n/res/values-zh-rHK/strings.xml
+++ b/tools/recovery_l10n/res/values-zh-rHK/strings.xml
@@ -6,7 +6,7 @@
     <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>
diff --git a/uncrypt/uncrypt.rc b/uncrypt/uncrypt.rc
index 52f564e..7b1ec37 100644
--- a/uncrypt/uncrypt.rc
+++ b/uncrypt/uncrypt.rc
@@ -3,15 +3,18 @@
     socket uncrypt stream 600 system system
     disabled
     oneshot
+    user root
 
 service setup-bcb /system/bin/uncrypt --setup-bcb
     class main
     socket uncrypt stream 600 system system
     disabled
     oneshot
+    user root
 
 service clear-bcb /system/bin/uncrypt --clear-bcb
     class main
     socket uncrypt stream 600 system system
     disabled
     oneshot
+    user root
diff --git a/update_verifier/update_verifier.rc b/update_verifier/update_verifier.rc
index 862b062..76376c8 100644
--- a/update_verifier/update_verifier.rc
+++ b/update_verifier/update_verifier.rc
@@ -1,10 +1,4 @@
-service update_verifier_nonencrypted /system/bin/update_verifier nonencrypted
-    user root
-    group cache system
-    priority -20
-    ioprio rt 0
-
-service update_verifier /system/bin/update_verifier ${vold.decrypt}
+service update_verifier /system/bin/update_verifier
     user root
     group cache system
     priority -20