Skip to content

Commit 9b6c739

Browse files
konraddysputjasoncdavis0
andauthored
Version 3.2.1 (#50)
* Fixed android initialization when db doesn't exist or is initialized * Fixed android stack frame parser * Security section * Changelog + readme update * Version update * Updated Privacy section * Update CHANGELOG.md * Backtrace api improvements * Disabled BacktraceClient integration OnDestroyed * Better log messages Co-authored-by: jasoncdavis0 <jason.davis@enterprisedb.com>
1 parent f029057 commit 9b6c739

File tree

11 files changed

+123
-21
lines changed

11 files changed

+123
-21
lines changed

CHANGELOG.md

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

3+
## Version 3.2.1
4+
- Android stack trace parser improvements,
5+
- Fixed Android NDK initialization when database directory doesn't exist,
6+
- Added Privacy section to Readme
7+
8+
39
## Version 3.2.0
410
- This release adds the ability to capture native iOS crashes from Unity games deployed to iOS. The Backtrace Configuration now exposes a setting for games being prepared for iOS to choose `Capture native crashes`. When enabled, the backtrace-unity client will capture and submit native iOS crashes to the configured Backtrace instance. To generate human readable callstacks, game programmers will need to generate and upload appropriate debug symbols.
511
- Added default uname.sysname attributes for some platforms. The following is the list of uname.sysname platforms that can be populated. list "Android, IOS, Linux, Mac OS, ps3, ps4, Samsung TV, tvOS, WebGL, WiiU, Switch, Xbox". Note 'Switch' had previously been reported as 'switch'

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- [Setup <a name="installation"></a>](#setup--a-name--installation----a-)
1212
- [Android Specific information](#android-specific-information)
1313
- [iOS Specific information](#ios-specific-information)
14+
- [Data Privacy](#data-privacy)
1415
- [API Overview](#api-overview)
1516
- [Architecture description](#architecture-description)
1617
- [Investigating an Error in Backtrace](#investigating-an-error-in-backtrace)
@@ -175,6 +176,41 @@ This change will generate dSYM files every time you build your game in Xcode. Yo
175176

176177
To learn more about how to submit those symbol files to Backtrace, please see the Project Settings / Symbols. You can manage submission tokens, upload via the UI, or configure external Symbol Servers to connect and discover required symbols. Please review additional Symbol documentaion at https://support.backtrace.io/hc/en-us/articles/360040517071-Symbolication-Overview
177178

179+
# Data Privacy
180+
181+
Backtrace-Unity allows developers to remove and modify data that the library collects when an exception occurs using the following methods:
182+
183+
* BeforeSend event
184+
The library will fire an event every time an exception in the managed environment occurs. The BeforeEvent trigger allows you to skip the report (you can do that by returning null value) or to modify data that library collected before sending the report. BeforeSend event might be useful in case if you would like to extend attributes or json object data based on data that application has at the time of exception.
185+
186+
Example code:
187+
188+
```csharp
189+
//Read from manager BacktraceClient instance
190+
var backtraceClient = GameObject.Find("manager name").GetComponent<BacktraceClient>();
191+
// set beforeSend event
192+
_backtraceClient.BeforeSend = (BacktraceData data) =>
193+
{
194+
data.Attributes.Attributes["my-dynamic-attribute"] = "value";
195+
return data;
196+
};
197+
```
198+
199+
* Environment Variable Management
200+
The `Annotations` class exposes the EnvironmentVariableCache dictionary - a dictionary that stores environment variables collected by the library. You can manipulate the data in this cache before the report is sent. For example - to replace the`USERNAME` environment variable collected by Backtrace library with random string you can easily edit annotations environment varaible and Backtrace-Untiy will reuse them on report creation.
201+
202+
```csharp
203+
Annotations.EnvironmentVariablesCache["USERNAME"] = "%USERNAME%";
204+
```
205+
206+
Also you can still use BeforeSend event to edit collected diagnostic data:
207+
```csharp
208+
client.BeforeSend = (BacktraceData data) =>
209+
{
210+
data.Annotation.EnvironmentVariables["USERNAME"] = "%USERNAME%";
211+
return data;
212+
}
213+
```
178214

179215

180216
# API Overview

Runtime/BacktraceClient.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,13 @@ public void Refresh()
305305
}
306306

307307
_nativeClient = NativeClientFactory.GetNativeClient(Configuration, name);
308-
308+
if (_nativeClient != null)
309+
{
310+
foreach (var attribute in _clientAttributes)
311+
{
312+
_nativeClient.SetAttribute(attribute.Key, attribute.Value);
313+
}
314+
}
309315
if (Configuration.SendUnhandledGameCrashesOnGameStartup && isActiveAndEnabled)
310316
{
311317
var nativeCrashUplaoder = new NativeCrashUploader();
@@ -319,6 +325,13 @@ private void Awake()
319325
Refresh();
320326
}
321327

328+
private void OnDestroy()
329+
{
330+
Debug.Log("Disabling Backtrace integration");
331+
Enabled = false;
332+
Application.logMessageReceived -= HandleUnityMessage;
333+
}
334+
322335
/// <summary>
323336
/// Change maximum number of reportrs sending per one minute
324337
/// </summary>
@@ -552,6 +565,11 @@ private BacktraceData SetupBacktraceData(BacktraceReport report)
552565
/// <param name="stackTrace">Main thread stack trace</param>
553566
internal void OnAnrDetected(string stackTrace)
554567
{
568+
if (!Enabled)
569+
{
570+
Debug.LogWarning("Please enable BacktraceClient first - Please validate Backtrace client initializaiton in Unity IDE.");
571+
return;
572+
}
555573
const string anrMessage = "ANRException: Blocked thread detected";
556574
_backtraceLogManager.Enqueue(new BacktraceUnityMessage(anrMessage, stackTrace, LogType.Error));
557575
var hang = new BacktraceUnhandledException(anrMessage, stackTrace);

Runtime/Model/BacktraceData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class BacktraceData
4545
/// <summary>
4646
/// Version of the C# library
4747
/// </summary>
48-
public const string AgentVersion = "3.2.0";
48+
public const string AgentVersion = "3.2.1";
4949

5050
/// <summary>
5151
/// Application thread details

Runtime/Model/BacktraceResult.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,19 @@ internal void AddInnerResult(BacktraceResult innerResult)
114114

115115
public static BacktraceResult FromJson(string json)
116116
{
117+
if (string.IsNullOrEmpty(json))
118+
{
119+
return new BacktraceResult()
120+
{
121+
Status = BacktraceResultStatus.Empty
122+
};
123+
}
117124
var rawResult = JsonUtility.FromJson<BacktraceRawResult>(json);
118125
var result = new BacktraceResult()
119126
{
120127
response = rawResult.response,
121128
_rxId = rawResult._rxid,
122-
Status = rawResult.response == "ok" ? BacktraceResultStatus.Ok: BacktraceResultStatus.ServerError
129+
Status = rawResult.response == "ok" ? BacktraceResultStatus.Ok : BacktraceResultStatus.ServerError
123130
};
124131
return result;
125132
}

Runtime/Model/BacktraceUnhandledException.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ private BacktraceStackFrame SetNativeStackTraceInformation(string frameString)
241241
var sourceCodeParts = sourceCodeInformation.Split(':');
242242
if (sourceCodeParts.Length == 2)
243243
{
244-
stackFrame.Line = int.Parse(sourceCodeParts[1]);
244+
int.TryParse(sourceCodeParts[1], out stackFrame.Line);
245245
stackFrame.Library = sourceCodeParts[0];
246246
stackFrame.FunctionName = stackFrame.FunctionName.Substring(sourceCodeEndIndex + 2);
247247
}
@@ -272,7 +272,7 @@ private BacktraceStackFrame SetAndroidStackTraceInformation(string frameString)
272272
if (sourceCodeInformation.Length == 2)
273273
{
274274
stackFrame.Library = sourceCodeInformation[0];
275-
stackFrame.Line = int.Parse(sourceCodeInformation[1]);
275+
int.TryParse(sourceCodeInformation[1], out stackFrame.Line);
276276
}
277277
else if (frameString.StartsWith("java.lang") || possibleSourceCodeInformation == "Unknown Source")
278278
{

Runtime/Native/Android/NativeClient.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,15 @@ public NativeClient(string gameObjectName, BacktraceConfiguration configuration)
6565
private void HandleNativeCrashes()
6666
{
6767
// make sure database is enabled
68-
if (!_captureNativeCrashes)
68+
if (!_captureNativeCrashes || !_configuration.Enabled)
69+
{
70+
Debug.LogWarning("Backtrace native integration status: Disabled NDK integration");
71+
return;
72+
}
73+
var databasePath = _configuration.CrashpadDatabasePath;
74+
if (string.IsNullOrEmpty(databasePath) || !Directory.Exists(databasePath))
6975
{
76+
Debug.LogWarning("Backtrace native integration status: database path doesn't exist");
7077
return;
7178
}
7279

@@ -78,15 +85,19 @@ private void HandleNativeCrashes()
7885
int apiLevel = version.GetStatic<int>("SDK_INT");
7986
if (apiLevel < 21)
8087
{
81-
Debug.LogWarning("Crashpad integration status: Unsupported Android API level");
88+
Debug.LogWarning("Backtrace native integration status: Unsupported Android API level");
8289
return;
8390
}
8491
}
8592
var libDirectory = Path.Combine(Path.GetDirectoryName(Application.dataPath), "lib");
93+
if (!Directory.Exists(libDirectory))
94+
{
95+
return;
96+
}
8697
var crashpadHandlerPath = Directory.GetFiles(libDirectory, "libcrashpad_handler.so", SearchOption.AllDirectories).FirstOrDefault();
8798
if (string.IsNullOrEmpty(crashpadHandlerPath))
8899
{
89-
Debug.LogWarning("Crashpad integration status: Cannot find crashpad library");
100+
Debug.LogWarning("Backtrace native integration status: Cannot find crashpad library");
90101
return;
91102
}
92103
// get default built-in Backtrace-Unity attributes
@@ -101,13 +112,13 @@ private void HandleNativeCrashes()
101112
// isn't available
102113
_captureNativeCrashes = Initialize(
103114
AndroidJNI.NewStringUTF(minidumpUrl),
104-
AndroidJNI.NewStringUTF(_configuration.CrashpadDatabasePath),
115+
AndroidJNI.NewStringUTF(databasePath),
105116
AndroidJNI.NewStringUTF(crashpadHandlerPath),
106117
AndroidJNIHelper.ConvertToJNIArray(backtraceAttributes.Attributes.Keys.ToArray()),
107118
AndroidJNIHelper.ConvertToJNIArray(backtraceAttributes.Attributes.Values.ToArray()));
108119
if (!_captureNativeCrashes)
109120
{
110-
Debug.LogWarning("Crashpad integration status: Cannot initialize Crashpad client");
121+
Debug.LogWarning("Backtrace native integration status: Cannot initialize Crashpad client");
111122
}
112123
}
113124

@@ -174,12 +185,10 @@ public void HandleAnr(string gameObjectName, string callbackName)
174185
/// <param name="value">Attribute value</param>
175186
public void SetAttribute(string key, string value)
176187
{
177-
Debug.Log($"Adding attribute to crashpad");
178188
if (!_captureNativeCrashes || string.IsNullOrEmpty(key))
179189
{
180190
return;
181191
}
182-
Debug.Log($"Adding attribute to crashpad. {key} {value}");
183192
// avoid null reference in crashpad source code
184193
if (value == null)
185194
{

Runtime/Services/BacktraceApi.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,14 @@ public IEnumerator SendMinidump(string minidumpPath, IEnumerable<string> attachm
103103
? System.Diagnostics.Stopwatch.StartNew()
104104
: new System.Diagnostics.Stopwatch();
105105

106+
var minidumpBytes = File.ReadAllBytes(minidumpPath);
107+
if (minidumpBytes == null || minidumpBytes.Length == 0)
108+
{
109+
yield break;
110+
}
106111
List<IMultipartFormSection> formData = new List<IMultipartFormSection>
107112
{
108-
new MultipartFormFileSection("upload_file", File.ReadAllBytes(minidumpPath))
113+
new MultipartFormFileSection("upload_file", minidumpBytes)
109114
};
110115

111116
foreach (var file in attachments)
@@ -224,7 +229,7 @@ public IEnumerator Send(string json, List<string> attachments, Dictionary<string
224229
yield return request.SendWebRequest();
225230

226231
BacktraceResult result;
227-
if (request.responseCode == 200)
232+
if (request.responseCode == 200 && (!request.isNetworkError || !request.isHttpError))
228233
{
229234
result = BacktraceResult.FromJson(request.downloadHandler.text);
230235

@@ -265,10 +270,9 @@ public IEnumerator Send(string json, List<string> attachments, Dictionary<string
265270

266271
private void PrintLog(UnityWebRequest request)
267272
{
268-
string responseText = Encoding.UTF8.GetString(request.downloadHandler.data);
269273
Debug.LogWarning(string.Format("{0}{1}", string.Format("[Backtrace]::Reponse code: {0}, Response text: {1}",
270274
request.responseCode,
271-
responseText),
275+
request.downloadHandler.text),
272276
"\n Please check provided url to Backtrace service or learn more from our integration guide: https://help.backtrace.io/integration-guides/game-engines/unity-integration-guide"));
273277
}
274278

@@ -313,7 +317,7 @@ private string GetAttachmentUploadUrl(string rxId, string attachmentName)
313317

314318
}
315319

316-
// private static readonly string reservedCharacters = "!*'();:@&=+$,/?%#[]";
320+
// private static readonly string reservedCharacters = "!*'();:@&=+$,/?%#[]";
317321

318322
public static string GetParametrizedQuery(string serverUrl, Dictionary<string, string> queryAttributes)
319323
{

Tests/Runtime/BacktraceStackTraceTests.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ public class BacktraceStackTraceTests
165165
FunctionName ="backtrace.io.backtrace_unity_android_plugin.BacktraceCrashHelper.InternalCall",
166166
Library = "BacktraceCrashHelper.java",
167167
Line = 31
168+
},
169+
new SampleStackFrame() {
170+
Type = StackTraceType.Android,
171+
FunctionName = "com.google.android.gms.ads.internal.webview.ac.loadUrl",
172+
Custom = "com.google.android.gms.ads.internal.webview.ac.loadUrl(:com.google.android.gms.policy_ads_fdr_dynamite@204102000@204102000000.334548305.334548305:1)"
168173
},
169174
// android unknown source
170175
new SampleStackFrame() {
@@ -324,9 +329,16 @@ public void TestStackTraceCreation_AndroidMixModeCallStack_ValidStackTraceObject
324329
{
325330
var mixModeCallStack = _mixModeCallStack.ElementAt(i);
326331
var backtraceStackFrame = backtraceStackTrace.StackFrames[i - startIndex];
327-
Assert.AreEqual(mixModeCallStack.FunctionName, backtraceStackFrame.FunctionName);
328-
Assert.AreEqual(mixModeCallStack.Line, backtraceStackFrame.Line);
329-
Assert.AreEqual(mixModeCallStack.Library, backtraceStackFrame.Library);
332+
if (!string.IsNullOrEmpty(mixModeCallStack.Custom))
333+
{
334+
Assert.AreEqual(mixModeCallStack.FunctionName, backtraceStackFrame.FunctionName);
335+
}
336+
else
337+
{
338+
Assert.AreEqual(mixModeCallStack.FunctionName, backtraceStackFrame.FunctionName);
339+
Assert.AreEqual(mixModeCallStack.Line, backtraceStackFrame.Line);
340+
Assert.AreEqual(mixModeCallStack.Library, backtraceStackFrame.Library);
341+
}
330342
}
331343
}
332344

@@ -512,6 +524,7 @@ internal enum StackTraceType { Default, Android, Native };
512524
internal class SampleStackFrame
513525
{
514526
public StackTraceType Type = StackTraceType.Default;
527+
public string Custom { get; set; }
515528
public string StackFrame { get; set; }
516529
public string FunctionName { get; set; }
517530
public string Library { get; set; }
@@ -543,6 +556,10 @@ private string ParseDefaultStackTrace()
543556

544557
public string ParseAndroidStackTrace()
545558
{
559+
if (!string.IsNullOrEmpty(Custom))
560+
{
561+
return string.Format("{0}\n", Custom);
562+
}
546563
var formattedLineNumber = Line != 0 ? string.Format(":{0}", Line) : string.Empty;
547564
return string.Format("{0}({1}{2})\n", FunctionName, Library, formattedLineNumber);
548565
}

Tests/Runtime/ClientSendTests.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ public IEnumerator PiiTests_ShouldRemoveEnvironmentVariableValue_IntegrationShou
182182

183183
var environmentVariableKey = "USERNAME";
184184
var expectedValue = "%USERNAME%";
185+
if (!Annotations.EnvironmentVariablesCache.ContainsKey(environmentVariableKey))
186+
{
187+
Annotations.EnvironmentVariablesCache[environmentVariableKey] = "fake user name";
188+
}
189+
185190
var defaultUserName = Annotations.EnvironmentVariablesCache[environmentVariableKey];
186191
Annotations.EnvironmentVariablesCache[environmentVariableKey] = expectedValue;
187192

0 commit comments

Comments
 (0)