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.compat.annotation.UnsupportedAppUsage; 20 import android.content.pm.SharedLibraryInfo; 21 import android.os.Build; 22 import android.os.GraphicsEnvironment; 23 import android.os.Trace; 24 import android.util.ArrayMap; 25 import android.util.Log; 26 27 import com.android.internal.os.ClassLoaderFactory; 28 29 import dalvik.system.PathClassLoader; 30 31 import java.util.ArrayList; 32 import java.util.Collection; 33 import java.util.HashMap; 34 import java.util.List; 35 import java.util.Map; 36 37 /** @hide */ 38 public class ApplicationLoaders { 39 private static final String TAG = "ApplicationLoaders"; 40 41 @UnsupportedAppUsage getDefault()42 public static ApplicationLoaders getDefault() { 43 return gApplicationLoaders; 44 } 45 getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String classLoaderName)46 ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, 47 String librarySearchPath, String libraryPermittedPath, 48 ClassLoader parent, String classLoaderName) { 49 return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, 50 librarySearchPath, libraryPermittedPath, parent, classLoaderName, 51 null); 52 } 53 getClassLoaderWithSharedLibraries( String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries)54 ClassLoader getClassLoaderWithSharedLibraries( 55 String zip, int targetSdkVersion, boolean isBundled, 56 String librarySearchPath, String libraryPermittedPath, 57 ClassLoader parent, String classLoaderName, 58 List<ClassLoader> sharedLibraries) { 59 // For normal usage the cache key used is the same as the zip path. 60 return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, 61 libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries); 62 } 63 64 /** 65 * Gets a class loader for a shared library. Additional dependent shared libraries are allowed 66 * to be specified (sharedLibraries). 67 * 68 * Additionally, as an optimization, this will return a pre-created ClassLoader if one has 69 * been cached by createAndCacheNonBootclasspathSystemClassLoaders. 70 */ getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries)71 ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion, 72 boolean isBundled, String librarySearchPath, String libraryPermittedPath, 73 ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) { 74 ClassLoader loader = getCachedNonBootclasspathSystemLib(zip, parent, classLoaderName, 75 sharedLibraries); 76 if (loader != null) { 77 return loader; 78 } 79 80 return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, 81 librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries); 82 } 83 getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey, String classLoaderName, List<ClassLoader> sharedLibraries)84 private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, 85 String librarySearchPath, String libraryPermittedPath, 86 ClassLoader parent, String cacheKey, 87 String classLoaderName, List<ClassLoader> sharedLibraries) { 88 /* 89 * This is the parent we use if they pass "null" in. In theory 90 * this should be the "system" class loader; in practice we 91 * don't use that and can happily (and more efficiently) use the 92 * bootstrap class loader. 93 */ 94 ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent(); 95 96 synchronized (mLoaders) { 97 if (parent == null) { 98 parent = baseParent; 99 } 100 101 /* 102 * If we're one step up from the base class loader, find 103 * something in our cache. Otherwise, we create a whole 104 * new ClassLoader for the zip archive. 105 */ 106 if (parent == baseParent) { 107 ClassLoader loader = mLoaders.get(cacheKey); 108 if (loader != null) { 109 return loader; 110 } 111 112 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); 113 114 ClassLoader classloader = ClassLoaderFactory.createClassLoader( 115 zip, librarySearchPath, libraryPermittedPath, parent, 116 targetSdkVersion, isBundled, classLoaderName, sharedLibraries); 117 118 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 119 120 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setLayerPaths"); 121 GraphicsEnvironment.getInstance().setLayerPaths( 122 classloader, librarySearchPath, libraryPermittedPath); 123 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 124 125 if (cacheKey != null) { 126 mLoaders.put(cacheKey, classloader); 127 } 128 return classloader; 129 } 130 131 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); 132 ClassLoader loader = ClassLoaderFactory.createClassLoader( 133 zip, null, parent, classLoaderName, sharedLibraries); 134 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 135 return loader; 136 } 137 } 138 139 /** 140 * Caches system library class loaders which are not on the bootclasspath but are still used 141 * by many system apps. 142 * 143 * All libraries in the closure of libraries to be loaded must be in libs. A library can 144 * only depend on libraries that come before it in the list. 145 */ createAndCacheNonBootclasspathSystemClassLoaders(SharedLibraryInfo[] libs)146 public void createAndCacheNonBootclasspathSystemClassLoaders(SharedLibraryInfo[] libs) { 147 if (mSystemLibsCacheMap != null) { 148 throw new IllegalStateException("Already cached."); 149 } 150 151 mSystemLibsCacheMap = new HashMap<String, CachedClassLoader>(); 152 153 for (SharedLibraryInfo lib : libs) { 154 createAndCacheNonBootclasspathSystemClassLoader(lib); 155 } 156 } 157 158 /** 159 * Caches a single non-bootclasspath class loader. 160 * 161 * All of this library's dependencies must have previously been cached. Otherwise, an exception 162 * is thrown. 163 */ createAndCacheNonBootclasspathSystemClassLoader(SharedLibraryInfo lib)164 private void createAndCacheNonBootclasspathSystemClassLoader(SharedLibraryInfo lib) { 165 String path = lib.getPath(); 166 List<SharedLibraryInfo> dependencies = lib.getDependencies(); 167 168 // get cached classloaders for dependencies 169 ArrayList<ClassLoader> sharedLibraries = null; 170 if (dependencies != null) { 171 sharedLibraries = new ArrayList<ClassLoader>(dependencies.size()); 172 for (SharedLibraryInfo dependency : dependencies) { 173 String dependencyPath = dependency.getPath(); 174 CachedClassLoader cached = mSystemLibsCacheMap.get(dependencyPath); 175 176 if (cached == null) { 177 throw new IllegalStateException("Failed to find dependency " + dependencyPath 178 + " of cachedlibrary " + path); 179 } 180 181 sharedLibraries.add(cached.loader); 182 } 183 } 184 185 // assume cached libraries work with current sdk since they are built-in 186 ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/, 187 null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/, 188 null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/); 189 190 if (classLoader == null) { 191 // bad configuration or break in classloading code 192 throw new IllegalStateException("Failed to cache " + path); 193 } 194 195 CachedClassLoader cached = new CachedClassLoader(); 196 cached.loader = classLoader; 197 cached.sharedLibraries = sharedLibraries; 198 199 Log.d(TAG, "Created zygote-cached class loader: " + path); 200 mSystemLibsCacheMap.put(path, cached); 201 } 202 sharedLibrariesEquals(List<ClassLoader> lhs, List<ClassLoader> rhs)203 private static boolean sharedLibrariesEquals(List<ClassLoader> lhs, List<ClassLoader> rhs) { 204 if (lhs == null) { 205 return rhs == null; 206 } 207 208 return lhs.equals(rhs); 209 } 210 211 /** 212 * Returns lib cached with createAndCacheNonBootclasspathSystemClassLoader. This is called by 213 * the zygote during caching. 214 * 215 * If there is an error or the cache is not available, this returns null. 216 */ getCachedNonBootclasspathSystemLib(String zip, ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries)217 public ClassLoader getCachedNonBootclasspathSystemLib(String zip, ClassLoader parent, 218 String classLoaderName, List<ClassLoader> sharedLibraries) { 219 if (mSystemLibsCacheMap == null) { 220 return null; 221 } 222 223 // we only cache top-level libs with the default class loader 224 if (parent != null || classLoaderName != null) { 225 return null; 226 } 227 228 CachedClassLoader cached = mSystemLibsCacheMap.get(zip); 229 if (cached == null) { 230 return null; 231 } 232 233 // cached must be built and loaded in the same environment 234 if (!sharedLibrariesEquals(sharedLibraries, cached.sharedLibraries)) { 235 Log.w(TAG, "Unexpected environment for cached library: (" + sharedLibraries + "|" 236 + cached.sharedLibraries + ")"); 237 return null; 238 } 239 240 Log.d(TAG, "Returning zygote-cached class loader: " + zip); 241 return cached.loader; 242 } 243 244 /** 245 * Creates a classloader for the WebView APK and places it in the cache of loaders maintained 246 * by this class. This is used in the WebView zygote, where its presence in the cache speeds up 247 * startup and enables memory sharing. 248 */ createAndCacheWebViewClassLoader(String packagePath, String libsPath, String cacheKey)249 public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath, 250 String cacheKey) { 251 // The correct paths are calculated by WebViewZygote in the system server and passed to 252 // us here. We hardcode the other parameters: WebView always targets the current SDK, 253 // does not need to use non-public system libraries, and uses the base classloader as its 254 // parent to permit usage of the cache. 255 // The cache key is passed separately to enable the stub WebView to be cached under the 256 // stub's APK path, when the actual package path is the donor APK. 257 return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, 258 cacheKey, null /* classLoaderName */, null /* sharedLibraries */); 259 } 260 261 /** 262 * Adds a new path the classpath of the given loader. 263 * @throws IllegalStateException if the provided class loader is not a {@link PathClassLoader}. 264 */ addPath(ClassLoader classLoader, String dexPath)265 void addPath(ClassLoader classLoader, String dexPath) { 266 if (!(classLoader instanceof PathClassLoader)) { 267 throw new IllegalStateException("class loader is not a PathClassLoader"); 268 } 269 final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader; 270 baseDexClassLoader.addDexPath(dexPath); 271 } 272 273 /** 274 * @hide 275 */ addNative(ClassLoader classLoader, Collection<String> libPaths)276 void addNative(ClassLoader classLoader, Collection<String> libPaths) { 277 if (!(classLoader instanceof PathClassLoader)) { 278 throw new IllegalStateException("class loader is not a PathClassLoader"); 279 } 280 final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader; 281 baseDexClassLoader.addNativePath(libPaths); 282 } 283 284 @UnsupportedAppUsage 285 private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>(); 286 287 private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); 288 289 private static class CachedClassLoader { 290 ClassLoader loader; 291 292 /** 293 * The shared libraries used when constructing loader for verification. 294 */ 295 List<ClassLoader> sharedLibraries; 296 } 297 298 /** 299 * This is a map of zip to associated class loader. 300 */ 301 private Map<String, CachedClassLoader> mSystemLibsCacheMap = null; 302 } 303