Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c037bdbc authored by Nikita Ioffe's avatar Nikita Ioffe Committed by Gerrit Code Review
Browse files

Merge "Add CreateEmptyDevice and WaitForDevice APIs"

parents 5e2363e1 15e0f5a9
Loading
Loading
Loading
Loading
+25 −7
Original line number Diff line number Diff line
@@ -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);
+15 −0
Original line number Diff line number Diff line
@@ -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));
}
+13 −0
Original line number Diff line number Diff line
@@ -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