Add installd support to dex2oat

Change-Id: Id1a64403ccea7dc2c1e8b8340d33d383d4045a33
diff --git a/Android.mk b/Android.mk
index 665f996..7ddaa37 100644
--- a/Android.mk
+++ b/Android.mk
@@ -117,7 +117,7 @@
 
 # $(1): jar or apk name
 define art-cache-oat
-  $(ART_CACHE_OUT)/$(subst /,@,$(patsubst %.apk,%.oat,$(patsubst %.jar,%.oat,$(1))))
+  $(ART_CACHE_OUT)/$(subst /,@,$(1).oat)
 endef
 
 ART_CACHE_OATS :=
@@ -127,13 +127,10 @@
   ART_CACHE_OATS += $(call art-cache-oat,$(1))
 endef
 
-# for test-art-target-am
-$(eval $(call build-art-cache-oat,system/framework/am.jar))
 
-# for test-art-target-Calculator
-$(eval $(call build-art-cache-oat,system/app/Calculator.apk))
+########################################################################
+# oat-target-sync
 
-# for zygote-art
 ifeq ($(TARGET_PRODUCT),mysid)
 
 $(eval $(call build-art-cache-oat,system/app/ApplicationsProvider.apk))
@@ -142,6 +139,7 @@
 $(eval $(call build-art-cache-oat,system/app/Bluetooth.apk))
 $(eval $(call build-art-cache-oat,system/app/BooksTablet.apk))
 $(eval $(call build-art-cache-oat,system/app/BrowserGoogle.apk))
+$(eval $(call build-art-cache-oat,system/app/Calculator.apk))
 $(eval $(call build-art-cache-oat,system/app/CalendarGoogle.apk))
 $(eval $(call build-art-cache-oat,system/app/CalendarProvider.apk))
 $(eval $(call build-art-cache-oat,system/app/CameraGoogle.apk))
@@ -229,6 +227,7 @@
 $(eval $(call build-art-cache-oat,system/app/VZWBackupAssistant.apk))
 $(eval $(call build-art-cache-oat,system/app/YouTube.apk))
 $(eval $(call build-art-cache-oat,system/app/talkback.apk))
+$(eval $(call build-art-cache-oat,system/framework/am.jar))
 $(eval $(call build-art-cache-oat,system/framework/android.test.runner.jar))
 $(eval $(call build-art-cache-oat,system/framework/bmgr.jar))
 $(eval $(call build-art-cache-oat,system/framework/bu.jar))
@@ -255,6 +254,7 @@
 $(eval $(call build-art-cache-oat,system/app/Bluetooth.apk))
 $(eval $(call build-art-cache-oat,system/app/BooksTablet.apk))
 $(eval $(call build-art-cache-oat,system/app/BrowserGoogle.apk))
+$(eval $(call build-art-cache-oat,system/app/Calculator.apk))
 $(eval $(call build-art-cache-oat,system/app/CalendarGoogle.apk))
 $(eval $(call build-art-cache-oat,system/app/CalendarProvider.apk))
 $(eval $(call build-art-cache-oat,system/app/CameraGoogle.apk))
@@ -333,6 +333,7 @@
 $(eval $(call build-art-cache-oat,system/app/YouTube.apk))
 $(eval $(call build-art-cache-oat,system/app/googlevoice.apk))
 $(eval $(call build-art-cache-oat,system/app/talkback.apk))
+$(eval $(call build-art-cache-oat,system/framework/am.jar))
 $(eval $(call build-art-cache-oat,system/framework/android.test.runner.jar))
 $(eval $(call build-art-cache-oat,system/framework/bmgr.jar))
 $(eval $(call build-art-cache-oat,system/framework/bu.jar))
@@ -358,52 +359,11 @@
 
 endif
 
-.PHONY: test-art-target-am
-test-art-target-am: $(call art-cache-oat,system/framework/am.jar) test-art-target-sync
-	adb shell sh -c "am start http://android.com && touch $(ART_TEST_DIR)/test-art-target-process-am"
-	$(hide) (adb pull $(ART_TEST_DIR)/test-art-target-process-am /tmp/ && echo test-art-target-process-am PASSED) || echo test-art-target-process-am FAILED
-	$(hide) rm /tmp/test-art-target-process-am
-
-.PHONY: test-art-target-Calculator
-test-art-target-Calculator: $(call art-cache-oat,system/app/Calculator.oat) $(call art-cache-oat,system/framework/am.jar) test-art-target-sync
-	adb shell kill `adb shell ps | fgrep com.android.calculator2 | sed -e 's/[^ ]* *\([0-9]*\).*/\1/'`
-	adb shell sh -c "am start -a android.intent.action.MAIN -n com.android.calculator2/.Calculator && touch $(ART_TEST_DIR)/test-art-target-process-Calculator"
-	$(hide) (adb pull $(ART_TEST_DIR)/test-art-target-process-Calculator /tmp/ && echo test-art-target-process-Calculator PASSED) || echo test-art-target-process-Calculator FAILED
-	$(hide) rm /tmp/test-art-target-process-Calculator
-
-########################################################################
-# zygote targets
-#
-# zygote-artd will change to use art to boot the device with a debug build
-# zygote-art will change to use art to boot the device with a production build
-#
-# zygote-artd-target-sync will just push a new artd in place of dvm
-# zygote-art-target-sync will just push a new art in place of dvm
-
-# $(1): "d" for debug build, "" for ndebug build
-define define-zygote-art-targets
-.PHONY: zygote-art$(1)-target-sync
-zygote-art$(1)-target-sync: $(ART_TARGET_DEPENDENCIES) $(TARGET_BOOT_OAT) $(ART_CACHE_OATS)
-	cp $(TARGET_OUT_EXECUTABLES)/oatopt$(1) $(TARGET_OUT_EXECUTABLES)/dexopt
-	cp $(TARGET_OUT_EXECUTABLES_UNSTRIPPED)/oatopt$(1) $(TARGET_OUT_EXECUTABLES_UNSTRIPPED)/dexopt
-	mkdir -p $(TARGET_OUT_DATA)/property
-	echo -n 1 > $(TARGET_OUT_DATA)/property/persist.sys.strictmode.disable
+.PHONY: oat-target-sync
+oat-target-sync: $(ART_TARGET_DEPENDENCIES) $(TARGET_BOOT_OAT) $(ART_CACHE_OATS)
 	adb remount
 	adb sync
 
-.PHONY: zygote-art$(1)
-zygote-art$(1): zygote-art$(1)-target-sync
-	sed -e 's/--start-system-server/--start-system-server --no-preload/' -e 's/art-cache 0771/art-cache 0777/' < system/core/rootdir/init.rc > $(ANDROID_PRODUCT_OUT)/root/init.rc
-	rm -f $(ANDROID_PRODUCT_OUT)/boot.img
-	unset ONE_SHOT_MAKEFILE && $(MAKE) showcommands bootimage
-	adb reboot bootloader
-	fastboot flash boot $(ANDROID_PRODUCT_OUT)/boot.img
-	fastboot reboot
-endef
-
-$(eval $(call define-zygote-art-targets,d))
-$(eval $(call define-zygote-art-targets,))
-
 ########################################################################
 # oatdump targets
 
@@ -421,8 +381,8 @@
 	@echo Output in /tmp/boot.oatdump.txt
 
 .PHONY: dump-oat-Calculator
-dump-oat-Calculator: $(call art-cache-oat,system/app/Calculator.oat) $(TARGET_BOOT_OAT) $(OATDUMP)
-	$(OATDUMP) --oat=$< --boot-image=$(TARGET_BOOT_IMG) --host-prefix=$(PRODUCT_OUT) --output=/tmp/Calculator.oatdump.txt
+dump-oat-Calculator: $(call art-cache-oat,system/app/Calculator.apk) $(TARGET_BOOT_OAT) $(OATDUMP)
+	$(OATDUMP) --oat-file=$< --boot-image=$(TARGET_BOOT_IMG) --host-prefix=$(PRODUCT_OUT) --output=/tmp/Calculator.oatdump.txt
 	@echo Output in /tmp/Calculator.oatdump.txt
 
 
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 3fe0477..f7e97a1 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -80,9 +80,6 @@
 OATEXEC_SRC_FILES := \
 	src/oatexec.cc
 
-OATOPT_SRC_FILES := \
-	src/oatopt.cc
-
 LIBART_COMMON_SRC_FILES := \
 	src/assembler.cc \
 	src/assembler_arm.cc \
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 52009ab..2d9bd23 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -95,24 +95,20 @@
   $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),target,ndebug))
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),target,ndebug))
   $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),target,ndebug))
-  $(eval $(call build-art-executable,oatopt,$(OATOPT_SRC_FILES),target,ndebug))
 endif
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
   $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),target,debug))
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),target,debug))
   $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),target,debug))
-  $(eval $(call build-art-executable,oatopt,$(OATOPT_SRC_FILES),target,debug))
 endif
 ifeq ($(ART_BUILD_HOST_NDEBUG),true)
   $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,ndebug))
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),host,ndebug))
   $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,ndebug))
-  $(eval $(call build-art-executable,oatopt,$(OATOPT_SRC_FILES),host,ndebug))
 endif
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
   $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,debug))
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),host,debug))
   $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,debug))
-  $(eval $(call build-art-executable,oatopt,$(OATOPT_SRC_FILES),host,debug))
 endif
 
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index a87de97..a1c2449 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -51,12 +51,12 @@
 $(HOST_CORE_OAT): $(HOST_CORE_DEX) $(DEX2OAT_DEPENDENCY)
 	@echo "host dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
-	$(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(HOST_CORE_IMG) --base=$(IMG_HOST_BASE_ADDRESS)
+	$(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat-file=$@ --image=$(HOST_CORE_IMG) --base=$(IMG_HOST_BASE_ADDRESS)
 
 $(TARGET_CORE_OAT): $(TARGET_CORE_DEX) $(DEX2OAT_DEPENDENCY)
 	@echo "target dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
-	$(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_CORE_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
+	$(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat-file=$@ --image=$(TARGET_CORE_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
 
 $(HOST_CORE_IMG): $(HOST_CORE_OAT)
 
@@ -72,7 +72,7 @@
 $(TARGET_BOOT_OAT): $(TARGET_BOOT_DEX) $(DEX2OAT_DEPENDENCY)
 	@echo "target dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
-	$(hide) $(DEX2OAT) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_BOOT_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
+	$(hide) $(DEX2OAT) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat-file=$@ --image=$(TARGET_BOOT_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
 
 $(TARGET_BOOT_IMG): $(TARGET_BOOT_OAT)
 
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index f982fe3..da64a84 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -41,7 +41,7 @@
 $(2): $(1) $(3) $(DEX2OAT_DEPENDENCY)
 	@echo "target dex2oat: $$@ ($$?)"
 	@mkdir -p $$(dir $$@)
-	$(hide) $(DEX2OAT) --runtime-arg -Xms64m --runtime-arg -Xmx64m --boot-image=$(3) $(addprefix --dex-file=,$$<) --oat=$$@ --host-prefix=$(PRODUCT_OUT)
+	$(hide) $(DEX2OAT) --runtime-arg -Xms64m --runtime-arg -Xmx64m --boot-image=$(3) $(addprefix --dex-file=,$$<) --oat-file=$$@ --host-prefix=$(PRODUCT_OUT)
 endef
 
 ########################################################################
@@ -49,8 +49,8 @@
 
 # $(1): directory
 define build-art-test-oat
-  $(call build-art-oat,$(ART_TEST_OUT)/art-test-dex-$(1).jar,$(ART_TEST_OUT)/art-test-dex-$(1).oat,$(TARGET_CORE_IMG))
-  ART_TEST_OAT_FILES += $(ART_TEST_OUT)/art-test-dex-$(1).oat
+  $(call build-art-oat,$(ART_TEST_OUT)/art-test-dex-$(1).jar,$(ART_TEST_OUT)/art-test-dex-$(1).jar.oat,$(TARGET_CORE_IMG))
+  ART_TEST_OAT_FILES += $(ART_TEST_OUT)/art-test-dex-$(1).jar.oat
 endef
 $(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-oat,$(dir))))
 
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e3b30d7..01ba9af 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -584,7 +584,7 @@
   dex_file_option_string += filename;
   const char* dex_file_option = dex_file_option_string.c_str();
 
-  std::string oat_file_option_string("--oat=");
+  std::string oat_file_option_string("--oat-file=");
   oat_file_option_string += oat_filename;
   const char* oat_file_option = oat_file_option_string.c_str();
 
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index a63d4ab..35494cb 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -19,6 +19,7 @@
 #include "os.h"
 #include "runtime.h"
 #include "stringpiece.h"
+#include "zip_archive.h"
 
 namespace art {
 
@@ -27,13 +28,27 @@
           "Usage: dex2oat [options]...\n"
           "\n");
   fprintf(stderr,
-          "  --dex-file=<dex-file>: specifies a .dex file to compile. At least one .dex\n"
-          "      file must be specified. \n"
+          "  --dex-file=<dex-file>: specifies a .dex file to compile.\n"
           "      Example: --dex-file=/system/framework/core.jar\n"
           "\n");
   fprintf(stderr,
-          "  --oat=<file.oat>: specifies the required oat filename.\n"
-          "      Example: --oat=/system/framework/boot.oat\n"
+          "  --zip-fd=<file-descriptor>: specifies a file descriptor of a zip file\n"
+          "      containing a classes.dex file to compile.\n"
+          "      Example: --zip-fd=5\n"
+          "\n");
+  fprintf(stderr,
+          "  --zip-name=<zip-name>: specifies a symbolic name for the file corresponding\n"
+          "      to the file descriptor specified by --zip-fd.\n"
+          "      Example: --zip-name=/system/app/Calculator.apk\n"
+          "\n");
+  fprintf(stderr,
+          "  --oat-file=<file.oat>: specifies the required oat filename.\n"
+          "      Example: --oat-file=/system/framework/boot.oat\n"
+          "\n");
+  fprintf(stderr,
+          "  --oat-name=<oat-name>: specifies a symbolic name for the file corresponding\n"
+          "      to the file descriptor specified by --oat-fd.\n"
+          "      Example: --oat-name=/data/art-cache/system@app@Calculator.apk.oat\n"
           "\n");
   fprintf(stderr,
           "  --image=<file.art>: specifies the output image filename.\n"
@@ -146,8 +161,7 @@
   }
 
   bool CreateOatFile(const std::string& boot_image_option,
-                     const std::vector<const char*>& dex_filenames,
-                     const std::string& host_prefix,
+                     const std::vector<const DexFile*>& dex_files,
                      File* oat_file,
                      bool image,
                      const std::set<std::string>* image_classes) {
@@ -158,18 +172,14 @@
       return false;
     }
 
-    std::vector<const DexFile*> dex_files;
     if (!boot_image_option.empty()) {
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-      DexFile::OpenDexFiles(dex_filenames, dex_files, host_prefix);
       std::vector<const DexFile*> class_path_files(dex_files);
       OpenClassPathFiles(runtime_->GetClassPath(), class_path_files);
       for (size_t i = 0; i < class_path_files.size(); i++) {
         class_linker->RegisterDexFile(*class_path_files[i]);
       }
       class_loader.get()->reset(PathClassLoader::AllocCompileTime(class_path_files));
-    } else {
-      dex_files = runtime_->GetClassLinker()->GetBootClassPath();
     }
 
     Compiler compiler(instruction_set_, image, image_classes);
@@ -333,6 +343,16 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
 };
 
+bool parse_int(const char* in, int* out) {
+  char* end;
+  int result = strtol(in, &end, 10);
+  if (in == end || *end != '\0') {
+    return false;
+  }
+  *out = result;
+  return true;
+}
+
 int dex2oat(int argc, char** argv) {
   // Skip over argv[0].
   argv++;
@@ -344,7 +364,11 @@
   }
 
   std::vector<const char*> dex_filenames;
+  int zip_fd = -1;
+  std::string zip_name;
   std::string oat_filename;
+  int oat_fd = -1;
+  std::string oat_name;
   const char* image_filename = NULL;
   const char* image_classes_filename = NULL;
   std::string boot_image_filename;
@@ -354,13 +378,30 @@
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
-    if (false) {
+    bool log_options = false;
+    if (log_options) {
       LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
     }
     if (option.starts_with("--dex-file=")) {
       dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
-    } else if (option.starts_with("--oat=")) {
-      oat_filename = option.substr(strlen("--oat=")).data();
+    } else if (option.starts_with("--zip-fd=")) {
+      const char* zip_fd_str = option.substr(strlen("--zip-fd=")).data();
+      if (!parse_int(zip_fd_str, &zip_fd)) {
+        fprintf(stderr, "could not parse --zip-fd argument %s as integer\n", zip_fd_str);
+        usage();
+      }
+    } else if (option.starts_with("--zip-name=")) {
+      zip_name = option.substr(strlen("--zip-name=")).data();
+    } else if (option.starts_with("--oat-file=")) {
+      oat_filename = option.substr(strlen("--oat-file=")).data();
+    } else if (option.starts_with("--oat-fd=")) {
+      const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data();
+      if (!parse_int(oat_fd_str, &oat_fd)) {
+        fprintf(stderr, "could not parse --oat-fd argument %s as integer\n", oat_fd_str);
+        usage();
+      }
+    } else if (option.starts_with("--oat-name=")) {
+      oat_name = option.substr(strlen("--oat-name=")).data();
     } else if (option.starts_with("--image=")) {
       image_filename = option.substr(strlen("--image=")).data();
     } else if (option.starts_with("--image-classes=")) {
@@ -382,6 +423,9 @@
         fprintf(stderr, "Missing required argument for --runtime-arg\n");
         usage();
       }
+      if (log_options) {
+        LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
+      }
       runtime_args.push_back(argv[i]);
     } else {
       fprintf(stderr, "unknown argument %s\n", option.data());
@@ -389,8 +433,33 @@
     }
   }
 
-  if (oat_filename.empty()) {
-    fprintf(stderr, "--oat file name not specified\n");
+  if (oat_filename.empty() && oat_fd == -1) {
+    fprintf(stderr, "Output must be supplied with either --oat-file or --oat-fd\n");
+    return EXIT_FAILURE;
+  }
+
+  if (!oat_filename.empty() && oat_fd != -1) {
+    fprintf(stderr, "--oat-file should not be used with --oat-fd\n");
+    return EXIT_FAILURE;
+  }
+
+  if (!oat_filename.empty() && oat_fd != -1) {
+    fprintf(stderr, "--oat-file should not be used with --oat-fd\n");
+    return EXIT_FAILURE;
+  }
+
+  if (!oat_filename.empty() && !oat_name.empty()) {
+    fprintf(stderr, "--oat-file should not be used with --oat-name\n");
+    return EXIT_FAILURE;
+  }
+
+  if (oat_fd != -1 && oat_name.empty()) {
+    fprintf(stderr, "--oat-name should be supplied with --oat-fd\n");
+    return EXIT_FAILURE;
+  }
+
+  if (oat_fd != -1 && image_filename != NULL) {
+    fprintf(stderr, "--oat-fd should not be used with --image\n");
     return EXIT_FAILURE;
   }
 
@@ -404,7 +473,7 @@
   bool image = (image_filename != NULL);
   if (!image && boot_image_filename.empty()) {
     boot_image_filename += host_prefix;
-    boot_image_filename += "/data/art-cache/boot.art";
+    boot_image_filename += "/system/framework/boot.art";
   }
   std::string boot_image_option;
   if (boot_image_filename != NULL) {
@@ -422,6 +491,26 @@
     return EXIT_FAILURE;
   }
 
+  if (dex_filenames.empty() && zip_fd == -1) {
+    fprintf(stderr, "Input must be supplied with either --dex-file or --zip-fd\n");
+    return EXIT_FAILURE;
+  }
+
+  if (!dex_filenames.empty() && zip_fd != -1) {
+    fprintf(stderr, "--dex-file should not be used with --zip-fd\n");
+    return EXIT_FAILURE;
+  }
+
+  if (!dex_filenames.empty() && !zip_name.empty()) {
+    fprintf(stderr, "--dex-file should not be used with --zip-name\n");
+    return EXIT_FAILURE;
+  }
+
+  if (zip_fd != -1 && zip_name.empty()) {
+    fprintf(stderr, "--zip-name should be supplied with --zip-fd\n");
+    return EXIT_FAILURE;
+  }
+
   if (boot_image_option.empty()) {
     if (image_base == 0) {
       fprintf(stderr, "non-zero --base not specified\n");
@@ -430,12 +519,19 @@
   }
 
   // Check early that the result of compilation can be written
-  UniquePtr<File> oat_file(OS::OpenFile(oat_filename.c_str(), true));
+  UniquePtr<File> oat_file;
+  if (!oat_filename.empty()) {
+    oat_file.reset(OS::OpenFile(oat_filename.c_str(), true));
+    oat_name = oat_filename;
+  } else {
+    oat_file.reset(OS::FileFromFd(oat_name.c_str(), oat_fd));
+  }
   if (oat_file.get() == NULL) {
-    PLOG(ERROR) << "Unable to create oat file " << oat_filename;
+    PLOG(ERROR) << "Unable to create oat file " << oat_name;
     return EXIT_FAILURE;
   }
-  LOG(INFO) << "dex2oat: " << oat_filename;
+
+  LOG(INFO) << "dex2oat: " << oat_name;
 
   Runtime::Options options;
   options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
@@ -470,13 +566,33 @@
     }
   }
 
+  std::vector<const DexFile*> dex_files;
+  if (boot_image_option.empty()) {
+    dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath();
+  } else {
+    if (dex_filenames.empty()) {
+      UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd));
+      if (zip_archive.get() == NULL) {
+        LOG(ERROR) << "Failed to zip from file descriptor for " << zip_name;
+        return NULL;
+      }
+      const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_name);
+      if (dex_file == NULL) {
+        LOG(ERROR) << "Failed to open dex from file descriptor for zip file " << zip_name;
+        return EXIT_FAILURE;
+      }
+      dex_files.push_back(dex_file);
+    } else {
+      DexFile::OpenDexFiles(dex_filenames, dex_files, host_prefix);
+    }
+  }
+
   if (!dex2oat->CreateOatFile(boot_image_option,
-                              dex_filenames,
-                              host_prefix,
+                              dex_files,
                               oat_file.get(),
                               image,
                               image_classes.get())) {
-    LOG(ERROR) << "Failed to create oat file" << oat_filename;
+    LOG(ERROR) << "Failed to create oat file" << oat_name;
     return EXIT_FAILURE;
   }
 
diff --git a/src/dex_file.cc b/src/dex_file.cc
index a45455d..81a60fc 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -187,9 +187,13 @@
     LOG(ERROR) << "Failed to open " << filename << " when looking for classes.dex";
     return NULL;
   }
-  UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex));
+  return DexFile::Open(*zip_archive.get(), location);
+}
+
+const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location) {
+  UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex));
   if (zip_entry.get() == NULL) {
-    LOG(ERROR) << "Failed to find classes.dex within " << filename;
+    LOG(ERROR) << "Failed to find classes.dex within " << location;
     return NULL;
   }
 
@@ -199,14 +203,14 @@
                                              length,
                                              PROT_READ | PROT_WRITE));
   if (map.get() == NULL) {
-    LOG(ERROR) << "mmap classes.dex for \"" << filename << "\" failed";
+    LOG(ERROR) << "mmap classes.dex for \"" << location << "\" failed";
     return NULL;
   }
 
   // Extract classes.dex
   bool success = zip_entry->ExtractToMemory(*map.get());
   if (!success) {
-    LOG(ERROR) << "Failed to extract classes.dex from '" << filename << "' to memory";
+    LOG(ERROR) << "Failed to extract classes.dex from '" << location << "' to memory";
     return NULL;
   }
 
diff --git a/src/dex_file.h b/src/dex_file.h
index a0363b0..2ca4308 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -18,6 +18,8 @@
 
 namespace art {
 
+class ZipArchive;
+
 // TODO: move all of the macro functionality into the DexCache class.
 class DexFile {
  public:
@@ -189,6 +191,9 @@
     return OpenMemory(base, length, location, NULL);
   }
 
+  // Opens .dex file from the classes.dex in a zip archive
+  static const DexFile* Open(const ZipArchive& zip_archive, const std::string& location);
+
   // Closes a .dex file.
   virtual ~DexFile();
 
diff --git a/src/oat_file.cc b/src/oat_file.cc
index c37c7a6..58dd984 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -12,8 +12,8 @@
 
 std::string OatFile::DexFilenameToOatFilename(const std::string& location) {
   CHECK(IsValidDexFilename(location) || IsValidZipFilename(location));
-  std::string oat_location(location.substr(0, location.size() - 3));
-  oat_location += "oat";
+  std::string oat_location(location);
+  oat_location += ".oat";
   return oat_location;
 }
 
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 3b204c0..a664852 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -27,7 +27,7 @@
           "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
           "\n");
   fprintf(stderr,
-          "  --oat=<file.oat>: specifies an input oat filename.\n"
+          "  --oat-file=<file.oat>: specifies an input oat filename.\n"
           "      Example: --image=/system/framework/boot.oat\n"
           "\n");
   fprintf(stderr,
@@ -505,8 +505,8 @@
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
-    if (option.starts_with("--oat=")) {
-      oat_filename = option.substr(strlen("--oat=")).data();
+    if (option.starts_with("--oat-file=")) {
+      oat_filename = option.substr(strlen("--oat-file=")).data();
     } else if (option.starts_with("--image=")) {
       image_filename = option.substr(strlen("--image=")).data();
     } else if (option.starts_with("--boot-image=")) {
diff --git a/src/oatopt.cc b/src/oatopt.cc
deleted file mode 100644
index 5862431..0000000
--- a/src/oatopt.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "dex_file.h"
-#include "file.h"
-#include "logging.h"
-#include "oat_file.h"
-#include "os.h"
-#include "UniquePtr.h"
-#include "zip_archive.h"
-
-namespace art {
-
-int ProcessZipFile(int zip_fd, int cache_fd, const char* zip_name, const char* flags) {
-  // TODO: need to read/write to installd opened file descriptors
-  if (false) {
-    UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_fd));
-    if (zip_archive.get() == NULL) {
-      LOG(ERROR) << "Failed to open " << zip_name << " when looking for classes.dex";
-      return -1;
-    }
-
-    UniquePtr<ZipEntry> zip_entry(zip_archive->Find(DexFile::kClassesDex));
-    if (zip_entry.get() == NULL) {
-      LOG(ERROR) << "Failed to find classes.dex within " << zip_name;
-      return -1;
-    }
-
-    UniquePtr<File> file(OS::FileFromFd("oatopt cache file descriptor", cache_fd));
-    bool success = zip_entry->ExtractToFile(*file);
-    if (!success) {
-      LOG(ERROR) << "Failed to extract classes.dex from " << zip_name;
-      return -1;
-    }
-  }
-
-  // Opening a zip file for a dex will extract to art-cache
-  UniquePtr<const DexFile> dex_file(DexFile::Open(zip_name, ""));
-  if (dex_file.get() == NULL) {
-    LOG(ERROR) << "Failed to open " << zip_name;
-    return -1;
-  }
-
-  std::string dex_file_option("--dex-file=");
-  dex_file_option += zip_name;
-
-  std::string oat_file_option("--oat=");
-  oat_file_option += GetArtCacheFilenameOrDie(OatFile::DexFilenameToOatFilename(dex_file.get()->GetLocation()));
-
-  std::string dex2oat("/system/bin/dex2oat");
-#ifndef NDEBUG
-  dex2oat += 'd';
-#endif
-
-  execl(dex2oat.c_str(), dex2oat.c_str(),
-        "--runtime-arg", "-Xms64m",
-        "--runtime-arg", "-Xmx64m",
-        "--boot-image=/data/art-cache/boot.art",
-        dex_file_option.c_str(),
-        oat_file_option.c_str(),
-        NULL);
-  PLOG(FATAL) << "execl(dex2oatd) failed";
-  return -1;
-}
-
-// Parse arguments.  We want:
-//   0. (name of command -- ignored)
-//   1. "--zip"
-//   2. zip fd (input, read-only)
-//   3. cache fd (output, read-write, locked with flock)
-//   4. filename of zipfile
-//   5. flags
-int FromZip(const int argc, const char* const argv[]) {
-  if (argc != 6) {
-    LOG(ERROR) << "Wrong number of args for --zip (found " << argc << ")";
-    return -1;
-  }
-
-  // ignore program name
-
-  // verify --zip
-  CHECK_STREQ(argv[1], "--zip");
-
-  char* zip_end;
-  int zip_fd = strtol(argv[2], &zip_end, 0);
-  if (*zip_end != '\0') {
-    LOG(ERROR) << "bad zip fd: " << argv[2];
-    return -1;
-  }
-#ifndef NDEBUG
-  LOG(INFO) << "zip_fd=" << zip_fd;
-#endif
-
-  char* cache_end;
-  int cache_fd = strtol(argv[3], &cache_end, 0);
-  if (*cache_end != '\0') {
-    LOG(ERROR) << "bad cache fd: " << argv[3];
-    return -1;
-  }
-#ifndef NDEBUG
-  LOG(INFO) << "cache_fd=" << cache_fd;
-#endif
-
-  const char* zip_name = argv[4];
-#ifndef NDEBUG
-  LOG(INFO) << "zip_name=" << zip_name;
-#endif
-
-  const char* flags = argv[5];
-#ifndef NDEBUG
-  LOG(INFO) << "flags=" << flags;
-#endif
-
-  return ProcessZipFile(zip_fd, cache_fd, zip_name, flags);
-}
-
-int oatopt(int argc, char** argv) {
-  setvbuf(stdout, NULL, _IONBF, 0);
-
-  if (true) {
-    for (int i = 0; i < argc; ++i) {
-      LOG(INFO) << "oatopt: option[" << i << "]=" << argv[i];
-    }
-  }
-
-  if (argc > 1) {
-    if (strcmp(argv[1], "--zip") == 0) {
-      return FromZip(argc, argv);
-    }
-  }
-
-  fprintf(stderr,
-          "Usage:\n\n"
-          "Short version: Don't use this.\n\n"
-          "Slightly longer version: This system-internal tool is used to extract\n"
-          "dex files and produce oat files. See the source code for details.\n");
-
-  return 1;
-}
-
-} // namespace art
-
-int main(int argc, char** argv) {
-  return art::oatopt(argc, argv);
-}
diff --git a/src/zip_archive.cc b/src/zip_archive.cc
index 666da23..6105c21 100644
--- a/src/zip_archive.cc
+++ b/src/zip_archive.cc
@@ -287,10 +287,10 @@
     PLOG(WARNING) << "Unable to open '" << filename << "'";
     return NULL;
   }
-  return Open(fd);
+  return OpenFromFd(fd);
 }
 
-ZipArchive* ZipArchive::Open(int fd) {
+ZipArchive* ZipArchive::OpenFromFd(int fd) {
   UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd));
   if (zip_archive.get() == NULL) {
       return NULL;
@@ -306,7 +306,7 @@
   return zip_archive.release();
 }
 
-ZipEntry* ZipArchive::Find(const char* name) {
+ZipEntry* ZipArchive::Find(const char* name) const {
   DCHECK(name != NULL);
   DirEntries::const_iterator it = dir_entries_.find(name);
   if (it == dir_entries_.end()) {
diff --git a/src/zip_archive.h b/src/zip_archive.h
index e367773..6427da9 100644
--- a/src/zip_archive.h
+++ b/src/zip_archive.h
@@ -46,7 +46,7 @@
 
  private:
 
-  ZipEntry(ZipArchive* zip_archive, const byte* ptr) : zip_archive_(zip_archive), ptr_(ptr) {}
+  ZipEntry(const ZipArchive* zip_archive, const byte* ptr) : zip_archive_(zip_archive), ptr_(ptr) {}
 
   // Zip compression methods
   enum {
@@ -62,7 +62,7 @@
   // returns -1 on error
   off_t GetDataOffset();
 
-  ZipArchive* zip_archive_;
+  const ZipArchive* zip_archive_;
 
   // pointer to zip entry within central directory
   const byte* ptr_;
@@ -102,9 +102,9 @@
 
   // return new ZipArchive instance on success, NULL on error.
   static ZipArchive* Open(const std::string& filename);
-  static ZipArchive* Open(int fd);
+  static ZipArchive* OpenFromFd(int fd);
 
-  ZipEntry* Find(const char* name);
+  ZipEntry* Find(const char* name) const;
 
   ~ZipArchive() {
     Close();
diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build
index f3f56ac..4a9fd37 100644
--- a/test/003-omnibus-opcodes/build
+++ b/test/003-omnibus-opcodes/build
@@ -24,4 +24,4 @@
 
 dx -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
 zip ${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar classes.dex
-dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat
+dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index c7d9c3b..896dba6 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -26,4 +26,4 @@
 
 dx --debug --dex --dump-to=classes.lst --output=classes.dex classes
 zip ${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar classes.dex
-dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat
+dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat
diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build
index 325c02a..fde3b67 100644
--- a/test/056-const-string-jumbo/build
+++ b/test/056-const-string-jumbo/build
@@ -44,4 +44,4 @@
 
 dx -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --dump-to=classes.lst --output=classes.dex classes
 zip ${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar classes.dex
-dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat
+dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
index 0497ad7..a7c0e25 100644
--- a/test/085-old-style-inner-class/build
+++ b/test/085-old-style-inner-class/build
@@ -26,4 +26,4 @@
 dx --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
 
 zip ${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar classes.dex
-dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat 2>/dev/null
+dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat 2>/dev/null
diff --git a/test/etc/default-build b/test/etc/default-build
index ce1889e..d039b87 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -26,7 +26,7 @@
 
 dx -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
 zip ${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar classes.dex
-dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat
+dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.jar --oat-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME.oat
 
 if [ -r src-ex ]; then
     mkdir classes-ex
@@ -37,7 +37,7 @@
     mv classes.dex classes-1.dex
     mv classes-ex.dex classes.dex
     zip ${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME-ex.jar classes.dex
-    dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME-ex.jar --oat=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME-ex.oat
+    dex2oat --boot-image=${ANDROID_PRODUCT_OUT}/data/art-test/core.art --dex-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME-ex.jar --oat-file=${ANDROID_PRODUCT_OUT}/data/art-test/$TEST_NAME-ex.oat
     mv classes.dex classes-ex.dex
     mv classes-1.dex classes.dex
 fi