Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev: flash additional partitions #246

Merged
merged 31 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
0604ff1
Add dtbo, vbmeta, super_empty flashing
anon1892 Aug 1, 2023
62be5c3
Added device specific notes
anon1892 Aug 1, 2023
361f0a4
Added Mi439 (Redmi 7A & co.)
anon1892 Aug 1, 2023
812bb51
Update `notes`, add `brand` and `untested` metadata.
anon1892 Aug 2, 2023
48be05d
Add `brand` metadata & update of `notes`
anon1892 Aug 2, 2023
616c7e6
Fix
anon1892 Aug 2, 2023
f464396
Add function to know image sdk (mainly Android version+20)
anon1892 Aug 4, 2023
5d34157
Set branch to anon1892:dtbo
tsterbak Aug 8, 2023
661f9b4
Update the code for flashing additional partitions and improve the la…
tsterbak Aug 8, 2023
357002c
Add fastboot_flash_recovery and fastboot_reboot_recovery from anon1892
tsterbak Aug 16, 2023
757a85c
Merge support for device specific notes
tsterbak Aug 16, 2023
6b28b52
Merge branch 'anon1892-notes' into dev-flash-additional
tsterbak Aug 16, 2023
9ba8e21
Fix merge issue
tsterbak Aug 16, 2023
cceae91
[SPLIT] Add support for Mi439 (Redmi 7A & co.) (#226)
tsterbak Aug 16, 2023
554b75b
Remove supported recoveries from Mi439 config for now
tsterbak Aug 16, 2023
0bd2ccc
Fix config validation for notes field
tsterbak Aug 16, 2023
13c85be
Improve the code of the notes generation a bit
tsterbak Aug 16, 2023
b90a5e4
Change the location the skip-buttons to the bottom of the start view.
tsterbak Aug 16, 2023
fd29a48
Improve typing a bit
tsterbak Aug 16, 2023
08fa43f
Add an info box with explainations for additional images; show the sc…
tsterbak Aug 16, 2023
3789f82
Fix vbmeta selection bug and update recovery checks on device codes
tsterbak Aug 22, 2023
b0e2a0b
Fix bugs on vbmeta flashing and checking recovery image
tsterbak Aug 22, 2023
8c5d438
Merge remote-tracking branch 'origin/dev' into dev-flash-additional
tsterbak Aug 29, 2023
ff5c2a1
Update tests
tsterbak Aug 29, 2023
0b53acc
ADd workflows to not flash the recovery and still work
tsterbak Aug 29, 2023
7092597
Minor fix
tsterbak Aug 29, 2023
6c09fbf
Fix some bugs in the behaviour of the select view with additional ima…
tsterbak Sep 4, 2023
83dbd7a
Update the message to acompany the install progress bar
tsterbak Sep 4, 2023
1cfc293
Fix bug where the validation still required some additional images ev…
tsterbak Sep 5, 2023
ed77d85
Improve behaviour of the continue buttons and validation
tsterbak Sep 5, 2023
aab4785
Merge branch 'dev' into dev-flash-additional
tsterbak Sep 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ OnePlus | Nord N200 | [dre](https://wiki.lineageos.org/devices/dre) | | tested
OnePlus | 9 | lemonade | | under development
</details>

<details><summary><b>Xiaomi</b></summary>

Vendor | Device Name | CodeName | Models | Status
---|---|---|---|---
Xiaomi | Redmi 7A / 8 / 8A / 8A Dual | [Mi439](https://wiki.lineageos.org/devices/Mi439) : pine / olive / olivelite / olivewood | | tested
</details>

And more to come!


Expand All @@ -196,7 +203,6 @@ Please have a look before opening an issue or starting to contribute.
A detailed list can be found [here](https://openandroidinstaller.org/#contribute).



## Tools

- The [Android SDK Platform Tools](https://developer.android.com/studio/releases/platform-tools) (such as adb and fastboot) are [Apache](https://android.googlesource.com/platform/system/adb/+/refs/heads/master/NOTICE)-licensed universal Android utilities
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ A config file consists of two parts. The first part are some metadata about the
Every config file should have `metadata` with the following fields:
- `maintainer`: str; Maintainer and author of the config file.
- `device_name`: str; Name of the device.
- `brand`: [OPTIONAL] str; Name of the brand. Can be used to make brand specific actions.
- `is_ab_device`: bool; A boolean to determine if the device is a/b-partitioned or not.
- `device_code`: str; The official device code.
- `supported_device_codes`: List[str]; A list of supported device codes for the config. The config will be loaded based on this field.
- `twrp-link`: [OPTIONAL] str; name of the corresponding twrp page.
- `additional_steps` : [OPTIONAL] List[str]; A list of additional steps. Can be `dtbo`, `vbmeta`, `vendor_boot` or `super_empty`.
- `notes`: [OPTIONAL] List[str]; specific phone information, showed before choosing ROM / recovery
- `untested`: [OPTIONAL] bool; If `true`, a warning message is showed during installation process.

In addition to these metadata, every config can have optional `requirements`. If these are set, the user is asked to check if they are meet.
- `android`: [OPTIONAL] int|str; Android version to install prior to installing a custom ROM.
Expand All @@ -32,7 +36,7 @@ Every step in the config file corresponds to one view in the application. These
- `img`: [OPTIONAL] Display an image on the left pane of the step view. Images are loaded from `openandroidinstaller/assets/imgs/`.
- `content`: str; The content text displayed alongside the action of the step. Used to inform the user about what's going on. For consistency and better readability the text should be moved into the next line using `>`.
- `link`: [OPTIONAL] Link to use for the link button if type is `link_button_with_confirm`.
- `command`: [ONLY for call_button* steps] str; The command to run. One of `adb_reboot`, `adb_reboot_bootloader`, `adb_reboot_download`, `adb_sideload`, `adb_twrp_wipe_and_install`, `adb_twrp_copy_partitions`, `fastboot_boot_recovery`, `fastboot_unlock_with_code`, `fastboot_unlock`, `fastboot_oem_unlock`, `fastboot_get_unlock_data`, `fastboot_reboot`, `heimdall_flash_recovery`.
- `command`: [ONLY for call_button* steps] str; The command to run. One of `adb_reboot`, `adb_reboot_bootloader`, `adb_reboot_download`, `adb_sideload`, `adb_twrp_wipe_and_install`, `adb_twrp_copy_partitions`, `fastboot_boot_recovery`, `fastboot_flash_recovery`, `fastboot_reboot_recovery`, `fastboot_flash_additional_partitions`, `fastboot_unlock_with_code`, `fastboot_unlock`, `fastboot_unlock_critical`, `fastboot_oem_unlock`, `fastboot_get_unlock_data`, `fastboot_reboot`, `heimdall_flash_recovery`.
- `allow_skip`: [OPTIONAL] boolean; If a skip button should be displayed to allow skipping this step. Can be useful when the bootloader is already unlocked.

**Please try to retain this order of these fields in your config to ensure consistency.**
Expand Down
55 changes: 54 additions & 1 deletion openandroidinstaller/app_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
import copy
from pathlib import Path
from typing import List, Optional
from loguru import logger

from installer_config import _load_config
from installer_config import _load_config, Step


class AppState:
Expand All @@ -37,13 +38,20 @@ def __init__(
self.test = test
self.test_config = test_config

# store state
self.unlock_bootloader = True
self.flash_recovery = True

# placeholders
self.advanced = False
self.install_addons = False
self.addon_paths = []
self.config = None
self.image_path = None
self.recovery_path = None
self.dtbo_path = None
self.vbmeta_path = None
self.super_empty_path = None

# store views
self.default_views: List = []
Expand All @@ -69,3 +77,48 @@ def load_config(self, device_code: str):
self.steps = copy.deepcopy(self.config.unlock_bootloader) + copy.deepcopy(
self.config.boot_recovery
)

def toggle_flash_unlock_bootloader(self):
"""Toggle flashing of unlock bootloader."""
self.unlock_bootloader = not self.unlock_bootloader
if self.unlock_bootloader:
logger.info("Enabled unlocking the bootloader again.")
self.steps = copy.deepcopy(self.config.unlock_bootloader)
else:
logger.info("Skipping bootloader unlocking.")
self.steps = []
# if the recovery is already flashed, skip flashing it again
if self.flash_recovery:
self.steps += copy.deepcopy(self.config.boot_recovery)
else:
self.steps = [
Step(
title="Boot custom recovery",
type="confirm_button",
content="If you already flashed TWRP, boot into it by pressing 'Confirm and run'. Otherwise restart the process. Once your phone screen looks like the picture on the left, continue.",
command="adb_reboot_recovery",
img="twrp-start.jpeg",
)
]

def toggle_flash_recovery(self):
"""Toggle flashing of recovery."""
self.flash_recovery = not self.flash_recovery
if self.unlock_bootloader:
self.steps = copy.deepcopy(self.config.unlock_bootloader)
else:
self.steps = []
if self.flash_recovery:
logger.info("Enabled flashing recovery again.")
self.steps += copy.deepcopy(self.config.boot_recovery)
else:
logger.info("Skipping flashing recovery.")
self.steps = [
Step(
title="Boot custom recovery",
type="confirm_button",
content="If you already flashed TWRP, boot into it by pressing 'Confirm and run'. Otherwise restart the process. Once your phone screen looks like the picture on the left, continue.",
command="adb_reboot_recovery",
img="twrp-start.jpeg",
)
]
68 changes: 68 additions & 0 deletions openandroidinstaller/assets/configs/Mi439.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
metadata:
maintainer: A non (anon)
brand: xiaomi
device_name: Xiaomi Redmi 7A / 8 / 8A / 8A Dual
is_ab_device: false
device_code: Mi439
additional_steps:
- dtbo
- vbmeta
- super_empty
supported_device_codes:
- Mi439
- mi439
- pine
- olive
- olivelite
- olivewood
notes:
- Be careful when choosing OrangeFox version, Android 12 & 13 ROM needs OrangeFox version code with `A12`, for example `R11.1_5_A12`. Android 10 & 11 ROM needs OrangeFox version code without `A12` (bellow on the page)
requirements:
firmware: MiUI 12.5 (Q)
steps:
unlock_bootloader:
- type: confirm_button
content: >
As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone
how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone.
- type: link_button_with_confirm
content: >
- Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days.

- Add a phone number to your Mi account, insert a SIM into your phone.

- Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version.

- Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`.

- Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step!

- After device and Mi account are successfully verified, the bootloader should be unlocked.

- Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging`
link: https://en.miui.com/unlock/download_en.html
boot_recovery:
- type: call_button
content: >
Now you need to install a custom recovery system on the phone. A recovery is a small subsystem on your phone,
that manages updating, adapting and repairing of the operating system.

Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue.
command: adb_reboot_bootloader
- type: call_button
content: >
Install additional partitions selected before by pressing 'Confirm and run'. Once it's done continue.

Note : If you have not selected this partition, it will do nothing.
command: fastboot_flash_additional_partitions
- type: call_button
content: >
Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue.
command: fastboot_flash_recovery
- type: call_button
img: ofox.png
content: >
Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery.
If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed.
Once it's done continue.
command: fastboot_reboot_recovery
14 changes: 12 additions & 2 deletions openandroidinstaller/installer_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

from pathlib import Path
from typing import List, Optional
from typing_extensions import Self

import schema
import yaml
Expand Down Expand Up @@ -62,11 +63,12 @@ def __init__(
self.requirements = requirements
self.device_code = metadata.get("device_code")
self.is_ab = metadata.get("is_ab_device", False)
self.additional_steps = metadata.get("additional_steps")
self.supported_device_codes = metadata.get("supported_device_codes")
self.twrp_link = metadata.get("twrp-link")

@classmethod
def from_file(cls, path):
def from_file(cls, path) -> Self:
with open(path, "r", encoding="utf-8") as stream:
try:
raw_config = yaml.safe_load(stream)
Expand Down Expand Up @@ -134,6 +136,8 @@ def _load_config(device_code: str, config_path: Path) -> Optional[InstallerConfi
config = InstallerConfig.from_file(path)
logger.info(f"Loaded device config from {path}.")
if config:
if "additional_steps" not in config.metadata:
config.metadata.update({"additional_steps": "[]"})
logger.info(f"Config metadata: {config.metadata}.")
return config
else:
Expand All @@ -150,7 +154,8 @@ def validate_config(config: str) -> bool:
),
"content": str,
schema.Optional("command"): Regex(
r"adb_reboot|adb_reboot_bootloader|adb_reboot_download|adb_sideload|adb_twrp_wipe_and_install|adb_twrp_copy_partitions|fastboot_boot_recovery|fastboot_flash_boot|fastboot_unlock_critical|fastboot_unlock_with_code|fastboot_get_unlock_data|fastboot_unlock|fastboot_oem_unlock|fastboot_reboot|heimdall_flash_recovery"
r"""adb_reboot|adb_reboot_bootloader|adb_reboot_download|adb_sideload|adb_twrp_wipe_and_install|adb_twrp_copy_partitions|fastboot_boot_recovery|fastboot_flash_boot|fastboot_flash_recovery|
fastboot_unlock_critical|fastboot_unlock_with_code|fastboot_get_unlock_data|fastboot_unlock|fastboot_oem_unlock|fastboot_reboot|fastboot_reboot_recovery|heimdall_flash_recovery|fastboot_flash_additional_partitions"""
),
schema.Optional("allow_skip"): bool,
schema.Optional("img"): str,
Expand All @@ -166,6 +171,11 @@ def validate_config(config: str) -> bool:
"device_code": str,
"supported_device_codes": [str],
schema.Optional("twrp-link"): str,
schema.Optional("additional_steps"): [
Regex(r"dtbo|vbmeta|vendor_boot|super_empty")
],
schema.Optional("notes"): [str],
schema.Optional("brand"): str,
},
schema.Optional("requirements"): {
schema.Optional("android"): schema.Or(str, int),
Expand Down
90 changes: 89 additions & 1 deletion openandroidinstaller/tooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@ def adb_wait_for_sideload(bin_path: Path) -> TerminalResponse:
yield line


@add_logging("Reboot to recovery with adb")
def adb_reboot_recovery(bin_path: Path) -> TerminalResponse:
"""Reboot to recovery with adb."""
for line in run_command("adb reboot recovery", bin_path):
yield line
for line in adb_wait_for_recovery(bin_path=bin_path):
yield line


def adb_twrp_copy_partitions(bin_path: Path, config_path: Path) -> TerminalResponse:
# some devices like one plus 6t or motorola moto g7 power need the partitions copied to prevent a hard brick
logger.info("Sideload copy_partitions script with adb.")
Expand Down Expand Up @@ -416,7 +425,7 @@ def fastboot_boot_recovery(


def fastboot_flash_boot(bin_path: Path, recovery: str) -> TerminalResponse:
"""Temporarily, flash custom recovery with fastboot to boot partition."""
"""Flash custom recovery with fastboot to boot partition."""
logger.info("Flash custom recovery with fastboot.")
for line in run_command(
"fastboot flash boot", target=f"{recovery}", bin_path=bin_path
Expand All @@ -440,6 +449,85 @@ def fastboot_flash_boot(bin_path: Path, recovery: str) -> TerminalResponse:
yield True


@add_logging("Flash custom recovery with fastboot.")
def fastboot_flash_recovery(
bin_path: Path, recovery: str, is_ab: bool = True
) -> TerminalResponse:
"""Flash custom recovery with fastboot."""
for line in run_command(
"fastboot flash recovery ", target=f"{recovery}", bin_path=bin_path
):
yield line
if not is_ab:
if (type(line) == bool) and not line:
logger.error("Flashing recovery failed.")
yield False
else:
yield True


@add_logging("Rebooting device to recovery.")
def fastboot_reboot_recovery(bin_path: Path) -> TerminalResponse:
"""Reboot to recovery with fastboot.

WARNING: On some devices, users need to press a specific key combo to make it work.
"""
for line in run_command("fastboot reboot recovery", bin_path):
yield line


@add_logging("Flash additional partitions with fastboot")
def fastboot_flash_additional_partitions(
bin_path: Path,
dtbo: Optional[str],
vbmeta: Optional[str],
super_empty: Optional[str],
is_ab: bool = True,
) -> TerminalResponse:
"""Flash additional partitions (dtbo, vbmeta, super_empty) with fastboot."""
logger.info("Flash additional partitions with fastboot.")
if dtbo:
logger.info("dtbo selected. Flashing dtbo partition.")
for line in run_command(
"fastboot flash dtbo ", target=f"{dtbo}", bin_path=bin_path
):
yield line
if not is_ab:
if (type(line) == bool) and not line:
logger.error("Flashing dtbo failed.")
yield False
else:
yield True
else:
yield True

if vbmeta:
logger.info("vbmeta selected. Flashing vbmeta partition.")
for line in run_command(
"fastboot flash vbmeta ", target=f"{vbmeta}", bin_path=bin_path
):
yield line
if not is_ab:
if (type(line) == bool) and not line:
logger.error("Flashing vbmeta failed.")
yield False
else:
yield True

if super_empty:
logger.info("super_empty selected. Wiping super partition.")
for line in run_command(
"fastboot wipe-super ", target=f"{super_empty}", bin_path=bin_path
):
yield line
if not is_ab:
if (type(line) == bool) and not line:
logger.error("Wiping super failed.")
yield False
else:
yield True


def heimdall_wait_for_download_available(bin_path: Path) -> bool:
"""Use heimdall detect to wait for download mode to become available on the device."""
logger.info("Wait for download mode to become available.")
Expand Down
Loading