diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 4672da2..4ef99cc 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -1,16 +1,33 @@ # Building ISO Droid -This document contains technical information for building and understanding ISO Droid. +This document explains how to build ISO Droid from source and contribute to the project. ## Building from Source ### Prerequisites -Before building the app, you need to obtain the `isodrive` binary: +**1. isodrive Binary (Required)** -1. The `isodrive` binary is compiled from [nitanmarcel/isodrive](https://github.com/nitanmarcel/isodrive) -2. Place the compiled binary at `app/src/main/assets/bin/isodrive` before building -3. The binary must be executable and compiled for the appropriate Android architecture (ARM64 recommended for modern devices) +ISO Droid requires the `isodrive` binary to function. This binary is the actual tool that communicates with the Linux kernel's USB gadget subsystem to mount ISO/IMG files. + +- **Source**: The binary is compiled from [nitanmarcel/isodrive](https://github.com/nitanmarcel/isodrive) +- **Why required**: Android apps cannot directly access USB gadget interfaces - they need a native binary with root privileges +- **Location**: Place the compiled binary at `app/src/main/assets/bin/isodrive` +- **Architecture**: Must be compiled for ARM64 (aarch64) for modern Android devices + +**How to obtain the binary:** + +Option 1: Download precompiled binary from [isodrive releases](https://github.com/nitanmarcel/isodrive/releases) + +Option 2: Compile from source: +```bash +# Clone isodrive repository +git clone https://github.com/nitanmarcel/isodrive.git +cd isodrive + +# Build for Android (requires Android NDK) +# Follow the build instructions in the isodrive repository +``` ### Build Steps @@ -22,311 +39,171 @@ cd ISODroid # Ensure isodrive binary is present ls -la app/src/main/assets/bin/isodrive -# Build the debug APK +# Build debug APK ./gradlew assembleDebug -# Or build the release APK (requires signing configuration) +# Or build release APK (requires signing configuration) ./gradlew assembleRelease ``` -The compiled APK will be located at: +The compiled APK will be in: - Debug: `app/build/outputs/apk/debug/app-debug.apk` - Release: `app/build/outputs/apk/release/app-release.apk` -## Technical Architecture - -### Overview - -ISO Droid is built using modern Android development practices: -- **Language**: Kotlin -- **UI Framework**: Jetpack Compose (Material 3) -- **Architecture**: MVVM (Model-View-ViewModel) -- **Minimum SDK**: 26 (Android 8.0) -- **Target SDK**: 34 (Android 14) - -### Core Components - -#### 1. IsoDriveManager (`isodrive/IsoDriveManager.kt`) - -The central component that interfaces with the `isodrive` binary: - -- **Binary Extraction**: Copies the bundled `isodrive` binary from assets to app-specific storage -- **Permission Management**: Ensures the binary has executable permissions (`chmod 755`) -- **Command Execution**: Wraps all isodrive commands (mount, unmount, status checks) -- **Device Support Detection**: Checks for configfs or sysfs USB gadget support - -```kotlin -// Example: Mounting an ISO -isoDriveManager.mount( - filePath = "/sdcard/isodrive/ubuntu.iso", - mountType = MountType.CDROM, - readOnly = true -) -``` - -#### 2. RootManager (`root/RootManager.kt`) - -Handles all root access operations: - -- **Root Detection**: Checks for available root methods (Magisk, KernelSU, APatch, su binary) -- **Cached Status**: Stores root grant status to avoid repeated prompts -- **Command Execution**: Executes shell commands with root privileges -- **Error Handling**: Captures stdout, stderr, and exit codes - -```kotlin -val result = RootManager.executeCommand("isodrive status") -if (result.isSuccess) { - // Parse output -} -``` - -#### 3. USB Gadget Subsystem - -ISO Droid supports both modern and legacy USB gadget interfaces: - -**ConfigFS (Modern - Preferred)** -- Path: `/config/usb_gadget/` -- More flexible and feature-rich -- Standard on Android 8.0+ devices - -**SysFS (Legacy)** -- Path: `/sys/class/android_usb/` -- Older interface -- Fallback for older devices - -The `isodrive` binary automatically detects and uses the appropriate interface. - -#### 4. Mount Types - -**Mass Storage Mode** -- Exposes the file as a USB mass storage device -- Supports read-write mode for IMG files -- Host PC sees it as a USB flash drive -- Can be formatted with any filesystem (FAT32, NTFS, exFAT, ext4) - -**CD-ROM Mode** -- Exposes the file as a virtual CD/DVD drive -- Always read-only -- Ideal for bootable ISOs -- Host PC sees it as an optical drive - -### UI Architecture - -#### Jetpack Compose - -All UI is built using Jetpack Compose with Material 3: - -- **Declarative**: UI is a function of state -- **Reactive**: Automatically updates when state changes -- **Type-safe**: Compile-time checking for UI code - -#### Key Screens - -1. **MainScreen** (`ui/screens/MainScreen.kt`) - - File browser with OS icon detection - - Mount/unmount operations - - Status card showing current mount state - -2. **DownloadsScreen** (`ui/screens/DownloadsScreen.kt`) - - Curated list of OS download links - - Grouped by category (Linux, BSD, Windows, Recovery) - -3. **SettingsScreen** (`ui/screens/SettingsScreen.kt`) - - Root permission status - - Notification permission (Android 13+) - - Default ISO directory configuration - - App version and build information - -#### State Management - -Uses Kotlin StateFlow for reactive state: - -```kotlin -data class MainUiState( - val isLoading: Boolean = true, - val hasRoot: Boolean? = null, - val isSupported: Boolean? = null, - val mountStatus: MountStatus = MountStatus.UNMOUNTED, - val isoFiles: List = emptyList(), - // ... -) -``` - -### OS Icon Detection - -Dynamic icon matching system: - -1. **Icon Storage**: SVG files in `app/src/main/assets/osicons/` -2. **Dynamic Loading**: Icons are loaded at runtime via `AssetManager` -3. **Fuzzy Matching**: Filename matching algorithm: - - Converts filename to lowercase - - Checks for icon name presence (e.g., "ubuntu" in "ubuntu-22.04-desktop.iso") - - Prioritizes longer matches (e.g., "linuxmint" over "linux") - - Prefers earlier position in filename - -4. **Rendering**: Uses Coil image library with SVG decoder -5. **Badge System**: Small circular badge shows file type (ISO/IMG) - -### File Operations - -#### Creating IMG Files - -```kotlin -// User specifies size (e.g., 4 GB) -val sizeBytes = 4L * 1024 * 1024 * 1024 - -// Creates sparse file using dd with progress reporting -dd if=/dev/zero of=/sdcard/isodrive/custom.img bs=1M count=4096 - -// Progress events are emitted via CreateImgEventBus -``` - -#### Rename/Delete Protection - -- Files currently mounted cannot be renamed or deleted -- UI shows warning message and disables actions -- Prevents accidental data corruption - -### Notifications - -Persistent notification while mounted: - -- **Information**: Shows mounted filename and mount type -- **Quick Actions**: Unmount button in notification -- **Foreground Service**: Ensures notification stays visible -- **Auto-dismiss**: Notification removed after unmount - -### Data Persistence - -Uses Android DataStore (Preferences): - -```kotlin -// Saves user preferences -dataStore.edit { preferences -> - preferences[KEY_ISO_DIRECTORY] = "/sdcard/custom/path" -} -``` - -Stores: -- ISO directory path -- Root grant status (from setup wizard) -- App settings - -### Event Bus System - -Decoupled communication using Kotlin Flow: - -```kotlin -// Mount events -object MountEventBus { - private val _events = MutableSharedFlow() - val events: SharedFlow = _events.asSharedFlow() -} - -// Emit event from notification -MountEventBus.emit(MountEvent.Unmounted) - -// Observe in ViewModel -MountEventBus.events.collect { event -> - when (event) { - is MountEvent.Unmounted -> updateUiState() - } -} -``` - -## Dependencies - -### Core Libraries - -- **Jetpack Compose**: Modern declarative UI -- **Material 3**: Design system and components -- **Lifecycle & ViewModel**: Android Architecture Components -- **DataStore**: Modern preference storage -- **Coroutines**: Asynchronous programming - -### Image Loading - -- **Coil**: Image loading library -- **Coil SVG**: SVG decoder for OS icons - -### JSON Parsing - -- **org.json**: Parsing OS download list (`assets/os.json`) - -## Testing - -### Manual Testing Checklist - -- [ ] Root access granted on first launch -- [ ] USB gadget support detected correctly -- [ ] ISO files mount successfully -- [ ] IMG files can be created and mounted -- [ ] OS icons display correctly -- [ ] Unmount via notification works -- [ ] File rename/delete protection when mounted -- [ ] Settings persist across app restarts -- [ ] Dark mode toggles correctly - -### Device Compatibility - -Tested on: -- Modern devices with ConfigFS (Android 8.0+) -- Legacy devices with SysFS (older Android versions) -- Various root methods (Magisk, KernelSU, APatch) - -## Debugging - -### Enable Verbose Logging - -Check logcat for ISO Droid logs: - -```bash -adb logcat | grep -i "isodroid\|isodrive" -``` - -### Common Issues - -**"Device not supported"** -- Check for USB gadget support: `ls /config/usb_gadget/` or `ls /sys/class/android_usb/` -- Verify kernel has USB gadget drivers - -**"Root access required"** -- Ensure root manager (Magisk/KernelSU) is installed -- Grant root access when prompted -- Check `RootManager.hasRoot()` returns true - -**Mount fails** -- Verify file exists and is readable -- Check file isn't corrupted -- Ensure no other USB modes are active -- Try rebooting device - -### isodrive Binary Version - -Check the bundled binary version: - -```bash -adb shell -su -/data/data/sh.sar.isodroid/files/isodrive --version -``` - ## Contributing -### Code Style +### Adding OS Icons + +OS icons are displayed in the file browser when ISO/IMG filenames match the icon name. + +**Steps:** + +1. Add your SVG file to `app/src/main/assets/osicons/` + - Filename should be lowercase (e.g., `ubuntu.svg`, `archlinux.svg`) + - SVG should be simple and recognizable + - Recommended: Get icons from [Simple Icons](https://simpleicons.org/) + +2. The app automatically detects and matches icons: + - Filename `ubuntu-22.04-desktop-amd64.iso` → matches `ubuntu.svg` + - Filename `archlinux-2024.12.01-x86_64.iso` → matches `archlinux.svg` + - Matching is case-insensitive and searches for icon name within filename + +3. **Symlinks for aliases:** + + Some distributions have multiple names. You can create symlinks: + ```bash + cd app/src/main/assets/osicons/ + + # Example: Manjaro uses Arch Linux icon + ln -s archlinux.svg manjaro.svg + + # Example: Kubuntu uses Ubuntu icon + ln -s ubuntu.svg kubuntu.svg + ``` + +4. Submit a pull request with your new icon(s) + +### Adding OS Download Links + +The Downloads screen shows curated links to operating system ISOs. + +**Steps:** + +1. Edit `app/src/main/assets/os.json` + +2. Add a new entry with all required fields: + +```json +{ + "name": "Ubuntu Desktop", + "category": "Linux", + "description": "Popular Linux distribution with GNOME desktop", + "icon": "ubuntu.svg", + "url": "https://ubuntu.com/download/desktop" +} +``` + +**Field descriptions:** + +- `name` (required): Display name for the OS +- `category` (required): One of: `Linux`, `BSD`, `Windows`, or `Recovery` +- `description` (required): Brief description (one sentence) +- `icon` (required): Filename of SVG in `osicons/` directory, or `null` if no icon +- `url` (required): Direct link to download page or ISO file + +**Example with no icon:** +```json +{ + "name": "Custom Linux", + "category": "Linux", + "description": "A custom Linux distribution", + "icon": null, + "url": "https://example.com/download" +} +``` + +3. Test your changes: + - Build the app + - Navigate to Downloads screen + - Verify your entry appears in the correct category + - Verify the icon displays (if provided) + - Verify the link opens correctly + +4. Submit a pull request with: + - Updated `os.json` + - New SVG icon in `osicons/` (if applicable) + - Brief description of what you added + +### OS Icon Symlinks + +Some distributions share the same logo. Use symlinks instead of duplicating files: + +**Common symlinks:** + +```bash +cd app/src/main/assets/osicons/ + +# Arch-based distributions +ln -s archlinux.svg manjaro.svg +ln -s archlinux.svg endeavouros.svg + +# Ubuntu derivatives +ln -s ubuntu.svg kubuntu.svg +ln -s ubuntu.svg xubuntu.svg +ln -s ubuntu.svg lubuntu.svg + +# Debian-based +ln -s debian.svg kali.svg +ln -s debian.svg raspbian.svg +``` + +**Why symlinks:** +- Reduces APK size +- Ensures consistency when upstream icon changes +- Makes maintenance easier + +**Note:** Git tracks symlinks, so they work across all platforms when cloned. + +## Project Structure + +``` +ISODroid/ +├── app/src/main/ +│ ├── assets/ +│ │ ├── bin/ +│ │ │ └── isodrive # Required binary +│ │ ├── osicons/ # OS logo SVGs +│ │ │ ├── ubuntu.svg +│ │ │ ├── archlinux.svg +│ │ │ └── ... +│ │ └── os.json # Download links +│ ├── java/sh/sar/isodroid/ # Kotlin source code +│ └── res/ # Android resources +├── docs/ +│ ├── BUILDING.md # This file +│ └── screenshots/ # App screenshots +└── README.md # Main documentation +``` + +## Code Style - Follow Kotlin coding conventions - Use meaningful variable names -- Comment complex logic - Keep functions focused and small +- Add comments for complex logic -### Pull Requests +## Testing -1. Fork the repository -2. Create a feature branch -3. Make your changes -4. Test thoroughly on a real device -5. Submit a pull request with description +Before submitting a PR, test on a real rooted Android device: + +- [ ] App builds successfully +- [ ] New OS icon displays correctly +- [ ] New download link opens properly +- [ ] No crashes or errors in logcat + +## Questions? + +Open an issue on the repository if you need help or have questions about contributing. ## License