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