Skip to content

AutoMobile Android SDK¶

✅ Implemented 🧪 Tested

Current state: android/auto-mobile-sdk/ is a published Android library providing navigation tracking (Navigation3, Circuit adapters), crash/ANR/handled-exception capture, Compose recomposition tracking, network interception with mock rules, log filtering, notification triggering, biometric stubbing, click tracking, OS event monitoring, SQLite database inspection, and SharedPreferences inspection. All subsystems are initialized through AutoMobileSDK.initialize(). Event-producing subsystems communicate with the control-proxy accessibility service via scoped Intent broadcasts, while storage inspection (database and SharedPreferences) uses debug-only ContentProvider entrypoints. See the Status Glossary for chip definitions.

Architecture Overview¶

graph TD
    subgraph App Process
        SDK["AutoMobileSDK
(singleton entry point)"]:::client CFG["AutoMobileConfiguration
(builder pattern)"]:::client CTX["SdkContext
(appVersion, userId, tags)"]:::core BUF["SdkEventBuffer
(batched, thread-safe)"]:::core PERSIST["FileEventPersistence
(disk-first durability)"]:::core BCAST["SdkEventBroadcaster
(Intent broadcast)"]:::core SESSION["SessionTracker
(foreground/background)"]:::core CRUMBS["BreadcrumbTrail
(ring buffer)"]:::core SDK --> CFG SDK --> CTX SDK --> BUF BUF --> PERSIST BUF --> BCAST SDK --> SESSION SDK --> CRUMBS end subgraph Subsystems NAV["Navigation Adapters"]:::client CRASH["AutoMobileCrashes"]:::client FAIL["AutoMobileFailures"]:::client ANR["AutoMobileAnr"]:::client NET["AutoMobileNetwork"]:::client LOG["AutoMobileLog"]:::client COMPOSE["RecompositionTracker"]:::client NOTIF["AutoMobileNotifications"]:::client BIO["AutoMobileBiometrics"]:::client CLICK["AutoMobileClickTracker"]:::client OS["AutoMobileOsEvents"]:::client BCINT["AutoMobileBroadcastInterceptor"]:::client DB["DatabaseInspector"]:::client SP["SharedPreferencesInspector"]:::client end CTRL["control-proxy
AccessibilityService"]:::external BCAST -->|"scoped Intent"| CTRL CRASH -->|"crash Intent"| CTRL FAIL -->|"handled exception Intent"| CTRL ANR -->|"ANR Intent"| CTRL COMPOSE -->|"snapshot Intent"| CTRL classDef client fill:#CC2200,color:#fff classDef core fill:#525FE1,color:#fff classDef external fill:#007A3D,color:#fff

1. Configuration¶

AutoMobileConfiguration uses a builder pattern with validated defaults.

Parameter Default Description
bufferSize 50 Maximum events before forced flush
flushIntervalMs 500 ms Periodic flush interval
maxBreadcrumbs 100 Ring buffer capacity for breadcrumbs
sessionTimeoutMs 30,000 ms Background inactivity before session rotation

```kotlin val config = AutoMobileConfiguration.Builder() .bufferSize(100) .flushIntervalMs(1000) .maxBreadcrumbs(200) .sessionTimeoutMs(60_000) .build()

AutoMobileSDK.initialize(applicationContext, config) ```

All builder parameters are validated with require(value > 0) at build time.

Component Description Status
AutoMobileConfiguration Builder-pattern config with validated defaults ✅ Implemented
AutoMobileConfiguration.Builder Fluent builder with bufferSize, flushIntervalMs, maxBreadcrumbs, sessionTimeoutMs ✅ Implemented

2. Initialization and Lifecycle¶

AutoMobileSDK is a Kotlin object (singleton). Initialization is split into two phases:

  1. Immediate (any thread): event buffer, disk persistence, SDK context, thread-safe subsystems (network, logging, crashes, failures, ANR, biometrics, database, SharedPreferences, breadcrumbs).
  2. Main thread (posted via Handler): lifecycle observers, activity callbacks, recomposition tracker, notifications, click tracker, OS events.

Shutdown cancels pending main-thread work, tears down OS events, broadcast interceptor, click tracker, session tracker, and event buffer. Note: the crash handler (AutoMobileCrashes) and biometric override are not uninstalled by shutdown() — they persist for the process lifetime.

Component Description Status
AutoMobileSDK.initialize() Two-phase init: immediate + main-thread posted ✅ Implemented
AutoMobileSDK.shutdown() Tears down OS events, broadcast interceptor, click tracker, session tracker, and event buffer; does not uninstall the crash handler or biometric override ✅ Implemented
AutoMobileSDK.setEnabled() Global enable/disable toggle for event tracking ✅ Implemented

3. Event Pipeline¶

Events flow through a disk-first pipeline to survive process death:

SdkEventBuffer.add(event) --> FileEventPersistence.persist(batch) // write to disk --> SdkEventBroadcaster.broadcastBatch() // scoped Intent to control-proxy --> FileEventPersistence.removeBatch() // remove on success

On next launch, replayPendingBatches() re-broadcasts any batches that survived process death, then cleanup() removes batches older than 7 days.

Batch splitting: if a serialized batch exceeds 100 KB, SdkEventBroadcaster.splitIntoBatches() recursively halves the event list to stay under Android’s Binder transaction limit.

Drop tracking: DropCounter records why events were dropped (disabled, shutdown, flush error) via ConcurrentHashMap<DropReason, AtomicLong>.

Component Description Status
SdkEventBuffer Thread-safe buffer with capacity and timer flush ✅ Implemented
SdkEventBroadcaster Serializes batches as JSON, sends scoped Intents ✅ Implemented
FileEventPersistence One JSON file per batch, FIFO ordering, 7-day cleanup ✅ Implemented
EventPersistence Interface for disk persistence (testable with fakes) ✅ Implemented
DropCounter / DefaultDropCounter Tracks dropped events by reason ✅ Implemented

4. Context¶

SdkContext holds ambient state attached to SDK events. Thread-safe via ReentrantLock.

Field Description
sessionId Current session UUID (set by SessionTracker)
userId User identifier (set via AutoMobileSDK.setUserId())
appVersion From PackageManager at init time
tags Arbitrary key-value pairs (set/remove via SDK)

SdkContextSnapshot provides an immutable point-in-time copy via snapshot().

Component Description Status
SdkContext Thread-safe mutable context with @Volatile fields and lock-guarded tags ✅ Implemented
SdkContextSnapshot Immutable data class snapshot ✅ Implemented

5. Session Tracking¶

SessionTracker manages session lifecycle based on foreground/background transitions via ProcessLifecycleOwner.

  • New session: created on first onForeground() or after timeout expires while backgrounded.
  • Background timeout: configurable via sessionTimeoutMs (default 30 s). When the app is backgrounded, a timer starts. If the app returns to foreground before the timer fires, the session continues. Otherwise the session ends and a new one starts on next foreground.
  • Testing: injectable uuidProvider and timerFactory for deterministic tests with FakeTimer.
State Transition
ENDED onForeground() creates new session UUID
ACTIVE onBackground() starts timeout timer
BACKGROUNDED onForeground() resumes; timeout fires session end
Component Description Status
SessionTracker Foreground/background lifecycle with configurable timeout ✅ Implemented
SessionTracking Interface for testability ✅ Implemented

6. Breadcrumbs¶

BreadcrumbTrail is a thread-safe ring buffer (default capacity 100) of recent app activity. When full, the oldest breadcrumb is evicted.

Breadcrumbs are automatically added for: - Navigation events - Custom events (trackEvent()) - Manual calls to addBreadcrumb()

Categories: NAVIGATION, TAP, LIFECYCLE, NETWORK, LOG, CUSTOM.

On crash, AutoMobileCrashes serializes the breadcrumb snapshot to JSON (capped at 50 KB via binary search) and attaches it to the crash Intent.

Component Description Status
BreadcrumbTrail Ring buffer with ReentrantLock, evicts oldest on overflow ✅ Implemented
BreadcrumbTracking Interface for testability ✅ Implemented
Breadcrumb Data class with timestamp, category, message, metadata ✅ Implemented

7. Navigation¶

Events and Listeners¶

NavigationEvent carries destination, source, arguments, and metadata. NavigationListener is a fun interface for in-process observers. Events are also routed through the event buffer for cross-process delivery.

Sources: NAVIGATION_COMPONENT, COMPOSE_NAVIGATION, CIRCUIT, CUSTOM, DEEP_LINK, ACTIVITY.

Framework Adapters¶

All adapters implement NavigationFrameworkAdapter (start/stop/isActive).

Adapter Framework Integration
Navigation3Adapter androidx.navigation3 @Composable TrackNavigation(destination) in each entry<> block
CircuitAdapter Slack Circuit Manual trackNavigation(destination) call

Navigation3Adapter auto-starts on first composable use and supports argument/metadata extraction lambdas. Both adapters delegate to AutoMobileSDK.notifyNavigationEvent().

Component Description Status
NavigationEvent Data class with destination, source, arguments, metadata ✅ Implemented
NavigationListener fun interface for in-process navigation observers ✅ Implemented
NavigationFrameworkAdapter Base interface for framework adapters ✅ Implemented
Navigation3Adapter Composable integration for androidx.navigation3 ✅ Implemented
CircuitAdapter Manual tracking for Slack Circuit ✅ Implemented

8. Crash and Failure Handling¶

Unhandled Crashes (AutoMobileCrashes)¶

Installs an UncaughtExceptionHandler that: 1. Captures exception class, message, full stack trace (including all-thread dump, capped at 50 KB). 2. Collects device info (Build.MODEL, MANUFACTURER, VERSION), app version, current screen. 3. Serializes breadcrumb trail snapshot. 4. Broadcasts a scoped Intent to the control-proxy accessibility service. 5. Calls the original handler to preserve default crash behavior. 6. Sleeps 200 ms to allow broadcast dispatch before process termination.

Handled Exceptions (AutoMobileFailures)¶

Reports non-fatal exceptions that were caught and recovered from. Stores up to 100 recent events in an in-memory ArrayDeque and broadcasts each to the control-proxy.

ANR Detection (AutoMobileAnr)¶

Uses ApplicationExitInfo API (Android 11+, API 30) to detect ANRs from previous sessions on app restart. Persists the last reported timestamp in SharedPreferences to avoid duplicate reporting. Reads ANR traces from exitInfo.traceInputStream.

Component Description Status
AutoMobileCrashes UncaughtExceptionHandler with all-thread dump and breadcrumbs ✅ Implemented
AutoMobileFailures Non-fatal exception recording and broadcast ✅ Implemented
HandledExceptionEvent Data class for handled exception details ✅ Implemented
AutoMobileAnr ApplicationExitInfo-based ANR detection (API 30+) ✅ Implemented

9. Network Interception¶

HTTP Interception (AutoMobileNetwork)¶

Provides an OkHttp Interceptor via AutoMobileNetwork.interceptor(). Events are routed through SdkEventBuffer. Optional header and body capture (disabled by default for privacy, bodies truncated to 32 KB).

WebSocket Tracking¶

AutoMobileNetwork.wrapWebSocketListener() wraps an existing WebSocketListener to capture frame metadata (direction, type, payload size).

OkHttp is a compileOnly dependency – consumers must include it themselves.

Mock Rules (NetworkMockRuleStore)¶

Thread-safe store for mock rules and error simulation config, updated via broadcast from the control-proxy process. Rules use compiled regex for host/path matching with optional request limits. Error simulation supports typed errors with TTL and request count limits.

The RuleMatcher interface decouples the interceptor from the full store.

Component Description Status
AutoMobileNetwork OkHttp interceptor factory and WebSocket wrapper ✅ Implemented
AutoMobileNetworkInterceptor Application-level interceptor with mock rule enforcement ✅ Implemented
AutoMobileWebSocketListener WebSocket frame metadata capture ✅ Implemented
NetworkMockRuleStore Broadcast-updated rule store with regex matching and error simulation ✅ Implemented
NetworkMockRuleStore.RuleMatcher Decoupled interface for interceptor queries ✅ Implemented

10. Logging¶

AutoMobileLog is a drop-in replacement for android.util.Log that also checks registered filters and posts matching entries to the event buffer.

  • Zero overhead when no filters are registered: a single filters.isEmpty() check.
  • First-match semantics: only records once per log call.
  • Filter matching order (cheapest first): level, tag regex, message regex.

kotlin AutoMobileLog.addFilter( name = "crash-related", tagPattern = Regex("Crash|Fatal"), minLevel = Log.ERROR, )

Component Description Status
AutoMobileLog android.util.Log drop-in with filter-based event capture ✅ Implemented
CompiledLogFilter Pre-compiled regex filter with level/tag/message matching ✅ Implemented

11. Storage Inspection¶

Database Inspection (DatabaseInspector)¶

Provides SQLite database access for debug builds. Disabled by default; must be explicitly enabled. Uses a lazy SQLiteDatabaseDriver that opens databases on demand. Closes all connections on disable or app destruction.

SharedPreferences Inspection (SharedPreferencesInspector)¶

Provides SharedPreferences read access for debug builds. Same enable/disable pattern as DatabaseInspector. Uses a lazy SharedPreferencesDriverImpl with change listeners.

Both inspectors follow the pattern: initialize(context) at SDK init, setEnabled(true) in debug builds, lazy driver creation on first access.

Component Description Status
DatabaseInspector SQLite database access with lazy driver and enable/disable gating ✅ Implemented
SQLiteDatabaseDriver Database driver with connection pooling ✅ Implemented
DatabaseDriver Interface for testability ✅ Implemented
SharedPreferencesInspector SharedPreferences access with lazy driver and enable/disable gating ✅ Implemented
SharedPreferencesDriverImpl SharedPreferences driver with change listeners ✅ Implemented
SharedPreferencesDriver Interface for testability ✅ Implemented

12. Compose Recomposition Tracking¶

Three layers work together:

ComposeRecomposition (API Surface)¶

  • Modifier.autoMobileRecomposition(id, ...) – modifier that records recompositions with optional metadata (composable name, resource ID, test tag, parent chain, stability annotations, likely cause).
  • TrackRecomposition(id, ...) { content } – composable wrapper that also measures composition duration via System.nanoTime().
  • Modifier.autoMobileRecompositionId(id) – lightweight semantics-only marker.

ComposeObservableApi (Cause Tracking)¶

EnableComposeObservableApi() composable hooks into Compose’s CompositionObserver/CompositionRegistrationObserver APIs to detect invalidation causes. The ObservableRecompositionBridge maps RecomposeScope to invalidation causes: state_read, unstable_lambda, collection_change, or unknown.

RecompositionTracker (Aggregation and Broadcast)¶

Singleton that aggregates recomposition counts with a 1-second rolling average window. Broadcasts JSON snapshots to the control-proxy every 1 second when enabled. Controlled remotely via broadcast intent. Each entry tracks: total count, skip count, rolling 1s average, composable name, resource ID, test tag, parent chain, stability annotation, remembered count, likely cause, and average duration.

Component Description Status
ComposeRecomposition Modifier and composable APIs for recomposition tracking ✅ Implemented
TrackRecomposition Composable wrapper with optional duration measurement ✅ Implemented
ComposeObservableApi Compose runtime observer for invalidation cause tracking ✅ Implemented
ObservableRecompositionBridge Maps RecomposeScope to invalidation cause strings ✅ Implemented
RecompositionTracker Aggregation with rolling average and periodic broadcast ✅ Implemented

13. Other Subsystems¶

Notifications (AutoMobileNotifications)¶

Posts notifications from the app-under-test process. Supports DEFAULT, BIG_TEXT, and BIG_PICTURE styles. Handles image loading from file paths, content URIs, and base64 data. Creates notification channels automatically on Android O+.

Component Description Status
AutoMobileNotifications Notification posting with multiple styles and image sources ✅ Implemented

Biometric Stubbing (AutoMobileBiometrics)¶

Provides deterministic biometric testing by injecting known BiometricResult values (Success, Failure, Cancel, Error) via broadcast. Overrides have a configurable TTL (default 5 s) and are consumed atomically.

Component Description Status
AutoMobileBiometrics Biometric override injection via broadcast with TTL ✅ Implemented
BiometricResult Sealed class: Success, Failure, Cancel, Error(errorCode) ✅ Implemented

Click Tracking (AutoMobileClickTracker)¶

Automatic tap tracking for all Activities via Window.Callback delegation. On ACTION_UP (when the gesture is a tap, not a drag), finds the tapped element via the accessibility node tree and emits an _auto_tap custom event with coordinates, text, content description, resource ID, class name, and clickability. Debounced at 100 ms. Works with Compose, XML Views, React Native, and Flutter.

Component Description Status
AutoMobileClickTracker Window.Callback delegation for automatic tap capture ✅ Implemented

OS Events (AutoMobileOsEvents)¶

Registers low-overhead listeners for system events and posts SdkLifecycleEvent to the buffer:

  • Foreground/background via ProcessLifecycleOwner
  • Activity lifecycle (created/started/resumed/paused/stopped/destroyed) via ActivityLifecycleCallbacks
  • Connectivity changes (wifi/cellular/ethernet) via ConnectivityManager.NetworkCallback
  • Battery changes (level/charging, deduplicated) via BroadcastReceiver
  • Screen on/off via BroadcastReceiver
Component Description Status
AutoMobileOsEvents Foreground, activity lifecycle, connectivity, battery, screen events ✅ Implemented

Broadcast Interceptor (AutoMobileBroadcastInterceptor)¶

Intercepts a curated set of system broadcasts (locale changed, timezone changed, screen on/off, user present, package added/removed) and records them as SdkBroadcastEvent. Only captures action, categories, and extra key names with type names (not values) to avoid leaking sensitive data.

Component Description Status
AutoMobileBroadcastInterceptor Curated system broadcast capture with privacy-safe extras ✅ Implemented

Testing Utilities¶

ConfigurationOverrideHelper applies configuration overrides in tests (e.g., locale changes) and triggers configuration change callbacks on the activity.

Component Description Status
ConfigurationOverrideHelper Test-only configuration override for Activity ✅ Implemented

See Also¶