blob: 6b253f106856b9767869341b7ca7b27758c1e35c [file] [log] [blame]
// Copyright 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "base/SharedMemory.h"
#include <cassert>
#include <string>
#include "base/PathUtils.h"
#include "base/Win32UnicodeString.h"
namespace android {
namespace base {
SharedMemory::SharedMemory(const std::string& name, size_t size) : mSize(size) {
const std::string kFileUri = "file://";
if (name.find(kFileUri, 0) == 0) {
mShareType = ShareType::FILE_BACKED;
auto path = name.substr(kFileUri.size());
mName = PathUtils::recompose(PathUtils::decompose(path));
} else {
mShareType = ShareType::SHARED_MEMORY;
mName = "SHM_" + name;
}
}
// Creates a shared region, you will be considered the owner, and will have
// write access. Returns 0 on success, or an error code otheriwse.
int SharedMemory::create(mode_t mode) {
return openInternal(AccessMode::READ_WRITE);
}
int SharedMemory::createNoMapping(mode_t mode) {
return openInternal(AccessMode::READ_WRITE, false /* no mapping */);
}
// Opens the shared memory object, returns 0 on success
// or the error code.
int SharedMemory::open(AccessMode access) {
return openInternal(access);
}
int SharedMemory::openInternal(AccessMode access, bool doMapping) {
if (mCreate) {
return EEXIST;
}
LARGE_INTEGER memory;
memory.QuadPart = (LONGLONG)mSize;
// Allows views to be mapped for read-only or copy-on-write access.
DWORD protection = PAGE_READONLY;
if (access == AccessMode::READ_WRITE) {
// Allows views to be mapped for read-only, copy-on-write, or read/write
// access.
protection = PAGE_READWRITE;
}
const Win32UnicodeString name(mName);
auto objectName = name.c_str();
if (mShareType == ShareType::FILE_BACKED) {
auto fileOptions = GENERIC_READ;
// File sharing permissions must be the same for readers/writers.
// otherwise readers will not be able to open the file.
auto fileShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
auto openMode = OPEN_EXISTING;
if (access == AccessMode::READ_WRITE) {
fileOptions = GENERIC_READ | GENERIC_WRITE;
openMode = OPEN_ALWAYS;
}
mFile = CreateFileW(objectName, fileOptions, fileShare, NULL, openMode,
FILE_FLAG_RANDOM_ACCESS, NULL);
if (mFile == INVALID_HANDLE_VALUE) {
int err = -GetLastError();
close();
return err;
}
objectName = nullptr;
}
HANDLE hMapFile = CreateFileMappingW(
mFile,
NULL, // default security
protection, // read/write access
memory.HighPart, // maximum object size (high-order DWORD)
memory.LowPart, // maximum object size (low-order DWORD)
objectName); // name of mapping object
if (hMapFile == NULL) {
int err = -GetLastError();
close();
return err;
}
if (doMapping) {
// MapViewOfFile has a slightly different way of naming protection.
protection = FILE_MAP_READ;
if (access == AccessMode::READ_WRITE) {
protection = FILE_MAP_WRITE;
}
mAddr = MapViewOfFile(hMapFile, protection, 0, 0, mSize);
if (mAddr == NULL) {
int err = -GetLastError();
close();
return err;
}
}
mFd = hMapFile;
mCreate = true;
return 0;
}
void SharedMemory::close(bool forceDestroy) {
if (mAddr != unmappedMemory()) {
UnmapViewOfFile(mAddr);
mAddr = unmappedMemory();
}
if (mFd) {
CloseHandle(mFd);
mFd = invalidHandle();
}
if (mFile) {
CloseHandle(mFile);
mFile = invalidHandle();
if ((forceDestroy || mCreate) && mShareType == ShareType::FILE_BACKED) {
const Win32UnicodeString name(mName);
DeleteFileW(name.c_str());
}
}
assert(!isOpen());
}
bool SharedMemory::isOpen() const {
return mFd != invalidHandle();
}
} // namespace base
} // namespace android