Add support for opening classes.dex file from zip, jar, apk

Adding new ZipArchive class and test

	src/zip_archive.h
	src/zip_archive.cc
	src/zip_archive_test.cc
	build/Android.common.mk

Change from host only use of build dex file for libcore to using host
and target core.jar containing classes.dex files. This requires
setting up an ANDROID_DATA directory to containing an art-cache file
for the extracted dex files, similar to the dalvik-cache for odex
files. A unique ANDROID_DATA and art-cache is created and cleaned up
for each test run (similar to vogar).

	src/common_test.h

Add dependency for libcore jar files to test targets to support
RuntimeTest use of core.jar

	Android.mk

Extract common includes to ART_C_INCLUDES when adding zlib dependency

	build/Android.common.mk
	build/Android.libart.mk
	build/Android.test.mk

Adding TODO regarding unordered map for ClassLinker::classes_ table.

	src/class_linker.h

Adding DexFile::OpenZip (also changed OpenFile to take
	src/dex_file.cc
	src/dex_file.h

Adding kPageSize of 4096, validated by Runtime::Init

	src/globals.h
	src/runtime.cc

    Updated to use kPageSize where it seemed appropriate.

	src/jni_compiler.cc
	src/jni_compiler_test.cc
	src/space.cc
	src/thread.cc
	src/thread_x86.cc

Changed thread_list_ and class_linker_ to be declared in Runtime::Init
initialization order.

	src/runtime.h

Change-Id: Id626abe5b6c1990e4f93598256ee0fae000818f6
diff --git a/src/dex_file.cc b/src/dex_file.cc
index a5ac01b..b61babf 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -3,17 +3,22 @@
 #include "dex_file.h"
 
 #include <fcntl.h>
+#include <map>
+#include <stdio.h>
 #include <string.h>
+#include <sys/file.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <map>
 
 #include "globals.h"
 #include "logging.h"
 #include "object.h"
 #include "scoped_ptr.h"
+#include "stringprintf.h"
+#include "thread.h"
 #include "utils.h"
+#include "zip_archive.h"
 
 namespace art {
 
@@ -34,9 +39,8 @@
 DexFile::PtrCloser::PtrCloser(byte* addr) : addr_(addr) {}
 DexFile::PtrCloser::~PtrCloser() { delete[] addr_; }
 
-DexFile* DexFile::OpenFile(const char* filename) {
-  CHECK(filename != NULL);
-  int fd = open(filename, O_RDONLY);  // TODO: scoped_fd
+DexFile* DexFile::OpenFile(const std::string& filename) {
+  int fd = open(filename.c_str(), O_RDONLY);  // TODO: scoped_fd
   if (fd == -1) {
     PLOG(ERROR) << "open(\"" << filename << "\", O_RDONLY) failed";
     return NULL;
@@ -61,6 +65,199 @@
   return Open(dex_file, length, closer);
 }
 
+static const char* kClassesDex = "classes.dex";
+
+class LockedFd {
+ public:
+   static LockedFd* CreateAndLock(std::string& name, mode_t mode) {
+    int fd = open(name.c_str(), O_CREAT | O_RDWR, mode);
+    if (fd == -1) {
+      PLOG(ERROR) << "Can't open file '" << name;
+      return NULL;
+    }
+    fchmod(fd, mode);
+
+    LOG(INFO) << "locking file " << name << " (fd=" << fd << ")";
+    int result = flock(fd, LOCK_EX | LOCK_NB);
+    if (result == -1) {
+        LOG(WARNING) << "sleeping while locking file " << name;
+        result = flock(fd, LOCK_EX);
+    }
+    if (result == -1 ) {
+      close(fd);
+      PLOG(ERROR) << "Can't lock file '" << name;
+      return NULL;
+    }
+    return new LockedFd(fd);
+   }
+
+   int GetFd() const {
+     return fd_;
+   }
+
+  ~LockedFd() {
+    if (fd_ != -1) {
+      int result = flock(fd_, LOCK_UN);
+      if (result == -1) {
+        PLOG(WARNING) << "flock(" << fd_ << ", LOCK_UN) failed";
+      }
+      close(fd_);
+    }
+  }
+
+ private:
+  LockedFd(int fd) : fd_(fd) {}
+
+  int fd_;
+};
+
+class TmpFile {
+ public:
+  TmpFile(const std::string name) : name_(name) {}
+  ~TmpFile() {
+    unlink(name_.c_str());
+  }
+ private:
+  const std::string name_;
+};
+
+// Open classes.dex from within a .zip, .jar, .apk, ...
+DexFile* DexFile::OpenZip(const std::string& filename) {
+
+  // First, look for a ".dex" alongside the jar file.  It will have
+  // the same name/path except for the extension.
+
+  // Example filename = dir/foo.jar
+  std::string adjacent_dex_filename(filename);
+  size_t found = adjacent_dex_filename.find_last_of(".");
+  if (found == std::string::npos) {
+    LOG(WARNING) << "No . in filename" << filename;
+  }
+  adjacent_dex_filename.replace(adjacent_dex_filename.begin() + found,
+                                adjacent_dex_filename.end(),
+                                ".dex");
+  // Example adjacent_dex_filename = dir/foo.dex
+  DexFile* adjacent_dex_file = DexFile::OpenFile(adjacent_dex_filename);
+  if (adjacent_dex_file != NULL) {
+      // We don't verify anything in this case, because we aren't in
+      // the cache and typically the file is in the readonly /system
+      // area, so if something is wrong, there is nothing we can do.
+      return adjacent_dex_file;
+  }
+
+  char resolved[PATH_MAX];
+  char* absolute_path = realpath(filename.c_str(), resolved);
+  if (absolute_path == NULL) {
+      LOG(WARNING) << "Could not create absolute path for " << filename
+                   << " when looking for classes.dex";
+      return NULL;
+  }
+  std::string cache_file(absolute_path+1); // skip leading slash
+  std::replace(cache_file.begin(), cache_file.end(), '/', '@');
+  cache_file.push_back('@');
+  cache_file.append(kClassesDex);
+  // Example cache_file = parent@dir@foo.jar@classes.dex
+
+  const char* data_root = getenv("ANDROID_DATA");
+  if (data_root == NULL) {
+      data_root = "/data";
+  }
+
+  std::string cache_path_tmp = StringPrintf("%s/art-cache/%s", data_root, cache_file.c_str());
+  // Example cache_path_tmp = /data/art-cache/parent@dir@foo.jar@classes.dex
+
+  scoped_ptr<ZipArchive> zip_archive(ZipArchive::Open(filename));
+  if (zip_archive == NULL) {
+    LOG(WARNING) << "Could not open " << filename << " when looking for classes.dex";
+    return NULL;
+  }
+  scoped_ptr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex));
+  if (zip_entry == NULL) {
+    LOG(WARNING) << "Could not find classes.dex within " << filename;
+    return NULL;
+  }
+
+  std::string cache_path = StringPrintf("%s.%08x", cache_path_tmp.c_str(), zip_entry->GetCrc32());
+  // Example cache_path = /data/art-cache/parent@dir@foo.jar@classes.dex.1a2b3c4d
+
+  while (true) {
+    DexFile* cached_dex_file = DexFile::OpenFile(cache_path);
+    if (cached_dex_file != NULL) {
+      return cached_dex_file;
+    }
+
+    // Try to open the temporary cache file, grabbing an exclusive
+    // lock. If somebody else is working on it, we'll block here until
+    // they complete.  Because we're waiting on an external resource,
+    // we go into native mode.
+    Thread* current_thread = Thread::Current();
+    Thread::State old = current_thread->GetState();
+    current_thread->SetState(Thread::kNative);
+    scoped_ptr<LockedFd> fd(LockedFd::CreateAndLock(cache_path_tmp, 0644));
+    current_thread->SetState(old);
+    if (fd == NULL) {
+      return NULL;
+    }
+
+    // Check to see if the fd we opened and locked matches the file in
+    // the filesystem.  If they don't, then somebody else unlinked
+    // ours and created a new file, and we need to use that one
+    // instead.  (If we caught them between the unlink and the create,
+    // we'll get an ENOENT from the file stat.)
+    struct stat fd_stat;
+    int fd_stat_result = fstat(fd->GetFd(), &fd_stat);
+    if (fd_stat_result == -1) {
+      PLOG(ERROR) << "Can't stat open file '" << cache_path_tmp << "'";
+      return NULL;
+    }
+    struct stat file_stat;
+    int file_stat_result = stat(cache_path_tmp.c_str(), &file_stat);
+    if (file_stat_result == -1 ||
+        fd_stat.st_dev != file_stat.st_dev || fd_stat.st_ino != file_stat.st_ino) {
+      LOG(WARNING) << "our open cache file is stale; sleeping and retrying";
+      usleep(250 * 1000);  // if something is hosed, don't peg machine
+      continue;
+    }
+
+    // We have the correct file open and locked. Extract classes.dex
+    TmpFile tmp_file(cache_path_tmp);
+    bool success = zip_entry->Extract(fd->GetFd());
+    if (!success) {
+      return NULL;
+    }
+
+    // TODO restat and check length against zip_entry->GetUncompressedLength()?
+
+    // Compute checksum and compare to zip. If things look okay, rename from tmp.
+    off_t lseek_result = lseek(fd->GetFd(), 0, SEEK_SET);
+    if (lseek_result == -1) {
+      return NULL;
+    }
+    const size_t kBufSize = 32768;
+    scoped_ptr<uint8_t> buf(new uint8_t[kBufSize]);
+    if (buf == NULL) {
+      return NULL;
+    }
+    uint32_t computed_crc = crc32(0L, Z_NULL, 0);
+    while (true) {
+      ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd->GetFd(), buf.get(), kBufSize));
+      if (bytes_read == 0) {
+        break;
+      }
+      computed_crc = crc32(computed_crc, buf.get(), bytes_read);
+    }
+    if (computed_crc != zip_entry->GetCrc32()) {
+      return NULL;
+    }
+    int rename_result = rename(cache_path_tmp.c_str(), cache_path.c_str());
+    if (rename_result == -1) {
+      PLOG(ERROR) << "Can't install dex cache file '" << cache_path << "' from '" << cache_path_tmp;
+      unlink(cache_path.c_str());
+    }
+  }
+  // NOTREACHED
+}
+
 DexFile* DexFile::OpenPtr(byte* ptr, size_t length) {
   CHECK(ptr != NULL);
   DexFile::Closer* closer = new PtrCloser(ptr);