Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 277 lines (233 sloc) 7.688 kb
f3b3a37 first commit
he chengjie authored
1 /*
2 * Copyright (C) 2008 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 * Open an unoptimized DEX file.
19 */
20
21 #include "Dalvik.h"
22 #include "libdex/OptInvocation.h"
23
24 #include <fcntl.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 /*
30 * Copy the given number of bytes from one fd to another, first
31 * seeking the source fd to the start of the file.
32 */
33 static int copyFileToFile(int destFd, int srcFd, size_t size)
34 {
35 if (lseek(srcFd, 0, SEEK_SET) != 0) {
36 LOGE("lseek failure: %s", strerror(errno));
37 return -1;
38 }
39
40 return sysCopyFileToFile(destFd, srcFd, size);
41 }
42
43 /*
44 * Get the modification time and size in bytes for the given fd.
45 */
46 static int getModTimeAndSize(int fd, u4* modTime, size_t* size)
47 {
48 struct stat buf;
49 int result = fstat(fd, &buf);
50
51 if (result < 0) {
52 LOGE("Unable to determine mod time: %s", strerror(errno));
53 return -1;
54 }
55
56 *modTime = (u4) buf.st_mtime;
57 *size = (size_t) buf.st_size;
58 assert((size_t) buf.st_size == buf.st_size);
59
60 return 0;
61 }
62
63 /*
64 * Verify the dex file magic number, and get the adler32 checksum out
65 * of the given fd, which is presumed to be a reference to a dex file
66 * with the cursor at the start of the file. The fd's cursor is
67 * modified by this operation.
68 */
69 static int verifyMagicAndGetAdler32(int fd, u4 *adler32)
70 {
71 /*
72 * The start of a dex file is eight bytes of magic followed by
73 * four bytes of checksum.
74 */
75 u1 headerStart[12];
76 ssize_t amt = read(fd, headerStart, sizeof(headerStart));
77
78 if (amt < 0) {
79 LOGE("Unable to read header: %s", strerror(errno));
80 return -1;
81 }
82
83 if (amt != sizeof(headerStart)) {
84 LOGE("Unable to read full header (only got %d bytes)", (int) amt);
85 return -1;
86 }
87
88 if (!dexHasValidMagic((DexHeader*) (void*) headerStart)) {
89 return -1;
90 }
91
92 /*
93 * We can't just cast the data to a u4 and read it, since the
94 * platform might be big-endian (also, because that would make the
95 * compiler complain about type-punned pointers). We assume here
96 * that the dex file is in the standard little-endian format; if
97 * that assumption turns out to be invalid, code that runs later
98 * will notice and complain.
99 */
100 *adler32 = (u4) headerStart[8]
101 | (((u4) headerStart[9]) << 8)
102 | (((u4) headerStart[10]) << 16)
103 | (((u4) headerStart[11]) << 24);
104
105 return 0;
106 }
107
108 /* See documentation comment in header. */
109 int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
110 RawDexFile** ppRawDexFile, bool isBootstrap)
111 {
112 /*
113 * TODO: This duplicates a lot of code from dvmJarFileOpen() in
114 * JarFile.c. This should be refactored.
115 */
116
117 DvmDex* pDvmDex = NULL;
118 char* cachedName = NULL;
119 int result = -1;
120 int dexFd = -1;
121 int optFd = -1;
122 u4 modTime = 0;
123 u4 adler32 = 0;
124 size_t fileSize = 0;
125 bool newFile = false;
126 bool locked = false;
127
128 dexFd = open(fileName, O_RDONLY);
129 if (dexFd < 0) goto bail;
130
131 /* If we fork/exec into dexopt, don't let it inherit the open fd. */
132 dvmSetCloseOnExec(dexFd);
133
134 if (verifyMagicAndGetAdler32(dexFd, &adler32) < 0) {
135 LOGE("Error with header for %s", fileName);
136 goto bail;
137 }
138
139 if (getModTimeAndSize(dexFd, &modTime, &fileSize) < 0) {
140 LOGE("Error with stat for %s", fileName);
141 goto bail;
142 }
143
144 /*
145 * See if the cached file matches. If so, optFd will become a reference
146 * to the cached file and will have been seeked to just past the "opt"
147 * header.
148 */
149
150 if (odexOutputName == NULL) {
151 cachedName = dexOptGenerateCacheFileName(fileName, NULL);
152 if (cachedName == NULL)
153 goto bail;
154 } else {
155 cachedName = strdup(odexOutputName);
156 }
157
158 LOGV("dvmRawDexFileOpen: Checking cache for %s (%s)",
159 fileName, cachedName);
160
161 optFd = dvmOpenCachedDexFile(fileName, cachedName, modTime,
162 adler32, isBootstrap, &newFile, /*createIfMissing=*/true);
163
164 if (optFd < 0) {
165 LOGI("Unable to open or create cache for %s (%s)",
166 fileName, cachedName);
167 goto bail;
168 }
169 locked = true;
170
171 /*
172 * If optFd points to a new file (because there was no cached
173 * version, or the cached version was stale), generate the
174 * optimized DEX. The file descriptor returned is still locked,
175 * and is positioned just past the optimization header.
176 */
177 if (newFile) {
178 u8 startWhen, copyWhen, endWhen;
179 bool result;
180 off_t dexOffset;
181
182 dexOffset = lseek(optFd, 0, SEEK_CUR);
183 result = (dexOffset > 0);
184
185 if (result) {
186 startWhen = dvmGetRelativeTimeUsec();
187 result = copyFileToFile(optFd, dexFd, fileSize) == 0;
188 copyWhen = dvmGetRelativeTimeUsec();
189 }
190
191 if (result) {
192 result = dvmOptimizeDexFile(optFd, dexOffset, fileSize,
193 fileName, modTime, adler32, isBootstrap);
194 }
195
196 if (!result) {
197 LOGE("Unable to extract+optimize DEX from '%s'", fileName);
198 goto bail;
199 }
200
201 endWhen = dvmGetRelativeTimeUsec();
202 LOGD("DEX prep '%s': copy in %dms, rewrite %dms",
203 fileName,
204 (int) (copyWhen - startWhen) / 1000,
205 (int) (endWhen - copyWhen) / 1000);
206 }
207
208 /*
209 * Map the cached version. This immediately rewinds the fd, so it
210 * doesn't have to be seeked anywhere in particular.
211 */
212 if (dvmDexFileOpenFromFd(optFd, &pDvmDex) != 0) {
213 LOGI("Unable to map cached %s", fileName);
214 goto bail;
215 }
216
217 if (locked) {
218 /* unlock the fd */
219 if (!dvmUnlockCachedDexFile(optFd)) {
220 /* uh oh -- this process needs to exit or we'll wedge the system */
221 LOGE("Unable to unlock DEX file");
222 goto bail;
223 }
224 locked = false;
225 }
226
227 LOGV("Successfully opened '%s'", fileName);
228
229 *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
230 (*ppRawDexFile)->cacheFileName = cachedName;
231 (*ppRawDexFile)->pDvmDex = pDvmDex;
232 cachedName = NULL; // don't free it below
233 result = 0;
234
235 bail:
236 free(cachedName);
237 if (dexFd >= 0) {
238 close(dexFd);
239 }
240 if (optFd >= 0) {
241 if (locked)
242 (void) dvmUnlockCachedDexFile(optFd);
243 close(optFd);
244 }
245 return result;
246 }
247
248 /* See documentation comment in header. */
249 int dvmRawDexFileOpenArray(u1* pBytes, u4 length, RawDexFile** ppRawDexFile)
250 {
251 DvmDex* pDvmDex = NULL;
252
253 if (!dvmPrepareDexInMemory(pBytes, length, &pDvmDex)) {
254 LOGD("Unable to open raw DEX from array");
255 return -1;
256 }
257 assert(pDvmDex != NULL);
258
259 *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
260 (*ppRawDexFile)->pDvmDex = pDvmDex;
261
262 return 0;
263 }
264
265 /*
266 * Close a RawDexFile and free the struct.
267 */
268 void dvmRawDexFileFree(RawDexFile* pRawDexFile)
269 {
270 if (pRawDexFile == NULL)
271 return;
272
273 dvmDexFileFree(pRawDexFile->pDvmDex);
274 free(pRawDexFile->cacheFileName);
275 free(pRawDexFile);
276 }
Something went wrong with that request. Please try again.