Setup Thread's context ClassLoader and add image DexFiles to ClassLinker's boot classpath

Change-Id: I84337c69ff743c58be9e7125d17fcccb514614ef
diff --git a/Android.mk b/Android.mk
index 9a53fd0..7008326 100644
--- a/Android.mk
+++ b/Android.mk
@@ -134,7 +134,7 @@
 test-art-target-oat-process-am: $(TARGET_OUT_JAVA_LIBRARIES)/am.oat test-art-target-sync
 	adb remount
 	adb sync
-	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Ximage:/system/framework/boot.art -Ximage:/system/framework/am.art /system/bin com.android.commands.am.Am start http://android.com && touch /sdcard/test-art-target-process-am"
+	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Ximage:/system/framework/boot.art /system/bin com.android.commands.am.Am start http://android.com && touch /sdcard/test-art-target-process-am"
 	$(hide) (adb pull /sdcard/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
 
@@ -158,7 +158,7 @@
 	  sleep 30; \
 	fi
 	adb shell kill `adb shell ps | fgrep com.android.calculator2 | sed -e 's/[^ ]* *\([0-9]*\).*/\1/'`
-	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Ximage:/system/framework/boot.art -Ximage:/system/framework/am.art /system/bin com.android.commands.am.Am start -a android.intent.action.MAIN -n com.android.calculator2/.Calculator && touch /sdcard/test-art-target-process-Calculator"
+	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Ximage:/system/framework/boot.art /system/bin com.android.commands.am.Am start -a android.intent.action.MAIN -n com.android.calculator2/.Calculator && touch /sdcard/test-art-target-process-Calculator"
 	$(hide) (adb pull /sdcard/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
 
diff --git a/oat_process/app_main.cpp b/oat_process/app_main.cpp
index 53321f1..4e90dab 100644
--- a/oat_process/app_main.cpp
+++ b/oat_process/app_main.cpp
@@ -77,7 +77,7 @@
         char* slashClassName = toSlashClassName(mClassName);
         mClass = env->FindClass(slashClassName);
         if (mClass == NULL) {
-            LOG(ERROR) << StringPrintf("ERROR: could not find class '%s'\n", mClassName);
+            LOG(FATAL) << "Could not find class: " << mClassName;
         }
         free(slashClassName);
 
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 5159f06..97a75ac 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -633,7 +633,7 @@
         const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
         CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file->GetDexFileChecksum());
 
-        RegisterDexFile(*dex_file, dex_cache);
+        AppendToBootClassPath(*dex_file, dex_cache);
       }
     }
   }
@@ -852,22 +852,18 @@
   std::string class_name_string = DescriptorToDot(descriptor);
   ScopedThreadStateChange(self, Thread::kNative);
   JNIEnv* env = self->GetJniEnv();
-  jclass c = AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader));
-  CHECK(c != NULL);
+  ScopedLocalRef<jclass> c(env, AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader)));
+  CHECK(c.get() != NULL);
   // TODO: cache method?
-  jmethodID mid = env->GetMethodID(c, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+  jmethodID mid = env->GetMethodID(c.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
   CHECK(mid != NULL);
-  jobject class_name_object = env->NewStringUTF(class_name_string.c_str());
+  ScopedLocalRef<jobject> class_name_object(env, env->NewStringUTF(class_name_string.c_str()));
   if (class_name_string == NULL) {
     return NULL;
   }
-  jobject class_loader_object = AddLocalReference<jobject>(env, class_loader);
-  jobject result = env->CallObjectMethod(class_loader_object, mid, class_name_object);
-  Class* klass_result = Decode<Class*>(env, result);
-  env->DeleteLocalRef(result);
-  env->DeleteLocalRef(class_name_object);
-  env->DeleteLocalRef(c);
-  return klass_result;
+  ScopedLocalRef<jobject> class_loader_object(env, AddLocalReference<jobject>(env, class_loader));
+  ScopedLocalRef<jobject> result(env, env->CallObjectMethod(class_loader_object.get(), mid, class_name_object.get()));
+  return Decode<Class*>(env, result.get());
 }
 
 Class* ClassLinker::DefineClass(const std::string& descriptor,
@@ -1608,9 +1604,8 @@
     if (klass->IsErroneous()) {
       // The caller wants an exception, but it was thrown in a
       // different thread.  Synthesize one here.
-      self->ThrowNewExceptionF("Ljava/lang/NoClassDefFoundError;",
-          "<clinit> failed for class %s; see exception in other thread",
-          PrettyDescriptor(klass->GetDescriptor()).c_str());
+      ThrowNoClassDefFoundError("<clinit> failed for class %s; see exception in other thread",
+                                PrettyDescriptor(klass->GetDescriptor()).c_str());
       return false;
     }
     if (klass->IsInitialized()) {
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 5905642..96b7817 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -117,12 +117,15 @@
   if (dex_file == NULL) {
     return NULL;
   }
-  String* name = Decode<String*>(env, javaName);
-  const char* class_name = name->ToModifiedUtf8().c_str();
-  const std::string descriptor = DotToDescriptor(class_name);
+  ScopedUtfChars class_name(env, javaName);
+  if (class_name.c_str() == NULL) {
+    return NULL;
+  }
+  const std::string descriptor = DotToDescriptor(class_name.c_str());
   const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
   if (dex_class_def == NULL) {
-    jniThrowExceptionFmt(env, "java/lang/NoClassDefFoundError", "Class %s not found", class_name);
+    jniThrowExceptionFmt(env, "java/lang/NoClassDefFoundError", "Class %s not found",
+                         class_name.c_str());
     return NULL;
   }
 
diff --git a/src/runtime.cc b/src/runtime.cc
index c733bfe..b4c25d3 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -320,16 +320,17 @@
   CHECK_EQ(self->GetState(), Thread::kNative);
 
   JNIEnv* env = self->GetJniEnv();
-  ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/ClassLoader"));
-  CHECK(c.get() != NULL);
-  jmethodID mid = env->GetStaticMethodID(c.get(),
-                                         "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
-  CHECK(mid != NULL);
-  ScopedLocalRef<jobject> result(env, env->CallStaticObjectMethod(c.get(), mid));
-  CHECK(result.get() != NULL);
+  ScopedLocalRef<jclass> ClassLoader_class(env, env->FindClass("java/lang/ClassLoader"));
+  CHECK(ClassLoader_class.get() != NULL);
+  jmethodID getSystemClassLoader = env->GetStaticMethodID(ClassLoader_class.get(),
+                                                          "getSystemClassLoader",
+                                                          "()Ljava/lang/ClassLoader;");
+  CHECK(getSystemClassLoader != NULL);
+  ScopedLocalRef<jobject> class_loader(env, env->CallStaticObjectMethod(ClassLoader_class.get(),
+                                                                        getSystemClassLoader));
+  CHECK(class_loader.get() != NULL);
 
-  ClassLoader* class_loader = Decode<ClassLoader*>(env, result.get());
-  Thread::Current()->SetClassLoaderOverride(class_loader);
+  Thread::Current()->SetClassLoaderOverride(Decode<ClassLoader*>(env, class_loader.get()));
 }
 
 void Runtime::Start() {
diff --git a/src/thread.cc b/src/thread.cc
index 4dcef55..d9c6b4f 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -27,6 +27,7 @@
 #include <list>
 
 #include "class_linker.h"
+#include "class_loader.h"
 #include "context.h"
 #include "dex_verifier.h"
 #include "heap.h"
@@ -631,6 +632,7 @@
 
   Class* boolean_class = FindPrimitiveClassOrDie(class_linker, 'Z');
   Class* int_class = FindPrimitiveClassOrDie(class_linker, 'I');
+  Class* ClassLoader_class = FindClassOrDie(class_linker, "Ljava/lang/ClassLoader;");
   Class* String_class = FindClassOrDie(class_linker, "Ljava/lang/String;");
   Class* Thread_class = FindClassOrDie(class_linker, "Ljava/lang/Thread;");
   Class* ThreadGroup_class = FindClassOrDie(class_linker, "Ljava/lang/ThreadGroup;");
@@ -654,7 +656,11 @@
       "uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
 
   // Finish attaching the main thread.
-  Thread::Current()->CreatePeer("main", false);
+  Thread* self = Thread::Current();
+  self->CreatePeer("main", false);
+
+  const Field* Thread_contextClassLoader = FindFieldOrDie(Thread_class , "contextClassLoader", ClassLoader_class);
+  Thread_contextClassLoader->SetObject(self->GetPeer(), self->GetClassLoaderOverride());
 }
 
 void Thread::Shutdown() {