Skip to content

Commit 44992bd

Browse files
adinauerclaude
andcommitted
fix(android): Preserve installation ID independently of Data Collection
Keep the Android installation ID available for distinct ID, user ID, device ID, and hybrid scope fallbacks regardless of the userInfo setting. Continue applying userInfo only to automatic user details such as IP addresses and remove the now-unused legacy-always resolver variant. Refs #5666 Co-Authored-By: Claude <noreply@anthropic.com>
1 parent ec07c59 commit 44992bd

13 files changed

Lines changed: 21 additions & 47 deletions

sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ private void mergeUser(final @NotNull SentryBaseEvent event) {
568568
}
569569

570570
// userId should be set even if event is Cached as the userId is static and won't change anyway.
571-
if (user.getId() == null && options.getDataCollectionResolver().isUserInfoWithLegacyAlways()) {
571+
if (user.getId() == null) {
572572
user.setId(getDeviceId());
573573
}
574574
if (user.getIpAddress() == null && options.getDataCollectionResolver().isUserInfo()) {
@@ -635,8 +635,7 @@ private void setDevice(final @NotNull SentryBaseEvent event) {
635635
device.setScreenDpi(displayMetrics.densityDpi);
636636
}
637637

638-
if (device.getId() == null
639-
&& options.getDataCollectionResolver().isUserInfoWithLegacyAlways()) {
638+
if (device.getId() == null) {
640639
device.setId(getDeviceId());
641640
}
642641

sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ private void mergeUser(final @NotNull SentryBaseEvent event) {
175175
}
176176

177177
// userId should be set even if event is Cached as the userId is static and won't change anyway.
178-
if (user.getId() == null && options.getDataCollectionResolver().isUserInfoWithLegacyAlways()) {
178+
if (user.getId() == null) {
179179
user.setId(Installation.id(context));
180180
}
181181
if (user.getIpAddress() == null && options.getDataCollectionResolver().isUserInfo()) {
@@ -374,9 +374,7 @@ private void setAppExtras(final @NotNull App app, final @NotNull Hint hint) {
374374
*/
375375
public @NotNull User getDefaultUser(final @NotNull Context context) {
376376
final @NotNull User user = new User();
377-
if (options.getDataCollectionResolver().isUserInfoWithLegacyAlways()) {
378-
user.setId(Installation.id(context));
379-
}
377+
user.setId(Installation.id(context));
380378
return user;
381379
}
382380

sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,7 @@ public Device collectDeviceInformation(
109109
device.setBootTime(getBootTime());
110110
device.setTimezone(getTimeZone());
111111

112-
if (device.getId() == null
113-
&& options.getDataCollectionResolver().isUserInfoWithLegacyAlways()) {
112+
if (device.getId() == null) {
114113
device.setId(getDeviceId());
115114
}
116115

sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ public static Map<String, Object> serializeScope(
9999
user = new User();
100100
scope.setUser(user);
101101
}
102-
if (user.getId() == null
103-
&& options.getDataCollectionResolver().isUserInfoWithLegacyAlways()) {
102+
if (user.getId() == null) {
104103
try {
105104
user.setId(Installation.id(context));
106105
} catch (RuntimeException e) {

sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,7 @@ public static void init(
149149
"Error in the 'OptionsConfiguration.configure' callback.",
150150
t);
151151
}
152-
if (options.getDistinctId() == null
153-
&& options.getDataCollectionResolver().isUserInfoWithLegacyAlways()) {
152+
if (options.getDistinctId() == null) {
154153
try {
155154
options.setDistinctId(Installation.id(context));
156155
} catch (RuntimeException e) {

sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,7 @@ class AndroidOptionsInitializerTest {
111111
)
112112

113113
sentryOptions.configureOptions()
114-
if (
115-
sentryOptions.distinctId == null &&
116-
sentryOptions.dataCollectionResolver.isUserInfoWithLegacyAlways
117-
) {
114+
if (sentryOptions.distinctId == null) {
118115
sentryOptions.distinctId = Installation.id(if (useRealContext) context else mockContext)
119116
}
120117
AndroidOptionsInitializer.initializeIntegrationsAndProcessors(
@@ -356,10 +353,10 @@ class AndroidOptionsInitializerTest {
356353
}
357354

358355
@Test
359-
fun `init should not set generated distinct id when user info is disabled`() {
356+
fun `init should set generated distinct id when user info is disabled`() {
360357
fixture.initSut(configureOptions = { dataCollection.setUserInfo(false) })
361358

362-
assertNull(fixture.sentryOptions.distinctId)
359+
assertNotNull(fixture.sentryOptions.distinctId)
363360
}
364361

365362
@Test

sentry-android-core/src/test/java/io/sentry/android/core/ApplicationExitInfoEventProcessorTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,13 +228,13 @@ class ApplicationExitInfoEventProcessorTest {
228228
}
229229

230230
@Test
231-
fun `when user info is disabled, does not set device id`() {
231+
fun `when user info is disabled, sets device id`() {
232232
fixture.options.dataCollection.setUserInfo(false)
233233
val hint = HintUtils.createWithTypeCheckHint(AbnormalExitHint())
234234

235235
val processed = processEvent(hint)
236236

237-
assertNull(processed.contexts.device!!.id)
237+
assertNotNull(processed.contexts.device!!.id)
238238
}
239239

240240
@Test
@@ -477,7 +477,7 @@ class ApplicationExitInfoEventProcessorTest {
477477
}
478478

479479
@Test
480-
fun `when user info is disabled, does not set installation id for missing user id`() {
480+
fun `when user info is disabled, sets installation id for missing user id`() {
481481
fixture.options.dataCollection.setUserInfo(false)
482482
val hint = HintUtils.createWithTypeCheckHint(BackfillableHint())
483483
val original = SentryEvent()
@@ -486,7 +486,7 @@ class ApplicationExitInfoEventProcessorTest {
486486

487487
val processed = processor.process(original, hint)
488488

489-
assertNull(processed!!.user!!.id)
489+
assertEquals(Installation.deviceId, processed!!.user!!.id)
490490
}
491491

492492
@Test

sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,15 +285,15 @@ class DefaultAndroidEventProcessorTest {
285285
}
286286

287287
@Test
288-
fun `when user info is disabled, does not set automatic user data`() {
288+
fun `when user info is disabled, sets installation id but not automatic ip`() {
289289
fixture.options.dataCollection.setUserInfo(false)
290290
val sut = fixture.getSut(context, isSendDefaultPii = true)
291291
val event = SentryEvent().apply { user = User() }
292292

293293
sut.process(event, Hint())
294294

295295
assertNotNull(event.user) {
296-
assertNull(it.id)
296+
assertNotNull(it.id)
297297
assertNull(it.ipAddress)
298298
}
299299
}

sentry-android-core/src/test/java/io/sentry/android/core/DeviceInfoUtilTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class DeviceInfoUtilTest {
7070
assertNotNull(enabledDevice.id)
7171
assertNotNull(enabledDevice.storageSize)
7272
assertNotNull(enabled.operatingSystem.isRooted)
73-
assertNull(disabledDevice.id)
73+
assertNotNull(disabledDevice.id)
7474
assertNull(disabledDevice.storageSize)
7575
assertNull(disabled.operatingSystem.isRooted)
7676
}
@@ -94,12 +94,12 @@ class DeviceInfoUtilTest {
9494
}
9595

9696
@Test
97-
fun `does not set device id when user info is disabled`() {
97+
fun `sets device id when user info is disabled`() {
9898
val options = SentryAndroidOptions().apply { dataCollection.setUserInfo(false) }
9999
val deviceInfo =
100100
DeviceInfoUtil.getInstance(context, options).collectDeviceInformation(false, false)
101101

102-
assertNull(deviceInfo.id)
102+
assertNotNull(deviceInfo.id)
103103
}
104104

105105
@Test

sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import java.util.concurrent.atomic.AtomicReference
3838
import kotlin.test.BeforeTest
3939
import kotlin.test.Test
4040
import kotlin.test.assertEquals
41-
import kotlin.test.assertFalse
4241
import kotlin.test.assertNotEquals
4342
import kotlin.test.assertNotNull
4443
import kotlin.test.assertNull
@@ -327,14 +326,14 @@ class InternalSentrySdkTest {
327326
}
328327

329328
@Test
330-
fun `serializeScope does not provide fallback user id when user info is disabled`() {
329+
fun `serializeScope provides fallback user id when user info is disabled`() {
331330
val options = SentryAndroidOptions().apply { dataCollection.setUserInfo(false) }
332331
val scope = Scope(options)
333332
scope.user = null
334333

335334
val serializedScope = InternalSentrySdk.serializeScope(context, options, scope)
336335

337-
assertFalse((serializedScope["user"] as Map<*, *>).containsKey("id"))
336+
assertTrue((serializedScope["user"] as Map<*, *>).containsKey("id"))
338337
}
339338

340339
@Test

0 commit comments

Comments
 (0)