'Android crash report shows exception that is caught
I have an Android app written in Java, and recently noticed many crash reports occurring in an AsyncTask. The stack trace makes no sense, as it is inside a try/catch so there is no way for the exception to be thrown. How can a caught exception cause an app crash?
13: public class HttpGoogleSignInAction...
@Override
protected String doInBackground(Void... voids) {
try {
// Check if user exists
UserConfig user = null;
31: user = MainActivity.connection.fetch(this.config);
if (user == null) {
} else {
// User exists, try to sign in user
this.config = MainActivity.connection.connect(this.config);
}
} catch (Exception userDoesNotExist) {
try {
// User does not exist, try to create user
this.config = MainActivity.connection.create(this.config);
} catch (Exception exception) {
this.exception = exception;
}
}
return "";
}
public String POST(String url, String xml) {
if (this.debug) {
System.out.println("POST: " + url);
System.out.println("XML: " + xml);
}
String result = "";
try {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);
StringEntity content = new StringEntity(xml, "utf-8");
content.setContentType("application/xml");
httpPost.setEntity(content);
HttpResponse response = httpClient.execute(httpPost, localContext);
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity, HTTP.UTF_8);
}
if ((response.getStatusLine().getStatusCode() != 200) && (response.getStatusLine().getStatusCode() != 204)) {
this.exception = new SDKException(""
+ response.getStatusLine().getStatusCode()
+ " : " + result);
2205: throw this.exception;
}
} catch (Exception exception) {
if (this.debug) {
exception.printStackTrace();
}
this.exception = new SDKException(exception);
2213: throw this.exception;
}
return result;
}
The stack trace shows the crash occurring in the line,
user = MainActivity.connection.fetch(this.config);
It is a normal RuntimeException subclass exception being thrown, which should be caught. If I try to force an exception to test it the try/catch works fine and no crash, but in 1% of users using the app I am seeing crashes, others it works fine. Makes no sense.
This is the stack trace from Google Play, SDKException is a subclass of RuntimeException, the line of code it occurs in is inside try/catch
org.botlibre.sdk.SDKException:
at org.botlibre.sdk.SDKConnection.POST (SDKConnection.java:2213)
at org.botlibre.sdk.SDKConnection.fetch (SDKConnection.java:259)
at ...HttpGoogleSignInAction.doInBackground (HttpGoogleSignInAction.java:31)
at ...HttpGoogleSignInAction.doInBackground (HttpGoogleSignInAction.java:13)
at android.os.AsyncTask$3.call (AsyncTask.java:394)
at java.util.concurrent.FutureTask.run (FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run (AsyncTask.java:305)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
at java.lang.Thread.run (Thread.java:923)
Caused by: org.botlibre.sdk.SDKException:
at org.botlibre.sdk.SDKConnection.POST (SDKConnection.java:2205)
Solution 1:[1]
org.botlibre.sdk.SDKException:
at org.botlibre.sdk.SDKConnection.POST (SDKConnection.java:2213)
at org.botlibre.sdk.SDKConnection.fetch (SDKConnection.java:259)
Shows that you're throwing the exception captured here in doInBackground()
:
try {
// User does not exist, try to create user
this.config = MainActivity.connection.create(this.config);
} catch (Exception exception) {
**this.exception = exception;**
}
}
Even though this execption is within a catch block, since it's persisted and then thrown later it is now outside of a try-catch block and can crash the app. That is
try {
...
} catch (Exception exception) {
if (this.debug) {
exception.printStackTrace();
}
this.exception = new SDKException(exception);
// This line will throw an execption that will have the message from the original exception.
2213: throw this.exception;
}
The source for SDKException's single exception constructor shows it reuses the message from the exception parameter.
Solution 2:[2]
You are very clearly re-throwing the caught exception on line 2213. If you throw
an exception from a catch
block, it escapes the try/catch because you are throwing it from a scope of code that is not surrounded by try { }
.
As for why fetch()
might be throwing, we would have to see the code to be able to guess.
Solution 3:[3]
Even though you have your code wrapped in try catch, there is a possibility of a crash if different threads are involved. try catch does not catch exceptions from child threads, so if any of your methods(like .fetch or .connect) used in doInBackground are internally using/creating different threads and an exception is thrown within that thread it might cause the app to crash. Looking at the logs, it is possible the .fetch method is asynchronous and performing operations in a different thread.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Michael Powell |
Solution 2 | Tenfour04 |
Solution 3 | inventionsbyhamid |