You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
4.8 KiB
160 lines
4.8 KiB
// 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 <shlwapi.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) {
|
|
// Convert URI to path using win32 api.
|
|
const Win32UnicodeString srcUri(name);
|
|
WCHAR path[MAX_PATH];
|
|
DWORD cPath = MAX_PATH;
|
|
auto HR = PathCreateFromUrlW(srcUri.c_str(), path, &cPath, NULL);
|
|
assert(HR == S_OK);
|
|
const Win32UnicodeString destPath(path);
|
|
mName = PathUtils::recompose(PathUtils::decompose(destPath.toString()));
|
|
mShareType = ShareType::FILE_BACKED;
|
|
} 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
|