• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.os.Build;
20 import android.util.ArrayMap;
21 
22 import dalvik.system.PathClassLoader;
23 
24 /** @hide */
25 public final class SystemServerClassLoaderFactory {
26     /**
27      * Map of paths to PathClassLoader for standalone system server jars.
28      */
29     private static final ArrayMap<String, PathClassLoader> sLoadedPaths = new ArrayMap<>();
30 
31     /**
32      * Creates and caches a ClassLoader for the jar at the given path.
33      *
34      * This method should only be called by ZygoteInit to prefetch jars. For other users, use
35      * {@link getOrCreateClassLoader} instead.
36      *
37      * The parent class loader should always be the system server class loader. Changing it has
38      * implications that require discussion with the mainline team.
39      *
40      * @hide for internal use only
41      */
createClassLoader(String path, ClassLoader parent)42     /* package */ static PathClassLoader createClassLoader(String path, ClassLoader parent) {
43         if (sLoadedPaths.containsKey(path)) {
44             throw new IllegalStateException("A ClassLoader for " + path + " already exists");
45         }
46         PathClassLoader pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader(
47                 path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent,
48                 Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null);
49         sLoadedPaths.put(path, pathClassLoader);
50         return pathClassLoader;
51     }
52 
53     /**
54      * Returns a cached ClassLoader to be used at runtime for the jar at the given path. Or, creates
55      * one if it is not prefetched and is allowed to be created at runtime.
56      *
57      * The parent class loader should always be the system server class loader. Changing it has
58      * implications that require discussion with the mainline team.
59      *
60      * @hide for internal use only
61      */
getOrCreateClassLoader( String path, ClassLoader parent, boolean isTestOnly)62     public static PathClassLoader getOrCreateClassLoader(
63             String path, ClassLoader parent, boolean isTestOnly) {
64         PathClassLoader pathClassLoader = sLoadedPaths.get(path);
65         if (pathClassLoader != null) {
66             return pathClassLoader;
67         }
68         if (!allowClassLoaderCreation(path, isTestOnly)) {
69             throw new RuntimeException("Creating a ClassLoader from " + path + " is not allowed. "
70                     + "Please make sure that the jar is listed in "
71                     + "`PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS` in the Makefile and added as a "
72                     + "`standalone_contents` of a `systemserverclasspath_fragment` in "
73                     + "`Android.bp`.");
74         }
75         return createClassLoader(path, parent);
76     }
77 
78     /**
79      * Returns whether a class loader for the jar is allowed to be created at runtime.
80      */
allowClassLoaderCreation(String path, boolean isTestOnly)81     private static boolean allowClassLoaderCreation(String path, boolean isTestOnly) {
82         // Currently, we only enforce prefetching for APEX jars.
83         if (!path.startsWith("/apex/")) {
84             return true;
85         }
86         // APEXes for testing only are okay to ignore.
87         if (isTestOnly) {
88             return true;
89         }
90         // If system server is being profiled, it's OK to create class loaders anytime.
91         if (ZygoteInit.shouldProfileSystemServer()) {
92             return true;
93         }
94         return false;
95     }
96 
97 
98 }
99