/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This source code was derived from Chromium code, and as such is also subject
* to the [Chromium license](ipc/chromium/src/LICENSE). */
#include "SharedMemoryPlatform.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <android/sharedmem.h>
#ifdef MOZ_VALGRIND
# include <valgrind/valgrind.h>
#endif
#include "mozilla/Maybe.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/UniquePtrExtensions.h"
#include "prenv.h"
namespace mozilla::ipc::shared_memory {
// Right now we do nothing different for freezable shared memory on Android.
static Maybe<PlatformHandle> CreateImpl(size_t aSize,
bool aFreezable) {
MOZ_ASSERT(aSize >
0);
int fd = ASharedMemory_create(nullptr, aSize);
if (fd <
0) {
MOZ_LOG_FMT(gSharedMemoryLog, LogLevel::Warning,
"failed to open shm: {}",
strerror(errno));
return Nothing();
}
return Some(fd);
}
bool AppendPosixShmPrefix(std::string* str, pid_t pid) {
return false; }
bool UsingPosixShm() {
return false; }
bool Platform::Create(MutableHandle& aHandle, size_t aSize) {
if (
auto ph = CreateImpl(aSize,
false)) {
aHandle.mHandle = std::move(*ph);
aHandle.SetSize(aSize);
return true;
}
return false;
}
bool Platform::CreateFreezable(FreezableHandle& aHandle, size_t aSize) {
if (
auto ph = CreateImpl(aSize, true)) {
aHandle.mHandle = std::move(*ph);
aHandle.SetSize(aSize);
return true;
}
return false;
}
PlatformHandle Platform::CloneHandle(
const PlatformHandle& aHandle) {
auto rv = DuplicateFileHandle(aHandle);
if (!rv) {
MOZ_LOG_FMT(gSharedMemoryLog, LogLevel::Warning,
"failed to duplicate file descriptor: {}", strerror(errno));
}
return rv;
}
bool Platform::Freeze(FreezableHandle& aHandle) {
if (ASharedMemory_setProt(aHandle.mHandle.get(), PROT_READ) !=
0) {
MOZ_LOG_FMT(gSharedMemoryLog, LogLevel::Warning,
"failed to set sharedmem read-only: {}", strerror(errno));
return false;
}
return true;
}
Maybe<
void*> Platform::Map(
const HandleBase& aHandle, uint64_t aOffset,
size_t aSize,
void* aFixedAddress,
bool aReadOnly) {
// Don't use MAP_FIXED when a fixed_address was specified, since that can
// replace pages that are alread mapped at that address.
void* mem =
mmap(aFixedAddress, aSize, PROT_READ | (aReadOnly ?
0 : PROT_WRITE),
MAP_SHARED, aHandle.mHandle.get(), aOffset);
if (mem == MAP_FAILED) {
MOZ_LOG_FMT(gSharedMemoryLog, LogLevel::Warning,
"call to mmap failed: {}",
strerror(errno));
return Nothing();
}
if (aFixedAddress && mem != aFixedAddress) {
DebugOnly<
bool> munmap_succeeded = munmap(mem, aSize) ==
0;
MOZ_ASSERT(munmap_succeeded,
"call to munmap failed");
return Nothing();
}
return Some(mem);
}
void Platform::Unmap(
void* aMemory, size_t aSize) { munmap(aMemory, aSize); }
bool Platform::Protect(
char* aAddr, size_t aSize, Access aAccess) {
int flags = PROT_NONE;
if (aAccess & AccessRead) flags |= PROT_READ;
if (aAccess & AccessWrite) flags |= PROT_WRITE;
return 0 == mprotect(aAddr, aSize, flags);
}
void* Platform::FindFreeAddressSpace(size_t aSize) {
void* memory = mmap(nullptr, aSize, PROT_NONE,
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -
1,
0);
if (memory == MAP_FAILED) {
return nullptr;
}
munmap(memory, aSize);
return memory;
}
size_t Platform::PageSize() {
return sysconf(_SC_PAGESIZE); }
size_t Platform::AllocationGranularity() {
return PageSize(); }
bool Platform::IsSafeToMap(
const PlatformHandle&) {
return true; }
}
// namespace mozilla::ipc::shared_memory