1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.app; 18 19 import android.os.Build; 20 import android.os.Trace; 21 import android.util.ArrayMap; 22 import com.android.internal.os.ClassLoaderFactory; 23 import dalvik.system.PathClassLoader; 24 25 /** @hide */ 26 public class ApplicationLoaders { 27 public static ApplicationLoaders getDefault() { 28 return gApplicationLoaders; 29 } 30 31 ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, 32 String librarySearchPath, String libraryPermittedPath, 33 ClassLoader parent, String classLoaderName) { 34 // For normal usage the cache key used is the same as the zip path. 35 return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, 36 libraryPermittedPath, parent, zip, classLoaderName); 37 } 38 39 private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, 40 String librarySearchPath, String libraryPermittedPath, 41 ClassLoader parent, String cacheKey, 42 String classLoaderName) { 43 /* 44 * This is the parent we use if they pass "null" in. In theory 45 * this should be the "system" class loader; in practice we 46 * don't use that and can happily (and more efficiently) use the 47 * bootstrap class loader. 48 */ 49 ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent(); 50 51 synchronized (mLoaders) { 52 if (parent == null) { 53 parent = baseParent; 54 } 55 56 /* 57 * If we're one step up from the base class loader, find 58 * something in our cache. Otherwise, we create a whole 59 * new ClassLoader for the zip archive. 60 */ 61 if (parent == baseParent) { 62 ClassLoader loader = mLoaders.get(cacheKey); 63 if (loader != null) { 64 return loader; 65 } 66 67 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); 68 69 ClassLoader classloader = ClassLoaderFactory.createClassLoader( 70 zip, librarySearchPath, libraryPermittedPath, parent, 71 targetSdkVersion, isBundled, classLoaderName); 72 73 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 74 75 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setupVulkanLayerPath"); 76 setupVulkanLayerPath(classloader, librarySearchPath); 77 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 78 79 mLoaders.put(cacheKey, classloader); 80 return classloader; 81 } 82 83 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); 84 ClassLoader loader = ClassLoaderFactory.createClassLoader( 85 zip, null, parent, classLoaderName); 86 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 87 return loader; 88 } 89 } 90 91 /** 92 * Creates a classloader for the WebView APK and places it in the cache of loaders maintained 93 * by this class. This is used in the WebView zygote, where its presence in the cache speeds up 94 * startup and enables memory sharing. 95 */ 96 public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath, 97 String cacheKey) { 98 // The correct paths are calculated by WebViewZygote in the system server and passed to 99 // us here. We hardcode the other parameters: WebView always targets the current SDK, 100 // does not need to use non-public system libraries, and uses the base classloader as its 101 // parent to permit usage of the cache. 102 // The cache key is passed separately to enable the stub WebView to be cached under the 103 // stub's APK path, when the actual package path is the donor APK. 104 return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, 105 cacheKey, null /* classLoaderName */); 106 } 107 108 private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath); 109 110 /** 111 * Adds a new path the classpath of the given loader. 112 * @throws IllegalStateException if the provided class loader is not a {@link PathClassLoader}. 113 */ 114 void addPath(ClassLoader classLoader, String dexPath) { 115 if (!(classLoader instanceof PathClassLoader)) { 116 throw new IllegalStateException("class loader is not a PathClassLoader"); 117 } 118 final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader; 119 baseDexClassLoader.addDexPath(dexPath); 120 } 121 122 private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>(); 123 124 private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); 125 } 126