diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index e132abd7e4cb7043f94d6a97e24ec6030076cb26..c6303518d9ae06fc7de9ae66b5b962244dbdab5c 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -125,6 +125,12 @@ public class ZygoteInit { private static boolean sPreloadComplete; + /** + * Cached classloader to use for the system server. Will only be populated in the system + * server process. + */ + private static ClassLoader sCachedSystemServerClassLoader = null; + static void preload(TimingsTraceLog bootTimingsTraceLog) { Log.d(TAG, "begin preload"); bootTimingsTraceLog.traceBegin("BeginPreload"); @@ -446,7 +452,13 @@ public class ZygoteInit { final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); if (systemServerClasspath != null) { - performSystemServerDexOpt(systemServerClasspath); + if (performSystemServerDexOpt(systemServerClasspath)) { + // Throw away the cached classloader. If we compiled here, the classloader would + // not have had AoT-ed artifacts. + // Note: This only works in a very special environment where selinux enforcement is + // disabled, e.g., Mac builds. + sCachedSystemServerClassLoader = null; + } // Capturing profiles is only supported for debug or eng builds since selinux normally // prevents it. boolean profileSystemServer = SystemProperties.getBoolean( @@ -479,10 +491,9 @@ public class ZygoteInit { throw new IllegalStateException("Unexpected return from WrapperInit.execApplication"); } else { - ClassLoader cl = null; - if (systemServerClasspath != null) { - cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion); - + createSystemServerClassLoader(); + ClassLoader cl = sCachedSystemServerClassLoader; + if (cl != null) { Thread.currentThread().setContextClassLoader(cl); } @@ -496,6 +507,24 @@ public class ZygoteInit { /* should never reach here */ } + /** + * 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. + */ + private static void createSystemServerClassLoader() { + if (sCachedSystemServerClassLoader != null) { + return; + } + final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); + // TODO: Should we run optimization here? + if (systemServerClasspath != null) { + sCachedSystemServerClassLoader = createPathClassLoader(systemServerClasspath, + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT); + } + } + /** * 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 @@ -560,15 +589,16 @@ public class ZygoteInit { /** * Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction - * set of the current runtime. + * set of the current runtime. If something was compiled, return true. */ - private static void performSystemServerDexOpt(String classPath) { + private static boolean performSystemServerDexOpt(String classPath) { final String[] classPathElements = classPath.split(":"); final IInstalld installd = IInstalld.Stub .asInterface(ServiceManager.getService("installd")); final String instructionSet = VMRuntime.getRuntime().vmInstructionSet(); String classPathForElement = ""; + boolean compiledSomething = false; for (String classPathElement : classPathElements) { // System server is fully AOTed and never profiled // for profile guided compilation. @@ -610,6 +640,7 @@ public class ZygoteInit { uuid, classLoaderContext, seInfo, false /* downgrade */, targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null, "server-dexopt"); + compiledSomething = true; } catch (RemoteException | ServiceSpecificException e) { // Ignore (but log), we need this on the classpath for fallback mode. Log.w(TAG, "Failed compiling classpath element for system server: " @@ -620,6 +651,8 @@ public class ZygoteInit { classPathForElement = encodeSystemServerClassPath( classPathForElement, classPathElement); } + + return compiledSomething; } /** diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 8216b616915c5ae79c9ad5bbcf8b40c81de49bcc..d8c68b436bb3ab18b1e72b3824a6ccddbab48c5c 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -108,11 +108,15 @@ typedef const std::function& fail_fn_t; static pid_t gSystemServerPid = 0; -static const char kZygoteClassName[] = "com/android/internal/os/Zygote"; +static constexpr const char* kZygoteClassName = "com/android/internal/os/Zygote"; static jclass gZygoteClass; static jmethodID gCallPostForkSystemServerHooks; static jmethodID gCallPostForkChildHooks; +static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit"; +static jclass gZygoteInitClass; +static jmethodID gCreateSystemServerClassLoader; + static bool g_is_security_enforced = true; /** @@ -1047,6 +1051,15 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, fail_fn("Error calling post fork system server hooks."); } + // Prefetch the classloader for the system server. This is done early to + // allow a tie-down of the proper system server selinux domain. + env->CallStaticVoidMethod(gZygoteInitClass, gCreateSystemServerClassLoader); + if (env->ExceptionCheck()) { + // Be robust here. The Java code will attempt to create the classloader + // at a later point (but may not have rights to use AoT artifacts). + env->ExceptionClear(); + } + // TODO(oth): Remove hardcoded label here (b/117874058). static const char* kSystemServerLabel = "u:r:system_server:s0"; if (selinux_android_setcon(kSystemServerLabel) != 0) { @@ -1566,6 +1579,13 @@ int register_com_android_internal_os_Zygote(JNIEnv* env) { gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks", "(IZZLjava/lang/String;)V"); - return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods)); + gZygoteInitClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteInitClassName)); + gCreateSystemServerClassLoader = GetStaticMethodIDOrDie(env, gZygoteInitClass, + "createSystemServerClassLoader", + "()V"); + + RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods)); + + return JNI_OK; } } // namespace android