Battery Statistics (batterystats) Log Documentation
Learning to Extract Battery Statistics Logs
Introduction
The Battery Statistics service (batterystats) provides comprehensive power consumption data and device activity timelines. This service tracks battery drain events, wake locks, sensor usage, and correlates power consumption with specific apps and system components, making it invaluable for forensic timeline reconstruction.
Prerequisites
- Android device with USB debugging enabled
- ADB (Android Debug Bridge) installed
- Understanding of Unix timestamps
- Sufficient storage for large log files (can exceed 50MB)
Step 1: Understanding Battery Stats Capabilities
Battery stats tracks multiple data types:
bash
# Check current battery status
adb shell dumpsys battery
# Sample output:
Current Battery Service state:
AC powered: false
USB powered: true
Wireless powered: false
Max charging current: 500000
Max charging voltage: 5000000
Charge counter: 2854000
status: 2 # 1=Unknown, 2=Charging, 3=Discharging, 4=Not charging, 5=Full
health: 2 # 1=Unknown, 2=Good, 3=Overheat, 4=Dead, 5=Over voltage, 6=Failure
present: true
level: 87 # Battery percentage
scale: 100
voltage: 4123
temperature: 285 # In tenths of degree Celsius (28.5°C)
technology: Li-ion
Step 2: Basic Battery Statistics Extraction
Create working directory and extract battery data:
bash
# Create evidence directory
mkdir batterystats_evidence
cd batterystats_evidence
# Extract full battery statistics
adb shell dumpsys batterystats > batterystats_full.txt
# Extract human-readable summary
adb shell dumpsys batterystats --charged > batterystats_charged.txt
# Extract history in detail
adb shell dumpsys batterystats --history > battery_history.txt
# Extract history with full detail
adb shell dumpsys batterystats --history-detail > battery_history_detail.txt
# Machine-readable format (CSV)
adb shell dumpsys batterystats --checkin > batterystats_checkin.csv
Step 3: Understanding the History Output
Battery history uses a compact format to track events:
Battery History (0% used, 3584 used of 256KB, 134 strings using 8918):
0 (15) RESET:TIME: 2024-01-15-08:00:00
0 (2) 100 status=discharging health=good plug=none temp=280 volt=4200
+1s032ms (2) 100 +running +wake_lock +screen phone_scanning
+3s451ms (2) 100 -wake_lock
+5s200ms (2) 100 +top=u0a142:"com.whatsapp"
+10s555ms (2) 099 temp=285 volt=4123
+15s022ms (2) 099 +sensor +wifi_full_lock
+45s331ms (2) 099 -screen
+47s122ms (2) 099 -top
\+1m30s044ms (2) 098 \+job=u0a142:"com.whatsapp/JobScheduler"
Step 4: First Analysis Exercise
Let's decode battery history events and create a timeline:
bash
# Extract screen on/off events with timestamps
grep -E "\+screen|-screen" battery_history.txt | \
awk '{
time \= $1
gsub(/[^0-9hms]/, " ", time)
if ($3 \~ /\+screen/)
print time, "SCREEN_ON"
else if ($3 \~ /-screen/)
print time, "SCREEN_OFF"
}' > screen_timeline.txt
# Calculate screen-on time
awk '
/SCREEN_ON/ {on_time \= $1}
/SCREEN_OFF/ && on_time {
off_time \= $1
# Convert to seconds and calculate duration
print "Screen on from", on_time, "to", off_time
on_time \= ""
}
' screen_timeline.txt
Understanding Battery History Symbols
- Time Format
+5s200ms- Relative time from start+1h30m45s- Hours, minutes, seconds+2d15h30m- Days, hours, minutes- Event Prefixes
+Event started (e.g.,+screen)-Event ended (e.g.,-screen)- No prefix: State change (e.g.,
temp=285)
Common Events
+running Device CPU active
+wake_lock Wake lock held
+screen Screen turned on
+wifi WiFi enabled
+gps GPS active
+phone_scanning Cellular scanning
+sensor Sensor active
+top= App in foreground
+job= Background job running
- +sync= Sync operation
Working with Battery Statistics Logs
How to Extract Specific Timeframes
Extract Battery Events for Specific Date
bash
# Function to find reset point for date
find_reset_for_date() {
TARGET_DATE="$1"
grep -n "RESET:TIME:.*$TARGET_DATE" batterystats_full.txt | head -1 | cut -d: -f1
}
# Extract events for January 15, 2024
START_LINE=$(find_reset_for_date "2024-01-15")
END_LINE=$(find_reset_for_date "2024-01-16")
if [ ! -z "$START_LINE" ] && [ ! -z "$END_LINE" ]; then
sed -n "${START_LINE},${END_LINE}p" batterystats_full.txt > battery_20240115.txt
fi
Convert Relative Time to Absolute Timestamps
python
#!/usr/bin/env python3
# convert_battery_time.py
import re
from datetime import datetime, timedelta
def parse_relative_time(time_str):
"""Convert '+1h30m45s123ms' to seconds"""
total_ms \= 0
*\# Parse each component*
days \= re.search(r'(\\d+)d', time\_str)
hours \= re.search(r'(\\d+)h', time\_str)
minutes \= re.search(r'(\\d+)m', time\_str)
seconds \= re.search(r'(\\d+)s', time\_str)
milliseconds \= re.search(r'(\\d+)ms', time\_str)
if days: total\_ms \+= int(days.group(1)) \* 86400000
if hours: total\_ms \+= int(hours.group(1)) \* 3600000
if minutes: total\_ms \+= int(minutes.group(1)) \* 60000
if seconds: total\_ms \+= int(seconds.group(1)) \* 1000
if milliseconds: total\_ms \+= int(milliseconds.group(1))
return total\_ms
# Find reset time
with open('battery_history.txt', 'r') as f:
for line in f:
if 'RESET:TIME:' in line:
reset_match \= re.search(r'RESET:TIME:\s*(\d{4}-\d{2}-\d{2}-\d{2}:\d{2}:\d{2})', line)
if reset_match:
reset_time \= datetime.strptime(reset_match.group(1), '%Y-%m-%d-%H:%M:%S')
break
*\# Convert all relative times*
f.seek(0)
for line in f:
time\_match \= re.search(r'^\\s\*(\\+\[\\dhms\]+)', line)
if time\_match:
relative\_ms \= parse\_relative\_time(time\_match.group(1))
absolute\_time \= reset\_time \+ timedelta(milliseconds\=relative\_ms)
print(f"{absolute\_time.strftime('%Y-%m-%d %H:%M:%S')} {line.strip()}")
How to Filter for Specific Events
Track App Power Consumption
bash
# Extract foreground app usage with battery level
TARGET_APP="com.whatsapp"
grep -E "\+top=.*$TARGET_APP|-top=.*$TARGET_APP|^[[:space:]]*\+" battery_history.txt | \
awk -v app="$TARGET_APP" '
/\+top=.*'$app'/ {
start_time \= $1
battery_level \= $3
print "App started:", start_time, "Battery:", battery_level "%"
}
/-top/ && start_time {
end_time \= $1
end_battery \= $3
print "App stopped:", end_time, "Battery:", end_battery "%"
print "Battery drain:", battery_level - end_battery "%"
print "---"
start_time \= ""
}
'
Identify Wake Lock Abuse
bash
# Find apps holding wake locks for extended periods
awk '
/\+wake_lock=/ {
match($0, /\+wake_lock=([^[:space:]]+)/, wl)
wakelocks[wl[1]] \= $1
wl_battery[wl[1]] \= $3
}
/-wake_lock=/ {
match($0, /-wake_lock=([^[:space:]]+)/, wl)
if (wakelocks[wl[1]]) {
duration \= $1 " - " wakelocks[wl[1]]
drain \= wl_battery[wl[1]] - $3
print "Wake lock:", wl[1]
print "Duration:", duration
print "Battery drain:", drain "%"
print "---"
delete wakelocks[wl[1]]
}
}
' battery_history.txt > wakelock_analysis.txt
How to Correlate with Other Logs
Correlate Battery Drain with Network Activity
bash
# Extract periods of high battery drain
awk '
NR > 1 && $3 \~ /^[0-9]+$/ {
battery \= $3
if (last_battery && (last_battery - battery) >= 5) {
print last_time, "-", $1, ":", last_battery - battery "% drain"
}
last_battery \= battery
last_time \= $1
}
' battery_history.txt > high_drain_periods.txt
# Cross-reference with network stats
while read period; do
echo "High drain period: $period"
# Extract time range and check network activity
START_TIME=$(echo $period | awk '{print $1}')
END_TIME=$(echo $period | awk '{print $3}')
echo "Checking network activity..."
adb shell dumpsys netstats | grep -A20 "$START_TIME"
done \< high_drain_periods.txt
Map Screen Time to App Usage
bash
# Create screen session analyzer
cat > analyze_screen_sessions.sh \<\< 'EOF'
#!/bin/bash
# Extract screen on/off with apps
awk '
/\+screen/ {
screen_on \= $1
screen_battery \= $3
print "\n=== Screen On at", screen_on, "Battery:", screen_battery "%"
}
/\+top=/ && screen_on {
match($0, /\+top=u[0-9]+a[0-9]+:"([^"]+)"/, app)
print " App launched:", app[1], "at", $1
}
/-screen/ && screen_on {
screen_off \= $1
screen_off_battery \= $3
duration \= screen_off " - " screen_on
drain \= screen_battery - screen_off_battery
print "Screen Off at", screen_off
print "Session duration:", duration
print "Battery drain:", drain "%"
screen_on \= ""
}
' battery_history.txt
EOF
chmod +x analyze_screen_sessions.sh
./analyze_screen_sessions.sh > screen_sessions.txt
How to Identify Anomalies
Detect Abnormal Battery Drain
bash
# Find rapid battery drain (>10% in 10 minutes)
awk '
function parse_time(t) {
# Convert time string to minutes
minutes \= 0
if (match(t, /([0-9]+)h/, h)) minutes += h[1] * 60
if (match(t, /([0-9]+)m/, m)) minutes += m[1]
if (match(t, /([0-9]+)s/, s)) minutes += s[1] / 60
return minutes
}
$3 \~ /^[0-9]+$/ {
battery \= $3
time \= parse_time($1)
if (last\_battery && last\_time) {
time\_diff \= time \- last\_time
battery\_diff \= last\_battery \- battery
if (time\_diff \> 0 && time\_diff \<= 10 && battery\_diff \>= 10\) {
drain\_rate \= battery\_diff / time\_diff
print "ABNORMAL DRAIN at", $1
print " Lost", battery\_diff "% in", time\_diff, "minutes"
print " Drain rate:", drain\_rate "%/minute"
print " Active:", $4, $5, $6
}
}
last\_battery \= battery
last\_time \= time
}
' battery_history.txt > abnormal_drain.txt
Identify Hidden Background Activity
bash
# Find jobs/syncs running when screen is off
awk '
/-screen/ {screen_off \= 1; off_time \= $1}
/\+screen/ {screen_off \= 0}
screen_off && /\+job=/ {
match($0, /\+job=([^[:space:]]+)/, job)
print "Background job while screen off:", job[1], "at", $1
}
screen_off && /\+sync=/ {
match($0, /\+sync=([^[:space:]]+)/, sync)
print "Sync while screen off:", sync[1], "at", $1
}
screen_off && /\+wake_lock/ {
print "Wake lock acquired while screen off at", $1
}
' battery_history.txt > hidden_activity.txt
Battery Statistics Log Structure
Complete Field Definitions
Battery History Entry Format
[timestamp] ([history_tag]) [battery_level] [state_changes] [active_components]
Components:
timestamp: +5s123ms # Relative time from reset
history_tag: (2) # Internal tag
battery_level: 099 # Battery percentage (0-100)
state_changes: status=discharging # Battery/system state
active_components: +screen +wifi # Active features/apps
State Flags and Their Meanings
Battery States:
status=unknown|charging|discharging|not-charging|full
health=unknown|good|overheat|dead|over-voltage|unspecified-failure|cold
plug=none|ac|usb|wireless
System States:
+/-running # CPU running
+/-wake_lock # System wake lock
+/-screen # Screen on/off
+/-phone_scanning # Cellular radio scanning
+/-wifi # WiFi on/off
+/-wifi_full_lock # WiFi high performance mode
+/-gps # GPS on/off
+/-sensor # Sensors active
+/-brightness=dim|medium|bright|dark # Screen brightness
App States:
+/-top=u0a142:"com.example.app" # Foreground app
+/-job=u0a142:"com.example/Job" # Background job
+/-sync=u0a142:"com.example.sync" # Sync adapter
+/-wake_lock=u0a142:"*alarm*" # App wake lock
Process States:
+/-proc=u0a142:"com.example.app" # Process running
+/-fg=u0a142 # Foreground service
Statistics Summary Structure
Statistics since last charge:
System starts: 1, currently on battery: false
Time on battery: 4h 32m 15s 200ms (89.2%) realtime, 2h 15m 30s 100ms (44.3%) uptime
Time on battery screen off: 3h 15m 45s 300ms (71.6%) realtime, 1h 30m 20s 50ms (66.7%) uptime
Total run time: 5h 5m 30s 500ms realtime, 5h 5m 30s 500ms uptime
Discharge step durations:
#0: +1h30m45s to 90%
#1: +45m20s to 80%
#2: +35m10s to 70%
Daily stats:
2024-01-15 - Discharge: 100% to 45%, 6h 30m on battery
2024-01-14 \- Discharge: 100% to 62%, 4h 15m on battery
Per-UID Statistics
u0a142 (com.whatsapp):
Total power: 245.31 mAh (15.2%)
Foreground: 1h 45m 30s
Background: 3h 20m 15s
WiFi: 125.45 MB received, 45.23 MB sent
Mobile: 15.67 MB received, 8.45 MB sent
Wake locks:
*alarm*: 15m 30s partial (250 times)
*net_scheduler*: 5m 45s partial (125 times)
Sensors:
GPS: 25m 15s (5 times)
Jobs:
com.whatsapp/MessageService: 45 times, 5m 30s total
Data Types and Formats
| Field | Type | Format | Example |
|---|---|---|---|
| Relative time | String | +[d][h][m][s][ms] | +1h30m45s200ms |
| Battery level | Integer | 0-100 | 087 |
| Temperature | Integer | Tenths of °C | 285 (28.5°C) |
| Voltage | Integer | Millivolts | 4123 |
| Current | Integer | Microamperes | -500000 |
| UID | String | u[user]a[app] | u0a142 |
| Power | Float | Milliamp hours | 245.31 |
| Data | Integer | Bytes | 125450000 |
Retention and Aggregation
| Data Type | Retention Period | Notes |
|---|---|---|
| History buffer | \~48-72 hours | RAM-based, size limited |
| Reset points | Last 10 resets | Includes reboots/charges |
| Daily stats | 10 days | Summary only |
| Per-charge stats | Current + last | Full details |
| Screen-off stats | Current session | Reset on charge |
Sample Outputs with Annotations
Normal Usage Pattern
+8h30m15s (2) 075 +screen +wifi brightness=bright # Morning usage
+8h31m20s (2) 075 +top=u0a120:"com.android.chrome" # Browsing
+8h35m45s (2) 074 -screen brightness=dark # Screen timeout
+8h40m00s (2) 074 +job=u0a85:"com.google.android.gms/GCM" # Background sync
+8h45m30s (2) 073 +screen # Check notification
+8h45m35s (2) 073 +top=u0a142:"com.whatsapp" # Reply to message
+8h47m10s (2) 073 -screen -top # Quick interaction
# Normal pattern: Brief interactions, appropriate battery drain
Suspicious Activity Pattern
+2h15m30s (2) 089 -screen # Screen off at 2:15 AM
+2h16m00s (2) 089 +wake_lock=u0a201:"*hidden*" # Suspicious wake lock
+2h16m00s (2) 089 +wifi_full_lock +gps # High power features
+2h16m30s (2) 089 +proc=u0a201:"com.unknown.app" # Unknown app active
+3h45m20s (2) 081 -wake_lock -wifi_full_lock -gps # 1.5 hours of activity!
# Red flags: Hidden wake lock name, night activity, 8% drain while "sleeping"
Malware Indicators
+15m30s (2) 095 -screen -top # User not active
+15m31s (2) 095 +wake_lock=u0a301:"AudioMix" # Fake audio wake lock
+15m31s (2) 095 +sensor # Sensors active (mic?)
+16m00s (2) 095 +mobile_radio # Data transmission
+16m30s (2) 094 +proc=u0a301:"com.game.fun" # Disguised app name
+45m20s (2) 088 -wake_lock -sensor -mobile_radio # 30 minutes activity
# Indicators: Covert recording, data exfiltration, misleading app name
Quick Reference Commands
bash
# Essential Battery Statistics Commands
adb shell dumpsys battery # Current battery state
adb shell dumpsys batterystats # Full statistics
adb shell dumpsys batterystats --charged # Stats since last charge
adb shell dumpsys batterystats --history # Compact history
adb shell dumpsys batterystats --history-detail # Detailed history
adb shell dumpsys batterystats --checkin # CSV format
adb shell dumpsys batterystats --reset # Reset statistics
# Analysis Commands
# High battery consumers
adb shell dumpsys batterystats --charged | grep -A20 "Estimated power use"
# Wake lock analysis
adb shell dumpsys batterystats | grep -A5 "Wake lock" | grep -v "realtime"
# Screen on time
adb shell dumpsys batterystats | grep "Screen on:"
# Per-app consumption
adb shell dumpsys batterystats | grep -E "^ u[0-9]" -A10
# Mobile radio active time
adb shell dumpsys batterystats | grep "Mobile radio active:"
# WiFi state time
adb shell dumpsys batterystats | grep -A5 "Wifi states:"
Understanding Battery Statistics Logs
Why Battery Statistics Logs Exist
Android's battery statistics serve multiple critical purposes:
- Power Management
- Track battery consumption by component
- Identify power-hungry apps
- Optimize system resources
- Implement Doze mode and app standby
- User Features
- Battery usage screen in Settings
- Battery optimization suggestions
- Low battery warnings
- Adaptive battery management
- Developer Tools
- Power profiling for apps
- Wake lock debugging
- Battery historian visualization
- Performance optimization
How Android Generates Battery Data
Data Collection Architecture
Hardware Battery Sensor
↓
Kernel Battery Driver
↓
Battery Service (system_server)
↓
├── Current State Updates
├── History Event Recording
├── Power Attribution
└── Statistics Aggregation
↓
BatteryStats Service
↓
/data/system/batterystats.bin
Event Recording Mechanism
- State Changes: Any system state change triggers a history entry
- Sampling: Battery level sampled every few minutes
- Attribution: Power usage attributed to UIDs based on:
- CPU time
- Wake lock duration
- Network usage
- Sensor activation
- Screen time
Power Calculation Model
App Power \= CPU Power + Wake Lock Power + Network Power + Sensor Power + Screen Power
Where:
- CPU Power \= CPU_TIME × POWER_PROFILE_CPU
- Wake Lock Power \= WAKE_DURATION × POWER_PROFILE_WAKE
- Network Power \= (BYTES_TX + BYTES_RX) × POWER_PROFILE_NETWORK
- Sensor Power \= SENSOR_TIME × POWER_PROFILE_SENSOR
- Screen Power \= (FOREGROUND_TIME / TOTAL_TIME) × SCREEN_POWER
Forensic Significance
Timeline Reconstruction Excellence
Battery statistics provide the most comprehensive timeline of device activity because:
- Always Recording: Cannot be disabled by users
- System-Level: Captures all activity, not just apps
- Precise Timing: Millisecond accuracy with relative timestamps
- State Correlation: Links multiple data points per event
Critical Forensic Artifacts
| Artifact Type | Forensic Value | Example Evidence |
|---|---|---|
| Screen Sessions | User presence | Physical access times |
| App Foreground | User activity | What user was doing |
| Wake Locks | Background activity | Hidden app behavior |
| Network Radio | Data transmission | Communication times |
| GPS Usage | Location tracking | Movement correlation |
| Charging Events | Location/routine | Home/work patterns |
Unique Investigative Capabilities
Sleep Pattern Analysis
bash
# Identify sleep periods (no screen activity for 4+ hours)
awk '
/\+screen/ {last_screen \= $1}
/-screen/ {
if (last_screen) {
# Calculate gap to next screen on
# Gaps > 4 hours likely indicate sleep
}
}
- ' battery_history.txt
Device Handling Detection
bash
# Movement detection through sensor activation
grep -E "\+sensor|\+sig_motion" battery_history.txt | \
- awk '{print $1, "Device moved/handled"}'
Covert App Detection
bash
# Apps active when screen is off
awk '
/-screen/ {screen_off \= 1}
/\+screen/ {screen_off \= 0}
screen_off && /\+top=/ {
print "App in foreground with screen off:", $0
}
- ' battery_history.txt
Relationship to Other Logs
Power Attribution Chain
BatteryStats ←→ CPU Stats
└─ Links CPU time to battery drain
BatteryStats ←→ Network Stats
└─ Correlates data usage with power
BatteryStats ←→ Wake Lock Stats
└─ Shows which apps prevent sleep
BatteryStats ←→ Sensor Hub
└─ Tracks sensor usage duration
Advanced Correlation Techniques
Communication Pattern Analysis
bash
# Link battery drain to messaging
COMM_APPS="whatsapp|telegram|signal|messages"
# Find communication sessions
grep -E "$COMM_APPS" battery_history.txt | \
grep "+top=" > comm_sessions.txt
# Check for radio activity during sessions
while read line; do
TIME=$(echo $line | awk '{print $1}')
# Check if mobile_radio active within 30 seconds
grep -A5 "$TIME" battery_history.txt | grep -q "mobile_radio" && \
echo "$line - Data transmitted"
- done \< comm_sessions.txt
Location Tracking Validation
bash
# Verify claimed locations through GPS usage
# Extract GPS activation times
grep "+gps" battery_history.txt | \
awk '{print $1, "GPS activated"}' > gps_usage.txt
# Cross-reference with map apps
MAP_APPS="maps|waze|uber|lyft"
grep -E "$MAP_APPS" battery_history.txt | \
- grep -B2 -A2 "+gps" > navigation_sessions.txt
Legal Considerations
Admissibility Strengths
- System Generated: No user input or modification possible
- Continuous Recording: No gaps in timeline
- Multiple Corroboration: Each event has multiple data points
- Technical Reliability: Core Android function since version 1.0
Court Presentation Best Practices
python
#!/usr/bin/env python3
# create_court_timeline.py
import re
from datetime import datetime, timedelta
def create_visual_timeline(battery_file, output_file):
"""Convert battery stats to court-friendly timeline"""
events \= \[\]
reset\_time \= None
with open(battery\_file, 'r') as f:
for line in f:
*\# Find reset time*
if 'RESET:TIME:' in line:
match \= re.search(r'(\\d{4}-\\d{2}-\\d{2}-\\d{2}:\\d{2}:\\d{2})', line)
if match:
reset\_time \= datetime.strptime(match.group(1), '%Y-%m-%d-%H:%M:%S')
*\# Extract events*
if reset\_time and line.strip() and line\[0\] \== ' ':
time\_match \= re.search(r'^\\s\*\\+(\[^\\s\]+)', line)
if time\_match:
*\# Convert relative time to absolute*
rel\_time \= parse\_relative\_time(time\_match.group(1))
abs\_time \= reset\_time \+ timedelta(milliseconds\=rel\_time)
*\# Extract meaningful events*
if any(x in line for x in \['+screen', '-screen', '+top=', 'gps', 'camera'\]):
events.append({
'time': abs\_time,
'event': line.strip()
})
*\# Generate report*
with open(output\_file, 'w') as out:
out.write("DEVICE ACTIVITY TIMELINE\\n")
out.write("========================\\n\\n")
for event in sorted(events, key\=lambda x: x\['time'\]):
out.write(f"{event\['time'\].strftime('%Y-%m-%d %H:%M:%S')} \- ")
*\# Translate to human-readable*
if '+screen' in event\['event'\]:
out.write("User turned screen ON\\n")
elif '-screen' in event\['event'\]:
out.write("Screen turned OFF\\n")
elif '+top=' in event\['event'\]:
app \= re.search(r'"(\[^"\]+)"', event\['event'\])
if app:
out.write(f"User opened app: {app.group(1)}\\n")
*\# ... additional translations*
Privacy Considerations
While battery stats don't contain message content or personal data, they reveal:
- Daily routines and sleep patterns
- App usage habits
- Location service usage
- Communication patterns
Consider appropriate redactions for sensitive investigations.
Common Challenges and Solutions
| Challenge | Solution |
|---|---|
| Large file size | Use grep/awk to filter before analysis |
| Relative timestamps | Convert to absolute using reset time |
| Multiple resets | Process each section separately |
| Attribution accuracy | Cross-reference with other logs |
| Missing history | Check if buffer full, extract more frequently |
| Encrypted devices | Battery stats still accessible via ADB |
Advanced Analysis Techniques
Behavioral Anomaly Detection
bash
#!/bin/bash
# detect_anomalies.sh
# 1. Find unusual night activity (12 AM - 5 AM)
echo "=== Night Activity Analysis \==="
awk '
bash
BEGIN {
night_start \= 0 # Midnight
night_end \= 5 # 5 AM
}
/RESET:TIME:/ {
match($0, /(\d{4}-\d{2}-\d{2})-(\d{2}):(\d{2}):(\d{2})/, arr)
reset_hour \= arr[2]
reset_date \= arr[1]
}
/^\s*\+/ {
# Calculate current hour from relative time
time_str \= $1
hours \= 0
if (match(time_str, /([0-9]+)h/, h)) hours += h[1]
if (match(time_str, /([0-9]+)d/, d)) hours += d[1] * 24
current_hour \= (reset_hour + hours) % 24
# Check if in night period
if (current_hour >= night_start && current_hour \< night_end) {
# Flag significant events
if (/\+screen/ || /\+top\=/ || /\+wake_lock/) {
print "NIGHT ACTIVITY at hour", current_hour ":", $0
}
}
}
' battery_history.txt > night_anomalies.txt
# 2. Detect rapid battery drain patterns
echo -e "\n=== Rapid Drain Detection \==="
awk '
/^[[:space:]]*\+.*[[:space:]][0-9]{3}[[:space:]]/ {
time \= $1
battery \= $3
if (last_battery && battery \< last_battery) {
drain \= last_battery - battery
*\# Extract time difference*
time\_diff \= 0
if (match(time, /(\[0\-9\]+)s/, s)) time\_diff \= s\[1\]
if (match(time, /(\[0\-9\]+)m/, m)) time\_diff \= m\[1\] \* 60
if (time\_diff \> 0 && time\_diff \< 300 && drain \>= 5) {
print "RAPID DRAIN:", drain "% in", time\_diff, "seconds"
print " Time:", time
print " Active:", $4, $5, $6, $7
}
}
last_battery \= battery
last_time \= time
}
' battery_history.txt >> night_anomalies.txt
# 3. Find hidden background services
echo -e "\n=== Hidden Services Analysis \==="
grep -E "job=|sync=" battery_history.txt | \
grep -v -E "com.google|com.android" | \
awk '{
print "Suspicious background activity:", $0
}' >> night_anomalies.txt
Device Usage Fingerprinting
python
#!/usr/bin/env python3
# usage_fingerprint.py
import re
from collections import defaultdict
from datetime import datetime, timedelta
class UsageFingerprint:
def __init__(self, battery_file):
self.battery_file \= battery_file
self.usage_patterns \= defaultdict(lambda: defaultdict(int))
self.app_sequences \= defaultdict(int)
self.charge_patterns \= []
def analyze(self):
"""Create a behavioral fingerprint from battery stats"""
with open(self.battery\_file, 'r') as f:
lines \= f.readlines()
current\_apps \= \[\]
screen\_on \= False
for line in lines:
*\# Track screen patterns*
if '+screen' in line:
screen\_on \= True
hour \= self.\_extract\_hour(line)
self.usage\_patterns\['screen\_on'\]\[hour\] \+= 1
elif '-screen' in line:
screen\_on \= False
*\# Record app sequence*
if len(current\_apps) \> 1:
sequence \= '-\>'.join(current\_apps\[\-3:\]) *\# Last 3 apps*
self.app\_sequences\[sequence\] \+= 1
current\_apps \= \[\]
*\# Track app usage*
if screen\_on and '+top=' in line:
app\_match \= re.search(r'"(\[^"\]+)"', line)
if app\_match:
app \= app\_match.group(1)
current\_apps.append(app)
hour \= self.\_extract\_hour(line)
self.usage\_patterns\['apps'\]\[f"{hour}:{app}"\] \+= 1
*\# Track charging patterns*
if 'status=charging' in line:
hour \= self.\_extract\_hour(line)
self.charge\_patterns.append(hour)
def get\_fingerprint(self):
"""Return behavioral fingerprint summary"""
print("=== DEVICE USAGE FINGERPRINT \===\\n")
*\# Peak usage hours*
print("Peak Usage Hours:")
screen\_hours \= sorted(self.usage\_patterns\['screen\_on'\].items(),
key\=lambda x: x\[1\], reverse\=True)\[:5\]
for hour, count in screen\_hours:
print(f" {hour:02d}:00 \- {count} screen activations")
*\# Most common app sequences*
print("\\nCommon App Sequences:")
sequences \= sorted(self.app\_sequences.items(),
key\=lambda x: x\[1\], reverse\=True)\[:5\]
for seq, count in sequences:
print(f" {seq}: {count} times")
*\# Charging routine*
print("\\nCharging Pattern:")
if self.charge\_patterns:
avg\_charge\_hour \= sum(self.charge\_patterns) / len(self.charge\_patterns)
print(f" Average charging time: {avg\_charge\_hour:.1f}:00")
*\# App usage by hour*
print("\\nHourly App Usage:")
for hour in range(24):
apps\_this\_hour \= \[k.split(':')\[1\] for k in self.usage\_patterns\['apps'\]
if k.startswith(f"{hour}:")\]
if apps\_this\_hour:
print(f" {hour:02d}:00 \- {len(set(apps\_this\_hour))} different apps")
def \_extract\_hour(self, line):
"""Extract hour from battery history line"""
*\# Simplified \- would need full implementation*
return 12 *\# Placeholder*
# Usage
fingerprinter \= UsageFingerprint('battery_history.txt')
fingerprinter.analyze()
fingerprinter.get_fingerprint()
Power-Based Malware Detection
bash
#!/bin/bash
# detect_malware_power.sh
echo "=== Power-Based Malware Detection \==="
# 1. Check for wake locks with suspicious names
echo -e "\n[+] Suspicious Wake Locks:"
grep -E "wake_lock=.*\*(hidden|system|update|service)\*" battery_history.txt | \
grep -v "com.android\|com.google" | \
awk '{print " SUSPICIOUS:", $0}'
# 2. Find apps with high battery drain but low screen time
echo -e "\n[+] High Drain / Low Visibility Apps:"
adb shell dumpsys batterystats --charged | \
awk '
/^ u[0-9]/ {
uid \= $1
getline
if (/Total:/ && $2 > 100) { # Over 100 mAh
total_power \= $2
# Check if has screen time
has_screen \= 0
for (i \= 0; i \< 10; i++) {
getline
if (/Foreground:/ && $2 != "0") {
has_screen \= 1
break
}
}
if (!has_screen) {
print " UID", uid, "consumed", total_power, "mAh with no screen time"
}
}
}
'
# 3. Detect camera/microphone abuse
echo -e "\n[+] Sensor Abuse Detection:"
awk '
/-screen/ {screen_off \= 1}
/\+screen/ {screen_off \= 0}
# Camera/audio sensor use while screen off
screen_off && /sensor.*camera|sensor.*audio/ {
print " PRIVACY VIOLATION - Sensor active with screen off:", $0
}
# Long sensor sessions
/\+sensor/ {
sensor_start \= $1
sensor_battery \= $3
}
/-sensor/ && sensor_start {
if ($3 \< sensor_battery - 2) { # More than 2% drain
print " Extended sensor use:", sensor_start, "to", $1
print " Battery drain:", sensor_battery - $3 "%"
}
sensor_start \= ""
}
' battery_history.txt
# 4. Network activity in unusual patterns
echo -e "\n[+] Suspicious Network Patterns:"
awk '
# Late night network activity
/mobile_radio.*[0-2]:[0-9][0-9]:[0-9][0-9]/ {
print " Late night network activity:", $0
}
# Periodic network patterns (beaconing)
/\+mobile_radio/ {
radio_times[++radio_count] \= $1
if (radio_count > 3) {
# Check for regular intervals
# (implementation would calculate time differences)
print " Potential beaconing behavior detected"
}
}
' battery_history.txt
Integration with Other Forensic Tools
Battery Historian Integration
bash
# Export for Battery Historian visualization
adb shell dumpsys batterystats --reset
adb shell dumpsys batterystats --enable full-wake-history
# Perform test activities
# ...
# Export bug report
adb bugreport bugreport.zip
# Process with Battery Historian
# python historian.py bugreport.zip > battery_report.html
Timeline Merger with Other Logs
python
#!/usr/bin/env python3
# merge_timelines.py
class ForensicTimeline:
def __init__(self):
self.events \= []
def add\_battery\_events(self, battery\_file):
"""Add battery statistics events"""
*\# Parse battery history and add to timeline*
pass
def add\_usage\_events(self, usage\_file):
"""Add usage statistics events"""
*\# Parse usage stats and add to timeline*
pass
def add\_package\_events(self, package\_file):
"""Add package manager events"""
*\# Parse package installs/updates*
pass
def generate\_unified\_timeline(self):
"""Create unified forensic timeline"""
self.events.sort(key\=lambda x: x\['timestamp'\])
for event in self.events:
print(f"{event\['timestamp'\]} | {event\['source'\]:10} | {event\['description'\]}")
Conclusion
Battery statistics logs provide the most comprehensive timeline of device activity available to forensic investigators. Their system-level recording, resistance to tampering, and correlation of multiple data points make them invaluable for:
- Establishing device usage patterns
- Detecting malicious activity
- Verifying user claims
- Reconstructing detailed timelines
- Identifying behavioral anomalies
When combined with other log sources, battery statistics form the backbone of Android forensic timeline analysis, offering insights that no other single log source can provide.