Merge changes I55d0e1a8,I4d9a8776

* changes:
  adb-remount-test: do not brick devices that support overlayfs but do not use it
  adb-remount-test: provide additional mount details
diff --git a/adb/daemon/include/adbd/usb.h b/adb/daemon/include/adbd/usb.h
index 3213f69..fca3c58 100644
--- a/adb/daemon/include/adbd/usb.h
+++ b/adb/daemon/include/adbd/usb.h
@@ -43,7 +43,7 @@
     bool open_new_connection = true;
 
     int (*write)(usb_handle* h, const void* data, int len);
-    int (*read)(usb_handle* h, void* data, int len);
+    int (*read)(usb_handle* h, void* data, int len, bool allow_partial);
     void (*kick)(usb_handle* h);
     void (*close)(usb_handle* h);
 
diff --git a/adb/daemon/usb_legacy.cpp b/adb/daemon/usb_legacy.cpp
index b65727a..fe80e7d 100644
--- a/adb/daemon/usb_legacy.cpp
+++ b/adb/daemon/usb_legacy.cpp
@@ -142,11 +142,12 @@
     return orig_len;
 }
 
-static int usb_ffs_read(usb_handle* h, void* data, int len) {
+static int usb_ffs_read(usb_handle* h, void* data, int len, bool allow_partial) {
     D("about to read (fd=%d, len=%d)", h->bulk_out.get(), len);
 
     char* buf = static_cast<char*>(data);
     int orig_len = len;
+    unsigned count = 0;
     while (len > 0) {
         int read_len = std::min(USB_FFS_BULK_SIZE, len);
         int n = adb_read(h->bulk_out, buf, read_len);
@@ -156,6 +157,16 @@
         }
         buf += n;
         len -= n;
+        count += n;
+
+        // For fastbootd command such as "getvar all", len parameter is always set 64.
+        // But what we read is actually less than 64.
+        // For example, length 10 for "getvar all" command.
+        // If we get less data than expected, this means there should be no more data.
+        if (allow_partial && n < read_len) {
+            orig_len = count;
+            break;
+        }
     }
 
     D("[ done fd=%d ]", h->bulk_out.get());
@@ -221,7 +232,7 @@
     }
 }
 
-static int usb_ffs_aio_read(usb_handle* h, void* data, int len) {
+static int usb_ffs_aio_read(usb_handle* h, void* data, int len, bool allow_partial) {
     return usb_ffs_do_aio(h, data, len, true);
 }
 
@@ -299,7 +310,7 @@
 }
 
 int usb_read(usb_handle* h, void* data, int len) {
-    return h->read(h, data, len);
+    return h->read(h, data, len, false /* allow_partial */);
 }
 
 int usb_close(usb_handle* h) {
diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h
index d70e50a..2307217 100644
--- a/base/include/android-base/expected.h
+++ b/base/include/android-base/expected.h
@@ -79,6 +79,15 @@
 #define _NODISCARD_
 #endif
 
+namespace {
+template< class T >
+struct remove_cvref {
+  typedef std::remove_cv_t<std::remove_reference_t<T>> type;
+};
+template< class T >
+using remove_cvref_t = typename remove_cvref<T>::type;
+} // namespace
+
 // Class expected
 template<class T, class E>
 class _NODISCARD_ expected {
@@ -93,7 +102,7 @@
   // constructors
   constexpr expected() = default;
   constexpr expected(const expected& rhs) = default;
-  constexpr expected(expected&& rhs) noexcept  = default;
+  constexpr expected(expected&& rhs) noexcept = default;
 
   template<class U, class G _ENABLE_IF(
     std::is_constructible_v<T, const U&> &&
@@ -173,6 +182,9 @@
 
   template<class U = T _ENABLE_IF(
     std::is_constructible_v<T, U&&> &&
+    !std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
+    !std::is_same_v<expected<T, E>, remove_cvref_t<U>> &&
+    !std::is_same_v<unexpected<E>, remove_cvref_t<U>> &&
     std::is_convertible_v<U&&,T> /* non-explicit */
   )>
   constexpr expected(U&& v)
@@ -180,6 +192,9 @@
 
   template<class U = T _ENABLE_IF(
     std::is_constructible_v<T, U&&> &&
+    !std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
+    !std::is_same_v<expected<T, E>, remove_cvref_t<U>> &&
+    !std::is_same_v<unexpected<E>, remove_cvref_t<U>> &&
     !std::is_convertible_v<U&&,T> /* explicit */
   )>
   constexpr explicit expected(U&& v)
@@ -241,38 +256,21 @@
   ~expected() = default;
 
   // assignment
-// TODO(b/132145659) enable assignment operator only when the condition
-// satisfies. SFNAIE doesn't work here because assignment operator should be
-// non-template. We could workaround this by defining a templated parent class
-// having the assignment operator. This incomplete implementation however
-// doesn't allow us to copy assign expected<T,E> even when T is non-copy
-// assignable. The copy assignment will fail by the underlying std::variant
-// anyway though the error message won't be clear.
-//  std::enable_if_t<(
-//    std::is_copy_assignable_v<T> &&
-//    std::is_copy_constructible_v<T> &&
-//    std::is_copy_assignable_v<E> &&
-//    std::is_copy_constructible_v<E> &&
-//    (std::is_nothrow_move_constructible_v<E> ||
-//     std::is_nothrow_move_constructible_v<T>)
-//  ), expected&>
-  expected& operator=(const expected& rhs) {
-    var_ = rhs.var_;
-    return *this;
-  }
-//  std::enable_if_t<(
-//    std::is_move_constructible_v<T> &&
-//    std::is_move_assignable_v<T> &&
-//    std::is_nothrow_move_constructible_v<E> &&
-//    std::is_nothrow_move_assignable_v<E>
-//  ), expected&>
-  expected& operator=(expected&& rhs) noexcept {
-    var_ = std::move(rhs.var_);
-    return *this;
-  }
+  // Note: SFNAIE doesn't work here because assignment operator should be
+  // non-template. We could workaround this by defining a templated parent class
+  // having the assignment operator. This incomplete implementation however
+  // doesn't allow us to copy assign expected<T,E> even when T is non-copy
+  // assignable. The copy assignment will fail by the underlying std::variant
+  // anyway though the error message won't be clear.
+  expected& operator=(const expected& rhs) = default;
+
+  // Note for SFNAIE above applies to here as well
+  expected& operator=(expected&& rhs) = default;
 
   template<class U = T _ENABLE_IF(
     !std::is_void_v<T> &&
+    !std::is_same_v<expected<T,E>, remove_cvref_t<U>> &&
+    !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::decay_t<U>>> &&
     std::is_constructible_v<T,U> &&
     std::is_assignable_v<T&,U> &&
     std::is_nothrow_move_constructible_v<E>
@@ -283,7 +281,6 @@
   }
 
   template<class G = E>
-  // TODO: std::is_nothrow_copy_constructible_v<E> && std::is_copy_assignable_v<E>
   expected& operator=(const unexpected<G>& rhs) {
     var_ = rhs;
     return *this;
@@ -399,7 +396,7 @@
   friend void swap(expected<T1, E1>&, expected<T1, E1>&) noexcept;
 
  private:
-    std::variant<value_type, unexpected_type> var_;
+  std::variant<value_type, unexpected_type> var_;
 };
 
 template<class T1, class E1, class T2, class E2>
@@ -468,7 +465,9 @@
   constexpr unexpected(unexpected&&) = default;
 
   template<class Err = E _ENABLE_IF(
-    std::is_constructible_v<E, Err>
+    std::is_constructible_v<E, Err> &&
+    !std::is_same_v<remove_cvref_t<E>, std::in_place_t> &&
+    !std::is_same_v<remove_cvref_t<E>, unexpected>
   )>
   constexpr unexpected(Err&& e)
   : val_(std::forward<Err>(e)) {}
@@ -559,7 +558,9 @@
   constexpr const E&& value() const&& noexcept { return std::move(val_); }
   constexpr E&& value() && noexcept { return std::move(val_); }
 
-  void swap(unexpected& other) noexcept { std::swap(val_, other.val_); }
+  void swap(unexpected& other) noexcept(std::is_nothrow_swappable_v<E>) {
+    std::swap(val_, other.val_);
+  }
 
   template<class E1, class E2>
   friend constexpr bool
@@ -570,8 +571,9 @@
 
   template<class E1>
   friend void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y)));
+
  private:
-    E val_;
+  E val_;
 };
 
 template<class E1, class E2>
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index b26f83b..c7be00b 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -304,11 +304,11 @@
     {"reboot,pmic_off_fault,.*", 175},
     {"reboot,pmic_off_s3rst,.*", 176},
     {"reboot,pmic_off_other,.*", 177},
-    {"reboot,fastboot_menu", 178},
-    {"reboot,recovery_menu", 179},
-    {"reboot,recovery_ui", 180},
-    {"shutdown,fastboot", 181},
-    {"shutdown,recovery", 182},
+    {"reboot,userrequested,fastboot", 178},
+    {"reboot,userrequested,recovery", 179},
+    {"reboot,userrequested,recovery,ui", 180},
+    {"shutdown,userrequested,fastboot", 181},
+    {"shutdown,userrequested,recovery", 182},
     {"reboot,unknown[0-9]*", 183},
 };
 
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
index 2f0cca7..5066046 100644
--- a/fastboot/device/usb_client.cpp
+++ b/fastboot/device/usb_client.cpp
@@ -255,7 +255,8 @@
     size_t bytes_read_total = 0;
     while (bytes_read_total < len) {
         auto bytes_to_read = std::min(len - bytes_read_total, kFbFfsNumBufs * kFbFfsBufSize);
-        auto bytes_read_now = handle_->read(handle_.get(), char_data, bytes_to_read);
+        auto bytes_read_now =
+                handle_->read(handle_.get(), char_data, bytes_to_read, true /* allow_partial */);
         if (bytes_read_now < 0) {
             return bytes_read_total == 0 ? -1 : bytes_read_total;
         }
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 6482ed3..d264d9a 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -93,14 +93,14 @@
     logd(id, severity, tag, file, line, message);
 }
 
-[[noreturn]] void reboot(bool dedupe) {
-    if (dedupe) {
-        LOG(INFO) << "The device will now reboot to recovery and attempt un-deduplication.";
+[[noreturn]] void reboot(bool overlayfs = false) {
+    if (overlayfs) {
+        LOG(INFO) << "Successfully setup overlayfs\nrebooting device";
     } else {
         LOG(INFO) << "Successfully disabled verity\nrebooting device";
     }
     ::sync();
-    android::base::SetProperty(ANDROID_RB_PROPERTY, dedupe ? "reboot,recovery" : "reboot,remount");
+    android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,remount");
     ::sleep(60);
     ::exit(0);  // SUCCESS
 }
@@ -251,6 +251,7 @@
     auto reboot_later = false;
     auto user_please_reboot_later = false;
     auto uses_overlayfs = fs_mgr_overlayfs_valid() != OverlayfsValidResult::kNotSupported;
+    auto setup_overlayfs = false;
     for (auto it = partitions.begin(); it != partitions.end();) {
         auto& entry = *it;
         auto& mount_point = entry.mount_point;
@@ -271,7 +272,7 @@
                                 ++it;
                                 continue;
                             }
-                            reboot(false);
+                            reboot();
                         }
                         user_please_reboot_later = true;
                     } else if (fs_mgr_set_blk_ro(entry.blk_device, false)) {
@@ -298,6 +299,9 @@
         if (fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change)) {
             if (change) {
                 LOG(INFO) << "Using overlayfs for " << mount_point;
+                reboot_later = can_reboot;
+                user_please_reboot_later = true;
+                setup_overlayfs = true;
             }
         } else if (errno) {
             PLOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
@@ -309,7 +313,7 @@
     }
 
     if (partitions.empty()) {
-        if (reboot_later) reboot(false);
+        if (reboot_later) reboot(setup_overlayfs);
         if (user_please_reboot_later) {
             LOG(INFO) << "Now reboot your device for settings to take effect";
             return 0;
@@ -389,7 +393,7 @@
         retval = REMOUNT_FAILED;
     }
 
-    if (reboot_later) reboot(false);
+    if (reboot_later) reboot(setup_overlayfs);
     if (user_please_reboot_later) {
         LOG(INFO) << "Now reboot your device for settings to take effect";
         return 0;
diff --git a/init/Android.bp b/init/Android.bp
index 383a69d..f71437f 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -68,6 +68,7 @@
         "libpropertyinfoparser",
     ],
     shared_libs: [
+        "libbacktrace",
         "libbase",
         "libbinder",
         "libbootloader_message",
diff --git a/init/Android.mk b/init/Android.mk
index b02c926..c4f7d34 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -105,6 +105,10 @@
     libcap \
     libgsi \
     libcom.android.sysprop.apex \
+    liblzma \
+    libdexfile_support \
+    libunwindstack \
+    libbacktrace \
 
 LOCAL_SANITIZE := signed-integer-overflow
 # First stage init is weird: it may start without stdout/stderr, and no /proc.
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 7dd3ad4..5d64f41 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -33,7 +33,6 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <cutils/android_reboot.h>
 #include <private/android_filesystem_config.h>
 
 #include "debug_ramdisk.h"
@@ -168,13 +167,10 @@
                     "mode=0755,uid=0,gid=0"));
 #undef CHECKCALL
 
+    SetStdioToDevNull(argv);
     // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
     // talk to the outside world...
-    // We need to set up stdin/stdout/stderr for child processes forked from first
-    // stage init as part of the mount process.  This closes /dev/console if the
-    // kernel had previously opened it.
-    auto reboot_bootloader = [](const char*) { RebootSystem(ANDROID_RB_RESTART2, "bootloader"); };
-    InitKernelLogging(argv, reboot_bootloader);
+    InitKernelLogging(argv);
 
     if (!errors.empty()) {
         for (const auto& [error_string, error_errno] : errors) {
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index 63ceead..f6e9676 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -44,6 +44,12 @@
 uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                            const std::string& source_context, const ucred& cr, std::string* error);
 
+// reboot_utils.h
+inline void SetFatalRebootTarget() {}
+inline void __attribute__((noreturn)) InitFatalReboot() {
+    abort();
+}
+
 // selinux.h
 int SelinuxGetVendorAndroidVersion();
 void SelabelInitialize();
diff --git a/init/init.cpp b/init/init.cpp
index 0615d44..548e8c5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -39,7 +39,6 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/android_reboot.h>
 #include <fs_avb/fs_avb.h>
 #include <fs_mgr_vendor_overlay.h>
 #include <keyutils.h>
@@ -605,17 +604,6 @@
     }
 }
 
-static void InitAborter(const char* abort_message) {
-    // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
-    // simply abort instead of trying to reboot the system.
-    if (getpid() != 1) {
-        android::base::DefaultAborter(abort_message);
-        return;
-    }
-
-    RebootSystem(ANDROID_RB_RESTART2, "bootloader");
-}
-
 static void GlobalSeccomp() {
     import_kernel_cmdline(false, [](const std::string& key, const std::string& value,
                                     bool in_qemu) {
@@ -663,8 +651,8 @@
 
     boot_clock::time_point start_time = boot_clock::now();
 
-    // We need to set up stdin/stdout/stderr again now that we're running in init's context.
-    InitKernelLogging(argv, InitAborter);
+    SetStdioToDevNull(argv);
+    InitKernelLogging(argv);
     LOG(INFO) << "init second stage started!";
 
     // Set init and its forked children's oom_adj.
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 5305dc7..12144c1 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -79,6 +79,38 @@
     return updatable;
 }
 
+static bool ActivateFlattenedApexesIfPossible() {
+    if (IsRecoveryMode() || IsApexUpdatable()) {
+        return true;
+    }
+
+    constexpr const char kSystemApex[] = "/system/apex";
+    constexpr const char kApexTop[] = "/apex";
+    if (mount(kSystemApex, kApexTop, nullptr, MS_BIND, nullptr) != 0) {
+        PLOG(ERROR) << "Could not bind mount " << kSystemApex << " to " << kApexTop;
+        return false;
+    }
+
+    // Special casing for the runtime APEX
+    constexpr const char kRuntimeApexMountPath[] = "/system/apex/com.android.runtime";
+    static const std::vector<std::string> kRuntimeApexDirNames = {"com.android.runtime.release",
+                                                                  "com.android.runtime.debug"};
+    bool success = false;
+    for (const auto& name : kRuntimeApexDirNames) {
+        std::string path = std::string(kSystemApex) + "/" + name;
+        if (access(path.c_str(), F_OK) == 0) {
+            if (mount(path.c_str(), kRuntimeApexMountPath, nullptr, MS_BIND, nullptr) == 0) {
+                success = true;
+                break;
+            }
+        }
+    }
+    if (!success) {
+        PLOG(ERROR) << "Failed to bind mount the runtime APEX to " << kRuntimeApexMountPath;
+    }
+    return success;
+}
+
 static android::base::unique_fd bootstrap_ns_fd;
 static android::base::unique_fd default_ns_fd;
 
@@ -129,6 +161,8 @@
         default_ns_id = GetMountNamespaceId();
     }
 
+    success &= ActivateFlattenedApexesIfPossible();
+
     LOG(INFO) << "SetupMountNamespaces done";
     return success;
 }
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index 9610304..d1a712f 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -19,14 +19,40 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
-#include <android-base/logging.h>
-#include <cutils/android_reboot.h>
+#include <string>
+
+#include "android-base/file.h"
+#include "android-base/logging.h"
+#include "android-base/strings.h"
+#include "backtrace/Backtrace.h"
+#include "cutils/android_reboot.h"
 
 #include "capabilities.h"
 
 namespace android {
 namespace init {
 
+static std::string init_fatal_reboot_target = "bootloader";
+
+void SetFatalRebootTarget() {
+    std::string cmdline;
+    android::base::ReadFileToString("/proc/cmdline", &cmdline);
+    cmdline = android::base::Trim(cmdline);
+
+    const char kRebootTargetString[] = "androidboot.init_fatal_reboot_target=";
+    auto start_pos = cmdline.find(kRebootTargetString);
+    if (start_pos == std::string::npos) {
+        return;  // We already default to bootloader if no setting is provided.
+    }
+    start_pos += sizeof(kRebootTargetString) - 1;
+
+    auto end_pos = cmdline.find(' ', start_pos);
+    // if end_pos isn't found, then we've run off the end, but this is okay as this is the last
+    // entry, and -1 is a valid size for string::substr();
+    auto size = end_pos == std::string::npos ? -1 : end_pos - start_pos;
+    init_fatal_reboot_target = cmdline.substr(start_pos, size);
+}
+
 bool IsRebootCapable() {
     if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
         PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
@@ -75,6 +101,32 @@
     abort();
 }
 
+void __attribute__((noreturn)) InitFatalReboot() {
+    auto pid = fork();
+
+    if (pid == -1) {
+        // Couldn't fork, don't even try to backtrace, just reboot.
+        RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
+    } else if (pid == 0) {
+        // Fork a child for safety, since we always want to shut down if something goes wrong, but
+        // its worth trying to get the backtrace, even in the signal handler, since typically it
+        // does work despite not being async-signal-safe.
+        sleep(5);
+        RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
+    }
+
+    // In the parent, let's try to get a backtrace then shutdown.
+    std::unique_ptr<Backtrace> backtrace(
+            Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+    if (!backtrace->Unwind(0)) {
+        LOG(ERROR) << __FUNCTION__ << ": Failed to unwind callstack.";
+    }
+    for (size_t i = 0; i < backtrace->NumFrames(); i++) {
+        LOG(ERROR) << backtrace->FormatFrameData(i);
+    }
+    RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
+}
+
 void InstallRebootSignalHandlers() {
     // Instead of panic'ing the kernel as is the default behavior when init crashes,
     // we prefer to reboot to bootloader on development builds, as this will prevent
@@ -94,7 +146,7 @@
         // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
         // and probably good enough given this is already an error case and only enabled for
         // development builds.
-        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+        InitFatalReboot();
     };
     action.sa_flags = SA_RESTART;
     sigaction(SIGABRT, &action, nullptr);
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index 073a16a..3fd969e 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -21,11 +21,13 @@
 namespace android {
 namespace init {
 
+void SetFatalRebootTarget();
 // Determines whether the system is capable of rebooting. This is conservative,
 // so if any of the attempts to determine this fail, it will still return true.
 bool IsRebootCapable();
 // This is a wrapper around the actual reboot calls.
 void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target);
+void __attribute__((noreturn)) InitFatalReboot();
 void InstallRebootSignalHandlers();
 
 }  // namespace init
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 8a63363..8a9662b 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -60,7 +60,6 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/unique_fd.h>
-#include <cutils/android_reboot.h>
 #include <fs_avb/fs_avb.h>
 #include <selinux/android.h>
 
@@ -522,9 +521,7 @@
 
 // This function initializes SELinux then execs init to run in the init SELinux context.
 int SetupSelinux(char** argv) {
-    android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
-        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
-    });
+    InitKernelLogging(argv);
 
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
diff --git a/init/service.cpp b/init/service.cpp
index 6887d7b..3e865a7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -46,6 +46,7 @@
 #include "util.h"
 
 #if defined(__ANDROID__)
+#include <ApexProperties.sysprop.h>
 #include <android/api-level.h>
 #include <sys/system_properties.h>
 
@@ -372,10 +373,17 @@
         return;
     }
 
+#if defined(__ANDROID__)
+    static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false);
+#else
+    static bool is_apex_updatable = false;
+#endif
+    const bool is_process_updatable = !pre_apexd_ && is_apex_updatable;
+
     // If we crash > 4 times in 4 minutes or before boot_completed,
     // reboot into bootloader or set crashing property
     boot_clock::time_point now = boot_clock::now();
-    if (((flags_ & SVC_CRITICAL) || !pre_apexd_) && !(flags_ & SVC_RESTART)) {
+    if (((flags_ & SVC_CRITICAL) || is_process_updatable) && !(flags_ & SVC_RESTART)) {
         bool boot_completed = android::base::GetBoolProperty("sys.boot_completed", false);
         if (now < time_crashed_ + 4min || !boot_completed) {
             if (++crash_count_ > 4) {
diff --git a/init/util.cpp b/init/util.cpp
index 29d7a76..63d2d44 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -40,6 +40,7 @@
 #include <selinux/android.h>
 
 #if defined(__ANDROID__)
+#include "reboot_utils.h"
 #include "selinux.h"
 #else
 #include "host_init_stubs.h"
@@ -425,20 +426,50 @@
     return true;
 }
 
-void InitKernelLogging(char** argv, std::function<void(const char*)> abort_function) {
+static void InitAborter(const char* abort_message) {
+    // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
+    // simply abort instead of trying to reboot the system.
+    if (getpid() != 1) {
+        android::base::DefaultAborter(abort_message);
+        return;
+    }
+
+    InitFatalReboot();
+}
+
+// The kernel opens /dev/console and uses that fd for stdin/stdout/stderr if there is a serial
+// console enabled and no initramfs, otherwise it does not provide any fds for stdin/stdout/stderr.
+// SetStdioToDevNull() is used to close these existing fds if they exist and replace them with
+// /dev/null regardless.
+//
+// In the case that these fds are provided by the kernel, the exec of second stage init causes an
+// SELinux denial as it does not have access to /dev/console.  In the case that they are not
+// provided, exec of any further process is potentially dangerous as the first fd's opened by that
+// process will take the stdin/stdout/stderr fileno's, which can cause issues if printf(), etc is
+// then used by that process.
+//
+// Lastly, simply calling SetStdioToDevNull() in first stage init is not enough, since first
+// stage init still runs in kernel context, future child processes will not have permissions to
+// access any fds that it opens, including the one opened below for /dev/null.  Therefore,
+// SetStdioToDevNull() must be called again in second stage init.
+void SetStdioToDevNull(char** argv) {
     // Make stdin/stdout/stderr all point to /dev/null.
     int fd = open("/dev/null", O_RDWR);
     if (fd == -1) {
         int saved_errno = errno;
-        android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function));
+        android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
         errno = saved_errno;
         PLOG(FATAL) << "Couldn't open /dev/null";
     }
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fd, 2);
-    if (fd > 2) close(fd);
-    android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function));
+    dup2(fd, STDIN_FILENO);
+    dup2(fd, STDOUT_FILENO);
+    dup2(fd, STDERR_FILENO);
+    if (fd > STDERR_FILENO) close(fd);
+}
+
+void InitKernelLogging(char** argv) {
+    SetFatalRebootTarget();
+    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
 }
 
 bool IsRecoveryMode() {
diff --git a/init/util.h b/init/util.h
index 2232a0f..767620b 100644
--- a/init/util.h
+++ b/init/util.h
@@ -63,7 +63,8 @@
 
 bool IsLegalPropertyName(const std::string& name);
 
-void InitKernelLogging(char** argv, std::function<void(const char*)> abort_function);
+void SetStdioToDevNull(char** argv);
+void InitKernelLogging(char** argv);
 bool IsRecoveryMode();
 }  // namespace init
 }  // namespace android
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index 07040b0..25104eb 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -4,10 +4,15 @@
 # Make sure any property changes are only performed with /data mounted, after
 # post-fs-data state because otherwise behavior is undefined. The exceptions
 # are device adjustments for logcatd service properties (persist.* overrides
-# notwithstanding) for logd.logpersistd.size and logd.logpersistd.buffer.
+# notwithstanding) for logd.logpersistd.size logd.logpersistd.rotate_kbytes and
+# logd.logpersistd.buffer.
 
 # persist to non-persistent trampolines to permit device properties can be
 # overridden when /data mounts, or during runtime.
+on property:persist.logd.logpersistd.count=*
+    # expect /init to report failure if property empty (default)
+    setprop persist.logd.logpersistd.size ${persist.logd.logpersistd.count}
+
 on property:persist.logd.logpersistd.size=256
     setprop persist.logd.logpersistd.size ""
     setprop logd.logpersistd.size ""
@@ -16,6 +21,14 @@
     # expect /init to report failure if property empty (default)
     setprop logd.logpersistd.size ${persist.logd.logpersistd.size}
 
+on property:persist.logd.logpersistd.rotate_kbytes=1024
+    setprop persist.logd.logpersistd.rotate_kbytes ""
+    setprop logd.logpersistd.rotate_kbytes ""
+
+on property:persist.logd.logpersistd.rotate_kbytes=*
+   # expect /init to report failure if property empty (default)
+   setprop logd.logpersistd.rotate_kbytes ${persist.logd.logpersistd.rotate_kbytes}
+
 on property:persist.logd.logpersistd.buffer=all
     setprop persist.logd.logpersistd.buffer ""
     setprop logd.logpersistd.buffer ""
@@ -54,7 +67,7 @@
     stop logcatd
 
 # logcatd service
-service logcatd /system/bin/logcatd -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
+service logcatd /system/bin/logcatd -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r ${logd.logpersistd.rotate_kbytes:-1024} -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
     class late_start
     disabled
     # logd for write to /data/misc/logd, log group for read from log daemon
diff --git a/logd/README.property b/logd/README.property
index da5f96f..d2a2cbb 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -17,10 +17,13 @@
 					 Responds to logcatd, clear and stop.
 logd.logpersistd.buffer          persist logpersistd buffers to collect
 logd.logpersistd.size            persist logpersistd size in MB
+logd.logpersistd.rotate_kbytes   	 persist logpersistd outout file size in KB.
 persist.logd.logpersistd   string        Enable logpersist daemon, "logcatd"
                                          turns on logcat -f in logd context.
 persist.logd.logpersistd.buffer    all   logpersistd buffers to collect
 persist.logd.logpersistd.size      256   logpersistd size in MB
+persist.logd.logpersistd.count     256   sets max number of rotated logs to <count>.
+persist.logd.logpersistd.rotate_kbytes   1024  logpersistd output file size in KB
 persist.logd.size          number  ro    Global default size of the buffer for
                                          all log ids at initial startup, at
                                          runtime use: logcat -b all -G <value>