SysUtil.cpp revision 8911f7a2222124ba724a4a9281555b74d0e098e2
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/*
2698911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * Map part of a file into a shared, read-only memory segment.  The "start"
2708911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden * offset is absolute, not relative.
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 */
2758911f7a2222124ba724a4a9281555b74d0e098e2Andy McFaddenint sysMapFileSegmentInShmem(int fd, off_t start, size_t length,
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    MemMapping* pMap)
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP
2798911f7a2222124ba724a4a9281555b74d0e098e2Andy McFadden    size_t actualLength;
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    off_t actualStart;
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int adjust;
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* memPtr;
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(pMap != NULL);
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* adjust to be page-aligned */
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    adjust = start % DEFAULT_PAGE_SIZE;
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    actualStart = start - adjust;
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    actualLength = length + adjust;
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                fd, actualStart);
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (memPtr == MAP_FAILED) {
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n",
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            (int) actualLength, fd, (int) actualStart, strerror(errno));
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseAddr = memPtr;
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseLength = actualLength;
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->addr = (char*)memPtr + adjust;
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->length = length;
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d\n",
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        (int) start, (int) length,
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMap->baseAddr, (int) pMap->baseLength,
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMap->addr, (int) pMap->length);
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return 0;
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGE("sysMapFileSegmentInShmem not implemented.\n");
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return -1;
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
31796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Change the access rights on one or more pages to read-only or read-write.
31896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
31996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns 0 on success.
32096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
32196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenint sysChangeMapAccess(void* addr, size_t length, int wantReadWrite,
32296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    MemMapping* pMap)
32396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
324518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#ifdef HAVE_POSIX_FILEMAP
32596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /*
32696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     * Verify that "addr" is part of this mapping file.
32796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     */
32896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (addr < pMap->baseAddr ||
32996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        (u1*)addr >= (u1*)pMap->baseAddr + pMap->baseLength)
33096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    {
33196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        LOGE("Attempted to change %p; map is %p - %p\n",
33296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            addr, pMap->baseAddr, (u1*)pMap->baseAddr + pMap->baseLength);
33396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return -1;
33496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
33596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
33696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /*
33796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     * Align "addr" to a page boundary and adjust "length" appropriately.
33896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     * (The address must be page-aligned, the length doesn't need to be,
33996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     * but we do need to ensure we cover the same range.)
34096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden     */
34196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    u1* alignAddr = (u1*) ((int) addr & ~(SYSTEM_PAGE_SIZE-1));
34296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    size_t alignLength = length + ((u1*) addr - alignAddr);
34396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
34496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    //LOGI("%p/%zd --> %p/%zd\n", addr, length, alignAddr, alignLength);
34596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int prot = wantReadWrite ? (PROT_READ|PROT_WRITE) : (PROT_READ);
34696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (mprotect(alignAddr, alignLength, prot) != 0) {
34796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        int err = errno;
348b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        LOGV("mprotect (%p,%zd,%d) failed: %s\n",
34996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            alignAddr, alignLength, prot, strerror(errno));
35096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return (errno != 0) ? errno : -1;
35196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
352518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden#endif
35396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
354518925b0103405fd0fa03cde1b9e58acf76a6a64Andy McFadden    /* for "fake" mapping, no need to do anything */
35596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return 0;
35696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
35796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
35896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release a memory mapping.
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid sysReleaseShmem(MemMapping* pMap)
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifdef HAVE_POSIX_FILEMAP
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap->baseAddr == NULL && pMap->baseLength == 0)
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (munmap(pMap->baseAddr, pMap->baseLength) < 0) {
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("munmap(%p, %d) failed: %s\n",
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            pMap->baseAddr, (int)pMap->baseLength, strerror(errno));
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGV("munmap(%p, %d) succeeded\n", pMap->baseAddr, pMap->baseLength);
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMap->baseAddr = NULL;
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMap->baseLength = 0;
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#else
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Free the bits allocated by sysMapFileInShmem. */
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap->baseAddr != NULL) {
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      free(pMap->baseAddr);
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      pMap->baseAddr = NULL;
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap->baseLength = 0;
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Make a copy of a MemMapping.
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid sysCopyMap(MemMapping* dst, const MemMapping* src)
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    memcpy(dst, src, sizeof(MemMapping));
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
393