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
This commit is contained in:
@@ -52,6 +52,7 @@ public class RuntimeInit {
|
||||
|
||||
private static final native void nativeZygoteInit();
|
||||
private static final native void nativeFinishInit();
|
||||
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
|
||||
|
||||
/**
|
||||
* Use this to log a message when a thread exits due to an uncaught
|
||||
@@ -281,6 +282,13 @@ public class RuntimeInit {
|
||||
|
||||
private static void applicationInit(int targetSdkVersion, String[] argv)
|
||||
throws ZygoteInit.MethodAndArgsCaller {
|
||||
// If the application calls System.exit(), terminate the process
|
||||
// immediately without running any shutdown hooks. It is not possible to
|
||||
// shutdown an Android application gracefully. Among other things, the
|
||||
// Android runtime shutdown hooks close the Binder driver, which can cause
|
||||
// leftover running threads to crash before the process actually exits.
|
||||
nativeSetExitWithoutCleanup(true);
|
||||
|
||||
// We want to be fairly aggressive about heap utilization, to avoid
|
||||
// holding on to a lot of memory that isn't needed.
|
||||
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
|
||||
|
||||
@@ -199,6 +199,12 @@ static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jo
|
||||
gCurRuntime->onZygoteInit();
|
||||
}
|
||||
|
||||
static void com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup(JNIEnv* env,
|
||||
jobject clazz, jboolean exitWithoutCleanup)
|
||||
{
|
||||
gCurRuntime->setExitWithoutCleanup(exitWithoutCleanup);
|
||||
}
|
||||
|
||||
/*
|
||||
* JNI registration.
|
||||
*/
|
||||
@@ -207,6 +213,8 @@ static JNINativeMethod gMethods[] = {
|
||||
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
|
||||
{ "nativeZygoteInit", "()V",
|
||||
(void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
|
||||
{ "nativeSetExitWithoutCleanup", "(Z)V",
|
||||
(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
|
||||
};
|
||||
|
||||
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
|
||||
@@ -220,7 +228,8 @@ int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
|
||||
/*static*/ JavaVM* AndroidRuntime::mJavaVM = NULL;
|
||||
|
||||
|
||||
AndroidRuntime::AndroidRuntime()
|
||||
AndroidRuntime::AndroidRuntime() :
|
||||
mExitWithoutCleanup(false)
|
||||
{
|
||||
SkGraphics::Init();
|
||||
// this sets our preference for 16bit images during decode
|
||||
@@ -298,8 +307,7 @@ status_t AndroidRuntime::callMain(const char* className,
|
||||
*/
|
||||
static void runtime_exit(int code)
|
||||
{
|
||||
gCurRuntime->onExit(code);
|
||||
exit(code);
|
||||
gCurRuntime->exit(code);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -870,10 +878,16 @@ void AndroidRuntime::start(const char* className, const char* options)
|
||||
ALOGW("Warning: VM did not shut down cleanly\n");
|
||||
}
|
||||
|
||||
void AndroidRuntime::onExit(int code)
|
||||
void AndroidRuntime::exit(int code)
|
||||
{
|
||||
ALOGV("AndroidRuntime onExit calling exit(%d)", code);
|
||||
exit(code);
|
||||
if (mExitWithoutCleanup) {
|
||||
ALOGI("VM exiting with result code %d, cleanup skipped.", code);
|
||||
::_exit(code);
|
||||
} else {
|
||||
ALOGI("VM exiting with result code %d.", code);
|
||||
onExit(code);
|
||||
::exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidRuntime::onVmCreated(JNIEnv* env)
|
||||
|
||||
@@ -66,6 +66,12 @@ public:
|
||||
|
||||
void start(const char *classname, const char* options);
|
||||
|
||||
void exit(int code);
|
||||
|
||||
void setExitWithoutCleanup(bool exitWithoutCleanup) {
|
||||
mExitWithoutCleanup = exitWithoutCleanup;
|
||||
}
|
||||
|
||||
static AndroidRuntime* getRuntime();
|
||||
|
||||
/**
|
||||
@@ -86,14 +92,13 @@ public:
|
||||
* fork. Override it to initialize threads, etc. Upon return, the
|
||||
* correct static main will be invoked.
|
||||
*/
|
||||
virtual void onZygoteInit() {};
|
||||
|
||||
virtual void onZygoteInit() { }
|
||||
|
||||
/**
|
||||
* Called when the Java application exits. The default
|
||||
* implementation calls exit(code).
|
||||
* Called when the Java application exits to perform additional cleanup actions
|
||||
* before the process is terminated.
|
||||
*/
|
||||
virtual void onExit(int code);
|
||||
virtual void onExit(int code) { }
|
||||
|
||||
/** create a new thread that is visible from Java */
|
||||
static android_thread_id_t createJavaThread(const char* name, void (*start)(void *),
|
||||
@@ -114,6 +119,7 @@ private:
|
||||
int startVm(JavaVM** pJavaVM, JNIEnv** pEnv);
|
||||
|
||||
Vector<JavaVMOption> mOptions;
|
||||
bool mExitWithoutCleanup;
|
||||
|
||||
/* JNI JavaVM pointer */
|
||||
static JavaVM* mJavaVM;
|
||||
|
||||
Reference in New Issue
Block a user