Detect system-wide safe mode and configure the VM accordingly.
Use pthread_cond_wait instead of timed wait for the system_server process to
wait on the go-ahead JIT signal. If the phone is booted under system-wide safe
mode, such signal will never come so all VM instances (including the system
server) will run in the interpreter-only mode.
Bug: 2267590
diff --git a/libcore/dalvik/src/main/java/dalvik/system/VMRuntime.java b/libcore/dalvik/src/main/java/dalvik/system/VMRuntime.java
index 398e7fc..e05e489 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/VMRuntime.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/VMRuntime.java
@@ -195,4 +195,11 @@
*/
public native void startJitCompilation();
+ /**
+ * Tells the VM to disable the JIT compiler. If the VM does not have a JIT
+ * implementation, calling this method should have no effect.
+ *
+ * {@hide}
+ */
+ public native void disableJitCompilation();
}
diff --git a/libcore/dalvik/src/main/java/dalvik/system/Zygote.java b/libcore/dalvik/src/main/java/dalvik/system/Zygote.java
index 4f83d28..641e856 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/Zygote.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/Zygote.java
@@ -38,6 +38,14 @@
/** disable the JIT compiler */
public static final int DEBUG_ENABLE_SAFEMODE = 1 << 3;
+ /**
+ * When set by the system server, all subsequent apps will be launched in
+ * VM safe mode.
+ *
+ * @hide
+ */
+ public static boolean systemInSafeMode = false;
+
private Zygote() {}
/**
diff --git a/vm/Globals.h b/vm/Globals.h
index 81bcefc..ddcd2db 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -794,6 +794,12 @@
/* Framework or stand-alone? */
bool runningInAndroidFramework;
+ /* Framework callback happened? */
+ bool alreadyEnabledViaFramework;
+
+ /* Framework requests to disable the JIT for good */
+ bool disableJit;
+
/* Place arrays at the end to ease the display in gdb sessions */
/* Work order queue for compilations */
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index 484f9a3..8297131 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -397,13 +397,41 @@
* up code isn't worth compiling. We'll resume when the framework
* signals us that the first screen draw has happened, or the timer
* below expires (to catch daemons).
+ *
+ * There is a theoretical race between the callback to
+ * VMRuntime.startJitCompiation and when the compiler thread reaches this
+ * point. In case the callback happens earlier, in order not to permanently
+ * hold the system_server (which is not using the timed wait) in
+ * interpreter-only mode we bypass the delay here.
*/
- if (gDvmJit.runningInAndroidFramework) {
- dvmLockMutex(&gDvmJit.compilerLock);
- // TUNING: experiment with the delay & perhaps make it target-specific
- dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
- &gDvmJit.compilerLock, 3000, 0);
- dvmUnlockMutex(&gDvmJit.compilerLock);
+ if (gDvmJit.runningInAndroidFramework &&
+ !gDvmJit.alreadyEnabledViaFramework) {
+ /*
+ * If the current VM instance is the system server (detected by having
+ * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
+ * conditional variable to determine whether to start the JIT or not.
+ * If the system server detects that the whole system is booted in
+ * safe mode, the conditional variable will never be signaled and the
+ * system server will remain in the interpreter-only mode. All
+ * subsequent apps will be started with the --enable-safemode flag
+ * explicitly appended.
+ */
+ if (gDvm.systemServerPid == 0) {
+ dvmLockMutex(&gDvmJit.compilerLock);
+ pthread_cond_wait(&gDvmJit.compilerQueueActivity,
+ &gDvmJit.compilerLock);
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+ LOGD("JIT started for system_server");
+ } else {
+ dvmLockMutex(&gDvmJit.compilerLock);
+ /*
+ * TUNING: experiment with the delay & perhaps make it
+ * target-specific
+ */
+ dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
+ &gDvmJit.compilerLock, 3000, 0);
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+ }
if (gDvmJit.haltCompilerThread) {
return NULL;
}
diff --git a/vm/native/dalvik_system_VMRuntime.c b/vm/native/dalvik_system_VMRuntime.c
index 5a22120..c020f8a 100644
--- a/vm/native/dalvik_system_VMRuntime.c
+++ b/vm/native/dalvik_system_VMRuntime.c
@@ -188,8 +188,10 @@
JValue* pResult)
{
#if defined(WITH_JIT)
- if (gDvm.executionMode == kExecutionModeJit) {
+ if (gDvm.executionMode == kExecutionModeJit &&
+ gDvmJit.disableJit == false) {
dvmLockMutex(&gDvmJit.compilerLock);
+ gDvmJit.alreadyEnabledViaFramework = true;
pthread_cond_signal(&gDvmJit.compilerQueueActivity);
dvmUnlockMutex(&gDvmJit.compilerLock);
}
@@ -197,6 +199,24 @@
RETURN_VOID();
}
+/*
+ * public native void disableJitCompilation()
+ *
+ * Callback function from the framework to indicate that a VM instance wants to
+ * permanently disable the JIT compiler. Currently only the system server uses
+ * this interface when it detects system-wide safe mode is enabled.
+ */
+static void Dalvik_dalvik_system_VMRuntime_disableJitCompilation(const u4* args,
+ JValue* pResult)
+{
+#if defined(WITH_JIT)
+ if (gDvm.executionMode == kExecutionModeJit) {
+ gDvmJit.disableJit = true;
+ }
+#endif
+ RETURN_VOID();
+}
+
const DalvikNativeMethod dvm_dalvik_system_VMRuntime[] = {
{ "getTargetHeapUtilization", "()F",
Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization },
@@ -216,5 +236,7 @@
Dalvik_dalvik_system_VMRuntime_getExternalBytesAllocated },
{ "startJitCompilation", "()V",
Dalvik_dalvik_system_VMRuntime_startJitCompilation },
+ { "disableJitCompilation", "()V",
+ Dalvik_dalvik_system_VMRuntime_disableJitCompilation },
{ NULL, NULL, NULL },
};