Activity Manager (activity) Log Documentation
Learning to Extract Activity Manager Logs
Introduction
The Activity Manager service (activity) is the heart of Android's application lifecycle management. It tracks all running applications, services, processes, and tasks, providing real-time visibility into what's happening on the device. For forensic investigators, it offers crucial evidence about running applications, user interactions, and system state at the time of extraction.
Prerequisites
- Android device with USB debugging enabled
- ADB (Android Debug Bridge) installed
- Understanding of Android components (Activities, Services, Broadcasts)
- Basic knowledge of process management
Step 1: Understanding Android Components
Before diving into logs, understand what Activity Manager tracks:
bash
# Check current device state
adb shell dumpsys activity | head -50
# Key components tracked:
# - Activities: User interface screens
# - Services: Background operations
# - Processes: Running application processes
# - Tasks: Collections of activities (back stack)
# - Broadcasts: System-wide messages
# - Content Providers: Data sharing components
Step 2: Basic Activity Manager Extraction
Create working directory and extract activity data:
bash
# Create evidence directory
mkdir activity_evidence
cd activity_evidence
# Extract complete activity manager state
adb shell dumpsys activity > activity_full.txt
# Extract specific sections
adb shell dumpsys activity activities > running_activities.txt
adb shell dumpsys activity services > running_services.txt
adb shell dumpsys activity processes > running_processes.txt
adb shell dumpsys activity broadcasts > pending_broadcasts.txt
adb shell dumpsys activity providers > content_providers.txt
adb shell dumpsys activity recents > recent_tasks.txt
# Get current top activity (what user sees)
adb shell dumpsys activity top > current_screen.txt
Step 3: Understanding the Output Structure
Activity Manager output is hierarchical and complex:
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from bottom to top):
Stack #1: type=home mode=fullscreen
Task{7c5d6f8 #1 type=home}
TaskRecord{7c5d6f8 #1 A=com.android.launcher3}
* ActivityRecord{5e8a4d1 u0 com.android.launcher3/.Launcher t1}
app=ProcessRecord{8c5d6f8 2567:com.android.launcher3/u0a57}
state=RESUMED
launchTime=2024-01-15 08:30:15.234
lastVisibleTime=2024-01-15 14:22:31.567
Stack #2: type=standard mode=fullscreen
Task{9a3b2c1 #42 type=standard}
TaskRecord{9a3b2c1 #42 A=com.whatsapp}
* ActivityRecord{7d4e3f2 u0 com.whatsapp/.Main t42}
app=ProcessRecord{6e7f8a9 12345:com.whatsapp/u0a142}
state=PAUSED
launchTime=2024-01-15 14:20:15.789
pauseTime=2024-01-15 14:22:31.567
Step 4: First Analysis Exercise
Let's identify currently active applications:
bash
# Extract all running activities with their states
grep -E "ActivityRecord|state=|app=ProcessRecord" running_activities.txt | \
awk '
/ActivityRecord/ {
# Extract package and activity name
match($0, /ActivityRecord{[^ ]+ [^ ]+ ([^/]+)\/([^ ]+)/, arr)
package \= arr[1]
activity \= arr[2]
}
/app=ProcessRecord/ {
# Extract PID
match($0, /ProcessRecord{[^ ]+ ([0-9]+):/, arr)
pid \= arr[1]
}
/state=/ {
# Extract state and print
state \= $1
gsub(/state=/, "", state)
if (package) {
printf "%-30s PID:%-6s State: %s\n", package, pid, state
package \= ""
}
}
' | sort -u
Understanding Key Components
- Activity States
RESUMED- Currently visible and interactivePAUSED- Visible but not interactiveSTOPPED- Not visibleDESTROYED- Removed from memory- Task Structure
- Stack: Container for tasks
- Task: Collection of activities
- Activity: Single screen/UI component
- Process Information
- PID: Process identifier
- UID: User/app identifier
- Process state and importance
Working with Activity Manager Logs
How to Extract Specific Information
Find Currently Visible Application
bash
# Get the focused activity (what user is looking at)
adb shell dumpsys activity activities | \
grep -A2 "mResumedActivity" | \
grep "ActivityRecord" | \
sed 's/.*ActivityRecord{[^ ]* [^ ]* \([^}]*\)}.*/\1/'
# Alternative method - from top
adb shell dumpsys activity top | \
grep "ACTIVITY" | \
head -1 | \
awk '{print $2}'
Track Application Launch History
bash
# Extract recent tasks with timestamps
adb shell dumpsys activity recents | \
grep -E "Recent #|realActivity=|lastActiveTime=" | \
awk '
/Recent #/ {
task_num \= $2
}
/realActivity=/ {
# Extract app name
app \= $1
gsub(/.*realActivity=/, "", app)
gsub(/{|}/, "", app)
}
/lastActiveTime=/ {
# Extract timestamp
time \= $1
gsub(/lastActiveTime=/, "", time)
if (app) {
# Convert to readable time
cmd \= "date -d @" int(time/1000) " +\"%Y-%m-%d %H:%M:%S\""
cmd | getline readable_time
close(cmd)
print readable_time, app
app \= ""
}
}
' | sort -r > recent_app_launches.txt
How to Filter for Specific Events
Find Background Services
bash
# Extract all running services with details
echo "=== Running Background Services \===" > background_services.txt
adb shell dumpsys activity services | \
awk '
/ServiceRecord{/ {
# Extract service info
match($0, /ServiceRecord{[^ ]+ [^ ]+ ([^}]+)}/, arr)
service \= arr[1]
print "\nService:", service
}
/app=ProcessRecord/ {
print " " $0
}
/createTime=/ {
print " " $0
# Convert timestamp
match($0, /createTime=([0-9]+)/, t)
cmd \= "date -d @" int(t[1]/1000) " +\"%Y-%m-%d %H:%M:%S\""
cmd | getline time
close(cmd)
print " Started at:", time
}
/lastActivity=/ {
print " " $0
}
' >> background_services.txt
# Find long-running services
awk '
/createTime=/ {
match($0, /createTime=([0-9]+)/, t)
create_time \= t[1]
}
/lastActivity=/ {
match($0, /lastActivity=([0-9]+)/, t)
last_time \= t[1]
if (create_time && last_time) {
duration \= (last_time - create_time) / 1000 / 60 # minutes
if (duration > 60) {
print prev_service, "running for", duration, "minutes"
}
}
}
/Service:/ {
prev_service \= $0
}
' background_services.txt > long_running_services.txt
Identify Hidden or System Activities
bash
# Find activities without UI (potential hidden operations)
adb shell dumpsys activity activities | \
grep -B5 -A5 "finishing=true\|visible=false" | \
grep -E "ActivityRecord|state=|app=" > hidden_activities.txt
# Extract system-level activities
adb shell dumpsys activity activities | \
grep -B3 -A3 "com.android.systemui\|android:ui\|com.android.settings" | \
grep -v "^--$" > system_activities.txt
# Find activities started by other apps (potential automation)
adb shell dumpsys activity activities | \
grep -B10 "launchedFromPackage=" | \
grep -E "ActivityRecord|launchedFromPackage=" | \
grep -B1 "launchedFromPackage=" | \
grep -v "launchedFromPackage=null" > cross_app_launches.txt
How to Correlate with Other Logs
Correlate with Memory Usage
bash
# Get memory info for running processes
adb shell dumpsys activity processes | \
grep -E "ProcessRecord|lastPss=" > process_memory.txt
# Extract high memory consumers
awk '
/ProcessRecord{/ {
match($0, /ProcessRecord{[^ ]+ [^ ]+:([^/]+)/, arr)
current_app \= arr[1]
}
/lastPss=/ {
match($0, /lastPss=([0-9]+)/, m)
pss_kb \= m[1]
pss_mb \= pss_kb / 1024
if (pss_mb > 100) { # Over 100MB
print current_app, "using", pss_mb, "MB"
}
}
' process_memory.txt > high_memory_apps.txt
Link to Battery Drain
bash
# Find apps in foreground during battery drain periods
# First, get foreground app timeline
adb shell dumpsys activity activities | \
grep -E "ActivityRecord.*state=RESUMED|lastVisibleTime=" | \
grep -B1 "state=RESUMED" > foreground_timeline.txt
# Cross-reference with battery stats
echo "Checking foreground apps during high battery drain..."
# Would combine with battery history timestamps
How to Identify Anomalies
Detect Suspicious Process Behavior
bash
# Find processes with unusual characteristics
echo "=== Suspicious Process Detection \==="
# 1. Processes with high restart count
adb shell dumpsys activity processes | \
awk '
/ProcessRecord/ {
process \= $0
}
/crashCount=/ {
match($0, /crashCount=([0-9]+)/, c)
if (c[1] > 5) {
print "High crash count:", process
print " Crashes:", c[1]
}
}
' > suspicious_processes.txt
# 2. Hidden or persistent processes
adb shell dumpsys activity processes | \
grep -B10 -A10 "persistent=true\|hidden=true" | \
grep -E "ProcessRecord|persistent=|hidden=" >> suspicious_processes.txt
# 3. Processes with unusual permissions
adb shell dumpsys activity processes | \
grep -B5 "SYSTEM_UID\|root" | \
grep -v "com.android" >> suspicious_processes.txt
Identify Automation and Bots
bash
# Detect automated behavior patterns
# 1. Rapid activity switching
adb shell dumpsys activity recents | \
grep "lastActiveTime=" | \
awk '{
match($0, /lastActiveTime=([0-9]+)/, t)
times[++count] \= t[1]
}
END {
print "Checking for automation patterns..."
for (i \= 2; i \<= count; i++) {
diff \= times[i-1] - times[i]
if (diff \< 1000 && diff > 0) { # Less than 1 second
print "Rapid switch at:", times[i], "Gap:", diff, "ms"
}
}
}' > automation_detection.txt
# 2. Check for accessibility service abuse
adb shell dumpsys activity services | \
grep -A10 "AccessibilityService" | \
grep -E "ServiceRecord|app=|createTime=" >> automation_detection.txt
Activity Manager Log Structure
Complete Field Definitions
Activity Record Structure
ActivityRecord{hashcode uid package/component taskId}
app=ProcessRecord{hashcode pid:processName/uid}
task=TaskRecord{hashcode #taskId A=affinity}
state=RESUMED|PAUSED|STOPPED|DESTROYED|INITIALIZING|FINISHING
launchedFromUid=uid
launchedFromPackage=package
launchMode=standard|singleTop|singleTask|singleInstance
intent={act=action cat=[categories] flg=flags cmp=component}
frontOfTask=true|false
visible=true|false
sleeping=true|false
finishing=true|false
keysPaused=true|false
inHistory=true|false
persistent=true|false
launchTime=timestamp
lastVisibleTime=timestamp
pauseTime=timestamp
stopTime=timestamp
connections=[ServiceConnection list]
Process Record Structure
ProcessRecord{hashcode pid:processName/uid}
user=userId
uid=appUid
gids=[groupIds]
requiredAbi=armeabi-v7a|arm64-v8a|x86|x86_64
instructionSet=arm|arm64|x86|x86_64
started=true|false
lastActivityTime=timestamp
lastPssTime=timestamp
nextPssTime=timestamp
lastPss=sizeKB lastSwapPss=sizeKB lastCachedPss=sizeKB
cached=true|false empty=true|false
serviceb=true|false serviceHighRam=true|false
notCachedSinceIdle=true|false
initialIdlePss=size trimMemoryLevel=level
memImportance=importance
curProcState=state repProcState=state setProcState=state
curAdj=oomAdj setAdj=oomAdj verifiedAdj=oomAdj
crashCount=count
crashTime=timestamp
restartCount=count
restartTime=timestamp
killedByAm=true|false
killed=true|false
Task Record Structure
TaskRecord{hashcode #taskId A=affinity U=userId}
intent={baseIntent}
origActivity=componentName
realActivity=componentName
autoRemoveRecents=true|false
taskType=home|standard|undefined
isPersistable=true|false
numFullscreen=count
taskDescription={label icon colorPrimary colorBackground}
lastActiveTime=timestamp
lastTimeOnTop=timestamp
lastDescription=description
activities=[ActivityRecord list]
askedCompatMode=true|false
inRecents=true|false
isAvailable=true|false
rootWasReset=true|false
mUserSetupComplete=true|false
effective uid=effectiveUid
Service Record Structure
ServiceRecord{hashcode uid package/component}
app=ProcessRecord{info}
created=true|false
started=true|false
connections={ComponentName -> ArrayList\<ConnectionRecord>}
bindings={Intent.FilterComparison -> IntentBindRecord}
createTime=timestamp
lastActivity=timestamp
restartTime=timestamp
restartDelay=milliseconds
restartCount=count
executeNesting=depth
executeFg=true|false
crashCount=count
isForeground=true|false
foregroundId=notificationId
foregroundNoti=Notification
startRequested=true|false
stopIfKilled=true|false
callStart=true|false
State Definitions and Transitions
| Component | States | Description |
|---|---|---|
| Activity | INITIALIZING | Being created |
| RESUMED | Visible and interactive | |
| PAUSED | Visible but not interactive | |
| STOPPED | Not visible | |
| FINISHING | Being destroyed | |
| DESTROYED | Removed from memory | |
| Service | Created | Service object exists |
| Started | startService() called | |
| Bound | bindService() active | |
| Foreground | Running with notification | |
| Process | Persistent | System-critical |
| Foreground | User-visible | |
| Visible | Affects what user sees | |
| Service | Running service | |
| Cached | Kept for performance |
Important Flags and Values
| Field | Values | Significance |
|---|---|---|
| curAdj | -1000 to 999 | OOM adjustment (lower \= higher priority) |
| procState | 0-19 | Process state (lower \= more important) |
| memImportance | 100-1000 | Memory importance level |
| trimMemoryLevel | 5-80 | Memory pressure level |
| crashCount | 0+ | App stability indicator |
| persistent | true/false | System app that shouldn't be killed |
Sample Outputs with Annotations
Normal App Usage
Stack #2: type=standard mode=fullscreen
Task{9a3b2c1 #42 type=standard U=0} # User 0, standard task
* ActivityRecord{7d4e3f2 u0 com.whatsapp/.Main t42}
app=ProcessRecord{6e7f8a9 12345:com.whatsapp/u0a142}
state=RESUMED # Currently visible
launchMode=standard # Normal launch mode
visible=true sleeping=false
launchTime=2024-01-15 14:20:15.789
lastVisibleTime=2024-01-15 14:22:31.567
Suspicious Background Activity
ServiceRecord{3a5b7c9 u0 com.unknown.app/.HiddenService}
app=ProcessRecord{9d8e7f6 23456:com.unknown.app/u0a201}
created=true started=true
createTime=1705274400000 # Started at 3 AM
lastActivity=1705359600000 # Still running after 24 hours!
restartCount=15 # Restarted many times
crashCount=8 # Unstable
isForeground=false # Hidden from user
startRequested=true stopIfKilled=false # Persistent behavior
System UI Manipulation
ActivityRecord{5f6a7b8 u0 com.malware.app/.FakeSystemUI t99}
intent={act=android.intent.action.MAIN
cat=[android.intent.category.HOME] # Pretending to be launcher!
flg=0x10200000} # System flags
task=TaskRecord{8c9d0e1 #99 A=com.android.launcher} # Wrong affinity
state=RESUMED
launchedFromUid=1000 # Claiming system UID launch
Quick Reference Commands
bash
# Essential Activity Manager Commands
adb shell dumpsys activity # Full dump
adb shell dumpsys activity activities # Running activities
adb shell dumpsys activity services # Running services
adb shell dumpsys activity processes # Running processes
adb shell dumpsys activity broadcasts # Pending broadcasts
adb shell dumpsys activity providers # Content providers
adb shell dumpsys activity recents # Recent tasks
adb shell dumpsys activity top # Current top activity
adb shell dumpsys activity oom # OOM adjustments
adb shell dumpsys activity containers # Activity containers
# Analysis Commands
# Current foreground app
adb shell dumpsys activity | grep -A2 "mResumedActivity"
# All running apps
adb shell dumpsys activity processes | grep "ProcessRecord{" | awk '{print $2}'
# Memory usage
adb shell dumpsys activity processes | grep -E "ProcessRecord|lastPss"
# Recent launches
adb shell dumpsys activity recents | grep -E "Recent #|realActivity="
# Background services
adb shell dumpsys activity services | grep "ServiceRecord{" | grep -v "com.android"
# Crash information
adb shell dumpsys activity processes | grep -B5 "crashCount=[1-9]"
Understanding Activity Manager Logs
Why Activity Manager Logs Exist
The Activity Manager is Android's central coordinator for application lifecycle, serving critical functions:
- Application Lifecycle Management
- Starting and stopping apps
- Managing activity stack (back button behavior)
- Handling configuration changes (rotation)
- Memory management and process killing
- System Resource Management
- Process prioritization
- Memory allocation
- CPU scheduling hints
- OOM (Out of Memory) killer decisions
- Security Enforcement
- Permission checking
- Component access control
- User separation
- Intent filtering
How Android Generates Activity Data
Component Lifecycle Flow
User Action (tap app icon)
↓
System Launcher sends Intent
↓
Activity Manager receives Intent
↓
├── Check if process exists
├── Create process if needed
├── Load application code
└── Create activity instance
↓
Activity lifecycle callbacks
├── onCreate()
├── onStart()
├── onResume() → RESUMED state
├── [User interacts]
├── onPause() → PAUSED state
├── onStop() → STOPPED state
└── onDestroy() → DESTROYED state
Data Collection Points
- Launch Events: Every startActivity() call logged
- State Changes: All lifecycle transitions recorded
- Process Events: Creation, death, ANRs tracked
- Service Bindings: All IPC connections monitored
- Memory Pressure: Trim events and kills logged
Memory Management
Process Importance Hierarchy:
1. Foreground (user-visible)
2. Visible (affects what user sees)
3. Service (doing work)
4. Cached (kept for performance)
5. Empty (candidates for killing)
OOM Adjustment Values:
-1000: System/Persistent
0: Foreground app
100: Visible app
200: Perceptible
300: Backup app
400: Heavy weight
500: Service
600: Home
700: Previous app
800: Service B
900: Cached app
Forensic Significance
Real-Time Device State
Activity Manager provides the most current view of device state:
- User Presence Indicators
- Current foreground app shows active use
- Recent tasks show usage patterns
- Activity transitions track user flow
- Hidden Operations Detection
- Background services reveal hidden apps
- Persistent processes show potential malware
- Unusual launch patterns indicate automation
- System Manipulation
- Accessibility service abuse
- System UI overlays
- Permission escalation attempts
- Performance Artifacts
- Crash counts indicate unstable apps
- Memory usage shows resource abuse
- Restart patterns reveal persistence
Investigative Applications
| Investigation Type | Relevant Activity Data |
|---|---|
| User Attribution | Current activity, recent tasks |
| Malware Detection | Hidden services, crashes, persistence |
| Timeline Reconstruction | Launch times, state transitions |
| App Behavior Analysis | Memory usage, crash patterns |
| Automation Detection | Rapid transitions, accessibility services |
| Data Exfiltration | Background services during inactive periods |
Relationship to Other Logs
Activity Manager as Central Hub
Activity Manager ←→ Package Manager
└─ Validates installed components
Activity Manager ←→ Window Manager
└─ Coordinates UI display
Activity Manager ←→ Power Manager
└─ Wake lock attribution
Activity Manager ←→ Content Providers
└─ Manages data access
Powerful Correlation Techniques
App Launch to Network Activity
bash
# Find app launches
LAUNCH_TIME=$(adb shell dumpsys activity recents | \
grep -A3 "com.target.app" | \
grep "lastActiveTime=" | \
sed 's/.*lastActiveTime=//')
# Check network activity around launch
echo "App launched at: $(date -d @$((LAUNCH_TIME/1000)))"
# Query network stats for same period
adb shell dumpsys netstats | \
awk -v time="$LAUNCH_TIME" '
/st=/ && $0 \~ time {
print "Network activity found:", $0
- }'
Service Correlation with Battery Drain
bash
# Long-running services
adb shell dumpsys activity services | \
grep -E "ServiceRecord|createTime=" | \
grep -B1 "createTime=" | \
awk '/ServiceRecord/ {service=$0}
/createTime/ {
match($0, /createTime=([0-9]+)/, t)
age \= (systime() * 1000 - t[1]) / 1000 / 60
if (age > 60) print service, "running for", age, "minutes"
}' > long_services.txt
# Cross-reference with battery stats
while read line; do
SERVICE=$(echo "$line" | awk -F'[{}]' '{print $2}' | awk '{print $3}')
echo "Checking battery impact of: $SERVICE"
adb shell dumpsys batterystats | grep -A5 "$SERVICE"
- done \< long_services.txt
Hidden App Detection
bash
# Find apps with services but no activities
# Get all services
adb shell dumpsys activity services | \
grep "ServiceRecord{" | \
awk -F'[{}]' '{print $2}' | \
awk '{print $3}' | \
cut -d'/' -f1 | sort -u > service_apps.txt
# Get all activities
adb shell dumpsys activity activities | \
grep "ActivityRecord{" | \
awk -F'[{}]' '{print $2}' | \
awk '{print $3}' | \
cut -d'/' -f1 | sort -u > activity_apps.txt
# Find services without UI
- comm -23 service_apps.txt activity_apps.txt > hidden_service_apps.txt
Legal Considerations
Admissibility Factors
- Volatility: Activity data is RAM-based, must be captured quickly
- Authenticity: System-generated, difficult to forge
- Timeliness: Represents state at exact extraction time
- Completeness: May miss historical data
Court Presentation Best Practices
python
#!/usr/bin/env python3
# create_activity_timeline.py
import re
from datetime import datetime
import json
class ActivityTimeline:
def __init__(self, activity_dump):
self.activity_dump \= activity_dump
self.timeline \= []
def parse\_activities(self):
"""Extract activity launch events"""
with open(self.activity\_dump, 'r') as f:
content \= f.read()
*\# Find all activity records with times*
pattern \= r'ActivityRecord{(\[^}\]+)}.\*?launchTime=(\\d+).\*?state=(\\w+)'
for match in re.finditer(pattern, content, re.DOTALL):
record\_id \= match.group(1)
launch\_time \= int(match.group(2))
state \= match.group(3)
*\# Extract app name*
app\_match \= re.search(r'(\\S+)/(\\S+)', record\_id)
if app\_match:
package \= app\_match.group(1)
activity \= app\_match.group(2)
self.timeline.append({
'timestamp': datetime.fromtimestamp(launch\_time/1000),
'package': package,
'activity': activity,
'state': state,
'type': 'activity\_launch'
})
def parse\_services(self):
"""Extract service start events"""
pattern \= r'ServiceRecord{\[^}\]+\\s+(\\S+)}.\*?createTime=(\\d+)'
with open(self.activity\_dump, 'r') as f:
for match in re.finditer(pattern, f.read()):
service \= match.group(1)
create\_time \= int(match.group(2))
self.timeline.append({
'timestamp': datetime.fromtimestamp(create\_time/1000),
'service': service,
'type': 'service\_start'
})
def generate\_report(self):
"""Create court-friendly timeline"""
print("ANDROID ACTIVITY TIMELINE REPORT")
print("=" \* 50)
print(f"Generated: {datetime.now()}\\n")
*\# Sort by time*
self.timeline.sort(key\=lambda x: x\['timestamp'\])
current\_date \= None
for event in self.timeline:
event\_date \= event\['timestamp'\].date()
if event\_date \!= current\_date:
print(f"\\n{event\_date}")
print("-" \* 30)
current\_date \= event\_date
time\_str \= event\['timestamp'\].strftime("%H:%M:%S")
if event\['type'\] \== 'activity\_launch':
print(f"{time\_str} \- User opened: {event\['package'\]}")
print(f" Screen: {event\['activity'\]}")
print(f" State: {event\['state'\]}")
elif event\['type'\] \== 'service\_start':
print(f"{time\_str} \- Service started: {event\['service'\]}")
# Usage
timeline \= ActivityTimeline('activity_full.txt')
timeline.parse_activities()
timeline.parse_services()
timeline.generate_report()
Common Challenges and Solutions
| Challenge | Solution |
|---|---|
| Volatile data | Extract immediately upon device seizure |
| Large output size | Use filtered dumps for specific components |
| Process churn | Multiple extractions to catch changes |
| System apps noise | Filter out com.android.* packages |
| Timestamp format | Convert milliseconds since epoch |
| State interpretation | Reference state transition diagram |
Advanced Analysis Techniques
Behavioral Pattern Analysis
bash
#!/bin/bash
# analyze_behavior_patterns.sh
echo "=== User Behavior Pattern Analysis \==="
# 1. App usage sequences
echo -e "\n[+] Common App Sequences:"
adb shell dumpsys activity recents | \
grep "realActivity=" | \
awk '{
gsub(/.*realActivity=/, "")
gsub(/{|}/, "")
if (prev) {
sequences[prev " -> " $0]++
}
prev \= $0
}
END {
for (seq in sequences) {
if (sequences[seq] > 2) {
print sequences[seq] "x:", seq
}
}
}' | sort -nr
# 2. Time-based usage patterns
echo -e "\n[+] Hourly Activity Distribution:"
adb shell dumpsys activity recents | \
grep "lastActiveTime=" | \
awk '{
match($0, /lastActiveTime\=([0-9]+)/, t)
hour \= strftime("%H", t[1]/1000)
hours[hour]++
}
END {
for (h\=0; h\<24; h++) {
Edit
bash
printf "%02d:00 - ", h
for (i\=0; i\<hours[sprintf("%02d",h)]; i++) printf "█"
printf " (%d)\n", hours[sprintf("%02d",h)]
}
}'
# 3. Session duration analysis
echo -e "\n[+] App Session Durations:"
adb shell dumpsys activity activities | \
awk '
/ActivityRecord.*launchTime\=/ {
match($0, /launchTime\=([0-9]+)/, launch)
match($0, /([^\/]+)\//, app)
app_launch[app[1]] \= launch[1]
}
/pauseTime\=/ && app[1] {
match($0, /pauseTime\=([0-9]+)/, pause)
if (app_launch[app[1]]) {
duration \= (pause[1] - app_launch[app[1]]) / 1000 / 60
print app[1], "session:", int(duration), "minutes"
delete app_launch[app[1]]
}
}
' | sort -k3 -nr | head -20
Malware Behavior Detection
python
#!/usr/bin/env python3
# detect_malware_behavior.py
import re
from collections import defaultdict
class MalwareDetector:
def __init__(self, activity_dump):
self.activity_dump \= activity_dump
self.suspicious_patterns \= []
def analyze(self):
"""Run all malware detection heuristics"""
with open(self.activity\_dump, 'r') as f:
self.content \= f.read()
self.detect\_hidden\_services()
self.detect\_persistent\_processes()
self.detect\_accessibility\_abuse()
self.detect\_overlay\_attacks()
self.detect\_unusual\_launches()
def detect\_hidden\_services(self):
"""Find services without corresponding activities"""
*\# Extract all services*
services \= re.findall(r'ServiceRecord{\[^}\]+\\s+(\[^/\]+)/(\[^}\]+)}', self.content)
service\_packages \= set(s\[0\] for s in services)
*\# Extract all activities*
activities \= re.findall(r'ActivityRecord{\[^}\]+\\s+(\[^/\]+)/(\[^}\]+)}', self.content)
activity\_packages \= set(a\[0\] for a in activities)
*\# Find services without UI*
hidden \= service\_packages \- activity\_packages
for package in hidden:
if not package.startswith('com.android'):
self.suspicious\_patterns.append({
'type': 'HIDDEN\_SERVICE',
'package': package,
'risk': 'HIGH',
'description': 'Service running without user interface'
})
def detect\_persistent\_processes(self):
"""Find processes that resist termination"""
pattern \= r'ProcessRecord{\[^}\]+:(\[^/\]+)/\[^}\]+}.\*?restartCount=(\\d+).\*?persistent=(\\w+)'
for match in re.finditer(pattern, self.content, re.DOTALL):
process \= match.group(1)
restart\_count \= int(match.group(2))
persistent \= match.group(3) \== 'true'
if restart\_count \> 10 or (persistent and not process.startswith('com.android')):
self.suspicious\_patterns.append({
'type': 'PERSISTENT\_PROCESS',
'process': process,
'restart\_count': restart\_count,
'persistent': persistent,
'risk': 'HIGH' if restart\_count \> 20 else 'MEDIUM',
'description': 'Process shows persistence behavior'
})
def detect\_accessibility\_abuse(self):
"""Find potential accessibility service abuse"""
*\# Look for accessibility services*
accessibility\_pattern \= r'ServiceRecord{\[^}\]+\\s+(\[^/\]+)/\[^}\]\*Accessibility\[^}\]\*}'
for match in re.finditer(accessibility\_pattern, self.content):
package \= match.group(1)
*\# Check if it's a known accessibility app*
if package not in \['com.google.android.marvin.talkback',
'com.android.talkback'\]:
self.suspicious\_patterns.append({
'type': 'ACCESSIBILITY\_SERVICE',
'package': package,
'risk': 'HIGH',
'description': 'Non-standard accessibility service detected'
})
def detect\_overlay\_attacks(self):
"""Find potential overlay/clickjacking attempts"""
*\# Look for TYPE\_SYSTEM\_ALERT windows*
overlay\_pattern \= r'Window{\[^}\]+\\s+(\[^/\]+)/\[^}\]+}.\*?ty=2003' *\# TYPE\_SYSTEM\_ALERT*
for match in re.finditer(overlay\_pattern, self.content):
package \= match.group(1)
if not package.startswith('com.android'):
self.suspicious\_patterns.append({
'type': 'OVERLAY\_WINDOW',
'package': package,
'risk': 'HIGH',
'description': 'App creating system overlay windows'
})
def detect\_unusual\_launches(self):
"""Find apps launched in unusual ways"""
*\# Check for apps launched by other apps*
launch\_pattern \= r'launchedFromPackage=(\[^\\s\]+).\*?ActivityRecord{\[^}\]+\\s+(\[^/\]+)/'
for match in re.finditer(launch\_pattern, self.content, re.DOTALL):
launcher \= match.group(1)
launched \= match.group(2)
if launcher \!= 'null' and launcher \!= launched:
if not launcher.startswith('com.android'):
self.suspicious\_patterns.append({
'type': 'CROSS\_APP\_LAUNCH',
'launcher': launcher,
'launched': launched,
'risk': 'MEDIUM',
'description': f'{launcher} launching {launched}'
})
def generate\_report(self):
"""Generate malware detection report"""
print("=== MALWARE BEHAVIOR DETECTION REPORT \===\\n")
if not self.suspicious\_patterns:
print("No suspicious patterns detected.")
return
*\# Group by risk level*
high\_risk \= \[p for p in self.suspicious\_patterns if p\['risk'\] \== 'HIGH'\]
medium\_risk \= \[p for p in self.suspicious\_patterns if p\['risk'\] \== 'MEDIUM'\]
if high\_risk:
print("HIGH RISK FINDINGS:")
print("-" \* 40)
for pattern in high\_risk:
print(f"\\n\[{pattern\['type'\]}\]")
print(f"Description: {pattern\['description'\]}")
for key, value in pattern.items():
if key not in \['type', 'description', 'risk'\]:
print(f"{key}: {value}")
if medium\_risk:
print("\\n\\nMEDIUM RISK FINDINGS:")
print("-" \* 40)
for pattern in medium\_risk:
print(f"\\n\[{pattern\['type'\]}\]")
print(f"Description: {pattern\['description'\]}")
for key, value in pattern.items():
if key not in \['type', 'description', 'risk'\]:
print(f"{key}: {value}")
# Usage
detector \= MalwareDetector('activity_full.txt')
detector.analyze()
detector.generate_report()
Process Forensics and Memory Analysis
bash
#!/bin/bash
# process_forensics.sh
echo "=== Process Forensics Analysis \==="
# 1. Extract process memory information
echo -e "\n[+] Process Memory Analysis:"
adb shell dumpsys activity processes | \
awk '
/ProcessRecord{/ {
match($0, /ProcessRecord{[^}]+\s+[0-9]+:([^/]+)/, app)
current_app \= app[1]
}
/lastPss=/ && current_app {
match($0, /lastPss=([0-9]+)/, pss)
match($0, /lastSwapPss=([0-9]+)/, swap)
match($0, /lastCachedPss=([0-9]+)/, cached)
total\_mb \= (pss\[1\] \+ swap\[1\]) / 1024
cached\_mb \= cached\[1\] / 1024
printf "%-30s Total: %6.1f MB (Cached: %6.1f MB)\\n",
current\_app, total\_mb, cached\_mb
}
' | sort -k3 -nr | head -20
# 2. Find memory leaks (high memory, low activity)
echo -e "\n[+] Potential Memory Leaks:"
adb shell dumpsys activity processes | \
awk '
/ProcessRecord{/ {
process \= $0
high_memory \= 0
}
/lastPss=([0-9]{6,})/ { # Over 100MB
high_memory \= 1
}
/lastActivityTime=/ && high_memory {
match($0, /lastActivityTime=([0-9]+)/, t)
age \= (systime() * 1000 - t[1]) / 1000 / 60
if (age > 30) { # Inactive for 30+ minutes
print process
print " High memory with", int(age), "minutes of inactivity"
}
}
'
# 3. Process relationships and dependencies
echo -e "\n[+] Process Dependencies:"
adb shell dumpsys activity services | \
grep -E "ProcessRecord|connections=" | \
grep -A1 "connections={" | \
grep -v "^--$" | \
awk '
/ProcessRecord/ {
current_proc \= $0
}
/connections=/ && current_proc {
if ($0 !\~ /connections={}/) {
print current_proc
print " Connected to:", $0
}
}
'
Integration with Forensic Workflow
Live Forensics Script
bash
#!/bin/bash
# live_activity_forensics.sh
# Comprehensive activity extraction for forensics
CASE_ID=$1
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTPUT_DIR="activity_forensics_${CASE_ID}_${TIMESTAMP}"
mkdir -p "$OUTPUT_DIR"
echo "Starting Activity Manager Forensic Extraction"
echo "Case ID: $CASE_ID"
echo "Timestamp: $TIMESTAMP"
# 1. Current state snapshot
echo "[+] Capturing current state..."
adb shell dumpsys activity > "$OUTPUT_DIR/activity_complete.txt"
adb shell dumpsys activity top > "$OUTPUT_DIR/current_screen.txt"
adb shell ps -A > "$OUTPUT_DIR/process_list.txt"
# 2. Extract key components
echo "[+] Extracting components..."
for component in activities services processes broadcasts providers recents; do
echo " - Extracting $component"
adb shell dumpsys activity $component > "$OUTPUT_DIR/${component}.txt"
done
# 3. Memory state
echo "[+] Capturing memory state..."
adb shell dumpsys meminfo > "$OUTPUT_DIR/meminfo.txt"
adb shell cat /proc/meminfo > "$OUTPUT_DIR/proc_meminfo.txt"
# 4. Create timeline
echo "[+] Creating timeline..."
cat > "$OUTPUT_DIR/create_timeline.py" \<\< 'EOF'
import re
from datetime import datetime
# Parse recent tasks
with open('recents.txt', 'r') as f:
content \= f.read()
timeline \= []
pattern \= r'Recent #(\d+):.*?realActivity=([^}]+).*?lastActiveTime=(\d+)'
for match in re.finditer(pattern, content, re.DOTALL):
num \= match.group(1)
activity \= match.group(2)
timestamp \= int(match.group(3))
timeline.append({
'time': datetime.fromtimestamp(timestamp/1000),
'activity': activity,
'position': num
})
# Output timeline
with open('activity_timeline.csv', 'w') as out:
out.write('Timestamp,Position,Activity\n')
for event in sorted(timeline, key=lambda x: x['time'], reverse=True):
out.write(f"{event['time']},{event['position']},{event['activity']}\n")
EOF
cd "$OUTPUT_DIR"
python3 create_timeline.py
# 5. Generate analysis report
echo "[+] Generating analysis report..."
cat > "analysis_report.txt" \<\< EOF
Activity Manager Forensic Analysis Report
\========================================
Case ID: $CASE_ID
Extraction Date: $(date)
Device: $(adb shell getprop ro.product.model)
Android Version: $(adb shell getprop ro.build.version.release)
Current State Summary
--------------------
Current App: $(grep -m1 "mResumedActivity" activity_complete.txt | sed 's/.*ActivityRecord{[^}]*\s\+\([^}]*\)}.*/\1/')
Running Apps: $(grep -c "ProcessRecord{" processes.txt)
Running Services: $(grep -c "ServiceRecord{" services.txt)
Recent Tasks: $(grep -c "Recent #" recents.txt)
High-Risk Findings
-----------------
EOF
# Check for suspicious patterns
grep -E "persistent=true|hidden=true" processes.txt | \
grep -v "com.android" >> analysis_report.txt
echo -e "\nPotential Issues:" >> analysis_report.txt
grep "crashCount=[1-9]" processes.txt >> analysis_report.txt
# 6. Create hashes
echo "[+] Creating integrity hashes..."
find . -name "*.txt" -exec sha256sum {} \; > file_hashes.txt
echo "Extraction complete. Results in: $OUTPUT_DIR"
Conclusion
Activity Manager logs provide critical real-time visibility into Android device state, offering:
- Immediate State Capture: What's currently running and visible
- Process Intelligence: Memory usage, crashes, and persistence
- Service Monitoring: Background operations and hidden activities
- User Flow Tracking: App launches and task switching patterns
- System Manipulation Detection: Overlays, accessibility abuse, and automation
Key forensic advantages:
- Volatile but Valuable: Captures current state precisely
- Behavioral Insights: Reveals app and user behavior patterns
- Malware Detection: Identifies suspicious process characteristics
- Timeline Support: Provides launch times and state transitions
- Cross-Validation: Correlates with other log sources
When combined with persistent logs (package manager, usage stats, battery stats), Activity Manager data completes the forensic picture by showing what was happening at the exact moment of extraction. This makes it invaluable for incident response, malware analysis, and user behavior investigations.
The ephemeral nature of this data means investigators must prioritize its extraction immediately upon device acquisition, as critical evidence about running processes and current state will be lost upon reboot or over time as the system manages memory.