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