snowplow / snowplow-android-tracker

Snowplow event tracker for Android. Add analytics to your Android apps and games
http://snowplowanalytics.com
Apache License 2.0
109 stars 63 forks source link

Can't create a tracker with an Application context #657

Closed eygraber closed 5 months ago

eygraber commented 9 months ago

Describe the bug When calling Snowplow.createTracker with a Context retrieved from Application.applicationContext, sending an event logs an error, and no events are sent:

Tried to access visual service WindowManager from a non-visual Context:com.myapp.MyApp@50529e1 WindowManager should be accessed from Activity or other visual Context. Use an Activity or a Context created with Context#createWindowContext(int, Bundle), which are adjusted to the configuration and visual bounds of an area on screen.
                 java.lang.IllegalAccessException: Tried to access visual service WindowManager from a non-visual Context:com.myapp.MyApp@50529e1
                    at android.app.ContextImpl.getSystemService(ContextImpl.java:2207)
                    at android.content.ContextWrapper.getSystemService(ContextWrapper.java:934)
                    at com.snowplowanalytics.core.tracker.Subject.setDefaultScreenResolution(Subject.kt:228)
                    at com.snowplowanalytics.core.tracker.Subject.<init>(Subject.kt:185)
                    at com.snowplowanalytics.core.tracker.ServiceProvider.makeSubject(ServiceProvider.kt:222)
                    at com.snowplowanalytics.core.tracker.ServiceProvider.getOrMakeSubject(ServiceProvider.kt:181)
                    at com.snowplowanalytics.core.tracker.ServiceProvider.makeTracker(ServiceProvider.kt:259)
                    at com.snowplowanalytics.core.tracker.ServiceProvider.getOrMakeTracker(ServiceProvider.kt:189)
                    at com.snowplowanalytics.core.tracker.ServiceProvider.<init>(ServiceProvider.kt:87)
                    at com.snowplowanalytics.snowplow.Snowplow.createTracker(Snowplow.kt:275)

To Reproduce

  private val networkConfig = NetworkConfiguration(
    endpoint = "...",
    method = HttpMethod.POST
  )

  private val trackerConfig =
    TrackerConfiguration("my-namespace")
      .applicationContext(true)
      .base64encoding(false)
      .deepLinkContext(true)
      .diagnosticAutotracking(false)
      .exceptionAutotracking(true)
      .geoLocationContext(false)
      .installAutotracking(true)
      .lifecycleAutotracking(true)
      .platformContext(true)
      .platformContextProperties(
        listOf(
          PlatformContextProperty.AVAILABLE_STORAGE,
          PlatformContextProperty.BATTERY_LEVEL,
          PlatformContextProperty.BATTERY_STATE,
          PlatformContextProperty.LANGUAGE,
          PlatformContextProperty.NETWORK_TYPE,
          PlatformContextProperty.NETWORK_TECHNOLOGY,
          PlatformContextProperty.SYSTEM_AVAILABLE_MEMORY
        )
      )
      .screenContext(true)
      .screenViewAutotracking(false)
      .sessionContext(true)

  private val sessionConfig = SessionConfiguration(
    foregroundTimeout = TimeMeasure(30, TimeUnit.MINUTES),
    backgroundTimeout = TimeMeasure(30, TimeUnit.MINUTES)
  )

  private val tracker by lazy {
    Snowplow.createTracker(
      context = context,
      namespace = "my-namespace",
      network = networkConfig,
      trackerConfig,
      sessionConfig
    )
  }

Expected behavior Not to get this error.

Device informatoin (please complete the following information):

Additional context I tried downgrading to v5.0.0 and the issue is still present there. I also tried on Android versions down to API 30

matus-tomlein commented 9 months ago

Hi @eygraber, thanks for reporting this!

We have seen this before in relation to using the tracker through dependency injection with Hilt. Do you by any chance also use Hilt?

The error seems to come from the way that the screen resolution is fetched in Subject. We will change this in the upcoming version 6 of the tracker to match how we retrieve the resolution here.

eygraber commented 9 months ago

I use a different DI, and I'm explicitly using the Application context. I believe this behavior was introduced in Android 11 where trying to get a visual service (like WindowManager) from an application context isn't allowed.

szymon-miloch commented 6 months ago

Hey, I am using Snowplow dependency with version 6.0.2 and I am still encountering the same or similar issue. I am using Google Pixel with Android 14 if that's of any help.

Here's the stacktrace:

android.os.strictmode.IncorrectContextUseViolation: StrictMode policy violation detected: VmPolicy
        at android.os.StrictMode.onIncorrectContextUsed(StrictMode.java:2296)
        at android.app.ContextImpl.getSystemService(ContextImpl.java:2209)
        at android.content.ContextWrapper.getSystemService(ContextWrapper.java:935)
        at android.content.Context.getSystemService(Context.java:4442)
        at com.snowplowanalytics.core.tracker.Subject.setDefaultScreenResolution(Subject.kt:233)
        at com.snowplowanalytics.core.tracker.Subject.<init>(Subject.kt:187)
        at com.snowplowanalytics.core.tracker.ServiceProvider.makeSubject(ServiceProvider.kt:222)
        at com.snowplowanalytics.core.tracker.ServiceProvider.getOrMakeSubject(ServiceProvider.kt:181)
        at com.snowplowanalytics.core.tracker.ServiceProvider.makeTracker(ServiceProvider.kt:266)
        at com.snowplowanalytics.core.tracker.ServiceProvider.getOrMakeTracker(ServiceProvider.kt:189)
        at com.snowplowanalytics.core.tracker.ServiceProvider.<init>(ServiceProvider.kt:87)
        at com.snowplowanalytics.snowplow.Snowplow.createTracker(Snowplow.kt:275)
        at com.snowplowanalytics.snowplow.Snowplow.createTracker(Snowplow.kt:375)
        at com.snowplowanalytics.snowplow.Snowplow.setup$lambda$0(Snowplow.kt:109)
        at com.snowplowanalytics.snowplow.Snowplow.$r8$lambda$7NriQQFjtqlHx_GQTCXOSPBV4YI(Unknown)
        at com.snowplowanalytics.snowplow.Snowplow$$ExternalSyntheticLambda1.accept(Unknown:6)
        at com.snowplowanalytics.core.remoteconfiguration.RemoteConfigurationProvider.retrieveConfiguration(RemoteConfigurationProvider.kt:60)
        at com.snowplowanalytics.snowplow.Snowplow.setup(Snowplow.kt:102)
        at my.package.analytics.snowplow.api.SnowplowApi.initialize(SnowplowApi.kt:23)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

Caused by: java.lang.IllegalAccessException: Tried to access visual service WindowManager from a non-visual Context:my.package.MyApplication@64e6c51
        at android.app.ContextImpl.getSystemService(ContextImpl.java:2208)
        at android.content.ContextWrapper.getSystemService(ContextWrapper.java:935)
        at android.content.Context.getSystemService(Context.java:4442)
        at com.snowplowanalytics.core.tracker.Subject.setDefaultScreenResolution(Subject.kt:233)
        at com.snowplowanalytics.core.tracker.Subject.<init>(Subject.kt:187)
        at com.snowplowanalytics.core.tracker.ServiceProvider.makeSubject(ServiceProvider.kt:222)
        at com.snowplowanalytics.core.tracker.ServiceProvider.getOrMakeSubject(ServiceProvider.kt:181)
        at com.snowplowanalytics.core.tracker.ServiceProvider.makeTracker(ServiceProvider.kt:266)
        at com.snowplowanalytics.core.tracker.ServiceProvider.getOrMakeTracker(ServiceProvider.kt:189)
        at com.snowplowanalytics.core.tracker.ServiceProvider.<init>(ServiceProvider.kt:87)
        at com.snowplowanalytics.snowplow.Snowplow.createTracker(Snowplow.kt:275)
        at com.snowplowanalytics.snowplow.Snowplow.createTracker(Snowplow.kt:375)
        at com.snowplowanalytics.snowplow.Snowplow.setup$lambda$0(Snowplow.kt:109)
        at com.snowplowanalytics.snowplow.Snowplow.$r8$lambda$7NriQQFjtqlHx_GQTCXOSPBV4YI(Unknown)
        at com.snowplowanalytics.snowplow.Snowplow$$ExternalSyntheticLambda1.accept(Unknown:6)
        at com.snowplowanalytics.core.remoteconfiguration.RemoteConfigurationProvider.retrieveConfiguration(RemoteConfigurationProvider.kt:60)
        at com.snowplowanalytics.snowplow.Snowplow.setup(Snowplow.kt:102)
        at my.package.analytics.snowplow.api.SnowplowApi.initialize(SnowplowApi.kt:23)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
mscwilson commented 6 months ago

Thanks for the report. That's disappointing. We'll have a look