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

Commit 70768af0 authored by Yifan Hong's avatar Yifan Hong Committed by Gerrit Code Review
Browse files

Merge "ImageManager returns FiemapStatus."

parents 0ed21b60 e4b44fc5
Loading
Loading
Loading
Loading
+44 −16
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#if !defined(__ANDROID_RECOVERY__)
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android/gsi/BnProgressCallback.h>
#include <android/gsi/IGsiService.h>
#include <android/gsi/IGsid.h>
#include <binder/IServiceManager.h>
@@ -29,10 +30,29 @@ namespace fiemap {
using namespace android::gsi;
using namespace std::chrono_literals;

class ProgressCallback final : public BnProgressCallback {
  public:
    ProgressCallback(std::function<bool(uint64_t, uint64_t)>&& callback)
        : callback_(std::move(callback)) {
        CHECK(callback_);
    }
    android::binder::Status onProgress(int64_t current, int64_t total) {
        if (callback_(static_cast<uint64_t>(current), static_cast<uint64_t>(total))) {
            return android::binder::Status::ok();
        }
        return android::binder::Status::fromServiceSpecificError(UNKNOWN_ERROR,
                                                                 "Progress callback failed");
    }

  private:
    std::function<bool(uint64_t, uint64_t)> callback_;
};

class ImageManagerBinder final : public IImageManager {
  public:
    ImageManagerBinder(android::sp<IGsiService>&& service, android::sp<IImageService>&& manager);
    bool CreateBackingImage(const std::string& name, uint64_t size, int flags) override;
    FiemapStatus CreateBackingImage(const std::string& name, uint64_t size, int flags,
                                    std::function<bool(uint64_t, uint64_t)>&& on_progress) override;
    bool DeleteBackingImage(const std::string& name) override;
    bool MapImageDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
                        std::string* path) override;
@@ -41,7 +61,7 @@ class ImageManagerBinder final : public IImageManager {
    bool IsImageMapped(const std::string& name) override;
    bool MapImageWithDeviceMapper(const IPartitionOpener& opener, const std::string& name,
                                  std::string* dev) override;
    bool ZeroFillNewImage(const std::string& name, uint64_t bytes) override;
    FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes) override;
    bool RemoveAllImages() override;
    bool DisableImage(const std::string& name) override;
    bool RemoveDisabledImages() override;
@@ -55,18 +75,31 @@ class ImageManagerBinder final : public IImageManager {
    android::sp<IImageService> manager_;
};

static FiemapStatus ToFiemapStatus(const char* func, const binder::Status& status) {
    if (!status.isOk()) {
        LOG(ERROR) << func << " binder returned: " << status.toString8().string();
        if (status.serviceSpecificErrorCode() != 0) {
            return FiemapStatus::FromErrorCode(status.serviceSpecificErrorCode());
        } else {
            return FiemapStatus::Error();
        }
    }
    return FiemapStatus::Ok();
}

ImageManagerBinder::ImageManagerBinder(android::sp<IGsiService>&& service,
                                       android::sp<IImageService>&& manager)
    : service_(std::move(service)), manager_(std::move(manager)) {}

bool ImageManagerBinder::CreateBackingImage(const std::string& name, uint64_t size, int flags) {
    auto status = manager_->createBackingImage(name, size, flags);
    if (!status.isOk()) {
        LOG(ERROR) << __PRETTY_FUNCTION__
                   << " binder returned: " << status.exceptionMessage().string();
        return false;
FiemapStatus ImageManagerBinder::CreateBackingImage(
        const std::string& name, uint64_t size, int flags,
        std::function<bool(uint64_t, uint64_t)>&& on_progress) {
    sp<IProgressCallback> callback = nullptr;
    if (on_progress) {
        callback = new ProgressCallback(std::move(on_progress));
    }
    return true;
    auto status = manager_->createBackingImage(name, size, flags, callback);
    return ToFiemapStatus(__PRETTY_FUNCTION__, status);
}

bool ImageManagerBinder::DeleteBackingImage(const std::string& name) {
@@ -147,14 +180,9 @@ std::vector<std::string> ImageManagerBinder::GetAllBackingImages() {
    return retval;
}

bool ImageManagerBinder::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
FiemapStatus ImageManagerBinder::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
    auto status = manager_->zeroFillNewImage(name, bytes);
    if (!status.isOk()) {
        LOG(ERROR) << __PRETTY_FUNCTION__
                   << " binder returned: " << status.exceptionMessage().string();
        return false;
    }
    return true;
    return ToFiemapStatus(__PRETTY_FUNCTION__, status);
}

bool ImageManagerBinder::RemoveAllImages() {
+22 −23
Original line number Diff line number Diff line
@@ -133,27 +133,25 @@ bool ImageManager::BackingImageExists(const std::string& name) {
    return access(header_file.c_str(), F_OK) == 0;
}

bool ImageManager::CreateBackingImage(const std::string& name, uint64_t size, int flags) {
    return CreateBackingImage(name, size, flags, nullptr);
}

static bool IsUnreliablePinningAllowed(const std::string& path) {
    return android::base::StartsWith(path, "/data/gsi/dsu/") ||
           android::base::StartsWith(path, "/data/gsi/test/") ||
           android::base::StartsWith(path, "/data/gsi/ota/test/");
}

bool ImageManager::CreateBackingImage(const std::string& name, uint64_t size, int flags,
FiemapStatus ImageManager::CreateBackingImage(
        const std::string& name, uint64_t size, int flags,
        std::function<bool(uint64_t, uint64_t)>&& on_progress) {
    auto data_path = GetImageHeaderPath(name);
    auto fw = SplitFiemap::Create(data_path, size, 0, on_progress);
    if (!fw) {
        return false;
    std::unique_ptr<SplitFiemap> fw;
    auto status = SplitFiemap::Create(data_path, size, 0, &fw, on_progress);
    if (!status.is_ok()) {
        return status;
    }

    bool reliable_pinning;
    if (!FilesystemHasReliablePinning(data_path, &reliable_pinning)) {
        return false;
        return FiemapStatus::Error();
    }
    if (!reliable_pinning && !IsUnreliablePinningAllowed(data_path)) {
        // For historical reasons, we allow unreliable pinning for certain use
@@ -164,7 +162,7 @@ bool ImageManager::CreateBackingImage(const std::string& name, uint64_t size, in
        // proper pinning.
        LOG(ERROR) << "File system does not have reliable block pinning";
        SplitFiemap::RemoveSplitFiles(data_path);
        return false;
        return FiemapStatus::Error();
    }

    // Except for testing, we do not allow persisting metadata that references
@@ -180,24 +178,25 @@ bool ImageManager::CreateBackingImage(const std::string& name, uint64_t size, in

        fw = {};
        SplitFiemap::RemoveSplitFiles(data_path);
        return false;
        return FiemapStatus::Error();
    }

    bool readonly = !!(flags & CREATE_IMAGE_READONLY);
    if (!UpdateMetadata(metadata_dir_, name, fw.get(), size, readonly)) {
        return false;
        return FiemapStatus::Error();
    }

    if (flags & CREATE_IMAGE_ZERO_FILL) {
        if (!ZeroFillNewImage(name, 0)) {
        auto res = ZeroFillNewImage(name, 0);
        if (!res.is_ok()) {
            DeleteBackingImage(name);
            return false;
            return res;
        }
    }
    return true;
    return FiemapStatus::Ok();
}

bool ImageManager::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
FiemapStatus ImageManager::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
    auto data_path = GetImageHeaderPath(name);

    // See the comment in MapImageDevice() about how this works.
@@ -205,13 +204,13 @@ bool ImageManager::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
    bool can_use_devicemapper;
    if (!FiemapWriter::GetBlockDeviceForFile(data_path, &block_device, &can_use_devicemapper)) {
        LOG(ERROR) << "Could not determine block device for " << data_path;
        return false;
        return FiemapStatus::Error();
    }

    if (!can_use_devicemapper) {
        // We've backed with loop devices, and since we store files in an
        // unencrypted folder, the initial zeroes we wrote will suffice.
        return true;
        return FiemapStatus::Ok();
    }

    // data is dm-crypt, or FBE + dm-default-key. This means the zeroes written
@@ -219,7 +218,7 @@ bool ImageManager::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
    // this.
    auto device = MappedDevice::Open(this, 10s, name);
    if (!device) {
        return false;
        return FiemapStatus::Error();
    }

    static constexpr size_t kChunkSize = 4096;
@@ -232,7 +231,7 @@ bool ImageManager::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
        remaining = get_block_device_size(device->fd());
        if (!remaining) {
            PLOG(ERROR) << "Could not get block device size for " << device->path();
            return false;
            return FiemapStatus::FromErrno(errno);
        }
    }
    while (remaining) {
@@ -240,11 +239,11 @@ bool ImageManager::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
        if (!android::base::WriteFully(device->fd(), zeroes.data(),
                                       static_cast<size_t>(to_write))) {
            PLOG(ERROR) << "write failed: " << device->path();
            return false;
            return FiemapStatus::FromErrno(errno);
        }
        remaining -= to_write;
    }
    return true;
    return FiemapStatus::Ok();
}

bool ImageManager::DeleteBackingImage(const std::string& name) {
+6 −0
Original line number Diff line number Diff line
@@ -37,6 +37,12 @@ class FiemapStatus {
    // Create from a given errno (specified in errno,h)
    static FiemapStatus FromErrno(int error_num) { return FiemapStatus(CastErrorCode(-error_num)); }

    // Create from an integer error code that is expected to be an ErrorCode
    // value. If it isn't, Error() is returned.
    static FiemapStatus FromErrorCode(int32_t error_code) {
        return FiemapStatus(CastErrorCode(error_code));
    }

    // Generic error.
    static FiemapStatus Error() { return FiemapStatus(ErrorCode::ERROR); }

+8 −7
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <string>

#include <android-base/unique_fd.h>
#include <libfiemap/fiemap_status.h>
#include <liblp/partition_opener.h>

namespace android {
@@ -52,7 +53,9 @@ class IImageManager {
    // of the image is undefined. If zero-fill is requested, and the operation
    // cannot be completed, the image will be deleted and this function will
    // return false.
    virtual bool CreateBackingImage(const std::string& name, uint64_t size, int flags) = 0;
    virtual FiemapStatus CreateBackingImage(
            const std::string& name, uint64_t size, int flags,
            std::function<bool(uint64_t, uint64_t)>&& on_progress = nullptr) = 0;

    // Delete an image created with CreateBackingImage. Its entry will be
    // removed from the associated lp_metadata file.
@@ -113,7 +116,7 @@ class IImageManager {

    // Writes |bytes| zeros to |name| file. If |bytes| is 0, then the
    // whole file if filled with zeros.
    virtual bool ZeroFillNewImage(const std::string& name, uint64_t bytes) = 0;
    virtual FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes) = 0;

    // Find and remove all images and metadata for this manager.
    virtual bool RemoveAllImages() = 0;
@@ -133,7 +136,8 @@ class ImageManager final : public IImageManager {
    static std::unique_ptr<ImageManager> Open(const std::string& dir_prefix);

    // Methods that must be implemented from IImageManager.
    bool CreateBackingImage(const std::string& name, uint64_t size, int flags) override;
    FiemapStatus CreateBackingImage(const std::string& name, uint64_t size, int flags,
                                    std::function<bool(uint64_t, uint64_t)>&& on_progress) override;
    bool DeleteBackingImage(const std::string& name) override;
    bool MapImageDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
                        std::string* path) override;
@@ -149,9 +153,6 @@ class ImageManager final : public IImageManager {
    bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;

    std::vector<std::string> GetAllBackingImages();
    // Same as CreateBackingImage, but provides a progress notification.
    bool CreateBackingImage(const std::string& name, uint64_t size, int flags,
                            std::function<bool(uint64_t, uint64_t)>&& on_progress);

    // Returns true if the named partition exists. This does not check the
    // consistency of the backing image/data file.
@@ -164,7 +165,7 @@ class ImageManager final : public IImageManager {
    void set_partition_opener(std::unique_ptr<IPartitionOpener>&& opener);

    // Writes |bytes| zeros at the beginning of the passed image
    bool ZeroFillNewImage(const std::string& name, uint64_t bytes);
    FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes);

  private:
    ImageManager(const std::string& metadata_dir, const std::string& data_dir);
+25 −0
Original line number Diff line number Diff line
@@ -14,10 +14,12 @@

#pragma once

#include <memory>
#include <optional>
#include <string>
#include <unordered_set>

#include <android-base/file.h>
#include <android/hardware/boot/1.1/IBootControl.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -155,5 +157,28 @@ void SetSize(PartitionUpdate* partition_update, uint64_t size);
// Get partition size from update package metadata.
uint64_t GetSize(PartitionUpdate* partition_update);

// Util class for test cases on low space scenario. These tests assumes image manager
// uses /data as backup device.
class LowSpaceUserdata {
  public:
    // Set the maximum free space allowed for this test. If /userdata has more space than the given
    // number, a file is allocated to consume space.
    AssertionResult Init(uint64_t max_free_space);

    uint64_t free_space() const;
    uint64_t available_space() const;
    uint64_t bsize() const;

  private:
    AssertionResult ReadUserdataStats();

    static constexpr const char* kUserDataDevice = "/data";
    std::unique_ptr<TemporaryFile> big_file_;
    bool initialized_ = false;
    uint64_t free_space_ = 0;
    uint64_t available_space_ = 0;
    uint64_t bsize_ = 0;
};

}  // namespace snapshot
}  // namespace android
Loading