Handle Java exceptions within Java to the best of our ability

This commit is contained in:
Aaron Culliney 2015-09-27 13:30:16 -07:00
parent e51aaa1695
commit b5de4222c3
3 changed files with 52 additions and 61 deletions

View File

@ -83,39 +83,26 @@ public class Apple2CrashHandler {
}
public synchronized void setCustomExceptionHandler(Apple2Activity activity) {
synchronized (this) {
if (homeDir == null) {
homeDir = Apple2DisksMenu.getDataDir(activity);
}
}
if (mDefaultExceptionHandler != null) {
return;
}
mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
final String homeDir = "/data/data/" + activity.getPackageName();
final Thread.UncaughtExceptionHandler defaultExceptionHandler = mDefaultExceptionHandler;
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable t) {
try {
StackTraceElement[] stackTraceElements = t.getStackTrace();
StringBuffer traceBuffer = new StringBuffer();
// append the Java stack trace
traceBuffer.append(t.getClass().getName());
traceBuffer.append("\n");
final int maxTraceSize = 2048 + 1024 + 512; // probably should keep this less than a standard Linux PAGE_SIZE
for (StackTraceElement elt : stackTraceElements) {
traceBuffer.append(elt.toString());
traceBuffer.append("\n");
if (traceBuffer.length() >= maxTraceSize) {
break;
}
}
traceBuffer.append("\n");
nativeOnUncaughtException(homeDir, traceBuffer.toString());
Apple2CrashHandler.onUncaughtException(thread, t);
} catch (Throwable terminator2) {
// Yo dawg, I hear you like exceptions in your exception handler! ...
}
defaultExceptionHandler.uncaughtException(thread, t);
}
});
@ -271,8 +258,49 @@ public class Apple2CrashHandler {
/* ... */
}
private static void onUncaughtException(Thread thread, Throwable t) {
StackTraceElement[] stackTraceElements = t.getStackTrace();
StringBuffer traceBuffer = new StringBuffer();
// append the Java stack trace
traceBuffer.append("NAME: ").append(t.getClass().getName()).append("\n");
traceBuffer.append("MESSAGE: ").append(t.getMessage()).append("\n");
final int maxTraceSize = 2048 + 1024 + 512; // probably should keep this less than a standard Linux PAGE_SIZE
for (StackTraceElement elt : stackTraceElements) {
traceBuffer.append(elt.toString());
traceBuffer.append("\n");
if (traceBuffer.length() >= maxTraceSize) {
break;
}
}
traceBuffer.append("\n");
final int maxAttempts = 5;
int attempts = 0;
do {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(sCrashHandler.homeDir, javaCrashFileName), /*append:*/true));
writer.append(traceBuffer);
writer.flush();
writer.close();
break;
} catch (InterruptedIOException ie) {
/* EINTR, EAGAIN ... */
} catch (IOException e) {
Log.e(TAG, "Exception attempting to write data : " + e);
}
try {
Thread.sleep(100, 0);
} catch (InterruptedException e) {
/* ... */
}
++attempts;
} while (attempts < maxAttempts);
}
private File _javaCrashFile(Apple2Activity activity) {
return new File(Apple2DisksMenu.getDataDir(activity), javaCrashFileName);
return new File(homeDir, javaCrashFileName);
}
private File[] _nativeCrashFiles(Apple2Activity activity) {
@ -297,7 +325,7 @@ public class Apple2CrashHandler {
}
};
return new File(Apple2DisksMenu.getDataDir(activity)).listFiles(dmpFilter);
return new File(homeDir).listFiles(dmpFilter);
}
private String _dumpPath2ProcessedPath(String crashPath) {
@ -329,7 +357,7 @@ public class Apple2CrashHandler {
} catch (InterruptedException e) {
/* ... */
}
++ attempts;
++attempts;
} while (attempts < maxAttempts);
return attempts < maxAttempts;
@ -396,14 +424,13 @@ public class Apple2CrashHandler {
private final static String TAG = "Apple2CrashHandler";
private final static Apple2CrashHandler sCrashHandler = new Apple2CrashHandler();
private String homeDir;
private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
private AtomicBoolean mAlreadyRanCrashCheck = new AtomicBoolean(false);
private AtomicBoolean mAlreadySentReport = new AtomicBoolean(false);
private static native void nativePerformCrash(int crashType); // testing
private static native void nativeOnUncaughtException(String home, String trace);
private static native void nativeProcessCrash(String crashFilePath, String crashProcessedPath);
}

View File

@ -24,7 +24,7 @@
<string name="crasher_processing">Processing…</string>
<string name="crasher_processing_message">Processing crash reports…</string>
<string name="crasher_send">Send crash report?</string>
<string name="crasher_send_message">Do you want to send a crash report to the developer?</string>
<string name="crasher_send_message">Sorry there has been a problem. Do you want to send a crash report to the developer?</string>
<string name="crasher_summary">Test crash generation</string>
<string name="crasher_title">Crash emulator</string>
<string name="crash_null">NULL-deref</string>

View File

@ -105,42 +105,6 @@ void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativePerformCrash(JNIEnv *en
}
}
#define _JAVA_CRASH_NAME "/jcrash.txt" // this should match the Java side
#define _HALF_PAGE_SIZE (PAGE_SIZE>>1)
void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativeOnUncaughtException(JNIEnv *env, jclass cls, jstring jhome, jstring jstr) {
RELEASE_ERRLOG("Uncaught Java Exception ...");
// Write to /data/data/org.deadc0de.apple2ix.basic/jcrash.txt
const char *home = (*env)->GetStringUTFChars(env, jhome, NULL);
char *q = (char *)home;
char buf[_HALF_PAGE_SIZE] = { 0 };
const char *p0 = &buf[0];
char *p = (char *)p0;
while (*q && (p-p0 < _HALF_PAGE_SIZE-1)) {
*p++ = *q++;
}
(*env)->ReleaseStringUTFChars(env, jhome, home);
q = &_JAVA_CRASH_NAME[0];
while (*q && (p-p0 < _HALF_PAGE_SIZE-1)) {
*p++ = *q++;
}
int fd = TEMP_FAILURE_RETRY(open(buf, (O_CREAT|O_APPEND|O_WRONLY), (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)));
if (fd == -1) {
RELEASE_ERRLOG("OOPS, could not create/write to java crash file");
return;
}
const char *str = (*env)->GetStringUTFChars(env, jstr, NULL);
jsize len = (*env)->GetStringUTFLength(env, jstr);
TEMP_FAILURE_RETRY(write(fd, str, len));
(*env)->ReleaseStringUTFChars(env, jstr, str);
TEMP_FAILURE_RETRY(fsync(fd));
TEMP_FAILURE_RETRY(close(fd));
}
void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativeProcessCrash(JNIEnv *env, jclass cls, jstring jCrashPath, jstring jOutputPath) {
if (!(crashHandler && crashHandler->processCrash)) {
return;