blob: 0abb86191f046cf6d86496a73bf39e2f57ecc3de [file] [log] [blame]
The Android Open Source Projectcbb10112009-03-03 19:31:44 -08001/*
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
Yabin Cui266092c2014-11-11 10:31:30 -080026#if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO)
Mark Salyzyn5bed8032014-04-30 11:10:46 -070027# define PRId32 "I32d"
28# define PRIx32 "I32x"
29# define PRId64 "I64d"
30#else
Mark Salyzyn15085a62014-04-17 09:34:42 -070031#include <inttypes.h>
Mark Salyzyn5bed8032014-04-30 11:10:46 -070032#endif
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080033#include <stdio.h>
34#include <stdlib.h>
35
Yabin Cui266092c2014-11-11 10:31:30 -080036#if !defined(__MINGW32__)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080037#include <sys/mman.h>
38#endif
39
40#include <string.h>
41#include <memory.h>
42#include <errno.h>
43#include <assert.h>
44
45using namespace android;
46
47/*static*/ long FileMap::mPageSize = -1;
48
Mark Salyzynb6185762014-04-17 10:01:12 -070049// Constructor. Create an empty object.
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080050FileMap::FileMap(void)
Yi Konge1731a42018-07-16 18:11:34 -070051 : mFileName(nullptr),
52 mBasePtr(nullptr),
Renaud Paquayb7a4f0b2017-05-10 17:48:59 -070053 mBaseLength(0),
Yi Konge1731a42018-07-16 18:11:34 -070054 mDataPtr(nullptr),
Renaud Paquayb7a4f0b2017-05-10 17:48:59 -070055 mDataLength(0)
56#if defined(__MINGW32__)
57 ,
58 mFileHandle(INVALID_HANDLE_VALUE),
59 mFileMapping(NULL)
60#endif
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080061{
62}
63
Adam Lesinski6f8885b2015-09-22 18:42:19 -070064// Move Constructor.
Chih-Hung Hsieh747eb142018-09-25 11:16:22 -070065FileMap::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)
Adam Lesinski6f8885b2015-09-22 18:42:19 -070072#if defined(__MINGW32__)
Chih-Hung Hsieh747eb142018-09-25 11:16:22 -070073 ,
74 mFileHandle(other.mFileHandle),
75 mFileMapping(other.mFileMapping)
Adam Lesinski6f8885b2015-09-22 18:42:19 -070076#endif
77{
Yi Konge1731a42018-07-16 18:11:34 -070078 other.mFileName = nullptr;
79 other.mBasePtr = nullptr;
80 other.mDataPtr = nullptr;
Adam Lesinski6f8885b2015-09-22 18:42:19 -070081#if defined(__MINGW32__)
Renaud Paquayb7a4f0b2017-05-10 17:48:59 -070082 other.mFileHandle = INVALID_HANDLE_VALUE;
83 other.mFileMapping = NULL;
Adam Lesinski6f8885b2015-09-22 18:42:19 -070084#endif
85}
86
87// Move assign operator.
Chih-Hung Hsieh747eb142018-09-25 11:16:22 -070088FileMap& FileMap::operator=(FileMap&& other) noexcept {
Adam Lesinski6f8885b2015-09-22 18:42:19 -070089 mFileName = other.mFileName;
90 mBasePtr = other.mBasePtr;
91 mBaseLength = other.mBaseLength;
92 mDataOffset = other.mDataOffset;
93 mDataPtr = other.mDataPtr;
94 mDataLength = other.mDataLength;
Yi Konge1731a42018-07-16 18:11:34 -070095 other.mFileName = nullptr;
96 other.mBasePtr = nullptr;
97 other.mDataPtr = nullptr;
Adam Lesinski6f8885b2015-09-22 18:42:19 -070098#if defined(__MINGW32__)
99 mFileHandle = other.mFileHandle;
100 mFileMapping = other.mFileMapping;
Renaud Paquayb7a4f0b2017-05-10 17:48:59 -0700101 other.mFileHandle = INVALID_HANDLE_VALUE;
102 other.mFileMapping = NULL;
Adam Lesinski6f8885b2015-09-22 18:42:19 -0700103#endif
104 return *this;
105}
106
Mark Salyzynb6185762014-04-17 10:01:12 -0700107// Destructor.
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800108FileMap::~FileMap(void)
109{
Yi Konge1731a42018-07-16 18:11:34 -0700110 if (mFileName != nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800111 free(mFileName);
112 }
Yabin Cui266092c2014-11-11 10:31:30 -0800113#if defined(__MINGW32__)
Jeff Brown1d618d62010-12-02 13:50:46 -0800114 if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
Colin Cross17b5b822016-09-15 18:15:37 -0700115 ALOGD("UnmapViewOfFile(%p) failed, error = %lu\n", mBasePtr,
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800116 GetLastError() );
117 }
Renaud Paquayb7a4f0b2017-05-10 17:48:59 -0700118 if (mFileMapping != NULL) {
Jeff Brown1d618d62010-12-02 13:50:46 -0800119 CloseHandle(mFileMapping);
120 }
Yabin Cui266092c2014-11-11 10:31:30 -0800121#else
122 if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
123 ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength);
124 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800125#endif
126}
127
128
Mark Salyzynb6185762014-04-17 10:01:12 -0700129// 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.
Kenny Roote2fa7dc2010-11-24 12:56:06 -0800135bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
136 bool readOnly)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800137{
Yabin Cui266092c2014-11-11 10:31:30 -0800138#if defined(__MINGW32__)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800139 int adjust;
Kenny Roote2fa7dc2010-11-24 12:56:06 -0800140 off64_t adjOffset;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800141 size_t adjLength;
142
143 if (mPageSize == -1) {
144 SYSTEM_INFO si;
Mark Salyzynb6185762014-04-17 10:01:12 -0700145
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800146 GetSystemInfo( &si );
147 mPageSize = si.dwAllocationGranularity;
148 }
149
150 DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
Mark Salyzynb6185762014-04-17 10:01:12 -0700151
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800152 mFileHandle = (HANDLE) _get_osfhandle(fd);
153 mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
154 if (mFileMapping == NULL) {
Colin Cross17b5b822016-09-15 18:15:37 -0700155 ALOGE("CreateFileMapping(%p, %lx) failed with error %lu\n",
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800156 mFileHandle, protect, GetLastError() );
157 return false;
158 }
Mark Salyzynb6185762014-04-17 10:01:12 -0700159
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800160 adjust = offset % mPageSize;
161 adjOffset = offset - adjust;
162 adjLength = length + adjust;
Mark Salyzynb6185762014-04-17 10:01:12 -0700163
164 mBasePtr = MapViewOfFile( mFileMapping,
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800165 readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
166 0,
167 (DWORD)(adjOffset),
168 adjLength );
169 if (mBasePtr == NULL) {
Colin Cross17b5b822016-09-15 18:15:37 -0700170 ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %lu\n",
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800171 adjOffset, adjLength, GetLastError() );
172 CloseHandle(mFileMapping);
Renaud Paquayb7a4f0b2017-05-10 17:48:59 -0700173 mFileMapping = NULL;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800174 return false;
175 }
Yabin Cui266092c2014-11-11 10:31:30 -0800176#else // !defined(__MINGW32__)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800177 assert(fd >= 0);
178 assert(offset >= 0);
179 assert(length > 0);
180
Mark Salyzynb6185762014-04-17 10:01:12 -0700181 // init on first use
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800182 if (mPageSize == -1) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800183 mPageSize = sysconf(_SC_PAGESIZE);
184 if (mPageSize == -1) {
Steve Block1b781ab2012-01-06 19:20:56 +0000185 ALOGE("could not get _SC_PAGESIZE\n");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800186 return false;
187 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800188 }
189
Elliott Hugheseb0ef142019-02-06 14:28:32 -0800190 int adjust = offset % mPageSize;
191 off64_t adjOffset = offset - adjust;
Christopher Ferris68604b92020-05-26 10:33:18 -0700192 size_t adjLength;
193 if (__builtin_add_overflow(length, adjust, &adjLength)) {
194 ALOGE("adjusted length overflow: length %zu adjust %d", length, adjust);
195 return false;
196 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800197
Elliott Hugheseb0ef142019-02-06 14:28:32 -0800198 int flags = MAP_SHARED;
199 int prot = PROT_READ;
200 if (!readOnly) prot |= PROT_WRITE;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800201
Christopher Ferris7b9f35c2020-05-06 13:48:32 -0700202 void* ptr = mmap64(nullptr, adjLength, prot, flags, fd, adjOffset);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800203 if (ptr == MAP_FAILED) {
Elliott Hugheseb0ef142019-02-06 14:28:32 -0800204 if (errno == EINVAL && length == 0) {
205 ptr = nullptr;
206 adjust = 0;
207 } else {
208 ALOGE("mmap(%lld,%zu) failed: %s\n", (long long)adjOffset, adjLength, strerror(errno));
209 return false;
210 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800211 }
212 mBasePtr = ptr;
Yabin Cui266092c2014-11-11 10:31:30 -0800213#endif // !defined(__MINGW32__)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800214
Yi Konge1731a42018-07-16 18:11:34 -0700215 mFileName = origFileName != nullptr ? strdup(origFileName) : nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800216 mBaseLength = adjLength;
217 mDataOffset = offset;
218 mDataPtr = (char*) mBasePtr + adjust;
219 mDataLength = length;
220
Mark Salyzyn15085a62014-04-17 09:34:42 -0700221 ALOGV("MAP: base %p/%zu data %p/%zu\n",
222 mBasePtr, mBaseLength, mDataPtr, mDataLength);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800223
224 return true;
225}
226
Mark Salyzynb6185762014-04-17 10:01:12 -0700227// Provide guidance to the system.
Yabin Cui745c5f62014-11-18 20:00:41 -0800228#if !defined(_WIN32)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800229int FileMap::advise(MapAdvice advice)
230{
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800231 int cc, sysAdvice;
232
233 switch (advice) {
234 case NORMAL: sysAdvice = MADV_NORMAL; break;
235 case RANDOM: sysAdvice = MADV_RANDOM; break;
236 case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break;
237 case WILLNEED: sysAdvice = MADV_WILLNEED; break;
238 case DONTNEED: sysAdvice = MADV_DONTNEED; break;
239 default:
240 assert(false);
241 return -1;
242 }
243
244 cc = madvise(mBasePtr, mBaseLength, sysAdvice);
245 if (cc != 0)
Steve Block61d341b2012-01-05 23:22:43 +0000246 ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800247 return cc;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800248}
Yabin Cui745c5f62014-11-18 20:00:41 -0800249
250#else
251int FileMap::advise(MapAdvice /* advice */)
252{
253 return -1;
254}
255#endif