From 8a6229415110b7ff6c11ebb286af7d4812d2aad4 Mon Sep 17 00:00:00 2001 From: konraddysput Date: Wed, 18 Nov 2020 11:49:08 +0100 Subject: [PATCH 01/10] Fixed android initialization when db doesn't exist or is initialized --- Runtime/BacktraceClient.cs | 8 +++++++- Runtime/Native/Android/NativeClient.cs | 13 ++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Runtime/BacktraceClient.cs b/Runtime/BacktraceClient.cs index 6b6f4a8b..e99fd0cc 100644 --- a/Runtime/BacktraceClient.cs +++ b/Runtime/BacktraceClient.cs @@ -305,7 +305,13 @@ public void Refresh() } _nativeClient = NativeClientFactory.GetNativeClient(Configuration, name); - + if (_nativeClient != null) + { + foreach (var attribute in _clientAttributes) + { + _nativeClient.SetAttribute(attribute.Key, attribute.Value); + } + } if (Configuration.SendUnhandledGameCrashesOnGameStartup && isActiveAndEnabled) { var nativeCrashUplaoder = new NativeCrashUploader(); diff --git a/Runtime/Native/Android/NativeClient.cs b/Runtime/Native/Android/NativeClient.cs index 6c110e63..20328909 100644 --- a/Runtime/Native/Android/NativeClient.cs +++ b/Runtime/Native/Android/NativeClient.cs @@ -69,6 +69,11 @@ private void HandleNativeCrashes() { return; } + var databasePath = _configuration.CrashpadDatabasePath; + if (string.IsNullOrEmpty(databasePath) || !Directory.Exists(databasePath)) + { + return; + } // crashpad is available only for API level 21+ // make sure we don't want ot start crashpad handler @@ -83,6 +88,10 @@ private void HandleNativeCrashes() } } var libDirectory = Path.Combine(Path.GetDirectoryName(Application.dataPath), "lib"); + if (!Directory.Exists(libDirectory)) + { + return; + } var crashpadHandlerPath = Directory.GetFiles(libDirectory, "libcrashpad_handler.so", SearchOption.AllDirectories).FirstOrDefault(); if (string.IsNullOrEmpty(crashpadHandlerPath)) { @@ -101,7 +110,7 @@ private void HandleNativeCrashes() // isn't available _captureNativeCrashes = Initialize( AndroidJNI.NewStringUTF(minidumpUrl), - AndroidJNI.NewStringUTF(_configuration.CrashpadDatabasePath), + AndroidJNI.NewStringUTF(databasePath), AndroidJNI.NewStringUTF(crashpadHandlerPath), AndroidJNIHelper.ConvertToJNIArray(backtraceAttributes.Attributes.Keys.ToArray()), AndroidJNIHelper.ConvertToJNIArray(backtraceAttributes.Attributes.Values.ToArray())); @@ -174,12 +183,10 @@ public void HandleAnr(string gameObjectName, string callbackName) /// Attribute value public void SetAttribute(string key, string value) { - Debug.Log($"Adding attribute to crashpad"); if (!_captureNativeCrashes || string.IsNullOrEmpty(key)) { return; } - Debug.Log($"Adding attribute to crashpad. {key} {value}"); // avoid null reference in crashpad source code if (value == null) { From 4418494761c5f765d3f0facfb000840e336027d4 Mon Sep 17 00:00:00 2001 From: konraddysput Date: Thu, 19 Nov 2020 19:04:42 +0100 Subject: [PATCH 02/10] Fixed android stack frame parser --- Runtime/Model/BacktraceUnhandledException.cs | 4 ++-- Tests/Runtime/BacktraceStackTraceTests.cs | 23 +++++++++++++++++--- Tests/Runtime/ClientSendTests.cs | 5 +++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Runtime/Model/BacktraceUnhandledException.cs b/Runtime/Model/BacktraceUnhandledException.cs index 0388c690..79867c45 100644 --- a/Runtime/Model/BacktraceUnhandledException.cs +++ b/Runtime/Model/BacktraceUnhandledException.cs @@ -241,7 +241,7 @@ private BacktraceStackFrame SetNativeStackTraceInformation(string frameString) var sourceCodeParts = sourceCodeInformation.Split(':'); if (sourceCodeParts.Length == 2) { - stackFrame.Line = int.Parse(sourceCodeParts[1]); + int.TryParse(sourceCodeParts[1], out stackFrame.Line); stackFrame.Library = sourceCodeParts[0]; stackFrame.FunctionName = stackFrame.FunctionName.Substring(sourceCodeEndIndex + 2); } @@ -272,7 +272,7 @@ private BacktraceStackFrame SetAndroidStackTraceInformation(string frameString) if (sourceCodeInformation.Length == 2) { stackFrame.Library = sourceCodeInformation[0]; - stackFrame.Line = int.Parse(sourceCodeInformation[1]); + int.TryParse(sourceCodeInformation[1], out stackFrame.Line); } else if (frameString.StartsWith("java.lang") || possibleSourceCodeInformation == "Unknown Source") { diff --git a/Tests/Runtime/BacktraceStackTraceTests.cs b/Tests/Runtime/BacktraceStackTraceTests.cs index d2521804..c362cc6d 100644 --- a/Tests/Runtime/BacktraceStackTraceTests.cs +++ b/Tests/Runtime/BacktraceStackTraceTests.cs @@ -165,6 +165,11 @@ public class BacktraceStackTraceTests FunctionName ="backtrace.io.backtrace_unity_android_plugin.BacktraceCrashHelper.InternalCall", Library = "BacktraceCrashHelper.java", Line = 31 + }, + new SampleStackFrame() { + Type = StackTraceType.Android, + FunctionName = "com.google.android.gms.ads.internal.webview.ac.loadUrl", + Custom = "com.google.android.gms.ads.internal.webview.ac.loadUrl(:com.google.android.gms.policy_ads_fdr_dynamite@204102000@204102000000.334548305.334548305:1)" }, // android unknown source new SampleStackFrame() { @@ -324,9 +329,16 @@ public void TestStackTraceCreation_AndroidMixModeCallStack_ValidStackTraceObject { var mixModeCallStack = _mixModeCallStack.ElementAt(i); var backtraceStackFrame = backtraceStackTrace.StackFrames[i - startIndex]; - Assert.AreEqual(mixModeCallStack.FunctionName, backtraceStackFrame.FunctionName); - Assert.AreEqual(mixModeCallStack.Line, backtraceStackFrame.Line); - Assert.AreEqual(mixModeCallStack.Library, backtraceStackFrame.Library); + if (!string.IsNullOrEmpty(mixModeCallStack.Custom)) + { + Assert.AreEqual(mixModeCallStack.FunctionName, backtraceStackFrame.FunctionName); + } + else + { + Assert.AreEqual(mixModeCallStack.FunctionName, backtraceStackFrame.FunctionName); + Assert.AreEqual(mixModeCallStack.Line, backtraceStackFrame.Line); + Assert.AreEqual(mixModeCallStack.Library, backtraceStackFrame.Library); + } } } @@ -512,6 +524,7 @@ internal enum StackTraceType { Default, Android, Native }; internal class SampleStackFrame { public StackTraceType Type = StackTraceType.Default; + public string Custom { get; set; } public string StackFrame { get; set; } public string FunctionName { get; set; } public string Library { get; set; } @@ -543,6 +556,10 @@ private string ParseDefaultStackTrace() public string ParseAndroidStackTrace() { + if (!string.IsNullOrEmpty(Custom)) + { + return string.Format("{0}\n", Custom); + } var formattedLineNumber = Line != 0 ? string.Format(":{0}", Line) : string.Empty; return string.Format("{0}({1}{2})\n", FunctionName, Library, formattedLineNumber); } diff --git a/Tests/Runtime/ClientSendTests.cs b/Tests/Runtime/ClientSendTests.cs index d99c2817..31910167 100644 --- a/Tests/Runtime/ClientSendTests.cs +++ b/Tests/Runtime/ClientSendTests.cs @@ -182,6 +182,11 @@ public IEnumerator PiiTests_ShouldRemoveEnvironmentVariableValue_IntegrationShou var environmentVariableKey = "USERNAME"; var expectedValue = "%USERNAME%"; + if (!Annotations.EnvironmentVariablesCache.ContainsKey(environmentVariableKey)) + { + Annotations.EnvironmentVariablesCache[environmentVariableKey] = "fake user name"; + } + var defaultUserName = Annotations.EnvironmentVariablesCache[environmentVariableKey]; Annotations.EnvironmentVariablesCache[environmentVariableKey] = expectedValue; From 33a9dd747830ba20d87ac325379d19e7bb32dd63 Mon Sep 17 00:00:00 2001 From: konraddysput Date: Thu, 19 Nov 2020 19:11:25 +0100 Subject: [PATCH 03/10] Security section --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index a90a1cb7..41f2ef11 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,41 @@ This change will generate dSYM files every time you build your game in Xcode. Yo 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 +# Security + +Backtrace-Unity allows you to remove/modify data that library collects when exception occured. Right now you can choose one of the methods below: + +* Before Send event +The library will fire an event every time when exception in managed environment occured. Before event allows you to skip report (you can do that by returning null value) or modify data that library were able to collect. BeforeSend event might be really useful in case if you would like to extend attributes or json object data based on data that application has right now. + +Example code: + +``` +//Read from manager BacktraceClient instance +var backtraceClient = GameObject.Find("manager name").GetComponent(); +// set beforeSend event +_backtraceClient.BeforeSend = (BacktraceData data) => + { + data.Attributes.Attributes["my-dynamic-attribute"] = "value"; + return data; + }; +``` + +* Environment variable +`Annotations` class exposes EnvironmentVariableCache dictionary - dictionary that stores environment variables collected by library. For example - to replace `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. + +```csharp +Annotations.EnvironmentVariablesCache["USERNAME"] = "%USERNAME%"; +``` + +Also you can still use BeforeSend event to edit collected diagnostic data: +```csharp + client.BeforeSend = (BacktraceData data) => + { + data.Annotation.EnvironmentVariables["USERNAME"] = "%USERNAME%"; + return data; + } +``` # API Overview From b7edb36a192b23eb999d4d29c3115b1c990a5941 Mon Sep 17 00:00:00 2001 From: konraddysput Date: Thu, 19 Nov 2020 19:13:44 +0100 Subject: [PATCH 04/10] Changelog + readme update --- CHANGELOG.md | 6 ++++++ README.md | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b00f9ff..554927f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Backtrace Unity Release Notes +## Version 3.2.1 +- Android stack trace parser improvements, +- Fixed Android NDK initialization when database directory doesn't exist, +- Added security section to Readme + + ## Version 3.2.0 - 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. - 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' diff --git a/README.md b/README.md index 41f2ef11..64d72468 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ - [Setup ](#setup--a-name--installation----a-) - [Android Specific information](#android-specific-information) - [iOS Specific information](#ios-specific-information) +- [Security](#security) - [API Overview](#api-overview) - [Architecture description](#architecture-description) - [Investigating an Error in Backtrace](#investigating-an-error-in-backtrace) @@ -184,15 +185,15 @@ The library will fire an event every time when exception in managed environment Example code: -``` +```csharp //Read from manager BacktraceClient instance var backtraceClient = GameObject.Find("manager name").GetComponent(); // set beforeSend event _backtraceClient.BeforeSend = (BacktraceData data) => - { - data.Attributes.Attributes["my-dynamic-attribute"] = "value"; - return data; - }; +{ + data.Attributes.Attributes["my-dynamic-attribute"] = "value"; + return data; +}; ``` * Environment variable From 02187ce62ee2a6c532695242de19fde55fb3b1f8 Mon Sep 17 00:00:00 2001 From: konraddysput Date: Thu, 19 Nov 2020 19:14:18 +0100 Subject: [PATCH 05/10] Version update --- Runtime/Model/BacktraceData.cs | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Runtime/Model/BacktraceData.cs b/Runtime/Model/BacktraceData.cs index 0d670e06..e7edf398 100644 --- a/Runtime/Model/BacktraceData.cs +++ b/Runtime/Model/BacktraceData.cs @@ -45,7 +45,7 @@ public class BacktraceData /// /// Version of the C# library /// - public const string AgentVersion = "3.2.0"; + public const string AgentVersion = "3.2.1"; /// /// Application thread details diff --git a/package.json b/package.json index b4a3b492..822234d9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "io.backtrace.unity", "displayName": "Backtrace", - "version": "3.2.0", + "version": "3.2.1", "unity": "2017.1", "description": "Backtrace's integration with Unity games allows customers to capture and report handled and unhandled Unity exceptions to their Backtrace instance, instantly offering the ability to prioritize and debug software errors.", "keywords": [ From 0dc385ccd0dbec0966f91e0f13fe0359d6b6347b Mon Sep 17 00:00:00 2001 From: jasoncdavis0 Date: Fri, 20 Nov 2020 08:09:31 -0500 Subject: [PATCH 06/10] Updated Privacy section --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 64d72468..d7be6de3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ - [Setup ](#setup--a-name--installation----a-) - [Android Specific information](#android-specific-information) - [iOS Specific information](#ios-specific-information) -- [Security](#security) +- [Data Privacy](#data-privacy) - [API Overview](#api-overview) - [Architecture description](#architecture-description) - [Investigating an Error in Backtrace](#investigating-an-error-in-backtrace) @@ -176,12 +176,12 @@ This change will generate dSYM files every time you build your game in Xcode. Yo 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 -# Security +# Data Privacy -Backtrace-Unity allows you to remove/modify data that library collects when exception occured. Right now you can choose one of the methods below: +Backtrace-Unity allows developers to remove and modify data that the library collects when an exception occurs using the following methods: -* Before Send event -The library will fire an event every time when exception in managed environment occured. Before event allows you to skip report (you can do that by returning null value) or modify data that library were able to collect. BeforeSend event might be really useful in case if you would like to extend attributes or json object data based on data that application has right now. +* BeforeSend event +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. Example code: @@ -196,8 +196,8 @@ _backtraceClient.BeforeSend = (BacktraceData data) => }; ``` -* Environment variable -`Annotations` class exposes EnvironmentVariableCache dictionary - dictionary that stores environment variables collected by library. For example - to replace `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. +* Environment Variable Management +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. ```csharp Annotations.EnvironmentVariablesCache["USERNAME"] = "%USERNAME%"; From d0310da1d350887b0f244c2000972a8d2b1b5c39 Mon Sep 17 00:00:00 2001 From: jasoncdavis0 Date: Fri, 20 Nov 2020 08:09:55 -0500 Subject: [PATCH 07/10] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 554927f2..9e0897fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Version 3.2.1 - Android stack trace parser improvements, - Fixed Android NDK initialization when database directory doesn't exist, -- Added security section to Readme +- Added Privacy section to Readme ## Version 3.2.0 From 09ea4f50cae9a320159d93d082b994b32d644e60 Mon Sep 17 00:00:00 2001 From: konraddysput Date: Fri, 20 Nov 2020 14:26:24 +0100 Subject: [PATCH 08/10] Backtrace api improvements --- Runtime/Model/BacktraceResult.cs | 9 ++++++++- Runtime/Services/BacktraceApi.cs | 14 +++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Runtime/Model/BacktraceResult.cs b/Runtime/Model/BacktraceResult.cs index 51a4d9b9..e593155d 100644 --- a/Runtime/Model/BacktraceResult.cs +++ b/Runtime/Model/BacktraceResult.cs @@ -114,12 +114,19 @@ 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(json); var result = new BacktraceResult() { response = rawResult.response, _rxId = rawResult._rxid, - Status = rawResult.response == "ok" ? BacktraceResultStatus.Ok: BacktraceResultStatus.ServerError + Status = rawResult.response == "ok" ? BacktraceResultStatus.Ok : BacktraceResultStatus.ServerError }; return result; } diff --git a/Runtime/Services/BacktraceApi.cs b/Runtime/Services/BacktraceApi.cs index a2cb308f..d6975dda 100644 --- a/Runtime/Services/BacktraceApi.cs +++ b/Runtime/Services/BacktraceApi.cs @@ -103,9 +103,14 @@ public IEnumerator SendMinidump(string minidumpPath, IEnumerable attachm ? System.Diagnostics.Stopwatch.StartNew() : new System.Diagnostics.Stopwatch(); + var minidumpBytes = File.ReadAllBytes(minidumpPath); + if (minidumpBytes == null || minidumpBytes.Length == 0) + { + yield break; + } List formData = new List { - new MultipartFormFileSection("upload_file", File.ReadAllBytes(minidumpPath)) + new MultipartFormFileSection("upload_file", minidumpBytes) }; foreach (var file in attachments) @@ -224,7 +229,7 @@ public IEnumerator Send(string json, List attachments, Dictionary attachments, Dictionary queryAttributes) { From 9962b235cc8586592c369e681ed52c65bef372b8 Mon Sep 17 00:00:00 2001 From: konraddysput Date: Mon, 23 Nov 2020 11:55:56 +0100 Subject: [PATCH 09/10] Disabled BacktraceClient integration OnDestroyed --- Runtime/BacktraceClient.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Runtime/BacktraceClient.cs b/Runtime/BacktraceClient.cs index e99fd0cc..ebf622b4 100644 --- a/Runtime/BacktraceClient.cs +++ b/Runtime/BacktraceClient.cs @@ -325,6 +325,13 @@ private void Awake() Refresh(); } + private void OnDestroy() + { + Debug.Log("Disabling Backtrace integration"); + Enabled = false; + Application.logMessageReceived -= HandleUnityMessage; + } + /// /// Change maximum number of reportrs sending per one minute /// From 2e471e4ccad00c9798e9d201153380ec95b0ee58 Mon Sep 17 00:00:00 2001 From: konraddysput Date: Mon, 23 Nov 2020 19:29:44 +0100 Subject: [PATCH 10/10] Better log messages --- Runtime/BacktraceClient.cs | 5 +++++ Runtime/Native/Android/NativeClient.cs | 10 ++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Runtime/BacktraceClient.cs b/Runtime/BacktraceClient.cs index ebf622b4..48b4883e 100644 --- a/Runtime/BacktraceClient.cs +++ b/Runtime/BacktraceClient.cs @@ -565,6 +565,11 @@ private BacktraceData SetupBacktraceData(BacktraceReport report) /// Main thread stack trace internal void OnAnrDetected(string stackTrace) { + if (!Enabled) + { + Debug.LogWarning("Please enable BacktraceClient first - Please validate Backtrace client initializaiton in Unity IDE."); + return; + } const string anrMessage = "ANRException: Blocked thread detected"; _backtraceLogManager.Enqueue(new BacktraceUnityMessage(anrMessage, stackTrace, LogType.Error)); var hang = new BacktraceUnhandledException(anrMessage, stackTrace); diff --git a/Runtime/Native/Android/NativeClient.cs b/Runtime/Native/Android/NativeClient.cs index 20328909..6077b629 100644 --- a/Runtime/Native/Android/NativeClient.cs +++ b/Runtime/Native/Android/NativeClient.cs @@ -65,13 +65,15 @@ public NativeClient(string gameObjectName, BacktraceConfiguration configuration) private void HandleNativeCrashes() { // make sure database is enabled - if (!_captureNativeCrashes) + if (!_captureNativeCrashes || !_configuration.Enabled) { + Debug.LogWarning("Backtrace native integration status: Disabled NDK integration"); return; } var databasePath = _configuration.CrashpadDatabasePath; if (string.IsNullOrEmpty(databasePath) || !Directory.Exists(databasePath)) { + Debug.LogWarning("Backtrace native integration status: database path doesn't exist"); return; } @@ -83,7 +85,7 @@ private void HandleNativeCrashes() int apiLevel = version.GetStatic("SDK_INT"); if (apiLevel < 21) { - Debug.LogWarning("Crashpad integration status: Unsupported Android API level"); + Debug.LogWarning("Backtrace native integration status: Unsupported Android API level"); return; } } @@ -95,7 +97,7 @@ private void HandleNativeCrashes() var crashpadHandlerPath = Directory.GetFiles(libDirectory, "libcrashpad_handler.so", SearchOption.AllDirectories).FirstOrDefault(); if (string.IsNullOrEmpty(crashpadHandlerPath)) { - Debug.LogWarning("Crashpad integration status: Cannot find crashpad library"); + Debug.LogWarning("Backtrace native integration status: Cannot find crashpad library"); return; } // get default built-in Backtrace-Unity attributes @@ -116,7 +118,7 @@ private void HandleNativeCrashes() AndroidJNIHelper.ConvertToJNIArray(backtraceAttributes.Attributes.Values.ToArray())); if (!_captureNativeCrashes) { - Debug.LogWarning("Crashpad integration status: Cannot initialize Crashpad client"); + Debug.LogWarning("Backtrace native integration status: Cannot initialize Crashpad client"); } }