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