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 "base/EintrWrapper.h"
20 #include "base/SharedMemory.h"
21 #include "base/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 shm_unlink(mName.c_str());
75 }
76 }
77 }
78
isOpen() const79 bool SharedMemory::isOpen() const {
80 return mFd != invalidHandle();
81 }
82
openInternal(int oflag,int mode,bool doMapping)83 int SharedMemory::openInternal(int oflag, int mode, bool doMapping) {
84 if (isOpen()) {
85 return EEXIST;
86 }
87
88 int err = 0;
89 struct stat sb;
90 if (mShareType == ShareType::SHARED_MEMORY) {
91 mFd = shm_open(mName.c_str(), oflag, mode);
92 } else {
93 mFd = ::open(mName.c_str(), oflag, mode);
94 // Make sure the file can hold at least mSize bytes..
95 struct stat stat;
96 if (!fstat(mFd, &stat) && stat.st_size < mSize) {
97 ftruncate(mFd, mSize);
98 }
99 }
100 if (mFd == -1) {
101 err = -errno;
102 close();
103 return err;
104 }
105
106 if (oflag & O_CREAT) {
107 if (HANDLE_EINTR(fstat(mFd, &sb)) == -1) {
108 err = -errno;
109 close();
110 return err;
111 }
112
113 // Only increase size, as we don't want to yank away memory
114 // from another process.
115 if (mSize > sb.st_size && HANDLE_EINTR(ftruncate(mFd, mSize)) == -1) {
116 err = -errno;
117 close();
118 return err;
119 }
120 }
121
122 if (doMapping) {
123 int mapFlags = PROT_READ;
124 if (oflag & O_RDWR || oflag & O_CREAT) {
125 mapFlags |= PROT_WRITE;
126 }
127
128 mAddr = mmap(nullptr, mSize, mapFlags, MAP_SHARED, mFd, 0);
129 if (mAddr == unmappedMemory()) {
130 err = -errno;
131 close();
132 return err;
133 }
134 }
135
136 mCreate |= (oflag & O_CREAT);
137 assert(isOpen());
138 return 0;
139 }
140 } // namespace base
141 } // namespace android
142