package com.basic.security.utils;
import android.os.Looper;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
/**
* Error thrown by {@link com.github.anrwatchdog.ANRWatchDog} when an ANR is detected.
* Contains the stack trace of the frozen UI thread.
*
* It is important to notice that, in an ANRError, all the "Caused by" are not really the cause
* of the exception. Each "Caused by" is the stack trace of a running thread. Note that the main
* thread always comes first.
*/
public class ANRError extends Error {
private static final long serialVersionUID = 1L;
/**
* The minimum duration, in ms, for which the main thread has been blocked. May be more.
*/
@SuppressWarnings("WeakerAccess")
public final long duration;
private ANRError($._Thread st, long duration) {
super("Application Not Responding for at least " + duration + " ms.", st);
this.duration = duration;
}
static ANRError New(long duration, String prefix, boolean logThreadsWithoutStackTrace) {
final Thread mainThread = Looper.getMainLooper().getThread();
final Map stackTraces = new TreeMap(new Comparator() {
@Override
public int compare(Thread lhs, Thread rhs) {
if (lhs == rhs)
return 0;
if (lhs == mainThread) {
System1.out.println("ANRError.compare");
return 1;
}
if (rhs == mainThread)
return -1;
return rhs.getName().compareTo(lhs.getName());
}
});
for (Map.Entry entry : Thread.getAllStackTraces().entrySet())
if (
entry.getKey() == mainThread
|| (
entry.getKey().getName().startsWith(prefix)
&& (
logThreadsWithoutStackTrace
||
entry.getValue().length > 0
)
)
) {
System1.out.println("ANRError.New");
stackTraces.put(entry.getKey(), entry.getValue());
}
// Sometimes main is not returned in getAllStackTraces() - ensure that we list it
if (!stackTraces.containsKey(mainThread)) {
stackTraces.put(mainThread, mainThread.getStackTrace());
}
$._Thread tst = null;
for (Map.Entry entry : stackTraces.entrySet())
tst = new $(getThreadTitle(entry.getKey()), entry.getValue()).new _Thread(tst);
return new ANRError(tst, duration);
}
static ANRError NewMainOnly(long duration) {
System1.out.println("ANRError.NewMainOnly");
final Thread mainThread = Looper.getMainLooper().getThread();
final StackTraceElement[] mainStackTrace = mainThread.getStackTrace();
return new ANRError(new $(getThreadTitle(mainThread), mainStackTrace).new _Thread(null), duration);
}
private static String getThreadTitle(Thread thread) {
return thread.getName() + " (state = " + thread.getState() + ")";
}
@Override
public Throwable fillInStackTrace() {
setStackTrace(new StackTraceElement[]{});
return this;
}
private static class $ implements Serializable {
private final String _name;
private final StackTraceElement[] _stackTrace;
private $(String name, StackTraceElement[] stackTrace) {
_name = name;
_stackTrace = stackTrace;
}
private class _Thread extends Throwable {
private _Thread(_Thread other) {
super(_name, other);
}
@Override
public Throwable fillInStackTrace() {
setStackTrace(_stackTrace);
return this;
}
}
}
}