blob: 9ef24c6c2aeb480e60930350b8ff9f46316da5c2 [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;
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010020import android.os.Build;
Cody Northrop86cedcb2017-10-20 09:03:13 -060021import android.os.GraphicsEnvironment;
Dianne Hackbornf7be4802013-04-12 14:52:58 -070022import android.os.Trace;
Dianne Hackbornadd005c2013-07-17 18:43:12 -070023import android.util.ArrayMap;
Cody Northrop86cedcb2017-10-20 09:03:13 -060024
Narayan Kamathf9419f02017-06-15 11:35:38 +010025import com.android.internal.os.ClassLoaderFactory;
Cody Northrop86cedcb2017-10-20 09:03:13 -060026
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import dalvik.system.PathClassLoader;
28
Patrick Baumann1bea2372018-03-13 14:26:58 -070029import java.util.Collection;
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000030import java.util.List;
Patrick Baumann1bea2372018-03-13 14:26:58 -070031
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010032/** @hide */
33public class ApplicationLoaders {
Mathew Inwood4fb17d12018-08-14 14:25:44 +010034 @UnsupportedAppUsage
Dimitry Ivanova55c7f12016-02-23 14:25:50 -080035 public static ApplicationLoaders getDefault() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 return gApplicationLoaders;
37 }
38
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +010039 ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
Torne (Richard Coles)04526702017-01-13 14:19:39 +000040 String librarySearchPath, String libraryPermittedPath,
Narayan Kamathf9419f02017-06-15 11:35:38 +010041 ClassLoader parent, String classLoaderName) {
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000042 return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
43 librarySearchPath, libraryPermittedPath, parent, classLoaderName,
44 null);
45 }
46
47 ClassLoader getClassLoaderWithSharedLibraries(
48 String zip, int targetSdkVersion, boolean isBundled,
49 String librarySearchPath, String libraryPermittedPath,
50 ClassLoader parent, String classLoaderName,
51 List<ClassLoader> sharedLibraries) {
Torne (Richard Coles)04526702017-01-13 14:19:39 +000052 // For normal usage the cache key used is the same as the zip path.
53 return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000054 libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
Torne (Richard Coles)04526702017-01-13 14:19:39 +000055 }
56
57 private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
58 String librarySearchPath, String libraryPermittedPath,
Narayan Kamathf9419f02017-06-15 11:35:38 +010059 ClassLoader parent, String cacheKey,
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000060 String classLoaderName, List<ClassLoader> sharedLibraries) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 /*
62 * This is the parent we use if they pass "null" in. In theory
63 * this should be the "system" class loader; in practice we
64 * don't use that and can happily (and more efficiently) use the
65 * bootstrap class loader.
66 */
67 ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();
68
69 synchronized (mLoaders) {
70 if (parent == null) {
71 parent = baseParent;
72 }
73
74 /*
75 * If we're one step up from the base class loader, find
76 * something in our cache. Otherwise, we create a whole
77 * new ClassLoader for the zip archive.
78 */
79 if (parent == baseParent) {
Torne (Richard Coles)04526702017-01-13 14:19:39 +000080 ClassLoader loader = mLoaders.get(cacheKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 if (loader != null) {
82 return loader;
83 }
Dimitry Ivanovb1ef62b2016-04-20 14:09:32 -070084
Dianne Hackbornf7be4802013-04-12 14:52:58 -070085 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
Dimitry Ivanova55c7f12016-02-23 14:25:50 -080086
Narayan Kamathf9419f02017-06-15 11:35:38 +010087 ClassLoader classloader = ClassLoaderFactory.createClassLoader(
88 zip, librarySearchPath, libraryPermittedPath, parent,
Nicolas Geoffray972b39e2018-11-15 12:59:52 +000089 targetSdkVersion, isBundled, classLoaderName, sharedLibraries);
Dimitry Ivanova55c7f12016-02-23 14:25:50 -080090
Dianne Hackbornf7be4802013-04-12 14:52:58 -070091 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
92
Cody Northrop86cedcb2017-10-20 09:03:13 -060093 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setLayerPaths");
94 GraphicsEnvironment.getInstance().setLayerPaths(
95 classloader, librarySearchPath, libraryPermittedPath);
Andreas Gampe4c8e5422016-05-18 11:58:47 -070096 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Dimitry Ivanov09979082016-04-19 11:11:01 -070097
Narayan Kamathf9419f02017-06-15 11:35:38 +010098 mLoaders.put(cacheKey, classloader);
99 return classloader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 }
101
Dianne Hackbornf7be4802013-04-12 14:52:58 -0700102 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
Narayan Kamathf9419f02017-06-15 11:35:38 +0100103 ClassLoader loader = ClassLoaderFactory.createClassLoader(
Nicolas Geoffray972b39e2018-11-15 12:59:52 +0000104 zip, null, parent, classLoaderName, sharedLibraries);
Dianne Hackbornf7be4802013-04-12 14:52:58 -0700105 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Narayan Kamathf9419f02017-06-15 11:35:38 +0100106 return loader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 }
108 }
109
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100110 /**
111 * Creates a classloader for the WebView APK and places it in the cache of loaders maintained
112 * by this class. This is used in the WebView zygote, where its presence in the cache speeds up
113 * startup and enables memory sharing.
114 */
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000115 public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath,
116 String cacheKey) {
117 // The correct paths are calculated by WebViewZygote in the system server and passed to
118 // us here. We hardcode the other parameters: WebView always targets the current SDK,
119 // does not need to use non-public system libraries, and uses the base classloader as its
120 // parent to permit usage of the cache.
121 // The cache key is passed separately to enable the stub WebView to be cached under the
122 // stub's APK path, when the actual package path is the donor APK.
123 return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null,
Nicolas Geoffray972b39e2018-11-15 12:59:52 +0000124 cacheKey, null /* classLoaderName */, null /* sharedLibraries */);
Torne (Richard Coles)3b6ca992016-10-10 15:11:36 +0100125 }
126
Todd Kennedy39bfee52016-02-24 10:28:21 -0800127 /**
128 * Adds a new path the classpath of the given loader.
129 * @throws IllegalStateException if the provided class loader is not a {@link PathClassLoader}.
130 */
131 void addPath(ClassLoader classLoader, String dexPath) {
132 if (!(classLoader instanceof PathClassLoader)) {
133 throw new IllegalStateException("class loader is not a PathClassLoader");
134 }
135 final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader;
136 baseDexClassLoader.addDexPath(dexPath);
137 }
138
Patrick Baumann1bea2372018-03-13 14:26:58 -0700139 /**
140 * @hide
141 */
142 void addNative(ClassLoader classLoader, Collection<String> libPaths) {
143 if (!(classLoader instanceof PathClassLoader)) {
144 throw new IllegalStateException("class loader is not a PathClassLoader");
145 }
146 final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader;
147 baseDexClassLoader.addNativePath(libPaths);
148 }
149
Mathew Inwood4fb17d12018-08-14 14:25:44 +0100150 @UnsupportedAppUsage
Narayan Kamathf9419f02017-06-15 11:35:38 +0100151 private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Dimitry Ivanovb1ef62b2016-04-20 14:09:32 -0700153 private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154}