Merge "Zygote: Load system server code early" am: f039816600
am: 782ae5139d
Change-Id: I82e6879aec4c55c806c3b512a813253cb122b656
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index e132abd..c630351 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -125,6 +125,12 @@
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 @@
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 @@
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);
}
@@ -497,6 +508,24 @@
}
/**
+ * 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
* capture profile information.
@@ -560,15 +589,16 @@
/**
* 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 @@
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 @@
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 8216b61..d8c68b4 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -108,11 +108,15 @@
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 @@
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 @@
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