Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions Android/BacktraceANRWatchdog.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ public class BacktraceANRWatchdog extends Thread {

private final static transient String LOG_TAG = BacktraceANRWatchdog.class.getSimpleName();

/**
* Default timeout value in milliseconds
*/
private final static transient int DEFAULT_ANR_TIMEOUT = 5000;


/**
* Enable debug mode - errors will not be sent if the debugger is connected
Expand Down Expand Up @@ -62,11 +57,11 @@ public class BacktraceANRWatchdog extends Thread {
/**
* Initialize new instance of BacktraceANRWatchdog with default timeout
*/
public BacktraceANRWatchdog(String gameObjectName, String methodName) {
public BacktraceANRWatchdog(String gameObjectName, String methodName, int anrTimeout) {
Log.d(LOG_TAG, "Initializing ANR watchdog");
this.methodName = methodName;
this.gameObjectName = gameObjectName;
this.timeout = DEFAULT_ANR_TIMEOUT;
this.timeout = anrTimeout;
this.debug = false;
BacktraceANRWatchdog._instance = this;
this.start();
Expand All @@ -77,9 +72,10 @@ public BacktraceANRWatchdog(String gameObjectName, String methodName) {
*/
@Override
public void run() {
Boolean reported = false;
Log.d(LOG_TAG, "Starting ANR watchdog. Anr timeout: " + this.timeout);
while (!shouldStop && !isInterrupted()) {
String dateTimeNow = Calendar.getInstance().getTime().toString();
Log.d(LOG_TAG, "ANR WATCHDOG - " + dateTimeNow);
final backtrace.io.backtrace_unity_android_plugin.BacktraceThreadWatcher threadWatcher = new backtrace.io.backtrace_unity_android_plugin.BacktraceThreadWatcher(0, 0);
mainThreadHandler.post(new Runnable() {
@Override
Expand All @@ -96,7 +92,7 @@ public void run() {
threadWatcher.tickPrivateCounter();

if (threadWatcher.getCounter() == threadWatcher.getPrivateCounter()) {
Log.d(LOG_TAG, "ANR is not detected");
reported = false;
continue;
}

Expand All @@ -105,6 +101,12 @@ public void run() {
"is on and connected debugger");
continue;
}
if (reported) {
// skipping, because we already reported an ANR report for current ANR
continue;
}
reported = true;
Log.d(LOG_TAG, "Detected blocked Java thread. Reporting Java ANR.");
NotifyUnityAboutANR();
}
}
Expand All @@ -129,5 +131,6 @@ public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter p
public void stopMonitoring() {
Log.d(LOG_TAG, "ANR handler has been disabled.");
shouldStop = true;
BacktraceANRWatchdog._instance = null;
}
}
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Backtrace Unity Release Notes

## Version 3.7.1

New functionality

- Where not allowed, negative number values in the Backtrace Configuration Asset will automatically be reset to the default value.

Bugfixes

- Fixed redundant ANR detection
- Improved ANR configurability. Client settings not allow you to specify how many seconds of a delay constitutes an ANR. This value can be set dynamically based on the the exact devices, choosing higher values for older devices for example.
- Add iOS cleanup for invalid cached reports
- Backward compatibility support for .NET 3.5

## Version 3.7.0

- When an ANR/Hang is detected, it is now added to the Breadcrumbs on all the platforms we support ANRs for
Expand Down
52 changes: 27 additions & 25 deletions Editor/BacktraceConfigurationEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ public override void OnInspectorGUI()
serializedObject.FindProperty("HandleUnhandledExceptions"),
new GUIContent(BacktraceConfigurationLabels.LABEL_HANDLE_UNHANDLED_EXCEPTION));

EditorGUILayout.PropertyField(
serializedObject.FindProperty("ReportPerMin"),
new GUIContent(BacktraceConfigurationLabels.LABEL_REPORT_PER_MIN));
DrawIntegerTextboxWithDefault("ReportPerMin", BacktraceConfigurationLabels.LABEL_REPORT_PER_MIN, 0, BacktraceConfiguration.DefaultReportPerMin, serializedObject);

GUIStyle clientAdvancedSettingsFoldout = new GUIStyle(EditorStyles.foldout);
showClientAdvancedSettings = EditorGUILayout.Foldout(showClientAdvancedSettings, "Client advanced settings", clientAdvancedSettingsFoldout);
Expand Down Expand Up @@ -62,10 +60,7 @@ public override void OnInspectorGUI()
}

DrawMultiselectDropdown("ReportFilterType", reportFilterType, BacktraceConfigurationLabels.LABEL_REPORT_FILTER, serializedObject);

EditorGUILayout.PropertyField(
serializedObject.FindProperty("NumberOfLogs"),
new GUIContent(BacktraceConfigurationLabels.LABEL_NUMBER_OF_LOGS));
DrawIntegerTextboxWithDefault("NumberOfLogs", BacktraceConfigurationLabels.LABEL_NUMBER_OF_LOGS, 0, BacktraceConfiguration.DefaultNumberOfLogs, serializedObject);

EditorGUILayout.PropertyField(
serializedObject.FindProperty("PerformanceStatistics"),
Expand All @@ -79,16 +74,11 @@ public override void OnInspectorGUI()
serializedObject.FindProperty("Sampling"),
new GUIContent(BacktraceConfigurationLabels.LABEL_SAMPLING));

SerializedProperty gameObjectDepth = serializedObject.FindProperty("GameObjectDepth");
EditorGUILayout.PropertyField(gameObjectDepth, new GUIContent(BacktraceConfigurationLabels.LABEL_GAME_OBJECT_DEPTH));
DrawIntegerTextboxWithDefault("GameObjectDepth", BacktraceConfigurationLabels.LABEL_GAME_OBJECT_DEPTH, -1, BacktraceConfiguration.DefaultGameObjectDepth, serializedObject);

if (gameObjectDepth.intValue < -1)
{
EditorGUILayout.HelpBox("Please insert value greater or equal -1", MessageType.Error);
}
EditorGUILayout.PropertyField(
serializedObject.FindProperty("DisableInEditor"),
new GUIContent(BacktraceConfigurationLabels.DISABLE_IN_EDITOR));
serializedObject.FindProperty("DisableInEditor"),
new GUIContent(BacktraceConfigurationLabels.DISABLE_IN_EDITOR));
}

#if !UNITY_WEBGL
Expand Down Expand Up @@ -213,18 +203,12 @@ public override void OnInspectorGUI()
serializedObject.FindProperty("GenerateScreenshotOnException"),
new GUIContent(BacktraceConfigurationLabels.LABEL_GENERATE_SCREENSHOT_ON_EXCEPTION));

SerializedProperty maxRecordCount = serializedObject.FindProperty("MaxRecordCount");
EditorGUILayout.PropertyField(maxRecordCount, new GUIContent(BacktraceConfigurationLabels.LABEL_MAX_REPORT_COUNT));

SerializedProperty maxDatabaseSize = serializedObject.FindProperty("MaxDatabaseSize");
EditorGUILayout.PropertyField(maxDatabaseSize, new GUIContent(BacktraceConfigurationLabels.LABEL_MAX_DATABASE_SIZE));

SerializedProperty retryInterval = serializedObject.FindProperty("RetryInterval");
EditorGUILayout.PropertyField(retryInterval, new GUIContent(BacktraceConfigurationLabels.LABEL_RETRY_INTERVAL));
DrawIntegerTextboxWithDefault("MaxRecordCount", BacktraceConfigurationLabels.LABEL_MAX_REPORT_COUNT, 1, BacktraceConfiguration.DefaultMaxRecordCount, serializedObject);
DrawIntegerTextboxWithDefault("MaxDatabaseSize", BacktraceConfigurationLabels.LABEL_MAX_DATABASE_SIZE, 0, BacktraceConfiguration.DefaultMaxDatabaseSize, serializedObject);
DrawIntegerTextboxWithDefault("RetryInterval", BacktraceConfigurationLabels.LABEL_RETRY_INTERVAL, 1, BacktraceConfiguration.DefaultRetryInterval, serializedObject);

EditorGUILayout.LabelField("Backtrace database require at least one retry.");
SerializedProperty retryLimit = serializedObject.FindProperty("RetryLimit");
EditorGUILayout.PropertyField(retryLimit, new GUIContent(BacktraceConfigurationLabels.LABEL_RETRY_LIMIT));
DrawIntegerTextboxWithDefault("RetryLimit", BacktraceConfigurationLabels.LABEL_RETRY_LIMIT, 0, BacktraceConfiguration.DefaultRetryLimit, serializedObject);

SerializedProperty retryOrder = serializedObject.FindProperty("RetryOrder");
EditorGUILayout.PropertyField(retryOrder, new GUIContent(BacktraceConfigurationLabels.LABEL_RETRY_ORDER));
Expand All @@ -234,6 +218,24 @@ public override void OnInspectorGUI()
serializedObject.ApplyModifiedProperties();
}


/// <summary>
/// Draw the textbox control dedicated to unsigned integers and apply default if user passes negative value
/// </summary>
/// <param name="propertyName">Backtrace configuration property name</param>
/// <param name="label">Property label</param>
/// <param name="defaultValue">Default value</param>
/// <param name="serializedObject">Configuration object</param>
private static void DrawIntegerTextboxWithDefault(string propertyName, string label, int minimumValue, int defaultValue, SerializedObject serializedObject)
{
var property = serializedObject.FindProperty(propertyName);
EditorGUILayout.PropertyField(property, new GUIContent(label));
if (property.intValue < minimumValue)
{
property.intValue = defaultValue;
}
}

/// <summary>
/// Draw multiselect dropdown. By default PropertyField won't work correctly in Unity 2017/2018
/// if editor has to display multiselect dropdown by using enum flags. This code allows to generate
Expand Down
8 changes: 4 additions & 4 deletions Editor/BacktraceDatabaseConfigurationEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public override void OnInspectorGUI()
#if UNITY_STANDALONE_WIN
settings.MinidumpType = (MiniDumpType)EditorGUILayout.EnumFlagsField(BacktraceConfigurationLabels.LABEL_MINIDUMP_SUPPORT, settings.MinidumpType);
#else
settings.MinidumpType = MiniDumpType.None;
settings.MinidumpType = MiniDumpType.None;

#endif

Expand All @@ -37,12 +37,12 @@ public override void OnInspectorGUI()
settings.MaxRecordCount = EditorGUILayout.IntField(BacktraceConfigurationLabels.LABEL_MAX_REPORT_COUNT, settings.MaxRecordCount);
if (settings.MaxRecordCount < 0)
{
settings.MaxRecordCount = 0;
settings.MaxRecordCount = BacktraceConfiguration.DefaultMaxRecordCount;
}
settings.MaxDatabaseSize = EditorGUILayout.LongField(BacktraceConfigurationLabels.LABEL_MAX_DATABASE_SIZE, settings.MaxDatabaseSize);
if (settings.MaxDatabaseSize < 0)
{
settings.MaxDatabaseSize = 0;
settings.MaxDatabaseSize = BacktraceConfiguration.DefaultMaxDatabaseSize;
}


Expand All @@ -51,7 +51,7 @@ public override void OnInspectorGUI()
settings.RetryLimit = EditorGUILayout.IntField(BacktraceConfigurationLabels.LABEL_RETRY_LIMIT, settings.RetryLimit);
if (settings.RetryLimit < 0)
{
settings.RetryLimit = 1;
settings.RetryLimit = BacktraceConfiguration.DefaultRetryLimit;
}
settings.RetryOrder = (RetryOrder)EditorGUILayout.EnumPopup(BacktraceConfigurationLabels.LABEL_RETRY_ORDER, settings.RetryOrder);
}
Expand Down
2 changes: 1 addition & 1 deletion Runtime/BacktraceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace Backtrace.Unity
/// </summary>
public class BacktraceClient : MonoBehaviour, IBacktraceClient
{
public const string VERSION = "3.7.0";
public const string VERSION = "3.7.1";
internal const string DefaultBacktraceGameObjectName = "BacktraceClient";
public BacktraceConfiguration Configuration;

Expand Down
28 changes: 21 additions & 7 deletions Runtime/Model/BacktraceConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ public class BacktraceConfiguration : ScriptableObject
UnityEngineLogLevel.Info |
UnityEngineLogLevel.Warning;

public const int DefaultAnrWatchdogTimeout = 5000;
public const int DefaultRetryLimit = 3;
public const int DefaultReportPerMin = 50;
public const int DefaultGameObjectDepth = -1;
public const int DefaultNumberOfLogs = 10;
public const int DefaultMaxRecordCount = 8;
public const int DefaultMaxDatabaseSize = 0;
public const int DefaultRetryInterval = 60;

/// <summary>
/// Backtrace server url
/// </summary>
Expand All @@ -44,7 +53,7 @@ public class BacktraceConfiguration : ScriptableObject
/// Maximum number reports per minute
/// </summary>
[Tooltip("Reports per minute: Limits the number of reports the client will send per minutes. If set to 0, there is no limit. If set to a higher value and the value is reached, the client will not send any reports until the next minute. Default: 50")]
public int ReportPerMin = 50;
public int ReportPerMin = DefaultReportPerMin;

/// <summary>
/// "Disable error reporting integration in editor mode.
Expand Down Expand Up @@ -96,13 +105,13 @@ public class BacktraceConfiguration : ScriptableObject
/// Game object depth in Backtrace report
/// </summary>
[Tooltip("Allows developer to filter number of game object childrens in Backtrace report.")]
public int GameObjectDepth = -1;
public int GameObjectDepth = DefaultGameObjectDepth;

/// <summary>
/// Number of logs collected by Backtrace-Unity
/// </summary>
[Tooltip("Number of logs collected by Backtrace-Unity")]
public uint NumberOfLogs = 10;
public uint NumberOfLogs = DefaultNumberOfLogs;

/// <summary>
/// Flag that allows to include performance statistics in Backtrace report
Expand Down Expand Up @@ -136,6 +145,11 @@ public class BacktraceConfiguration : ScriptableObject
[Tooltip("Capture ANR events - Application not responding")]
public bool HandleANR = true;

/// <summary>
/// Anr watchdog timeout in ms. Time needed to detect an ANR event
/// </summary>
public int AnrWatchdogTimeout = DefaultAnrWatchdogTimeout;

#if UNITY_ANDROID || UNITY_IOS
/// <summary>
/// Send Out of memory exceptions to Backtrace.
Expand Down Expand Up @@ -261,23 +275,23 @@ public class BacktraceConfiguration : ScriptableObject
/// Maximum number of stored reports in Database. If value is equal to zero, then limit not exists
/// </summary>
[Tooltip("This is one of two limits you can impose for controlling the growth of the offline store. This setting is the maximum number of stored reports in database. If value is equal to zero, then limit not exists, When the limit is reached, the database will remove the oldest entries.")]
public int MaxRecordCount = 8;
public int MaxRecordCount = DefaultMaxRecordCount;

/// <summary>
/// Database size in MB
/// </summary>
[Tooltip("This is the second limit you can impose for controlling the growth of the offline store. This setting is the maximum database size in MB. If value is equal to zero, then size is unlimited, When the limit is reached, the database will remove the oldest entries.")]
public long MaxDatabaseSize;
public long MaxDatabaseSize = DefaultMaxDatabaseSize;
/// <summary>
/// How much seconds library should wait before next retry.
/// </summary>
[Tooltip("If the database is unable to send its record, this setting specifies how many seconds the library should wait between retries.")]
public int RetryInterval = 60;
public int RetryInterval = DefaultRetryInterval;

/// <summary>
/// Maximum number of retries
[Tooltip("If the database is unable to send its record, this setting specifies the maximum number of retries before the system gives up.")]
public int RetryLimit = 3;
public int RetryLimit = DefaultRetryLimit;

/// <summary>
/// Retry order
Expand Down
28 changes: 17 additions & 11 deletions Runtime/Model/BacktraceResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,26 @@ internal void AddInnerResult(BacktraceResult innerResult)

public static BacktraceResult FromJson(string json)
{
if (string.IsNullOrEmpty(json))
{
return new BacktraceResult()
{
Status = BacktraceResultStatus.Empty
};
}
var rawResult = JsonUtility.FromJson<BacktraceRawResult>(json);
var result = new BacktraceResult()
{
response = rawResult.response,
_rxId = rawResult._rxid,
Status = rawResult.response == "ok" ? BacktraceResultStatus.Ok : BacktraceResultStatus.ServerError
Status = string.IsNullOrEmpty(json) ? BacktraceResultStatus.Empty : BacktraceResultStatus.Ok
};

if (result.Status == BacktraceResultStatus.Empty)
{
return result;
}

try
{
var rawResult = JsonUtility.FromJson<BacktraceRawResult>(json);
result.response = rawResult.response;
result._rxId = rawResult._rxid;
}
catch (Exception e)
{
Debug.LogWarning(string.Format("Cannot parse Backtrace JSON response. Error: {0}. Content: {1}", json, e.Message));
}
return result;
}

Expand Down
4 changes: 3 additions & 1 deletion Runtime/Model/Database/BacktraceDatabaseSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Backtrace.Unity.Model.Database
public class BacktraceDatabaseSettings
{
private readonly BacktraceConfiguration _configuration;
private readonly uint _retryInterval;
public BacktraceDatabaseSettings(string databasePath, BacktraceConfiguration configuration)
{
if (configuration == null || string.IsNullOrEmpty(databasePath))
Expand All @@ -18,6 +19,7 @@ public BacktraceDatabaseSettings(string databasePath, BacktraceConfiguration con

DatabasePath = databasePath;
_configuration = configuration;
_retryInterval = configuration.RetryInterval > 0 ? (uint)_configuration.RetryInterval : BacktraceConfiguration.DefaultRetryInterval;
}
/// <summary>
/// Directory path where reports and minidumps are stored
Expand Down Expand Up @@ -68,7 +70,7 @@ public uint RetryInterval
{
get
{
return Convert.ToUInt32(_configuration.RetryInterval);
return _retryInterval;
}
}

Expand Down
7 changes: 4 additions & 3 deletions Runtime/Native/Android/NativeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,10 @@ private void SetDefaultAttributeMaps()
private AndroidJavaObject _unhandledExceptionWatcher;

private readonly bool _enableClientSideUnwinding = false;
public string GameObjectName { get; internal set; } = BacktraceClient.DefaultBacktraceGameObjectName;
public string GameObjectName { get; internal set; }
public NativeClient(BacktraceConfiguration configuration, BacktraceBreadcrumbs breadcrumbs, IDictionary<string, string> clientAttributes, IEnumerable<string> attachments) : base(configuration, breadcrumbs)
{
GameObjectName = BacktraceClient.DefaultBacktraceGameObjectName;
SetDefaultAttributeMaps();
if (!_enabled)
{
Expand Down Expand Up @@ -382,7 +383,7 @@ public void HandleAnr()
}
try
{
_anrWatcher = new AndroidJavaObject(_anrPath, GameObjectName, CallbackMethodName);
_anrWatcher = new AndroidJavaObject(_anrPath, GameObjectName, CallbackMethodName, AnrWatchdogTimeout);
}
catch (Exception e)
{
Expand Down Expand Up @@ -440,7 +441,7 @@ public void HandleAnr()
// we won't false positive ANR report
lastUpdatedCache = 0;
}
Thread.Sleep(5000);
Thread.Sleep(AnrWatchdogTimeout);
}
});
AnrThread.IsBackground = true;
Expand Down
Loading