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