1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "aemu/base/memory/SharedMemory.h"
15
16 #include <shlwapi.h>
17 #include <cassert>
18 #include <string>
19
20 #include "aemu/base/files/PathUtils.h"
21 #include "aemu/base/system/Win32UnicodeString.h"
22
23 namespace android {
24 namespace base {
25
SharedMemory(const std::string & name,size_t size)26 SharedMemory::SharedMemory(const std::string& name, size_t size) : mSize(size) {
27 const std::string kFileUri = "file://";
28 if (name.find(kFileUri, 0) == 0) {
29 // Convert URI to path using win32 api.
30 const Win32UnicodeString srcUri(name);
31 WCHAR path[MAX_PATH];
32 DWORD cPath = MAX_PATH;
33 auto HR = PathCreateFromUrlW(srcUri.c_str(), path, &cPath, NULL);
34 assert(HR == S_OK);
35 const Win32UnicodeString destPath(path);
36 mName = PathUtils::recompose(PathUtils::decompose(destPath.toString()));
37 mShareType = ShareType::FILE_BACKED;
38 } else {
39 mShareType = ShareType::SHARED_MEMORY;
40 mName = "SHM_" + name;
41 }
42 }
43
44 // Creates a shared region, you will be considered the owner, and will have
45 // write access. Returns 0 on success, or an error code otheriwse.
create(mode_t mode)46 int SharedMemory::create(mode_t mode) {
47 return openInternal(AccessMode::READ_WRITE);
48 }
49
createNoMapping(mode_t mode)50 int SharedMemory::createNoMapping(mode_t mode) {
51 return openInternal(AccessMode::READ_WRITE, false /* no mapping */);
52 }
53
54 // Opens the shared memory object, returns 0 on success
55 // or the error code.
open(AccessMode access)56 int SharedMemory::open(AccessMode access) {
57 return openInternal(access);
58 }
59
openInternal(AccessMode access,bool doMapping)60 int SharedMemory::openInternal(AccessMode access, bool doMapping) {
61 if (mCreate) {
62 return EEXIST;
63 }
64 LARGE_INTEGER memory;
65 memory.QuadPart = (LONGLONG)mSize;
66
67 // Allows views to be mapped for read-only or copy-on-write access.
68 DWORD protection = PAGE_READONLY;
69
70 if (access == AccessMode::READ_WRITE) {
71 // Allows views to be mapped for read-only, copy-on-write, or read/write
72 // access.
73 protection = PAGE_READWRITE;
74 }
75 const Win32UnicodeString name(mName);
76 auto objectName = name.c_str();
77
78 if (mShareType == ShareType::FILE_BACKED) {
79 auto fileOptions = GENERIC_READ;
80 // File sharing permissions must be the same for readers/writers.
81 // otherwise readers will not be able to open the file.
82 auto fileShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
83 auto openMode = OPEN_EXISTING;
84 if (access == AccessMode::READ_WRITE) {
85 fileOptions = GENERIC_READ | GENERIC_WRITE;
86 openMode = OPEN_ALWAYS;
87 }
88 mFile = CreateFileW(objectName, fileOptions, fileShare, NULL, openMode,
89 FILE_FLAG_RANDOM_ACCESS, NULL);
90 if (mFile == INVALID_HANDLE_VALUE) {
91 int err = -GetLastError();
92 close();
93 return err;
94 }
95 objectName = nullptr;
96 }
97
98 HANDLE hMapFile = CreateFileMappingW(
99 mFile,
100 NULL, // default security
101 protection, // read/write access
102 memory.HighPart, // maximum object size (high-order DWORD)
103 memory.LowPart, // maximum object size (low-order DWORD)
104 objectName); // name of mapping object
105
106 if (hMapFile == NULL) {
107 int err = -GetLastError();
108 close();
109 return err;
110 }
111
112 if (doMapping) {
113 // MapViewOfFile has a slightly different way of naming protection.
114 protection = FILE_MAP_READ;
115 if (access == AccessMode::READ_WRITE) {
116 protection = FILE_MAP_WRITE;
117 }
118
119 mAddr = MapViewOfFile(hMapFile, protection, 0, 0, mSize);
120
121 if (mAddr == NULL) {
122 int err = -GetLastError();
123 close();
124 return err;
125 }
126 }
127
128 mFd = hMapFile;
129 mCreate = true;
130 return 0;
131 }
132
close(bool forceDestroy)133 void SharedMemory::close(bool forceDestroy) {
134 if (mAddr != unmappedMemory()) {
135 UnmapViewOfFile(mAddr);
136 mAddr = unmappedMemory();
137 }
138 if (mFd) {
139 CloseHandle(mFd);
140 mFd = invalidHandle();
141 }
142 if (mFile) {
143 CloseHandle(mFile);
144 mFile = invalidHandle();
145 if ((forceDestroy || mCreate) && mShareType == ShareType::FILE_BACKED) {
146 const Win32UnicodeString name(mName);
147 DeleteFileW(name.c_str());
148 }
149 }
150
151 assert(!isOpen());
152 }
153
isOpen() const154 bool SharedMemory::isOpen() const {
155 return mFd != invalidHandle();
156 }
157
158 } // namespace base
159 } // namespace android
160