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

Commit 2bb4f40d authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi Committed by android-build-merger
Browse files

Merge "[base] Make MappedFile work with OS file handles"

am: 5f0e5e0e

Change-Id: Iae9f09cfa4dc86485ebb6f3fe70e999bd0a7fa8e
parents 9674b347 5f0e5e0e
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -28,15 +28,17 @@
#include <windows.h>
#define PROT_READ 1
#define PROT_WRITE 2
using os_handle = HANDLE;
#else
#include <sys/mman.h>
using os_handle = int;
#endif

namespace android {
namespace base {

/**
 * A region of a file mapped into memory, also known as MmapFile.
 * A region of a file mapped into memory (for grepping: also known as MmapFile or file mapping).
 */
class MappedFile {
 public:
@@ -48,17 +50,34 @@ class MappedFile {
  static std::unique_ptr<MappedFile> FromFd(borrowed_fd fd, off64_t offset, size_t length,
                                            int prot);

  /**
   * Same thing, but using the raw OS file handle instead of a CRT wrapper.
   */
  static MappedFile FromOsHandle(os_handle h, off64_t offset, size_t length, int prot);

  /**
   * Removes the mapping.
   */
  ~MappedFile();

  char* data() { return base_ + offset_; }
  size_t size() { return size_; }
  /**
   * Not copyable but movable.
   */
  MappedFile(MappedFile&& other);
  MappedFile& operator=(MappedFile&& other);

  char* data() const { return base_ + offset_; }
  size_t size() const { return size_; }

  bool isValid() const { return base_ != nullptr; }

  explicit operator bool() const { return isValid(); }

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(MappedFile);

  void Close();

  char* base_;
  size_t size_;

+55 −18
Original line number Diff line number Diff line
@@ -16,13 +16,15 @@

#include "android-base/mapped_file.h"

#include <errno.h>
#include <utility>

#include "android-base/unique_fd.h"
#include <errno.h>

namespace android {
namespace base {

static constexpr char kEmptyBuffer[] = {'0'};

static off64_t InitPageSize() {
#if defined(_WIN32)
  SYSTEM_INFO si;
@@ -35,51 +37,86 @@ static off64_t InitPageSize() {

std::unique_ptr<MappedFile> MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length,
                                               int prot) {
  static off64_t page_size = InitPageSize();
#if defined(_WIN32)
  auto file =
      FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
#else
  auto file = FromOsHandle(fd.get(), offset, length, prot);
#endif
  return file ? std::make_unique<MappedFile>(std::move(file)) : std::unique_ptr<MappedFile>{};
}

MappedFile MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length, int prot) {
  static const off64_t page_size = InitPageSize();
  size_t slop = offset % page_size;
  off64_t file_offset = offset - slop;
  off64_t file_length = length + slop;

#if defined(_WIN32)
  HANDLE handle =
      CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), nullptr,
                        (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
  HANDLE handle = CreateFileMappingW(
      h, nullptr, (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
  if (handle == nullptr) {
    // http://b/119818070 "app crashes when reading asset of zero length".
    // Return a MappedFile that's only valid for reading the size.
    if (length == 0) {
      return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0, nullptr});
    if (length == 0 && ::GetLastError() == ERROR_FILE_INVALID) {
      return MappedFile{const_cast<char*>(kEmptyBuffer), 0, 0, nullptr};
    }
    return nullptr;
    return MappedFile(nullptr, 0, 0, nullptr);
  }
  void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
                             file_offset, file_length);
  if (base == nullptr) {
    CloseHandle(handle);
    return nullptr;
    return MappedFile(nullptr, 0, 0, nullptr);
  }
  return std::unique_ptr<MappedFile>(
      new MappedFile{static_cast<char*>(base), length, slop, handle});
  return MappedFile{static_cast<char*>(base), length, slop, handle};
#else
  void* base = mmap(nullptr, file_length, prot, MAP_SHARED, fd.get(), file_offset);
  void* base = mmap(nullptr, file_length, prot, MAP_SHARED, h, file_offset);
  if (base == MAP_FAILED) {
    // http://b/119818070 "app crashes when reading asset of zero length".
    // mmap fails with EINVAL for a zero length region.
    if (errno == EINVAL && length == 0) {
      return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0});
      return MappedFile{const_cast<char*>(kEmptyBuffer), 0, 0};
    }
    return nullptr;
    return MappedFile(nullptr, 0, 0);
  }
  return std::unique_ptr<MappedFile>(new MappedFile{static_cast<char*>(base), length, slop});
  return MappedFile{static_cast<char*>(base), length, slop};
#endif
}

MappedFile::MappedFile(MappedFile&& other)
    : base_(std::exchange(other.base_, nullptr)),
      size_(std::exchange(other.size_, 0)),
      offset_(std::exchange(other.offset_, 0))
#ifdef _WIN32
      ,
      handle_(std::exchange(other.handle_, nullptr))
#endif
{
}

MappedFile& MappedFile::operator=(MappedFile&& other) {
  Close();
  base_ = std::exchange(other.base_, nullptr);
  size_ = std::exchange(other.size_, 0);
  offset_ = std::exchange(other.offset_, 0);
#ifdef _WIN32
  handle_ = std::exchange(other.handle_, nullptr);
#endif
  return *this;
}

MappedFile::~MappedFile() {
  Close();
}

void MappedFile::Close() {
#if defined(_WIN32)
  if (base_ != nullptr) UnmapViewOfFile(base_);
  if (base_ != nullptr && size_ != 0) UnmapViewOfFile(base_);
  if (handle_ != nullptr) CloseHandle(handle_);
  handle_ = nullptr;
#else
  if (base_ != nullptr) munmap(base_, size_ + offset_);
  if (base_ != nullptr && size_ != 0) munmap(base_, size_ + offset_);
#endif

  base_ = nullptr;
+4 −1
Original line number Diff line number Diff line
@@ -44,5 +44,8 @@ TEST(mapped_file, zero_length_mapping) {
  ASSERT_TRUE(tf.fd != -1);

  auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ);
  ASSERT_EQ(0u, m->size());
  ASSERT_NE(nullptr, m);
  EXPECT_TRUE((bool)*m);
  EXPECT_EQ(0u, m->size());
  EXPECT_NE(nullptr, m->data());
}