Skip to content

WIP: Tests for the android-release-symbols branch #4227

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ mono_crash.*.json
test_output/
test/**/*.apk
/tools/
/test/Sentry.Android.AssemblyReader.Tests/tools
*.log
.sentry-native

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixes

- Fixed symbolication for net9.0-android applications in Release config ([#4221](https://github.com/getsentry/sentry-dotnet/pull/4221))

## 5.8.1

### Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ 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);
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 Down Expand Up @@ -137,6 +140,7 @@ 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;
}

Expand All @@ -145,6 +149,7 @@ public ArchiveAssemblyHelper(string archivePath, DebugLogger? logger)
{
if (zip.GetEntry(assemblyPath) is not { } entry)
{
_logger?.Invoke("No entry found for path '{0}' in archive '{1}'", assemblyPath, _archivePath);
continue;
}

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
25 changes: 25 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,29 @@ 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 GetArchivePathForArchitecture(this string archivePath, AndroidTargetArch arch, DebugLogger? logger)
{
return ArchToAbiMap.TryGetValue(arch, out var abi)
? GetArchivePathForAbi(archivePath, abi, logger)
: archivePath;
}

/// <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("-", "_");
var splitFilePath = Path.Combine(basePath, $"split_config.{abiPart}.apk");
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
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,58 @@
<MSBuild Projects="$(MSBuildProjectFile)" Targets="_BuildTestAPK" Condition="!$(TargetFramework.StartsWith('net8'))" Properties="_Aot=True;_Store=True;_Compressed=False" />
<MSBuild Projects="$(MSBuildProjectFile)" Targets="_BuildTestAPK" Condition="!$(TargetFramework.StartsWith('net8'))" Properties="_Aot=True;_Store=True;_Compressed=True" />
</Target>

<Target Name="_BuildTestAPK">
<PropertyGroup>
<_ConfigString>A=$(_Aot)-S=$(_Store)-C=$(_Compressed)</_ConfigString>
<SourceAPK>..\AndroidTestApp\bin\$(TargetFramework)\$(_ConfigString)\com.companyname.AndroidTestApp-Signed.apk</SourceAPK>
<DestinationAPK>TestAPKs\$(TargetFramework)-$(_ConfigString).apk</DestinationAPK>
<_AndroidTestAppOutputDir>..\AndroidTestApp\bin\$(TargetFramework)\$(_ConfigString)</_AndroidTestAppOutputDir>
<SourceAPK>$(_AndroidTestAppOutputDir)\com.companyname.AndroidTestApp-Signed.apk</SourceAPK>
</PropertyGroup>
<MSBuild Projects="..\AndroidTestApp\AndroidTestApp.csproj" Targets="Build" Properties="Configuration=Release;PublishAot=$(_Aot);_IsPublishing=true;RuntimeIdentifier=android-x64;AndroidUseAssemblyStore=$(_Store);AndroidEnableAssemblyCompression=$(_Compressed);OutDir=bin\$(TargetFramework)\$(_ConfigString)\" Condition="!Exists('$(DestinationAPK)')" />

<Message Text="Copying APK from $(SourceAPK) to $(DestinationAPK)" Importance="high" />
<MSBuild Projects="..\AndroidTestApp\AndroidTestApp.csproj" Targets="Build" Properties="Configuration=Release;PublishAot=$(_Aot);_IsPublishing=true;RuntimeIdentifier=android-x64;AndroidUseAssemblyStore=$(_Store);AndroidEnableAssemblyCompression=$(_Compressed);OutDir=bin\$(TargetFramework)\$(_ConfigString)\" Condition="!Exists('$(SourceAPK)')" />
</Target>

<Target Name="_CopyTestAPKNet8" AfterTargets="_BuildTestAPK" Condition="$(TargetFramework.StartsWith('net8'))">
<PropertyGroup>
<DestinationAPK>TestAPKs\$(TargetFramework)-$(_ConfigString).apk</DestinationAPK>
</PropertyGroup>
<Copy SourceFiles="$(SourceAPK)" DestinationFiles="$(DestinationAPK)" Condition="!Exists('$(DestinationAPK)')" />
</Target>

<Target Name="_CopyTestAPKNet9" AfterTargets="_BuildTestAPK" Condition="$(TargetFramework.StartsWith('net9'))">
<PropertyGroup>
<DestinationAPKExists Condition="Exists('$(DestinationAPK)')">True</DestinationAPKExists>
<DestinationAPKExists Condition="!Exists('$(DestinationAPK)')">False</DestinationAPKExists>
<_ToolsFolder>tools</_ToolsFolder>
<_BundleToolVersion>1.18.1</_BundleToolVersion>
<_BundleToolFile>bundletool-$(_BundleToolVersion).jar</_BundleToolFile>
<_BundleToolPath>$(_ToolsFolder)\$(_BundleToolFile)</_BundleToolPath>
<_SourceAab>$(_AndroidTestAppOutputDir)\com.companyname.AndroidTestApp-Signed.aab</_SourceAab>
<_SplitApksZip>$(_AndroidTestAppOutputDir)\split_config.apks</_SplitApksZip>
<_SplitApksDir>$(_AndroidTestAppOutputDir)\apks</_SplitApksDir>
</PropertyGroup>
<Message Text="APK copy result: Exists('$(DestinationAPK)') = $(DestinationAPKExists)" Importance="high" />

<DownloadFile
SourceUrl="https://github.com/google/bundletool/releases/download/$(_BundleToolVersion)/bundletool-all-$(_BundleToolVersion).jar"
DestinationFolder="$(_ToolsFolder)"
DestinationFileName="$(_BundleToolFile)"
Condition="!Exists('$(_BundleToolPath)')"
Retries="3"
/>

<Exec Command="java -jar $(_BundleToolPath) build-apks --device-spec=device-spec.json --bundle=$(_SourceAab) --output=$(_SplitApksZip)" Condition="Exists('$(_SourceAab)') and !Exists('$(_SplitApksZip)')" />

<ItemGroup>
<_ApksToExtract Include="$(_SplitApksZip)" />
</ItemGroup>

<Unzip SourceFiles="@(_ApksToExtract)"
DestinationFolder="$(_SplitApksDir)\"
Condition="'@(_ApksToExtract)' != ''" />

<ItemGroup>
<_SplitApks Include="$(_SplitApksDir)\splits\*.apk" />
</ItemGroup>

<Copy SourceFiles="@(_SplitApks)" DestinationFolder="TestAPKs\$(TargetFramework)-$(_ConfigString)\" SkipUnchangedFiles="true" />
</Target>

</Project>
11 changes: 11 additions & 0 deletions test/Sentry.Android.AssemblyReader.Tests/device-spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"supportedAbis": ["x86_64"],
"supportedLocales": ["en-US"],
"deviceFeatures": ["reqGlEsVersion\u003d0x30000", "android.hardware.audio.output", "android.hardware.biometrics.face", "android.hardware.bluetooth", "android.hardware.bluetooth_le", "android.hardware.camera", "android.hardware.camera.any", "android.hardware.camera.autofocus", "android.hardware.camera.capability.manual_post_processing", "android.hardware.camera.capability.manual_sensor", "android.hardware.camera.capability.raw", "android.hardware.camera.concurrent", "android.hardware.camera.flash", "android.hardware.camera.front", "android.hardware.camera.level.full", "android.hardware.faketouch", "android.hardware.fingerprint", "android.hardware.hardware_keystore\u003d300", "android.hardware.identity_credential\u003d202301", "android.hardware.keystore.app_attest_key", "android.hardware.location", "android.hardware.location.gps", "android.hardware.location.network", "android.hardware.microphone", "android.hardware.ram.normal", "android.hardware.reboot_escrow", "android.hardware.screen.landscape", "android.hardware.screen.portrait", "android.hardware.security.model.compatible", "android.hardware.sensor.accelerometer", "android.hardware.sensor.ambient_temperature", "android.hardware.sensor.barometer", "android.hardware.sensor.compass", "android.hardware.sensor.gyroscope", "android.hardware.sensor.light", "android.hardware.sensor.proximity", "android.hardware.sensor.relative_humidity", "android.hardware.telephony", "android.hardware.telephony.calling", "android.hardware.telephony.data", "android.hardware.telephony.gsm", "android.hardware.telephony.ims", "android.hardware.telephony.messaging", "android.hardware.telephony.radio.access", "android.hardware.telephony.subscription", "android.hardware.touchscreen", "android.hardware.touchscreen.multitouch", "android.hardware.touchscreen.multitouch.distinct", "android.hardware.touchscreen.multitouch.jazzhand", "android.hardware.vulkan.compute", "android.hardware.vulkan.level\u003d1", "android.hardware.vulkan.version\u003d4206592", "android.hardware.wifi", "android.hardware.wifi.direct", "android.hardware.wifi.passpoint", "android.software.activities_on_secondary_displays", "android.software.adoptable_storage", "android.software.app_enumeration", "android.software.app_widgets", "android.software.autofill", "android.software.backup", "android.software.cant_save_state", "android.software.companion_device_setup", "android.software.controls", "android.software.credentials", "android.software.cts", "android.software.device_admin", "android.software.device_lock", "android.software.erofs", "android.software.file_based_encryption", "android.software.home_screen", "android.software.incremental_delivery\u003d2", "android.software.input_methods", "android.software.ipsec_tunnel_migration", "android.software.ipsec_tunnels", "android.software.live_wallpaper", "android.software.managed_users", "android.software.midi", "android.software.opengles.deqp.level\u003d132645633", "android.software.picture_in_picture", "android.software.print", "android.software.secure_lock_screen", "android.software.securely_removes_users", "android.software.telecom", "android.software.verified_boot", "android.software.voice_recognizers", "android.software.vulkan.deqp.level\u003d132645633", "android.software.webview", "android.software.window_magnification", "com.google.android.apps.dialer.SUPPORTED", "com.google.android.feature.EXCHANGE_6_2", "com.google.android.feature.GOOGLE_BUILD", "com.google.android.feature.GOOGLE_EXPERIENCE", "com.google.android.feature.WELLBEING"],
"glExtensions": ["GL_EXT_debug_marker", "GL_EXT_robustness", "GL_OES_EGL_sync", "GL_OES_EGL_image", "GL_OES_EGL_image_external", "GL_OES_depth24", "GL_OES_depth32", "GL_OES_element_index_uint", "GL_OES_texture_float", "GL_OES_texture_float_linear", "GL_OES_compressed_paletted_texture", "GL_OES_compressed_ETC1_RGB8_texture", "GL_OES_depth_texture", "GL_OES_texture_npot", "GL_OES_rgb8_rgba8", "GL_EXT_color_buffer_float", "GL_EXT_color_buffer_half_float", "GL_EXT_texture_format_BGRA8888", "GL_APPLE_texture_format_BGRA8888", "ANDROID_EMU_CHECKSUM_HELPER_v1", "ANDROID_EMU_native_sync_v2", "ANDROID_EMU_native_sync_v3", "ANDROID_EMU_native_sync_v4", "ANDROID_EMU_dma_v1", "ANDROID_EMU_host_composition_v1", "ANDROID_EMU_host_composition_v2", "ANDROID_EMU_vulkan", "ANDROID_EMU_deferred_vulkan_commands", "ANDROID_EMU_vulkan_null_optional_strings", "ANDROID_EMU_vulkan_create_resources_with_requirements", "ANDROID_EMU_YUV_Cache", "ANDROID_EMU_vulkan_ignored_handles", "ANDROID_EMU_has_shared_slots_host_memory_allocator", "ANDROID_EMU_vulkan_free_memory_sync", "ANDROID_EMU_vulkan_shader_float16_int8", "ANDROID_EMU_vulkan_async_queue_submit", "ANDROID_EMU_vulkan_queue_submit_with_commands", "ANDROID_EMU_sync_buffer_data", "ANDROID_EMU_vulkan_async_qsri", "ANDROID_EMU_hwc_multi_configs", "GL_OES_EGL_image_external_essl3", "GL_OES_vertex_array_object", "ANDROID_EMU_host_side_tracing", "ANDROID_EMU_gles_max_version_3_0"],
"screenDensity": 420,
"sdkVersion": 35,
"sdkRuntime": {
"supported": true
}
}
Loading