Merge "Small clean ups for issues raised in reviews of fastdeploy"
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index bc18994..be0bdd0 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -72,12 +72,7 @@
     return c == '\\' || c == '/';
 }
 
-static __inline__ int adb_thread_setname(const std::string& name) {
-    // TODO: See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx for how to set
-    // the thread name in Windows. Unfortunately, it only works during debugging, but
-    // our build process doesn't generate PDB files needed for debugging.
-    return 0;
-}
+extern int adb_thread_setname(const std::string& name);
 
 static __inline__ void  close_on_exec(int  fd)
 {
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index c94d13f..026dd1c 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -2742,3 +2742,26 @@
 
     return buf;
 }
+
+// The SetThreadDescription API was brought in version 1607 of Windows 10.
+typedef HRESULT(WINAPI* SetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription);
+
+// Based on PlatformThread::SetName() from
+// https://cs.chromium.org/chromium/src/base/threading/platform_thread_win.cc
+int adb_thread_setname(const std::string& name) {
+    // The SetThreadDescription API works even if no debugger is attached.
+    auto set_thread_description_func = reinterpret_cast<SetThreadDescription>(
+            ::GetProcAddress(::GetModuleHandleW(L"Kernel32.dll"), "SetThreadDescription"));
+    if (set_thread_description_func) {
+        std::wstring name_wide;
+        if (!android::base::UTF8ToWide(name.c_str(), &name_wide)) {
+            return errno;
+        }
+        set_thread_description_func(::GetCurrentThread(), name_wide.c_str());
+    }
+
+    // Don't use the thread naming SEH exception because we're compiled with -fno-exceptions.
+    // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code?view=vs-2017
+
+    return 0;
+}
diff --git a/adb/test_device.py b/adb/test_device.py
index 20f224a..9f45115 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1334,6 +1334,206 @@
             self.device.forward_remove("tcp:{}".format(local_port))
 
 
+if sys.platform == "win32":
+    # From https://stackoverflow.com/a/38749458
+    import os
+    import contextlib
+    import msvcrt
+    import ctypes
+    from ctypes import wintypes
+
+    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
+
+    GENERIC_READ  = 0x80000000
+    GENERIC_WRITE = 0x40000000
+    FILE_SHARE_READ  = 1
+    FILE_SHARE_WRITE = 2
+    CONSOLE_TEXTMODE_BUFFER = 1
+    INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
+    STD_OUTPUT_HANDLE = wintypes.DWORD(-11)
+    STD_ERROR_HANDLE = wintypes.DWORD(-12)
+
+    def _check_zero(result, func, args):
+        if not result:
+            raise ctypes.WinError(ctypes.get_last_error())
+        return args
+
+    def _check_invalid(result, func, args):
+        if result == INVALID_HANDLE_VALUE:
+            raise ctypes.WinError(ctypes.get_last_error())
+        return args
+
+    if not hasattr(wintypes, 'LPDWORD'): # Python 2
+        wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
+        wintypes.PSMALL_RECT = ctypes.POINTER(wintypes.SMALL_RECT)
+
+    class COORD(ctypes.Structure):
+        _fields_ = (('X', wintypes.SHORT),
+                    ('Y', wintypes.SHORT))
+
+    class CONSOLE_SCREEN_BUFFER_INFOEX(ctypes.Structure):
+        _fields_ = (('cbSize',               wintypes.ULONG),
+                    ('dwSize',               COORD),
+                    ('dwCursorPosition',     COORD),
+                    ('wAttributes',          wintypes.WORD),
+                    ('srWindow',             wintypes.SMALL_RECT),
+                    ('dwMaximumWindowSize',  COORD),
+                    ('wPopupAttributes',     wintypes.WORD),
+                    ('bFullscreenSupported', wintypes.BOOL),
+                    ('ColorTable',           wintypes.DWORD * 16))
+        def __init__(self, *args, **kwds):
+            super(CONSOLE_SCREEN_BUFFER_INFOEX, self).__init__(
+                    *args, **kwds)
+            self.cbSize = ctypes.sizeof(self)
+
+    PCONSOLE_SCREEN_BUFFER_INFOEX = ctypes.POINTER(
+                                        CONSOLE_SCREEN_BUFFER_INFOEX)
+    LPSECURITY_ATTRIBUTES = wintypes.LPVOID
+
+    kernel32.GetStdHandle.errcheck = _check_invalid
+    kernel32.GetStdHandle.restype = wintypes.HANDLE
+    kernel32.GetStdHandle.argtypes = (
+        wintypes.DWORD,) # _In_ nStdHandle
+
+    kernel32.CreateConsoleScreenBuffer.errcheck = _check_invalid
+    kernel32.CreateConsoleScreenBuffer.restype = wintypes.HANDLE
+    kernel32.CreateConsoleScreenBuffer.argtypes = (
+        wintypes.DWORD,        # _In_       dwDesiredAccess
+        wintypes.DWORD,        # _In_       dwShareMode
+        LPSECURITY_ATTRIBUTES, # _In_opt_   lpSecurityAttributes
+        wintypes.DWORD,        # _In_       dwFlags
+        wintypes.LPVOID)       # _Reserved_ lpScreenBufferData
+
+    kernel32.GetConsoleScreenBufferInfoEx.errcheck = _check_zero
+    kernel32.GetConsoleScreenBufferInfoEx.argtypes = (
+        wintypes.HANDLE,               # _In_  hConsoleOutput
+        PCONSOLE_SCREEN_BUFFER_INFOEX) # _Out_ lpConsoleScreenBufferInfo
+
+    kernel32.SetConsoleScreenBufferInfoEx.errcheck = _check_zero
+    kernel32.SetConsoleScreenBufferInfoEx.argtypes = (
+        wintypes.HANDLE,               # _In_  hConsoleOutput
+        PCONSOLE_SCREEN_BUFFER_INFOEX) # _In_  lpConsoleScreenBufferInfo
+
+    kernel32.SetConsoleWindowInfo.errcheck = _check_zero
+    kernel32.SetConsoleWindowInfo.argtypes = (
+        wintypes.HANDLE,      # _In_ hConsoleOutput
+        wintypes.BOOL,        # _In_ bAbsolute
+        wintypes.PSMALL_RECT) # _In_ lpConsoleWindow
+
+    kernel32.FillConsoleOutputCharacterW.errcheck = _check_zero
+    kernel32.FillConsoleOutputCharacterW.argtypes = (
+        wintypes.HANDLE,  # _In_  hConsoleOutput
+        wintypes.WCHAR,   # _In_  cCharacter
+        wintypes.DWORD,   # _In_  nLength
+        COORD,            # _In_  dwWriteCoord
+        wintypes.LPDWORD) # _Out_ lpNumberOfCharsWritten
+
+    kernel32.ReadConsoleOutputCharacterW.errcheck = _check_zero
+    kernel32.ReadConsoleOutputCharacterW.argtypes = (
+        wintypes.HANDLE,  # _In_  hConsoleOutput
+        wintypes.LPWSTR,  # _Out_ lpCharacter
+        wintypes.DWORD,   # _In_  nLength
+        COORD,            # _In_  dwReadCoord
+        wintypes.LPDWORD) # _Out_ lpNumberOfCharsRead
+
+    @contextlib.contextmanager
+    def allocate_console():
+        allocated = kernel32.AllocConsole()
+        try:
+            yield allocated
+        finally:
+            if allocated:
+                kernel32.FreeConsole()
+
+    @contextlib.contextmanager
+    def console_screen(ncols=None, nrows=None):
+        info = CONSOLE_SCREEN_BUFFER_INFOEX()
+        new_info = CONSOLE_SCREEN_BUFFER_INFOEX()
+        nwritten = (wintypes.DWORD * 1)()
+        hStdOut = kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
+        kernel32.GetConsoleScreenBufferInfoEx(
+               hStdOut, ctypes.byref(info))
+        if ncols is None:
+            ncols = info.dwSize.X
+        if nrows is None:
+            nrows = info.dwSize.Y
+        elif nrows > 9999:
+            raise ValueError('nrows must be 9999 or less')
+        fd_screen = None
+        hScreen = kernel32.CreateConsoleScreenBuffer(
+                    GENERIC_READ | GENERIC_WRITE,
+                    FILE_SHARE_READ | FILE_SHARE_WRITE,
+                    None, CONSOLE_TEXTMODE_BUFFER, None)
+        try:
+            fd_screen = msvcrt.open_osfhandle(
+                            hScreen, os.O_RDWR | os.O_BINARY)
+            kernel32.GetConsoleScreenBufferInfoEx(
+                   hScreen, ctypes.byref(new_info))
+            new_info.dwSize = COORD(ncols, nrows)
+            new_info.srWindow = wintypes.SMALL_RECT(
+                    Left=0, Top=0, Right=(ncols - 1),
+                    Bottom=(info.srWindow.Bottom - info.srWindow.Top))
+            kernel32.SetConsoleScreenBufferInfoEx(
+                    hScreen, ctypes.byref(new_info))
+            kernel32.SetConsoleWindowInfo(hScreen, True,
+                    ctypes.byref(new_info.srWindow))
+            kernel32.FillConsoleOutputCharacterW(
+                    hScreen, u'\0', ncols * nrows, COORD(0,0), nwritten)
+            kernel32.SetConsoleActiveScreenBuffer(hScreen)
+            try:
+                yield fd_screen
+            finally:
+                kernel32.SetConsoleScreenBufferInfoEx(
+                    hStdOut, ctypes.byref(info))
+                kernel32.SetConsoleWindowInfo(hStdOut, True,
+                        ctypes.byref(info.srWindow))
+                kernel32.SetConsoleActiveScreenBuffer(hStdOut)
+        finally:
+            if fd_screen is not None:
+                os.close(fd_screen)
+            else:
+                kernel32.CloseHandle(hScreen)
+
+    def read_screen(fd):
+        hScreen = msvcrt.get_osfhandle(fd)
+        csbi = CONSOLE_SCREEN_BUFFER_INFOEX()
+        kernel32.GetConsoleScreenBufferInfoEx(
+            hScreen, ctypes.byref(csbi))
+        ncols = csbi.dwSize.X
+        pos = csbi.dwCursorPosition
+        length = ncols * pos.Y + pos.X + 1
+        buf = (ctypes.c_wchar * length)()
+        n = (wintypes.DWORD * 1)()
+        kernel32.ReadConsoleOutputCharacterW(
+            hScreen, buf, length, COORD(0,0), n)
+        lines = [buf[i:i+ncols].rstrip(u'\0')
+                    for i in range(0, n[0], ncols)]
+        return u'\n'.join(lines)
+
+@unittest.skipUnless(sys.platform == "win32", "requires Windows")
+class WindowsConsoleTest(DeviceTest):
+    def test_unicode_output(self):
+        """Test Unicode command line parameters and Unicode console window output.
+
+        Bug: https://issuetracker.google.com/issues/111972753
+        """
+        # If we don't have a console window, allocate one. This isn't necessary if we're already
+        # being run from a console window, which is typical.
+        with allocate_console() as allocated_console:
+            # Create a temporary console buffer and switch to it. We could also pass a parameter of
+            # ncols=len(unicode_string), but it causes the window to flash as it is resized and
+            # likely unnecessary given the typical console window size.
+            with console_screen(nrows=1000) as screen:
+                unicode_string = u'로보카 폴리'
+                # Run adb and allow it to detect that stdout is a console, not a pipe, by using
+                # device.shell_popen() which does not use a pipe, unlike device.shell().
+                process = self.device.shell_popen(['echo', '"' + unicode_string + '"'])
+                process.wait()
+                # Read what was written by adb to the temporary console buffer.
+                console_output = read_screen(screen)
+                self.assertEqual(unicode_string, console_output)
+
+
 def main():
     random.seed(0)
     if len(adb.get_devices()) > 0:
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index cb7cbbe..77f3515 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -143,12 +143,16 @@
   ssize_t rc =
       TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
   if (rc == 0) {
-    LOG(ERROR) << "libdebuggerd_client: failed to read response from tombstoned: timeout reached?";
+    LOG(ERROR) << "libdebuggerd_client: failed to read initial response from tombstoned: "
+               << "timeout reached?";
+    return false;
+  } else if (rc == -1) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to read initial response from tombstoned";
     return false;
   } else if (rc != sizeof(response)) {
-    LOG(ERROR)
-        << "libdebuggerd_client: received packet of unexpected length from tombstoned: expected "
-        << sizeof(response) << ", received " << rc;
+    LOG(ERROR) << "libdebuggerd_client: received packet of unexpected length from tombstoned while "
+                  "reading initial response: expected "
+               << sizeof(response) << ", received " << rc;
     return false;
   }
 
@@ -164,12 +168,16 @@
 
   rc = TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
   if (rc == 0) {
-    LOG(ERROR) << "libdebuggerd_client: failed to read response from tombstoned: timeout reached?";
+    LOG(ERROR) << "libdebuggerd_client: failed to read status response from tombstoned: "
+                  "timeout reached?";
+    return false;
+  } else if (rc == -1) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to read status response from tombstoned";
     return false;
   } else if (rc != sizeof(response)) {
-    LOG(ERROR)
-      << "libdebuggerd_client: received packet of unexpected length from tombstoned: expected "
-      << sizeof(response) << ", received " << rc;
+    LOG(ERROR) << "libdebuggerd_client: received packet of unexpected length from tombstoned while "
+                  "reading confirmation response: expected "
+               << sizeof(response) << ", received " << rc;
     return false;
   }
 
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 3b91ddd..6b175af 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -121,6 +121,7 @@
 
     shared_libs: [
         "android.hardware.boot@1.0",
+        "android.hardware.fastboot@1.0",
         "libadbd",
         "libasyncio",
         "libbase",
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 8a425ae..57e25fc 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -53,6 +53,7 @@
 #define FB_VAR_HAS_SLOT "has-slot"
 #define FB_VAR_SLOT_COUNT "slot-count"
 #define FB_VAR_PARTITION_SIZE "partition-size"
+#define FB_VAR_PARTITION_TYPE "partition-type"
 #define FB_VAR_SLOT_SUCCESSFUL "slot-successful"
 #define FB_VAR_SLOT_UNBOOTABLE "slot-unbootable"
 #define FB_VAR_IS_LOGICAL "is-logical"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 771c288..0ec0994 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -88,6 +88,7 @@
             {FB_VAR_SLOT_SUCCESSFUL, {GetSlotSuccessful, nullptr}},
             {FB_VAR_SLOT_UNBOOTABLE, {GetSlotUnbootable, nullptr}},
             {FB_VAR_PARTITION_SIZE, {GetPartitionSize, GetAllPartitionArgsWithSlot}},
+            {FB_VAR_PARTITION_TYPE, {GetPartitionType, GetAllPartitionArgsWithSlot}},
             {FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}},
             {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}},
             {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}}};
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 55aca9c..ae2e7a6 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -19,7 +19,7 @@
 #include <android-base/logging.h>
 #include <android-base/strings.h>
 #include <android/hardware/boot/1.0/IBootControl.h>
-
+#include <android/hardware/fastboot/1.0/IFastboot.h>
 #include <algorithm>
 
 #include "constants.h"
@@ -29,6 +29,7 @@
 using ::android::hardware::hidl_string;
 using ::android::hardware::boot::V1_0::IBootControl;
 using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::fastboot::V1_0::IFastboot;
 namespace sph = std::placeholders;
 
 FastbootDevice::FastbootDevice()
@@ -49,7 +50,8 @@
               {FB_CMD_UPDATE_SUPER, UpdateSuperHandler},
       }),
       transport_(std::make_unique<ClientUsbTransport>()),
-      boot_control_hal_(IBootControl::getService()) {}
+      boot_control_hal_(IBootControl::getService()),
+      fastboot_hal_(IFastboot::getService()) {}
 
 FastbootDevice::~FastbootDevice() {
     CloseDevice();
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index 171e7ae..189cf80 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include <android/hardware/boot/1.0/IBootControl.h>
+#include <android/hardware/fastboot/1.0/IFastboot.h>
 
 #include "commands.h"
 #include "transport.h"
@@ -49,11 +50,15 @@
     android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal() {
         return boot_control_hal_;
     }
+    android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal() {
+        return fastboot_hal_;
+    }
 
   private:
     const std::unordered_map<std::string, CommandHandler> kCommandMap;
 
     std::unique_ptr<Transport> transport_;
     android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
+    android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
     std::vector<char> download_data_;
 };
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index d78c809..261a202 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -28,6 +28,7 @@
 #include "fastboot_device.h"
 
 using namespace android::fs_mgr;
+using namespace std::chrono_literals;
 using android::base::unique_fd;
 using android::hardware::boot::V1_0::Slot;
 
@@ -48,11 +49,11 @@
     }
     uint32_t slot_number = SlotNumberForSlotSuffix(slot);
     std::string dm_path;
-    if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, &dm_path)) {
+    if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, 5s, &dm_path)) {
         LOG(ERROR) << "Could not map partition: " << name;
         return false;
     }
-    auto closer = [name]() -> void { DestroyLogicalPartition(name); };
+    auto closer = [name]() -> void { DestroyLogicalPartition(name, 5s); };
     *handle = PartitionHandle(dm_path, std::move(closer));
     return true;
 }
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index a960189..7535248 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -31,6 +31,9 @@
 
 using ::android::hardware::boot::V1_0::BoolResult;
 using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::fastboot::V1_0::FileSystemType;
+using ::android::hardware::fastboot::V1_0::Result;
+using ::android::hardware::fastboot::V1_0::Status;
 
 constexpr int kMaxDownloadSizeDefault = 0x20000000;
 constexpr char kFastbootProtocolVersion[] = "0.4";
@@ -195,6 +198,47 @@
     return true;
 }
 
+bool GetPartitionType(FastbootDevice* device, const std::vector<std::string>& args,
+                      std::string* message) {
+    if (args.size() < 1) {
+        *message = "Missing argument";
+        return false;
+    }
+    std::string partition_name = args[0];
+    auto fastboot_hal = device->fastboot_hal();
+    if (!fastboot_hal) {
+        *message = "Fastboot HAL not found";
+        return false;
+    }
+
+    FileSystemType type;
+    Result ret;
+    auto ret_val =
+            fastboot_hal->getPartitionType(args[0], [&](FileSystemType fs_type, Result result) {
+                type = fs_type;
+                ret = result;
+            });
+    if (!ret_val.isOk() || (ret.status != Status::SUCCESS)) {
+        *message = "Unable to retrieve partition type";
+    } else {
+        switch (type) {
+            case FileSystemType::RAW:
+                *message = "raw";
+                return true;
+            case FileSystemType::EXT4:
+                *message = "ext4";
+                return true;
+            case FileSystemType::F2FS:
+                *message = "f2fs";
+                return true;
+            default:
+                *message = "Unknown file system type";
+        }
+    }
+
+    return false;
+}
+
 bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args,
                            std::string* message) {
     if (args.size() < 1) {
diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h
index a44e729..63f2670 100644
--- a/fastboot/device/variables.h
+++ b/fastboot/device/variables.h
@@ -44,6 +44,8 @@
 bool GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args, std::string* message);
 bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args,
                       std::string* message);
+bool GetPartitionType(FastbootDevice* device, const std::vector<std::string>& args,
+                      std::string* message);
 bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args,
                            std::string* message);
 bool GetIsUserspace(FastbootDevice* device, const std::vector<std::string>& args,
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index e3c2c2b..f56043c 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -102,12 +102,16 @@
 
 // TODO: switch to inotify()
 bool fs_mgr_wait_for_file(const std::string& filename,
-                          const std::chrono::milliseconds relative_timeout) {
+                          const std::chrono::milliseconds relative_timeout,
+                          FileWaitMode file_wait_mode) {
     auto start_time = std::chrono::steady_clock::now();
 
     while (true) {
-        if (!access(filename.c_str(), F_OK) || errno != ENOENT) {
-            return true;
+        int rv = access(filename.c_str(), F_OK);
+        if (file_wait_mode == FileWaitMode::Exists) {
+            if (!rv || errno != ENOENT) return true;
+        } else if (file_wait_mode == FileWaitMode::DoesNotExist) {
+            if (rv && errno == ENOENT) return true;
         }
 
         std::this_thread::sleep_for(50ms);
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index a91e92e..804069a 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -81,7 +81,7 @@
 
 static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
                                    const LpMetadataPartition& partition, bool force_writable,
-                                   std::string* path) {
+                                   const std::chrono::milliseconds& timeout_ms, std::string* path) {
     DeviceMapper& dm = DeviceMapper::Instance();
 
     DmTable table;
@@ -98,6 +98,13 @@
     if (!dm.GetDmDevicePathByName(name, path)) {
         return false;
     }
+    if (timeout_ms > std::chrono::milliseconds::zero()) {
+        if (!fs_mgr_wait_for_file(*path, timeout_ms, FileWaitMode::Exists)) {
+            DestroyLogicalPartition(name, {});
+            LERROR << "Timed out waiting for device path: " << *path;
+            return false;
+        }
+    }
     LINFO << "Created logical partition " << name << " on device " << *path;
     return true;
 }
@@ -115,7 +122,7 @@
             continue;
         }
         std::string path;
-        if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, &path)) {
+        if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, {}, &path)) {
             LERROR << "Could not create logical partition: " << GetPartitionName(partition);
             return false;
         }
@@ -125,7 +132,7 @@
 
 bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
                             const std::string& partition_name, bool force_writable,
-                            std::string* path) {
+                            const std::chrono::milliseconds& timeout_ms, std::string* path) {
     auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
     if (!metadata) {
         LOG(ERROR) << "Could not read partition table.";
@@ -134,18 +141,26 @@
     for (const auto& partition : metadata->partitions) {
         if (GetPartitionName(partition) == partition_name) {
             return CreateLogicalPartition(block_device, *metadata.get(), partition, force_writable,
-                                          path);
+                                          timeout_ms, path);
         }
     }
     LERROR << "Could not find any partition with name: " << partition_name;
     return false;
 }
 
-bool DestroyLogicalPartition(const std::string& name) {
+bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
     DeviceMapper& dm = DeviceMapper::Instance();
+    std::string path;
+    if (timeout_ms > std::chrono::milliseconds::zero()) {
+        dm.GetDmDevicePathByName(name, &path);
+    }
     if (!dm.DeleteDevice(name)) {
         return false;
     }
+    if (!path.empty() && !fs_mgr_wait_for_file(path, timeout_ms, FileWaitMode::DoesNotExist)) {
+        LERROR << "Timed out waiting for device path to unlink: " << path;
+        return false;
+    }
     LINFO << "Unmapped logical partition " << name;
     return true;
 }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index a347faf..ebc4a0f 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -119,9 +119,13 @@
 
 using namespace std::chrono_literals;
 
-int fs_mgr_set_blk_ro(const char *blockdev);
+enum class FileWaitMode { Exists, DoesNotExist };
+
 bool fs_mgr_wait_for_file(const std::string& filename,
-                          const std::chrono::milliseconds relative_timeout);
+                          const std::chrono::milliseconds relative_timeout,
+                          FileWaitMode wait_mode = FileWaitMode::Exists);
+
+int fs_mgr_set_blk_ro(const char* blockdev);
 bool fs_mgr_update_for_slotselect(struct fstab *fstab);
 bool fs_mgr_is_device_unlocked();
 const std::string& get_android_dt_dir();
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index f15c450..08f4554 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -27,6 +27,7 @@
 
 #include <stdint.h>
 
+#include <chrono>
 #include <memory>
 #include <string>
 #include <vector>
@@ -43,12 +44,16 @@
 // the partition name. On success, a path to the partition's block device is
 // returned. If |force_writable| is true, the "readonly" flag will be ignored
 // so the partition can be flashed.
+//
+// If |timeout_ms| is non-zero, then CreateLogicalPartition will block for the
+// given amount of time until the path returned in |path| is available.
 bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
                             const std::string& partition_name, bool force_writable,
-                            std::string* path);
+                            const std::chrono::milliseconds& timeout_ms, std::string* path);
 
-// Destroy the block device for a logical partition, by name.
-bool DestroyLogicalPartition(const std::string& name);
+// Destroy the block device for a logical partition, by name. If |timeout_ms|
+// is non-zero, then this will block until the device path has been unlinked.
+bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms);
 
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 2b526f6..c4b57c7 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -278,7 +278,7 @@
     struct dm_ioctl io;
     InitIo(&io, name);
     if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
-        PLOG(ERROR) << "DM_DEV_STATUS failed for " << name;
+        PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
         return false;
     }
 
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index a35cf8e..38842a4 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -192,6 +192,10 @@
 
   private:
     MetadataBuilder();
+    MetadataBuilder(const MetadataBuilder&) = delete;
+    MetadataBuilder(MetadataBuilder&&) = delete;
+    MetadataBuilder& operator=(const MetadataBuilder&) = delete;
+    MetadataBuilder& operator=(MetadataBuilder&&) = delete;
     bool Init(const BlockDeviceInfo& info, uint32_t metadata_max_size, uint32_t metadata_slot_count);
     bool Init(const LpMetadata& metadata);
     bool GrowPartition(Partition* partition, uint64_t aligned_size);
diff --git a/healthd/Android.mk b/healthd/Android.mk
index f7214c6..9096f79 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -43,7 +43,7 @@
     AnimationParser.cpp
 
 LOCAL_MODULE := libhealthd_charger
-LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := \
     $(LOCAL_PATH) \
     $(LOCAL_PATH)/include
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index ce2421e..1980dc6 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -97,6 +97,8 @@
 
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 
+#define FAIL_REPORT_RLIMIT_MS 1000
+
 /* default to old in-kernel interface if no memory pressure events */
 static bool use_inkernel_interface = true;
 static bool has_inkernel_module;
@@ -1097,8 +1099,7 @@
 }
 
 /* Kill one process specified by procp.  Returns the size of the process killed */
-static int kill_one_process(struct proc* procp, int min_score_adj,
-                            enum vmpressure_level level) {
+static int kill_one_process(struct proc* procp) {
     int pid = procp->pid;
     uid_t uid = procp->uid;
     char *taskname;
@@ -1132,11 +1133,8 @@
 
     /* CAP_KILL required */
     r = kill(pid, SIGKILL);
-    ALOGI(
-        "Killing '%s' (%d), uid %d, adj %d\n"
-        "   to free %ldkB because system is under %s memory pressure (min_oom_adj=%d)\n",
-        taskname, pid, uid, procp->oomadj, tasksize * page_k,
-        level_name[level], min_score_adj);
+    ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
+        taskname, pid, uid, procp->oomadj, tasksize * page_k);
     pid_remove(pid);
 
     TRACE_KILL_END();
@@ -1163,8 +1161,7 @@
  * If pages_to_free is set to 0 only one process will be killed.
  * Returns the size of the killed processes.
  */
-static int find_and_kill_processes(enum vmpressure_level level,
-                                   int min_score_adj, int pages_to_free) {
+static int find_and_kill_processes(int min_score_adj, int pages_to_free) {
     int i;
     int killed_size;
     int pages_freed = 0;
@@ -1183,7 +1180,7 @@
             if (!procp)
                 break;
 
-            killed_size = kill_one_process(procp, min_score_adj, level);
+            killed_size = kill_one_process(procp);
             if (killed_size >= 0) {
 #ifdef LMKD_LOG_STATS
                 if (enable_stats_log && !lmk_state_change_start) {
@@ -1282,6 +1279,7 @@
     enum vmpressure_level lvl;
     union meminfo mi;
     union zoneinfo zi;
+    struct timespec curr_tm;
     static struct timespec last_kill_tm;
     static unsigned long kill_skip_count = 0;
     enum vmpressure_level level = (enum vmpressure_level)data;
@@ -1312,14 +1310,12 @@
         }
     }
 
+    if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
+        ALOGE("Failed to get current time");
+        return;
+    }
+
     if (kill_timeout_ms) {
-        struct timespec curr_tm;
-
-        if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
-            ALOGE("Failed to get current time");
-            return;
-        }
-
         if (get_time_diff_ms(&last_kill_tm, &curr_tm) < kill_timeout_ms) {
             kill_skip_count++;
             return;
@@ -1425,7 +1421,7 @@
 do_kill:
     if (low_ram_device) {
         /* For Go devices kill only one task */
-        if (find_and_kill_processes(level, level_oomadj[level], 0) == 0) {
+        if (find_and_kill_processes(level_oomadj[level], 0) == 0) {
             if (debug_process_killing) {
                 ALOGI("Nothing to kill");
             }
@@ -1434,6 +1430,8 @@
         }
     } else {
         int pages_freed;
+        static struct timespec last_report_tm;
+        static unsigned long report_skip_count = 0;
 
         if (!use_minfree_levels) {
             /* If pressure level is less than critical and enough free swap then ignore */
@@ -1461,30 +1459,41 @@
             min_score_adj = level_oomadj[level];
         }
 
-        pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free);
+        pages_freed = find_and_kill_processes(min_score_adj, pages_to_free);
 
-        if (use_minfree_levels) {
-            ALOGI("Killing because cache %ldkB is below "
-                  "limit %ldkB for oom_adj %d\n"
-                  "   Free memory is %ldkB %s reserved",
-                  other_file * page_k, minfree * page_k, min_score_adj,
-                  other_free * page_k, other_free >= 0 ? "above" : "below");
-        }
-
-        if (pages_freed < pages_to_free) {
-            ALOGI("Unable to free enough memory (pages to free=%d, pages freed=%d)",
-                  pages_to_free, pages_freed);
-        } else {
-            ALOGI("Reclaimed enough memory (pages to free=%d, pages freed=%d)",
-                  pages_to_free, pages_freed);
-            if (clock_gettime(CLOCK_MONOTONIC_COARSE, &last_kill_tm) != 0) {
-                ALOGE("Failed to get current time");
+        if (pages_freed == 0) {
+            /* Rate limit kill reports when nothing was reclaimed */
+            if (get_time_diff_ms(&last_report_tm, &curr_tm) < FAIL_REPORT_RLIMIT_MS) {
+                report_skip_count++;
                 return;
             }
         }
-        if (pages_freed > 0) {
-            meminfo_log(&mi);
+
+        /* Log meminfo whenever we kill or when report rate limit allows */
+        meminfo_log(&mi);
+        if (pages_freed >= pages_to_free) {
+            /* Reset kill time only if reclaimed enough memory */
+            last_kill_tm = curr_tm;
         }
+
+        if (use_minfree_levels) {
+            ALOGI("Killing to reclaim %ldkB, reclaimed %ldkB, cache(%ldkB) and "
+                "free(%" PRId64 "kB)-reserved(%" PRId64 "kB) below min(%ldkB) for oom_adj %d",
+                pages_to_free * page_k, pages_freed * page_k,
+                other_file * page_k, mi.field.nr_free_pages * page_k,
+                zi.field.totalreserve_pages * page_k,
+                minfree * page_k, min_score_adj);
+        } else {
+            ALOGI("Killing to reclaim %ldkB, reclaimed %ldkB at oom_adj %d",
+                pages_to_free * page_k, pages_freed * page_k, min_score_adj);
+        }
+
+        if (report_skip_count > 0) {
+            ALOGI("Suppressed %lu failed kill reports", report_skip_count);
+            report_skip_count = 0;
+        }
+
+        last_report_tm = curr_tm;
     }
 }
 
diff --git a/lmkd/tests/lmkd_test.cpp b/lmkd/tests/lmkd_test.cpp
index 1996bae..f54b25c 100644
--- a/lmkd/tests/lmkd_test.cpp
+++ b/lmkd/tests/lmkd_test.cpp
@@ -39,7 +39,7 @@
 #define LMKDTEST_RESPAWN_FLAG "LMKDTEST_RESPAWN"
 
 #define LMKD_LOGCAT_MARKER "lowmemorykiller"
-#define LMKD_KILL_MARKER_TEMPLATE LMKD_LOGCAT_MARKER ": Killing '%s'"
+#define LMKD_KILL_MARKER_TEMPLATE LMKD_LOGCAT_MARKER ": Kill '%s'"
 #define OOM_MARKER "Out of memory"
 #define OOM_KILL_MARKER "Killed process"
 #define MIN_LOG_SIZE 100
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1c2ef64..915540e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -306,12 +306,12 @@
     # /data, which in turn can only be loaded when system properties are present.
     trigger post-fs-data
 
-    # Now we can start zygote for devices with file based encryption
-    trigger zygote-start
-
     # Load persist properties and override properties (if enabled) from /data.
     trigger load_persist_props_action
 
+    # Now we can start zygote for devices with file based encryption
+    trigger zygote-start
+
     # Remove a file to wake up anything waiting for firmware.
     trigger firmware_mounts_complete