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. 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. 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. 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. 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. 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; 193 if (__builtin_add_overflow(length, adjust, &adjLength)) { 194 ALOGE("adjusted length overflow: length %zu adjust %d", length, adjust); 195 return false; 196 } 197 198 int flags = MAP_SHARED; 199 int prot = PROT_READ; 200 if (!readOnly) prot |= PROT_WRITE; 201 202 void* ptr = mmap64(nullptr, adjLength, prot, flags, fd, adjOffset); 203 if (ptr == MAP_FAILED) { 204 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 } 211 } 212 mBasePtr = ptr; 213 #endif // !defined(__MINGW32__) 214 215 mFileName = origFileName != nullptr ? strdup(origFileName) : nullptr; 216 mBaseLength = adjLength; 217 mDataOffset = offset; 218 mDataPtr = (char*) mBasePtr + adjust; 219 mDataLength = length; 220 221 ALOGV("MAP: base %p/%zu data %p/%zu\n", 222 mBasePtr, mBaseLength, mDataPtr, mDataLength); 223 224 return true; 225 } 226 227 // Provide guidance to the system. 228 #if !defined(_WIN32) 229 int FileMap::advise(MapAdvice advice) 230 { 231 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) 246 ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno)); 247 return cc; 248 } 249 250 #else 251 int FileMap::advise(MapAdvice /* advice */) 252 { 253 return -1; 254 } 255 #endif 256