[Base] Android content URI file memory mapping

This commit is contained in:
Triang3l 2022-07-17 16:34:17 +03:00
parent 93a7918025
commit 624f2b2d9e
4 changed files with 73 additions and 39 deletions

View File

@ -12,7 +12,9 @@
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
#include <string> #include <string_view>
#include "xenia/base/platform.h"
namespace xe { namespace xe {
@ -26,21 +28,25 @@ class MappedMemory {
static std::unique_ptr<MappedMemory> Open(const std::filesystem::path& path, static std::unique_ptr<MappedMemory> Open(const std::filesystem::path& path,
Mode mode, size_t offset = 0, Mode mode, size_t offset = 0,
size_t length = 0); size_t length = 0);
#if XE_PLATFORM_ANDROID
static std::unique_ptr<MappedMemory> 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) MappedMemory() : data_(nullptr), size_(0) {}
: path_(path), mode_(mode), data_(nullptr), size_(0) {} MappedMemory(void* data, size_t size) : data_(data), size_(size) {}
MappedMemory(const std::filesystem::path& path, Mode mode, void* data,
size_t size)
: path_(path), mode_(mode), data_(data), size_(size) {}
MappedMemory(const MappedMemory& mapped_memory) = delete; MappedMemory(const MappedMemory& mapped_memory) = delete;
MappedMemory& operator=(const MappedMemory& mapped_memory) = delete; MappedMemory& operator=(const MappedMemory& mapped_memory) = delete;
MappedMemory(MappedMemory&& mapped_memory) = delete; MappedMemory(MappedMemory&& mapped_memory) = delete;
MappedMemory& operator=(MappedMemory&& mapped_memory) = delete; MappedMemory& operator=(MappedMemory&& mapped_memory) = delete;
virtual ~MappedMemory() = default; virtual ~MappedMemory() = default;
std::unique_ptr<MappedMemory> 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<MappedMemory> Slice(size_t offset, size_t length) {
return std::unique_ptr<MappedMemory>( return std::unique_ptr<MappedMemory>(
new MappedMemory(path_, mode, data() + offset, length)); new MappedMemory(data() + offset, length));
} }
uint8_t* data() const { return reinterpret_cast<uint8_t*>(data_); } uint8_t* data() const { return reinterpret_cast<uint8_t*>(data_); }
@ -54,8 +60,6 @@ class MappedMemory {
virtual bool Remap(size_t offset, size_t length) { return false; } virtual bool Remap(size_t offset, size_t length) { return false; }
protected: protected:
std::filesystem::path path_;
Mode mode_;
void* data_; void* data_;
size_t size_; size_t size_;
}; };

View File

@ -15,16 +15,15 @@
#include <unistd.h> #include <unistd.h>
#include <memory> #include <memory>
#include "xenia/base/string.h" #include "xenia/base/filesystem.h"
#include "xenia/base/platform.h"
namespace xe { namespace xe {
class PosixMappedMemory : public MappedMemory { class PosixMappedMemory : public MappedMemory {
public: public:
PosixMappedMemory(const std::filesystem::path& path, Mode mode, void* data, PosixMappedMemory(void* data, size_t size, int file_descriptor)
size_t size, int file_descriptor) : MappedMemory(data, size), file_descriptor_(file_descriptor) {}
: MappedMemory(path, mode, data, size),
file_descriptor_(file_descriptor) {}
~PosixMappedMemory() override { ~PosixMappedMemory() override {
if (data_) { if (data_) {
@ -35,6 +34,39 @@ class PosixMappedMemory : public MappedMemory {
} }
} }
static std::unique_ptr<PosixMappedMemory> 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<PosixMappedMemory>(data, map_length,
file_descriptor);
}
void Close(uint64_t truncate_size) override { void Close(uint64_t truncate_size) override {
if (data_) { if (data_) {
munmap(data_, size()); munmap(data_, size());
@ -59,42 +91,43 @@ std::unique_ptr<MappedMemory> MappedMemory::Open(
const std::filesystem::path& path, Mode mode, size_t offset, const std::filesystem::path& path, Mode mode, size_t offset,
size_t length) { size_t length) {
int open_flags = 0; int open_flags = 0;
int prot;
switch (mode) { switch (mode) {
case Mode::kRead: case Mode::kRead:
open_flags |= O_RDONLY; open_flags |= O_RDONLY;
prot = PROT_READ;
break; break;
case Mode::kReadWrite: case Mode::kReadWrite:
open_flags |= O_RDWR; open_flags |= O_RDWR;
prot = PROT_READ | PROT_WRITE;
break; break;
} }
int file_descriptor = open(path.c_str(), open_flags); int file_descriptor = open(path.c_str(), open_flags);
if (file_descriptor < 0) { if (file_descriptor < 0) {
return nullptr; return nullptr;
} }
return PosixMappedMemory::WrapFileDescriptor(file_descriptor, mode, offset,
length);
}
size_t map_length = length; #if XE_PLATFORM_ANDROID
if (!length) { std::unique_ptr<MappedMemory> MappedMemory::OpenForAndroidContentUri(
struct stat64 file_stat; const std::string_view uri, Mode mode, size_t offset, size_t length) {
if (fstat64(file_descriptor, &file_stat)) { const char* open_mode = nullptr;
close(file_descriptor); switch (mode) {
return nullptr; case Mode::kRead:
} open_mode = "r";
map_length = size_t(file_stat.st_size); break;
case Mode::kReadWrite:
open_mode = "rw";
break;
} }
int file_descriptor =
void* data = mmap(0, map_length, prot, MAP_SHARED, file_descriptor, offset); xe::filesystem::OpenAndroidContentFileDescriptor(uri, open_mode);
if (!data) { if (file_descriptor < 0) {
close(file_descriptor);
return nullptr; return nullptr;
} }
return PosixMappedMemory::WrapFileDescriptor(file_descriptor, mode, offset,
return std::unique_ptr<MappedMemory>( length);
new PosixMappedMemory(path, mode, data, map_length, file_descriptor));
} }
#endif // XE_PLATFORM_ANDROID
std::unique_ptr<ChunkedMappedMemoryWriter> ChunkedMappedMemoryWriter::Open( std::unique_ptr<ChunkedMappedMemoryWriter> ChunkedMappedMemoryWriter::Open(
const std::filesystem::path& path, size_t chunk_size, const std::filesystem::path& path, size_t chunk_size,

View File

@ -32,9 +32,6 @@ class Win32MappedMemory : public MappedMemory {
// CreateFileMapping returns nullptr in case of failure. // CreateFileMapping returns nullptr in case of failure.
static constexpr HANDLE kMappingHandleInvalid = nullptr; static constexpr HANDLE kMappingHandleInvalid = nullptr;
Win32MappedMemory(const std::filesystem::path& path, Mode mode)
: MappedMemory(path, mode) {}
~Win32MappedMemory() override { ~Win32MappedMemory() override {
if (data_) { if (data_) {
UnmapViewOfFile(data_); UnmapViewOfFile(data_);
@ -135,7 +132,7 @@ std::unique_ptr<MappedMemory> MappedMemory::Open(
offset & ~static_cast<size_t>(system_info.dwAllocationGranularity - 1); offset & ~static_cast<size_t>(system_info.dwAllocationGranularity - 1);
const size_t aligned_length = length + (offset - aligned_offset); const size_t aligned_length = length + (offset - aligned_offset);
auto mm = std::make_unique<Win32MappedMemory>(path, mode); auto mm = std::make_unique<Win32MappedMemory>();
mm->view_access_ = view_access; mm->view_access_ = view_access;
mm->file_handle = CreateFile(path.c_str(), file_access, file_share, nullptr, mm->file_handle = CreateFile(path.c_str(), file_access, file_share, nullptr,

View File

@ -48,7 +48,7 @@ std::unique_ptr<MappedMemory> DiscImageEntry::OpenMapped(
size_t real_offset = data_offset_ + offset; size_t real_offset = data_offset_ + offset;
size_t real_length = length ? std::min(length, data_size_) : data_size_; 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 } // namespace vfs