• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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