mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-06-26 00:29:27 +00:00
Refactor crash testing/reports into separate class/files
This commit is contained in:
parent
a20b2461b5
commit
88be6086a2
|
@ -39,8 +39,6 @@ public class Apple2Activity extends Activity {
|
|||
private final static int MAX_FINGERS = 32;// HACK ...
|
||||
private static volatile boolean DEBUG_STRICT = false;
|
||||
|
||||
private boolean mSetUncaughtExceptionHandler = false;
|
||||
|
||||
private Apple2View mView = null;
|
||||
private Apple2SplashScreen mSplashScreen = null;
|
||||
private Apple2MainMenu mMainMenu = null;
|
||||
|
@ -52,10 +50,6 @@ public class Apple2Activity extends Activity {
|
|||
private int mWidth = 0;
|
||||
private int mHeight = 0;
|
||||
|
||||
private int mSampleRate = 0;
|
||||
private int mMonoBufferSize = 0;
|
||||
private int mStereoBufferSize = 0;
|
||||
|
||||
private float[] mXCoords = new float[MAX_FINGERS];
|
||||
private float[] mYCoords = new float[MAX_FINGERS];
|
||||
|
||||
|
@ -91,8 +85,6 @@ public class Apple2Activity extends Activity {
|
|||
|
||||
private native void nativeOnKeyUp(int keyCode, int metaState);
|
||||
|
||||
private native void nativeOnUncaughtException(String home, String trace);
|
||||
|
||||
private native void nativeOnResume(boolean isSystemResume);
|
||||
|
||||
public native void nativeOnPause(boolean isSystemPause);
|
||||
|
@ -112,63 +104,6 @@ public class Apple2Activity extends Activity {
|
|||
public native void nativePerformCrash(int crashType);
|
||||
|
||||
|
||||
private void _setCustomExceptionHandler() {
|
||||
if (mSetUncaughtExceptionHandler) {
|
||||
return;
|
||||
}
|
||||
mSetUncaughtExceptionHandler = true;
|
||||
|
||||
final String homeDir = "/data/data/" + this.getPackageName();
|
||||
final Thread.UncaughtExceptionHandler defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable t) {
|
||||
try {
|
||||
StackTraceElement[] stackTraceElements = t.getStackTrace();
|
||||
StringBuffer traceBuffer = new StringBuffer();
|
||||
|
||||
// prepend information about this device
|
||||
traceBuffer.append(Build.BRAND);
|
||||
traceBuffer.append("\n");
|
||||
traceBuffer.append(Build.MODEL);
|
||||
traceBuffer.append("\n");
|
||||
traceBuffer.append(Build.MANUFACTURER);
|
||||
traceBuffer.append("\n");
|
||||
traceBuffer.append(Build.DEVICE);
|
||||
traceBuffer.append("\n");
|
||||
traceBuffer.append("Device sample rate:");
|
||||
traceBuffer.append(mSampleRate);
|
||||
traceBuffer.append("\n");
|
||||
traceBuffer.append("Device mono buffer size:");
|
||||
traceBuffer.append(mMonoBufferSize);
|
||||
traceBuffer.append("\n");
|
||||
traceBuffer.append("Device stereo buffer size:");
|
||||
traceBuffer.append(mStereoBufferSize);
|
||||
traceBuffer.append("\n");
|
||||
|
||||
// now append the actual 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());
|
||||
} catch (Throwable terminator2) {
|
||||
// Yo dawg, I hear you like exceptions in your exception handler! ...
|
||||
}
|
||||
|
||||
defaultExceptionHandler.uncaughtException(thread, t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (Apple2Activity.DEBUG_STRICT && BuildConfig.DEBUG) {
|
||||
|
@ -189,7 +124,7 @@ public class Apple2Activity extends Activity {
|
|||
|
||||
Log.e(TAG, "onCreate()");
|
||||
|
||||
_setCustomExceptionHandler();
|
||||
Apple2CrashHandler.getInstance().setCustomExceptionHandler(this);
|
||||
|
||||
// run first-time initializations
|
||||
if (!Apple2Preferences.FIRST_TIME_CONFIGURED.booleanValue(this)) {
|
||||
|
@ -199,13 +134,13 @@ public class Apple2Activity extends Activity {
|
|||
Apple2Preferences.FIRST_TIME_CONFIGURED.saveBoolean(this, true);
|
||||
|
||||
// get device audio parameters for native OpenSLES
|
||||
mSampleRate = DevicePropertyCalculator.getRecommendedSampleRate(this);
|
||||
mMonoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/false);
|
||||
mStereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/true);
|
||||
Log.d(TAG, "Device sampleRate:" + mSampleRate + " mono bufferSize:" + mMonoBufferSize + " stereo bufferSize:" + mStereoBufferSize);
|
||||
int sampleRate = DevicePropertyCalculator.getRecommendedSampleRate(this);
|
||||
int monoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/false);
|
||||
int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/true);
|
||||
Log.d(TAG, "Device sampleRate:" + sampleRate + " mono bufferSize:" + monoBufferSize + " stereo bufferSize:" + stereoBufferSize);
|
||||
|
||||
String dataDir = Apple2DisksMenu.getDataDir(this);
|
||||
nativeOnCreate(dataDir, mSampleRate, mMonoBufferSize, mStereoBufferSize);
|
||||
nativeOnCreate(dataDir, sampleRate, monoBufferSize, stereoBufferSize);
|
||||
|
||||
// NOTE: load preferences after nativeOnCreate ... native CPU thread should still be paused
|
||||
Apple2Preferences.loadPreferences(this);
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Apple // emulator for *nix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 2 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* THERE ARE NO WARRANTIES WHATSOEVER.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||
import org.deadc0de.apple2ix.basic.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class Apple2CrashHandler {
|
||||
|
||||
public final static String javaCrashFileName = "jcrash.txt";
|
||||
|
||||
public static Apple2CrashHandler getInstance() {
|
||||
return sCrashHandler;
|
||||
}
|
||||
|
||||
public enum CrashType {
|
||||
JAVA_CRASH {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.crash_java_npe);
|
||||
}
|
||||
},
|
||||
NULL_DEREF {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.crash_null);
|
||||
}
|
||||
},
|
||||
STACKCALL_OVERFLOW {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.crash_stackcall_overflow);
|
||||
}
|
||||
},
|
||||
STACKBUF_OVERFLOW {
|
||||
@Override
|
||||
public final String getTitle(Apple2Activity activity) {
|
||||
return activity.getResources().getString(R.string.crash_stackbuf_overflow);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static final int size = CrashType.values().length;
|
||||
|
||||
public abstract String getTitle(Apple2Activity activity);
|
||||
|
||||
public static String[] titles(Apple2Activity activity) {
|
||||
String[] titles = new String[size];
|
||||
int i = 0;
|
||||
for (CrashType setting : values()) {
|
||||
titles[i++] = setting.getTitle(activity);
|
||||
}
|
||||
return titles;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setCustomExceptionHandler(Apple2Activity 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());
|
||||
} catch (Throwable terminator2) {
|
||||
// Yo dawg, I hear you like exceptions in your exception handler! ...
|
||||
}
|
||||
|
||||
defaultExceptionHandler.uncaughtException(thread, t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean areJavaCrashesPresent(Apple2Activity activity) {
|
||||
File javaCrash = _javaCrashFile(activity);
|
||||
return javaCrash.exists();
|
||||
}
|
||||
|
||||
public boolean areNativeCrashesPresent(Apple2Activity activity) {
|
||||
File[] nativeCrashes = _nativeCrashFiles(activity);
|
||||
return nativeCrashes != null && nativeCrashes.length > 0;
|
||||
}
|
||||
|
||||
public boolean areCrashesPresent(Apple2Activity activity) {
|
||||
return areJavaCrashesPresent(activity) || areNativeCrashesPresent(activity);
|
||||
}
|
||||
|
||||
public void performCrash(int crashType) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
nativePerformCrash(crashType);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// privates
|
||||
|
||||
private Apple2CrashHandler() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
private File _javaCrashFile(Apple2Activity activity) {
|
||||
return new File(Apple2DisksMenu.getDataDir(activity), javaCrashFileName);
|
||||
}
|
||||
|
||||
private File[] _nativeCrashFiles(Apple2Activity activity) {
|
||||
FilenameFilter dmpFilter = new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
File file = new File(dir, name);
|
||||
if (file.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check file extensions ... sigh ... no String.endsWithIgnoreCase() ?
|
||||
|
||||
final String extension = ".dmp";
|
||||
final int nameLen = name.length();
|
||||
final int extLen = extension.length();
|
||||
if (nameLen <= extLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String suffix = name.substring(nameLen - extLen, nameLen);
|
||||
return (suffix.equalsIgnoreCase(extension));
|
||||
}
|
||||
};
|
||||
|
||||
return new File(Apple2DisksMenu.getDataDir(activity)).listFiles(dmpFilter);
|
||||
}
|
||||
|
||||
private String _dumpPath2ProcessedPath(String crashPath) {
|
||||
return crashPath.substring(0, crashPath.length() - 4) + ".txt";
|
||||
}
|
||||
|
||||
private boolean _readFile(File file, StringBuilder fileData) {
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
char[] buf = new char[1024];
|
||||
int numRead = 0;
|
||||
while ((numRead = reader.read(buf)) != -1) {
|
||||
String readData = String.valueOf(buf, 0, numRead);
|
||||
fileData.append(readData);
|
||||
}
|
||||
reader.close();
|
||||
break;
|
||||
} catch (InterruptedIOException ie) {
|
||||
/* EINTR, EAGAIN ... */
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "Error reading file at path : " + file.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100, 0);
|
||||
} catch (InterruptedException e) {
|
||||
/* ... */
|
||||
}
|
||||
++ attempts;
|
||||
} while (attempts < maxAttempts);
|
||||
|
||||
return attempts < maxAttempts;
|
||||
}
|
||||
|
||||
private File _writeTempLogFile(StringBuilder allCrashData) {
|
||||
|
||||
File allCrashFile = null;
|
||||
|
||||
String storageState = Environment.getExternalStorageState();
|
||||
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
|
||||
allCrashFile = new File(Environment.getExternalStorageDirectory(), "apple2ix_crash.txt");
|
||||
} else {
|
||||
allCrashFile = new File("/data/local/tmp", "apple2ix_crash.txt");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Writing all crashes to temp file : " + allCrashFile);
|
||||
final int maxAttempts = 5;
|
||||
int attempts = 0;
|
||||
do {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(allCrashFile));
|
||||
writer.append(allCrashData);
|
||||
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);
|
||||
|
||||
return allCrashFile;
|
||||
}
|
||||
|
||||
private void _sendEmailToDeveloperWithCrashData(Apple2Activity activity, StringBuilder allCrashData) {
|
||||
mAlreadySentReport.set(true);
|
||||
|
||||
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "apple2ix_crash@deadcode.org"/*non-zero variant is correct endpoint at the moment*/, null));
|
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Crasher");
|
||||
|
||||
File allCrashFile = _writeTempLogFile(allCrashData);
|
||||
// Putting all the text data into the EXTRA_TEXT appears to trigger android.os.TransactionTooLargeException ...
|
||||
//emailIntent.putExtra(Intent.EXTRA_TEXT, allCrashData.toString());
|
||||
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(allCrashFile));
|
||||
|
||||
// But we can put some text data
|
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, "Greeting Apple2ix developers! The app crashed, please help!");
|
||||
|
||||
Log.d(TAG, "STARTING CHOOSER FOR EMAIL ...");
|
||||
activity.startActivity(Intent.createChooser(emailIntent, "Send email"));
|
||||
Log.d(TAG, "AFTER START ACTIVITY ...");
|
||||
}
|
||||
|
||||
|
||||
private final static String TAG = "Apple2CrashHandler";
|
||||
private final static Apple2CrashHandler sCrashHandler = new Apple2CrashHandler();
|
||||
|
||||
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);
|
||||
|
||||
}
|
|
@ -300,7 +300,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
// in debug mode we actually exercise the crash reporter ...
|
||||
return activity.getResources().getString(R.string.crasher_title);
|
||||
} else {
|
||||
return activity.getResources().getString(R.string.crasher_send_title);
|
||||
return activity.getResources().getString(R.string.crasher_check_title);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
if (BuildConfig.DEBUG) {
|
||||
return activity.getResources().getString(R.string.crasher_summary);
|
||||
} else {
|
||||
return activity.getResources().getString(R.string.crasher_send_summary);
|
||||
return activity.getResources().getString(R.string.crasher_check_summary);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,12 +317,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
_alertDialogHandleSelection(activity, R.string.crasher, new String[]{
|
||||
activity.getResources().getString(R.string.crash_java_npe),
|
||||
activity.getResources().getString(R.string.crash_null),
|
||||
activity.getResources().getString(R.string.crash_stackcall_overflow),
|
||||
activity.getResources().getString(R.string.crash_stackbuf_overflow),
|
||||
}, new IPreferenceLoadSave() {
|
||||
_alertDialogHandleSelection(activity, R.string.crasher, Apple2CrashHandler.CrashType.titles(activity), new IPreferenceLoadSave() {
|
||||
@Override
|
||||
public int intValue() {
|
||||
return -1;
|
||||
|
@ -344,13 +339,13 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
|
|||
break;
|
||||
|
||||
default:
|
||||
activity.nativePerformCrash(value);
|
||||
Apple2CrashHandler.getInstance().performCrash(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// TODO FIXME : run local crash analysis and open Email Intent to send
|
||||
// TODO FIXME : checkbox on whether to enable checking/sending crashes
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,11 +19,14 @@
|
|||
<string name="color_color">Color</string>
|
||||
<string name="color_interpolated">Interpolated color</string>
|
||||
<string name="crasher">Crasher</string>
|
||||
<string name="crasher_title">Crash emulator</string>
|
||||
<string name="crasher_check_title">Check for crash reports</string>
|
||||
<string name="crasher_check_summary">Check for crash reports to email developer)</string>
|
||||
<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_summary">Test crash generation</string>
|
||||
<string name="crasher_send">Send crash reports</string>
|
||||
<string name="crasher_send_title">Send crash reports</string>
|
||||
<string name="crasher_send_summary">Will email crash reports to developer (if any)</string>
|
||||
<string name="crasher_title">Crash emulator</string>
|
||||
<string name="crash_null">NULL-deref</string>
|
||||
<string name="crash_java_npe">Java NPE</string>
|
||||
<string name="crash_stackcall_overflow">stack call overflow</string>
|
||||
|
|
|
@ -68,7 +68,8 @@ static volatile int __attribute__((noinline)) _crash_stackbuf_overflow(void) {
|
|||
return getpid();
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativePerformCrash(JNIEnv *env, jobject obj, jint crashType) {
|
||||
void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativePerformCrash(JNIEnv *env, jclass cls, jint crashType) {
|
||||
#warning FIXME TODO ... we should turn off test codepaths in release build =D
|
||||
LOG("... performing crash of type : %d", crashType);
|
||||
|
||||
switch (crashType) {
|
||||
|
@ -91,3 +92,39 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativePerformCrash(JNIEnv *env, j
|
|||
}
|
||||
}
|
||||
|
||||
#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));
|
||||
}
|
||||
|
||||
|
|
|
@ -252,41 +252,6 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit(JNIEnv *env, jobject
|
|||
#endif
|
||||
}
|
||||
|
||||
#define _JAVA_CRASH_NAME "/jcrash.txt"
|
||||
#define _HALF_PAGE_SIZE (PAGE_SIZE>>1)
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnUncaughtException(JNIEnv *env, jobject obj, 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_Apple2Activity_nativeOnKeyDown(JNIEnv *env, jobject obj, jint keyCode, jint metaState) {
|
||||
if (UNLIKELY(shuttingDown)) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user