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