OSDN Git Service

ApplicationLoaders: hard failures & tests
authorSteven Moreland <smoreland@google.com>
Wed, 27 Mar 2019 13:38:42 +0000 (06:38 -0700)
committerSteven Moreland <smoreland@google.com>
Fri, 5 Apr 2019 16:16:17 +0000 (16:16 +0000)
Make errors in ApplicationLoaders caching hard failures since they are
only ever expected under bad configuration. Tests for these are also
added.

Test: atest android.app.ApplicationLoadersTest
Bug: 128529256
Change-Id: Ib259bcdf472e6a2f7f6b1071bb70cfead4502231
(cherry picked from commit 0975a412b3b7ffa11aa9bcdecba3a9e0b3c55d81)

core/java/android/app/ApplicationLoaders.java
core/tests/coretests/src/android/app/ApplicationLoadersTest.java [new file with mode: 0644]

index faa30f3..2e59b90 100644 (file)
@@ -145,8 +145,7 @@ public class ApplicationLoaders {
      */
     public void createAndCacheNonBootclasspathSystemClassLoaders(SharedLibraryInfo[] libs) {
         if (mSystemLibsCacheMap != null) {
-            Log.wtf(TAG, "Already cached.");
-            return;
+            throw new IllegalStateException("Already cached.");
         }
 
         mSystemLibsCacheMap = new HashMap<String, CachedClassLoader>();
@@ -159,7 +158,8 @@ public class ApplicationLoaders {
     /**
      * Caches a single non-bootclasspath class loader.
      *
-     * All of this library's dependencies must have previously been cached.
+     * All of this library's dependencies must have previously been cached. Otherwise, an exception
+     * is thrown.
      */
     private void createAndCacheNonBootclasspathSystemClassLoader(SharedLibraryInfo lib) {
         String path = lib.getPath();
@@ -174,9 +174,8 @@ public class ApplicationLoaders {
                 CachedClassLoader cached = mSystemLibsCacheMap.get(dependencyPath);
 
                 if (cached == null) {
-                    Log.e(TAG, "Failed to find dependency " + dependencyPath
-                            + " of cached library " + path);
-                    return;
+                    throw new IllegalStateException("Failed to find dependency " + dependencyPath
+                            + " of cachedlibrary " + path);
                 }
 
                 sharedLibraries.add(cached.loader);
@@ -189,8 +188,8 @@ public class ApplicationLoaders {
                 null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/);
 
         if (classLoader == null) {
-            Log.e(TAG, "Failed to cache " + path);
-            return;
+            // bad configuration or break in classloading code
+            throw new IllegalStateException("Failed to cache " + path);
         }
 
         CachedClassLoader cached = new CachedClassLoader();
@@ -215,7 +214,7 @@ public class ApplicationLoaders {
      *
      * If there is an error or the cache is not available, this returns null.
      */
-    private ClassLoader getCachedNonBootclasspathSystemLib(String zip, ClassLoader parent,
+    public ClassLoader getCachedNonBootclasspathSystemLib(String zip, ClassLoader parent,
             String classLoaderName, List<ClassLoader> sharedLibraries) {
         if (mSystemLibsCacheMap == null) {
             return null;
diff --git a/core/tests/coretests/src/android/app/ApplicationLoadersTest.java b/core/tests/coretests/src/android/app/ApplicationLoadersTest.java
new file mode 100644 (file)
index 0000000..4b9910c
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.pm.SharedLibraryInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApplicationLoadersTest {
+
+    // a library installed onto the device with no dependencies
+    private static final String LIB_A = "/system/framework/android.hidl.base-V1.0-java.jar";
+    // a library installed onto the device which only depends on A
+    private static final String LIB_DEP_A = "/system/framework/android.hidl.manager-V1.0-java.jar";
+
+    private static SharedLibraryInfo createLib(String zip) {
+        return new SharedLibraryInfo(
+                zip, null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/,
+                SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/,
+                null /*dependentPackages*/, null /*dependencies*/);
+    }
+
+    @Test
+    public void testGetNonExistantLib() {
+        ApplicationLoaders loaders = new ApplicationLoaders();
+        assertEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+                "/system/framework/nonexistantlib.jar", null, null, null));
+    }
+
+    @Test
+    public void testCacheExistantLib() {
+        ApplicationLoaders loaders = new ApplicationLoaders();
+        SharedLibraryInfo libA = createLib(LIB_A);
+
+        loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA});
+
+        assertNotEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+                LIB_A, null, null, null));
+    }
+
+    @Test
+    public void testNonNullParent() {
+        ApplicationLoaders loaders = new ApplicationLoaders();
+        SharedLibraryInfo libA = createLib(LIB_A);
+
+        ClassLoader parent = ClassLoader.getSystemClassLoader();
+        assertNotEquals(null, parent);
+
+        loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA});
+
+        assertEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+                LIB_A, parent, null, null));
+    }
+
+    @Test
+    public void testNonNullClassLoaderNamespace() {
+        ApplicationLoaders loaders = new ApplicationLoaders();
+        SharedLibraryInfo libA = createLib(LIB_A);
+
+        loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA});
+
+        assertEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+                LIB_A, null, "other classloader", null));
+    }
+
+    @Test
+    public void testDifferentSharedLibraries() {
+        ApplicationLoaders loaders = new ApplicationLoaders();
+        SharedLibraryInfo libA = createLib(LIB_A);
+
+        // any other existant lib
+        ClassLoader dep = ClassLoader.getSystemClassLoader();
+        ArrayList<ClassLoader> sharedLibraries = new ArrayList<>();
+        sharedLibraries.add(dep);
+
+        loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA});
+
+        assertEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+                LIB_A, null, null, sharedLibraries));
+    }
+
+    @Test
+    public void testDependentLibs() {
+        ApplicationLoaders loaders = new ApplicationLoaders();
+        SharedLibraryInfo libA = createLib(LIB_A);
+        SharedLibraryInfo libB = createLib(LIB_DEP_A);
+        libB.addDependency(libA);
+
+        loaders.createAndCacheNonBootclasspathSystemClassLoaders(
+                new SharedLibraryInfo[]{libA, libB});
+
+        ClassLoader loadA = loaders.getCachedNonBootclasspathSystemLib(
+                LIB_A, null, null, null);
+        assertNotEquals(null, loadA);
+
+        ArrayList<ClassLoader> sharedLibraries = new ArrayList<>();
+        sharedLibraries.add(loadA);
+
+        assertNotEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+                LIB_DEP_A, null, null, sharedLibraries));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testDependentLibsWrongOrder() {
+        ApplicationLoaders loaders = new ApplicationLoaders();
+        SharedLibraryInfo libA = createLib(LIB_A);
+        SharedLibraryInfo libB = createLib(LIB_DEP_A);
+        libB.addDependency(libA);
+
+        loaders.createAndCacheNonBootclasspathSystemClassLoaders(
+                new SharedLibraryInfo[]{libB, libA});
+    }
+}