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 throughAutoMobileSDK.initialize(). Event-producing subsystems communicate with the control-proxy accessibility service via scopedIntentbroadcasts, while storage inspection (database and SharedPreferences) uses debug-onlyContentProviderentrypoints. 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:
- Immediate (any thread): event buffer, disk persistence, SDK context, thread-safe subsystems (network, logging, crashes, failures, ANR, biometrics, database, SharedPreferences, breadcrumbs).
- 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
uuidProviderandtimerFactoryfor deterministic tests withFakeTimer.
| 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 viaSystem.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¶
- JUnitRunner – test execution framework
- Control Proxy (AccessibilityService) – real-time view hierarchy access
- Notification Triggering – MCP tool for SDK notifications
- Biometrics Stubbing – MCP tool for biometric overrides
- iOS SDK – iOS platform equivalent
- Status Glossary – chip definitions