Skip to content

Commit

Permalink
Merge 5bc4a9a into f274c79
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanosiano committed Jul 7, 2023
2 parents f274c79 + 5bc4a9a commit dbcee0c
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 34 deletions.
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

- Allow removing integrations in SentryAndroid.init ([#2826](https://github.com/getsentry/sentry-java/pull/2826))

## 6.25.0

### Features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,41 +100,30 @@ static void loadDefaultAndMetadataOptions(

@TestOnly
static void initializeIntegrationsAndProcessors(
final @NotNull SentryAndroidOptions options, final @NotNull Context context) {
final @NotNull SentryAndroidOptions options,
final @NotNull Context context,
final @NotNull LoadClass loadClass,
final @NotNull ActivityFramesTracker activityFramesTracker) {
initializeIntegrationsAndProcessors(
options,
context,
new BuildInfoProvider(new AndroidLogger()),
new LoadClass(),
false,
false);
loadClass,
activityFramesTracker);
}

static void initializeIntegrationsAndProcessors(
final @NotNull SentryAndroidOptions options,
final @NotNull Context context,
final @NotNull BuildInfoProvider buildInfoProvider,
final @NotNull LoadClass loadClass,
final boolean isFragmentAvailable,
final boolean isTimberAvailable) {
final @NotNull ActivityFramesTracker activityFramesTracker) {

if (options.getCacheDirPath() != null
&& options.getEnvelopeDiskCache() instanceof NoOpEnvelopeCache) {
options.setEnvelopeDiskCache(new AndroidEnvelopeCache(options));
}

final ActivityFramesTracker activityFramesTracker =
new ActivityFramesTracker(loadClass, options);

installDefaultIntegrations(
context,
options,
buildInfoProvider,
loadClass,
activityFramesTracker,
isFragmentAvailable,
isTimberAvailable);

options.addEventProcessor(
new DefaultAndroidEventProcessor(context, buildInfoProvider, options));
options.addEventProcessor(new PerformanceAndroidEventProcessor(options, activityFramesTracker));
Expand Down Expand Up @@ -192,7 +181,7 @@ static void initializeIntegrationsAndProcessors(
}
}

private static void installDefaultIntegrations(
static void installDefaultIntegrations(
final @NotNull Context context,
final @NotNull SentryAndroidOptions options,
final @NotNull BuildInfoProvider buildInfoProvider,
Expand All @@ -201,6 +190,9 @@ private static void installDefaultIntegrations(
final boolean isFragmentAvailable,
final boolean isTimberAvailable) {

// Integration MUST NOT cache option values in ctor, as they will be configured later by the
// user

// read the startup crash marker here to avoid doing double-IO for the SendCachedEnvelope
// integrations below
final boolean hasStartupCrashMarker = AndroidEnvelopeCache.hasStartupCrashMarker(options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,29 @@ public static synchronized void init(

final BuildInfoProvider buildInfoProvider = new BuildInfoProvider(logger);
final LoadClass loadClass = new LoadClass();
final ActivityFramesTracker activityFramesTracker =
new ActivityFramesTracker(loadClass, options);

AndroidOptionsInitializer.loadDefaultAndMetadataOptions(
options, context, logger, buildInfoProvider);

configuration.configure(options);

AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
options,
// We install the default integrations before the option configuration, so that the user
// can remove any of them. Integrations will not evaluate the options immediately, but
// will use them later, after being configured.
AndroidOptionsInitializer.installDefaultIntegrations(
context,
options,
buildInfoProvider,
loadClass,
activityFramesTracker,
isFragmentAvailable,
isTimberAvailable);

configuration.configure(options);

AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
options, context, buildInfoProvider, loadClass, activityFramesTracker);

deduplicateIntegrations(options, isFragmentAvailable, isTimberAvailable);
},
true);
Expand Down Expand Up @@ -151,7 +160,7 @@ public static synchronized void init(

/**
* Deduplicate potentially duplicated Fragment and Timber integrations, which can be added
* automatically by our SDK as well as by the user. The user's ones (provided first in the
* automatically by our SDK as well as by the user. The user's ones (provided last in the
* options.integrations list) win over ours.
*
* @param options SentryOptions to retrieve integrations from
Expand All @@ -178,14 +187,14 @@ private static void deduplicateIntegrations(
}

if (fragmentIntegrations.size() > 1) {
for (int i = 1; i < fragmentIntegrations.size(); i++) {
for (int i = 0; i < fragmentIntegrations.size() - 1; i++) {
final Integration integration = fragmentIntegrations.get(i);
options.getIntegrations().remove(integration);
}
}

if (timberIntegrations.size() > 1) {
for (int i = 1; i < timberIntegrations.size(); i++) {
for (int i = 0; i < timberIntegrations.size() - 1; i++) {
final Integration integration = timberIntegrations.get(i);
options.getIntegrations().remove(integration);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,26 @@ class AndroidOptionsInitializerTest {
sentryOptions,
if (useRealContext) context else mockContext
)

val loadClass = LoadClass()
val activityFramesTracker = ActivityFramesTracker(loadClass, sentryOptions)

AndroidOptionsInitializer.installDefaultIntegrations(
if (useRealContext) context else mockContext,
sentryOptions,
BuildInfoProvider(AndroidLogger()),
loadClass,
activityFramesTracker,
false,
false
)

sentryOptions.configureOptions()
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
sentryOptions,
if (useRealContext) context else mockContext
if (useRealContext) context else mockContext,
loadClass,
activityFramesTracker
)
}

Expand All @@ -89,21 +105,33 @@ class AndroidOptionsInitializerTest {
)
sentryOptions.isDebug = true
val buildInfo = createBuildInfo(minApi)
val loadClass = createClassMock(classesToLoad)
val activityFramesTracker = ActivityFramesTracker(loadClass, sentryOptions)

AndroidOptionsInitializer.loadDefaultAndMetadataOptions(
sentryOptions,
context,
logger,
buildInfo
)
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
sentryOptions,

AndroidOptionsInitializer.installDefaultIntegrations(
context,
sentryOptions,
buildInfo,
createClassMock(classesToLoad),
loadClass,
activityFramesTracker,
isFragmentAvailable,
isTimberAvailable
)

AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
sentryOptions,
context,
buildInfo,
loadClass,
activityFramesTracker
)
}

private fun createBuildInfo(minApi: Int = 16): BuildInfoProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,32 @@ class AndroidTransactionProfilerTest {
fun `set up`() {
context = ApplicationProvider.getApplicationContext()
val buildInfoProvider = BuildInfoProvider(fixture.mockLogger)
val loadClass = LoadClass()
val activityFramesTracker = ActivityFramesTracker(loadClass, fixture.options)
AndroidOptionsInitializer.loadDefaultAndMetadataOptions(
fixture.options,
context,
fixture.mockLogger,
buildInfoProvider
)
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
fixture.options,

AndroidOptionsInitializer.installDefaultIntegrations(
context,
fixture.options,
buildInfoProvider,
LoadClass(),
loadClass,
activityFramesTracker,
false,
false
)

AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
fixture.options,
context,
buildInfoProvider,
loadClass,
activityFramesTracker
)
// Profiler doesn't start if the folder doesn't exists.
// Usually it's generated when calling Sentry.init, but for tests we can create it manually.
File(fixture.options.profilingTracesDirPath!!).mkdirs()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.sentry.android.core

import android.app.ActivityManager
import android.app.Application
import android.app.ApplicationExitInfo
import android.content.Context
import android.os.Bundle
Expand All @@ -17,6 +18,8 @@ import io.sentry.SentryLevel.FATAL
import io.sentry.SentryOptions
import io.sentry.SentryOptions.BeforeSendCallback
import io.sentry.Session
import io.sentry.ShutdownHookIntegration
import io.sentry.UncaughtExceptionHandlerIntegration
import io.sentry.android.core.cache.AndroidEnvelopeCache
import io.sentry.android.fragment.FragmentLifecycleIntegration
import io.sentry.android.timber.SentryTimberIntegration
Expand Down Expand Up @@ -388,6 +391,36 @@ class SentryAndroidTest {
)
}

@Test
fun `init can remove all integrations`() {
lateinit var optionsRef: SentryOptions
fixture.initSut(context = mock<Application>()) { options ->
optionsRef = options
options.dsn = "https://key@sentry.io/123"
assertEquals(18, options.integrations.size)
options.integrations.removeAll {
it is UncaughtExceptionHandlerIntegration ||
it is ShutdownHookIntegration ||
it is SendCachedEnvelopeIntegration ||
it is NdkIntegration ||
it is EnvelopeFileObserverIntegration ||
it is AppLifecycleIntegration ||
it is AnrIntegration ||
it is ActivityLifecycleIntegration ||
it is CurrentActivityIntegration ||
it is UserInteractionIntegration ||
it is FragmentLifecycleIntegration ||
it is SentryTimberIntegration ||
it is AppComponentsBreadcrumbsIntegration ||
it is SystemEventsBreadcrumbsIntegration ||
it is NetworkBreadcrumbsIntegration ||
it is TempSensorBreadcrumbsIntegration ||
it is PhoneStateBreadcrumbsIntegration
}
}
assertEquals(0, optionsRef.integrations.size)
}

private fun prefillScopeCache(cacheDir: String) {
val scopeDir = File(cacheDir, SCOPE_CACHE).also { it.mkdirs() }
File(scopeDir, BREADCRUMBS_FILENAME).writeText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,20 @@ class SentryInitProviderTest {
metaData.putBoolean(ManifestMetadataReader.NDK_ENABLE, false)

AndroidOptionsInitializer.loadDefaultAndMetadataOptions(sentryOptions, mockContext)
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(sentryOptions, mockContext)

val loadClass = LoadClass()
val activityFramesTracker = ActivityFramesTracker(loadClass, sentryOptions)
AndroidOptionsInitializer.installDefaultIntegrations(
mockContext,
sentryOptions,
BuildInfoProvider(AndroidLogger()),
loadClass,
activityFramesTracker,
false,
false
)

AndroidOptionsInitializer.initializeIntegrationsAndProcessors(sentryOptions, mockContext, loadClass, activityFramesTracker)

assertFalse(sentryOptions.isEnableNdk)
}
Expand Down

0 comments on commit dbcee0c

Please sign in to comment.