Fix InsertDexFileInToClassLoader to handle null class loaders

Maybe used by legacy apps. This functionality is planned for
deprecation.

Bug: 27954959

(cherry picked from commit f2bf9d640e37b72be8b4f6016d4aa95a0e27b7b4)

Change-Id: I1ae2cf1e33f2f1b237a41c8cc50d2a814a52a95a
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 18def2d..1e7ee65 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7760,12 +7760,11 @@
 void ClassLinker::InsertDexFileInToClassLoader(mirror::Object* dex_file,
                                                mirror::ClassLoader* class_loader) {
   DCHECK(dex_file != nullptr);
-  DCHECK(class_loader != nullptr);
   Thread* const self = Thread::Current();
   WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
-  ClassTable* const table = class_loader->GetClassTable();
+  ClassTable* const table = ClassTableForClassLoader(class_loader);
   DCHECK(table != nullptr);
-  if (table->InsertDexFile(dex_file)) {
+  if (table->InsertDexFile(dex_file) && class_loader != nullptr) {
     // It was not already inserted, perform the write barrier to let the GC know the class loader's
     // class table was modified.
     Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index b4b7f34..5de502b 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -595,6 +595,7 @@
       REQUIRES(!Locks::classlinker_classes_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  // May be called with null class_loader due to legacy code. b/27954959
   void InsertDexFileInToClassLoader(mirror::Object* dex_file, mirror::ClassLoader* class_loader)
       REQUIRES(!Locks::classlinker_classes_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/test/068-classloader/expected.txt b/test/068-classloader/expected.txt
index 8725799..ae937e0 100644
--- a/test/068-classloader/expected.txt
+++ b/test/068-classloader/expected.txt
@@ -13,3 +13,4 @@
 Got LinkageError on IDI (early)
 class Main
 Got expected ClassNotFoundException
+Loaded class into null class loader
diff --git a/test/068-classloader/src/Main.java b/test/068-classloader/src/Main.java
index 361e293..b2d843b 100644
--- a/test/068-classloader/src/Main.java
+++ b/test/068-classloader/src/Main.java
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
 /**
  * Class loader test.
  */
@@ -62,6 +65,28 @@
         testSeparation();
 
         testClassForName();
+
+        testNullClassLoader();
+    }
+
+    static void testNullClassLoader() {
+        try {
+            /* this is the "alternate" DEX/Jar file */
+            String DEX_FILE = System.getenv("DEX_LOCATION") + "/068-classloader-ex.jar";
+            /* on Dalvik, this is a DexFile; otherwise, it's null */
+            Class mDexClass = Class.forName("dalvik.system.DexFile");
+            Constructor ctor = mDexClass.getConstructor(new Class[] {String.class});
+            Object mDexFile = ctor.newInstance(DEX_FILE);
+            Method meth = mDexClass.getMethod("loadClass",
+                    new Class[] { String.class, ClassLoader.class });
+            Object klass = meth.invoke(mDexFile, "Mutator", null);
+            if (klass == null) {
+                throw new AssertionError("loadClass with nullclass loader failed");
+            }
+        } catch (Exception e) {
+            System.out.println(e);
+        }
+        System.out.println("Loaded class into null class loader");
     }
 
     static void testSeparation() {