• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * Utility functions for dealing with optimized dex files.
19  */
20 
21 #include "vm/DalvikVersion.h"
22 
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/file.h>
30 #include <errno.h>
31 
32 #include "OptInvocation.h"
33 #include "DexFile.h"
34 
35 static const char* kCacheDirectoryName = "dalvik-cache";
36 static const char* kClassesDex = "classes.dex";
37 
38 #if defined(__aarch64__)
39 static const char* kInstructionSet = "arm64";
40 #elif defined(__arm__)
41 static const char* kInstructionSet = "arm";
42 #elif defined(__i386__)
43 static const char* kInstructionSet = "x86";
44 #elif defined(__mips__)
45 static const char* kInstructionSet = "mips";
46 #elif defined(__x86_64__)
47 static const char* kInstructionSet = "x86_64";
48 #else
49 #error Unsupported instruction set.
50 #endif
51 
dexOptMkdir(const char * path,int mode)52 static int dexOptMkdir(const char*  path, int mode)
53 {
54 #ifdef _WIN32
55     return mkdir(path);
56 #else
57     return mkdir(path, mode);
58 #endif
59 }
60 
61 /*
62  * Given the filename of a .jar or .dex file, construct the DEX file cache
63  * name.
64  *
65  * For a Jar, "subFileName" is the name of the entry (usually "classes.dex").
66  * For a DEX, it may be NULL.
67  *
68  * Returns a newly-allocated string, or NULL on failure.
69  */
dexOptGenerateCacheFileName(const char * fileName,const char * subFileName)70 char* dexOptGenerateCacheFileName(const char* fileName, const char* subFileName)
71 {
72     char nameBuf[512];
73     char absoluteFile[sizeof(nameBuf)];
74     const size_t kBufLen = sizeof(nameBuf) - 1;
75     const char* dataRoot;
76     char* cp;
77 
78     /*
79      * Get the absolute path of the Jar or DEX file.
80      */
81     absoluteFile[0] = '\0';
82     if (fileName[0] != '/') {
83         /*
84          * Generate the absolute path.  This doesn't do everything it
85          * should, e.g. if filename is "./out/whatever" it doesn't crunch
86          * the leading "./" out, but it'll do.
87          */
88         if (getcwd(absoluteFile, kBufLen) == NULL) {
89             ALOGE("Can't get CWD while opening jar file");
90             return NULL;
91         }
92         strncat(absoluteFile, "/", kBufLen);
93     }
94     strncat(absoluteFile, fileName, kBufLen);
95 
96     /*
97      * Append the name of the Jar file entry, if any.  This is not currently
98      * required, but will be if we start putting more than one DEX file
99      * in a Jar.
100      */
101     if (subFileName != NULL) {
102         strncat(absoluteFile, "/", kBufLen);
103         strncat(absoluteFile, subFileName, kBufLen);
104     }
105 
106     /* Turn the path into a flat filename by replacing
107      * any slashes after the first one with '@' characters.
108      */
109     cp = absoluteFile + 1;
110     while (*cp != '\0') {
111         if (*cp == '/') {
112             *cp = '@';
113         }
114         cp++;
115     }
116 
117     /* Build the name of the cache directory.
118      */
119     dataRoot = getenv("ANDROID_DATA");
120     if (dataRoot == NULL)
121         dataRoot = "/data";
122     snprintf(nameBuf, kBufLen, "%s/%s", dataRoot, kCacheDirectoryName);
123     if (strcmp(dataRoot, "/data") != 0) {
124         int result = dexOptMkdir(nameBuf, 0700);
125         if (result != 0 && errno != EEXIST) {
126             ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
127             return NULL;
128         }
129     }
130     snprintf(nameBuf, kBufLen, "%s/%s/%s", dataRoot, kCacheDirectoryName, kInstructionSet);
131     if (strcmp(dataRoot, "/data") != 0) {
132         int result = dexOptMkdir(nameBuf, 0700);
133         if (result != 0 && errno != EEXIST) {
134             ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
135             return NULL;
136         }
137     }
138 
139     /* Tack on the file name for the actual cache file path.
140      */
141     strncat(nameBuf, absoluteFile, kBufLen);
142 
143     ALOGV("Cache file for '%s' '%s' is '%s'", fileName, subFileName, nameBuf);
144     return strdup(nameBuf);
145 }
146 
147 /*
148  * Create a skeletal "opt" header in a new file.  Most of the fields are
149  * initialized to garbage, but we fill in "dexOffset" so others can
150  * see how large the header is.
151  *
152  * "fd" must be positioned at the start of the file.  On return, it will
153  * be positioned just past the header, and the place where the DEX data
154  * should go.
155  *
156  * Returns 0 on success, errno on failure.
157  */
dexOptCreateEmptyHeader(int fd)158 int dexOptCreateEmptyHeader(int fd)
159 {
160     DexOptHeader optHdr;
161     ssize_t actual;
162 
163     assert(lseek(fd, 0, SEEK_CUR) == 0);
164 
165     /*
166      * The data is only expected to be readable on the current system, so
167      * we just write the structure.  We do need the file offset to be 64-bit
168      * aligned to fulfill a DEX requirement.
169      */
170     assert((sizeof(optHdr) & 0x07) == 0);
171     memset(&optHdr, 0xff, sizeof(optHdr));
172     optHdr.dexOffset = sizeof(optHdr);
173     actual = write(fd, &optHdr, sizeof(optHdr));
174     if (actual != sizeof(optHdr)) {
175         int err = errno ? errno : -1;
176         ALOGE("opt header write failed: %s", strerror(errno));
177         return errno;
178     }
179 
180     return 0;
181 }
182