summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Bornstein <danfuzz@android.com>2010-12-16 12:59:56 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2010-12-16 12:59:56 -0800
commitb6959072254ff85d79817b0b542d78d61dc06a1c (patch)
tree28d01995c4c9b4b93755266716e7daf37155e157
parentbfac08e47db21634161398169e638d8b6fbd7373 (diff)
parenteab7355f9280dabcfe62fa2f21ca4e5511a59a24 (diff)
downloadandroid_dalvik-b6959072254ff85d79817b0b542d78d61dc06a1c.tar.gz
android_dalvik-b6959072254ff85d79817b0b542d78d61dc06a1c.tar.bz2
android_dalvik-b6959072254ff85d79817b0b542d78d61dc06a1c.zip
am eab7355f: Hook up the preexisting RawDexFile opener.
* commit 'eab7355f9280dabcfe62fa2f21ca4e5511a59a24': Hook up the preexisting RawDexFile opener.
-rw-r--r--vm/JarFile.c9
-rw-r--r--vm/RawDexFile.c262
-rw-r--r--vm/native/dalvik_system_DexFile.c18
3 files changed, 283 insertions, 6 deletions
diff --git a/vm/JarFile.c b/vm/JarFile.c
index 919787629..8b13e6a4e 100644
--- a/vm/JarFile.c
+++ b/vm/JarFile.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Access the contents of a Jar file.
*
@@ -20,6 +21,7 @@
* just wants a zip archive with "classes.dex" inside. In Android the
* most common example is ".apk".
*/
+
#include "Dalvik.h"
#include "libdex/OptInvocation.h"
@@ -186,6 +188,11 @@ bail:
int dvmJarFileOpen(const char* fileName, const char* odexOutputName,
JarFile** ppJarFile, bool isBootstrap)
{
+ /*
+ * TODO: This function has been duplicated and modified to become
+ * dvmRawDexFileOpen() in RawDexFile.c. This should be refactored.
+ */
+
ZipArchive archive;
DvmDex* pDvmDex = NULL;
char* cachedName = NULL;
@@ -254,7 +261,7 @@ tryArchive:
} else {
cachedName = strdup(odexOutputName);
}
- LOGV("dvmDexCacheStatus: Checking cache for %s (%s)\n",
+ LOGV("dvmJarFileOpen: Checking cache for %s (%s)\n",
fileName, cachedName);
fd = dvmOpenCachedDexFile(fileName, cachedName,
dexGetZipEntryModTime(&archive, entry),
diff --git a/vm/RawDexFile.c b/vm/RawDexFile.c
index 62e67100e..1d8784ca0 100644
--- a/vm/RawDexFile.c
+++ b/vm/RawDexFile.c
@@ -17,14 +17,272 @@
/*
* Open an unoptimized DEX file.
*/
+
#include "Dalvik.h"
+#include "libdex/OptInvocation.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ * Copy the given number of bytes from one fd to another, first
+ * seeking the source fd to the start of the file.
+ */
+static int copyFileToFile(int destFd, int srcFd, u4 size)
+{
+ u1* buf = malloc(size);
+ int result = -1;
+ ssize_t amt;
+
+ if (buf == NULL) {
+ LOGE("malloc failure (errno %d)\n", errno);
+ goto bail;
+ }
+
+ if (lseek(srcFd, 0, SEEK_SET) != 0) {
+ LOGE("lseek failure (errno %d)\n", errno);
+ goto bail;
+ }
+
+ amt = read(srcFd, buf, size);
+
+ if (amt < 0) {
+ LOGE("read failure (errno %d)\n", errno);
+ goto bail;
+ }
+
+ if (amt != (ssize_t) size) {
+ LOGE("short read (%d < %ud)\n", (int) amt, size);
+ goto bail;
+ }
+
+ amt = write(destFd, buf, size);
+
+ if (amt < 0) {
+ LOGE("write failure (errno %d)\n", errno);
+ goto bail;
+ }
+
+ if (amt != (ssize_t) size) {
+ LOGE("short write (%d < %ud)\n", (int) amt, size);
+ goto bail;
+ }
+
+ result = 0; // Success!
+
+bail:
+ free(buf);
+ return result;
+}
+
+/*
+ * Get the modification time and size in bytes for the given fd.
+ */
+static int getModTimeAndSize(int fd, u4* modTime, u4* size)
+{
+ struct stat buf;
+ int result = fstat(fd, &buf);
+
+ if (result < 0) {
+ LOGE("Unable to determing mod time (errno %d)\n", errno);
+ return -1;
+ }
+
+ *modTime = (u4) buf.st_mtime;
+ *size = (u4) buf.st_size;
+
+ return 0;
+}
+
+/*
+ * Verify the dex file magic number, and get the adler32 checksum out
+ * of the given fd, which is presumed to be a reference to a dex file
+ * with the cursor at the start of the file. The fd's cursor is
+ * modified by this operation.
+ */
+static int verifyMagicAndGetAdler32(int fd, u4 *adler32)
+{
+ /*
+ * The start of a dex file is eight bytes of magic followed by
+ * four bytes of checksum.
+ */
+ u1 headerStart[12];
+ ssize_t amt = read(fd, headerStart, sizeof(headerStart));
+
+ if (amt < 0) {
+ LOGE("Unable to read header (errno %d)\n", errno);
+ return -1;
+ }
+
+ if (amt != sizeof(headerStart)) {
+ LOGE("Unable to read full header (only got %d bytes)\n", (int) amt);
+ return -1;
+ }
+
+ if (memcmp(headerStart, DEX_MAGIC DEX_MAGIC_VERS, 8) != 0) {
+ LOGE("Unexpected dex magic (0x%02x%02x%02x%02x%02x%02x%02x%02x)\n",
+ headerStart[0], headerStart[1], headerStart[2],
+ headerStart[3], headerStart[4], headerStart[5],
+ headerStart[6], headerStart[7]);
+ return -1;
+ }
+
+ /*
+ * We can't just cast the data to a u4 and read it, since the
+ * platform might be big-endian (also, because that would make the
+ * compiler complain about type-punned pointers). We assume here
+ * that the dex file is in the standard little-endian format; if
+ * that assumption turns out to be invalid, code that runs later
+ * will notice and complain.
+ */
+ *adler32 = (u4) headerStart[8]
+ | (((u4) headerStart[9]) << 8)
+ | (((u4) headerStart[10]) << 16)
+ | (((u4) headerStart[11]) << 24);
+
+ return 0;
+}
/* See documentation comment in header. */
int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
RawDexFile** ppRawDexFile, bool isBootstrap)
{
- // TODO - should be very similar to what JarFile does.
- return -1;
+ /*
+ * TODO: This duplicates a lot of code from dvmJarFileOpen() in
+ * JarFile.c. This should be refactored.
+ */
+
+ DvmDex* pDvmDex = NULL;
+ char* cachedName = NULL;
+ int result = -1;
+ int dexFd = -1;
+ int optFd = -1;
+ u4 modTime = 0;
+ u4 adler32 = 0;
+ u4 fileSize = 0;
+ bool newFile = false;
+ bool locked = false;
+
+ dexFd = open(fileName, O_RDONLY);
+ if (dexFd < 0) goto bail;
+
+ /* If we fork/exec into dexopt, don't let it inherit the open fd. */
+ dvmSetCloseOnExec(dexFd);
+
+ if (verifyMagicAndGetAdler32(dexFd, &adler32) < 0) {
+ LOGE("Error with header for %s\n", fileName);
+ goto bail;
+ }
+
+ if (getModTimeAndSize(dexFd, &modTime, &fileSize) < 0) {
+ LOGE("Error with stat for %s\n", fileName);
+ goto bail;
+ }
+
+ /*
+ * See if the cached file matches. If so, optFd will become a reference
+ * to the cached file and will have been seeked to just past the "opt"
+ * header.
+ */
+
+ if (odexOutputName == NULL) {
+ cachedName = dexOptGenerateCacheFileName(fileName, NULL);
+ if (cachedName == NULL)
+ goto bail;
+ } else {
+ cachedName = strdup(odexOutputName);
+ }
+
+ LOGV("dvmRawDexFileOpen: Checking cache for %s (%s)\n",
+ fileName, cachedName);
+
+ optFd = dvmOpenCachedDexFile(fileName, cachedName, modTime,
+ adler32, isBootstrap, &newFile, /*createIfMissing=*/true);
+
+ if (optFd < 0) {
+ LOGI("Unable to open or create cache for %s (%s)\n",
+ fileName, cachedName);
+ goto bail;
+ }
+ locked = true;
+
+ /*
+ * If optFd points to a new file (because there was no cached
+ * version, or the cached version was stale), generate the
+ * optimized DEX. The file descriptor returned is still locked,
+ * and is positioned just past the optimization header.
+ */
+ if (newFile) {
+ u8 startWhen, copyWhen, endWhen;
+ bool result;
+ off_t dexOffset;
+
+ dexOffset = lseek(optFd, 0, SEEK_CUR);
+ result = (dexOffset > 0);
+
+ if (result) {
+ startWhen = dvmGetRelativeTimeUsec();
+ result = copyFileToFile(optFd, dexFd, fileSize) == 0;
+ copyWhen = dvmGetRelativeTimeUsec();
+ }
+
+ if (result) {
+ result = dvmOptimizeDexFile(optFd, dexOffset, fileSize,
+ fileName, modTime, adler32, isBootstrap);
+ }
+
+ if (!result) {
+ LOGE("Unable to extract+optimize DEX from '%s'\n", fileName);
+ goto bail;
+ }
+
+ endWhen = dvmGetRelativeTimeUsec();
+ LOGD("DEX prep '%s': copy in %dms, rewrite %dms\n",
+ fileName,
+ (int) (copyWhen - startWhen) / 1000,
+ (int) (endWhen - copyWhen) / 1000);
+ }
+
+ /*
+ * Map the cached version. This immediately rewinds the fd, so it
+ * doesn't have to be seeked anywhere in particular.
+ */
+ if (dvmDexFileOpenFromFd(optFd, &pDvmDex) != 0) {
+ LOGI("Unable to map cached %s\n", fileName);
+ goto bail;
+ }
+
+ if (locked) {
+ /* unlock the fd */
+ if (!dvmUnlockCachedDexFile(optFd)) {
+ /* uh oh -- this process needs to exit or we'll wedge the system */
+ LOGE("Unable to unlock DEX file\n");
+ goto bail;
+ }
+ locked = false;
+ }
+
+ LOGV("Successfully opened '%s'\n", fileName);
+
+ *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
+ (*ppRawDexFile)->cacheFileName = cachedName;
+ (*ppRawDexFile)->pDvmDex = pDvmDex;
+ cachedName = NULL; // don't free it below
+ result = 0;
+
+bail:
+ free(cachedName);
+ if (dexFd >= 0) {
+ close(dexFd);
+ }
+ if (optFd >= 0) {
+ if (locked)
+ (void) dvmUnlockCachedDexFile(optFd);
+ close(optFd);
+ }
+ return result;
}
/* See documentation comment in header. */
diff --git a/vm/native/dalvik_system_DexFile.c b/vm/native/dalvik_system_DexFile.c
index 59f5d57fc..7c601d841 100644
--- a/vm/native/dalvik_system_DexFile.c
+++ b/vm/native/dalvik_system_DexFile.c
@@ -20,6 +20,16 @@
#include "Dalvik.h"
#include "native/InternalNativePriv.h"
+/*
+ * Return true if the given name ends with ".dex".
+ */
+static bool hasDexExtension(const char* name) {
+ size_t len = strlen(name);
+
+ return (len >= 5)
+ && (name[len - 5] != '/')
+ && (strcmp(&name[len - 4], ".dex") == 0);
+}
/*
* Internal struct for managing DexFile.
@@ -191,10 +201,12 @@ static void Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,
}
/*
- * Try to open it directly as a DEX. If that fails, try it as a Zip
- * with a "classes.dex" inside.
+ * Try to open it directly as a DEX if the name ends with ".dex".
+ * If that fails (or isn't tried in the first place), try it as a
+ * Zip with a "classes.dex" inside.
*/
- if (dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
+ if (hasDexExtension(sourceName)
+ && dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
LOGV("Opening DEX file '%s' (DEX)\n", sourceName);
pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));