From 624f2b2d9e6ac7511015d89bbef62e5a82f26346 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Sun, 17 Jul 2022 16:34:17 +0300 Subject: [PATCH] [Base] Android content URI file memory mapping --- src/xenia/base/mapped_memory.h | 24 ++++--- src/xenia/base/mapped_memory_posix.cc | 81 ++++++++++++++++------- src/xenia/base/mapped_memory_win.cc | 5 +- src/xenia/vfs/devices/disc_image_entry.cc | 2 +- 4 files changed, 73 insertions(+), 39 deletions(-) diff --git a/src/xenia/base/mapped_memory.h b/src/xenia/base/mapped_memory.h index 6a58ab4c4..ce89b651a 100644 --- a/src/xenia/base/mapped_memory.h +++ b/src/xenia/base/mapped_memory.h @@ -12,7 +12,9 @@ #include #include -#include +#include + +#include "xenia/base/platform.h" namespace xe { @@ -26,21 +28,25 @@ class MappedMemory { static std::unique_ptr Open(const std::filesystem::path& path, Mode mode, size_t offset = 0, size_t length = 0); +#if XE_PLATFORM_ANDROID + static std::unique_ptr OpenForAndroidContentUri( + const std::string_view uri, Mode mode, size_t offset = 0, + size_t length = 0); +#endif // XE_PLATFORM_ANDROID - MappedMemory(const std::filesystem::path& path, Mode mode) - : path_(path), mode_(mode), data_(nullptr), size_(0) {} - MappedMemory(const std::filesystem::path& path, Mode mode, void* data, - size_t size) - : path_(path), mode_(mode), data_(data), size_(size) {} + MappedMemory() : data_(nullptr), size_(0) {} + MappedMemory(void* data, size_t size) : data_(data), size_(size) {} MappedMemory(const MappedMemory& mapped_memory) = delete; MappedMemory& operator=(const MappedMemory& mapped_memory) = delete; MappedMemory(MappedMemory&& mapped_memory) = delete; MappedMemory& operator=(MappedMemory&& mapped_memory) = delete; virtual ~MappedMemory() = default; - std::unique_ptr Slice(Mode mode, size_t offset, size_t length) { + // The mapping is still backed by the object the slice was created from, a + // slice is not owning. + std::unique_ptr Slice(size_t offset, size_t length) { return std::unique_ptr( - new MappedMemory(path_, mode, data() + offset, length)); + new MappedMemory(data() + offset, length)); } uint8_t* data() const { return reinterpret_cast(data_); } @@ -54,8 +60,6 @@ class MappedMemory { virtual bool Remap(size_t offset, size_t length) { return false; } protected: - std::filesystem::path path_; - Mode mode_; void* data_; size_t size_; }; diff --git a/src/xenia/base/mapped_memory_posix.cc b/src/xenia/base/mapped_memory_posix.cc index 6f89ffe43..330ced53f 100644 --- a/src/xenia/base/mapped_memory_posix.cc +++ b/src/xenia/base/mapped_memory_posix.cc @@ -15,16 +15,15 @@ #include #include -#include "xenia/base/string.h" +#include "xenia/base/filesystem.h" +#include "xenia/base/platform.h" namespace xe { class PosixMappedMemory : public MappedMemory { public: - PosixMappedMemory(const std::filesystem::path& path, Mode mode, void* data, - size_t size, int file_descriptor) - : MappedMemory(path, mode, data, size), - file_descriptor_(file_descriptor) {} + PosixMappedMemory(void* data, size_t size, int file_descriptor) + : MappedMemory(data, size), file_descriptor_(file_descriptor) {} ~PosixMappedMemory() override { if (data_) { @@ -35,6 +34,39 @@ class PosixMappedMemory : public MappedMemory { } } + static std::unique_ptr WrapFileDescriptor( + int file_descriptor, Mode mode, size_t offset = 0, size_t length = 0) { + int protection = 0; + switch (mode) { + case Mode::kRead: + protection |= PROT_READ; + break; + case Mode::kReadWrite: + protection |= PROT_READ | PROT_WRITE; + break; + } + + size_t map_length = length; + if (!length) { + struct stat64 file_stat; + if (fstat64(file_descriptor, &file_stat)) { + close(file_descriptor); + return nullptr; + } + map_length = size_t(file_stat.st_size); + } + + void* data = + mmap(0, map_length, protection, MAP_SHARED, file_descriptor, offset); + if (!data) { + close(file_descriptor); + return nullptr; + } + + return std::make_unique(data, map_length, + file_descriptor); + } + void Close(uint64_t truncate_size) override { if (data_) { munmap(data_, size()); @@ -59,42 +91,43 @@ std::unique_ptr MappedMemory::Open( const std::filesystem::path& path, Mode mode, size_t offset, size_t length) { int open_flags = 0; - int prot; switch (mode) { case Mode::kRead: open_flags |= O_RDONLY; - prot = PROT_READ; break; case Mode::kReadWrite: open_flags |= O_RDWR; - prot = PROT_READ | PROT_WRITE; break; } - int file_descriptor = open(path.c_str(), open_flags); if (file_descriptor < 0) { return nullptr; } + return PosixMappedMemory::WrapFileDescriptor(file_descriptor, mode, offset, + length); +} - size_t map_length = length; - if (!length) { - struct stat64 file_stat; - if (fstat64(file_descriptor, &file_stat)) { - close(file_descriptor); - return nullptr; - } - map_length = size_t(file_stat.st_size); +#if XE_PLATFORM_ANDROID +std::unique_ptr MappedMemory::OpenForAndroidContentUri( + const std::string_view uri, Mode mode, size_t offset, size_t length) { + const char* open_mode = nullptr; + switch (mode) { + case Mode::kRead: + open_mode = "r"; + break; + case Mode::kReadWrite: + open_mode = "rw"; + break; } - - void* data = mmap(0, map_length, prot, MAP_SHARED, file_descriptor, offset); - if (!data) { - close(file_descriptor); + int file_descriptor = + xe::filesystem::OpenAndroidContentFileDescriptor(uri, open_mode); + if (file_descriptor < 0) { return nullptr; } - - return std::unique_ptr( - new PosixMappedMemory(path, mode, data, map_length, file_descriptor)); + return PosixMappedMemory::WrapFileDescriptor(file_descriptor, mode, offset, + length); } +#endif // XE_PLATFORM_ANDROID std::unique_ptr ChunkedMappedMemoryWriter::Open( const std::filesystem::path& path, size_t chunk_size, diff --git a/src/xenia/base/mapped_memory_win.cc b/src/xenia/base/mapped_memory_win.cc index 79e94eeaf..f0af5ee7b 100644 --- a/src/xenia/base/mapped_memory_win.cc +++ b/src/xenia/base/mapped_memory_win.cc @@ -32,9 +32,6 @@ class Win32MappedMemory : public MappedMemory { // CreateFileMapping returns nullptr in case of failure. static constexpr HANDLE kMappingHandleInvalid = nullptr; - Win32MappedMemory(const std::filesystem::path& path, Mode mode) - : MappedMemory(path, mode) {} - ~Win32MappedMemory() override { if (data_) { UnmapViewOfFile(data_); @@ -135,7 +132,7 @@ std::unique_ptr MappedMemory::Open( offset & ~static_cast(system_info.dwAllocationGranularity - 1); const size_t aligned_length = length + (offset - aligned_offset); - auto mm = std::make_unique(path, mode); + auto mm = std::make_unique(); mm->view_access_ = view_access; mm->file_handle = CreateFile(path.c_str(), file_access, file_share, nullptr, diff --git a/src/xenia/vfs/devices/disc_image_entry.cc b/src/xenia/vfs/devices/disc_image_entry.cc index e8450bd73..0d251dff5 100644 --- a/src/xenia/vfs/devices/disc_image_entry.cc +++ b/src/xenia/vfs/devices/disc_image_entry.cc @@ -48,7 +48,7 @@ std::unique_ptr DiscImageEntry::OpenMapped( size_t real_offset = data_offset_ + offset; size_t real_length = length ? std::min(length, data_size_) : data_size_; - return mmap_->Slice(mode, real_offset, real_length); + return mmap_->Slice(real_offset, real_length); } } // namespace vfs