Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a862711 authored by Jiakai Zhang's avatar Jiakai Zhang Committed by Automerger Merge Worker
Browse files

Merge "Prefetch standalone system server jars before switching domain." am:...

Merge "Prefetch standalone system server jars before switching domain." am: 04b45b74 am: 16895824

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1909973

Change-Id: I3e3a0853ab1d14a4759d2954d318d8213f1ea8a9
parents eaba1a12 16895824
Loading
Loading
Loading
Loading
+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;
    }
}
+26 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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) {
@@ -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
+10 −0
Original line number Diff line number Diff line
@@ -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;

@@ -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) {
@@ -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));

+3 −16
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
    }