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

Commit 16895824 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: 04b45b74

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

Change-Id: I1c66a904c3688717853ce34a2952d976960b21a7
parents dcd05837 04b45b74
Loading
Loading
Loading
Loading
+50 −0
Original line number Original line 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 Original line Diff line number Diff line
@@ -46,6 +46,7 @@ import android.system.OsConstants;
import android.system.StructCapUserData;
import android.system.StructCapUserData;
import android.system.StructCapUserHeader;
import android.system.StructCapUserHeader;
import android.text.Hyphenator;
import android.text.Hyphenator;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.EventLog;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
@@ -560,9 +561,8 @@ public class ZygoteInit {


    /**
    /**
     * Create the classloader for the system server and store it in
     * Create the classloader for the system server and store it in
     * {@link sCachedSystemServerClassLoader}. This function may be called through JNI in
     * {@link sCachedSystemServerClassLoader}. This function is called through JNI in the forked
     * system server startup, when the runtime is in a critically low state. Do not do
     * system server process in the zygote SELinux domain.
     * extended computation etc here.
     */
     */
    private static ClassLoader getOrCreateSystemServerClassLoader() {
    private static ClassLoader getOrCreateSystemServerClassLoader() {
        if (sCachedSystemServerClassLoader == null) {
        if (sCachedSystemServerClassLoader == null) {
@@ -575,6 +575,29 @@ public class ZygoteInit {
        return sCachedSystemServerClassLoader;
        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
     * 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
     * permissions. From the installer perspective the system server is a regular package which can
+10 −0
Original line number Original line Diff line number Diff line
@@ -124,6 +124,7 @@ static jmethodID gCallPostForkChildHooks;
static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit";
static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit";
static jclass gZygoteInitClass;
static jclass gZygoteInitClass;
static jmethodID gGetOrCreateSystemServerClassLoader;
static jmethodID gGetOrCreateSystemServerClassLoader;
static jmethodID gPrefetchStandaloneSystemServerJars;


static bool gIsSecurityEnforced = true;
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).
            // at a later point (but may not have rights to use AoT artifacts).
            env->ExceptionClear();
            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) {
    if (setresgid(gid, gid, gid) == -1) {
@@ -2678,6 +2685,9 @@ int register_com_android_internal_os_Zygote(JNIEnv* env) {
  gGetOrCreateSystemServerClassLoader =
  gGetOrCreateSystemServerClassLoader =
          GetStaticMethodIDOrDie(env, gZygoteInitClass, "getOrCreateSystemServerClassLoader",
          GetStaticMethodIDOrDie(env, gZygoteInitClass, "getOrCreateSystemServerClassLoader",
                                 "()Ljava/lang/ClassLoader;");
                                 "()Ljava/lang/ClassLoader;");
  gPrefetchStandaloneSystemServerJars =
          GetStaticMethodIDOrDie(env, gZygoteInitClass, "prefetchStandaloneSystemServerJars",
                                 "()V");


  RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
  RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));


+3 −16
Original line number Original line Diff line number Diff line
@@ -21,18 +21,16 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.os.Build;
import android.os.Environment;
import android.os.Environment;
import android.os.SystemClock;
import android.os.SystemClock;
import android.os.Trace;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;


import com.android.internal.annotations.GuardedBy;
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.internal.util.Preconditions;
import com.android.server.SystemService.TargetUser;
import com.android.server.SystemService.TargetUser;
import com.android.server.am.EventLogTags;
import com.android.server.am.EventLogTags;
@@ -77,9 +75,6 @@ public final class SystemServiceManager implements Dumpable {
    // Services that should receive lifecycle events.
    // Services that should receive lifecycle events.
    private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
    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 int mCurrentPhase = -1;


    private UserManagerInternal mUserManagerInternal;
    private UserManagerInternal mUserManagerInternal;
@@ -119,16 +114,8 @@ public final class SystemServiceManager implements Dumpable {
     * @return The service instance.
     * @return The service instance.
     */
     */
    public SystemService startServiceFromJar(String className, String path) {
    public SystemService startServiceFromJar(String className, String path) {
        PathClassLoader pathClassLoader = mLoadedPaths.get(path);
        PathClassLoader pathClassLoader = SystemServerClassLoaderFactory.getOrCreateClassLoader(
        if (pathClassLoader == null) {
                path, this.getClass().getClassLoader());
            // 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);
        }
        final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader);
        final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader);
        return startService(serviceClass);
        return startService(serviceClass);
    }
    }