-
Notifications
You must be signed in to change notification settings - Fork 73
[Feat][SDK-347] ANR report #323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
buongarzoni
wants to merge
25
commits into
master
Choose a base branch
from
feat/SDK-347/anr-report
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
0161c77
feat: Update android min sdk from 16 to 21 and target/compile sdk fro…
christianbuon 69df96d
feat: Add ANR detectors
christianbuon 6ae33b7
feat: send non main threads as extra information for api >= 30
christianbuon bc3f27a
refactor: remove unnecessary code
christianbuon b8cb8f0
refactor: don't launch thread if listener is null
christianbuon 957a0d8
refactor: remove unnecessary attribute for Line
christianbuon 91ab622
refactor: do not create watchdog or run it if anr listener is null
christianbuon a0082ff
test: add Tests for Watchdog
christianbuon c69563e
test: remove unused imports
christianbuon c3ed238
test: set parameters as private
christianbuon dcac7ab
test: Add tests for HistoricalAnrDetector
christianbuon 61dfa33
refactor: Initialize ThreadParser as expected
christianbuon 6c0848e
feat: Add AndroidConfiguration to tun on/off ANR detectors implementa…
christianbuon 64c5f4e
Merge branch 'master' into feat/SDK-347/anr-report
christianbuon da109a7
refactor: use RollbarThread to send ANR information
christianbuon c1a5df0
feat(HistoricalAnrDetector): save last anr timestamp
christianbuon a349bf3
build: downgrade compile and target sdk to 30, to test CI
christianbuon c8e8c77
test: delete tests to validate if CI completes
christianbuon 1c23f8b
fix: lint
christianbuon 5c94db7
fix(RollbarThrowableWrapper): lint
christianbuon 978c831
fix(RollbarThrowableWrapper): lint
christianbuon 7000260
chore: add new method information in revapi file
christianbuon 073a470
build(android-example): migrate old libs to AndroidX
christianbuon 257f738
build: update compile and target sdk to 32
christianbuon d044fa3
build: downgrade compile and target sdk to 31
christianbuon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
rollbar-android/src/main/java/com/rollbar/android/anr/AnrDetector.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.rollbar.android.anr; | ||
|
||
public interface AnrDetector { | ||
void init(); | ||
} |
27 changes: 27 additions & 0 deletions
27
rollbar-android/src/main/java/com/rollbar/android/anr/AnrDetectorFactory.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.rollbar.android.anr; | ||
|
||
import android.content.Context; | ||
import android.os.Build; | ||
|
||
import com.rollbar.android.anr.historical.HistoricalAnrDetector; | ||
import com.rollbar.android.anr.watchdog.WatchdogAnrDetector; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class AnrDetectorFactory { | ||
private final static Logger LOGGER = LoggerFactory.getLogger(AnrDetectorFactory.class); | ||
|
||
public static AnrDetector create( | ||
Context context, | ||
AnrListener anrListener | ||
) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { | ||
LOGGER.debug("Creating HistoricalAnrDetector"); | ||
return new HistoricalAnrDetector(context, anrListener); | ||
} else { | ||
LOGGER.debug("Creating WatchdogAnrDetector"); | ||
return new WatchdogAnrDetector(context, anrListener); | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
rollbar-android/src/main/java/com/rollbar/android/anr/AnrException.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.rollbar.android.anr; | ||
|
||
public final class AnrException extends RuntimeException { | ||
|
||
public AnrException(String message, Thread thread) { | ||
super(message); | ||
setStackTrace(thread.getStackTrace()); | ||
} | ||
|
||
public AnrException(StackTraceElement[] stackTraceElements) { | ||
super("Application Not Responding"); | ||
setStackTrace(stackTraceElements); | ||
} | ||
|
||
} |
10 changes: 10 additions & 0 deletions
10
rollbar-android/src/main/java/com/rollbar/android/anr/AnrListener.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.rollbar.android.anr; | ||
|
||
public interface AnrListener { | ||
/** | ||
* Called when an ANR is detected. | ||
* | ||
* @param error The error describing the ANR. | ||
*/ | ||
void onAppNotResponding(AnrException error); | ||
} |
135 changes: 135 additions & 0 deletions
135
rollbar-android/src/main/java/com/rollbar/android/anr/historical/HistoricalAnrDetector.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package com.rollbar.android.anr.historical; | ||
|
||
import android.annotation.SuppressLint; | ||
import android.app.ActivityManager; | ||
import android.app.ApplicationExitInfo; | ||
import android.content.Context; | ||
|
||
import com.rollbar.android.anr.AnrDetector; | ||
import com.rollbar.android.anr.AnrException; | ||
import com.rollbar.android.anr.AnrListener; | ||
import com.rollbar.android.anr.historical.stacktrace.Lines; | ||
import com.rollbar.android.anr.historical.stacktrace.RollbarThread; | ||
import com.rollbar.android.anr.historical.stacktrace.ThreadDumpParser; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.ByteArrayInputStream; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
@SuppressLint("NewApi") // Validated in the Factory | ||
public class HistoricalAnrDetector implements AnrDetector { | ||
private final static Logger LOGGER = LoggerFactory.getLogger(HistoricalAnrDetector.class); | ||
|
||
private final Context context; | ||
private final AnrListener anrListener; | ||
ThreadDumpParser threadDumpParser = new ThreadDumpParser(true);//todo remove isBackground | ||
|
||
public HistoricalAnrDetector( | ||
Context context, | ||
AnrListener anrListener | ||
) { | ||
this.context = context; | ||
this.anrListener = anrListener; | ||
} | ||
|
||
@Override | ||
public void init() { | ||
Thread thread = new Thread("HistoricalAnrDetectorThread") { | ||
@Override | ||
public void run() { | ||
super.run(); | ||
evaluateLastExitReasons(); | ||
} | ||
}; | ||
thread.setDaemon(true); | ||
thread.start(); | ||
} | ||
|
||
|
||
private void evaluateLastExitReasons() { | ||
if (anrListener == null) { | ||
LOGGER.error("AnrListener is null"); | ||
return; | ||
} | ||
|
||
List<ApplicationExitInfo> applicationExitInfoList = getApplicationExitInformation(); | ||
|
||
if (applicationExitInfoList.isEmpty()) { | ||
LOGGER.debug("Empty ApplicationExitInfo List"); | ||
return; | ||
} | ||
|
||
for (ApplicationExitInfo applicationExitInfo : applicationExitInfoList) { | ||
if (isNotAnr(applicationExitInfo)) { | ||
continue; | ||
} | ||
|
||
try { | ||
List<RollbarThread> threads = getThreads(applicationExitInfo); | ||
|
||
if (threads.isEmpty()) { | ||
LOGGER.warn("Error parsing ANR"); | ||
continue;//Todo: Do something ? | ||
} | ||
|
||
anrListener.onAppNotResponding(createAnrException(threads)); | ||
} catch (Throwable e) { | ||
LOGGER.error("Can't parse ANR", e); | ||
} | ||
} | ||
} | ||
|
||
private boolean isNotAnr(ApplicationExitInfo applicationExitInfo) { | ||
return applicationExitInfo.getReason() != ApplicationExitInfo.REASON_ANR; | ||
} | ||
|
||
private AnrException createAnrException(List<RollbarThread> threads) { | ||
return new AnrException(threads.get(0).toStackTraceElement()); | ||
} | ||
|
||
private List<ApplicationExitInfo> getApplicationExitInformation() { | ||
ActivityManager activityManager = | ||
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); | ||
return activityManager.getHistoricalProcessExitReasons(null, 0, 0); | ||
} | ||
|
||
private List<RollbarThread> getThreads(ApplicationExitInfo applicationExitInfo) throws IOException { | ||
Lines lines = getLines(applicationExitInfo); | ||
return threadDumpParser.parse(lines); | ||
} | ||
|
||
private Lines getLines(ApplicationExitInfo applicationExitInfo) throws IOException { | ||
byte[] dump = getDumpBytes(Objects.requireNonNull(applicationExitInfo.getTraceInputStream())); | ||
return getLines(dump); | ||
} | ||
|
||
private Lines getLines(byte[] dump) throws IOException { | ||
return Lines.readLines(toBufferReader(dump)); | ||
} | ||
|
||
private BufferedReader toBufferReader(byte[] dump) { | ||
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(dump))); | ||
} | ||
|
||
private byte[] getDumpBytes(final InputStream trace) throws IOException { | ||
try (final ByteArrayOutputStream buffer = new ByteArrayOutputStream()) { | ||
|
||
int nRead; | ||
byte[] data = new byte[1024]; | ||
|
||
while ((nRead = trace.read(data, 0, data.length)) != -1) { | ||
buffer.write(data, 0, nRead); | ||
} | ||
|
||
return buffer.toByteArray(); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
rollbar-android/src/main/java/com/rollbar/android/anr/historical/stacktrace/Line.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.rollbar.android.anr.historical.stacktrace; | ||
|
||
public final class Line { | ||
public int lineno; | ||
public String text; | ||
|
||
public Line(final int lineno, final String text) { | ||
this.lineno = lineno; | ||
this.text = text; | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
rollbar-android/src/main/java/com/rollbar/android/anr/historical/stacktrace/Lines.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package com.rollbar.android.anr.historical.stacktrace; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.File; | ||
import java.io.FileReader; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
|
||
public final class Lines { | ||
private final ArrayList<? extends Line> mList; | ||
private final int mMin; | ||
private final int mMax; | ||
|
||
/** The read position inside the list. */ | ||
public int pos; | ||
|
||
/** Read the whole file into a Lines object. */ | ||
public static Lines readLines(final File file) throws IOException { | ||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) { | ||
return Lines.readLines(reader); | ||
} | ||
} | ||
|
||
/** Read the whole file into a Lines object. */ | ||
public static Lines readLines(final BufferedReader in) throws IOException { | ||
final ArrayList<Line> list = new ArrayList<>(); | ||
|
||
int lineno = 0; | ||
String text; | ||
while ((text = in.readLine()) != null) { | ||
lineno++; | ||
list.add(new Line(lineno, text)); | ||
} | ||
|
||
return new Lines(list); | ||
} | ||
|
||
/** Construct with a list of lines. */ | ||
public Lines(final ArrayList<Line> list) { | ||
this.mList = list; | ||
mMin = 0; | ||
mMax = mList.size(); | ||
} | ||
|
||
/** If there are more lines to read within the current range. */ | ||
public boolean hasNext() { | ||
return pos < mMax; | ||
} | ||
|
||
/** | ||
* Return the next line, or null if there are no more lines to read. Also returns null in the | ||
* error condition where pos is before the beginning. | ||
*/ | ||
public Line next() { | ||
if (pos >= mMin && pos < mMax) { | ||
return this.mList.get(pos++); | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
/** Move the read position back by one line. */ | ||
public void rewind() { | ||
pos--; | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like something that should be read-only and hidden?