Skip to content

Only enable load debug image integration for obfuscated apps #2907

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
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
4fa09ee
Update
buenaflor May 5, 2025
9015295
Update
buenaflor May 5, 2025
6142497
add initial impl
buenaflor May 6, 2025
63b5ed2
Update
buenaflor May 7, 2025
acc4f93
Update mocks
buenaflor May 8, 2025
210c451
Formatting
buenaflor May 8, 2025
7920bf6
Update searching for debug id
buenaflor May 8, 2025
68284ff
Update
buenaflor May 8, 2025
138f6e2
Update
buenaflor May 8, 2025
966a5c7
Revert main
buenaflor May 8, 2025
ed3c45a
Improve readability
buenaflor May 8, 2025
d722722
Return unmodifiable
buenaflor May 8, 2025
90e80ce
Merge branch 'main' into feat-web/debug-id
buenaflor May 8, 2025
190672d
Update CHANGELOG
buenaflor May 8, 2025
f5e3a89
Update web_load_debug_images_integration.dart
buenaflor May 8, 2025
80198f4
Update
buenaflor May 8, 2025
ce76820
Improve
buenaflor May 12, 2025
14a1ce1
Update naming
buenaflor May 12, 2025
3a7db1a
Add additional test
buenaflor May 12, 2025
6d0e7e1
Update test
buenaflor May 12, 2025
d17a450
Merge branch 'main' into feat-web/debug-id
buenaflor May 12, 2025
4576340
Update debug id impl
buenaflor May 12, 2025
f98a03e
Update
buenaflor May 12, 2025
d143766
Update
buenaflor May 12, 2025
7ea5ebd
Merge branch 'feat-web/debug-id' into chore/only-add-load-debug-image…
denrase May 26, 2025
7f65ab7
rename processors to match integration names
denrase May 26, 2025
1d7d42c
update condition, update naming of processors
denrase May 26, 2025
44ddbad
add cl entry
denrase May 26, 2025
b0cee7d
Update runtime_checker.dart
buenaflor Jun 12, 2025
ee6d449
Rename
buenaflor Jun 12, 2025
ea357f9
Fix analyze
buenaflor Jun 12, 2025
a76ebe3
Merge branch 'feat-web/debug-id' into chore/only-add-load-debug-image…
buenaflor Jun 12, 2025
b4e9bd3
Merge branch 'main' into feat-web/debug-id
buenaflor Jun 17, 2025
a47d886
Fix log
buenaflor Jun 17, 2025
92381f5
Merge branch 'feat-web/debug-id' into chore/only-add-load-debug-image…
denrase Jun 18, 2025
f1215c6
dont add on web
denrase Jun 18, 2025
c7357b1
fix cl
denrase Jun 18, 2025
7317f53
Fix test
buenaflor Jun 18, 2025
51bb735
Merge branch 'main' into feat-web/debug-id
buenaflor Jun 18, 2025
8a6c412
update
buenaflor Jun 18, 2025
d494b81
Fix test
buenaflor Jun 18, 2025
36dea6f
Formatting
buenaflor Jun 18, 2025
9eed114
Merge branch 'feat-web/debug-id' into chore/only-add-load-debug-image…
buenaflor Jun 20, 2025
067e92a
Merge branch 'main' into chore/only-add-load-debug-image-integration-…
buenaflor Jun 20, 2025
e3613b1
Update
buenaflor Jun 20, 2025
1ade42f
Update
buenaflor Jun 20, 2025
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ void initState() {
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#090)
- [diff](https://github.com/getsentry/sentry-native/compare/0.8.4...0.9.0)

### Enhancements

- Only enable load debug image integration for obfuscated apps ([#2907](https://github.com/getsentry/sentry-dart/pull/2907))

## 9.0.0

Version 9.0.0 marks a major release of the Sentry Dart/Flutter SDKs containing breaking changes.
Expand Down
13 changes: 8 additions & 5 deletions dart/lib/src/load_dart_debug_images_integration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@ import 'protocol/sentry_stack_trace.dart';
import 'sentry_options.dart';

class LoadDartDebugImagesIntegration extends Integration<SentryOptions> {
static const integrationName = 'LoadDartDebugImagesIntegration';
static const integrationName = 'LoadDartDebugImages';

@override
void call(Hub hub, SentryOptions options) {
if (options.enableDartSymbolication) {
options.addEventProcessor(LoadImageIntegrationEventProcessor(options));
if (options.enableDartSymbolication &&
options.runtimeChecker.isAppObfuscated() &&
!options.platform.isWeb) {
options.addEventProcessor(
LoadDartDebugImagesIntegrationEventProcessor(options));
options.sdk.addIntegration(integrationName);
}
}
}

@internal
class LoadImageIntegrationEventProcessor implements EventProcessor {
LoadImageIntegrationEventProcessor(this._options);
class LoadDartDebugImagesIntegrationEventProcessor implements EventProcessor {
LoadDartDebugImagesIntegrationEventProcessor(this._options);

final SentryOptions _options;

Expand Down
9 changes: 9 additions & 0 deletions dart/lib/src/runtime_checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ class RuntimeChecker {
return const bool.fromEnvironment('dart.vm.profile', defaultValue: false);
}

/// Check if the Dart code is obfuscated.
bool isAppObfuscated() {
// In non-obfuscated builds, this will return "RuntimeChecker"
// In obfuscated builds, this will return something like "a" or other short identifier
// Note: Flutter Web production builds will always be minified / "obfuscated".
final typeName = runtimeType.toString();
return !typeName.contains('RuntimeChecker');
}

final bool isRootZone;

String get compileMode {
Expand Down
40 changes: 37 additions & 3 deletions dart/test/load_dart_debug_images_integration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:sentry/src/platform/mock_platform.dart';
import 'package:sentry/src/sentry_stack_trace_factory.dart';
import 'package:test/test.dart';

import 'mocks/mock_runtime_checker.dart';
import 'test_utils.dart';

void main() {
Expand All @@ -26,6 +27,7 @@ void main() {
setUp(() {
fixture = Fixture();
fixture.options.platform = platform;
fixture.callIntegration();
});

test('adds itself to sdk.integrations', () {
Expand All @@ -40,7 +42,7 @@ void main() {
expect(fixture.options.eventProcessors.length, 1);
expect(
fixture.options.eventProcessors.first.runtimeType.toString(),
'LoadImageIntegrationEventProcessor',
'LoadDartDebugImagesIntegrationEventProcessor',
);
});

Expand Down Expand Up @@ -191,8 +193,39 @@ isolate_dso_base: 10000000
});
}

test('does not add itself to sdk.integrations if app is not obfuscated', () {
final fixture = Fixture()
..options.runtimeChecker = MockRuntimeChecker(isObfuscated: false);
fixture.callIntegration();
expect(
fixture.options.sdk.integrations
.contains(LoadDartDebugImagesIntegration.integrationName),
false,
);
});

test('does not add event processor to options if app is not obfuscated', () {
final fixture = Fixture()
..options.runtimeChecker = MockRuntimeChecker(isObfuscated: false);
fixture.callIntegration();
expect(fixture.options.eventProcessors.length, 0);
});

test('does not add itself to sdk.integrations if platform is web', () {
final fixture = Fixture()
..options.runtimeChecker = MockRuntimeChecker(isObfuscated: true)
..options.platform = MockPlatform(isWeb: true);
fixture.callIntegration();
expect(
fixture.options.sdk.integrations
.contains(LoadDartDebugImagesIntegration.integrationName),
false,
);
});

test('debug image is null on unsupported platforms', () async {
final fixture = Fixture()..options.platform = MockPlatform.linux();
fixture.callIntegration();
final event = fixture.newEvent(stackTrace: fixture.parse('''
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
build_id: 'b680cb890f9e3c12a24b172d050dec73'
Expand All @@ -205,10 +238,11 @@ isolate_dso_base: 40000000
}

class Fixture {
final options = defaultTestOptions();
final options = defaultTestOptions()
..runtimeChecker = MockRuntimeChecker(isObfuscated: true);
late final factory = SentryStackTraceFactory(options);

Fixture() {
void callIntegration() {
final integration = LoadDartDebugImagesIntegration();
integration.call(Hub(options), options);
}
Expand Down
5 changes: 5 additions & 0 deletions dart/test/mocks/mock_runtime_checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ class MockRuntimeChecker extends RuntimeChecker with NoSuchMethodProvider {
this.isDebug = false,
this.isProfile = false,
this.isRelease = false,
this.isObfuscated = false,
bool isRootZone = true,
}) : super(isRootZone: isRootZone);

final bool isDebug;
final bool isProfile;
final bool isRelease;
final bool isObfuscated;

@override
bool isDebugMode() => isDebug;
Expand All @@ -22,4 +24,7 @@ class MockRuntimeChecker extends RuntimeChecker with NoSuchMethodProvider {

@override
bool isReleaseMode() => isRelease;

@override
bool isAppObfuscated() => isObfuscated;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,25 @@ class LoadNativeDebugImagesIntegration

@override
void call(Hub hub, SentryFlutterOptions options) {
options.addEventProcessor(
_LoadImageListIntegrationEventProcessor(options, _native),
);
options.sdk.addIntegration(integrationName);
// ignore: invalid_use_of_internal_member
if (options.runtimeChecker.isAppObfuscated()) {
options.addEventProcessor(
_LoadNativeDebugImagesIntegrationEventProcessor(options, _native),
);
options.sdk.addIntegration(integrationName);
}
}
}

class _LoadImageListIntegrationEventProcessor implements EventProcessor {
_LoadImageListIntegrationEventProcessor(this._options, this._native);
class _LoadNativeDebugImagesIntegrationEventProcessor
implements EventProcessor {
_LoadNativeDebugImagesIntegrationEventProcessor(this._options, this._native);

final SentryFlutterOptions _options;
final SentryNativeBinding _native;

late final _dartProcessor = LoadImageIntegrationEventProcessor(_options);
late final _dartProcessor =
LoadDartDebugImagesIntegrationEventProcessor(_options);

@override
Future<SentryEvent?> apply(SentryEvent event, Hint hint) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:mockito/mockito.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:sentry_flutter/src/integrations/native_load_debug_images_integration.dart';

import '../mocks.dart';
import 'fixture.dart';

void main() {
Expand All @@ -26,6 +27,7 @@ void main() {

setUp(() async {
fixture = IntegrationTestFixture(LoadNativeDebugImagesIntegration.new);
fixture.options.runtimeChecker = MockRuntimeChecker(isObfuscated: true);
when(fixture.binding.loadDebugImages(any))
.thenAnswer((_) async => imageList.toList());
await fixture.registerIntegration();
Expand Down Expand Up @@ -73,8 +75,8 @@ void main() {

test('Event processor adds image list to the event', () async {
final ep = fixture.options.eventProcessors.first;
expect(
ep.runtimeType.toString(), "_LoadImageListIntegrationEventProcessor");
expect(ep.runtimeType.toString(),
"_LoadNativeDebugImagesIntegrationEventProcessor");
SentryEvent? event = _getEvent();
event = await ep.apply(event, Hint());

Expand Down Expand Up @@ -104,6 +106,28 @@ void main() {
verifyNever(fixture.binding.loadDebugImages(any));
});
});

test('does not add itself to sdk.integrations if app is not obfuscated',
() async {
final fixture =
IntegrationTestFixture(LoadNativeDebugImagesIntegration.new);
fixture.options.runtimeChecker = MockRuntimeChecker();
await fixture.registerIntegration();
expect(
fixture.options.sdk.integrations
.contains(LoadNativeDebugImagesIntegration.integrationName),
false,
);
});

test('does not add event processor to options if app is not obfuscated',
() async {
final fixture =
IntegrationTestFixture(LoadNativeDebugImagesIntegration.new);
fixture.options.runtimeChecker = MockRuntimeChecker();
await fixture.registerIntegration();
expect(fixture.options.eventProcessors.length, 0);
});
}

SentryEvent _getEvent() {
Expand Down
5 changes: 5 additions & 0 deletions flutter/test/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ void main() {}
class MockRuntimeChecker with NoSuchMethodProvider implements RuntimeChecker {
MockRuntimeChecker({
this.buildMode = MockRuntimeCheckerBuildMode.debug,
this.isObfuscated = false,
this.isRoot = true,
});

final MockRuntimeCheckerBuildMode buildMode;
final bool isObfuscated;
final bool isRoot;

@override
Expand All @@ -94,6 +96,9 @@ class MockRuntimeChecker with NoSuchMethodProvider implements RuntimeChecker {
@override
bool isReleaseMode() => buildMode == MockRuntimeCheckerBuildMode.release;

@override
bool isAppObfuscated() => isObfuscated;

@override
bool get isRootZone => isRoot;
}
Expand Down
Loading