Skip to content

Commit 0604ff1

Browse files
author
rudu
committed
Add dtbo, vbmeta, super_empty flashing
1 parent f656346 commit 0604ff1

File tree

6 files changed

+239
-2
lines changed

6 files changed

+239
-2
lines changed

‎README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ Every config file should have `metadata` with the following fields:
215215
- `device_code`: str; The official device code.
216216
- `supported_device_codes`: List[str]; A list of supported device codes for the config. The config will be loaded based on this field.
217217
- `twrp-link`: [OPTIONAL] str; name of the corresponding twrp page.
218+
- `additional_steps` : [OPTIONAL] List[str]; A list of additional steps. Could be `dtbo`, `vbmeta`, `super_empty`.
218219

219220
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.
220221
- `android`: [OPTIONAL] int|str; Android version to install prior to installing a custom ROM.
@@ -231,7 +232,7 @@ Every step in the config file corresponds to one view in the application. These
231232
- `img`: [OPTIONAL] Display an image on the left pane of the step view. Images are loaded from `openandroidinstaller/assets/imgs/`.
232233
- `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 `>`.
233234
- `link`: [OPTIONAL] Link to use for the link button if type is `link_button_with_confirm`.
234-
- `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`.
235+
- `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_additional_partitions`, `fastboot_unlock_with_code`, `fastboot_unlock`, `fastboot_oem_unlock`, `fastboot_get_unlock_data`, `fastboot_reboot`, `heimdall_flash_recovery`.
235236
- `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.
236237

237238
**Please try to retain this order of these fields in your config to ensure consistency.**

‎openandroidinstaller/app_state.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ def __init__(
4444
self.config = None
4545
self.image_path = None
4646
self.recovery_path = None
47+
self.dtbo_path = None
48+
self.vbmeta_path = None
49+
self.super_empty_path = None
4750

4851
# store views
4952
self.default_views: List = []

‎openandroidinstaller/installer_config.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def __init__(
6262
self.requirements = requirements
6363
self.device_code = metadata.get("device_code")
6464
self.is_ab = metadata.get("is_ab_device", False)
65+
self.additional_steps = metadata.get("additional_steps")
6566
self.supported_device_codes = metadata.get("supported_device_codes")
6667
self.twrp_link = metadata.get("twrp-link")
6768

@@ -134,6 +135,8 @@ def _load_config(device_code: str, config_path: Path) -> Optional[InstallerConfi
134135
config = InstallerConfig.from_file(path)
135136
logger.info(f"Loaded device config from {path}.")
136137
if config:
138+
if "additional_steps" not in config.metadata:
139+
config.metadata.update({"additional_steps": "[]"})
137140
logger.info(f"Config metadata: {config.metadata}.")
138141
return config
139142
else:
@@ -150,7 +153,7 @@ def validate_config(config: str) -> bool:
150153
),
151154
"content": str,
152155
schema.Optional("command"): Regex(
153-
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_with_code|fastboot_get_unlock_data|fastboot_unlock|fastboot_oem_unlock|fastboot_reboot|heimdall_flash_recovery"
156+
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_with_code|fastboot_get_unlock_data|fastboot_unlock|fastboot_oem_unlock|fastboot_reboot|heimdall_flash_recovery|fastboot_flash_additional_partitions"
154157
),
155158
schema.Optional("allow_skip"): bool,
156159
schema.Optional("img"): str,
@@ -166,6 +169,7 @@ def validate_config(config: str) -> bool:
166169
"device_code": str,
167170
"supported_device_codes": [str],
168171
schema.Optional("twrp-link"): str,
172+
schema.Optional("additional_steps"): [str],
169173
},
170174
schema.Optional("requirements"): {
171175
schema.Optional("android"): schema.Or(str, int),

‎openandroidinstaller/tooling.py‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,3 +497,54 @@ def search_device(platform: str, bin_path: Path) -> Optional[str]:
497497
except CalledProcessError:
498498
logger.error("Failed to detect a device.")
499499
return None
500+
501+
502+
@add_logging("Flash additional partitions with fastboot")
503+
def fastboot_flash_additional_partitions(
504+
bin_path: Path, dtbo: str, vbmeta: str, super_empty: str, is_ab: bool = True
505+
) -> TerminalResponse:
506+
"""Flash additional partitions (dtbo, vbmeta, super_empty) with fastboot."""
507+
if dtbo:
508+
for line in run_command(
509+
"fastboot flash dtbo ", target=f"{dtbo}", bin_path=bin_path
510+
):
511+
yield line
512+
if not is_ab:
513+
if (type(line) == bool) and not line:
514+
logger.error("Flashing dtbo failed.")
515+
yield False
516+
else:
517+
yield True
518+
else:
519+
logger.info("No dtbo selected. Skipping")
520+
yield True
521+
522+
if vbmeta:
523+
for line in run_command(
524+
"fastboot flash vbmeta ", target=f"{vbmeta}", bin_path=bin_path
525+
):
526+
yield line
527+
if not is_ab:
528+
if (type(line) == bool) and not line:
529+
logger.error("Flashing vbmeta failed.")
530+
yield False
531+
else:
532+
yield True
533+
else:
534+
logger.info("No vbmeta selected. Skipping")
535+
yield True
536+
537+
if super_empty:
538+
for line in run_command(
539+
"fastboot wipe-super ", target=f"{super_empty}", bin_path=bin_path
540+
):
541+
yield line
542+
if not is_ab:
543+
if (type(line) == bool) and not line:
544+
logger.error("Wiping super failed.")
545+
yield False
546+
else:
547+
yield True
548+
else:
549+
logger.info("No super_empty selected. Skipping")
550+
yield True

‎openandroidinstaller/views/select_view.py‎

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,26 @@ def init_visuals(
9595
# initialize file pickers
9696
self.pick_image_dialog = FilePicker(on_result=self.pick_image_result)
9797
self.pick_recovery_dialog = FilePicker(on_result=self.pick_recovery_result)
98+
self.pick_dtbo_dialog = FilePicker(on_result=self.pick_dtbo_result)
99+
self.pick_vbmeta_dialog = FilePicker(on_result=self.pick_vbmeta_result)
100+
self.pick_super_empty_dialog = FilePicker(
101+
on_result=self.pick_super_empty_result
102+
)
103+
98104
self.selected_image = Text("Selected image: ")
99105
self.selected_recovery = Text("Selected recovery: ")
106+
self.selected_dtbo = Text("Selected dtbo: ")
107+
self.selected_vbmeta = Text("Selected vbmeta: ")
108+
self.selected_super_empty = Text("Selected super_empty: ")
100109

101110
# initialize and manage button state.
102111
self.confirm_button = confirm_button(self.on_confirm)
103112
self.confirm_button.disabled = True
104113
self.pick_recovery_dialog.on_result = self.enable_button_if_ready
105114
self.pick_image_dialog.on_result = self.enable_button_if_ready
115+
self.pick_dtbo_dialog.on_result = self.enable_button_if_ready
116+
self.pick_vbmeta_dialog.on_result = self.enable_button_if_ready
117+
self.pick_super_empty_dialog.on_result = self.enable_button_if_ready
106118
# back button
107119
self.back_button = ElevatedButton(
108120
"Back",
@@ -122,6 +134,9 @@ def build(self):
122134
# attach hidden dialogues
123135
self.right_view.controls.append(self.pick_image_dialog)
124136
self.right_view.controls.append(self.pick_recovery_dialog)
137+
self.right_view.controls.append(self.pick_dtbo_dialog)
138+
self.right_view.controls.append(self.pick_vbmeta_dialog)
139+
self.right_view.controls.append(self.pick_super_empty_dialog)
125140

126141
# create help/info button to show the help dialog
127142
info_button = OutlinedButton(
@@ -226,6 +241,83 @@ def build(self):
226241
),
227242
self.selected_recovery,
228243
Divider(),
244+
]
245+
)
246+
247+
# attach the controls for uploading others partitions, like dtbo, vbmeta & super_empty
248+
if "dtbo" in self.state.config.metadata["additional_steps"]:
249+
self.right_view.controls.extend(
250+
[
251+
Text("Select other specific images:", style="titleSmall"),
252+
Markdown(
253+
"""
254+
Depending of the ROM, OpenAndroidInstaller may have to install additional images.
255+
These images are usually needed for Android 13 ROM.
256+
Make sure the file is for **your exact phone model!**
257+
"""
258+
),
259+
Row(
260+
[
261+
FilledButton(
262+
"Pick `dtbo.img` image",
263+
icon=icons.UPLOAD_FILE,
264+
on_click=lambda _: self.pick_dtbo_dialog.pick_files(
265+
allow_multiple=False,
266+
file_type="custom",
267+
allowed_extensions=["img"],
268+
),
269+
expand=True,
270+
),
271+
]
272+
),
273+
self.selected_dtbo,
274+
]
275+
)
276+
if "vbmeta" in self.state.config.metadata["additional_steps"]:
277+
self.right_view.controls.extend(
278+
[
279+
Row(
280+
[
281+
FilledButton(
282+
"Pick `vbmeta.img` image",
283+
icon=icons.UPLOAD_FILE,
284+
on_click=lambda _: self.pick_vbmeta_dialog.pick_files(
285+
allow_multiple=False,
286+
file_type="custom",
287+
allowed_extensions=["img"],
288+
),
289+
expand=True,
290+
),
291+
]
292+
),
293+
self.selected_vbmeta,
294+
]
295+
)
296+
if "super_empty" in self.state.config.metadata["additional_steps"]:
297+
self.right_view.controls.extend(
298+
[
299+
Row(
300+
[
301+
FilledButton(
302+
"Pick `super_empty.img` image",
303+
icon=icons.UPLOAD_FILE,
304+
on_click=lambda _: self.pick_super_empty_dialog.pick_files(
305+
allow_multiple=False,
306+
file_type="custom",
307+
allowed_extensions=["img"],
308+
),
309+
expand=True,
310+
),
311+
]
312+
),
313+
self.selected_super_empty,
314+
Divider(),
315+
]
316+
)
317+
318+
# attach the bottom buttons
319+
self.right_view.controls.extend(
320+
[
229321
self.info_field,
230322
Row([self.back_button, self.confirm_button]),
231323
]
@@ -291,6 +383,61 @@ def pick_recovery_result(self, e: FilePickerResultEvent):
291383
# update
292384
self.selected_recovery.update()
293385

386+
def pick_dtbo_result(self, e: FilePickerResultEvent):
387+
path = ", ".join(map(lambda f: f.name, e.files)) if e.files else "Cancelled!"
388+
# update the textfield with the name of the file
389+
self.selected_dtbo.value = self.selected_dtbo.value.split(":")[0] + f": {path}"
390+
if e.files:
391+
# check if the dtbo works with the device and show the filename in different colors accordingly
392+
if path == "dtbo.img":
393+
self.selected_dtbo.color = colors.GREEN
394+
self.state.dtbo_path = e.files[0].path
395+
logger.info(f"Selected dtbo from {self.state.dtbo_path}")
396+
else:
397+
self.selected_dtbo.color = colors.RED
398+
else:
399+
logger.info("No image selected.")
400+
# update
401+
self.selected_dtbo.update()
402+
403+
def pick_vbmeta_result(self, e: FilePickerResultEvent):
404+
path = ", ".join(map(lambda f: f.name, e.files)) if e.files else "Cancelled!"
405+
# update the textfield with the name of the file
406+
self.selected_vbmeta.value = (
407+
self.selected_vbmeta.value.split(":")[0] + f": {path}"
408+
)
409+
if e.files:
410+
# check if the vbmeta works with the device and show the filename in different colors accordingly
411+
if path == "vbmeta.img":
412+
self.selected_vbmeta.color = colors.GREEN
413+
self.state.vbmeta_path = e.files[0].path
414+
logger.info(f"Selected vbmeta from {self.state.vbmeta_path}")
415+
else:
416+
self.selected_vbmeta.color = colors.RED
417+
else:
418+
logger.info("No image selected.")
419+
# update
420+
self.selected_vbmeta.update()
421+
422+
def pick_super_empty_result(self, e: FilePickerResultEvent):
423+
path = ", ".join(map(lambda f: f.name, e.files)) if e.files else "Cancelled!"
424+
# update the textfield with the name of the file
425+
self.selected_super_empty.value = (
426+
self.selected_super_empty.value.split(":")[0] + f": {path}"
427+
)
428+
if e.files:
429+
# check if the super_empty works with the device and show the filename in different colors accordingly
430+
if path == "super_empty.img":
431+
self.selected_super_empty.color = colors.GREEN
432+
self.state.super_empty_path = e.files[0].path
433+
logger.info(f"Selected super_empty from {self.state.super_empty_path}")
434+
else:
435+
self.selected_super_empty.color = colors.RED
436+
else:
437+
logger.info("No image selected.")
438+
# update
439+
self.selected_super_empty.update()
440+
294441
def enable_button_if_ready(self, e):
295442
"""Enable the confirm button if both files have been selected."""
296443
if (".zip" in self.selected_image.value) and (
@@ -320,6 +467,29 @@ def enable_button_if_ready(self, e):
320467
self.confirm_button.disabled = True
321468
self.right_view.update()
322469
return
470+
471+
if (
472+
(self.selected_dtbo.color and self.selected_dtbo.color == "red")
473+
or (self.selected_vbmeta.color and self.selected_vbmeta.color == "red")
474+
or (
475+
self.selected_super_empty.color
476+
and self.selected_super_empty.color == "red"
477+
)
478+
):
479+
logger.error(
480+
"Some additional images don't match. Please select different ones."
481+
)
482+
self.info_field.controls = [
483+
Text(
484+
"Some additional images don't match. Select right ones or unselect them.",
485+
color=colors.RED,
486+
weight="bold",
487+
)
488+
]
489+
self.confirm_button.disabled = True
490+
self.right_view.update()
491+
return
492+
323493
logger.info("Image and recovery work with the device. You can continue.")
324494
self.info_field.controls = []
325495
self.confirm_button.disabled = False

‎openandroidinstaller/views/step_view.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
adb_twrp_copy_partitions,
4646
fastboot_boot_recovery,
4747
fastboot_flash_boot,
48+
fastboot_flash_additional_partitions,
4849
fastboot_oem_unlock,
4950
fastboot_reboot,
5051
fastboot_unlock,
@@ -231,6 +232,13 @@ def call_to_phone(self, e, command: str):
231232
fastboot_flash_boot,
232233
recovery=self.state.recovery_path,
233234
),
235+
"fastboot_flash_additional_partitions": partial(
236+
fastboot_flash_additional_partitions,
237+
dtbo=self.state.dtbo_path,
238+
vbmeta=self.state.vbmeta_path,
239+
super_empty=self.state.super_empty_path,
240+
is_ab=self.state.config.is_ab,
241+
),
234242
"fastboot_reboot": fastboot_reboot,
235243
"heimdall_flash_recovery": partial(
236244
heimdall_flash_recovery, recovery=self.state.recovery_path

0 commit comments

Comments
 (0)