A-Team-Android_ROM_Builder/README-TECHNICAL.md
2026-08-14 21:48:48 -05:00

1434 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# A-Team Android ROM Builder — Technical Guide
## 1. Architecture at a Glance
A-Team Android ROM Builder is a Python/GTK application wrapped around a script-driven Android ROM workflow.
The central design is:
```text
GTK interface
|
v
Project state
|
+--> device configuration
|
+--> ROM configuration
|
+--> host configuration
|
+--> profile configuration
|
v
Environment generation
|
v
Bash scripts
|
+--> sync
+--> device setup
+--> GApps
+--> build
+--> clean
+--> updater
```
The GUI should be treated as the control plane. The scripts remain the execution plane.
That distinction is important when extending the application: a new ROM-specific operation normally belongs in the script/configuration layer rather than becoming a large block of shell logic inside a GTK callback.
---
## 2. Source Tree
The important top-level areas are:
```text
builder/
Python backend and application helpers
configs/
Device, ROM, host, setup, build-command, and upload configuration
profiles/
Saved project profiles
scripts/
Build and synchronization operations
gui.py
GTK application and tab construction
```
The project also contains application assets and supporting files used by the GUI.
---
## 3. `gui.py`
`gui.py` is the main GTK application.
It is responsible for:
- Creating the main window
- Creating the application tabs
- Creating controls
- Reading user selections
- Building the current project state
- Starting backend actions
- Starting scripts
- Displaying terminal output
- Displaying updater state
- Handling application-side UI tools
The application uses GTK 3 and VTE for the embedded terminal.
### UI constants
UI dimensions are intentionally centralized.
Current spacing controls include:
```text
BUILD_COMMANDS_TOP_BOTTOM_SPACING
BUILD_SETUP_TOP_SPACING
PROJECT_PROFILES_TOP_SPACING
SYNC_SETUP_TOP_SPACING
SPLASH_TOP_BOTTOM_SPACING
```
Current button-width controls include:
```text
SYNC_SETUP_BUTTON_WIDTH
SYNC_GAPPS_BUTTON_WIDTH
BUILD_ROM_BUTTON_WIDTH
LAUNCHER_BUTTON_WIDTH
CLEAN_BUTTON_WIDTH
```
Keep these constants centralized when modifying layout. Do not scatter repeated pixel values through widget construction unless there is a specific reason.
---
## 4. Configuration Parsing
The configuration system uses simple key/value files.
Example:
```text
DEVICE_CODENAME="milanf"
DEVICE_SOC="sm6375"
DEVICE_MANUFACTURER="Motorola"
```
Conceptually this becomes:
```python
{
"DEVICE_CODENAME": "milanf",
"DEVICE_SOC": "sm6375",
"DEVICE_MANUFACTURER": "Motorola"
}
```
Configuration parsing supports the projects simple `KEY=VALUE` format and ignores comments and blank lines.
This intentionally avoids making device and ROM configuration dependent on Python code.
---
## 5. Device Discovery
Device discovery is configuration-driven.
The builder searches:
```text
configs/devices/
```
for device configuration files.
A new device therefore normally does not require a Python edit.
### Minimum device integration
Create:
```text
configs/devices/example.conf
```
Then provide the values required by the device scripts.
For example:
```text
DEVICE_CODENAME="example"
DEVICE_DISPLAY_CODENAME="Example"
DEVICE_DISPLAY_NAME="Example Android Device"
DEVICE_MANUFACTURER="Motorola"
DEVICE_MODEL_NUMBER="XT0000"
DEVICE_SYNC_SCRIPT="example-sync.sh"
```
The GUI can then discover the device from the configuration directory.
---
## 6. Device Sync Scripts
Device-specific scripts live under:
```text
scripts/devices_sync/
```
A device configuration points to its script:
```text
DEVICE_SYNC_SCRIPT="example-sync.sh"
```
The common synchronization workflow can then load the selected device configuration and execute the selected device-specific script.
### Recommended device addition procedure
1. Create the device `.conf`.
2. Add the device identity variables.
3. Add only device-specific variables that scripts actually require.
4. Create the device sync script.
5. Set `DEVICE_SYNC_SCRIPT`.
6. Test the script independently.
7. Start the GUI and confirm the device appears.
8. Run Sync & Setup Device Source.
Testing the shell script independently is useful because it separates Android source/setup failures from GTK failures.
---
## 7. ROM Configuration
ROM configuration can come from either:
```text
configs/rom.conf
```
or:
```text
<ROM_ROOT>/rom.conf
```
The ROM-local configuration is the preferred location when a ROM needs its own settings.
### Why two locations exist
The builder-wide file provides defaults.
The ROM-local file allows a ROM source tree to carry its own configuration.
For example:
```text
configs/rom.conf
```
could provide generic defaults while:
```text
/home/pizzag/Android/Roms/Lineage/23.2/rom.conf
```
contains values specific to that ROM tree.
### Case sensitivity
On Linux:
```text
rom.conf
Rom.conf
ROM.conf
```
are three different names.
The loader's expected filename is:
```text
rom.conf
```
---
## 8. ROM Configuration Variables
ROM configuration can contain build metadata and script variables.
Examples:
```text
ROM_BUILD_NAME="lineage"
ROM_TARGET_RELEASE="bp4a"
DEFAULT_ROM_BUILD_COMMAND="brunch $DEVICE_CODENAME"
ROM_DISPLAY_NAME="LineageOS"
ROM_VENDOR_NAME="lineage"
ROM_MANIFEST="https://github.com/LineageOS/android.git"
ROM_BRANCH_PREFIX="lineage-"
ROM_MAJOR_VERSION="23"
ROM_MINOR_VERSION="2"
```
The important principle is that the ROM configuration should contain values that describe the ROM rather than values that uniquely identify a single physical device.
Device-specific values belong in the device configuration.
---
## 9. Project State
The project state is the bridge between GUI selections and scripts.
Typical values include:
```text
DEVICE_NAME
ROM_NAME
ROM_BRANCH
ROM_PATH
ANDROID_VERSION
BUILD_VARIANT
BUILD_COMMAND
GAPPS_VARIANT
CLEAN_VARIANT
INSTALLER_VARIANT
BUILD_JOBS
USE_CCACHE
APN_VARIANT
```
Additional variables are merged from configuration sources.
The result is converted into an environment that can be consumed by Bash.
---
## 10. Environment Construction
The project environment combines GUI selections with configuration values.
A simplified model is:
```text
GUI/project values
|
v
device variables
|
v
ROM variables
|
v
A-Team setup variables
|
v
upload variables
|
v
variable expansion
```
This is what allows a configuration value such as:
```text
DEFAULT_ROM_BUILD_COMMAND="brunch $DEVICE_CODENAME"
```
to use the currently selected device without duplicating the device name in the ROM configuration.
When adding a new variable, decide whether it belongs to:
- project state
- device configuration
- ROM configuration
- A-Team setup
- upload configuration
before adding Python-specific handling.
---
## 11. ROM Path Interpretation
The selected ROM directory is used to derive ROM identity.
For example:
```text
/home/pizzag/Android/Roms/Lineage/23.2
```
can represent:
```text
ROM_NAME = Lineage
ROM_BRANCH = 23.2
ROM_PATH = /home/pizzag/Android/Roms/Lineage/23.2
```
The project then exports these values to the scripts.
This is why the expected ROM directory structure matters to the GUI.
---
## 12. Build Command System
The Build tab reads:
```text
configs/rom_build_commands.conf
```
Example:
```text
Default --> rom.conf
Lineage
Derpfest
```
Normal entries become selectable build commands.
The command implementation is deliberately separate from the GUI:
```text
scripts/build_options/rom_build_commands.sh
```
This allows the command selector to remain simple while the actual command-specific environment is handled in Bash.
---
## 13. `rom_build_commands()`
The build-command implementation is a Bash function:
```bash
rom_build_commands() {
...
}
```
It currently handles three paths.
### Lineage
```bash
if [[ $BUILD_COMMAND == "lineage" ]]; then
LUNCH_COMMAND="${ROM_BUILD_NAME}_${DEVICE_NAME}-${ROM_TARGET_RELEASE}-${BUILD_VARIANT}"
ROM_BUILD_COMMAND="brunch $DEVICE_CODENAME"
```
### Derpfest
```bash
elif [[ $BUILD_COMMAND == "derpfest" ]]; then
LUNCH_COMMAND="${ROM_BUILD_NAME}_${DEVICE_NAME}-${ROM_TARGET_RELEASE}-${BUILD_VARIANT}"
ROM_BUILD_COMMAND="m derp"
```
### Default
```bash
else
LUNCH_COMMAND="${ROM_BUILD_NAME}_${DEVICE_NAME}-${ROM_TARGET_RELEASE}-${BUILD_VARIANT}"
ROM_BUILD_COMMAND="$DEFAULT_ROM_BUILD_COMMAND"
```
Each branch exports:
```text
LUNCH_COMMAND
ROM_BUILD_COMMAND
```
### Why the function is sourced
`build.sh` uses:
```bash
source "$BUILD_OPTIONS_DIR/rom_build_commands.sh"
rom_build_commands
```
It is important that the file is sourced rather than executed with a separate `bash` process.
If the function ran in a child shell, exported variables would not remain available to the parent build script.
---
## 14. Build Execution
The build entry point is:
```text
scripts/build.sh
```
The script receives the project environment and performs the build preparation.
The command-selection flow is:
```text
GUI selection
|
v
BUILD_COMMAND
|
v
rom_build_commands()
|
+--> LUNCH_COMMAND
|
+--> ROM_BUILD_COMMAND
|
v
build execution
```
The current implementation uses the resulting command strings for the ROM build.
When a command is stored as a string containing shell syntax or multiple arguments, the build script must execute it in a way consistent with how the command is defined.
---
## 15. Build Options
The GUI exposes project-level build options.
### Android version
The selected Android version is exported as:
```text
ANDROID_VERSION
```
### Build variant
The project supports the Android build variants exposed by the current GUI.
The selected value becomes:
```text
BUILD_VARIANT
```
### GApps
The selected GApps mode becomes:
```text
GAPPS_VARIANT
```
### Clean
The clean selection becomes:
```text
CLEAN_VARIANT
```
### Installer
The installer selection becomes:
```text
INSTALLER_VARIANT
```
### Build jobs
The selected job count becomes:
```text
BUILD_JOBS
```
### Ccache
The checkbox controls:
```text
USE_CCACHE
```
### Custom APN
The Custom APN option controls the APN-related project value consumed by the build scripts.
---
## 16. Sync Workflow
The common synchronization entry point is:
```text
scripts/sync.sh
```
Its role is to coordinate common setup and then dispatch to the selected device workflow.
The architecture is:
```text
sync.sh
|
+--> load configuration
|
+--> establish A-Team setup
|
+--> select device script
|
+--> execute device sync
```
Device-specific behavior remains in:
```text
scripts/devices_sync/
```
This prevents the common sync script from becoming a large device-specific conditional tree.
---
## 17. A-Team Setup Marker
The project uses a setup marker under the ROM tree to identify whether the A-Team setup process has already been performed.
The marker is:
```text
device/A-Team/A-Team-Setup.check
```
The purpose is to prevent the common setup work from being repeated unnecessarily.
If the setup requirements change, the marker/versioning logic should be reviewed so existing ROM trees can be migrated safely.
---
## 18. MindTheGapps Synchronization
GApps synchronization is handled by:
```text
scripts/gapps_sync.sh
```
The script uses the Android version to determine the appropriate MindTheGapps source.
The source is synchronized into the ROM tree at the location expected by the current build system.
This operation is separate from the core ROM build so it can be repeated without rebuilding the entire ROM.
---
## 19. Project Profiles
Profiles are stored under:
```text
profiles/
```
A profile represents a reusable set of project selections.
Examples of profile-level information include:
```text
device
ROM path
Android version
build variant
build command
GApps variant
clean variant
installer variant
build jobs
ccache
APN selection
host
```
Profiles should not be used as a replacement for device or ROM configuration files.
A profile says:
> "Build this project this way."
A device configuration says:
> "This is how this device is defined."
A ROM configuration says:
> "This is how this ROM is defined."
Keeping those responsibilities separate makes the project easier to maintain.
---
## 20. Build Hosts
Host configuration is stored in:
```text
configs/hosts.conf
```
The builder supports local and SSH-based hosts.
A remote host needs:
- SSH access
- Android build dependencies
- ROM source
- required device/vendor/kernel source
- Git and other source-management tools
- any ROM-specific build dependencies
The host configuration tells the application how to reach the machine; it does not replace the machine's Android build environment.
---
## 21. Embedded Terminal
The terminal uses VTE and provides a real interactive shell inside the application.
The terminal is intentionally not treated as a static output window.
It supports shell input and now provides desktop clipboard integration for terminal text.
### Copy
Selected terminal text can be copied to the system clipboard.
The terminal copy action should not replace normal:
```text
Ctrl+C
```
terminal behavior, because Ctrl+C is commonly used to interrupt a running process.
### Paste
Clipboard contents can be inserted into the terminal.
### Design consideration
Terminal keyboard shortcuts must be implemented carefully because shortcuts such as Ctrl+C have established Unix terminal semantics.
---
## 22. Resource Monitor
The Resource Monitor provides live system information through:
```text
btop
```
with:
```text
bpytop
```
as a fallback where supported by the current implementation.
It is particularly useful during Android builds because compilation can consume large amounts of:
- CPU
- RAM
- storage I/O
- swap
- filesystem capacity
---
## 23. Tools
The Tools area contains application-side utilities.
### Splash selection
The splash manager handles selection of available splash assets.
### Launcher icons
The icon manager handles launcher icon selection.
### Desktop launcher
The launcher utility creates a desktop entry for the builder.
### Clean ROM
The clean operation invokes the appropriate backend/script workflow rather than embedding a large cleanup implementation in the GUI.
---
## 24. Updater Architecture
The updater has three distinct responsibilities:
```text
Python updater logic
|
+--> update discovery
+--> download/extraction
|
GTK updater UI
|
+--> progress bar
+--> status text
+--> update dialog
|
scripts/updater.sh
|
+--> actual staged update operations
```
This separation matters because the shell script reports what is happening, while the GUI decides how those reports are presented.
---
## 25. Updater Progress Protocol
The shell updater communicates progress using:
```text
::PROGRESS::<current>::<total>
```
For example:
```text
::PROGRESS::3::5
```
represents:
```text
3 / 5
```
or:
```text
60%
```
Status messages use:
```text
::STATUS::<message>
```
Example:
```text
::STATUS::Backing Up Current Installation ...
```
The GUI listens for these markers and updates the updater interface.
### Adding an updater stage
If another stage is required:
1. Increase `TOTAL_STEPS`.
2. Add a `::PROGRESS::N::TOTAL` message.
3. Add the corresponding `::STATUS::...` message.
4. Keep the numbering sequential.
5. Test both the script and GUI interpretation.
Do not change the marker syntax unless the Python parser is changed at the same time.
---
## 26. Updater Status Appearance
Updater status messages are intentionally displayed in:
```text
cyan
bold
```
The status text is separate from the progress calculation.
Therefore:
```text
status appearance
```
can be changed without changing:
```text
progress percentage
```
and vice versa.
The progress calculation is based on:
```text
current / total
```
while the status label is simply the human-readable description associated with that stage.
---
## 27. Update JSON and Changelog
The update JSON is loaded as a complete object.
The update popup uses the available version information and the optional:
```json
"changelog": "..."
```
field.
For example:
```json
{
"version": 102,
"display": "1.02",
"file": "A-Team-Android_ROM_Builder-v1.02.7z",
"changelog": "Improved terminal clipboard support."
}
```
The popup can present:
```text
Installed Version : 1.01
Available Version : 1.02
Changelog:
Improved terminal clipboard support.
```
If the field is absent, the application uses its fallback text rather than failing the update dialog.
---
## 28. Adding a Device — Complete Example
Suppose a new device is called:
```text
example
```
### Device configuration
Create:
```text
configs/devices/example.conf
```
Example:
```text
DEVICE_CODENAME="example"
DEVICE_DISPLAY_CODENAME="Example"
DEVICE_DISPLAY_NAME="Example Phone"
DEVICE_MANUFACTURER="Motorola"
DEVICE_MODEL_NUMBER="XT0000"
DEVICE_SYNC_SCRIPT="example-sync.sh"
```
### Device sync script
Create:
```text
scripts/devices_sync/example-sync.sh
```
Make it executable:
```bash
chmod +x scripts/devices_sync/example-sync.sh
```
### Test it
Run it manually with the required environment before involving the GUI.
### Test discovery
Start the GUI and verify that:
```text
Example Phone
```
appears in the device selector.
### Test sync
Select the device and run:
```text
Sync & Setup Device Source
```
This isolates the device integration into configuration plus one device-specific script.
---
## 29. Adding a ROM
A new ROM normally needs:
1. A valid ROM source tree.
2. A recognizable ROM path.
3. A ROM configuration.
4. A compatible build command.
5. Any required synchronization logic.
If the ROM has unique settings, put them in:
```text
<ROM_ROOT>/rom.conf
```
rather than modifying the global:
```text
configs/rom.conf
```
If it needs a unique build command, add the command to:
```text
configs/rom_build_commands.conf
```
and implement the command behavior in:
```text
scripts/build_options/rom_build_commands.sh
```
---
## 30. Adding a Build Command
There are two parts.
### Part 1 — GUI selection
Add the command name to:
```text
configs/rom_build_commands.conf
```
For example:
```text
Aosp
```
### Part 2 — command behavior
Add a branch to:
```text
rom_build_commands()
```
For example:
```bash
elif [[ $BUILD_COMMAND == "aosp" ]]; then
LUNCH_COMMAND="${ROM_BUILD_NAME}_${DEVICE_NAME}-${ROM_TARGET_RELEASE}-${BUILD_VARIANT}"
ROM_BUILD_COMMAND="m"
export LUNCH_COMMAND
export ROM_BUILD_COMMAND
```
Then run:
```bash
bash -n scripts/build_options/rom_build_commands.sh
```
before testing the GUI.
---
## 31. Adding a Configuration Variable
Before adding a new variable, identify its scope.
### Device scope
```text
configs/devices/<device>.conf
```
Use for:
```text
SOC
codename
model
device-specific paths
device-specific flags
```
### ROM scope
```text
rom.conf
```
Use for:
```text
ROM name
ROM build metadata
ROM default command
ROM manifest
ROM release metadata
```
### Application-wide setup
```text
configs/a_team_setup.conf
```
Use for values shared across projects.
### Upload services
```text
configs/upload_services.conf
```
Use for upload-service configuration.
Keeping variable scope correct prevents device-specific details from leaking into ROM-wide configuration.
---
## 32. Debugging Strategy
When something fails, isolate the layer.
### GUI problem
Check:
```text
gui.py
builder/*.py
```
### Configuration problem
Check:
```text
configs/
profiles/
```
### Sync problem
Run:
```text
scripts/sync.sh
```
directly.
### Device problem
Run the device-specific script directly.
### Build problem
Run:
```text
scripts/build.sh
```
directly with the required environment.
### Updater problem
Run:
```text
scripts/updater.sh
```
directly and inspect:
```text
::PROGRESS::
::STATUS::
```
output.
This approach avoids changing GUI code to solve a shell or Android-source problem.
---
## 33. Bash Validation
Before committing a shell change:
```bash
bash -n scripts/build.sh
bash -n scripts/sync.sh
bash -n scripts/gapps_sync.sh
bash -n scripts/updater.sh
```
For the command-selection function:
```bash
bash -n scripts/build_options/rom_build_commands.sh
```
Syntax validation does not prove that an Android build will succeed, but it catches malformed shell syntax before a full build.
---
## 34. Python Validation
For Python changes:
```bash
python3 -m py_compile gui.py
```
and for backend modules:
```bash
python3 -m py_compile builder/*.py
```
For GTK changes, syntax validation is not enough.
The affected UI path should also be exercised in an environment containing:
```text
gi
Gtk 3
VTE
```
because GTK errors commonly occur during widget creation or signal execution rather than Python parsing.
---
## 35. Preserving Executable Permissions
The application contains executable shell scripts.
Important files include:
```text
scripts/*.sh
scripts/build_options/*.sh
scripts/devices_sync/*.sh
```
The updater is one example where executable permissions matter because the Python updater launches:
```text
scripts/updater.sh
```
directly.
When packaging a release, preserve executable mode, normally:
```text
0755
```
for shell scripts and the executable application entry point where applicable.
A ZIP process that strips Unix permissions can cause:
```text
PermissionError: [Errno 13] Permission denied
```
even when the script contents themselves are correct.
---
## 36. UI Extension Pattern
For a new button:
1. Add a width constant if its width should be configurable.
2. Create the GTK button.
3. Apply the shared sizing/alignment helper.
4. Connect its callback.
5. Put the actual operation in an appropriate backend or script.
For example:
```python
MY_BUTTON_WIDTH = 140
```
then:
```python
set_button_width(
my_button,
MY_BUTTON_WIDTH
)
```
This keeps layout changes localized.
---
## 37. UI Layout Maintenance
When adjusting spacing:
- Change the corresponding named constant.
- Avoid replacing unrelated margins.
- Keep the existing alignment model.
- Do not duplicate spacing constants for the same visual relationship.
- Verify the neighboring controls after a change.
The current UI intentionally exposes independent spacing values for sections that need independent tuning.
---
## 38. Recommended Development Workflow
For a new feature:
### Step 1 — Identify the layer
Decide whether the feature belongs in:
```text
GUI
backend
config
script
```
### Step 2 — Find the existing path
Reuse the existing action/config/script architecture where possible.
### Step 3 — Make the smallest change
Avoid changing unrelated layout or configuration code.
### Step 4 — Validate syntax
Run Python or Bash syntax checks.
### Step 5 — Exercise the affected operation
Do not stop at syntax validation.
### Step 6 — Verify packaging
Ensure scripts retain executable permissions.
### Step 7 — Update documentation
Update `README.md` for user-visible functionality and `README-TECHNICAL.md` for implementation details.
---
## 39. Documentation Boundary
`README.md` should answer:
> What does the application do, how do I run it, and how do I configure it?
`README-TECHNICAL.md` should answer:
> How does it work, where is the code, how do the components communicate, and how do I extend or debug it?
Avoid duplicating every implementation detail in the normal README.
The technical document should be detailed where implementation knowledge matters, but should remain organized around the application's actual architecture and workflows.
---
## 40. Current Extension Points
The cleanest existing extension points are:
```text
configs/devices/
Add devices
configs/rom.conf
Add ROM defaults
<ROM_ROOT>/rom.conf
Add ROM-local configuration
configs/rom_build_commands.conf
Add build command choices
scripts/devices_sync/
Add device-specific sync logic
scripts/build_options/
Add build-option behavior
scripts/
Add reusable workflow operations
builder/
Add reusable Python-side functionality
gui.py
Add/modify user interface
```
When possible, use these extension points instead of introducing special-case logic into unrelated components.