Migration Guide

This guide helps you migrate from the legacy Sandroid installation to the modern PyPI package, and understand the changes introduced in v1.1.0.

Migration Overview

What Changed in v1.1.0:

  • Complete package restructuring from src/utils/ to proper Python packages

  • Modern PyPI distribution with all analysis modules included

  • New configuration system with sandroid-config CLI tool

  • Dual-mode architecture supporting both legacy and modern usage

  • Fixed the critical “Legacy analysis modules not available” error

Migration Types:

  1. Gradual Migration - Use both systems in parallel (recommended)

  2. Complete Migration - Switch entirely to modern system

  3. Development Migration - Update development workflows

Legacy to Modern Migration

Current State Assessment:

First, determine your current setup:

# Check if you have legacy installation
ls -la ./sandroid  # Legacy script exists?

# Check if you have PyPI installation
which sandroid    # Modern command available?
sandroid --version  # Should show 1.1.0+

Gradual Migration (Recommended):

This approach lets you test the modern system while keeping the legacy system working:

# 1. Keep your existing legacy installation
# Don't remove anything yet

# 2. Install modern PyPI package alongside
pip install sandroid

# 3. Test modern installation
sandroid --version  # Should work without "legacy modules" error
sandroid --help     # Should show full help

# 4. Initialize modern configuration
sandroid-config init

# 5. Test side-by-side
./sandroid --help         # Legacy way (still works)
sandroid --help           # Modern way (now also works)

Configuration Migration:

# 1. Create modern configuration
sandroid-config init

# 2. Migrate settings from legacy hardcoded values
# Check your current settings in src/utils/toolbox.py
grep -r "device_name\|results_path\|number_of_runs" src/utils/

# 3. Set corresponding values in modern config
sandroid-config set emulator.device_name "Your_Current_Device"
sandroid-config set paths.results_path "./results/"
sandroid-config set analysis.number_of_runs 2

Testing Migration:

# Test with identical parameters

# Legacy way:
./sandroid -n 2 --network --screenshot 5

# Modern way:
sandroid --number 2 --network --screenshot 5

# Compare results - they should be identical

Complete Migration:

Once you’re confident the modern system works:

# 1. Archive your legacy installation
tar -czf sandroid_legacy_backup.tar.gz src/ utils/ *.py sandroid

# 2. Update your scripts/aliases
echo "alias sandroid-legacy='./sandroid'" >> ~/.bashrc
echo "alias sandroid='sandroid'"  # Modern version is now default

# 3. Update documentation and workflows
# Replace ./sandroid with sandroid in scripts

Package Structure Migration

Old Structure (Legacy):

Sandroid_core/
├── src/
│   ├── utils/           # Core utilities (15 modules)
│   ├── datagather/      # Analysis modules (10 modules)
│   └── functionality/   # Feature modules (5 modules)
├── sandroid             # Main script
└── install-requirements.sh

New Structure (Modern):

Sandroid_core/
├── src/sandroid/
│   ├── core/           # Was: src/utils/ (15 modules)
│   ├── analysis/       # Was: src/datagather/ (10 modules)
│   ├── features/       # Was: src/functionality/ (5 modules)
│   ├── config/         # New: Configuration system
│   └── cli.py          # New: Modern CLI entry point
├── src/utils/          # Compatibility aliases
├── src/datagather/     # Compatibility aliases
├── src/functionality/  # Compatibility aliases
└── sandroid            # Still works (legacy compatibility)

Import Path Changes:

If you have custom code importing Sandroid modules:

# Old imports (still work via compatibility layer):
from src.utils.toolbox import Toolbox
from src.datagather.changedfiles import ChangedFiles
from src.functionality.screenshot import Screenshot

# New imports (recommended):
from sandroid.core.toolbox import Toolbox
from sandroid.analysis.changedfiles import ChangedFiles
from sandroid.features.screenshot import Screenshot

Development Workflow Migration

Legacy Development Setup:

git clone https://github.com/fkie-cad/Sandroid_core.git
cd Sandroid_core
./install-requirements.sh
./sandroid --help

Modern Development Setup:

git clone https://github.com/fkie-cad/Sandroid_core.git
cd Sandroid_core

# Install in development mode
pip install -e .[dev]

# Initialize configuration
sandroid-config init

# Test installation
sandroid --version
sandroid --help

CI/CD Migration:

Legacy CI Pipeline:

- name: Setup Sandroid
  run: |
    git clone https://github.com/fkie-cad/Sandroid_core.git
    cd Sandroid_core
    ./install-requirements.sh

- name: Run Analysis
  run: |
    cd Sandroid_core
    ./sandroid --network --report

Modern CI Pipeline:

- name: Setup Sandroid
  run: |
    pip install sandroid[ai]
    sandroid-config init

- name: Run Analysis
  run: |
    sandroid --network --report

Docker Migration:

Legacy Dockerfile:

FROM python:3.10
RUN git clone https://github.com/fkie-cad/Sandroid_core.git
WORKDIR /app/Sandroid_core
RUN ./install-requirements.sh
CMD ["./sandroid"]

Modern Dockerfile:

FROM python:3.10
RUN pip install sandroid[ai]
RUN sandroid-config init
CMD ["sandroid"]

Configuration System Migration

Legacy Configuration (Hardcoded):

Previously, configuration was hardcoded in src/utils/toolbox.py:

# Old way - hardcoded values
class Toolbox:
    device_name = "Pixel_6_Pro_API_31"
    results_path = "./results/"
    number_of_runs = 2

Modern Configuration (File-based):

Now configuration uses structured files:

# ~/.config/sandroid/sandroid.toml
log_level = "INFO"
output_file = "sandroid.json"

[emulator]
device_name = "Pixel_6_Pro_API_31"

[analysis]
number_of_runs = 2

[paths]
results_path = "./results/"

Environment Variable Migration:

Legacy:

export RESULTS_PATH="/custom/results"
export RAW_RESULTS_PATH="/custom/raw"

Modern:

export SANDROID_PATHS__RESULTS_PATH="/custom/results"
export SANDROID_PATHS__RAW_RESULTS_PATH="/custom/raw"

API Migration Guide

For Developers Using Sandroid as a Library:

Legacy API Usage:

# Old way
sys.path.append('path/to/Sandroid_core/src')
from utils.toolbox import Toolbox
from datagather.changedfiles import ChangedFiles

# Initialize and run
toolbox = Toolbox()
changed_files = ChangedFiles()
changed_files.gather()

Modern API Usage:

# New way
from sandroid.core.toolbox import Toolbox
from sandroid.analysis.changedfiles import ChangedFiles
from sandroid.config.loader import load_config

# Initialize with configuration
config = load_config()
Toolbox.configure(config)

# Use analysis modules
changed_files = ChangedFiles()
changed_files.gather()

Custom Module Development:

Legacy Custom Module:

# old_custom_module.py
import sys
sys.path.append('src/')
from utils.toolbox import Toolbox
from datagather.datagather import DataGather

class CustomAnalyzer(DataGather):
    def gather(self):
        # Custom logic
        pass

Modern Custom Module:

# modern_custom_module.py
from sandroid.core.toolbox import Toolbox
from sandroid.analysis.datagather import DataGather
from sandroid.config.loader import load_config

class CustomAnalyzer(DataGather):
    def __init__(self):
        super().__init__()
        self.config = load_config()

    def gather(self):
        # Custom logic with configuration support
        pass

Breaking Changes and Compatibility

No Breaking Changes for End Users:

  • All CLI commands work identically

  • All analysis results are the same format

  • All interactive menu options unchanged

  • Legacy ./sandroid script still works

Potential Issues for Developers:

  1. Direct File Path Dependencies:

# This might break:
with open('src/utils/config.py') as f:
    content = f.read()

# Use imports instead:
from sandroid.core import config
  1. Hardcoded sys.path Modifications:

# This is no longer needed:
sys.path.append('src/')

# Just use normal imports:
from sandroid.core.toolbox import Toolbox
  1. Assumption About File Structure:

# Don't assume file paths:
config_path = 'src/utils/config.json'  # Bad

# Use proper configuration:
from sandroid.config.loader import find_config_file
config_path = find_config_file()  # Good

Validation and Testing

Migration Validation Checklist:

# 1. Installation validation
sandroid --version  # Should show 1.1.0+
sandroid-config validate  # Should pass

# 2. Basic functionality
sandroid --help  # Should show full help without errors

# 3. Configuration system
sandroid-config show  # Should display configuration

# 4. Analysis capability
sandroid --number 1 --screenshot 10  # Should run without errors

# 5. Compatibility
./sandroid --help  # Legacy script should still work

Regression Testing:

# Test with same APK using both methods

# Legacy method
./sandroid --number 2 --network --output legacy_results.json

# Modern method
sandroid --number 2 --network --output modern_results.json

# Compare results (should be identical)
diff legacy_results.json modern_results.json

Performance Comparison:

# Time both methods
time ./sandroid --number 2
time sandroid --number 2

# Performance should be identical or better

Rollback Plan

If you need to rollback the modern installation:

# 1. Remove PyPI installation
pip uninstall sandroid

# 2. Restore legacy installation (if you have backup)
tar -xzf sandroid_legacy_backup.tar.gz

# 3. Reinstall legacy dependencies
./install-requirements.sh

# 4. Test legacy functionality
./sandroid --version

Common Migration Issues

Issue: “Command not found: sandroid”

# Solution: Check pip installation location
pip show sandroid

# Add to PATH if needed
export PATH=$PATH:~/.local/bin

Issue: “Configuration file not found”

# Solution: Initialize configuration
sandroid-config init

# Or create manually
mkdir -p ~/.config/sandroid
sandroid-config init

Issue: “Import errors in custom code”

# Update import statements
# Old:
from src.utils.toolbox import Toolbox

# New:
from sandroid.core.toolbox import Toolbox

Issue: “Different results between legacy and modern”

# Check configuration differences
sandroid-config show

# Ensure same parameters
sandroid --loglevel DEBUG --number 2

Issue: “Performance degradation”

# Check for conflicting installations
which sandroid
pip list | grep sandroid

# Clear Python cache
find . -name "*.pyc" -delete
find . -name "__pycache__" -delete

Support and Help

Getting Help During Migration:

  1. Check Documentation: - Installation - Modern installation guide - Troubleshooting - Common issues and solutions

  2. Validate Your Setup:

sandroid-config validate
sandroid --version
sandroid --help
  1. Enable Debug Mode:

SANDROID_LOG_LEVEL=DEBUG sandroid --network
  1. Report Issues: - GitHub Issues: https://github.com/fkie-cad/Sandroid_core/issues - Include: Sandroid version, system info, error messages

Pre-Migration Checklist:

  • [ ] Backup current installation

  • [ ] Document current configuration/settings

  • [ ] Test modern installation in parallel

  • [ ] Validate results match between versions

  • [ ] Update scripts and documentation

  • [ ] Train team on new configuration system

Post-Migration Checklist:

  • [ ] All team members can run sandroid --version

  • [ ] Configuration system is working: sandroid-config validate

  • [ ] CI/CD pipelines updated and tested

  • [ ] Documentation reflects modern installation

  • [ ] Legacy backup is archived safely

This migration ensures you get all the benefits of the modern Sandroid system while maintaining complete compatibility with your existing workflows.