blob: 2e59b903f06d52c0a50703080d3657ef7e25b8b6 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Mathew Inwood4fb17d12018-08-14 14:25:44 +010019import android.annotation.UnsupportedAppUsage;
Steven Morelandbdc27022019-03-29 21:23:48 +000020import android.content.pm.SharedLibraryInfo;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010021import android.os.Build;
Cody Northrop86cedcb2017-10-20 09:03:13 -060022import android.os.GraphicsEnvironment;
Dianne Hackbornf7be4802013-04-12 14:52:58 -070023import android.os.Trace;
Dianne Hackbornadd005c2013-07-17 18:43:12 -070024import android.util.ArrayMap;
Steven Morelandbdc27022019-03-29 21:23:48 +000025import android.util.Log;
Cody Northrop86cedcb2017-10-20 09:03:13 -060026
Narayan Kamathf9419f02017-06-15 11:35:38 +010027import com.android.internal.os.ClassLoaderFactory;
Cody Northrop86cedcb2017-10-20 09:03:13 -060028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import dalvik.system.PathClassLoader;
30
Steven Morelandbdc27022019-03-29 21:23:48 +000031import java.util.ArrayList;
Patrick Baumann1bea2372018-03-13 14:26:58 -070032import java.util.Collection;
Steven Morelandbdc27022019-03-29 21:23:48 +000033import java.util.HashMap;
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000034import java.util.List;
Steven Morelandbdc27022019-03-29 21:23:48 +000035import java.util.Map;
Patrick Baumann1bea2372018-03-13 14:26:58 -070036
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010037/** @hide */
38public class ApplicationLoaders {
Steven Morelandbdc27022019-03-29 21:23:48 +000039 private static final String TAG = "ApplicationLoaders";
40
Mathew Inwood4fb17d12018-08-14 14:25:44 +010041 @UnsupportedAppUsage
Dimitry Ivanova55c7f12016-02-23 14:25:50 -080042 public static ApplicationLoaders getDefault() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 return gApplicationLoaders;
44 }
45
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010046 ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
Torne (Richard Coles)04526702017-01-13 14:19:39 +000047 String librarySearchPath, String libraryPermittedPath,
Narayan Kamathf9419f02017-06-15 11:35:38 +010048 ClassLoader parent, String classLoaderName) {
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000049 return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
50 librarySearchPath, libraryPermittedPath, parent, classLoaderName,
51 null);
52 }
53
54 ClassLoader getClassLoaderWithSharedLibraries(
55 String zip, int targetSdkVersion, boolean isBundled,
56 String librarySearchPath, String libraryPermittedPath,
57 ClassLoader parent, String classLoaderName,
58 List<ClassLoader> sharedLibraries) {
Torne (Richard Coles)04526702017-01-13 14:19:39 +000059 // For normal usage the cache key used is the same as the zip path.
60 return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000061 libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
Torne (Richard Coles)04526702017-01-13 14:19:39 +000062 }
63
Steven Morelandbdc27022019-03-29 21:23:48 +000064 /**
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 */
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
Torne (Richard Coles)04526702017-01-13 14:19:39 +000084 private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
85 String librarySearchPath, String libraryPermittedPath,
Narayan Kamathf9419f02017-06-15 11:35:38 +010086 ClassLoader parent, String cacheKey,
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000087 String classLoaderName, List<ClassLoader> sharedLibraries) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 /*
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) {
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000107 ClassLoader loader = mLoaders.get(cacheKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 if (loader != null) {
109 return loader;
110 }
Dimitry Ivanovb1ef62b2016-04-20 14:09:32 -0700111
Dianne Hackbornf7be4802013-04-12 14:52:58 -0700112 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
Dimitry Ivanova55c7f12016-02-23 14:25:50 -0800113
Narayan Kamathf9419f02017-06-15 11:35:38 +0100114 ClassLoader classloader = ClassLoaderFactory.createClassLoader(
115 zip, librarySearchPath, libraryPermittedPath, parent,
Nicolas Geoffray972b39e2018-11-15 12:59:52 +0000116 targetSdkVersion, isBundled, classLoaderName, sharedLibraries);
Dimitry Ivanova55c7f12016-02-23 14:25:50 -0800117
Dianne Hackbornf7be4802013-04-12 14:52:58 -0700118 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
119
Cody Northrop86cedcb2017-10-20 09:03:13 -0600120 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setLayerPaths");
121 GraphicsEnvironment.getInstance().setLayerPaths(
122 classloader, librarySearchPath, libraryPermittedPath);
Andreas Gampe4c8e5422016-05-18 11:58:47 -0700123 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Dimitry Ivanov09979082016-04-19 11:11:01 -0700124
Steven Morelandbdc27022019-03-29 21:23:48 +0000125 if (cacheKey != null) {
126 mLoaders.put(cacheKey, classloader);
127 }
Narayan Kamathf9419f02017-06-15 11:35:38 +0100128 return classloader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 }
130
Dianne Hackbornf7be4802013-04-12 14:52:58 -0700131 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
Narayan Kamathf9419f02017-06-15 11:35:38 +0100132 ClassLoader loader = ClassLoaderFactory.createClassLoader(
Nicolas Geoffray972b39e2018-11-15 12:59:52 +0000133 zip, null, parent, classLoaderName, sharedLibraries);
Dianne Hackbornf7be4802013-04-12 14:52:58 -0700134 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Narayan Kamathf9419f02017-06-15 11:35:38 +0100135 return loader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 }
137 }
138
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100139 /**
Steven Morelandbdc27022019-03-29 21:23:48 +0000140 * 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 */
146 public void createAndCacheNonBootclasspathSystemClassLoaders(SharedLibraryInfo[] libs) {
147 if (mSystemLibsCacheMap != null) {
Steven Moreland94190e02019-03-27 06:38:42 -0700148 throw new IllegalStateException("Already cached.");
Steven Morelandbdc27022019-03-29 21:23:48 +0000149 }
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 *
Steven Moreland94190e02019-03-27 06:38:42 -0700161 * All of this library's dependencies must have previously been cached. Otherwise, an exception
162 * is thrown.
Steven Morelandbdc27022019-03-29 21:23:48 +0000163 */
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) {
Steven Moreland94190e02019-03-27 06:38:42 -0700177 throw new IllegalStateException("Failed to find dependency " + dependencyPath
178 + " of cachedlibrary " + path);
Steven Morelandbdc27022019-03-29 21:23:48 +0000179 }
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) {
Steven Moreland94190e02019-03-27 06:38:42 -0700191 // bad configuration or break in classloading code
192 throw new IllegalStateException("Failed to cache " + path);
Steven Morelandbdc27022019-03-29 21:23:48 +0000193 }
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
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 */
Steven Moreland94190e02019-03-27 06:38:42 -0700217 public ClassLoader getCachedNonBootclasspathSystemLib(String zip, ClassLoader parent,
Steven Morelandbdc27022019-03-29 21:23:48 +0000218 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 /**
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100245 * 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 */
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000249 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,
Nicolas Geoffray972b39e2018-11-15 12:59:52 +0000258 cacheKey, null /* classLoaderName */, null /* sharedLibraries */);
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100259 }
260
Todd Kennedy39bfee52016-02-24 10:28:21 -0800261 /**
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 */
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
Patrick Baumann1bea2372018-03-13 14:26:58 -0700273 /**
274 * @hide
275 */
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
Mathew Inwood4fb17d12018-08-14 14:25:44 +0100284 @UnsupportedAppUsage
Narayan Kamathf9419f02017-06-15 11:35:38 +0100285 private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286
Dimitry Ivanovb1ef62b2016-04-20 14:09:32 -0700287 private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
Steven Morelandbdc27022019-03-29 21:23:48 +0000288
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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302}