Loading core/java/com/android/internal/os/SystemServerClassLoaderFactory.java 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.os; import android.os.Build; import android.util.ArrayMap; import dalvik.system.PathClassLoader; /** @hide */ public final class SystemServerClassLoaderFactory { /** * Map of paths to PathClassLoader for standalone system server jars. */ private static final ArrayMap<String, PathClassLoader> sLoadedPaths = new ArrayMap<>(); /** * Creates and caches a ClassLoader for the jar at the given path, or returns a cached * ClassLoader if it exists. * * The parent class loader should always be the system server class loader. Changing it has * implications that require discussion with the mainline team. * * @hide for internal use only */ public static PathClassLoader getOrCreateClassLoader(String path, ClassLoader parent) { PathClassLoader pathClassLoader = sLoadedPaths.get(path); if (pathClassLoader == null) { pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader( path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent, Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null); sLoadedPaths.put(path, pathClassLoader); } return pathClassLoader; } } core/java/com/android/internal/os/ZygoteInit.java +26 −3 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.system.OsConstants; import android.system.StructCapUserData; import android.system.StructCapUserHeader; import android.text.Hyphenator; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; import android.util.Slog; Loading Loading @@ -560,9 +561,8 @@ public class ZygoteInit { /** * Create the classloader for the system server and store it in * {@link sCachedSystemServerClassLoader}. This function may be called through JNI in * system server startup, when the runtime is in a critically low state. Do not do * extended computation etc here. * {@link sCachedSystemServerClassLoader}. This function is called through JNI in the forked * system server process in the zygote SELinux domain. */ private static ClassLoader getOrCreateSystemServerClassLoader() { if (sCachedSystemServerClassLoader == null) { Loading @@ -575,6 +575,29 @@ public class ZygoteInit { return sCachedSystemServerClassLoader; } /** * Creates class loaders for standalone system server jars. This function is called through JNI * in the forked system server process in the zygote SELinux domain. */ private static void prefetchStandaloneSystemServerJars() { String envStr = Os.getenv("STANDALONE_SYSTEMSERVER_JARS"); if (TextUtils.isEmpty(envStr)) { return; } for (String jar : envStr.split(":")) { try { SystemServerClassLoaderFactory.getOrCreateClassLoader( jar, getOrCreateSystemServerClassLoader()); } catch (Error e) { // We don't want the process to crash for this error because prefetching is just an // optimization. Log.e(TAG, String.format("Failed to prefetch standalone system server jar \"%s\": %s", jar, e.toString())); } } } /** * Note that preparing the profiles for system server does not require special selinux * permissions. From the installer perspective the system server is a regular package which can Loading core/jni/com_android_internal_os_Zygote.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ static jmethodID gCallPostForkChildHooks; static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit"; static jclass gZygoteInitClass; static jmethodID gGetOrCreateSystemServerClassLoader; static jmethodID gPrefetchStandaloneSystemServerJars; static bool gIsSecurityEnforced = true; Loading Loading @@ -1617,6 +1618,12 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, // at a later point (but may not have rights to use AoT artifacts). env->ExceptionClear(); } // Also prefetch standalone system server jars. The reason for doing this here is the same // as above. env->CallStaticObjectMethod(gZygoteInitClass, gPrefetchStandaloneSystemServerJars); if (env->ExceptionCheck()) { env->ExceptionClear(); } } if (setresgid(gid, gid, gid) == -1) { Loading Loading @@ -2678,6 +2685,9 @@ int register_com_android_internal_os_Zygote(JNIEnv* env) { gGetOrCreateSystemServerClassLoader = GetStaticMethodIDOrDie(env, gZygoteInitClass, "getOrCreateSystemServerClassLoader", "()Ljava/lang/ClassLoader;"); gPrefetchStandaloneSystemServerJars = GetStaticMethodIDOrDie(env, gZygoteInitClass, "prefetchStandaloneSystemServerJars", "()V"); RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods)); Loading services/core/java/com/android/server/SystemServiceManager.java +3 −16 Original line number Diff line number Diff line Loading @@ -21,18 +21,16 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.os.Build; import android.os.Environment; import android.os.SystemClock; import android.os.Trace; import android.util.ArrayMap; import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.ClassLoaderFactory; import com.android.internal.os.SystemServerClassLoaderFactory; import com.android.internal.util.Preconditions; import com.android.server.SystemService.TargetUser; import com.android.server.am.EventLogTags; Loading Loading @@ -77,9 +75,6 @@ public final class SystemServiceManager implements Dumpable { // Services that should receive lifecycle events. private final ArrayList<SystemService> mServices = new ArrayList<SystemService>(); // Map of paths to PathClassLoader, so we don't load the same path multiple times. private final ArrayMap<String, PathClassLoader> mLoadedPaths = new ArrayMap<>(); private int mCurrentPhase = -1; private UserManagerInternal mUserManagerInternal; Loading Loading @@ -119,16 +114,8 @@ public final class SystemServiceManager implements Dumpable { * @return The service instance. */ public SystemService startServiceFromJar(String className, String path) { PathClassLoader pathClassLoader = mLoadedPaths.get(path); if (pathClassLoader == null) { // NB: the parent class loader should always be the system server class loader. // Changing it has implications that require discussion with the mainline team. pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader( path, null /* librarySearchPath */, null /* libraryPermittedPath */, this.getClass().getClassLoader(), Build.VERSION.SDK_INT, true /* isNamespaceShared */, null /* classLoaderName */); mLoadedPaths.put(path, pathClassLoader); } PathClassLoader pathClassLoader = SystemServerClassLoaderFactory.getOrCreateClassLoader( path, this.getClass().getClassLoader()); final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader); return startService(serviceClass); } Loading Loading
core/java/com/android/internal/os/SystemServerClassLoaderFactory.java 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.os; import android.os.Build; import android.util.ArrayMap; import dalvik.system.PathClassLoader; /** @hide */ public final class SystemServerClassLoaderFactory { /** * Map of paths to PathClassLoader for standalone system server jars. */ private static final ArrayMap<String, PathClassLoader> sLoadedPaths = new ArrayMap<>(); /** * Creates and caches a ClassLoader for the jar at the given path, or returns a cached * ClassLoader if it exists. * * The parent class loader should always be the system server class loader. Changing it has * implications that require discussion with the mainline team. * * @hide for internal use only */ public static PathClassLoader getOrCreateClassLoader(String path, ClassLoader parent) { PathClassLoader pathClassLoader = sLoadedPaths.get(path); if (pathClassLoader == null) { pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader( path, /*librarySearchPath=*/null, /*libraryPermittedPath=*/null, parent, Build.VERSION.SDK_INT, /*isNamespaceShared=*/true , /*classLoaderName=*/null); sLoadedPaths.put(path, pathClassLoader); } return pathClassLoader; } }
core/java/com/android/internal/os/ZygoteInit.java +26 −3 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.system.OsConstants; import android.system.StructCapUserData; import android.system.StructCapUserHeader; import android.text.Hyphenator; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; import android.util.Slog; Loading Loading @@ -560,9 +561,8 @@ public class ZygoteInit { /** * Create the classloader for the system server and store it in * {@link sCachedSystemServerClassLoader}. This function may be called through JNI in * system server startup, when the runtime is in a critically low state. Do not do * extended computation etc here. * {@link sCachedSystemServerClassLoader}. This function is called through JNI in the forked * system server process in the zygote SELinux domain. */ private static ClassLoader getOrCreateSystemServerClassLoader() { if (sCachedSystemServerClassLoader == null) { Loading @@ -575,6 +575,29 @@ public class ZygoteInit { return sCachedSystemServerClassLoader; } /** * Creates class loaders for standalone system server jars. This function is called through JNI * in the forked system server process in the zygote SELinux domain. */ private static void prefetchStandaloneSystemServerJars() { String envStr = Os.getenv("STANDALONE_SYSTEMSERVER_JARS"); if (TextUtils.isEmpty(envStr)) { return; } for (String jar : envStr.split(":")) { try { SystemServerClassLoaderFactory.getOrCreateClassLoader( jar, getOrCreateSystemServerClassLoader()); } catch (Error e) { // We don't want the process to crash for this error because prefetching is just an // optimization. Log.e(TAG, String.format("Failed to prefetch standalone system server jar \"%s\": %s", jar, e.toString())); } } } /** * Note that preparing the profiles for system server does not require special selinux * permissions. From the installer perspective the system server is a regular package which can Loading
core/jni/com_android_internal_os_Zygote.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ static jmethodID gCallPostForkChildHooks; static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit"; static jclass gZygoteInitClass; static jmethodID gGetOrCreateSystemServerClassLoader; static jmethodID gPrefetchStandaloneSystemServerJars; static bool gIsSecurityEnforced = true; Loading Loading @@ -1617,6 +1618,12 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, // at a later point (but may not have rights to use AoT artifacts). env->ExceptionClear(); } // Also prefetch standalone system server jars. The reason for doing this here is the same // as above. env->CallStaticObjectMethod(gZygoteInitClass, gPrefetchStandaloneSystemServerJars); if (env->ExceptionCheck()) { env->ExceptionClear(); } } if (setresgid(gid, gid, gid) == -1) { Loading Loading @@ -2678,6 +2685,9 @@ int register_com_android_internal_os_Zygote(JNIEnv* env) { gGetOrCreateSystemServerClassLoader = GetStaticMethodIDOrDie(env, gZygoteInitClass, "getOrCreateSystemServerClassLoader", "()Ljava/lang/ClassLoader;"); gPrefetchStandaloneSystemServerJars = GetStaticMethodIDOrDie(env, gZygoteInitClass, "prefetchStandaloneSystemServerJars", "()V"); RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods)); Loading
services/core/java/com/android/server/SystemServiceManager.java +3 −16 Original line number Diff line number Diff line Loading @@ -21,18 +21,16 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.os.Build; import android.os.Environment; import android.os.SystemClock; import android.os.Trace; import android.util.ArrayMap; import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.ClassLoaderFactory; import com.android.internal.os.SystemServerClassLoaderFactory; import com.android.internal.util.Preconditions; import com.android.server.SystemService.TargetUser; import com.android.server.am.EventLogTags; Loading Loading @@ -77,9 +75,6 @@ public final class SystemServiceManager implements Dumpable { // Services that should receive lifecycle events. private final ArrayList<SystemService> mServices = new ArrayList<SystemService>(); // Map of paths to PathClassLoader, so we don't load the same path multiple times. private final ArrayMap<String, PathClassLoader> mLoadedPaths = new ArrayMap<>(); private int mCurrentPhase = -1; private UserManagerInternal mUserManagerInternal; Loading Loading @@ -119,16 +114,8 @@ public final class SystemServiceManager implements Dumpable { * @return The service instance. */ public SystemService startServiceFromJar(String className, String path) { PathClassLoader pathClassLoader = mLoadedPaths.get(path); if (pathClassLoader == null) { // NB: the parent class loader should always be the system server class loader. // Changing it has implications that require discussion with the mainline team. pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader( path, null /* librarySearchPath */, null /* libraryPermittedPath */, this.getClass().getClassLoader(), Build.VERSION.SDK_INT, true /* isNamespaceShared */, null /* classLoaderName */); mLoadedPaths.put(path, pathClassLoader); } PathClassLoader pathClassLoader = SystemServerClassLoaderFactory.getOrCreateClassLoader( path, this.getClass().getClassLoader()); final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader); return startService(serviceClass); } Loading