OptInvocation.cpp 5.34 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
16

17
/*
18
 * Utility functions for dealing with optimized dex files.
19
 */
20

21 22 23 24 25 26 27 28 29 30 31 32
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <errno.h>

#include "OptInvocation.h"
#include "DexFile.h"

33
static const char* kCacheDirectoryName = "dalvik-cache";
34 35
static const char* kClassesDex = "classes.dex";

36 37 38 39
#if defined(__aarch64__)
static const char* kInstructionSet = "arm64";
#elif defined(__arm__)
static const char* kInstructionSet = "arm";
40
#elif defined(__i386__)
41
static const char* kInstructionSet = "x86";
42
#elif defined(__mips__)
43 44 45
static const char* kInstructionSet = "mips";
#elif defined(__x86_64__)
static const char* kInstructionSet = "x86_64";
46 47 48 49
#else
#error Unsupported instruction set.
#endif

Brian Carlstrom's avatar
Brian Carlstrom committed
50 51 52 53 54 55 56 57
static int dexOptMkdir(const char*  path, int mode)
{
#ifdef _WIN32
    return mkdir(path);
#else
    return mkdir(path, mode);
#endif
}
58

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
/*
 * Given the filename of a .jar or .dex file, construct the DEX file cache
 * name.
 *
 * For a Jar, "subFileName" is the name of the entry (usually "classes.dex").
 * For a DEX, it may be NULL.
 *
 * Returns a newly-allocated string, or NULL on failure.
 */
char* dexOptGenerateCacheFileName(const char* fileName, const char* subFileName)
{
    char nameBuf[512];
    char absoluteFile[sizeof(nameBuf)];
    const size_t kBufLen = sizeof(nameBuf) - 1;
    const char* dataRoot;
    char* cp;

    /*
     * Get the absolute path of the Jar or DEX file.
     */
    absoluteFile[0] = '\0';
    if (fileName[0] != '/') {
        /*
         * Generate the absolute path.  This doesn't do everything it
         * should, e.g. if filename is "./out/whatever" it doesn't crunch
         * the leading "./" out, but it'll do.
         */
        if (getcwd(absoluteFile, kBufLen) == NULL) {
87
            ALOGE("Can't get CWD while opening jar file");
88 89
            return NULL;
        }
Aart Bik's avatar
Aart Bik committed
90
        strncat(absoluteFile, "/", kBufLen - strlen(absoluteFile));
91
    }
Aart Bik's avatar
Aart Bik committed
92
    strncat(absoluteFile, fileName, kBufLen - strlen(absoluteFile));
93 94 95 96 97 98 99

    /*
     * Append the name of the Jar file entry, if any.  This is not currently
     * required, but will be if we start putting more than one DEX file
     * in a Jar.
     */
    if (subFileName != NULL) {
Aart Bik's avatar
Aart Bik committed
100 101
        strncat(absoluteFile, "/", kBufLen - strlen(absoluteFile));
        strncat(absoluteFile, subFileName, kBufLen - strlen(absoluteFile));
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
    }

    /* Turn the path into a flat filename by replacing
     * any slashes after the first one with '@' characters.
     */
    cp = absoluteFile + 1;
    while (*cp != '\0') {
        if (*cp == '/') {
            *cp = '@';
        }
        cp++;
    }

    /* Build the name of the cache directory.
     */
    dataRoot = getenv("ANDROID_DATA");
    if (dataRoot == NULL)
        dataRoot = "/data";
120 121
    snprintf(nameBuf, kBufLen, "%s/%s", dataRoot, kCacheDirectoryName);
    if (strcmp(dataRoot, "/data") != 0) {
Brian Carlstrom's avatar
Brian Carlstrom committed
122
        int result = dexOptMkdir(nameBuf, 0700);
123 124 125 126 127
        if (result != 0 && errno != EEXIST) {
            ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
            return NULL;
        }
    }
128
    snprintf(nameBuf, kBufLen, "%s/%s/%s", dataRoot, kCacheDirectoryName, kInstructionSet);
129
    if (strcmp(dataRoot, "/data") != 0) {
Brian Carlstrom's avatar
Brian Carlstrom committed
130
        int result = dexOptMkdir(nameBuf, 0700);
131 132 133 134 135
        if (result != 0 && errno != EEXIST) {
            ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
            return NULL;
        }
    }
136 137 138

    /* Tack on the file name for the actual cache file path.
     */
Aart Bik's avatar
Aart Bik committed
139
    strncat(nameBuf, absoluteFile, kBufLen - strlen(nameBuf));
140

141
    ALOGV("Cache file for '%s' '%s' is '%s'", fileName, subFileName, nameBuf);
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    return strdup(nameBuf);
}

/*
 * Create a skeletal "opt" header in a new file.  Most of the fields are
 * initialized to garbage, but we fill in "dexOffset" so others can
 * see how large the header is.
 *
 * "fd" must be positioned at the start of the file.  On return, it will
 * be positioned just past the header, and the place where the DEX data
 * should go.
 *
 * Returns 0 on success, errno on failure.
 */
int dexOptCreateEmptyHeader(int fd)
{
    DexOptHeader optHdr;
    ssize_t actual;

    assert(lseek(fd, 0, SEEK_CUR) == 0);

    /*
     * The data is only expected to be readable on the current system, so
     * we just write the structure.  We do need the file offset to be 64-bit
     * aligned to fulfill a DEX requirement.
     */
    assert((sizeof(optHdr) & 0x07) == 0);
    memset(&optHdr, 0xff, sizeof(optHdr));
    optHdr.dexOffset = sizeof(optHdr);
    actual = write(fd, &optHdr, sizeof(optHdr));
    if (actual != sizeof(optHdr)) {
        int err = errno ? errno : -1;
174
        ALOGE("opt header write failed: %s", strerror(errno));
175 176 177 178 179
        return errno;
    }

    return 0;
}