Add CreateEmptyDevice and WaitForDevice APIs
These APIs support a flow in which dm devices can be created before they are actually needed, hence minimizing the time a process will wait for ueventd to create user space paths. Bug: 190618831 Test: atest libdm_test Change-Id: I4dfa14e5271a6a13de6da73ec3c7efb1ebc0f8b8
This commit is contained in:
parent
5e2363e14d
commit
15e0f5a98a
|
@ -170,19 +170,18 @@ static bool IsRecovery() {
|
|||
return access("/system/bin/recovery", F_OK) == 0;
|
||||
}
|
||||
|
||||
bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
|
||||
const std::chrono::milliseconds& timeout_ms) {
|
||||
bool DeviceMapper::CreateEmptyDevice(const std::string& name) {
|
||||
std::string uuid = GenerateUuid();
|
||||
if (!CreateDevice(name, uuid)) {
|
||||
return false;
|
||||
}
|
||||
return CreateDevice(name, uuid);
|
||||
}
|
||||
|
||||
bool DeviceMapper::WaitForDevice(const std::string& name,
|
||||
const std::chrono::milliseconds& timeout_ms, std::string* path) {
|
||||
// We use the unique path for testing whether the device is ready. After
|
||||
// that, it's safe to use the dm-N path which is compatible with callers
|
||||
// that expect it to be formatted as such.
|
||||
std::string unique_path;
|
||||
if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
|
||||
!GetDmDevicePathByName(name, path)) {
|
||||
if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) {
|
||||
DeleteDevice(name);
|
||||
return false;
|
||||
}
|
||||
|
@ -208,6 +207,25 @@ bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, s
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
|
||||
const std::chrono::milliseconds& timeout_ms) {
|
||||
if (!CreateEmptyDevice(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LoadTableAndActivate(name, table)) {
|
||||
DeleteDevice(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WaitForDevice(name, timeout_ms, path)) {
|
||||
DeleteDevice(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
|
||||
struct dm_ioctl io;
|
||||
InitIo(&io, name);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <thread>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/scopeguard.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
@ -679,3 +680,17 @@ TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) {
|
|||
ASSERT_NE(0, access(path.c_str(), F_OK));
|
||||
ASSERT_EQ(ENOENT, errno);
|
||||
}
|
||||
|
||||
TEST(libdm, CreateEmptyDevice) {
|
||||
DeviceMapper& dm = DeviceMapper::Instance();
|
||||
ASSERT_TRUE(dm.CreateEmptyDevice("empty-device"));
|
||||
auto guard = android::base::make_scope_guard([&]() { dm.DeleteDevice("empty-device", 5s); });
|
||||
|
||||
// Empty device should be in suspended state.
|
||||
ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device"));
|
||||
|
||||
std::string path;
|
||||
ASSERT_TRUE(dm.WaitForDevice("empty-device", 5s, &path));
|
||||
// Path should exist.
|
||||
ASSERT_EQ(0, access(path.c_str(), F_OK));
|
||||
}
|
||||
|
|
|
@ -115,6 +115,19 @@ class DeviceMapper final {
|
|||
// - ACTIVE: resumes the device.
|
||||
bool ChangeState(const std::string& name, DmDeviceState state);
|
||||
|
||||
// Creates empty device.
|
||||
// This supports a use case when a caller doesn't need a device straight away, but instead
|
||||
// asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd
|
||||
// to create user space paths.
|
||||
// Callers are expected to then activate their device by calling LoadTableAndActivate function.
|
||||
// To avoid race conditions, callers must still synchronize with ueventd by calling
|
||||
// WaitForDevice function.
|
||||
bool CreateEmptyDevice(const std::string& name);
|
||||
|
||||
// Waits for device paths to be created in the user space.
|
||||
bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
|
||||
std::string* path);
|
||||
|
||||
// Creates a device, loads the given table, and activates it. If the device
|
||||
// is not able to be activated, it is destroyed, and false is returned.
|
||||
// After creation, |path| contains the result of calling
|
||||
|
|
Loading…
Reference in New Issue