Merge "Fix libutils dependencies for dexdump & dexlist."
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
index a6c9545..6041846 100644
--- a/dexdump/Android.mk
+++ b/dexdump/Android.mk
@@ -24,7 +24,8 @@
dalvik
dexdump_static_libraries := \
- libdex
+ libdex \
+ libutils
##
##
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
index 5c3be63..7012c7d 100644
--- a/dexlist/Android.mk
+++ b/dexlist/Android.mk
@@ -24,7 +24,8 @@
dalvik
dexdump_static_libraries := \
- libdex
+ libdex \
+ libutils
include $(CLEAR_VARS)
LOCAL_MODULE := dexlist
diff --git a/dexopt/OptMain.cpp b/dexopt/OptMain.cpp
index 3cdf5be..f948ff4 100644
--- a/dexopt/OptMain.cpp
+++ b/dexopt/OptMain.cpp
@@ -58,10 +58,8 @@
const char* debugFileName, bool isBootstrap, const char* bootClassPath,
const char* dexoptFlagStr)
{
- ZipArchive zippy;
+ ZipArchiveHandle zippy;
ZipEntry zipEntry;
- size_t uncompLen;
- long modWhen, crc32;
off_t dexOffset;
int err;
int result = -1;
@@ -69,8 +67,6 @@
DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;
DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;
- memset(&zippy, 0, sizeof(zippy));
-
/* make sure we're still at the start of an empty file */
if (lseek(cacheFd, 0, SEEK_END) != 0) {
ALOGE("DexOptZ: new cache file '%s' is not empty", debugFileName);
@@ -93,36 +89,21 @@
/*
* Open the zip archive, find the DEX entry.
*/
- if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) {
+ if (dexZipOpenArchiveFd(zipFd, debugFileName, &zippy) != 0) {
ALOGW("DexOptZ: unable to open zip archive '%s'", debugFileName);
goto bail;
}
- zipEntry = dexZipFindEntry(&zippy, kClassesDex);
- if (zipEntry == NULL) {
+ if (dexZipFindEntry(zippy, kClassesDex, &zipEntry) != 0) {
ALOGW("DexOptZ: zip archive '%s' does not include %s",
debugFileName, kClassesDex);
goto bail;
}
/*
- * Extract some info about the zip entry.
- */
- if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
- &modWhen, &crc32) != 0)
- {
- ALOGW("DexOptZ: zip archive GetEntryInfo failed on %s", debugFileName);
- goto bail;
- }
-
- uncompLen = uncompLen;
- modWhen = modWhen;
- crc32 = crc32;
-
- /*
* Extract the DEX data into the cache file at the current offset.
*/
- if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {
+ if (dexZipExtractEntryToFile(zippy, &zipEntry, cacheFd) != 0) {
ALOGW("DexOptZ: extraction of %s from %s failed",
kClassesDex, debugFileName);
goto bail;
@@ -183,8 +164,9 @@
//vmStarted = 1;
/* do the optimization */
- if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,
- modWhen, crc32, isBootstrap))
+ if (!dvmContinueOptimization(cacheFd, dexOffset,
+ zipEntry.uncompressed_length, debugFileName,
+ zipEntry.mod_time, zipEntry.crc32, isBootstrap))
{
ALOGE("Optimization failed");
goto bail;
@@ -195,7 +177,7 @@
result = 0;
bail:
- dexZipCloseArchive(&zippy);
+ dexZipCloseArchive(zippy);
return result;
}
diff --git a/libdex/Android.mk b/libdex/Android.mk
index 7ab0013..0a46396 100644
--- a/libdex/Android.mk
+++ b/libdex/Android.mk
@@ -32,7 +32,6 @@
OptInvocation.cpp \
sha1.cpp \
SysUtil.cpp \
- ZipArchive.cpp
dex_include_files := \
dalvik \
@@ -51,6 +50,8 @@
LOCAL_SRC_FILES := $(dex_src_files)
LOCAL_C_INCLUDES += $(dex_include_files)
LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_WHOLE_STATIC_LIBRARIES := libziparchive
+LOCAL_SHARED_LIBRARIES := libutils
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libdex
include $(BUILD_STATIC_LIBRARY)
@@ -66,7 +67,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(dex_src_files)
LOCAL_C_INCLUDES += $(dex_include_files)
-LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := liblog libutils
+LOCAL_WHOLE_STATIC_LIBRARIES := libziparchive-host
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libdex
include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libdex/CmdUtils.cpp b/libdex/CmdUtils.cpp
index ff737a3..bf89444 100644
--- a/libdex/CmdUtils.cpp
+++ b/libdex/CmdUtils.cpp
@@ -40,7 +40,7 @@
{
UnzipToFileResult result = kUTFRSuccess;
static const char* kFileToExtract = "classes.dex";
- ZipArchive archive;
+ ZipArchiveHandle archive;
ZipEntry entry;
bool unlinkOnFailure = false;
int fd = -1;
@@ -64,8 +64,7 @@
unlinkOnFailure = true;
- entry = dexZipFindEntry(&archive, kFileToExtract);
- if (entry == NULL) {
+ if (dexZipFindEntry(archive, kFileToExtract, &entry) != 0) {
if (!quiet) {
fprintf(stderr, "Unable to find '%s' in '%s'\n",
kFileToExtract, zipFileName);
@@ -74,7 +73,7 @@
goto bail;
}
- if (dexZipExtractEntryToFile(&archive, entry, fd) != 0) {
+ if (dexZipExtractEntryToFile(archive, &entry, fd) != 0) {
fprintf(stderr, "Extract of '%s' from '%s' failed\n",
kFileToExtract, zipFileName);
result = kUTFRBadZip;
diff --git a/libdex/ZipArchive.cpp b/libdex/ZipArchive.cpp
deleted file mode 100644
index f70a5df..0000000
--- a/libdex/ZipArchive.cpp
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Read-only access to Zip archives, with minimal heap allocation.
- */
-#include "ZipArchive.h"
-
-#include <zlib.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd
-#include <utils/Compat.h> // For off64_t and lseek64 on Mac
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-/*
- * Zip file constants.
- */
-#define kEOCDSignature 0x06054b50
-#define kEOCDLen 22
-#define kEOCDDiskNumber 4 // number of the current disk
-#define kEOCDDiskNumberForCD 6 // disk number with the Central Directory
-#define kEOCDNumEntries 8 // offset to #of entries in file
-#define kEOCDTotalNumEntries 10 // offset to total #of entries in spanned archives
-#define kEOCDSize 12 // size of the central directory
-#define kEOCDFileOffset 16 // offset to central directory
-#define kEOCDCommentSize 20 // offset to the length of the file comment
-
-#define kMaxCommentLen 65535 // longest possible in ushort
-#define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen)
-
-#define kLFHSignature 0x04034b50
-#define kLFHLen 30 // excluding variable-len fields
-#define kLFHGPBFlags 6 // offset to GPB flags
-#define kLFHNameLen 26 // offset to filename length
-#define kLFHExtraLen 28 // offset to extra length
-
-#define kCDESignature 0x02014b50
-#define kCDELen 46 // excluding variable-len fields
-#define kCDEGPBFlags 8 // offset to GPB flags
-#define kCDEMethod 10 // offset to compression method
-#define kCDEModWhen 12 // offset to modification timestamp
-#define kCDECRC 16 // offset to entry CRC
-#define kCDECompLen 20 // offset to compressed length
-#define kCDEUncompLen 24 // offset to uncompressed length
-#define kCDENameLen 28 // offset to filename length
-#define kCDEExtraLen 30 // offset to extra length
-#define kCDECommentLen 32 // offset to comment length
-#define kCDELocalOffset 42 // offset to local hdr
-
-/* General Purpose Bit Flag */
-#define kGPFEncryptedFlag (1 << 0)
-#define kGPFUnsupportedMask (kGPFEncryptedFlag)
-
-/*
- * The values we return for ZipEntryRO use 0 as an invalid value, so we
- * want to adjust the hash table index by a fixed amount. Using a large
- * value helps insure that people don't mix & match arguments, e.g. to
- * findEntryByIndex().
- */
-#define kZipEntryAdj 10000
-
-/*
- * Convert a ZipEntry to a hash table index, verifying that it's in a
- * valid range.
- */
-static int entryToIndex(const ZipArchive* pArchive, const ZipEntry entry)
-{
- long ent = ((long) entry) - kZipEntryAdj;
- if (ent < 0 || ent >= pArchive->mHashTableSize ||
- pArchive->mHashTable[ent].name == NULL)
- {
- ALOGW("Zip: invalid ZipEntry %p (%ld)", entry, ent);
- return -1;
- }
- return ent;
-}
-
-/*
- * Simple string hash function for non-null-terminated strings.
- */
-static unsigned int computeHash(const char* str, int len)
-{
- unsigned int hash = 0;
-
- while (len--)
- hash = hash * 31 + *str++;
-
- return hash;
-}
-
-/*
- * Add a new entry to the hash table.
- */
-static void addToHash(ZipArchive* pArchive, const char* str, int strLen,
- unsigned int hash)
-{
- const int hashTableSize = pArchive->mHashTableSize;
- int ent = hash & (hashTableSize - 1);
-
- /*
- * We over-allocated the table, so we're guaranteed to find an empty slot.
- */
- while (pArchive->mHashTable[ent].name != NULL)
- ent = (ent + 1) & (hashTableSize-1);
-
- pArchive->mHashTable[ent].name = str;
- pArchive->mHashTable[ent].nameLen = strLen;
-}
-
-/*
- * Get 2 little-endian bytes.
- */
-static u2 get2LE(unsigned char const* pSrc)
-{
- return pSrc[0] | (pSrc[1] << 8);
-}
-
-/*
- * Get 4 little-endian bytes.
- */
-static u4 get4LE(unsigned char const* pSrc)
-{
- u4 result;
-
- result = pSrc[0];
- result |= pSrc[1] << 8;
- result |= pSrc[2] << 16;
- result |= pSrc[3] << 24;
-
- return result;
-}
-
-static int mapCentralDirectory0(int fd, const char* debugFileName,
- ZipArchive* pArchive, off64_t fileLength, size_t readAmount, u1* scanBuf)
-{
- /*
- * Make sure this is a Zip archive.
- */
- if (lseek64(pArchive->mFd, 0, SEEK_SET) != 0) {
- ALOGW("seek to start failed: %s", strerror(errno));
- return false;
- }
-
- ssize_t actual = TEMP_FAILURE_RETRY(read(pArchive->mFd, scanBuf, sizeof(int32_t)));
- if (actual != (ssize_t) sizeof(int32_t)) {
- ALOGI("couldn't read first signature from zip archive: %s", strerror(errno));
- return false;
- }
-
- unsigned int header = get4LE(scanBuf);
- if (header != kLFHSignature) {
- ALOGV("Not a Zip archive (found 0x%08x)\n", header);
- return false;
- }
-
- /*
- * Perform the traditional EOCD snipe hunt.
- *
- * We're searching for the End of Central Directory magic number,
- * which appears at the start of the EOCD block. It's followed by
- * 18 bytes of EOCD stuff and up to 64KB of archive comment. We
- * need to read the last part of the file into a buffer, dig through
- * it to find the magic number, parse some values out, and use those
- * to determine the extent of the CD.
- *
- * We start by pulling in the last part of the file.
- */
- off64_t searchStart = fileLength - readAmount;
-
- if (lseek64(pArchive->mFd, searchStart, SEEK_SET) != searchStart) {
- ALOGW("seek %ld failed: %s\n", (long) searchStart, strerror(errno));
- return false;
- }
- actual = TEMP_FAILURE_RETRY(read(pArchive->mFd, scanBuf, readAmount));
- if (actual != (ssize_t) readAmount) {
- ALOGW("Zip: read %zd, expected %zd. Failed: %s\n",
- actual, readAmount, strerror(errno));
- return false;
- }
-
-
- /*
- * Scan backward for the EOCD magic. In an archive without a trailing
- * comment, we'll find it on the first try. (We may want to consider
- * doing an initial minimal read; if we don't find it, retry with a
- * second read as above.)
- */
- int i;
- for (i = readAmount - kEOCDLen; i >= 0; i--) {
- if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
- ALOGV("+++ Found EOCD at buf+%d", i);
- break;
- }
- }
- if (i < 0) {
- ALOGD("Zip: EOCD not found, %s is not zip", debugFileName);
- return -1;
- }
-
- off64_t eocdOffset = searchStart + i;
- const u1* eocdPtr = scanBuf + i;
-
- assert(eocdOffset < fileLength);
-
- /*
- * Grab the CD offset and size, and the number of entries in the
- * archive. Verify that they look reasonable.
- */
- u4 diskNumber = get2LE(eocdPtr + kEOCDDiskNumber);
- u4 diskWithCentralDir = get2LE(eocdPtr + kEOCDDiskNumberForCD);
- u4 numEntries = get2LE(eocdPtr + kEOCDNumEntries);
- u4 totalNumEntries = get2LE(eocdPtr + kEOCDTotalNumEntries);
- u4 centralDirSize = get4LE(eocdPtr + kEOCDSize);
- u4 centralDirOffset = get4LE(eocdPtr + kEOCDFileOffset);
- u4 commentSize = get2LE(eocdPtr + kEOCDCommentSize);
-
- // Verify that they look reasonable.
- if ((long long) centralDirOffset + (long long) centralDirSize > (long long) eocdOffset) {
- ALOGW("bad offsets (dir %ld, size %u, eocd %ld)\n",
- (long) centralDirOffset, centralDirSize, (long) eocdOffset);
- return false;
- }
- if (numEntries == 0) {
- ALOGW("empty archive?\n");
- return false;
- } else if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
- ALOGW("spanned archives not supported");
- return false;
- }
-
- // Check to see if comment is a sane size
- if (((size_t) commentSize > (fileLength - kEOCDLen))
- || (eocdOffset > (fileLength - kEOCDLen) - commentSize)) {
- ALOGW("comment size runs off end of file");
- return false;
- }
-
- ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
- numEntries, centralDirSize, centralDirOffset);
-
- /*
- * It all looks good. Create a mapping for the CD, and set the fields
- * in pArchive.
- */
- if (sysMapFileSegmentInShmem(fd, centralDirOffset, centralDirSize,
- &pArchive->mDirectoryMap) != 0)
- {
- ALOGW("Zip: cd map failed");
- return -1;
- }
-
- pArchive->mNumEntries = numEntries;
- pArchive->mDirectoryOffset = centralDirOffset;
-
- return 0;
-}
-
-/*
- * Find the zip Central Directory and memory-map it.
- *
- * On success, returns 0 after populating fields from the EOCD area:
- * mDirectoryOffset
- * mDirectoryMap
- * mNumEntries
- */
-static int mapCentralDirectory(int fd, const char* debugFileName,
- ZipArchive* pArchive)
-{
- /*
- * Get and test file length.
- */
- off64_t fileLength = lseek64(fd, 0, SEEK_END);
- if (fileLength < kEOCDLen) {
- ALOGV("Zip: length %ld is too small to be zip", (long) fileLength);
- return -1;
- }
-
- /*
- * Perform the traditional EOCD snipe hunt.
- *
- * We're searching for the End of Central Directory magic number,
- * which appears at the start of the EOCD block. It's followed by
- * 18 bytes of EOCD stuff and up to 64KB of archive comment. We
- * need to read the last part of the file into a buffer, dig through
- * it to find the magic number, parse some values out, and use those
- * to determine the extent of the CD.
- *
- * We start by pulling in the last part of the file.
- */
- size_t readAmount = kMaxEOCDSearch;
- if (fileLength < off_t(readAmount))
- readAmount = fileLength;
-
- u1* scanBuf = (u1*) malloc(readAmount);
- if (scanBuf == NULL) {
- return -1;
- }
-
- int result = mapCentralDirectory0(fd, debugFileName, pArchive,
- fileLength, readAmount, scanBuf);
-
- free(scanBuf);
- return result;
-}
-
-/*
- * Parses the Zip archive's Central Directory. Allocates and populates the
- * hash table.
- *
- * Returns 0 on success.
- */
-static int parseZipArchive(ZipArchive* pArchive)
-{
- int result = -1;
- const u1* cdPtr = (const u1*)pArchive->mDirectoryMap.addr;
- size_t cdLength = pArchive->mDirectoryMap.length;
- int numEntries = pArchive->mNumEntries;
-
- /*
- * Create hash table. We have a minimum 75% load factor, possibly as
- * low as 50% after we round off to a power of 2. There must be at
- * least one unused entry to avoid an infinite loop during creation.
- */
- pArchive->mHashTableSize = dexRoundUpPower2(1 + (numEntries * 4) / 3);
- pArchive->mHashTable = (ZipHashEntry*)
- calloc(pArchive->mHashTableSize, sizeof(ZipHashEntry));
-
- /*
- * Walk through the central directory, adding entries to the hash
- * table and verifying values.
- */
- const u1* ptr = cdPtr;
- int i;
- for (i = 0; i < numEntries; i++) {
- if (get4LE(ptr) != kCDESignature) {
- ALOGW("Zip: missed a central dir sig (at %d)", i);
- goto bail;
- }
- if (ptr + kCDELen > cdPtr + cdLength) {
- ALOGW("Zip: ran off the end (at %d)", i);
- goto bail;
- }
-
- long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
- if (localHdrOffset >= pArchive->mDirectoryOffset) {
- ALOGW("Zip: bad LFH offset %ld at entry %d", localHdrOffset, i);
- goto bail;
- }
-
- unsigned int gpbf = get2LE(ptr + kCDEGPBFlags);
- if ((gpbf & kGPFUnsupportedMask) != 0) {
- ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
- goto bail;
- }
-
- unsigned int nameLen, extraLen, commentLen, hash;
- nameLen = get2LE(ptr + kCDENameLen);
- extraLen = get2LE(ptr + kCDEExtraLen);
- commentLen = get2LE(ptr + kCDECommentLen);
-
- const char *name = (const char *) ptr + kCDELen;
-
- /* Check name for NULL characters */
- if (memchr(name, 0, nameLen) != NULL) {
- ALOGW("Filename contains NUL byte");
- goto bail;
- }
-
- /* add the CDE filename to the hash table */
- hash = computeHash(name, nameLen);
- addToHash(pArchive, name, nameLen, hash);
-
- /* We don't care about the comment or extra data. */
- ptr += kCDELen + nameLen + extraLen + commentLen;
- if ((size_t)(ptr - cdPtr) > cdLength) {
- ALOGW("Zip: bad CD advance (%d vs %zd) at entry %d",
- (int) (ptr - cdPtr), cdLength, i);
- goto bail;
- }
- }
- ALOGV("+++ zip good scan %d entries", numEntries);
-
- result = 0;
-
-bail:
- return result;
-}
-
-/*
- * Open the specified file read-only. We examine the contents and verify
- * that it appears to be a valid zip file.
- *
- * This will be called on non-Zip files, especially during VM startup, so
- * we don't want to be too noisy about certain types of failure. (Do
- * we want a "quiet" flag?)
- *
- * On success, we fill out the contents of "pArchive" and return 0. On
- * failure we return the errno value.
- */
-int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive)
-{
- int fd, err;
-
- ALOGV("Opening as zip '%s' %p", fileName, pArchive);
-
- memset(pArchive, 0, sizeof(ZipArchive));
-
- fd = open(fileName, O_RDONLY | O_BINARY, 0);
- if (fd < 0) {
- err = errno ? errno : -1;
- ALOGV("Unable to open '%s': %s", fileName, strerror(err));
- return err;
- }
-
- return dexZipPrepArchive(fd, fileName, pArchive);
-}
-
-/*
- * Prepare to access a ZipArchive through an open file descriptor.
- *
- * On success, we fill out the contents of "pArchive" and return 0.
- */
-int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive)
-{
- int result = -1;
-
- memset(pArchive, 0, sizeof(*pArchive));
- pArchive->mFd = fd;
-
- if (mapCentralDirectory(fd, debugFileName, pArchive) != 0)
- goto bail;
-
- if (parseZipArchive(pArchive) != 0) {
- ALOGV("Zip: parsing '%s' failed", debugFileName);
- goto bail;
- }
-
- /* success */
- result = 0;
-
-bail:
- if (result != 0)
- dexZipCloseArchive(pArchive);
- return result;
-}
-
-
-/*
- * Close a ZipArchive, closing the file and freeing the contents.
- *
- * NOTE: the ZipArchive may not have been fully created.
- */
-void dexZipCloseArchive(ZipArchive* pArchive)
-{
- ALOGV("Closing archive %p", pArchive);
-
- if (pArchive->mFd >= 0)
- close(pArchive->mFd);
-
- sysReleaseShmem(&pArchive->mDirectoryMap);
-
- free(pArchive->mHashTable);
-
- /* ensure nobody tries to use the ZipArchive after it's closed */
- pArchive->mDirectoryOffset = -1;
- pArchive->mFd = -1;
- pArchive->mNumEntries = -1;
- pArchive->mHashTableSize = -1;
- pArchive->mHashTable = NULL;
-}
-
-
-/*
- * Find a matching entry.
- *
- * Returns 0 if not found.
- */
-ZipEntry dexZipFindEntry(const ZipArchive* pArchive, const char* entryName)
-{
- int nameLen = strlen(entryName);
- unsigned int hash = computeHash(entryName, nameLen);
- const int hashTableSize = pArchive->mHashTableSize;
- int ent = hash & (hashTableSize-1);
-
- while (pArchive->mHashTable[ent].name != NULL) {
- if (pArchive->mHashTable[ent].nameLen == nameLen &&
- memcmp(pArchive->mHashTable[ent].name, entryName, nameLen) == 0)
- {
- /* match */
- return (ZipEntry)(long)(ent + kZipEntryAdj);
- }
-
- ent = (ent + 1) & (hashTableSize-1);
- }
-
- return NULL;
-}
-
-#if 0
-/*
- * Find the Nth entry.
- *
- * This currently involves walking through the sparse hash table, counting
- * non-empty entries. If we need to speed this up we can either allocate
- * a parallel lookup table or (perhaps better) provide an iterator interface.
- */
-ZipEntry findEntryByIndex(ZipArchive* pArchive, int idx)
-{
- if (idx < 0 || idx >= pArchive->mNumEntries) {
- ALOGW("Invalid index %d", idx);
- return NULL;
- }
-
- int ent;
- for (ent = 0; ent < pArchive->mHashTableSize; ent++) {
- if (pArchive->mHashTable[ent].name != NULL) {
- if (idx-- == 0)
- return (ZipEntry) (ent + kZipEntryAdj);
- }
- }
-
- return NULL;
-}
-#endif
-
-/*
- * Get the useful fields from the zip entry.
- *
- * Returns non-zero if the contents of the fields (particularly the data
- * offset) appear to be bogus.
- */
-int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
- int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
- long* pModWhen, long* pCrc32)
-{
- int ent = entryToIndex(pArchive, entry);
- if (ent < 0)
- return -1;
-
- /*
- * Recover the start of the central directory entry from the filename
- * pointer. The filename is the first entry past the fixed-size data,
- * so we can just subtract back from that.
- */
- const unsigned char* basePtr = (const unsigned char*)
- pArchive->mDirectoryMap.addr;
- const unsigned char* ptr = (const unsigned char*)
- pArchive->mHashTable[ent].name;
- off_t cdOffset = pArchive->mDirectoryOffset;
-
- ptr -= kCDELen;
-
- int method = get2LE(ptr + kCDEMethod);
- if (pMethod != NULL)
- *pMethod = method;
-
- if (pModWhen != NULL)
- *pModWhen = get4LE(ptr + kCDEModWhen);
- if (pCrc32 != NULL)
- *pCrc32 = get4LE(ptr + kCDECRC);
-
- size_t compLen = get4LE(ptr + kCDECompLen);
- if (pCompLen != NULL)
- *pCompLen = compLen;
- size_t uncompLen = get4LE(ptr + kCDEUncompLen);
- if (pUncompLen != NULL)
- *pUncompLen = uncompLen;
-
- /*
- * If requested, determine the offset of the start of the data. All we
- * have is the offset to the Local File Header, which is variable size,
- * so we have to read the contents of the struct to figure out where
- * the actual data starts.
- *
- * We also need to make sure that the lengths are not so large that
- * somebody trying to map the compressed or uncompressed data runs
- * off the end of the mapped region.
- *
- * Note we don't verify compLen/uncompLen if they don't request the
- * dataOffset, because dataOffset is expensive to determine. However,
- * if they don't have the file offset, they're not likely to be doing
- * anything with the contents.
- */
- if (pOffset != NULL) {
- long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
- if (localHdrOffset + kLFHLen >= cdOffset) {
- ALOGW("Zip: bad local hdr offset in zip");
- return -1;
- }
-
- u1 lfhBuf[kLFHLen];
- if (lseek(pArchive->mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
- ALOGW("Zip: failed seeking to lfh at offset %ld", localHdrOffset);
- return -1;
- }
- ssize_t actual =
- TEMP_FAILURE_RETRY(read(pArchive->mFd, lfhBuf, sizeof(lfhBuf)));
- if (actual != sizeof(lfhBuf)) {
- ALOGW("Zip: failed reading lfh from offset %ld", localHdrOffset);
- return -1;
- }
-
- if (get4LE(lfhBuf) != kLFHSignature) {
- ALOGW("Zip: didn't find signature at start of lfh, offset=%ld",
- localHdrOffset);
- return -1;
- }
-
- u4 gpbf = get2LE(lfhBuf + kLFHGPBFlags);
- if ((gpbf & kGPFUnsupportedMask) != 0) {
- ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
- return -1;
- }
-
- off64_t dataOffset = localHdrOffset + kLFHLen
- + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
- if (dataOffset >= cdOffset) {
- ALOGW("Zip: bad data offset %ld in zip", (long) dataOffset);
- return -1;
- }
-
- /* check lengths */
- if ((off_t)(dataOffset + compLen) > cdOffset) {
- ALOGW("Zip: bad compressed length in zip (%ld + %zd > %ld)",
- (long) dataOffset, compLen, (long) cdOffset);
- return -1;
- }
-
- if (method == kCompressStored &&
- (off_t)(dataOffset + uncompLen) > cdOffset)
- {
- ALOGW("Zip: bad uncompressed length in zip (%ld + %zd > %ld)",
- (long) dataOffset, uncompLen, (long) cdOffset);
- return -1;
- }
-
- *pOffset = dataOffset;
- }
- return 0;
-}
-
-/*
- * Uncompress "deflate" data from the archive's file to an open file
- * descriptor.
- */
-static int inflateToFile(int outFd, int inFd, size_t uncompLen, size_t compLen)
-{
- int result = -1;
- const size_t kBufSize = 32768;
- unsigned char* readBuf = (unsigned char*) malloc(kBufSize);
- unsigned char* writeBuf = (unsigned char*) malloc(kBufSize);
- z_stream zstream;
- int zerr;
-
- if (readBuf == NULL || writeBuf == NULL)
- goto bail;
-
- /*
- * Initialize the zlib stream struct.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = NULL;
- zstream.avail_in = 0;
- zstream.next_out = (Bytef*) writeBuf;
- zstream.avail_out = kBufSize;
- zstream.data_type = Z_UNKNOWN;
-
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
- zerr = inflateInit2(&zstream, -MAX_WBITS);
- if (zerr != Z_OK) {
- if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)",
- ZLIB_VERSION);
- } else {
- ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
- }
- goto bail;
- }
-
- /*
- * Loop while we have more to do.
- */
- do {
- /* read as much as we can */
- if (zstream.avail_in == 0) {
- size_t getSize = (compLen > kBufSize) ? kBufSize : compLen;
-
- ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, readBuf, getSize));
- if (actual != (ssize_t) getSize) {
- ALOGW("Zip: inflate read failed (%d vs %zd)",
- (int)actual, getSize);
- goto z_bail;
- }
-
- compLen -= getSize;
-
- zstream.next_in = readBuf;
- zstream.avail_in = getSize;
- }
-
- /* uncompress the data */
- zerr = inflate(&zstream, Z_NO_FLUSH);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
- zerr, zstream.next_in, zstream.avail_in,
- zstream.next_out, zstream.avail_out);
- goto z_bail;
- }
-
- /* write when we're full or when we're done */
- if (zstream.avail_out == 0 ||
- (zerr == Z_STREAM_END && zstream.avail_out != kBufSize))
- {
- size_t writeSize = zstream.next_out - writeBuf;
- if (sysWriteFully(outFd, writeBuf, writeSize, "Zip inflate") != 0)
- goto z_bail;
-
- zstream.next_out = writeBuf;
- zstream.avail_out = kBufSize;
- }
- } while (zerr == Z_OK);
-
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
-
- /* paranoia */
- if (zstream.total_out != uncompLen) {
- ALOGW("Zip: size mismatch on inflated file (%ld vs %zd)",
- zstream.total_out, uncompLen);
- goto z_bail;
- }
-
- result = 0;
-
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- free(readBuf);
- free(writeBuf);
- return result;
-}
-
-/*
- * Uncompress an entry, in its entirety, to an open file descriptor.
- *
- * TODO: this doesn't verify the data's CRC, but probably should (especially
- * for uncompressed data).
- */
-int dexZipExtractEntryToFile(const ZipArchive* pArchive,
- const ZipEntry entry, int fd)
-{
- int result = -1;
- int ent = entryToIndex(pArchive, entry);
- if (ent < 0) {
- ALOGW("Zip: extract can't find entry %p", entry);
- goto bail;
- }
-
- int method;
- size_t uncompLen, compLen;
- off_t dataOffset;
-
- if (dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen,
- &dataOffset, NULL, NULL) != 0)
- {
- goto bail;
- }
- if (lseek(pArchive->mFd, dataOffset, SEEK_SET) != dataOffset) {
- ALOGW("Zip: lseek to data at %ld failed", (long) dataOffset);
- goto bail;
- }
-
- if (method == kCompressStored) {
- if (sysCopyFileToFile(fd, pArchive->mFd, uncompLen) != 0)
- goto bail;
- } else {
- if (inflateToFile(fd, pArchive->mFd, uncompLen, compLen) != 0)
- goto bail;
- }
-
- result = 0;
-
-bail:
- return result;
-}
diff --git a/libdex/ZipArchive.h b/libdex/ZipArchive.h
index df5c49a..c4794ce 100644
--- a/libdex/ZipArchive.h
+++ b/libdex/ZipArchive.h
@@ -20,75 +20,20 @@
#ifndef LIBDEX_ZIPARCHIVE_H_
#define LIBDEX_ZIPARCHIVE_H_
+#include <ziparchive/zip_archive.h>
+
#include "SysUtil.h"
#include "DexFile.h" // need DEX_INLINE
/*
- * Trivial typedef to ensure that ZipEntry is not treated as a simple
- * integer. We use NULL to indicate an invalid value.
- */
-typedef void* ZipEntry;
-
-/*
- * One entry in the hash table.
- */
-struct ZipHashEntry {
- const char* name;
- unsigned short nameLen;
-};
-
-/*
- * Read-only Zip archive.
- *
- * We want "open" and "find entry by name" to be fast operations, and
- * we want to use as little memory as possible. We memory-map the zip
- * central directory, and load a hash table with pointers to the filenames
- * (which aren't null-terminated). The other fields are at a fixed offset
- * from the filename, so we don't need to extract those (but we do need
- * to byte-read and endian-swap them every time we want them).
- *
- * It's possible that somebody has handed us a massive (~1GB) zip archive,
- * so we can't expect to mmap the entire file.
- *
- * To speed comparisons when doing a lookup by name, we could make the mapping
- * "private" (copy-on-write) and null-terminate the filenames after verifying
- * the record structure. However, this requires a private mapping of
- * every page that the Central Directory touches. Easier to tuck a copy
- * of the string length into the hash table entry.
- */
-struct ZipArchive {
- /* open Zip archive */
- int mFd;
-
- /* mapped central directory area */
- off_t mDirectoryOffset;
- MemMapping mDirectoryMap;
-
- /* number of entries in the Zip archive */
- int mNumEntries;
-
- /*
- * We know how many entries are in the Zip archive, so we can have a
- * fixed-size hash table. We probe on collisions.
- */
- int mHashTableSize;
- ZipHashEntry* mHashTable;
-};
-
-/* Zip compression methods we support */
-enum {
- kCompressStored = 0, // no compression
- kCompressDeflated = 8, // standard deflate
-};
-
-
-/*
* Open a Zip archive.
*
* On success, returns 0 and populates "pArchive". Returns nonzero errno
* value on failure.
*/
-int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive);
+DEX_INLINE int dexZipOpenArchive(const char* fileName, ZipArchiveHandle* pArchive) {
+ return OpenArchive(fileName, pArchive);
+}
/*
* Like dexZipOpenArchive, but takes a file descriptor open for reading
@@ -97,7 +42,10 @@
*
* "debugFileName" will appear in error messages, but is not otherwise used.
*/
-int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive);
+DEX_INLINE int dexZipOpenArchiveFd(int fd, const char* debugFileName,
+ ZipArchiveHandle* pArchive) {
+ return OpenArchiveFd(fd, debugFileName, pArchive);
+}
/*
* Close archive, releasing resources associated with it.
@@ -105,62 +53,24 @@
* Depending on the implementation this could unmap pages used by classes
* stored in a Jar. This should only be done after unloading classes.
*/
-void dexZipCloseArchive(ZipArchive* pArchive);
+DEX_INLINE void dexZipCloseArchive(ZipArchiveHandle archive) {
+ CloseArchive(archive);
+}
/*
* Return the archive's file descriptor.
*/
-DEX_INLINE int dexZipGetArchiveFd(const ZipArchive* pArchive) {
- return pArchive->mFd;
+DEX_INLINE int dexZipGetArchiveFd(const ZipArchiveHandle pArchive) {
+ return GetFileDescriptor(pArchive);
}
/*
* Find an entry in the Zip archive, by name. Returns NULL if the entry
* was not found.
*/
-ZipEntry dexZipFindEntry(const ZipArchive* pArchive,
- const char* entryName);
-
-/*
- * Retrieve one or more of the "interesting" fields. Non-NULL pointers
- * are filled in.
- *
- * Returns 0 on success.
- */
-int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
- int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
- long* pModWhen, long* pCrc32);
-
-/*
- * Simple accessors.
- */
-DEX_INLINE long dexGetZipEntryOffset(const ZipArchive* pArchive,
- const ZipEntry entry)
-{
- off_t val = 0;
- dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, &val, NULL, NULL);
- return (long) val;
-}
-DEX_INLINE size_t dexGetZipEntryUncompLen(const ZipArchive* pArchive,
- const ZipEntry entry)
-{
- size_t val = 0;
- dexZipGetEntryInfo(pArchive, entry, NULL, &val, NULL, NULL, NULL, NULL);
- return val;
-}
-DEX_INLINE long dexGetZipEntryModTime(const ZipArchive* pArchive,
- const ZipEntry entry)
-{
- long val = 0;
- dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, &val, NULL);
- return val;
-}
-DEX_INLINE long dexGetZipEntryCrc32(const ZipArchive* pArchive,
- const ZipEntry entry)
-{
- long val = 0;
- dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, NULL, &val);
- return val;
+DEX_INLINE int dexZipFindEntry(const ZipArchiveHandle pArchive,
+ const char* entryName, ZipEntry* data) {
+ return FindEntry(pArchive, entryName, data);
}
/*
@@ -168,13 +78,9 @@
*
* Returns 0 on success.
*/
-int dexZipExtractEntryToFile(const ZipArchive* pArchive,
- const ZipEntry entry, int fd);
-
-/*
- * Utility function to compute a CRC-32.
- */
-u4 dexInitCrc32(void);
-u4 dexComputeCrc32(u4 crc, const void* buf, size_t len);
+DEX_INLINE int dexZipExtractEntryToFile(ZipArchiveHandle handle,
+ ZipEntry* entry, int fd) {
+ return ExtractEntryToFile(handle, entry, fd);
+}
#endif // LIBDEX_ZIPARCHIVE_H_
diff --git a/vm/Android.mk b/vm/Android.mk
index a5c58ad..1c1f91a 100644
--- a/vm/Android.mk
+++ b/vm/Android.mk
@@ -135,6 +135,7 @@
# time. When building this target as a regular static library, certain
# dependencies like expat are not found by the linker.
LOCAL_WHOLE_STATIC_LIBRARIES += libexpat libcutils libdex liblog libz
+ LOCAL_STATIC_LIBRARIES += libutils
# The libffi from the source tree should never be used by host builds.
# The recommendation is that host builds should always either
diff --git a/vm/Dalvik.h b/vm/Dalvik.h
index eecbf8d..27174e7 100644
--- a/vm/Dalvik.h
+++ b/vm/Dalvik.h
@@ -30,7 +30,6 @@
#include "libdex/DexFile.h"
#include "libdex/DexProto.h"
#include "libdex/DexUtf.h"
-#include "libdex/ZipArchive.h"
#include "DvmDex.h"
#include "RawDexFile.h"
#include "Sync.h"
diff --git a/vm/JarFile.cpp b/vm/JarFile.cpp
index 3a037a0..e56f730 100644
--- a/vm/JarFile.cpp
+++ b/vm/JarFile.cpp
@@ -24,6 +24,7 @@
#include "Dalvik.h"
#include "libdex/OptInvocation.h"
+#include "JarFile.h"
#include <stdlib.h>
#include <string.h>
@@ -85,7 +86,7 @@
*/
DexCacheStatus dvmDexCacheStatus(const char *fileName)
{
- ZipArchive archive;
+ ZipArchiveHandle archive;
char* cachedName = NULL;
int fd;
DexCacheStatus result = DEX_CACHE_ERROR;
@@ -108,8 +109,7 @@
if (dexZipOpenArchive(fileName, &archive) != 0) {
return DEX_CACHE_BAD_ARCHIVE;
}
- entry = dexZipFindEntry(&archive, kDexInJarName);
- if (entry != NULL) {
+ if (dexZipFindEntry(archive, kDexInJarName, &entry) == 0) {
bool newFile = false;
/*
@@ -122,8 +122,7 @@
return DEX_CACHE_BAD_ARCHIVE;
fd = dvmOpenCachedDexFile(fileName, cachedName,
- dexGetZipEntryModTime(&archive, entry),
- dexGetZipEntryCrc32(&archive, entry),
+ entry.mod_time, entry.crc32,
/*isBootstrap=*/false, &newFile, /*createIfMissing=*/false);
ALOGV("dvmOpenCachedDexFile returned fd %d", fd);
if (fd < 0) {
@@ -169,7 +168,7 @@
result = DEX_CACHE_OK;
bail:
- dexZipCloseArchive(&archive);
+ dexZipCloseArchive(archive);
free(cachedName);
if (fd >= 0) {
close(fd);
@@ -193,7 +192,7 @@
* dvmRawDexFileOpen() in RawDexFile.c. This should be refactored.
*/
- ZipArchive archive;
+ ZipArchiveHandle archive;
DvmDex* pDvmDex = NULL;
char* cachedName = NULL;
bool archiveOpen = false;
@@ -210,7 +209,7 @@
/* If we fork/exec into dexopt, don't let it inherit the archive's fd.
*/
- dvmSetCloseOnExec(dexZipGetArchiveFd(&archive));
+ dvmSetCloseOnExec(dexZipGetArchiveFd(archive));
/* First, look for a ".odex" alongside the jar file. It will
* have the same name/path except for the extension.
@@ -239,8 +238,7 @@
* Pre-created .odex absent or stale. Look inside the jar for a
* "classes.dex".
*/
- entry = dexZipFindEntry(&archive, kDexInJarName);
- if (entry != NULL) {
+ if (dexZipFindEntry(archive, kDexInJarName, &entry) == 0) {
bool newFile = false;
/*
@@ -265,8 +263,8 @@
ALOGV("dvmJarFileOpen: Checking cache for %s (%s)",
fileName, cachedName);
fd = dvmOpenCachedDexFile(fileName, cachedName,
- dexGetZipEntryModTime(&archive, entry),
- dexGetZipEntryCrc32(&archive, entry),
+ entry.mod_time,
+ entry.crc32,
isBootstrap, &newFile, /*createIfMissing=*/true);
if (fd < 0) {
ALOGI("Unable to open or create cache for %s (%s)",
@@ -291,15 +289,15 @@
if (result) {
startWhen = dvmGetRelativeTimeUsec();
- result = dexZipExtractEntryToFile(&archive, entry, fd) == 0;
+ result = dexZipExtractEntryToFile(archive, &entry, fd) == 0;
extractWhen = dvmGetRelativeTimeUsec();
}
if (result) {
result = dvmOptimizeDexFile(fd, dexOffset,
- dexGetZipEntryUncompLen(&archive, entry),
+ entry.uncompressed_length,
fileName,
- dexGetZipEntryModTime(&archive, entry),
- dexGetZipEntryCrc32(&archive, entry),
+ entry.mod_time,
+ entry.crc32,
isBootstrap);
}
@@ -353,7 +351,7 @@
bail:
/* clean up, closing the open file */
if (archiveOpen && result != 0)
- dexZipCloseArchive(&archive);
+ dexZipCloseArchive(archive);
free(cachedName);
if (fd >= 0) {
if (locked)
diff --git a/vm/JarFile.h b/vm/JarFile.h
index d8fd998..b3a8a0f 100644
--- a/vm/JarFile.h
+++ b/vm/JarFile.h
@@ -19,12 +19,14 @@
#ifndef DALVIK_JARFILE_H_
#define DALVIK_JARFILE_H_
+#include "libdex/ZipArchive.h"
+
/*
* This represents an open, scanned Jar file. (It's actually for any Zip
* archive that happens to hold a Dex file.)
*/
struct JarFile {
- ZipArchive archive;
+ ZipArchiveHandle archive;
//MemMapping map;
char* cacheFileName;
DvmDex* pDvmDex;
diff --git a/vm/ReconfigureDvm.mk b/vm/ReconfigureDvm.mk
index e6b29d5..d7ad1cc 100644
--- a/vm/ReconfigureDvm.mk
+++ b/vm/ReconfigureDvm.mk
@@ -28,6 +28,7 @@
liblog \
libnativehelper \
libselinux \
+ libutils \
libz
LOCAL_STATIC_LIBRARIES += libdex
diff --git a/vm/oo/Class.cpp b/vm/oo/Class.cpp
index db5340e..904d53d 100644
--- a/vm/oo/Class.cpp
+++ b/vm/oo/Class.cpp
@@ -23,6 +23,7 @@
#include "Dalvik.h"
#include "libdex/DexClass.h"
+#include "libdex/ZipArchive.h"
#include "analysis/Optimize.h"
#include <stdlib.h>
@@ -886,6 +887,7 @@
const int kUrlOverhead = 13; // worst case for Jar URL
const ClassPathEntry* cpe = gDvm.bootClassPath;
StringObject* urlObj = NULL;
+ ZipEntry entry;
ALOGV("+++ searching for resource '%s' in %d(%s)",
name, idx, cpe[idx].fileName);
@@ -904,7 +906,7 @@
case kCpeJar:
{
JarFile* pJarFile = (JarFile*) cpe->ptr;
- if (dexZipFindEntry(&pJarFile->archive, name) == NULL)
+ if (dexZipFindEntry(pJarFile->archive, name, &entry) != 0)
goto bail;
sprintf(urlBuf, "jar:file://%s!/%s", cpe->fileName, name);
}