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 <errno.h>
15 #include <fcntl.h>
16 #include <sys/mman.h>
17 #include <sys/stat.h>
18
19 #include "aemu/base/EintrWrapper.h"
20 #include "aemu/base/memory/SharedMemory.h"
21 #include "aemu/base/files/PathUtils.h"
22 #ifndef _MSC_VER
23 #include <unistd.h>
24 #endif
25
26 namespace android {
27 namespace base {
28
SharedMemory(const std::string & name,size_t size)29 SharedMemory::SharedMemory(const std::string& name, size_t size) : mSize(size) {
30 const std::string& kFileUri = "file://";
31 if (name.find(kFileUri, 0) == 0) {
32 mShareType = ShareType::FILE_BACKED;
33 auto path = name.substr(kFileUri.size());
34 mName = PathUtils::recompose(PathUtils::decompose(std::move(path)));
35 } else {
36 mShareType = ShareType::SHARED_MEMORY;
37 mName = name;
38 }
39 }
40
create(mode_t mode)41 int SharedMemory::create(mode_t mode) {
42 return openInternal(O_CREAT | O_RDWR, mode);
43 }
44
createNoMapping(mode_t mode)45 int SharedMemory::createNoMapping(mode_t mode) {
46 return openInternal(O_CREAT | O_RDWR, mode, false /* no mapping */);
47 }
48
open(AccessMode access)49 int SharedMemory::open(AccessMode access) {
50 int oflag = O_RDONLY;
51 int mode = 0400;
52 if (access == AccessMode::READ_WRITE) {
53 oflag = O_RDWR;
54 mode = 0600;
55 }
56 return openInternal(oflag, mode);
57 }
58
close(bool forceDestroy)59 void SharedMemory::close(bool forceDestroy) {
60 if (mAddr != unmappedMemory()) {
61 munmap(mAddr, mSize);
62 mAddr = unmappedMemory();
63 }
64 if (mFd) {
65 ::close(mFd);
66 mFd = invalidHandle();
67 }
68
69 assert(!isOpen());
70 if (forceDestroy || mCreate) {
71 if (mShareType == ShareType::FILE_BACKED) {
72 remove(mName.c_str());
73 } else {
74 #if !defined(__BIONIC__)
75 shm_unlink(mName.c_str());
76 #endif
77 }
78 }
79 }
80
isOpen() const81 bool SharedMemory::isOpen() const {
82 return mFd != invalidHandle();
83 }
84
openInternal(int oflag,int mode,bool doMapping)85 int SharedMemory::openInternal(int oflag, int mode, bool doMapping) {
86 if (isOpen()) {
87 return EEXIST;
88 }
89
90 int err = 0;
91 struct stat sb;
92 if (mShareType == ShareType::SHARED_MEMORY) {
93 #if !defined(__BIONIC__)
94 mFd = shm_open(mName.c_str(), oflag, mode);
95 #else
96 return ENOTTY;
97 #endif
98 } else {
99 mFd = ::open(mName.c_str(), oflag, mode);
100 // Make sure the file can hold at least mSize bytes..
101 struct stat stat;
102 if (!fstat(mFd, &stat) && stat.st_size < mSize) {
103 err = ftruncate(mFd, mSize);
104 }
105 }
106 if (mFd == -1 || err) {
107 err = -errno;
108 close();
109 return err;
110 }
111
112 if (oflag & O_CREAT) {
113 if (HANDLE_EINTR(fstat(mFd, &sb)) == -1) {
114 err = -errno;
115 close();
116 return err;
117 }
118
119 // Only increase size, as we don't want to yank away memory
120 // from another process.
121 if (mSize > sb.st_size && HANDLE_EINTR(ftruncate(mFd, mSize)) == -1) {
122 err = -errno;
123 close();
124 return err;
125 }
126 }
127
128 if (doMapping) {
129 int mapFlags = PROT_READ;
130 if (oflag & O_RDWR || oflag & O_CREAT) {
131 mapFlags |= PROT_WRITE;
132 }
133
134 mAddr = mmap(nullptr, mSize, mapFlags, MAP_SHARED, mFd, 0);
135 if (mAddr == unmappedMemory()) {
136 err = -errno;
137 close();
138 return err;
139 }
140 }
141
142 mCreate |= (oflag & O_CREAT);
143 assert(isOpen());
144 return 0;
145 }
146 } // namespace base
147 } // namespace android
148