update docs
This commit is contained in:
465
docs/BUILDING.md
465
docs/BUILDING.md
@@ -1,16 +1,33 @@
|
|||||||
# Building ISO Droid
|
# 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
|
## Building from Source
|
||||||
|
|
||||||
### Prerequisites
|
### 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)
|
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.
|
||||||
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)
|
- **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
|
### Build Steps
|
||||||
|
|
||||||
@@ -22,311 +39,171 @@ cd ISODroid
|
|||||||
# Ensure isodrive binary is present
|
# Ensure isodrive binary is present
|
||||||
ls -la app/src/main/assets/bin/isodrive
|
ls -la app/src/main/assets/bin/isodrive
|
||||||
|
|
||||||
# Build the debug APK
|
# Build debug APK
|
||||||
./gradlew assembleDebug
|
./gradlew assembleDebug
|
||||||
|
|
||||||
# Or build the release APK (requires signing configuration)
|
# Or build release APK (requires signing configuration)
|
||||||
./gradlew assembleRelease
|
./gradlew assembleRelease
|
||||||
```
|
```
|
||||||
|
|
||||||
The compiled APK will be located at:
|
The compiled APK will be in:
|
||||||
- Debug: `app/build/outputs/apk/debug/app-debug.apk`
|
- Debug: `app/build/outputs/apk/debug/app-debug.apk`
|
||||||
- Release: `app/build/outputs/apk/release/app-release.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<IsoFile> = 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<MountEvent>()
|
|
||||||
val events: SharedFlow<MountEvent> = _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
|
## 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
|
- Follow Kotlin coding conventions
|
||||||
- Use meaningful variable names
|
- Use meaningful variable names
|
||||||
- Comment complex logic
|
|
||||||
- Keep functions focused and small
|
- Keep functions focused and small
|
||||||
|
- Add comments for complex logic
|
||||||
|
|
||||||
### Pull Requests
|
## Testing
|
||||||
|
|
||||||
1. Fork the repository
|
Before submitting a PR, test on a real rooted Android device:
|
||||||
2. Create a feature branch
|
|
||||||
3. Make your changes
|
- [ ] App builds successfully
|
||||||
4. Test thoroughly on a real device
|
- [ ] New OS icon displays correctly
|
||||||
5. Submit a pull request with description
|
- [ ] 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
|
## License
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user