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 #pragma once 15 16 #ifdef _WIN32 17 #ifdef _MSC_VER 18 #include <windows.h> 19 20 #include "aemu/base/msvc.h" 21 #else 22 #include <windows.h> 23 #endif // _MSC_VER 24 #endif // _WIN32 25 26 #include <sys/types.h> 27 28 #include <string> 29 #include <utility> 30 31 namespace android { 32 33 namespace base { 34 35 // SharedMemory - A class to share memory between 2 process. The region can 36 // be shared in 2 modes: 37 // 38 // - As shared memory (/dev/shm, memory page file in windows) 39 // - Using memory mapped files backed by a file on the file system. 40 // 41 // To use memory mapped files prefix the handle with "file://" followed 42 // by an absolute path. For example: file:///c:/WINDOWS/shared.mem or 43 // file:///tmp/shared.mem 44 // 45 // Usage examples: 46 // Proc1: The owner 47 // StringView message = "Hello world!"; 48 // SharedMemory writer("foo", 4096); 49 // writer.create(0600); 50 // memcpy(*writer, message.c_str(), message.size()); 51 // 52 // Proc2: The observer 53 // SharedMemory reader("foo", 4096); 54 // reader.open(SharedMemory::AccessMode::READ_ONLY); 55 // StringView read((const char*) *reader)); 56 // 57 // Using file backed ram: 58 // 59 // Proc1: The owner 60 // StringView message = "Hello world!"; 61 // SharedMemory writer("file:///abs/path/to/a/file", 4096); 62 // writer.create(0600); 63 // memcpy(*writer, message.c_str(), message.size()); 64 // 65 // Proc2: The observer 66 // SharedMemory reader("file::///abs/path/to/a/file", 4096); 67 // reader.open(SharedMemory::AccessMode::READ_ONLY); 68 // StringView read((const char*) *reader)); 69 // 70 // It is not possible to find out the size of an in memory shared region on 71 // Win32 (boo!), there are undocumented workaround (See: 72 // https://stackoverflow.com/questions/34860452/extracting-shared-memorys-size/47951175#47951175) 73 // that we are not using. 74 // 75 // For this reason the size has to be explicitly set in the 76 // constructor. As a workaround you could write the region size in the first 77 // few bytes of the region, or use a different channel to exchange region 78 // size. 79 // 80 // Shared memory behaves differently on Win32 vs Posix. You as a user must be 81 // very well aware of these differences, or run into unexpected results on 82 // different platforms: 83 // 84 // Posix (linux/macos): 85 // - There is a notion of an OWNER of a SharedMemory region. The one to call 86 // create will own the region. If this object goes out of scope the region 87 // will be unlinked, meaning that mappings (calls to open) will fail. As 88 // soon as all other references to the shared memory go away the handle will 89 // disappear from /dev/shm as well. 90 // - Multiple calls to create for the same region can cause undefined behavior 91 // due to closing and potential resizing of the shared memory. 92 // - Shared memory can outlive processes that are using it. So don't crash 93 // while a shared object is still alive. 94 // - Access control is observed by mode permissions 95 // Mac: 96 // - The name cannot exceed 30 chars. 97 // Win32: 98 // - Names are prefixed with SHM_ to prevent collision with other objects 99 // in windows; 100 // - There is no notion of an owner. The OS will release the region as 101 // soon as all references to a region disappear. 102 // - The first call to create will determine the size of the region. 103 // According to msdn regions cannot grow. Multiple calls to create 104 // have no effect, and behave like open. (Note, you can grow size according 105 // to https://blogs.msdn.microsoft.com/oldnewthing/20150130-00/?p=44793) 106 // - Win32 does not officially support determining the size of a shared 107 // region. 108 // - The access control lists (ACL) in the default security descriptor for 109 // a file mapping object come from the primary or impersonation token of 110 // the creator. 111 // 112 // If the shared memory region is backed by a file you must keep the following 113 // things in mind: 114 // 115 // Win32: 116 // - If an application specifies a size for the file mapping object that 117 // is larger than the size of the actual named file on disk and if the page 118 // protection allows write access (that is, the flProtect parameter specifies 119 // PAGE_READWRITE or PAGE_EXECUTE_READWRITE), then the file on disk is 120 // increased to match the specified size of the file mapping object. If the 121 // file is extended, the contents of the file between the old end of the file 122 // and the new end of the file are not guaranteed to be zero; the behavior is 123 // defined by the file system. If the file on disk cannot be increased, 124 // CreateFileMapping fails and GetLastError returns ERROR_DISK_FULL. 125 // In practice this means that the shared memory region will not contain 126 // useful data upon creation. 127 // - A sharing object will be created for each view on the file. 128 // - The memory mapped file will be deleted by the owner upond destruction. 129 // this is however not guaranteed! 130 // Posix: 131 // - The notion of ownership is handled at the filesystem level. Usually this 132 // means that a memory mapped file will be deleted once all references have 133 // been removed. 134 // - The memory mapped file will be deleted by the owner upond destruction. 135 // this is however not guaranteed! 136 class SharedMemory { 137 public: 138 #ifdef _WIN32 139 using memory_type = void*; 140 using handle_type = HANDLE; invalidHandle()141 constexpr static handle_type invalidHandle() { 142 // This is the invalid return value for 143 // CreateFileMappingW; INVALID_HANDLE_VALUE 144 // could mean the paging file on Windows. 145 return NULL; 146 } unmappedMemory()147 constexpr static memory_type unmappedMemory() { return nullptr; } 148 #else 149 using memory_type = void*; 150 using handle_type = int; 151 constexpr static handle_type invalidHandle() { return -1; } 152 static memory_type unmappedMemory() { 153 return reinterpret_cast<memory_type>(-1); 154 } 155 #endif 156 enum class AccessMode { READ_ONLY, READ_WRITE }; 157 enum class ShareType { SHARED_MEMORY, FILE_BACKED }; 158 159 // Creates a SharedMemory region either backed by a shared memory handle 160 // or by a file. If the string uriOrHandle starts with `file://` it will be 161 // file backed otherwise it will be a named shared memory region. 162 // |uriHandle| A file:// uri or handle 163 // |size| Size of the desired shared memory region. Cannot change after 164 // creation. 165 SharedMemory(const std::string& uriOrHandle, size_t size); ~SharedMemory()166 ~SharedMemory() { close(); } 167 SharedMemory(SharedMemory && other)168 SharedMemory(SharedMemory&& other) { 169 mName = std::move(other.mName); 170 mSize = other.mSize; 171 mAddr = other.mAddr; 172 mFd = other.mFd; 173 mCreate = other.mCreate; 174 mShareType = other.mShareType; 175 other.clear(); 176 } 177 178 SharedMemory& operator=(SharedMemory&& other) { 179 mName = std::move(other.mName); 180 mSize = other.mSize; 181 mAddr = other.mAddr; 182 mShareType = other.mShareType; 183 mFd = other.mFd; 184 mCreate = other.mCreate; 185 186 other.clear(); 187 return *this; 188 } 189 190 // Let's not have any weirdness due to double unlinks due to destructors. 191 SharedMemory(const SharedMemory&) = delete; 192 SharedMemory& operator=(const SharedMemory&) = delete; 193 194 // Creates a shared region, you will be considered the owner, and will have 195 // write access. Returns 0 on success, or an negative error code otheriwse. 196 // The error code (errno) is platform dependent. 197 int create(mode_t mode); 198 // Creates a shared object in the same manner as create(), except for 199 // performing actual mapping. 200 int createNoMapping(mode_t mode); 201 202 // Opens the shared memory object, returns 0 on success 203 // or the negative error code. 204 // The shared memory object will be mapped. 205 int open(AccessMode access); 206 207 bool isOpen() const; 208 void close(bool forceDestroy = false); 209 size()210 size_t size() const { return mSize; } name()211 std::string name() const { return mName; } get()212 memory_type get() const { return mAddr; } 213 memory_type operator*() const { return get(); } type()214 ShareType type() const { return mShareType; } getFd()215 handle_type getFd() { return mFd; } releaseHandle()216 handle_type releaseHandle() { 217 if (mShareType == ShareType::FILE_BACKED) { 218 return invalidHandle(); 219 } 220 221 return std::exchange(mFd, invalidHandle()); 222 } isMapped()223 bool isMapped() const { return mAddr != unmappedMemory(); } 224 225 private: 226 #ifdef _WIN32 227 int openInternal(AccessMode access, bool doMapping = true); 228 #else 229 int openInternal(int oflag, int mode, bool doMapping = true); 230 #endif 231 clear()232 void clear() { 233 mSize = 0; 234 mName = ""; 235 mCreate = false; 236 mFd = invalidHandle(); 237 mAddr = unmappedMemory(); 238 } 239 240 memory_type mAddr = unmappedMemory(); 241 handle_type mFd = invalidHandle(); 242 handle_type mFile = invalidHandle(); 243 bool mCreate = false; 244 245 std::string mName; 246 size_t mSize; 247 ShareType mShareType; 248 }; 249 } // namespace base 250 } // namespace android 251