1 /*
2  * Copyright (C) 2016 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 com.android.internal.os;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import android.os.Build;
21 import android.os.Trace;
22 
23 import dalvik.system.DelegateLastClassLoader;
24 import dalvik.system.DexClassLoader;
25 import dalvik.system.PathClassLoader;
26 
27 import java.util.List;
28 
29 /**
30  * Creates class loaders.
31  *
32  * @hide
33  */
34 public class ClassLoaderFactory {
35     // Unconstructable
ClassLoaderFactory()36     private ClassLoaderFactory() {}
37 
38     private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName();
39     private static final String DEX_CLASS_LOADER_NAME = DexClassLoader.class.getName();
40     private static final String DELEGATE_LAST_CLASS_LOADER_NAME =
41             DelegateLastClassLoader.class.getName();
42 
43     /**
44      * Returns the name of the class for PathClassLoader.
45      */
getPathClassLoaderName()46     public static String getPathClassLoaderName() {
47         return PATH_CLASS_LOADER_NAME;
48     }
49 
50     /**
51      * Returns true if {@code name} is a supported classloader. {@code name} must be a
52      * binary name of a class, as defined by {@code Class.getName}.
53      */
isValidClassLoaderName(String name)54     public static boolean isValidClassLoaderName(String name) {
55         // This method is used to parse package data and does not accept null names.
56         return name != null && (isPathClassLoaderName(name) || isDelegateLastClassLoaderName(name));
57     }
58 
59     /**
60      * Returns true if {@code name} is the encoding for either PathClassLoader or DexClassLoader.
61      * The two class loaders are grouped together because they have the same behaviour.
62      */
isPathClassLoaderName(String name)63     public static boolean isPathClassLoaderName(String name) {
64         // For null values we default to PathClassLoader. This cover the case when packages
65         // don't specify any value for their class loaders.
66         return name == null || PATH_CLASS_LOADER_NAME.equals(name) ||
67                 DEX_CLASS_LOADER_NAME.equals(name);
68     }
69 
70     /**
71      * Returns true if {@code name} is the encoding for the DelegateLastClassLoader.
72      */
isDelegateLastClassLoaderName(String name)73     public static boolean isDelegateLastClassLoaderName(String name) {
74         return DELEGATE_LAST_CLASS_LOADER_NAME.equals(name);
75     }
76 
77     /**
78      * Same as {@code createClassLoader} below, except that no associated namespace
79      * is created.
80      */
createClassLoader(String dexPath, String librarySearchPath, ClassLoader parent, String classloaderName, List<ClassLoader> sharedLibraries)81     public static ClassLoader createClassLoader(String dexPath,
82             String librarySearchPath, ClassLoader parent, String classloaderName,
83             List<ClassLoader> sharedLibraries) {
84         ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
85                 ? null
86                 : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
87         if (isPathClassLoaderName(classloaderName)) {
88             return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);
89         } else if (isDelegateLastClassLoaderName(classloaderName)) {
90             return new DelegateLastClassLoader(dexPath, librarySearchPath, parent,
91                     arrayOfSharedLibraries);
92         }
93 
94         throw new AssertionError("Invalid classLoaderName: " + classloaderName);
95     }
96 
97     /**
98      * Same as {@code createClassLoader} below, but passes a null list of shared
99      * libraries.
100      */
createClassLoader(String dexPath, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName)101     public static ClassLoader createClassLoader(String dexPath,
102             String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
103             int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) {
104         return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath,
105             parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null);
106     }
107 
108 
109     /**
110      * Create a ClassLoader and initialize a linker-namespace for it.
111      */
createClassLoader(String dexPath, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName, List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries)112     public static ClassLoader createClassLoader(String dexPath,
113             String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
114             int targetSdkVersion, boolean isNamespaceShared, String classLoaderName,
115             List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) {
116 
117         final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,
118                 classLoaderName, sharedLibraries);
119 
120         String sonameList = "";
121         if (nativeSharedLibraries != null) {
122             sonameList = String.join(":", nativeSharedLibraries);
123         }
124 
125         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace");
126         String errorMessage = createClassloaderNamespace(classLoader,
127                                                          targetSdkVersion,
128                                                          librarySearchPath,
129                                                          libraryPermittedPath,
130                                                          isNamespaceShared,
131                                                          dexPath,
132                                                          sonameList);
133         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
134 
135         if (errorMessage != null) {
136             throw new UnsatisfiedLinkError("Unable to create namespace for the classloader " +
137                                            classLoader + ": " + errorMessage);
138         }
139 
140         return classLoader;
141     }
142 
143     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
createClassloaderNamespace(ClassLoader classLoader, int targetSdkVersion, String librarySearchPath, String libraryPermittedPath, boolean isNamespaceShared, String dexPath, String sonameList)144     private static native String createClassloaderNamespace(ClassLoader classLoader,
145                                                             int targetSdkVersion,
146                                                             String librarySearchPath,
147                                                             String libraryPermittedPath,
148                                                             boolean isNamespaceShared,
149                                                             String dexPath,
150                                                             String sonameList);
151 }
152