mixpanel-android icon indicating copy to clipboard operation
mixpanel-android copied to clipboard

Fix StrictMode DiskReadViolations during SDK initialization

Open jaredmixpanel opened this issue 4 months ago • 1 comments

Problem

SDK users are experiencing StrictMode DiskReadViolations when initializing the Mixpanel SDK on the main thread. These violations occur at three specific points during initialization, causing issues for apps that enforce strict StrictMode policies.

Solution

This PR addresses all three DiskReadViolation sources by deferring disk I/O operations to background threads or using lazy initialization patterns:

1. PersistentIdentity.getTimeEvents() violation

  • Issue: Blocking on Future.get() when loading SharedPreferences on main thread
  • Fix: Added main thread detection to return empty map immediately and load cache asynchronously
  • Impact: Prevents blocking while maintaining eventual consistency of time events data

2. MPDbAdapter initialization violation

  • Issue: getDatabasePath() called synchronously in constructor
  • Fix: Implemented lazy initialization pattern for database file path resolution
  • Impact: Database path is now resolved only when first accessed, not during construction

3. MixpanelAPI constructor violation

  • Issue: Synchronous database file existence check for first launch detection
  • Fix: Moved first launch check to background thread via new checkFirstLaunchAsync() method
  • Impact: First open event tracking now happens asynchronously without blocking

Testing

  • Added comprehensive StrictModeTest that verifies no violations occur during SDK initialization
  • Test captures StrictMode output and validates no disk read violations are triggered
  • All existing tests continue to pass, confirming backward compatibility

Impact

  • Eliminates StrictMode violations for SDK users who enforce strict policies
  • Maintains full backward compatibility - no API changes
  • Performance improvement: initialization no longer blocks on disk I/O operations
  • Thread-safe implementation using proper synchronization mechanisms

GitHub Copilot Summary

This pull request addresses StrictMode disk I/O violations by ensuring that Mixpanel's initialization and first-launch checks avoid disk reads on the main thread. The changes introduce lazy initialization for database file access, move first-launch tracking to a background thread, and add instrumentation tests to verify compliance with StrictMode policies.

StrictMode compliance and testing:

  • Added a new instrumentation test StrictModeTest to verify that initializing MixpanelAPI on the main thread does not trigger StrictMode disk read violations, and to ensure SDK initialization completes successfully.

Database file access improvements:

  • Refactored MPDbAdapter.MPDatabaseHelper to lazily initialize the mDatabaseFile field using a new getDatabaseFile() method, deferring disk I/O until actually needed. Updated all usages to call this method instead of directly accessing the field. [1] [2] [3] [4]

First-launch logic refactor:

  • Moved the first-launch check and automatic event tracking ($app_open and FIRST_OPEN) into a new asynchronous method checkFirstLaunchAsync(), which runs on a background thread to avoid main-thread disk I/O. The synchronous check was removed from the constructor. [1] [2]

jaredmixpanel avatar Aug 22 '25 22:08 jaredmixpanel

Addressed GitHub Copilot Feedback

Refactored the first launch check to use the established message passing pattern instead of creating a new Thread:

Changes made:

  1. Added CHECK_FIRST_LAUNCH message type to AnalyticsMessages for handling first launch checks
  2. Created FirstLaunchDescription class to carry the message data including the MixpanelAPI instance reference
  3. Implemented handler in Worker to process first launch checks on the existing background HandlerThread
  4. Added package-private methods (isFirstLaunch() and setHasLaunched()) to MixpanelAPI to allow AnalyticsMessages to perform the operations
  5. Updated checkFirstLaunchAsync() to use mMessages.checkFirstLaunchMessage() instead of creating a new Thread

This approach maintains the SDK's single HandlerThread architecture for all background operations, ensuring consistency and avoiding the overhead of creating additional threads.

The StrictMode tests continue to pass, confirming that the disk I/O violations are still resolved while properly following the SDK's architectural patterns.

jaredmixpanel avatar Aug 22 '25 22:08 jaredmixpanel