Skip to content

Fixes symbolication for net9.0-android applications in Release config #4221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 30, 2025
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- Fixed symbolication for net9.0-android applications in Release config ([#4221](https://github.com/getsentry/sentry-dotnet/pull/4221))
- Support Linux arm64 on Native AOT ([#3700](https://github.com/getsentry/sentry-dotnet/pull/3700))
- Revert W3C traceparent support ([#4204](https://github.com/getsentry/sentry-dotnet/pull/4204))

Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>

<PropertyGroup>
<VersionPrefix>5.8.1</VersionPrefix>
<VersionPrefix>5.8.2-beta.1</VersionPrefix>
<LangVersion>13</LangVersion>
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ public AndroidAssemblyDirectoryReaderV2(string apkPath, IList<string> supportedA
Logger = logger;
foreach (var abi in supportedAbis)
{
logger?.Invoke("Adding {0} to supported architectures for Directory Reader", abi);
SupportedArchitectures.Add(abi.AbiToDeviceArchitecture());
}
_archiveAssemblyHelper = new ArchiveAssemblyHelper(apkPath, logger);
_archiveAssemblyHelper = new ArchiveAssemblyHelper(apkPath, logger, supportedAbis);
}

public PEReader? TryReadAssembly(string name)
Expand All @@ -25,11 +26,13 @@ public AndroidAssemblyDirectoryReaderV2(string apkPath, IList<string> supportedA
var stream = File.OpenRead(name);
return new PEReader(stream);
}
Logger?.Invoke("File {0} does not exist in the APK", name);

foreach (var arch in SupportedArchitectures)
{
if (_archiveAssemblyHelper.ReadEntry($"assemblies/{name}", arch) is not { } memStream)
{
Logger?.Invoke("Couldn't find entry {0} in the APK for the {1} architecture", name, arch);
continue;
}

Expand All @@ -56,8 +59,9 @@ internal class ArchiveAssemblyHelper

private readonly string _archivePath;
private readonly DebugLogger? _logger;
private readonly IList<string> _supportedAbis;

public ArchiveAssemblyHelper(string archivePath, DebugLogger? logger)
public ArchiveAssemblyHelper(string archivePath, DebugLogger? logger, IList<string> supportedAbis)
{
if (string.IsNullOrEmpty(archivePath))
{
Expand All @@ -66,6 +70,7 @@ public ArchiveAssemblyHelper(string archivePath, DebugLogger? logger)

_archivePath = archivePath;
_logger = logger;
_supportedAbis = supportedAbis;
}

public MemoryStream? ReadEntry(string path, AndroidTargetArch arch = AndroidTargetArch.None, bool uncompressIfNecessary = false)
Expand Down Expand Up @@ -137,23 +142,52 @@ public ArchiveAssemblyHelper(string archivePath, DebugLogger? logger)
var potentialEntries = TransformArchiveAssemblyPath(path, arch);
if (potentialEntries == null || potentialEntries.Count == 0)
{
_logger?.Invoke("No potential entries for path '{0}' with arch '{1}'", path, arch);
return null;
}

using var zip = ZipFile.OpenRead(_archivePath);
foreach (var assemblyPath in potentialEntries)
// First we check the base.apk
if (ReadEntryFromApk(_archivePath) is { } baseEntry)
{
if (zip.GetEntry(assemblyPath) is not { } entry)
_logger?.Invoke("Found entry '{0}' in base archive '{1}'", path, _archivePath);
return baseEntry;
}

// Otherwise check in the device specific APKs
foreach (var supportedAbi in _supportedAbis)
{
var splitFilePath = _archivePath.GetArchivePathForAbi(supportedAbi, _logger);
if (!File.Exists(splitFilePath))
{
continue;
_logger?.Invoke("No split config detected at: '{0}'", splitFilePath);
}
else if (ReadEntryFromApk(splitFilePath) is { } splitEntry)
{
return splitEntry;
}

var ret = entry.Extract();
ret.Flush();
return ret;
}

// Finally admit defeat
return null;

MemoryStream? ReadEntryFromApk(string archivePath)
{
using var zip = ZipFile.OpenRead(archivePath);
foreach (var assemblyPath in potentialEntries)
{
if (zip.GetEntry(assemblyPath) is not { } entry)
{
_logger?.Invoke("No entry found for path '{0}' in archive '{1}'", assemblyPath, archivePath);
continue;
}

var ret = entry.Extract();
ret.Flush();
return ret;
}

return null;
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,35 @@ private AndroidAssemblyStoreReaderV2(IList<AssemblyStoreExplorer> explorers, Deb

public static bool TryReadStore(string inputFile, IList<string> supportedAbis, DebugLogger? logger, [NotNullWhen(true)] out AndroidAssemblyStoreReaderV2? reader)
{
List<AssemblyStoreExplorer> supportedExplorers = [];

// First we check the base.apk for an assembly store
var (explorers, errorMessage) = AssemblyStoreExplorer.Open(inputFile, logger);
if (errorMessage != null)
if (explorers is null)
{
logger?.Invoke(errorMessage);
reader = null;
return false;
}
logger?.Invoke("Unable to read store information for {0}: {1}", inputFile, errorMessage);

List<AssemblyStoreExplorer> supportedExplorers = [];
if (explorers is not null)
// Check for assembly stores in any device specific APKs
foreach (var supportedAbi in supportedAbis)
{
var splitFilePath = inputFile.GetArchivePathForAbi(supportedAbi, logger);
if (!File.Exists(splitFilePath))
{
logger?.Invoke("No split config detected at: '{0}'", splitFilePath);
continue;
}
(explorers, errorMessage) = AssemblyStoreExplorer.Open(splitFilePath, logger);
if (explorers is not null)
{
supportedExplorers.AddRange(explorers); // If the error is null then this is not null
}
else
{
logger?.Invoke("Unable to read store information for {0}: {1}", splitFilePath, errorMessage);
}
}
}
else
{
foreach (var explorer in explorers)
{
Expand Down
13 changes: 13 additions & 0 deletions src/Sentry.Android.AssemblyReader/V2/MonoAndroidHelper.Basic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,17 @@ public static string MakeZipArchivePath(string part1, ICollection<string>? pathP
public const string MANGLED_ASSEMBLY_REGULAR_ASSEMBLY_MARKER = "lib_";
public const string MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER = "lib-";
public const string SATELLITE_CULTURE_END_MARKER_CHAR = "_";

/// <summary>
/// When an AAB file is deployed, the APK is split into multiple APKs so our modules can end up in a companion
/// architecture specific APK like split_config.arm64_v8a.apk. This method returns the path to that split_config APK
/// if it exists... otherwise we just return the original archive path.
/// </summary>
internal static string GetArchivePathForAbi(this string archivePath, string abi, DebugLogger? logger)
{
var basePath = Path.GetDirectoryName(archivePath) ?? string.Empty;
var abiPart = abi.Replace("-", "_");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can avoid this by having supportedAbis be provided in the right format

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The abi.Replace("-", "_") you mean? Not really... most of the time it is used with a hyphen. When building the file names for the split_config APKs though it gets replaced with an underscore (I'm sure there's a reason... not sure what it is though).

var splitFilePath = Path.Combine(basePath, $"split_config.{abiPart}.apk");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if GetDirectoryName returned null and we ended up with "" does this code make sense?

return splitFilePath;
}
}
1 change: 1 addition & 0 deletions src/Sentry/Internal/DebugStackTrace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ private IEnumerable<SentryStackFrame> CreateFrames(StackTrace stackTrace, bool i
return null;
}

_options.LogDebug("Attempting to get debug image for native AOT Frame");
var imageAddress = stackFrame.GetNativeImageBase();
var frame = ParseNativeAOTToString(stackFrame.ToString());
frame.ImageAddress = imageAddress;
Expand Down
Loading