• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //
18 // Shared file mapping class.
19 //
20 
21 #define LOG_TAG "filemap"
22 
23 #include <utils/FileMap.h>
24 #include <utils/Log.h>
25 
26 #if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO)
27 # define PRId32 "I32d"
28 # define PRIx32 "I32x"
29 # define PRId64 "I64d"
30 #else
31 #include <inttypes.h>
32 #endif
33 #include <stdio.h>
34 #include <stdlib.h>
35 
36 #if !defined(__MINGW32__)
37 #include <sys/mman.h>
38 #endif
39 
40 #include <string.h>
41 #include <memory.h>
42 #include <errno.h>
43 #include <assert.h>
44 
45 using namespace android;
46 
47 /*static*/ long FileMap::mPageSize = -1;
48 
49 // Constructor.  Create an empty object.
FileMap(void)50 FileMap::FileMap(void)
51     : mFileName(nullptr),
52       mBasePtr(nullptr),
53       mBaseLength(0),
54       mDataPtr(nullptr),
55       mDataLength(0)
56 #if defined(__MINGW32__)
57       ,
58       mFileHandle(INVALID_HANDLE_VALUE),
59       mFileMapping(NULL)
60 #endif
61 {
62 }
63 
64 // Move Constructor.
FileMap(FileMap && other)65 FileMap::FileMap(FileMap&& other) noexcept
66     : mFileName(other.mFileName),
67       mBasePtr(other.mBasePtr),
68       mBaseLength(other.mBaseLength),
69       mDataOffset(other.mDataOffset),
70       mDataPtr(other.mDataPtr),
71       mDataLength(other.mDataLength)
72 #if defined(__MINGW32__)
73       ,
74       mFileHandle(other.mFileHandle),
75       mFileMapping(other.mFileMapping)
76 #endif
77 {
78     other.mFileName = nullptr;
79     other.mBasePtr = nullptr;
80     other.mDataPtr = nullptr;
81 #if defined(__MINGW32__)
82     other.mFileHandle = INVALID_HANDLE_VALUE;
83     other.mFileMapping = NULL;
84 #endif
85 }
86 
87 // Move assign operator.
operator =(FileMap && other)88 FileMap& FileMap::operator=(FileMap&& other) noexcept {
89     mFileName = other.mFileName;
90     mBasePtr = other.mBasePtr;
91     mBaseLength = other.mBaseLength;
92     mDataOffset = other.mDataOffset;
93     mDataPtr = other.mDataPtr;
94     mDataLength = other.mDataLength;
95     other.mFileName = nullptr;
96     other.mBasePtr = nullptr;
97     other.mDataPtr = nullptr;
98 #if defined(__MINGW32__)
99     mFileHandle = other.mFileHandle;
100     mFileMapping = other.mFileMapping;
101     other.mFileHandle = INVALID_HANDLE_VALUE;
102     other.mFileMapping = NULL;
103 #endif
104     return *this;
105 }
106 
107 // Destructor.
~FileMap(void)108 FileMap::~FileMap(void)
109 {
110     if (mFileName != nullptr) {
111         free(mFileName);
112     }
113 #if defined(__MINGW32__)
114     if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
115         ALOGD("UnmapViewOfFile(%p) failed, error = %lu\n", mBasePtr,
116               GetLastError() );
117     }
118     if (mFileMapping != NULL) {
119         CloseHandle(mFileMapping);
120     }
121 #else
122     if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
123         ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength);
124     }
125 #endif
126 }
127 
128 
129 // Create a new mapping on an open file.
130 //
131 // Closing the file descriptor does not unmap the pages, so we don't
132 // claim ownership of the fd.
133 //
134 // Returns "false" on failure.
create(const char * origFileName,int fd,off64_t offset,size_t length,bool readOnly)135 bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
136         bool readOnly)
137 {
138 #if defined(__MINGW32__)
139     int     adjust;
140     off64_t adjOffset;
141     size_t  adjLength;
142 
143     if (mPageSize == -1) {
144         SYSTEM_INFO  si;
145 
146         GetSystemInfo( &si );
147         mPageSize = si.dwAllocationGranularity;
148     }
149 
150     DWORD  protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
151 
152     mFileHandle  = (HANDLE) _get_osfhandle(fd);
153     mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
154     if (mFileMapping == NULL) {
155         ALOGE("CreateFileMapping(%p, %lx) failed with error %lu\n",
156               mFileHandle, protect, GetLastError() );
157         return false;
158     }
159 
160     adjust    = offset % mPageSize;
161     adjOffset = offset - adjust;
162     adjLength = length + adjust;
163 
164     mBasePtr = MapViewOfFile( mFileMapping,
165                               readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
166                               0,
167                               (DWORD)(adjOffset),
168                               adjLength );
169     if (mBasePtr == NULL) {
170         ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %lu\n",
171               adjOffset, adjLength, GetLastError() );
172         CloseHandle(mFileMapping);
173         mFileMapping = NULL;
174         return false;
175     }
176 #else // !defined(__MINGW32__)
177     assert(fd >= 0);
178     assert(offset >= 0);
179     assert(length > 0);
180 
181     // init on first use
182     if (mPageSize == -1) {
183         mPageSize = sysconf(_SC_PAGESIZE);
184         if (mPageSize == -1) {
185             ALOGE("could not get _SC_PAGESIZE\n");
186             return false;
187         }
188     }
189 
190     int adjust = offset % mPageSize;
191     off64_t adjOffset = offset - adjust;
192     size_t adjLength = length + adjust;
193 
194     int flags = MAP_SHARED;
195     int prot = PROT_READ;
196     if (!readOnly) prot |= PROT_WRITE;
197 
198     void* ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
199     if (ptr == MAP_FAILED) {
200         if (errno == EINVAL && length == 0) {
201             ptr = nullptr;
202             adjust = 0;
203         } else {
204             ALOGE("mmap(%lld,%zu) failed: %s\n", (long long)adjOffset, adjLength, strerror(errno));
205             return false;
206         }
207     }
208     mBasePtr = ptr;
209 #endif // !defined(__MINGW32__)
210 
211     mFileName = origFileName != nullptr ? strdup(origFileName) : nullptr;
212     mBaseLength = adjLength;
213     mDataOffset = offset;
214     mDataPtr = (char*) mBasePtr + adjust;
215     mDataLength = length;
216 
217     ALOGV("MAP: base %p/%zu data %p/%zu\n",
218         mBasePtr, mBaseLength, mDataPtr, mDataLength);
219 
220     return true;
221 }
222 
223 // Provide guidance to the system.
224 #if !defined(_WIN32)
advise(MapAdvice advice)225 int FileMap::advise(MapAdvice advice)
226 {
227     int cc, sysAdvice;
228 
229     switch (advice) {
230         case NORMAL:        sysAdvice = MADV_NORMAL;        break;
231         case RANDOM:        sysAdvice = MADV_RANDOM;        break;
232         case SEQUENTIAL:    sysAdvice = MADV_SEQUENTIAL;    break;
233         case WILLNEED:      sysAdvice = MADV_WILLNEED;      break;
234         case DONTNEED:      sysAdvice = MADV_DONTNEED;      break;
235         default:
236                             assert(false);
237                             return -1;
238     }
239 
240     cc = madvise(mBasePtr, mBaseLength, sysAdvice);
241     if (cc != 0)
242         ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
243     return cc;
244 }
245 
246 #else
advise(MapAdvice)247 int FileMap::advise(MapAdvice /* advice */)
248 {
249     return -1;
250 }
251 #endif
252