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 17package android.app; 18 19import android.os.Build; 20import android.os.GraphicsEnvironment; 21import android.os.Trace; 22import android.util.ArrayMap; 23 24import com.android.internal.os.ClassLoaderFactory; 25 26import dalvik.system.PathClassLoader; 27 28import java.util.Collection; 29 30/** @hide */ 31public class ApplicationLoaders { 32 public static ApplicationLoaders getDefault() { 33 return gApplicationLoaders; 34 } 35 36 ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, 37 String librarySearchPath, String libraryPermittedPath, 38 ClassLoader parent, String classLoaderName) { 39 // For normal usage the cache key used is the same as the zip path. 40 return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, 41 libraryPermittedPath, parent, zip, classLoaderName); 42 } 43 44 private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, 45 String librarySearchPath, String libraryPermittedPath, 46 ClassLoader parent, String cacheKey, 47 String classLoaderName) { 48 /* 49 * This is the parent we use if they pass "null" in. In theory 50 * this should be the "system" class loader; in practice we 51 * don't use that and can happily (and more efficiently) use the 52 * bootstrap class loader. 53 */ 54 ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent(); 55 56 synchronized (mLoaders) { 57 if (parent == null) { 58 parent = baseParent; 59 } 60 61 /* 62 * If we're one step up from the base class loader, find 63 * something in our cache. Otherwise, we create a whole 64 * new ClassLoader for the zip archive. 65 */ 66 if (parent == baseParent) { 67 ClassLoader loader = mLoaders.get(cacheKey); 68 if (loader != null) { 69 return loader; 70 } 71 72 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); 73 74 ClassLoader classloader = ClassLoaderFactory.createClassLoader( 75 zip, librarySearchPath, libraryPermittedPath, parent, 76 targetSdkVersion, isBundled, classLoaderName); 77 78 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 79 80 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setLayerPaths"); 81 GraphicsEnvironment.getInstance().setLayerPaths( 82 classloader, librarySearchPath, libraryPermittedPath); 83 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 84 85 mLoaders.put(cacheKey, classloader); 86 return classloader; 87 } 88 89 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); 90 ClassLoader loader = ClassLoaderFactory.createClassLoader( 91 zip, null, parent, classLoaderName); 92 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 93 return loader; 94 } 95 } 96 97 /** 98 * Creates a classloader for the WebView APK and places it in the cache of loaders maintained 99 * by this class. This is used in the WebView zygote, where its presence in the cache speeds up 100 * startup and enables memory sharing. 101 */ 102 public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath, 103 String cacheKey) { 104 // The correct paths are calculated by WebViewZygote in the system server and passed to 105 // us here. We hardcode the other parameters: WebView always targets the current SDK, 106 // does not need to use non-public system libraries, and uses the base classloader as its 107 // parent to permit usage of the cache. 108 // The cache key is passed separately to enable the stub WebView to be cached under the 109 // stub's APK path, when the actual package path is the donor APK. 110 return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, 111 cacheKey, null /* classLoaderName */); 112 } 113 114 /** 115 * Adds a new path the classpath of the given loader. 116 * @throws IllegalStateException if the provided class loader is not a {@link PathClassLoader}. 117 */ 118 void addPath(ClassLoader classLoader, String dexPath) { 119 if (!(classLoader instanceof PathClassLoader)) { 120 throw new IllegalStateException("class loader is not a PathClassLoader"); 121 } 122 final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader; 123 baseDexClassLoader.addDexPath(dexPath); 124 } 125 126 /** 127 * @hide 128 */ 129 void addNative(ClassLoader classLoader, Collection<String> libPaths) { 130 if (!(classLoader instanceof PathClassLoader)) { 131 throw new IllegalStateException("class loader is not a PathClassLoader"); 132 } 133 final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader; 134 baseDexClassLoader.addNativePath(libPaths); 135 } 136 137 private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>(); 138 139 private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); 140} 141