# ADB Local State Extraction Guide

How to extract Hevy's local React Native state during an active workout on the Pixel 9a.

## Setup

```bash
# Verify ADB connection
adb devices
# Expected: [serial]    device

# If unauthorized, check phone screen for RSA fingerprint prompt

# Check Android version (affects CA cert handling for mitmproxy)
adb shell getprop ro.build.version.sdk
# API 34 = Android 14 (user CA certs blocked for apps)
# API 33 = Android 13 (user CA certs work)
```

---

## Method 1: run-as Extraction (requires debuggable app or root)

```bash
# Check if run-as works
adb shell run-as com.hevy whoami
# If "run-as: package not debuggable" → use Method 2 or 3

# If it works, explore app data
adb shell run-as com.hevy ls -la /data/data/com.hevy/

# Expected structure:
# databases/
# shared_prefs/
# files/
# cache/
# code_cache/
# app_webview/

# Dump AsyncStorage (React Native key-value store)
adb shell "run-as com.hevy cat /data/data/com.hevy/databases/RKStorage" > rkstorage.db

# Also check for alternative names
adb shell run-as com.hevy ls -la /data/data/com.hevy/databases/
# Look for: AsyncStorage.db, AsyncStorage.db-wal, AsyncStorage.db-shm
# Also: hevy.db, workout.db, session.db

# Dump all databases
for db in $(adb shell "run-as com.hevy ls /data/data/com.hevy/databases/"); do
    adb shell "run-as com.hevy cat /data/data/com.hevy/databases/$db" > "hevy_data/$db"
done

# Dump SharedPreferences
adb shell run-as com.hevy ls -la /data/data/com.hevy/shared_prefs/
adb shell "run-as com.hevy cat /data/data/com.hevy/shared_prefs/com.hevy_preferences.xml" > hevy_prefs.xml

# Dump files
adb shell run-as com.hevy ls -la /data/data/com.hevy/files/

# Dump cache (may contain offline workout data)
adb shell run-as com.hevy ls -la /data/data/com.hevy/cache/
```

### Query AsyncStorage for Workout State

```bash
# Open the SQLite database
sqlite3 rkstorage.db

# List tables
.tables
# Expected: catalystLocalStorage or AsyncStorageKV

# Schema
.schema

# Dump all keys
.dump

# Search for workout-related keys (in shell)
sqlite3 rkstorage.db ".dump" | grep -i -E "workout|session|draft|active|live|current|exercise|set|timer|routine|start|finish"

# The key format is typically: 
# @HevyStore:workoutState
# @HevyStore:activeWorkout
# workout_session
# draft_workout
# etc.

# Full dump to file for analysis
sqlite3 rkstorage.db ".dump" > hevy_async_storage_dump.sql
```

---

## Method 2: ADB Backup (non-root, works on older Android)

```bash
# Warning: May not work on Android 12+ if app disallows backup
# Check if backup is allowed in AndroidManifest:
# android:allowBackup="true"

# Create backup
adb backup -f hevy_backup.ab -apk -nosystem com.hevy
# Phone will prompt for permission (no password = blank)

# Convert to tar (Android backup format)
dd if=hevy_backup.ab bs=24 skip=1 | openssl zlib -d > hevy_backup.tar

# Extract
mkdir hevy_backup_extracted
tar xvf hevy_backup.tar -C hevy_backup_extracted/

# Explore
find hevy_backup_extracted/ -type f | head -50
```

---

## Method 3: ADB shell + cp to accessible location (needs any writeable dir)

```bash
# Try to copy to /sdcard (external storage)
adb shell "cp -r /data/data/com.hevy/databases /sdcard/hevy_databases" 2>/dev/null
adb shell "cp -r /data/data/com.hevy/shared_prefs /sdcard/hevy_prefs" 2>/dev/null

# Pull from sdcard
adb pull /sdcard/hevy_databases ./
adb pull /sdcard/hevy_prefs ./

# If access denied, try:
adb shell "ls /data/data/com.hevy/databases/"  # see if listing works
adb shell "cat /data/data/com.hevy/databases/RKStorage > /sdcard/hevy_storage.db"
adb pull /sdcard/hevy_storage.db
```

---

## Method 4: Root Access (if device is rooted)

```bash
adb root
adb shell ls -la /data/data/com.hevy/

# Direct pull
adb pull /data/data/com.hevy/databases/ ./hevy_databases/
adb pull /data/data/com.hevy/shared_prefs/ ./hevy_prefs/
adb pull /data/data/com.hevy/files/ ./hevy_files/

# Or use su from shell
adb shell
su
cp -r /data/data/com.hevy/databases /sdcard/
exit
exit
adb pull /sdcard/databases
```

---

## Method 5: Bug Report (contains process info)

```bash
# Generate bug report (may include heap dumps with state)
adb bugreport hevy_bugreport
unzip hevy_bugreport.zip

# Look for Hevy process info
grep -r "com.hevy" hevy_bugreport/ | head -20
```

---

## Real-time Monitoring Script

Save as `monitor_hevy_state.sh`:

```bash
#!/bin/bash
# Monitor Hevy AsyncStorage changes during a workout

OUTDIR="hevy_state_snapshots"
mkdir -p "$OUTDIR"

echo "Waiting for Hevy to be running..."
while ! adb shell pidof com.hevy > /dev/null 2>&1; do
    sleep 2
done

echo "Hevy detected! Starting snapshot loop (Ctrl+C to stop)..."
SNAP=0

while true; do
    SNAP=$((SNAP + 1))
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    echo "Snapshot $SNAP at $TIMESTAMP"
    
    # Try to grab AsyncStorage
    adb shell "run-as com.hevy cat /data/data/com.hevy/databases/RKStorage" > "$OUTDIR/snap_${SNAP}_${TIMESTAMP}.db" 2>/dev/null
    
    # If run-as fails, try copy method
    if [ ! -s "$OUTDIR/snap_${SNAP}_${TIMESTAMP}.db" ]; then
        adb shell "cat /data/data/com.hevy/databases/RKStorage > /sdcard/hevy_snap.db" 2>/dev/null
        adb pull /sdcard/hevy_snap.db "$OUTDIR/snap_${SNAP}_${TIMESTAMP}.db" 2>/dev/null
    fi
    
    sleep 5
done
```

---

## What to Look For in AsyncStorage

Expected key patterns (React Native + MobX):

```
# MobX persistence (mst-persist or similar)
@HevyStore:workoutState      # Active workout state object
@HevyStore:userSettings      # User preferences
@HevyStore:routines          # Cached routines
@HevyStore:exerciseHistory   # Cached history

# Raw key-value
activeWorkout                 # JSON of current workout
draftWorkout                  # JSON of draft workout
workoutSession                # Session ID and metadata
currentExerciseIndex          # Number
restTimerEnd                  # Unix timestamp
activeWorkoutStartTime        # Unix timestamp

# Offline queue
offlineSets                   # Sets pending sync
pendingWorkoutChanges         # Changes not yet saved
syncQueue                     # Outgoing sync queue

# Auth
authToken                     # JWT token
userProfile                   # Cached user
```

---

## React Native AsyncStorage Implementation Details

Hevy uses React Native. The AsyncStorage data is stored as:

```
File: /data/data/com.hevy/databases/RKStorage
Format: SQLite database
Table: catalystLocalStorage
Columns: key TEXT PRIMARY KEY, value TEXT
```

The `value` column contains JSON-serialized strings.

To extract specific key:

```bash
sqlite3 rkstorage.db "SELECT value FROM catalystLocalStorage WHERE key LIKE '%workout%';"
```

To get all keys:

```bash
sqlite3 rkstorage.db "SELECT key FROM catalystLocalStorage;"
```

---

## Post-Extraction Analysis

```bash
# Find all unique keys
sqlite3 rkstorage.db "SELECT key FROM catalystLocalStorage;" | sort > all_keys.txt

# Extract JSON values and pretty-print
sqlite3 rkstorage.db "SELECT key, value FROM catalystLocalStorage WHERE key LIKE '%workout%';" | while read line; do
    key=$(echo "$line" | cut -d'|' -f1)
    val=$(echo "$line" | cut -d'|' -f2)
    echo "=== $key ==="
    echo "$val" | python3 -m json.tool 2>/dev/null || echo "$val"
done
```
