Implement DexFile_isDexOptNeeded

Change-Id: Ib4d641ca7000b0f563cb9ab9c0970d6b8ad92060
diff --git a/src/class_linker.h b/src/class_linker.h
index 7c5acaa..e74494e 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -207,6 +207,9 @@
   const DexFile& FindDexFile(const DexCache* dex_cache) const;
   DexCache* FindDexCache(const DexFile& dex_file) const;
   bool IsDexFileRegistered(const DexFile& dex_file) const;
+
+  // Find, possibily opening, an OatFile corresponding to a DexFile
+  const OatFile* FindOatFile(const DexFile& dex_file);
   const OatFile* FindOatFile(const std::string& location);
 
   // TODO: replace this with multiple methods that allocate the correct managed type.
@@ -299,9 +302,6 @@
   void RegisterDexFileLocked(const DexFile& dex_file, DexCache* dex_cache);
   bool IsDexFileRegisteredLocked(const DexFile& dex_file) const;
 
-  // Find, possibily opening, an OatFile corresponding to a DexFile
-  const OatFile* FindOatFile(const DexFile& dex_file);
-
   bool InitializeClass(Class* klass, bool can_run_clinit);
   bool WaitForInitializeClass(Class* klass, Thread* self, ObjectLock& lock);
   bool ValidateSuperClassDescriptors(const Class* klass);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index cad1acd..e6d45e3 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+#include <unistd.h>
+
 #include "class_loader.h"
 #include "class_linker.h"
 #include "dex_file.h"
 #include "logging.h"
+#include "os.h"
 #include "runtime.h"
 #include "toStringArray.h"
 #include "ScopedUtfChars.h"
@@ -158,10 +161,34 @@
 jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) {
   ScopedUtfChars filename(env, javaFilename);
   if (filename.c_str() == NULL) {
-    return JNI_FALSE;
+    return JNI_TRUE;
   }
-  // TODO: return true if we need to extract dex or run dex2oat
-  UNIMPLEMENTED(WARNING) << filename.c_str();
+
+  if (!OS::FileExists(filename.c_str())) {
+    jniThrowExceptionFmt(env, "java/io/FileNotFoundException", "%s", filename.c_str());
+    return JNI_TRUE;
+  }
+
+  // Always treat elements of the bootclasspath as up-to-date.  The
+  // fact that code is running at all means that this should be true.
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  const std::vector<const DexFile*>& boot_class_path = class_linker->GetBootClassPath();
+  for (size_t i = 0; i < boot_class_path.size(); i++) {
+    if (boot_class_path[i]->GetLocation() == filename.c_str()) {
+      return JNI_FALSE;
+    }
+  }
+
+  UniquePtr<const DexFile> dex_file(DexFile::Open(filename.c_str(), ""));
+  if (dex_file.get() == NULL) {
+    return JNI_TRUE;
+  }
+
+  UniquePtr<const OatFile> oat_file(class_linker->FindOatFile(*dex_file.get()));
+  if (oat_file.get() == NULL) {
+    return JNI_TRUE;
+  }
+
   return JNI_FALSE;
 }