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(NULL), 52 mBasePtr(NULL), 53 mBaseLength(0), 54 mDataPtr(NULL), 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) 66 : mFileName(other.mFileName), mBasePtr(other.mBasePtr), mBaseLength(other.mBaseLength), 67 mDataOffset(other.mDataOffset), mDataPtr(other.mDataPtr), mDataLength(other.mDataLength) 68 #if defined(__MINGW32__) 69 , mFileHandle(other.mFileHandle), mFileMapping(other.mFileMapping) 70 #endif 71 { 72 other.mFileName = NULL; 73 other.mBasePtr = NULL; 74 other.mDataPtr = NULL; 75 #if defined(__MINGW32__) 76 other.mFileHandle = INVALID_HANDLE_VALUE; 77 other.mFileMapping = NULL; 78 #endif 79 } 80 81 // Move assign operator. 82 FileMap& FileMap::operator=(FileMap&& other) { 83 mFileName = other.mFileName; 84 mBasePtr = other.mBasePtr; 85 mBaseLength = other.mBaseLength; 86 mDataOffset = other.mDataOffset; 87 mDataPtr = other.mDataPtr; 88 mDataLength = other.mDataLength; 89 other.mFileName = NULL; 90 other.mBasePtr = NULL; 91 other.mDataPtr = NULL; 92 #if defined(__MINGW32__) 93 mFileHandle = other.mFileHandle; 94 mFileMapping = other.mFileMapping; 95 other.mFileHandle = INVALID_HANDLE_VALUE; 96 other.mFileMapping = NULL; 97 #endif 98 return *this; 99 } 100 101 // Destructor. 102 FileMap::~FileMap(void) 103 { 104 if (mFileName != NULL) { 105 free(mFileName); 106 } 107 #if defined(__MINGW32__) 108 if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) { 109 ALOGD("UnmapViewOfFile(%p) failed, error = %lu\n", mBasePtr, 110 GetLastError() ); 111 } 112 if (mFileMapping != NULL) { 113 CloseHandle(mFileMapping); 114 } 115 #else 116 if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) { 117 ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength); 118 } 119 #endif 120 } 121 122 123 // Create a new mapping on an open file. 124 // 125 // Closing the file descriptor does not unmap the pages, so we don't 126 // claim ownership of the fd. 127 // 128 // Returns "false" on failure. 129 bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length, 130 bool readOnly) 131 { 132 #if defined(__MINGW32__) 133 int adjust; 134 off64_t adjOffset; 135 size_t adjLength; 136 137 if (mPageSize == -1) { 138 SYSTEM_INFO si; 139 140 GetSystemInfo( &si ); 141 mPageSize = si.dwAllocationGranularity; 142 } 143 144 DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE; 145 146 mFileHandle = (HANDLE) _get_osfhandle(fd); 147 mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL); 148 if (mFileMapping == NULL) { 149 ALOGE("CreateFileMapping(%p, %lx) failed with error %lu\n", 150 mFileHandle, protect, GetLastError() ); 151 return false; 152 } 153 154 adjust = offset % mPageSize; 155 adjOffset = offset - adjust; 156 adjLength = length + adjust; 157 158 mBasePtr = MapViewOfFile( mFileMapping, 159 readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, 160 0, 161 (DWORD)(adjOffset), 162 adjLength ); 163 if (mBasePtr == NULL) { 164 ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %lu\n", 165 adjOffset, adjLength, GetLastError() ); 166 CloseHandle(mFileMapping); 167 mFileMapping = NULL; 168 return false; 169 } 170 #else // !defined(__MINGW32__) 171 int prot, flags, adjust; 172 off64_t adjOffset; 173 size_t adjLength; 174 175 void* ptr; 176 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 adjust = offset % mPageSize; 191 adjOffset = offset - adjust; 192 adjLength = length + adjust; 193 194 flags = MAP_SHARED; 195 prot = PROT_READ; 196 if (!readOnly) 197 prot |= PROT_WRITE; 198 199 ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset); 200 if (ptr == MAP_FAILED) { 201 ALOGE("mmap(%lld,%zu) failed: %s\n", 202 (long long)adjOffset, adjLength, strerror(errno)); 203 return false; 204 } 205 mBasePtr = ptr; 206 #endif // !defined(__MINGW32__) 207 208 mFileName = origFileName != NULL ? strdup(origFileName) : NULL; 209 mBaseLength = adjLength; 210 mDataOffset = offset; 211 mDataPtr = (char*) mBasePtr + adjust; 212 mDataLength = length; 213 214 assert(mBasePtr != NULL); 215 216 ALOGV("MAP: base %p/%zu data %p/%zu\n", 217 mBasePtr, mBaseLength, mDataPtr, mDataLength); 218 219 return true; 220 } 221 222 // Provide guidance to the system. 223 #if !defined(_WIN32) 224 int FileMap::advise(MapAdvice advice) 225 { 226 int cc, sysAdvice; 227 228 switch (advice) { 229 case NORMAL: sysAdvice = MADV_NORMAL; break; 230 case RANDOM: sysAdvice = MADV_RANDOM; break; 231 case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break; 232 case WILLNEED: sysAdvice = MADV_WILLNEED; break; 233 case DONTNEED: sysAdvice = MADV_DONTNEED; break; 234 default: 235 assert(false); 236 return -1; 237 } 238 239 cc = madvise(mBasePtr, mBaseLength, sysAdvice); 240 if (cc != 0) 241 ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno)); 242 return cc; 243 } 244 245 #else 246 int FileMap::advise(MapAdvice /* advice */) 247 { 248 return -1; 249 } 250 #endif 251