Skip to content

Commit fa1090c

Browse files
Version 3.7.1 (#136)
* Native client compilation issues in older .NET platforms (#134) * Android compilation issues * Add missing namespace * Apply default when value is below limit (#133) * Apply default when value is below limit * use defaults and different cast for backtracedatabasesettings * Backtrace-cocoa - purge invalid report on game startup * Improvement/prevent duplicated anrs (#135) * Safe way to serialize Backtrace response * Configurable ANR watchdog timeout * Formatting + logger changes * Code review suggestions * Version update * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: Vincent Lussenburg <vlussenburg@users.noreply.github.com>
1 parent 024b99e commit fa1090c

13 files changed

+93
-53
lines changed

Android/BacktraceANRWatchdog.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ public class BacktraceANRWatchdog extends Thread {
2121

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

24-
/**
25-
* Default timeout value in milliseconds
26-
*/
27-
private final static transient int DEFAULT_ANR_TIMEOUT = 5000;
28-
2924

3025
/**
3126
* Enable debug mode - errors will not be sent if the debugger is connected
@@ -62,11 +57,11 @@ public class BacktraceANRWatchdog extends Thread {
6257
/**
6358
* Initialize new instance of BacktraceANRWatchdog with default timeout
6459
*/
65-
public BacktraceANRWatchdog(String gameObjectName, String methodName) {
60+
public BacktraceANRWatchdog(String gameObjectName, String methodName, int anrTimeout) {
6661
Log.d(LOG_TAG, "Initializing ANR watchdog");
6762
this.methodName = methodName;
6863
this.gameObjectName = gameObjectName;
69-
this.timeout = DEFAULT_ANR_TIMEOUT;
64+
this.timeout = anrTimeout;
7065
this.debug = false;
7166
BacktraceANRWatchdog._instance = this;
7267
this.start();
@@ -77,9 +72,10 @@ public BacktraceANRWatchdog(String gameObjectName, String methodName) {
7772
*/
7873
@Override
7974
public void run() {
75+
Boolean reported = false;
76+
Log.d(LOG_TAG, "Starting ANR watchdog. Anr timeout: " + this.timeout);
8077
while (!shouldStop && !isInterrupted()) {
8178
String dateTimeNow = Calendar.getInstance().getTime().toString();
82-
Log.d(LOG_TAG, "ANR WATCHDOG - " + dateTimeNow);
8379
final backtrace.io.backtrace_unity_android_plugin.BacktraceThreadWatcher threadWatcher = new backtrace.io.backtrace_unity_android_plugin.BacktraceThreadWatcher(0, 0);
8480
mainThreadHandler.post(new Runnable() {
8581
@Override
@@ -96,7 +92,7 @@ public void run() {
9692
threadWatcher.tickPrivateCounter();
9793

9894
if (threadWatcher.getCounter() == threadWatcher.getPrivateCounter()) {
99-
Log.d(LOG_TAG, "ANR is not detected");
95+
reported = false;
10096
continue;
10197
}
10298

@@ -105,6 +101,12 @@ public void run() {
105101
"is on and connected debugger");
106102
continue;
107103
}
104+
if (reported) {
105+
// skipping, because we already reported an ANR report for current ANR
106+
continue;
107+
}
108+
reported = true;
109+
Log.d(LOG_TAG, "Detected blocked Java thread. Reporting Java ANR.");
108110
NotifyUnityAboutANR();
109111
}
110112
}
@@ -129,5 +131,6 @@ public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter p
129131
public void stopMonitoring() {
130132
Log.d(LOG_TAG, "ANR handler has been disabled.");
131133
shouldStop = true;
134+
BacktraceANRWatchdog._instance = null;
132135
}
133136
}

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Backtrace Unity Release Notes
22

3+
## Version 3.7.1
4+
5+
New functionality
6+
7+
- Where not allowed, negative number values in the Backtrace Configuration Asset will automatically be reset to the default value.
8+
9+
Bugfixes
10+
11+
- Fixed redundant ANR detection
12+
- 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.
13+
- Add iOS cleanup for invalid cached reports
14+
- Backward compatibility support for .NET 3.5
15+
316
## Version 3.7.0
417

518
- When an ANR/Hang is detected, it is now added to the Breadcrumbs on all the platforms we support ANRs for

Editor/BacktraceConfigurationEditor.cs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ public override void OnInspectorGUI()
3232
serializedObject.FindProperty("HandleUnhandledExceptions"),
3333
new GUIContent(BacktraceConfigurationLabels.LABEL_HANDLE_UNHANDLED_EXCEPTION));
3434

35-
EditorGUILayout.PropertyField(
36-
serializedObject.FindProperty("ReportPerMin"),
37-
new GUIContent(BacktraceConfigurationLabels.LABEL_REPORT_PER_MIN));
35+
DrawIntegerTextboxWithDefault("ReportPerMin", BacktraceConfigurationLabels.LABEL_REPORT_PER_MIN, 0, BacktraceConfiguration.DefaultReportPerMin, serializedObject);
3836

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

6462
DrawMultiselectDropdown("ReportFilterType", reportFilterType, BacktraceConfigurationLabels.LABEL_REPORT_FILTER, serializedObject);
65-
66-
EditorGUILayout.PropertyField(
67-
serializedObject.FindProperty("NumberOfLogs"),
68-
new GUIContent(BacktraceConfigurationLabels.LABEL_NUMBER_OF_LOGS));
63+
DrawIntegerTextboxWithDefault("NumberOfLogs", BacktraceConfigurationLabels.LABEL_NUMBER_OF_LOGS, 0, BacktraceConfiguration.DefaultNumberOfLogs, serializedObject);
6964

7065
EditorGUILayout.PropertyField(
7166
serializedObject.FindProperty("PerformanceStatistics"),
@@ -79,16 +74,11 @@ public override void OnInspectorGUI()
7974
serializedObject.FindProperty("Sampling"),
8075
new GUIContent(BacktraceConfigurationLabels.LABEL_SAMPLING));
8176

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

85-
if (gameObjectDepth.intValue < -1)
86-
{
87-
EditorGUILayout.HelpBox("Please insert value greater or equal -1", MessageType.Error);
88-
}
8979
EditorGUILayout.PropertyField(
90-
serializedObject.FindProperty("DisableInEditor"),
91-
new GUIContent(BacktraceConfigurationLabels.DISABLE_IN_EDITOR));
80+
serializedObject.FindProperty("DisableInEditor"),
81+
new GUIContent(BacktraceConfigurationLabels.DISABLE_IN_EDITOR));
9282
}
9383

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

216-
SerializedProperty maxRecordCount = serializedObject.FindProperty("MaxRecordCount");
217-
EditorGUILayout.PropertyField(maxRecordCount, new GUIContent(BacktraceConfigurationLabels.LABEL_MAX_REPORT_COUNT));
218-
219-
SerializedProperty maxDatabaseSize = serializedObject.FindProperty("MaxDatabaseSize");
220-
EditorGUILayout.PropertyField(maxDatabaseSize, new GUIContent(BacktraceConfigurationLabels.LABEL_MAX_DATABASE_SIZE));
221-
222-
SerializedProperty retryInterval = serializedObject.FindProperty("RetryInterval");
223-
EditorGUILayout.PropertyField(retryInterval, new GUIContent(BacktraceConfigurationLabels.LABEL_RETRY_INTERVAL));
206+
DrawIntegerTextboxWithDefault("MaxRecordCount", BacktraceConfigurationLabels.LABEL_MAX_REPORT_COUNT, 1, BacktraceConfiguration.DefaultMaxRecordCount, serializedObject);
207+
DrawIntegerTextboxWithDefault("MaxDatabaseSize", BacktraceConfigurationLabels.LABEL_MAX_DATABASE_SIZE, 0, BacktraceConfiguration.DefaultMaxDatabaseSize, serializedObject);
208+
DrawIntegerTextboxWithDefault("RetryInterval", BacktraceConfigurationLabels.LABEL_RETRY_INTERVAL, 1, BacktraceConfiguration.DefaultRetryInterval, serializedObject);
224209

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

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

221+
222+
/// <summary>
223+
/// Draw the textbox control dedicated to unsigned integers and apply default if user passes negative value
224+
/// </summary>
225+
/// <param name="propertyName">Backtrace configuration property name</param>
226+
/// <param name="label">Property label</param>
227+
/// <param name="defaultValue">Default value</param>
228+
/// <param name="serializedObject">Configuration object</param>
229+
private static void DrawIntegerTextboxWithDefault(string propertyName, string label, int minimumValue, int defaultValue, SerializedObject serializedObject)
230+
{
231+
var property = serializedObject.FindProperty(propertyName);
232+
EditorGUILayout.PropertyField(property, new GUIContent(label));
233+
if (property.intValue < minimumValue)
234+
{
235+
property.intValue = defaultValue;
236+
}
237+
}
238+
237239
/// <summary>
238240
/// Draw multiselect dropdown. By default PropertyField won't work correctly in Unity 2017/2018
239241
/// if editor has to display multiselect dropdown by using enum flags. This code allows to generate

Editor/BacktraceDatabaseConfigurationEditor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public override void OnInspectorGUI()
2323
#if UNITY_STANDALONE_WIN
2424
settings.MinidumpType = (MiniDumpType)EditorGUILayout.EnumFlagsField(BacktraceConfigurationLabels.LABEL_MINIDUMP_SUPPORT, settings.MinidumpType);
2525
#else
26-
settings.MinidumpType = MiniDumpType.None;
26+
settings.MinidumpType = MiniDumpType.None;
2727

2828
#endif
2929

@@ -37,12 +37,12 @@ public override void OnInspectorGUI()
3737
settings.MaxRecordCount = EditorGUILayout.IntField(BacktraceConfigurationLabels.LABEL_MAX_REPORT_COUNT, settings.MaxRecordCount);
3838
if (settings.MaxRecordCount < 0)
3939
{
40-
settings.MaxRecordCount = 0;
40+
settings.MaxRecordCount = BacktraceConfiguration.DefaultMaxRecordCount;
4141
}
4242
settings.MaxDatabaseSize = EditorGUILayout.LongField(BacktraceConfigurationLabels.LABEL_MAX_DATABASE_SIZE, settings.MaxDatabaseSize);
4343
if (settings.MaxDatabaseSize < 0)
4444
{
45-
settings.MaxDatabaseSize = 0;
45+
settings.MaxDatabaseSize = BacktraceConfiguration.DefaultMaxDatabaseSize;
4646
}
4747

4848

@@ -51,7 +51,7 @@ public override void OnInspectorGUI()
5151
settings.RetryLimit = EditorGUILayout.IntField(BacktraceConfigurationLabels.LABEL_RETRY_LIMIT, settings.RetryLimit);
5252
if (settings.RetryLimit < 0)
5353
{
54-
settings.RetryLimit = 1;
54+
settings.RetryLimit = BacktraceConfiguration.DefaultRetryLimit;
5555
}
5656
settings.RetryOrder = (RetryOrder)EditorGUILayout.EnumPopup(BacktraceConfigurationLabels.LABEL_RETRY_ORDER, settings.RetryOrder);
5757
}

Runtime/BacktraceClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace Backtrace.Unity
2424
/// </summary>
2525
public class BacktraceClient : MonoBehaviour, IBacktraceClient
2626
{
27-
public const string VERSION = "3.7.0";
27+
public const string VERSION = "3.7.1";
2828
internal const string DefaultBacktraceGameObjectName = "BacktraceClient";
2929
public BacktraceConfiguration Configuration;
3030

Runtime/Model/BacktraceConfiguration.cs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ public class BacktraceConfiguration : ScriptableObject
2828
UnityEngineLogLevel.Info |
2929
UnityEngineLogLevel.Warning;
3030

31+
public const int DefaultAnrWatchdogTimeout = 5000;
32+
public const int DefaultRetryLimit = 3;
33+
public const int DefaultReportPerMin = 50;
34+
public const int DefaultGameObjectDepth = -1;
35+
public const int DefaultNumberOfLogs = 10;
36+
public const int DefaultMaxRecordCount = 8;
37+
public const int DefaultMaxDatabaseSize = 0;
38+
public const int DefaultRetryInterval = 60;
39+
3140
/// <summary>
3241
/// Backtrace server url
3342
/// </summary>
@@ -44,7 +53,7 @@ public class BacktraceConfiguration : ScriptableObject
4453
/// Maximum number reports per minute
4554
/// </summary>
4655
[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")]
47-
public int ReportPerMin = 50;
56+
public int ReportPerMin = DefaultReportPerMin;
4857

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

101110
/// <summary>
102111
/// Number of logs collected by Backtrace-Unity
103112
/// </summary>
104113
[Tooltip("Number of logs collected by Backtrace-Unity")]
105-
public uint NumberOfLogs = 10;
114+
public uint NumberOfLogs = DefaultNumberOfLogs;
106115

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

148+
/// <summary>
149+
/// Anr watchdog timeout in ms. Time needed to detect an ANR event
150+
/// </summary>
151+
public int AnrWatchdogTimeout = DefaultAnrWatchdogTimeout;
152+
139153
#if UNITY_ANDROID || UNITY_IOS
140154
/// <summary>
141155
/// Send Out of memory exceptions to Backtrace.
@@ -261,23 +275,23 @@ public class BacktraceConfiguration : ScriptableObject
261275
/// Maximum number of stored reports in Database. If value is equal to zero, then limit not exists
262276
/// </summary>
263277
[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.")]
264-
public int MaxRecordCount = 8;
278+
public int MaxRecordCount = DefaultMaxRecordCount;
265279

266280
/// <summary>
267281
/// Database size in MB
268282
/// </summary>
269283
[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.")]
270-
public long MaxDatabaseSize;
284+
public long MaxDatabaseSize = DefaultMaxDatabaseSize;
271285
/// <summary>
272286
/// How much seconds library should wait before next retry.
273287
/// </summary>
274288
[Tooltip("If the database is unable to send its record, this setting specifies how many seconds the library should wait between retries.")]
275-
public int RetryInterval = 60;
289+
public int RetryInterval = DefaultRetryInterval;
276290

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

282296
/// <summary>
283297
/// Retry order

Runtime/Model/Database/BacktraceDatabaseSettings.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace Backtrace.Unity.Model.Database
99
public class BacktraceDatabaseSettings
1010
{
1111
private readonly BacktraceConfiguration _configuration;
12+
private readonly uint _retryInterval;
1213
public BacktraceDatabaseSettings(string databasePath, BacktraceConfiguration configuration)
1314
{
1415
if (configuration == null || string.IsNullOrEmpty(databasePath))
@@ -18,6 +19,7 @@ public BacktraceDatabaseSettings(string databasePath, BacktraceConfiguration con
1819

1920
DatabasePath = databasePath;
2021
_configuration = configuration;
22+
_retryInterval = configuration.RetryInterval > 0 ? (uint)_configuration.RetryInterval : BacktraceConfiguration.DefaultRetryInterval;
2123
}
2224
/// <summary>
2325
/// Directory path where reports and minidumps are stored
@@ -68,7 +70,7 @@ public uint RetryInterval
6870
{
6971
get
7072
{
71-
return Convert.ToUInt32(_configuration.RetryInterval);
73+
return _retryInterval;
7274
}
7375
}
7476

Runtime/Native/Android/NativeClient.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,10 @@ private void SetDefaultAttributeMaps()
119119
private AndroidJavaObject _unhandledExceptionWatcher;
120120

121121
private readonly bool _enableClientSideUnwinding = false;
122-
public string GameObjectName { get; internal set; } = BacktraceClient.DefaultBacktraceGameObjectName;
122+
public string GameObjectName { get; internal set; }
123123
public NativeClient(BacktraceConfiguration configuration, BacktraceBreadcrumbs breadcrumbs, IDictionary<string, string> clientAttributes, IEnumerable<string> attachments) : base(configuration, breadcrumbs)
124124
{
125+
GameObjectName = BacktraceClient.DefaultBacktraceGameObjectName;
125126
SetDefaultAttributeMaps();
126127
if (!_enabled)
127128
{
@@ -382,7 +383,7 @@ public void HandleAnr()
382383
}
383384
try
384385
{
385-
_anrWatcher = new AndroidJavaObject(_anrPath, GameObjectName, CallbackMethodName);
386+
_anrWatcher = new AndroidJavaObject(_anrPath, GameObjectName, CallbackMethodName, AnrWatchdogTimeout);
386387
}
387388
catch (Exception e)
388389
{
@@ -440,7 +441,7 @@ public void HandleAnr()
440441
// we won't false positive ANR report
441442
lastUpdatedCache = 0;
442443
}
443-
Thread.Sleep(5000);
444+
Thread.Sleep(AnrWatchdogTimeout);
444445
}
445446
});
446447
AnrThread.IsBackground = true;

Runtime/Native/Base/NativeClientBase.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ internal abstract class NativeClientBase
1313
protected const string CrashType = "Crash";
1414
protected const string ErrorTypeAttribute = "error.type";
1515

16+
protected int AnrWatchdogTimeout;
1617
/// <summary>
1718
/// Determine if ANR occurred and NativeClient should report ANR in breadcrumbs
1819
/// </summary>
@@ -57,6 +58,9 @@ internal NativeClientBase(BacktraceConfiguration configuration, BacktraceBreadcr
5758
_configuration = configuration;
5859
_breadcrumbs = breadcrumbs;
5960
_shouldLogAnrsInBreadcrumbs = ShouldStoreAnrBreadcrumbs();
61+
AnrWatchdogTimeout = configuration.AnrWatchdogTimeout > 1000
62+
? configuration.AnrWatchdogTimeout
63+
: BacktraceConfiguration.DefaultAnrWatchdogTimeout;
6064
}
6165

6266
/// <summary>

Runtime/Native/Windows/NativeClient.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#if UNITY_STANDALONE_WIN
22
using Backtrace.Unity.Interfaces;
33
using Backtrace.Unity.Model;
4+
using Backtrace.Unity.Extensions;
45
using Backtrace.Unity.Model.Breadcrumbs;
56
using Backtrace.Unity.Model.Breadcrumbs.Storage;
67
using Backtrace.Unity.Runtime.Native.Base;
@@ -187,7 +188,7 @@ public void HandleAnr()
187188
// we won't false positive ANR report
188189
lastUpdatedCache = 0;
189190
}
190-
Thread.Sleep(5000);
191+
Thread.Sleep(AnrWatchdogTimeout);
191192
}
192193
});
193194
AnrThread.IsBackground = true;

0 commit comments

Comments
 (0)