Skip to content

Commit 4b8a959

Browse files
konraddysputvlussenburglysannepSarah Edkinssarahedkins
authored
Version 3.7.4 (#153)
* 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 * Avoid using unsupported property in not-native builds (#140) * Avoid using unsupported property in not-native builds * Filter out whole base client * Version update * Invalid background exception behavior (#139) * INvalid background exception behaviour * remove cast * Java background exception better variable names/comments * correcet variable name * Updates CHANGELOG for 3.7.2 * Do not test native client on not supported platforms * Invalid cast (#144) * prevent monitor disposing in the disable method (#143) * Use game object name instead of 'backtrace' * Version update + make sure backtrace-unity don't throw an exception when disk is full * Typo * Changelog * Add attributes to runtime xception * fix unable to delete reports when db path has trailing slash * Update README.md (#152) NDK16b support is now baked into the main. * Invalid crashpad handler behavior on x86 devices (#149) * Fixed crashpad handler for x86 * Different meta guid * Different crashpad path to x86/x64 directories * Disable native client on x86 devices on Windows * Disable on editor mode * Android memory usage improvements (#150) * Small nits that should speedup anr algorithm * Background exception handler * Forward crashes in the background exception handler, capture and store unhandled android Exceptions * ANR watchdog adjustements * Version Update * Apply suggestions from code review Change request changes Co-authored-by: Lysanne Pinto <lysannepinto@gmail.com> * Delay breadcrumbs integration initialization * Version 3.7.4 preview 1 * Unity dynamic attributes (#154) * Unity dynamic attributes * background attribute * Release improvements * Preview version update * Version 3.7.4 Co-authored-by: Vincent Lussenburg <vlussenburg@users.noreply.github.com> Co-authored-by: Lysanne Pinto <lysannepinto@gmail.com> Co-authored-by: Sarah Edkins <sedkins@backtrace.io> Co-authored-by: Sarah Edkins <sarahedkins@users.noreply.github.com> Co-authored-by: jasoncdavis0 <jdavis@backtrace.io>
1 parent 18f4114 commit 4b8a959

18 files changed

+148
-71
lines changed

Android/BacktraceANRWatchdog.java

+6-16
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,8 @@
1717
*/
1818
public class BacktraceANRWatchdog extends Thread {
1919

20-
private static BacktraceANRWatchdog _instance;
21-
2220
private final static transient String LOG_TAG = BacktraceANRWatchdog.class.getSimpleName();
2321

24-
25-
/**
26-
* Enable debug mode - errors will not be sent if the debugger is connected
27-
*/
28-
private final boolean debug;
2922
/**
3023
* Handler for UI Thread - used to check if the thread is not blocked
3124
*/
@@ -62,8 +55,6 @@ public BacktraceANRWatchdog(String gameObjectName, String methodName, int anrTim
6255
this.methodName = methodName;
6356
this.gameObjectName = gameObjectName;
6457
this.timeout = anrTimeout;
65-
this.debug = false;
66-
BacktraceANRWatchdog._instance = this;
6758
this.start();
6859
}
6960

@@ -72,10 +63,15 @@ public BacktraceANRWatchdog(String gameObjectName, String methodName, int anrTim
7263
*/
7364
@Override
7465
public void run() {
66+
if (Debug.isDebuggerConnected() || Debug.waitingForDebugger()) {
67+
Log.d(LOG_TAG, "Detected a debugger connection. ANR Watchdog is disabled");
68+
return;
69+
}
70+
7571
Boolean reported = false;
7672
Log.d(LOG_TAG, "Starting ANR watchdog. Anr timeout: " + this.timeout);
73+
7774
while (!shouldStop && !isInterrupted()) {
78-
String dateTimeNow = Calendar.getInstance().getTime().toString();
7975
final backtrace.io.backtrace_unity_android_plugin.BacktraceThreadWatcher threadWatcher = new backtrace.io.backtrace_unity_android_plugin.BacktraceThreadWatcher(0, 0);
8076
mainThreadHandler.post(new Runnable() {
8177
@Override
@@ -96,11 +92,6 @@ public void run() {
9692
continue;
9793
}
9894

99-
if (debug && (Debug.isDebuggerConnected() || Debug.waitingForDebugger())) {
100-
Log.d(LOG_TAG, "ANR detected but will be ignored because debug mode " +
101-
"is on and connected debugger");
102-
continue;
103-
}
10495
if (reported) {
10596
// skipping, because we already reported an ANR report for current ANR
10697
continue;
@@ -131,6 +122,5 @@ public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter p
131122
public void stopMonitoring() {
132123
Log.d(LOG_TAG, "ANR handler has been disabled.");
133124
shouldStop = true;
134-
BacktraceANRWatchdog._instance = null;
135125
}
136126
}

Android/BacktraceAndroidBackgroundUnhandledExceptionHandler.java

+19-11
Original file line numberDiff line numberDiff line change
@@ -29,34 +29,38 @@ public class BacktraceAndroidBackgroundUnhandledExceptionHandler implements Thre
2929
private volatile boolean shouldStop = false;
3030

3131
private final String _gameObject;
32-
private final String _methodName;
32+
private final String _methodName;
3333

3434
public BacktraceAndroidBackgroundUnhandledExceptionHandler(String gameObject, String methodName) {
3535
Log.d(LOG_TAG, "Initializing Android unhandled exception handler");
3636
this._gameObject = gameObject;
3737
this._methodName = methodName;
38-
3938
mRootHandler = Thread.getDefaultUncaughtExceptionHandler();
4039
Thread.setDefaultUncaughtExceptionHandler(this);
4140
}
4241

4342
@Override
4443
public void uncaughtException(final Thread thread, final Throwable throwable) {
45-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE && mRootHandler != null && shouldStop == false) {
46-
if(Looper.getMainLooper().getThread().getId() == thread.getId()) {
47-
// prevent from sending exception happened to main thread - we will catch them via unity logger
48-
return;
49-
}
44+
_lastCaughtBackgroundExceptionThread = thread;
45+
_lastCaughtBackgroundException = throwable;
46+
if (shouldStop == true) {
47+
Log.d(LOG_TAG, "Background exception handler is disabled.");
48+
finish();
49+
return;
50+
}
51+
if (throwable instanceof Exception) {
5052
String throwableType = throwable.getClass().getName();
5153
Log.d(LOG_TAG, "Detected unhandled background thread exception. Exception type: " + throwableType + ". Reporting to Backtrace");
52-
_lastCaughtBackgroundExceptionThread = thread;
53-
_lastCaughtBackgroundException = throwable;
5454
ReportThreadException(throwableType + " : " + throwable.getMessage(), stackTraceToString(throwable.getStackTrace()));
55+
} else {
56+
Log.d(LOG_TAG, "Detected android crash. Using native crash reporter to report an error.");
57+
finish();
5558
}
5659
}
5760

5861
public void ReportThreadException(String message, String stackTrace) {
5962
UnityPlayer.UnitySendMessage(this._gameObject, this._methodName, message + '\n' + stackTrace);
63+
Log.d(LOG_TAG, "UnitySendMessageFinished. passing an exception object. Game object: " + this._gameObject + " method name: " + this._methodName);
6064
}
6165

6266
private static String stackTraceToString(StackTraceElement[] stackTrace) {
@@ -73,13 +77,17 @@ private static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter
7377

7478
public void finish() {
7579
if (_lastCaughtBackgroundExceptionThread == null || _lastCaughtBackgroundException == null) {
76-
Log.d(LOG_TAG, "pass unhandled exception to the thread root handler, because exception thread/background thread doesn't exist");
80+
Log.d(LOG_TAG, "The exception object or the exception thread is not available. This is probably a bug.");
81+
return;
82+
}
83+
if (shouldStop) {
84+
Log.d(LOG_TAG, "Backtrace client has been disposed. The report won't be available.");
7785
return;
7886
}
79-
Log.d(LOG_TAG, "The unhandled exception has been stored in the database.");
8087
mRootHandler.uncaughtException(_lastCaughtBackgroundExceptionThread, _lastCaughtBackgroundException);
8188
}
8289

90+
8391
public void stopMonitoring() {
8492
Log.d(LOG_TAG, "Uncaught exception handler has been disabled.");
8593
shouldStop = true;

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Backtrace Unity Release Notes
22

3+
## Version 3.7.4
4+
5+
Bugfixes
6+
- Updates native libraries for Windows.
7+
- Removes native support for x86 games on Windows.
8+
- Improves the background thread exception handler on Android, which allows you to capture managed crashes and forward exception information to other exceptions handlers.
9+
- Handles database paths in the configuration file that end with trailing slashes (“/”).
10+
- Disables the dialog used to upload symbols for Android when Unity is running in batch mode.
11+
- Fixes a problem with nullable breadcrumbs when initializing the Backtrace client.
12+
313
## Version 3.7.3
414

515
Bugfixes

Editor/Native/Android/SymbolsUpload.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public void OnPostprocessBuild(BuildReport report)
5959

6060
Debug.Log("Backtrace symbols upload. Detected Backtrace configuration with enabled symbols upload option.");
6161
Debug.Log(string.Format("Configuration path {0}", path));
62-
if (!EditorUtility.DisplayDialog("Backtrace symbols upload",
62+
if (!Application.isBatchMode && !EditorUtility.DisplayDialog("Backtrace symbols upload",
6363
"Would you like to upload generated symbols files for better debugging experience?",
6464
"Yes", "Skip"))
6565
{

README.md

-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
[Backtrace](http://backtrace.io/)'s integration with Unity allows developers to capture and report log errors, handled and unhandled Unity exceptions, and native crashes to their Backtrace instance, instantly offering the ability to prioritize and debug software errors.
44

5-
**Note**: For developers creating Android games on **Unity 2018.4 (NDK16b)** and requiring support for **native events on Android (crashes, ANR, low memory)** Backtrace **requires** you use the [3.6.0-ndk16b](https://github.com/backtrace-labs/backtrace-unity/tree/3.6.0-ndk16b) version.
6-
75
Create your Backtrace instance at https://register.backtrace.io/#/ today and then integrate this library into your game.
86

97
[![openupm](https://img.shields.io/npm/v/io.backtrace.unity?label=openupm&registry_uri=https://package.openupm.com)](https://openupm.com/packages/io.backtrace.unity/)

Runtime/BacktraceClient.cs

+2-2
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.3";
27+
public const string VERSION = "3.7.4";
2828
internal const string DefaultBacktraceGameObjectName = "BacktraceClient";
2929
public BacktraceConfiguration Configuration;
3030

@@ -536,8 +536,8 @@ public void Refresh()
536536
Database = GetComponent<BacktraceDatabase>();
537537
if (Database != null)
538538
{
539-
_breadcrumbs = (BacktraceBreadcrumbs)Database.Breadcrumbs;
540539
Database.Reload();
540+
_breadcrumbs = (BacktraceBreadcrumbs)Database.Breadcrumbs;
541541
Database.SetApi(BacktraceApi);
542542
Database.SetReportWatcher(_reportLimitWatcher);
543543
if (_breadcrumbs != null)

Runtime/Common/ClientPathHelper.cs

+11
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,16 @@ private static string GenerateFullPath(this string path)
6969
}
7070

7171
}
72+
73+
internal static bool IsFileInDatabaseDirectory(string databasePath, string filePath)
74+
{
75+
// If databasePath does not have a trailing slash, it is already a directory.
76+
if (!databasePath.EndsWith("/"))
77+
{
78+
return new DirectoryInfo(databasePath).FullName == new DirectoryInfo(Path.GetDirectoryName(filePath)).FullName;
79+
}
80+
// Handles case when users put a trailing slash in their database path
81+
return Path.GetDirectoryName(databasePath) == Path.GetDirectoryName(filePath);
82+
}
7283
}
7384
}

Runtime/Model/Attributes/ProcessAttributeProvider.cs

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ public void GetAttributes(IDictionary<string, string> attributes)
2222
attributes["system.memory.temp"] = Profiler.GetTempAllocatorSize().ToString(CultureInfo.InvariantCulture);
2323
attributes["mono.heap"] = Profiler.GetMonoHeapSizeLong().ToString(CultureInfo.InvariantCulture);
2424
attributes["mono.used"] = Profiler.GetMonoUsedSizeLong().ToString(CultureInfo.InvariantCulture);
25+
attributes["application.playing"] = Application.isPlaying.ToString(CultureInfo.InvariantCulture);
26+
attributes["application.focused"] = Application.isFocused.ToString(CultureInfo.InvariantCulture);
27+
attributes["application.background"] = Application.runInBackground.ToString(CultureInfo.InvariantCulture);
28+
attributes["application.internet_reachability"] = Application.internetReachability.ToString();
2529

2630
}
2731
}

Runtime/Model/Attributes/RuntimeAttributeProvider.cs

+2-6
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,8 @@ public void GetAttributes(IDictionary<string, string> attributes)
2323
attributes["application.data_path"] = Application.dataPath;
2424
attributes["application.id"] = Application.identifier;
2525
attributes["application.installer.name"] = Application.installerName;
26-
attributes["application.internet_reachability"] = Application.internetReachability.ToString();
27-
attributes["application.editor"] = Application.isEditor.ToString(CultureInfo.InvariantCulture);
28-
attributes["application.focused"] = Application.isFocused.ToString(CultureInfo.InvariantCulture);
29-
attributes["application.mobile"] = Application.isMobilePlatform.ToString(CultureInfo.InvariantCulture);
30-
attributes["application.playing"] = Application.isPlaying.ToString(CultureInfo.InvariantCulture);
31-
attributes["application.background"] = Application.runInBackground.ToString(CultureInfo.InvariantCulture);
26+
attributes["application.editor"] = Application.isEditor.ToString(CultureInfo.InvariantCulture);
27+
attributes["application.mobile"] = Application.isMobilePlatform.ToString(CultureInfo.InvariantCulture);
3228
attributes["application.sandboxType"] = Application.sandboxType.ToString();
3329
attributes["application.system.language"] = Application.systemLanguage.ToString();
3430
attributes["application.unity.version"] = Application.unityVersion;

Runtime/Model/Breadcrumbs/Storage/BacktraceStorageLogManager.cs

+10
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ public BacktraceStorageLogManager(string storagePath)
104104
/// <returns>true if breadcrumbs file was created. Otherwise false.</returns>
105105
public bool Enable()
106106
{
107+
if (currentSize != 0)
108+
{
109+
return true;
110+
}
107111
try
108112
{
109113
if (BreadcrumbFile.Exists())
@@ -116,6 +120,7 @@ public bool Enable()
116120
_breadcrumbStream.Write(StartOfDocument, 0, StartOfDocument.Length);
117121
_breadcrumbStream.Write(EndOfDocument, 0, EndOfDocument.Length);
118122
}
123+
_emptyFile = true;
119124
currentSize = StartOfDocument.Length + EndOfDocument.Length;
120125
}
121126
catch (Exception e)
@@ -136,6 +141,11 @@ public bool Enable()
136141
/// <returns>True if breadcrumb was stored in the breadcrumbs file. Otherwise false.</returns>
137142
public bool Add(string message, BreadcrumbLevel level, UnityEngineLogLevel type, IDictionary<string, string> attributes)
138143
{
144+
// file is not initialized
145+
if (currentSize == 0)
146+
{
147+
return false;
148+
}
139149
byte[] bytes;
140150
lock (_lockObject)
141151
{

Runtime/Native/Android/NativeClient.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,9 @@ public void HandleAnr()
431431

432432
NativeReport(AndroidJNI.NewStringUTF(AnrMessage), true);
433433
// update error.type attribute in case when crash happen
434-
SetAttribute(ErrorTypeAttribute, CrashType);
434+
AddAttribute(
435+
AndroidJNI.NewStringUTF(ErrorTypeAttribute),
436+
AndroidJNI.NewStringUTF(CrashType));
435437
}
436438
}
437439
}
@@ -495,8 +497,8 @@ public override void Disable()
495497
{
496498
if (CaptureNativeCrashes)
497499
{
498-
CaptureNativeCrashes = false;
499-
DisableNativeIntegration();
500+
CaptureNativeCrashes = false;
501+
DisableNativeIntegration();
500502
}
501503
if (_anrWatcher != null)
502504
{

Runtime/Native/NativeClientFactory.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ internal static class NativeClientFactory
88
{
99
internal static INativeClient CreateNativeClient(BacktraceConfiguration configuration, string gameObjectName, BacktraceBreadcrumbs breadcrumbs, IDictionary<string, string> attributes, ICollection<string> attachments)
1010
{
11-
#if UNITY_STANDALONE_WIN
11+
#if UNITY_EDITOR
12+
return null;
13+
#elif UNITY_STANDALONE_WIN
1214
return new Windows.NativeClient(configuration, breadcrumbs, attributes, attachments);
1315
#elif UNITY_ANDROID
1416
return new Android.NativeClient(configuration, breadcrumbs, attributes, attachments, gameObjectName);

Runtime/Native/Windows/NativeClient.cs

+40-15
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,35 @@ private void HandleNativeCrashes(IDictionary<string, string> clientAttributes, I
8181
{
8282
return;
8383
}
84-
var databasePath = _configuration.CrashpadDatabasePath;
85-
if (string.IsNullOrEmpty(databasePath) || !Directory.Exists(_configuration.GetFullDatabasePath()))
84+
85+
86+
var pluginDirectoryPath = GetPluginDirectoryPath();
87+
if (!Directory.Exists(pluginDirectoryPath))
88+
{
89+
Debug.LogWarning("Backtrace native lib directory doesn't exist");
90+
return;
91+
}
92+
// prevent from initialization in the x86 devices
93+
const int intPtrSizeOnx86 = 4;
94+
if (Isx86Build(pluginDirectoryPath) || IntPtr.Size == intPtrSizeOnx86)
8695
{
87-
Debug.LogWarning("Backtrace native integration status: database path doesn't exist");
8896
return;
8997
}
9098

91-
var crashpadHandlerPath = GetDefaultPathToCrashpadHandler();
92-
if (!File.Exists(crashpadHandlerPath))
99+
var crashpadHandlerPath = GetDefaultPathToCrashpadHandler(pluginDirectoryPath);
100+
if (string.IsNullOrEmpty(crashpadHandlerPath) || !File.Exists(crashpadHandlerPath))
93101
{
94102
Debug.LogWarning("Backtrace native integration status: Cannot find path to Crashpad handler.");
95103
return;
96104
}
97105

106+
var databasePath = _configuration.CrashpadDatabasePath;
107+
if (string.IsNullOrEmpty(databasePath) || !Directory.Exists(_configuration.GetFullDatabasePath()))
108+
{
109+
Debug.LogWarning("Backtrace native integration status: database path doesn't exist");
110+
return;
111+
}
112+
98113
var minidumpUrl = new BacktraceCredentials(_configuration.GetValidServerUrl()).GetMinidumpSubmissionUrl().ToString();
99114

100115
if (!Directory.Exists(databasePath))
@@ -117,7 +132,7 @@ private void HandleNativeCrashes(IDictionary<string, string> clientAttributes, I
117132

118133
foreach (var attribute in clientAttributes)
119134
{
120-
AddNativeAttribute(attribute.Key, attribute.Value);
135+
AddNativeAttribute(attribute.Key, attribute.Value == null ? string.Empty : attribute.Value);
121136
}
122137

123138
// add exception type to crashes handled by crashpad - all exception handled by crashpad
@@ -130,6 +145,15 @@ private void HandleNativeCrashes(IDictionary<string, string> clientAttributes, I
130145
// attribute via attributes parameters.
131146
AddNativeAttribute(ErrorTypeAttribute, CrashType);
132147
}
148+
149+
private bool Isx86Build(string pluginDirectoryPath)
150+
{
151+
const string unsupportedx86BuildPath = "x86";
152+
const string backtraceLib = "BacktraceCrashpadWindows.dll";
153+
var buildPath = Path.Combine(pluginDirectoryPath, unsupportedx86BuildPath);
154+
return File.Exists(Path.Combine(buildPath, backtraceLib));
155+
}
156+
133157
public void GetAttributes(IDictionary<string, string> attributes)
134158
{
135159
return;
@@ -315,21 +339,22 @@ public static IEnumerator SendUnhandledGameCrashesOnGameStartup(ICollection<stri
315339
}
316340
}
317341
}
342+
343+
private string GetPluginDirectoryPath()
344+
{
345+
const string pluginDir = "Plugins";
346+
return Path.Combine(Application.dataPath, pluginDir);
347+
}
318348
/// <summary>
319349
/// Generate path to Crashpad handler binary
320350
/// </summary>
321351
/// <returns>Path to crashpad handler binary</returns>
322-
private string GetDefaultPathToCrashpadHandler()
352+
private string GetDefaultPathToCrashpadHandler(string pluginDirectoryPath)
323353
{
324354
const string crashpadHandlerName = "crashpad_handler.dll";
325-
const string pluginDir = "Plugins";
326-
string architecture = IntPtr.Size == 8 ? "x86_64" : "x86";
327-
328-
string pluginPath = Path.Combine(pluginDir, architecture);
329-
string pluginHandlerPath = Path.Combine(pluginPath, crashpadHandlerName);
330-
331-
// generate full path to .dll file in plugins dir.
332-
return Path.Combine(Application.dataPath, pluginHandlerPath);
355+
const string supportedArchitecture = "x86_64";
356+
var architectureDirectory = Path.Combine(pluginDirectoryPath, supportedArchitecture);
357+
return Path.Combine(architectureDirectory, crashpadHandlerName);
333358

334359
}
335360
/// <summary>

0 commit comments

Comments
 (0)