SysUtil.cpp revision 518925b0103405fd0fa03cde1b9e58acf76a6a64
1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License. 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License. 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 1699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * System utilities. 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "DexFile.h" 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "SysUtil.h" 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdlib.h> 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdio.h> 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <unistd.h> 26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <string.h> 27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/mman.h> 30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <limits.h> 33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <errno.h> 34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Having trouble finding a portable way to get this. sysconf(_SC_PAGE_SIZE) 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * seems appropriate, but we don't have that on the device. Some systems 38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * have getpagesize(2), though the linux man page has some odd cautions. 39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define DEFAULT_PAGE_SIZE 4096 41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create an anonymous shared memory segment large enough to hold "length" 45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * bytes. The actual segment may be larger because mmap() operates on 46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * page boundaries (usually 4K). 47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void* sysCreateAnonShmem(size_t length) 49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project void* ptr; 52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project MAP_SHARED | MAP_ANON, -1, 0); 55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (ptr == MAP_FAILED) { 56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("mmap(%d, RW, SHARED|ANON) failed: %s\n", (int) length, 57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project strerror(errno)); 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return ptr; 62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("sysCreateAnonShmem not implemented.\n"); 64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return NULL; 65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 6899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/* 6999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Create a private anonymous storage area. 7099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 7199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectint sysCreatePrivateMap(size_t length, MemMapping* pMap) 7299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{ 7399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project void* memPtr; 7499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 7599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project memPtr = sysCreateAnonShmem(length); 7699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project if (memPtr == NULL) 7799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project return -1; 7899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 7999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project pMap->addr = pMap->baseAddr = memPtr; 8099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project pMap->length = pMap->baseLength = length; 8199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project return 0; 8299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project} 8399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project 8499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/* 8599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Determine the current offset and remaining length of the open file. 8699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */ 87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int getFileStartAndLength(int fd, off_t *start_, size_t *length_) 88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project off_t start, end; 90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project size_t length; 91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(start_ != NULL); 93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(length_ != NULL); 94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project start = lseek(fd, 0L, SEEK_CUR); 96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project end = lseek(fd, 0L, SEEK_END); 97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (void) lseek(fd, start, SEEK_SET); 98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (start == (off_t) -1 || end == (off_t) -1) { 100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("could not determine length of file\n"); 101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project length = end - start; 105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (length == 0) { 106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("file is empty\n"); 107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *start_ = start; 111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *length_ = length; 112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return 0; 114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Pull the contents of a file into an new shared memory segment. We grab 118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * everything from fd's current offset on. 119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need to know the length ahead of time so we can allocate a segment 121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of sufficient size. 122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint sysLoadFileInShmem(int fd, MemMapping* pMap) 124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP 126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project off_t start; 127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project size_t length, actual; 128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project void* memPtr; 129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(pMap != NULL); 131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (getFileStartAndLength(fd, &start, &length) < 0) 133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project memPtr = sysCreateAnonShmem(length); 136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (memPtr == NULL) 137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project actual = read(fd, memPtr, length); 140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (actual != length) { 141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("only read %d of %d bytes\n", (int) actual, (int) length); 142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sysReleaseShmem(pMap); 143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseAddr = pMap->addr = memPtr; 147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseLength = pMap->length = length; 148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return 0; 150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("sysLoadFileInShmem not implemented.\n"); 152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 156518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#ifndef HAVE_POSIX_FILEMAP 157518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFaddenint sysFakeMapFile(int fd, MemMapping* pMap) 158518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden{ 159518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden /* No MMAP, just fake it by copying the bits. 160518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden For Win32 we could use MapViewOfFile if really necessary 161518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden (see libs/utils/FileMap.cpp). 162518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden */ 163518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden off_t start; 164518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden size_t length; 165518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden void* memPtr; 166518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden 167518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden assert(pMap != NULL); 168518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden 169518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden if (getFileStartAndLength(fd, &start, &length) < 0) 170518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden return -1; 171518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden 172518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden memPtr = malloc(length); 173518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden if (read(fd, memPtr, length) < 0) { 174518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden LOGW("read(fd=%d, start=%d, length=%d) failed: %s\n", (int) length, 175518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden fd, (int) start, strerror(errno)); 176518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden return -1; 177518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden } 178518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden 179518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden pMap->baseAddr = pMap->addr = memPtr; 180518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden pMap->baseLength = pMap->length = length; 181518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden 182518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden return 0; 183518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden} 184518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#endif 185518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden 186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Map a file (from fd's current offset) into a shared, read-only memory 18896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * segment. The file offset must be a multiple of the system page size. 189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * On success, returns 0 and fills out "pMap". On failure, returns a nonzero 191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * value and does not disturb "pMap". 192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 193b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFaddenint sysMapFileInShmemReadOnly(int fd, MemMapping* pMap) 194b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden{ 195b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden#ifdef HAVE_POSIX_FILEMAP 196b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden off_t start; 197b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden size_t length; 198b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden void* memPtr; 199b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden 200b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden assert(pMap != NULL); 201b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden 202b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden if (getFileStartAndLength(fd, &start, &length) < 0) 203b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden return -1; 204b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden 205b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start); 206b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden if (memPtr == MAP_FAILED) { 207b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden LOGW("mmap(%d, RO, FILE|SHARED, %d, %d) failed: %s\n", (int) length, 208b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden fd, (int) start, strerror(errno)); 209b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden return -1; 210b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden } 211b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden 212b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden pMap->baseAddr = pMap->addr = memPtr; 213b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden pMap->baseLength = pMap->length = length; 214b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden 215b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden return 0; 216b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden#else 217518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden return sysFakeMapFile(fd, pMap); 218b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden#endif 219b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden} 220b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden 221b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden/* 222b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * Map a file (from fd's current offset) into a private, read-write memory 223b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * segment that will be marked read-only (a/k/a "writable read-only"). The 224b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * file offset must be a multiple of the system page size. 225b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * 226b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * In some cases the mapping will be fully writable (e.g. for files on 227b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * FAT filesystems). 228b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * 229b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * On success, returns 0 and fills out "pMap". On failure, returns a nonzero 230b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden * value and does not disturb "pMap". 231b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden */ 232b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFaddenint sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap) 233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP 235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project off_t start; 236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project size_t length; 237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project void* memPtr; 238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(pMap != NULL); 240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (getFileStartAndLength(fd, &start, &length) < 0) 242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 24496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden memPtr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, 24596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden fd, start); 246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (memPtr == MAP_FAILED) { 24796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden LOGW("mmap(%d, R/W, FILE|PRIVATE, %d, %d) failed: %s\n", (int) length, 248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fd, (int) start, strerror(errno)); 249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 25196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (mprotect(memPtr, length, PROT_READ) < 0) { 252b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden /* this fails with EACCESS on FAT filesystems, e.g. /sdcard */ 253b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden int err = errno; 254b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden LOGV("mprotect(%p, %d, PROT_READ) failed: %s\n", 255b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden memPtr, length, strerror(err)); 256b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden LOGD("mprotect(RO) failed (%d), file will remain read-write\n", err); 25796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseAddr = pMap->addr = memPtr; 260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseLength = pMap->length = length; 261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return 0; 263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 264518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden return sysFakeMapFile(fd, pMap); 265b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden#endif 266b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden} 267b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden 268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Map part of a file (from fd's current offset) into a shared, read-only 270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * memory segment. 271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * On success, returns 0 and fills out "pMap". On failure, returns a nonzero 273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * value and does not disturb "pMap". 274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint sysMapFileSegmentInShmem(int fd, off_t start, long length, 276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project MemMapping* pMap) 277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP 279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project off_t dummy; 280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project size_t fileLength, actualLength; 281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project off_t actualStart; 282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int adjust; 283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project void* memPtr; 284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project assert(pMap != NULL); 286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (getFileStartAndLength(fd, &dummy, &fileLength) < 0) 288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (start + length > (long)fileLength) { 291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("bad segment: st=%d len=%ld flen=%d\n", 292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (int) start, length, (int) fileLength); 293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* adjust to be page-aligned */ 297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project adjust = start % DEFAULT_PAGE_SIZE; 298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project actualStart = start - adjust; 299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project actualLength = length + adjust; 300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED, 302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fd, actualStart); 303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (memPtr == MAP_FAILED) { 304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n", 305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (int) actualLength, fd, (int) actualStart, strerror(errno)); 306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseAddr = memPtr; 310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseLength = actualLength; 311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->addr = (char*)memPtr + adjust; 312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->length = length; 313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d\n", 315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (int) start, (int) length, 316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseAddr, (int) pMap->baseLength, 317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->addr, (int) pMap->length); 318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return 0; 320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGE("sysMapFileSegmentInShmem not implemented.\n"); 322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return -1; 323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 32796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Change the access rights on one or more pages to read-only or read-write. 32896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 32996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns 0 on success. 33096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 33196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenint sysChangeMapAccess(void* addr, size_t length, int wantReadWrite, 33296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden MemMapping* pMap) 33396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 334518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#ifdef HAVE_POSIX_FILEMAP 33596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* 33696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Verify that "addr" is part of this mapping file. 33796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 33896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (addr < pMap->baseAddr || 33996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden (u1*)addr >= (u1*)pMap->baseAddr + pMap->baseLength) 34096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden { 34196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden LOGE("Attempted to change %p; map is %p - %p\n", 34296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden addr, pMap->baseAddr, (u1*)pMap->baseAddr + pMap->baseLength); 34396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return -1; 34496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 34596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 34696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* 34796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Align "addr" to a page boundary and adjust "length" appropriately. 34896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * (The address must be page-aligned, the length doesn't need to be, 34996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * but we do need to ensure we cover the same range.) 35096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 35196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden u1* alignAddr = (u1*) ((int) addr & ~(SYSTEM_PAGE_SIZE-1)); 35296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden size_t alignLength = length + ((u1*) addr - alignAddr); 35396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 35496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden //LOGI("%p/%zd --> %p/%zd\n", addr, length, alignAddr, alignLength); 35596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int prot = wantReadWrite ? (PROT_READ|PROT_WRITE) : (PROT_READ); 35696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (mprotect(alignAddr, alignLength, prot) != 0) { 35796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int err = errno; 358b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden LOGV("mprotect (%p,%zd,%d) failed: %s\n", 35996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden alignAddr, alignLength, prot, strerror(errno)); 36096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return (errno != 0) ? errno : -1; 36196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 362518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#endif 36396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 364518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden /* for "fake" mapping, no need to do anything */ 36596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return 0; 36696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 36796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 36896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release a memory mapping. 370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid sysReleaseShmem(MemMapping* pMap) 372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP 374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pMap->baseAddr == NULL && pMap->baseLength == 0) 375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (munmap(pMap->baseAddr, pMap->baseLength) < 0) { 378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGW("munmap(%p, %d) failed: %s\n", 379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseAddr, (int)pMap->baseLength, strerror(errno)); 380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project LOGV("munmap(%p, %d) succeeded\n", pMap->baseAddr, pMap->baseLength); 382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseAddr = NULL; 383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseLength = 0; 384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else 386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* Free the bits allocated by sysMapFileInShmem. */ 387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (pMap->baseAddr != NULL) { 388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project free(pMap->baseAddr); 389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseAddr = NULL; 390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pMap->baseLength = 0; 392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif 393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Make a copy of a MemMapping. 397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid sysCopyMap(MemMapping* dst, const MemMapping* src) 399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project memcpy(dst, src, sizeof(MemMapping)); 401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 403