I'm using a crash report library in my Android project. Once activated, it reacts to every uncatched exception and creates a report just before the app shutdown.
So far so good, but I want to add more "control" to this thing and create reports for non-Exceptions too. My idea is to define a "fake" Exception this way:
public final class NonFatalError extends RuntimeException {
private static final long serialVersionUID = -6259026017799110412L;
public NonFatalError(String msg) {
super(msg);
}
}
So, when I want to send a non-fatal error message and create a report, I'll do this:
throw new NonFatalError("Warning! A strange thing happened. I report this to the server but I let you continue the job...");
If called from the main thread, this obviously makes the app crash. So, I tried to throw it on a background thread!
new Thread(new Runnable() {
#Override
public void run() {
throw new NotFatalError("Warning! A strange thing happened. I report this to the server but I let you continue the job...");
}
}).start();
A great idea? No. The app crashes anyway (but the fake crash report is sent as expected). Is there another way to achieve what I want?
Your exception never gets caught, so that's why your application is crashing.
You can do this do catch the exception from your main thread:
Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread th, Throwable ex) {
System.out.println("Uncaught exception: " + ex);
}
};
Thread t = new Thread(new Runnable() {
#Override
public void run() {
throw new NotFatalError("Warning! A strange thing happened. I report this to the server but I let you continue the job...");
}
});
t.setUncaughtExceptionHandler(h);
t.start();
But you can also run the code from your main thread and catch it there.. Like:
try
{
throw new NonFatalError("Warning! blablabla...");
}
catch(NonFatalError e)
{
System.out.println(e.getMessage());
}
Because your exception is extended from the RuntimeException class the default behaviour is to exit the application if the exception is not catched anywhere. So that's why you should catch it before the Java Runtime decides to quit the app.
You are using exception to create logs. You shouldnt do that. If you are using a library like crashlytics (https://try.crashlytics.com/) you can send log reports like in this link: http://support.crashlytics.com/knowledgebase/articles/120066-how-do-i-use-logging
The library you are using should have a similar method.
If you want to continue to use Exceptions, you need to catch them to not crash the application.
Related
Is there a way to create a listener in a separate class that runs a certain piece of code whenever an exception is caught within your project?
My code has a lot of try-catches in it, and if an exception is caught I would like to see the logs using log4j. I can do the following for every try-catch I have fairly easily (just with some time effort):
private static final Logger logger = LogManager.getLogger(Example.class);
public void testMethod() {
try {
// some code here that could throw an exception
} catch(Exception e) {
logger.error("Unexpected error has occurred: ", e);
}
}
This will log the exception using log4j. However, I would need to do that over 50 times, and it's so redundant that I would rather be able to use 1 method to do that. So, is there a way to instead do something like this?
public class ListenerClass {
private static final Logger logger = LogManager.getLogger(ListenerClass.class);
// This method will be listening for exceptions to be caught within the project
/**
* #param e - The exception that was just caught
*/
public void listenerMethod(ExceptionCaught e) {
logger.error("An exception has been thrown: ", e);
}
}
Is this possible?
Thanks
Standard java way:
Thread.setDefaultUncaughtExceptionHandler( (thread, throwable) -> {
log(throwable.getMessage(), thread.getId());
});
which will handle uncaught RuntimeExceptions, and unless otherwise specified it will act for all your application threads.
Just remember the Exceptions are thrown for a reason, and shouldn't be ignored, especially RuntimeExceptions.
If you are using an older version of java (before 8), you must explicitly instantiate an anonymous class:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(final Thread t, final Throwable e) {
}
});
Look at Thread.setDefaultUncaughtExceptionHandler()
In an app I'm developing, I'm using Google Analytics to track uncaught exceptions like so:
// ...after setting up Google Analytics...
Thread.setDefaultUncaughtExceptionHandler(new AnalyticsExceptionHandler(Thread.getDefaultUncaughtExceptionHandler()));
And this is the handler, the AnalyticsExceptionHandler class:
public class AnalyticsExceptionHandler implements UncaughtExceptionHandler
{
// Private
private UncaughtExceptionHandler _defaultHandlerRef;
public AnalyticsExceptionHandler(UncaughtExceptionHandler defaultHandlerRef)
{
this._defaultHandlerRef = defaultHandlerRef;
}
#Override
public void uncaughtException(Thread t, Throwable e)
{
// ...track and send the exception to Google Analytics...
_defaultHandlerRef.uncaughtException(t, e);
}
}
Thing is, the app never actually crashes, it just freezes. If I remove the setDefaultUncaughtExceptionHandler() line then the app crashes normally.
Am I doing something wrong in the above code by passing it to the previous default handler?
Why not re-throw the exception?
public void uncaughtException(Thread t, Throwable e)
{
// ...track and send the exception to Google Analytics...
_defaultHandlerRef.uncaughtException(t, e);
throw e;
}
I want to override the global Exception Handling in my RCP app. Whenever an uncaught Exception happens I want to log it (using java logging) and then exit the app. I have already overwritten the eventLoopException(Throwable exception) method in the ApplicationWorkbenchAdvisor class. But this catches only the event loop exceptions. As of now I have also overwritten the postStartup() method like this:
public void postStartup()
{
Policy.setStatusHandler(new StatusHandler()
{
#Override
public void show(IStatus status, String title)
{
LOGGER.log(Level.SEVERE, "Uncaught Exception", status.getException());
UnexpectedErrorDialog();
PlatformUI.getWorkbench().close();
}
});
}
It logs the exception in my log file and exits the app. But it's obviously not right and the exception is shown twice in the console, cause all I do is intercepting the showing of the exception in a gui dialog to the user. So how can I properly overwrite/change the global exception handling, so that my code (log) is used instead of the default one?
I would suggest you to use org.eclipse.ui.statusHandlers extension point
Thanks to sambi reddy's tip i have now overwritten AbstractStatusHandler in the ApplicationWorkbenchAdvisor class
#Override
public synchronized AbstractStatusHandler getWorkbenchErrorHandler() {
if (myStatusHandler == null) {
myStatusHandler = new MyStatusHandler();
}
return myStatusHandler;
}
MyStatusHandler extends AbstractStatusHandler and i have overwritten the handle method like this:
#Override
public void handle(StatusAdapter statusAdapter, int style)
{
if(statusAdapter.getStatus().matches(IStatus.ERROR) && ((style != StatusManager.NONE)))
{
LOGGER.log(Level.SEVERE, "Uncaught Exception", statusAdapter.getStatus().getException());
UnexpectedErrorDialog();
PlatformUI.getWorkbench().close();
}
}
seems to work right, only downside is that i still get 2 console outputs.
I want to test out crash report using acra but the first step is I need to simulate a fatal crash in Android using code.
Any idea?
Just execute this code: divide by zero
Update: Also can try this
Create a method,
public void stackOverflow() {
this.stackOverflow();
}
And call this somewhere/buttonClick
OR simply throw an uncaught exception
throw new RuntimeException("This is a crash");
Bingo!
Access a view that is not defined.
Access the first element of an empty list without checking.
Divide by Zero.
Throw the device out the window.
Submerge the device in water.
Don't declare activity in the Android Manifest .
You could try a Null Pointer exception.
Integer i = null;
Then invoke any method on the object.
i.byteValue();
Invoking a method on an object that hasn't been initialized will crash the app.
A very simple approach... and is very important to understand that why it happened.
Try initiating a variable in onCreate() before the setContentView() method, then use it to call a method or variable or try registering it to some listener..
Eg:
Button b;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
b = (Button)findViewById(R.id.butt);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
}
});
setContentView(R.layout.main);
}
This crashed, because before setContentView() none of the components/view in the main.xml layout got their ids.
Simply create in your main.xml a button like this:
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="crash"
android:text="Crash me" />
then run your app and click for crash
Most simple I know : throw null.
You can't throw null, so a NullPointerException is raised.
throw null;
you can crash with a simple null point exception.
throw new NullPointerException();
in addition to #vinnet-shukla answer:
"OR simply throw an uncaught exception"
throwing uncaught exception to do a crash is bad idea as the exception could by caught somwhere higher in the stack - especially when whe don't know where we are right now :)
more ellegant way is to use ERROR
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.
so we could make our own Error subclass and use it:
/*
* usage:
*
* CrashError.doCrash();
*
*/
public class CrashError extends Error {
public CrashError() {
this("simulated crash");
}
public CrashError(String msg) {
super(msg);
}
public static void doCrash() {
throw new CrashError();
}
}
but if we talk about other possibilities we could also a throw checked exception :)
this will also be a lesson how we could RETHROW CHECKED EXCEPTION :) with other way than use of sun.misc.Unsafe especially when the class is not available in VM implementation
#SuppressWarnings("unchecked")
public static <E extends Throwable> void throwAnyT(Throwable e) throws E {
throw (E) e;
}
public static void throwUnchecked(Throwable e) {
throwAny(e);
// should never get there.
throw new InternalError();
}
public static void crash() {
throwUnchecked(new java.io.IOException("simulated crash"));
}
in addition to #audric answer:
"You can't throw null"
yes you can :) it's exactly what you are doing in your example and yes it could get undetectable if the catch block will not use Throwable - the NPX will never be thrown and simply there will be normal flow when code will still execute and yes i'll have seen this and experienced by myself :) on ANDROID DALVIK
and what about..? maybe it could fulfill your needs?
java specific (also in android):
- Runtime.getRuntime().exit(int);
- System.exit(int);
- Runtime.getRuntime().halt(int);
android specific:
- android.os.Process.killProcess(int);
- android.os.Process.killProcessQuiet(int);
- android.os.Process.sendSignal(int,int);
- android.system.Os.kill(int);
For kotlin:
val test = ("0")
println(test[1])
Force crash after some delay like this,
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
Log.i("tag", "This'll run 10 seconds later");
throw new RuntimeException("This is a crash");
}
},
10000);
Ref-1 & Ref-2
If you are using firebase crashlytics, then there is a very easy way to do this. Mentioned in their document also.
val crashlytics = FirebaseCrashlytics.getInstance()
crashlytics.log("my message")
You can crash the application simply with this line of code.
throw new RuntimeException("Test Crash"); // Force a crash
You can pass the message, in this case "Test Crash", which can be useful later to refer.
One step ahead,
Make sure none of your application's class files implement UncaughtExceptionHandler interface as below,
public class MyApplication extends Application implements Thread.UncaughtExceptionHandler{
Otherwise the above exception or any exception for that matter, would be caught/consumed by that class, resulting in not crashing the app. However, you can get hold of that exception in uncaughtException(Thread t, Throwable e) method as below and take the required action. In your case, you'd be reporting it to the Acra using their supported SDK methods.
#Override
public void uncaughtException(Thread t, Throwable e) {
Log.e("MyApplication", "Error", e);
}
You can use activity manager to crash the app with no code changes
adb shell am crash <packagename>
Use the following code:
String xyz=null;
system.out.println(xyz);
I'm developing a multi-threaded Java program use different assertions throughout the code and run my program using the ea flag.
Can I make my program immediately stop and exit when any assertion fails?
try {
code that may generate AssertionError
} catch (AssertionError e) {
System.exit(0);//logging or any action
}
enable assertion also.
but it must be taken care.
Assert will stop whatever thread threw the assertion, assuming the AssertionError isn't caught. Although I would think that killing that thread would be enough and you wouldn't want to go and kill the whole program. Anyhow, to actually kill the entire program, just wrap your runnables with a
try {
} catch (AssertionError e) {
System.exit(1);
}
which will kill the program when the assertion is raised.
So you could make a "CrashOnAssertionError" runnable to wrap all of your runnables:
public class CrashOnAssertionError implements Runnable {
private final Runnable mActualRunnable;
public CrashOnAssertionError(Runnable pActualRunnable) {
mActualRunnable = pActualRunnable;
}
public void run() {
try {
mActualRunnable.run();
} catch (AssertionError) {
System.exit(1);
}
}
}
And then you can do something like:
Runnable r = new CrashOnAssertionError(
new Runnable() {
public void run() {
// do stuff
}
});
new Thread(r).start();
When assertions are enabled, they throw a java.lang.AssertionError upon failing. As long as you don't try to catch this, the thread throwing the exception will stop when an assertion fails.
If you want any other behavior, you can catch (AssertionError) and do whatever you want inside the catch statement. For example, call System.exit(1).
If you want AssertionError to include an error message, you need to use the assert Expression1 : Expression2; form of assert. For more information, read this.