Skip to content

Commit 4280c4a

Browse files
author
Jeff Brown
committed
If an application calls System.exit() terminate it immediately.
There is no graceful way to kill Android application processes. They typically have many threads running doing various things When System.exit() is called, those threads just keep going while the cleanup actions run until the process finally. Performing shutdown actions can easily cause more harm than good. For example, closing the Binder driver's file descriptor may cause other threads waiting on Binder to wake up and then crash in nasty ways after receiving EBADF. So when an Android application exits, skip the cleanup and just call _exit() to end it all. Bug: 6168809 Change-Id: I29790c064426a0bf7dae7cdf444eea3eef1d5275
1 parent 16f5f5c commit 4280c4a

File tree

3 files changed

+39
-11
lines changed

3 files changed

+39
-11
lines changed

core/java/com/android/internal/os/RuntimeInit.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class RuntimeInit {
5252

5353
private static final native void nativeZygoteInit();
5454
private static final native void nativeFinishInit();
55+
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
5556

5657
/**
5758
* Use this to log a message when a thread exits due to an uncaught
@@ -281,6 +282,13 @@ public static void wrapperInit(int targetSdkVersion, String[] argv)
281282

282283
private static void applicationInit(int targetSdkVersion, String[] argv)
283284
throws ZygoteInit.MethodAndArgsCaller {
285+
// If the application calls System.exit(), terminate the process
286+
// immediately without running any shutdown hooks. It is not possible to
287+
// shutdown an Android application gracefully. Among other things, the
288+
// Android runtime shutdown hooks close the Binder driver, which can cause
289+
// leftover running threads to crash before the process actually exits.
290+
nativeSetExitWithoutCleanup(true);
291+
284292
// We want to be fairly aggressive about heap utilization, to avoid
285293
// holding on to a lot of memory that isn't needed.
286294
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);

core/jni/AndroidRuntime.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jo
199199
gCurRuntime->onZygoteInit();
200200
}
201201

202+
static void com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup(JNIEnv* env,
203+
jobject clazz, jboolean exitWithoutCleanup)
204+
{
205+
gCurRuntime->setExitWithoutCleanup(exitWithoutCleanup);
206+
}
207+
202208
/*
203209
* JNI registration.
204210
*/
@@ -207,6 +213,8 @@ static JNINativeMethod gMethods[] = {
207213
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
208214
{ "nativeZygoteInit", "()V",
209215
(void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
216+
{ "nativeSetExitWithoutCleanup", "(Z)V",
217+
(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
210218
};
211219

212220
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
@@ -220,7 +228,8 @@ int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
220228
/*static*/ JavaVM* AndroidRuntime::mJavaVM = NULL;
221229

222230

223-
AndroidRuntime::AndroidRuntime()
231+
AndroidRuntime::AndroidRuntime() :
232+
mExitWithoutCleanup(false)
224233
{
225234
SkGraphics::Init();
226235
// this sets our preference for 16bit images during decode
@@ -298,8 +307,7 @@ status_t AndroidRuntime::callMain(const char* className,
298307
*/
299308
static void runtime_exit(int code)
300309
{
301-
gCurRuntime->onExit(code);
302-
exit(code);
310+
gCurRuntime->exit(code);
303311
}
304312

305313
/*
@@ -870,10 +878,16 @@ void AndroidRuntime::start(const char* className, const char* options)
870878
ALOGW("Warning: VM did not shut down cleanly\n");
871879
}
872880

873-
void AndroidRuntime::onExit(int code)
881+
void AndroidRuntime::exit(int code)
874882
{
875-
ALOGV("AndroidRuntime onExit calling exit(%d)", code);
876-
exit(code);
883+
if (mExitWithoutCleanup) {
884+
ALOGI("VM exiting with result code %d, cleanup skipped.", code);
885+
::_exit(code);
886+
} else {
887+
ALOGI("VM exiting with result code %d.", code);
888+
onExit(code);
889+
::exit(code);
890+
}
877891
}
878892

879893
void AndroidRuntime::onVmCreated(JNIEnv* env)

include/android_runtime/AndroidRuntime.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ class AndroidRuntime
6666

6767
void start(const char *classname, const char* options);
6868

69+
void exit(int code);
70+
71+
void setExitWithoutCleanup(bool exitWithoutCleanup) {
72+
mExitWithoutCleanup = exitWithoutCleanup;
73+
}
74+
6975
static AndroidRuntime* getRuntime();
7076

7177
/**
@@ -86,14 +92,13 @@ class AndroidRuntime
8692
* fork. Override it to initialize threads, etc. Upon return, the
8793
* correct static main will be invoked.
8894
*/
89-
virtual void onZygoteInit() {};
90-
95+
virtual void onZygoteInit() { }
9196

9297
/**
93-
* Called when the Java application exits. The default
94-
* implementation calls exit(code).
98+
* Called when the Java application exits to perform additional cleanup actions
99+
* before the process is terminated.
95100
*/
96-
virtual void onExit(int code);
101+
virtual void onExit(int code) { }
97102

98103
/** create a new thread that is visible from Java */
99104
static android_thread_id_t createJavaThread(const char* name, void (*start)(void *),
@@ -114,6 +119,7 @@ class AndroidRuntime
114119
int startVm(JavaVM** pJavaVM, JNIEnv** pEnv);
115120

116121
Vector<JavaVMOption> mOptions;
122+
bool mExitWithoutCleanup;
117123

118124
/* JNI JavaVM pointer */
119125
static JavaVM* mJavaVM;

0 commit comments

Comments
 (0)