Skip to content

Conversation

@jaredmixpanel
Copy link
Collaborator

@jaredmixpanel jaredmixpanel commented Aug 22, 2025

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]

This commit addresses three DiskReadViolations that occur when the SDK is initialized on the main thread with StrictMode enabled:

1. PersistentIdentity.getTimeEvents() - Avoid blocking Future.get() on main thread
   - Added main thread detection using Looper.getMainLooper()
   - Returns empty map immediately on main thread and loads cache asynchronously
   - Maintains backward compatibility while preventing disk I/O blocking

2. MPDbAdapter initialization - Defer getDatabasePath() call
   - Changed database file initialization to use lazy loading pattern
   - Database path is now resolved only when first accessed
   - Prevents disk I/O during constructor execution

3. MixpanelAPI constructor - Remove synchronous database file check
   - Moved first launch detection to background thread
   - Added checkFirstLaunchAsync() method for async processing
   - Ensures first open event tracking without blocking main thread

Added comprehensive StrictModeTest to verify all violations are resolved while maintaining SDK functionality.
@jaredmixpanel jaredmixpanel requested a review from Copilot August 22, 2025 22:42
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR addresses StrictMode DiskReadViolations that occur during Mixpanel SDK initialization on the main thread. The fix ensures SDK compliance with strict StrictMode policies by deferring disk I/O operations to background threads or using lazy initialization patterns.

Key changes:

  • Moved first launch detection and tracking to a background thread to avoid synchronous disk operations during initialization
  • Implemented lazy initialization for database file path resolution to defer disk access until actually needed
  • Added comprehensive StrictMode compliance testing to verify no violations occur during SDK initialization

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
MixpanelAPI.java Moved first launch check to background thread via new checkFirstLaunchAsync() method
MPDbAdapter.java Implemented lazy initialization pattern for database file path using synchronized getDatabaseFile() method
StrictModeTest.java Added new instrumented test to verify StrictMode compliance during SDK initialization

});

// Wait for test to complete
assertTrue("Test should complete within timeout",
Copy link

Copilot AI Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertTrue method is defined at the bottom of the test class but shadows the static Assert.assertTrue method. This creates confusion and could lead to incorrect test behavior. Use the imported Assert.assertTrue directly or rename the custom method to avoid shadowing.

Copilot uses AI. Check for mistakes.
});

assertTrue("Initialization should complete",
latch.await(5, TimeUnit.SECONDS));
Copy link

Copilot AI Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as line 111 - this assertTrue call uses the custom method instead of the imported Assert.assertTrue, which could lead to inconsistent test behavior.

Suggested change
latch.await(5, TimeUnit.SECONDS));
latch.await(5, TimeUnit.SECONDS));

Copilot uses AI. Check for mistakes.
- Replace direct Thread creation with SDK's message passing architecture
- Add CHECK_FIRST_LAUNCH message type to AnalyticsMessages
- Implement FirstLaunchDescription class for message data
- Add package-private methods in MixpanelAPI for first launch operations
- Update Worker handler to process first launch checks on background thread

This follows the SDK's established pattern of using a single HandlerThread
for all background operations, avoiding direct thread creation.
@jaredmixpanel
Copy link
Collaborator Author

jaredmixpanel commented Aug 22, 2025

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.

The async first launch check was causing timing issues in tests.
Implemented a hybrid approach that:
- Uses async message passing on main thread to avoid StrictMode violations
- Executes synchronously on background threads (like in tests) for reliability

This ensures both StrictMode compliance and test stability.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants