From 5ec5e0a7ace99ffead92b41b2040c0e6fc17dd93 Mon Sep 17 00:00:00 2001 From: Bing Date: Wed, 31 May 2023 23:52:24 -0400 Subject: [PATCH] - Update build workflows - Add payload_dumper functionality to PixelFlasher to handle OTA files, thanks to @vm03 for sharing source code. - Added rules engine code to better / easier management of the UI widgets enabling / disabling. - Auto detect Pixel OTA image and extract boot / init_boot / vbmeta for patching and flashing. - Add Full OTA mode, which flashes full OTA image, while optionally retaining root, and best of all, for A/B devices, both slots are bootable, you can even have one rooted and one not. --- .github/workflows/codeql-analysis.yml | 1 + .github/workflows/mac_11.yml | 9 +- .github/workflows/mac_13.yml | 9 +- .github/workflows/mint_21_1.yml | 9 +- .github/workflows/ubuntu_20_04.yml | 9 +- .github/workflows/ubuntu_22_04.yml | 9 +- .github/workflows/windows_2022.yml | 9 +- Main.py | 396 +++++++++------ README.md | 4 +- build-on-mac.spec | 2 +- build.sh | 2 +- constants.py | 2 +- modules.py | 504 +++++++++++-------- payload_dumper.py | 148 ++++++ requirements.txt | 5 +- runtime.py | 34 ++ update_metadata_pb2.py | 669 ++++++++++++++++++++++++++ windows-metadata.yaml | 2 +- windows-version-info.txt | 8 +- 19 files changed, 1476 insertions(+), 355 deletions(-) create mode 100644 payload_dumper.py create mode 100644 update_metadata_pb2.py diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b3c24b7..66b9285 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,6 +22,7 @@ on: jobs: analyze: + if: ${{ github.actor == 'badabing2005' || env.ACT }} name: Analyze runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/mac_11.yml b/.github/workflows/mac_11.yml index ee227d8..83b5cea 100644 --- a/.github/workflows/mac_11.yml +++ b/.github/workflows/mac_11.yml @@ -18,7 +18,7 @@ on: jobs: build_mac_11: - if: github.actor == 'badabing2005' + if: ${{ github.actor == 'badabing2005' || env.ACT }} # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners # runs-on: macos-latest runs-on: macos-11 @@ -70,12 +70,19 @@ jobs: # Upload artifcats Mac-OS 11 - name: Upload Mac-OS 11 Artifact + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} # Only run this step when running in GitHub Actions uses: actions/upload-artifact@v3 id: upload_artifact_macos_11 with: name: PixelFlasher_MacOS_11.dmg path: dist/PixelFlasher.dmg + # Copy the artifact to a local directory + - name: Copy MacOS 11 Artifact locally + if: ${{ env.ACT }} # Only run this step when not running in GitHub Actions + run: | + cp dist/PixelFlasher.dmg dist/PixelFlasher_MacOS_11.dmg + # # Create a release # - name: Create Release # id: create_release diff --git a/.github/workflows/mac_13.yml b/.github/workflows/mac_13.yml index 521a053..c4e9deb 100644 --- a/.github/workflows/mac_13.yml +++ b/.github/workflows/mac_13.yml @@ -18,7 +18,7 @@ on: jobs: build_mac_13: - if: github.actor == 'badabing2005' + if: ${{ github.actor == 'badabing2005' || env.ACT }} # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners # runs-on: macos-latest runs-on: macos-13 @@ -70,12 +70,19 @@ jobs: # Upload artifcats Mac-OS 13 to Actions - name: Upload Mac-OS 13 Artifact + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} # Only run this step when running in GitHub Actions uses: actions/upload-artifact@v3 id: upload_artifact_macos_13 with: name: PixelFlasher_MacOS_13.dmg path: dist/PixelFlasher.dmg + # Copy the artifact to a local directory + - name: Copy MacOS 13 Artifact locally + if: ${{ env.ACT }} # Only run this step when not running in GitHub Actions + run: | + cp dist/PixelFlasher.dmg dist/PixelFlasher_MacOS_13.dmg + # # Create a release # - name: Create Release # id: create_release diff --git a/.github/workflows/mint_21_1.yml b/.github/workflows/mint_21_1.yml index 3abbebb..76f3f68 100644 --- a/.github/workflows/mint_21_1.yml +++ b/.github/workflows/mint_21_1.yml @@ -18,7 +18,7 @@ on: jobs: build_mint_21_1: - if: github.actor == 'badabing2005' + if: ${{ github.actor == 'badabing2005' || env.ACT }} # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners runs-on: ubuntu-latest container: @@ -63,9 +63,16 @@ jobs: # Upload artifcats Mint 21.1 to Actions - name: Upload Mint 21.1 Artifact + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} # Only run this step when running in GitHub Actions uses: actions/upload-artifact@v3 id: upload_artifacts_mint_21_1 with: name: PixelFlasher_Mint_21_1 path: dist/PixelFlasher + # Copy the artifact to a local directory + - name: Copy Mint 21.1 Artifact locally + if: ${{ env.ACT }} # Only run this step when not running in GitHub Actions + run: | + cp dist/PixelFlasher dist/PixelFlasher_Mint_21_1 + diff --git a/.github/workflows/ubuntu_20_04.yml b/.github/workflows/ubuntu_20_04.yml index a818113..78cb240 100644 --- a/.github/workflows/ubuntu_20_04.yml +++ b/.github/workflows/ubuntu_20_04.yml @@ -18,7 +18,7 @@ on: jobs: build_ubuntu_20_04: - if: github.actor == 'badabing2005' + if: ${{ github.actor == 'badabing2005' || env.ACT }} # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners runs-on: ubuntu-20.04 @@ -63,12 +63,19 @@ jobs: # Upload artifcats Ubuntu 20.04 to Actions - name: Upload Ubuntu 20.04 Artifact + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} # Only run this step when running in GitHub Actions uses: actions/upload-artifact@v3 id: upload_artifacts_ubuntu_20_04 with: name: PixelFlasher_Ubuntu_20_04 path: dist/PixelFlasher + # Copy the artifact to a local directory + - name: Copy Mint 21.1 Artifact locally + if: ${{ env.ACT }} # Only run this step when not running in GitHub Actions + run: | + cp dist/PixelFlasher dist/PixelFlasher_Ubuntu_20_04 + # # Create a release # - name: Create Release # id: create_release diff --git a/.github/workflows/ubuntu_22_04.yml b/.github/workflows/ubuntu_22_04.yml index 9fb90ec..27ae49b 100644 --- a/.github/workflows/ubuntu_22_04.yml +++ b/.github/workflows/ubuntu_22_04.yml @@ -18,7 +18,7 @@ on: jobs: build_ubuntu_22_04: - if: github.actor == 'badabing2005' + if: ${{ github.actor == 'badabing2005' || env.ACT }} # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners runs-on: ubuntu-latest @@ -61,12 +61,19 @@ jobs: # Upload artifcats Ubuntu 22.04 to Actions - name: Upload Ubuntu 22.04 Artifact + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} # Only run this step when running in GitHub Actions uses: actions/upload-artifact@v3 id: upload_artifacts_ubuntu_22_04 with: name: PixelFlasher_Ubuntu_22_04 path: dist/PixelFlasher + # Copy the artifact to a local directory + - name: Copy Ubuntu 22.04 Artifact locally + if: ${{ env.ACT }} # Only run this step when not running in GitHub Actions + run: | + cp dist/PixelFlasher dist/PixelFlasher_Ubuntu_22_04 + # # Create a release # - name: Create Release # id: create_release diff --git a/.github/workflows/windows_2022.yml b/.github/workflows/windows_2022.yml index 1f79747..1963f38 100644 --- a/.github/workflows/windows_2022.yml +++ b/.github/workflows/windows_2022.yml @@ -18,7 +18,7 @@ on: jobs: build_windows: - if: github.actor == 'badabing2005' + if: ${{ github.actor == 'badabing2005' || env.ACT }} # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners runs-on: windows-latest @@ -64,12 +64,19 @@ jobs: # Upload artifcats Windows to Actions - name: Upload Windows Artifact + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} # Only run this step when running in GitHub Actions uses: actions/upload-artifact@v3 id: upload_artifacts_windows with: name: PixelFlasher.exe path: dist/PixelFlasher.exe + # Copy the artifact to a local directory + - name: Copy Windows Artifact locally + if: ${{ env.ACT }} # Only run this step when not running in GitHub Actions + run: | + cp dist/PixelFlasher dist/PixelFlasher.exe + # # Create a release # - name: Create Release # id: create_release diff --git a/Main.py b/Main.py index f5db661..bfd260e 100644 --- a/Main.py +++ b/Main.py @@ -190,7 +190,17 @@ def initialize(self): else: try: set_firmware_model(firmware[0]) - set_firmware_id(f"{firmware[0]}-{firmware[1]}") + if firmware[1] == 'ota': + set_firmware_id(f"{firmware[0]}-{firmware[1]}-{firmware[2]}") + set_ota(True) + self.enable_disable_radio_button('OTA', True, selected=True, just_select=True) + self.config.flash_mode = 'OTA' + else: + set_firmware_id(f"{firmware[0]}-{firmware[1]}") + if self.config.flash_mode == 'OTA': + self.config.flash_mode = 'dryRun' + self.enable_disable_radio_button('dryRun', True, selected=True, just_select=True) + set_ota(False) except Exception as e: set_firmware_model(None) set_firmware_id(filename) @@ -235,12 +245,6 @@ def initialize(self): rom_hash = sha256(self.config.custom_rom_path) self.config.rom_sha256 = rom_hash self.custom_rom.SetToolTip(f"SHA-256: {rom_hash}") - if self.config.custom_rom: - self.custom_rom.Enable() - self.process_rom.Enable() - else: - self.custom_rom.Disable() - self.process_rom.Disable() # refresh boot.img list populate_boot_list(self) @@ -310,9 +314,28 @@ def initialize(self): # set the ui fonts self.set_ui_fonts() + # update widgets + self.update_widget_states() + self.spinner.Hide() self.spinner_label.Hide() + + # ----------------------------------------------- + # enable_disable_radio_buttons + # ----------------------------------------------- + def enable_disable_radio_button(self, name, state, selected=False, just_select=False): + radio_buttons = self.mode_sizer.GetChildren() + if isinstance(name, str): + for child in radio_buttons: + radio_button = child.GetWindow() + if radio_button and radio_button.GetName() == f"mode-{name}": + if not just_select: + radio_button.Enable(state) + if state and selected: + radio_button.SetValue(True) + + # ----------------------------------------------- # set_ui_fonts # ----------------------------------------------- @@ -660,6 +683,11 @@ def Test(self, event): print("Entrering Test function (used during development only) ...") # device = get_phone() # res = device.open_shell() + start_time = time.time() + self.update_widget_states() + end_time = time.time() + elapsed_time = end_time - start_time + print(f"The function update_widget_states took {elapsed_time} seconds to execute.") # ----------------------------------------------- # _on_help_about @@ -694,10 +722,12 @@ def _on_advanced_config(self, event): self.config.pf_font_size = get_pf_font_size() self.set_ui_fonts() advanced_setting_dialog.Destroy() + # show / hide advanced settings self._advanced_options_hide(not get_advanced_options()) populate_boot_list(self) set_flash_button_state(self) + self.update_widget_states() # ----------------------------------------------- # _on_package_manager @@ -798,8 +828,13 @@ def _advanced_options_hide(self, value): a = self.mode_radio_button.Name # if we're turning off advanced options, and the current mode is customFlash, change it to dryRun if self.mode_radio_button.Name == 'mode-customFlash' and self.mode_radio_button.GetValue(): - self.mode_radio_button.PreviousInGroup.SetValue(True) - self.config.flash_mode = 'dryRun' + if get_ota(): + self.enable_disable_radio_button('OTA', True, selected=True, just_select=True) + self.config.flash_mode = 'OTA' + else: + #self.mode_radio_button.PreviousInGroup.SetValue(True) + self.enable_disable_radio_button('dryRun', True, selected=True, just_select=True) + self.config.flash_mode = 'dryRun' else: # flash options self.flash_both_slots_checkBox.Show() @@ -968,27 +1003,11 @@ def _check_for_bad_magisk(self, m_version, m_app_version): # ----------------------------------------------- def _update_custom_flash_options(self): boot = get_boot() - if not boot: - self.paste_boot.Enable(False) image_mode = get_image_mode() image_path = get_image_path() - if self.config.flash_mode == 'customFlash': - self.temporary_root_checkBox.Enable(False) - self.image_file_picker.Enable(True) - self.image_choice.Enable(True) - if boot: - self.paste_boot.Enable(True) - else: - # disable custom_flash_options - if boot and boot.is_patched == 1: - self.temporary_root_checkBox.Enable(True) - else: - self.temporary_root_checkBox.Enable(False) + if self.config.flash_mode != 'customFlash' or not boot: self.flash_radio_button.Enable(False) self.live_boot_radio_button.Enable(False) - self.image_file_picker.Enable(False) - self.image_choice.Enable(False) - self.paste_boot.Enable(False) return self.live_boot_radio_button.Enable(False) self.flash_radio_button.Enable(False) @@ -998,8 +1017,6 @@ def _update_custom_flash_options(self): filename, extension = os.path.splitext(image_path) extension = extension.lower() if image_mode == 'boot': - if boot: - self.paste_boot.Enable(True) if extension == '.img': self.live_boot_radio_button.Enable(True) self.flash_radio_button.Enable(True) @@ -1007,7 +1024,6 @@ def _update_custom_flash_options(self): else: print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Selected file is not of type .img") elif image_mode in ['image', 'SIDELOAD']: - self.paste_boot.Enable(False) if extension == '.zip': self.live_boot_radio_button.Enable(False) self.flash_radio_button.Enable(True) @@ -1015,20 +1031,13 @@ def _update_custom_flash_options(self): self.flash_radio_button.SetValue(True) else: print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Selected file is not of type .zip") + elif extension == '.img': + self.live_boot_radio_button.Enable(False) + self.flash_radio_button.Enable(True) + self.flash_button.Enable(True) + self.flash_radio_button.SetValue(True) else: - self.paste_boot.Enable(False) - if extension == '.img': - self.live_boot_radio_button.Enable(False) - self.flash_radio_button.Enable(True) - self.flash_button.Enable(True) - self.flash_radio_button.SetValue(True) - else: - print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Selected file is not of type .img") - elif image_mode == 'boot': - if boot: - self.paste_boot.Enable(True) - else: - self.paste_boot.Enable(False) + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Selected file is not of type .img") # ----------------------------------------------- # _select_configured_device @@ -1065,6 +1074,8 @@ def _select_configured_device(self): print(f"{datetime.now():%Y-%m-%d %H:%M:%S} No Device is selected!") puml(f":Select Device;\nnote right:No Device is selected!\n") self._reflect_slots() + self.update_widget_states() + # ----------------------------------------------- # _reflect_slots @@ -1072,87 +1083,214 @@ def _select_configured_device(self): def _reflect_slots(self): device = get_phone() if device: - self.reboot_recovery_button.Enable(True) - if device.mode == 'adb': - self.reboot_download_button.Enable(True) - if device.rooted: - self.reboot_safemode_button.Enable(True) - else: - self.reboot_safemode_button.Enable(False) - else: - self.reboot_download_button.Enable(False) - self.reboot_safemode_button.Enable(False) - self.reboot_bootloader_button.Enable(True) - self.reboot_system_button.Enable(True) - self.shell_button.Enable(True) - self.info_button.Enable(True) - self.unlock_bootloader.Enable(True) - self.lock_bootloader.Enable(True) - self.install_magisk_button.Enable(True) - self.flash_both_slots_checkBox.Enable(True) - self.flash_to_inactive_slot_checkBox.Enable(True) - self.no_reboot_checkBox.Enable(True) - self.partition_manager_button.Enable(True) - if device.rooted: - self.backup_manager_button.Enable(True) - else: - self.backup_manager_button.Enable(False) - self.install_apk.Enable(True) - self.package_manager.Enable(True) if device.active_slot == 'a': self.device_label.Label = "ADB Connected Devices\nCurrent Active Slot: [A]" - self.a_radio_button.Enable(False) - self.b_radio_button.Enable(True) self.b_radio_button.SetValue(True) - self.set_active_slot_button.Enable(True) set_a_only(False) elif device.active_slot == 'b': self.device_label.Label = "ADB Connected Devices\nCurrent Active Slot: [B]" - self.a_radio_button.Enable(True) - self.b_radio_button.Enable(False) self.a_radio_button.SetValue(True) - self.set_active_slot_button.Enable(True) set_a_only(False) else: self.device_label.Label = "ADB Connected Devices" - self.a_radio_button.Enable(False) - self.b_radio_button.Enable(False) self.a_radio_button.SetValue(False) self.b_radio_button.SetValue(False) - self.set_active_slot_button.Enable(False) - self.flash_both_slots_checkBox.Enable(False) - self.flash_to_inactive_slot_checkBox.Enable(False) - self.no_reboot_checkBox.Enable(False) set_a_only(True) - if device.magisk_modules_summary == '': - self.magisk_button.Enable(False) - else: - self.magisk_button.Enable(True) else: self.device_label.Label = "ADB Connected Devices" - self.a_radio_button.Enable(False) - self.b_radio_button.Enable(False) self.a_radio_button.SetValue(False) self.b_radio_button.SetValue(False) - self.set_active_slot_button.Enable(False) - self.reboot_recovery_button.Enable(False) - self.reboot_download_button.Enable(False) - self.reboot_safemode_button.Enable(False) - self.reboot_bootloader_button.Enable(False) - self.reboot_system_button.Enable(False) - self.shell_button.Enable(False) - self.info_button.Enable(False) - self.magisk_button.Enable(False) - self.unlock_bootloader.Enable(False) - self.lock_bootloader.Enable(False) - self.install_magisk_button.Enable(False) - self.backup_manager_button.Enable(False) - self.partition_manager_button.Enable(False) - self.install_apk.Enable(False) - self.package_manager.Enable(False) - self.flash_both_slots_checkBox.Enable(False) - self.flash_to_inactive_slot_checkBox.Enable(False) - self.no_reboot_checkBox.Enable(False) + + + #----------------------------------------------------------------------------- + # evaluate_condition + #----------------------------------------------------------------------------- + # Define the rules engine + def evaluate_condition(self, condition): + try: + if condition == 'device_attached': + device = get_phone() + if device: + return True + return False + + elif condition == 'device_mode_adb': + device = get_phone() + if device and device.mode == 'adb': + return True + return False + + elif condition == 'device_is_rooted': + device = get_phone() + if device and device.rooted: + return True + return False + + elif condition == 'mode_is_not_ota': + if self.config.flash_mode != 'OTA': + return True + return False + + elif condition == 'custom_flash': + if self.config.flash_mode == 'customFlash': + return True + return False + + elif condition == 'custom_rom': + if self.config.custom_rom: + return True + return False + + elif condition == 'custom_rom_selected': + if self.config.custom_rom_path and os.path.exists(self.config.custom_rom_path): + return True + return False + + elif condition == 'firmware_selected': + if self.config.firmware_path and os.path.exists(self.config.firmware_path): + return True + return False + + elif condition == 'not_custom_flash': + if self.config.flash_mode != 'customFlash': + return True + return False + + elif condition == 'dual_slot': + device = get_phone() + if device and device.active_slot in ['a', 'b']: + return True + return False + + elif condition == 'slot_a': + device = get_phone() + if device and device.active_slot == 'a': + return True + return False + + elif condition == 'slot_b': + device = get_phone() + if device and device.active_slot =='b': + return True + return False + + elif condition == 'has_magisk_modules': + device = get_phone() + if device.magisk_modules_summary == '': + return False + return True + + elif condition == 'boot_is_selected': + boot = get_boot() + if boot: + return True + return False + + elif condition == 'boot_is_patched': + boot = get_boot() + if boot and boot.is_patched == 1: + return True + return False + + elif condition == 'boot_is_not_patched': + boot = get_boot() + if boot and boot.is_patched == 1: + return False + return True + + elif condition == 'custom_image_selected': + image_path = get_image_path() + if image_path: + return True + return False + + elif condition == 'custom_image_mode_is_boot': + image_mode = get_image_mode() + if image_mode == 'boot': + return True + return False + + elif condition == 'firmware_is_ota': + return get_ota() + + elif condition == 'firmware_is_not_ota': + return not get_ota() + + elif condition == 'sdk_ok': + return get_sdk_state() + + except Exception as e: + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while evaluating a rule") + print(e) + + #----------------------------------------------------------------------------- + # update_widget_states + #----------------------------------------------------------------------------- + def update_widget_states(self): + try: + widget_conditions = { + self.reboot_recovery_button: ['device_attached'], + self.reboot_bootloader_button: ['device_attached'], + self.reboot_system_button: ['device_attached'], + self.shell_button: ['device_attached'], + self.info_button: ['device_attached'], + self.unlock_bootloader: ['device_attached'], + self.lock_bootloader: ['device_attached'], + self.install_magisk_button: ['device_attached'], + self.partition_manager_button: ['device_attached'], + self.install_apk: ['device_attached'], + self.package_manager: ['device_attached'], + self.no_reboot_checkBox: ['device_attached'], + self.image_file_picker: ['custom_flash'], + self.image_choice: ['custom_flash'], + self.custom_rom: ['custom_rom'], + self.scan_button: ['sdk_ok'], + self.wifi_adb: ['sdk_ok'], + self.device_choice: ['sdk_ok'], + self.process_firmware: ['firmware_selected'], + self.delete_boot_button: ['boot_is_selected'], + self.boot_folder_button: ['boot_is_selected'], + self.firmware_folder_button: ['boot_is_selected'], + self.live_boot_button: ['boot_is_selected'], + self.flash_boot_button: ['boot_is_selected'], + self.paste_boot: ['boot_is_selected', 'custom_flash'], + self.patch_boot_button: ['boot_is_selected', 'boot_is_not_patched'], + self.process_rom: ['custom_rom', 'custom_rom_selected'], + self.magisk_button: ['device_attached', 'has_magisk_modules'], + self.a_radio_button: ['device_attached', 'slot_b'], + self.b_radio_button: ['device_attached', 'slot_a'], + self.set_active_slot_button: ['device_attached', 'dual_slot'], + self.reboot_download_button: ['device_attached', 'device_mode_adb'], + self.backup_manager_button: ['device_attached', 'device_is_rooted'], + self.reboot_safemode_button: ['device_attached', 'device_mode_adb', 'device_is_rooted'], + self.flash_both_slots_checkBox: ['device_attached', 'mode_is_not_ota', 'dual_slot'], + self.flash_to_inactive_slot_checkBox: ['device_attached', 'mode_is_not_ota', 'dual_slot'], + self.fastboot_force_checkBox: ['device_attached', 'mode_is_not_ota', 'dual_slot'], + self.temporary_root_checkBox: ['not_custom_flash', 'boot_is_patched', 'boot_is_selected'], + # Special handling of non-widgets + 'mode_radio_button.OTA': ['firmware_selected', 'firmware_is_ota'], + 'mode_radio_button.keepData': ['firmware_selected', 'firmware_is_not_ota'], + 'mode_radio_button.wipeData': ['firmware_selected', 'firmware_is_not_ota'], + 'mode_radio_button.dryRun': ['firmware_selected', 'firmware_is_not_ota'], + } + + for widget, conditions in widget_conditions.items(): + # Evaluate conditions for the widget using the rules engine + enable_widget = all(self.evaluate_condition(condition) for condition in conditions) + + # Set the state of the widget + if isinstance(widget, str): + # Handle special case for Flash Mode Radio Button Widget + if widget.startswith('mode_radio_button'): + name = widget.split('.')[1] + self.enable_disable_radio_button(name, enable_widget) + else: + # Handle widget objects + widget.Enable(enable_widget) + + except Exception as e: + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while updating widgets.") + print(e) #----------------------------------------------------------------------------- @@ -1190,6 +1328,7 @@ def _on_select_device(event): set_phone(device) self._print_device_details(device) self._reflect_slots() + self.update_widget_states() self._on_spin('stop') # ----------------------------------------------- @@ -1330,6 +1469,7 @@ def _on_mode_changed(event): print(f"Flash mode changed to: {self.config.flash_mode}") puml(f":Flash mode change;\n", True) puml(f"note right:{self.config.flash_mode}\n") + self.update_widget_states() if self.config.flash_mode != 'customFlash': set_flash_button_state(self) self._update_custom_flash_options() @@ -1846,15 +1986,11 @@ def _on_custom_rom(event): if status: print(f"{datetime.now():%Y-%m-%d %H:%M:%S} Enabled Custom ROM") puml(":Custom ROM: ON;\n", True) - self.custom_rom.Enable() - self.process_rom.Enable() - populate_boot_list(self) else: print(f"{datetime.now():%Y-%m-%d %H:%M:%S} Disabled Custom ROM") puml(":Custom ROM: ON;\n", True) - self.custom_rom.Disable() - self.process_rom.Disable() - populate_boot_list(self) + populate_boot_list(self) + self.update_widget_states() # ----------------------------------------------- # _on_show_all_boot @@ -1943,15 +2079,6 @@ def _on_boot_selected(event): debug("INFO: Duplicate PACKAGE_BOOT records found") self.config.boot_id = boot.boot_id self.config.selected_boot_md5 = boot.boot_hash - self.delete_boot_button.Enable(True) - self.boot_folder_button.Enable(True) - self.firmware_folder_button.Enable(True) - self.live_boot_button.Enable(True) - self.flash_boot_button.Enable(True) - if boot.magisk_version == '': - self.patch_boot_button.Enable(True) - else: - self.patch_boot_button.Enable(False) print("Selected Boot:") puml(":Select Boot;\n", True) message = f" File: {os.path.basename(urlparse(boot.boot_path).path)}\n" @@ -1977,13 +2104,6 @@ def _on_boot_selected(event): else: self.config.boot_id = None self.config.selected_boot_md5 = None - self.patch_boot_button.Enable(False) - self.delete_boot_button.Enable(False) - self.boot_folder_button.Enable(False) - self.firmware_folder_button.Enable(False) - self.live_boot_button.Enable(False) - self.flash_boot_button.Enable(False) - self.paste_boot.Enable(False) if self.list.ItemCount == 0 : if self.config.firmware_path: print("\nPlease Process the firmware!") @@ -1992,6 +2112,7 @@ def _on_boot_selected(event): set_boot(boot) set_flash_button_state(self) self._update_custom_flash_options() + self.update_widget_states() # ----------------------------------------------- # _on_delete_boot @@ -2178,7 +2299,6 @@ def _on_clear(event): self.wifi_adb = wx.BitmapButton(panel, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, wx.BU_AUTODRAW|0) self.wifi_adb.SetBitmap(images.Wifi_ADB.GetBitmap()) self.wifi_adb.SetToolTip(u"Connect/Disconnect to Remote Device (Wifi ADB)\nNote: ADB only, fastboot commands (example flashing)\ncannot be executed remotely.\nLeft click to connect, Right click to disconnect.") - self.wifi_adb.Enable(False) adb_label_sizer = wx.BoxSizer(wx.HORIZONTAL) adb_label_sizer.Add(self.device_label, 1, wx.EXPAND) adb_label_sizer.Add(self.wifi_adb, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL, border=24) @@ -2197,7 +2317,6 @@ def _on_clear(event): self.scan_button = wx.Button(panel, label=u"Scan") self.scan_button.SetToolTip(u"Scan for Devices\nPlease manually select the device after the scan is completed.") self.scan_button.SetBitmap(images.Scan.GetBitmap()) - self.scan_button.Enable(False) device_tooltip = "[root status] [device mode] [device id] [device model] [device firmware]\n\n" device_sizer = wx.BoxSizer(wx.HORIZONTAL) device_sizer.Add(self.device_choice, 1, wx.EXPAND) @@ -2383,14 +2502,15 @@ def _on_clear(event): list_sizer.Add(self.list, 1, wx.ALL|wx.EXPAND) list_sizer.Add(image_buttons_sizer, 0, wx.ALL|wx.EXPAND) - # 8th row widgets + # 8th row widgets (Flash Mode) mode_label = wx.StaticText(panel, label=u"Flash Mode") - mode_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.mode_sizer = wx.BoxSizer(wx.HORIZONTAL) # _add_mode_radio_button(sizer, index, flash_mode, label, tooltip) - _add_mode_radio_button(mode_sizer, 0, 'keepData', "Keep Data", "Data will be kept intact.") - _add_mode_radio_button(mode_sizer, 1, 'wipeData', "WIPE all data", "CAUTION: This will wipe your data") - _add_mode_radio_button(mode_sizer, 2, 'dryRun', "Dry Run", "Dry Run, no flashing will be done.\nThe phone will reboot to fastboot and then\nback to normal.\nThis is for testing.") - _add_mode_radio_button(mode_sizer, 3, 'customFlash', "Custom Flash", "Custom Flash, Advanced option to flash a single file.\nThis will not flash the factory image.\It will flash the single selected file.") + _add_mode_radio_button(self.mode_sizer, 0, 'keepData', "Keep Data", "Data will be kept intact.") + _add_mode_radio_button(self.mode_sizer, 1, 'wipeData', "WIPE all data", "CAUTION: This will wipe your data") + _add_mode_radio_button(self.mode_sizer, 2, 'dryRun', "Dry Run", "Dry Run, no flashing will be done.\nThe phone will reboot to fastboot and then\nback to normal.\nThis is for testing.") + _add_mode_radio_button(self.mode_sizer, 3, 'OTA', "Full OTA", "Flash full OTA, and have the choice of flashing patched image(s).") + _add_mode_radio_button(self.mode_sizer, 4, 'customFlash', "Custom Flash", "Custom Flash, Advanced option to flash a single file.\nThis will not flash the factory image.\It will flash the single selected file.") # 9th row widgets (custom flash) self.live_boot_radio_button = wx.RadioButton(panel, wx.ID_ANY, u"Live Boot", wx.DefaultPosition, wx.DefaultSize, wx.RB_GROUP) @@ -2429,7 +2549,7 @@ def _on_clear(event): self.fastboot_verbose_checkBox = wx.CheckBox(panel, wx.ID_ANY, u"Verbose", wx.DefaultPosition, wx.DefaultSize, 0) self.fastboot_verbose_checkBox.SetToolTip(u"set fastboot option to verbose") self.temporary_root_checkBox = wx.CheckBox(panel, wx.ID_ANY, u"Temporary Root", wx.DefaultPosition, wx.DefaultSize, 0) - self.temporary_root_checkBox.SetToolTip(u"This option when enabled will not flash patched boot\nInstead it will flash unpatched boot.img, but boot to Live Patched boot\nHandy to test if magisk will cause a bootloop.\n\nPlease be aware that factory image will be flashed, and if you reboot\nthe device will be unrooted.\nIf you want to make this permanent, just flash the patched boot.img") + self.temporary_root_checkBox.SetToolTip(u"This option when enabled will not flash patched boot\nInstead it will flash unpatched boot.img, but boot to Live Patched boot\nHandy to test if magisk will cause a bootloop.\n\nPlease be aware that this temporary root will not survive a subsequent reboot.\nIf you want to make this permanent, just Flash Boot the patched boot image.") self.no_reboot_checkBox = wx.CheckBox(panel, wx.ID_ANY, u"No reboot", wx.DefaultPosition, wx.DefaultSize, 0) self.no_reboot_checkBox.SetToolTip(u"Do not reboot after flashing\nThis is useful if you want to perform other actions before reboot.") self.advanced_options_sizer = wx.BoxSizer(wx.HORIZONTAL) @@ -2500,7 +2620,7 @@ def _on_clear(event): (self.custom_rom_checkbox, 0, wx.ALIGN_CENTER_VERTICAL, 5), (custom_rom_sizer, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL), (label_v_sizer, 1, wx.EXPAND), (list_sizer, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL), # (wx.StaticText(panel, label="")), (wx.StaticText(panel, label="")), - (mode_label, 0, wx.ALIGN_CENTER_VERTICAL, 5), (mode_sizer, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL), + (mode_label, 0, wx.ALIGN_CENTER_VERTICAL, 5), (self.mode_sizer, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL), (custom_advanced_options_sizer, 0, wx.ALIGN_CENTER_VERTICAL, 5), (custom_flash_sizer, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL), self.advanced_options_label, self.advanced_options_sizer, (wx.StaticText(panel, label="")), (self.flash_button, 1, wx.EXPAND), diff --git a/README.md b/README.md index 254f845..38fd9ad 100644 --- a/README.md +++ b/README.md @@ -283,9 +283,11 @@ Select the appropriate flash options. This program could not have been possible without their easy to follow guides. I strongly encourage all beginners to follow those guides rather than use this program, it is important to understand the basic steps involved before diving into one click tools or advanced tasks. - Marcel Stör's [nodemcu-pyflasher](https://github.com/marcelstoer/nodemcu-pyflasher) source code which jump started my introduction to [wxPython](https://www.wxpython.org/) and eventually this program. +- [wxPython Team](https://wxpython.org/) for their corss-platform GUI toolkit for Python. - [JackMcKew](https://github.com/JackMcKew) for pyinstaller Github Actions. - Endless counts of [xda](https://forum.xda-developers.com/) members and their posts that tirelessly answer questions and share tools. Too many to enumerate. -- Artwork / graphics / icons, designed and supplied by: [[ryder203]](https://www.t-ryder.de/), [[t-ryder]](https://forum.xda-developers.com/m/t-ryder.3705546/) based on [material-design-icons](https://github.com/google/material-design-icons/blob/master/LICENSE). +- Artwork / graphics / icons, designed and supplied by: [[ryder203]](https://www.t-ryder.de/), [[t-ryder]](https://forum.xda-developers.com/m/t-ryder.3705546/) based on [material-design-icons](https://github.com/google/material-design-icons/blob/master/LICENSE) +- vm03's [payload_dumper](https://github.com/vm03/payload_dumper) source code to extract images from payload.bin files. ## Disclaimer diff --git a/build-on-mac.spec b/build-on-mac.spec index 818585d..8e30f34 100644 --- a/build-on-mac.spec +++ b/build-on-mac.spec @@ -28,6 +28,6 @@ exe = EXE(pyz, icon='images/icon-256.icns') app = BUNDLE(exe, name='PixelFlasher.app', - version='5.1.0.2', + version='5.2.0.0', icon='./images/icon-256.icns', bundle_identifier='com.badabing.pixelflasher') diff --git a/build.sh b/build.sh index 183e3b6..19c483d 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash rm -rf build dist -VERSION=5.1.0.2 +VERSION=5.2.0.0 NAME="PixelFlasher" DIST_NAME="PixelFlasher" diff --git a/constants.py b/constants.py index 90f5fed..f6632f3 100644 --- a/constants.py +++ b/constants.py @@ -2,7 +2,7 @@ APPNAME = 'PixelFlasher' CONFIG_FILE_NAME = 'PixelFlasher.json' -VERSION = '5.1.0.2' +VERSION = '5.2.0.0' SDKVERSION = '33.0.3' WIDTH = 1400 HEIGHT = 1040 diff --git a/modules.py b/modules.py index 33c94a9..a69847d 100644 --- a/modules.py +++ b/modules.py @@ -7,6 +7,7 @@ import shutil import sqlite3 as sl import sys +import tempfile import time from datetime import datetime from urllib.parse import urlparse @@ -19,6 +20,7 @@ from file_editor import FileEditor from magisk_downloads import MagiskDownloads from message_box_ex import MessageBoxEx +from payload_dumper import extract_payload from phone import get_connected_devices from runtime import * @@ -221,20 +223,13 @@ def populate_boot_list(self): # disable buttons self.config.boot_id = None self.config.selected_boot_md5 = None - self.paste_boot.Enable(False) if self.list.ItemCount == 0 : if self.config.firmware_path: print("\nPlease Process the firmware!") else: print("\nPlease select a boot image!") - self.patch_boot_button.Enable(False) self.process_firmware.SetFocus() # we need to do this, otherwise the focus goes on the next control, which is a radio button, and undesired. - self.delete_boot_button.Enable(False) - self.boot_folder_button.Enable(False) - self.firmware_folder_button.Enable(False) - self.live_boot_button.Enable(False) - self.flash_boot_button.Enable(False) # ============================================================================ @@ -242,6 +237,7 @@ def populate_boot_list(self): # ============================================================================ def identify_sdk_version(self): sdk_version = None + set_sdk_state(False) # Let's grab the adb version with contextlib.suppress(Exception): if get_adb(): @@ -262,11 +258,8 @@ def identify_sdk_version(self): puml(f"#red:Selected Platform Tools;\nnote left: {self.config.platform_tools_path}\nnote right:ERROR: Detected older Android Platform Tools version {sdk_version}\n") if result == wx.ID_YES: print(f"{datetime.now():%Y-%m-%d %H:%M:%S} User accepted older version {sdk_version} of Android platform tools.") - self.scan_button.Enable(True) - self.wifi_adb.Enable(True) - self.device_choice.Enable(True) + set_sdk_state(True) puml("#red:User wanted to proceed regardless;\n") - return else: print("Older Android platform tools is not accepted. For your protection, disabling device selection.") print("Please update Android SDK.\n") @@ -293,20 +286,18 @@ def identify_sdk_version(self): # result = dlg.ShowModal() # break else: - self.scan_button.Enable(True) - self.wifi_adb.Enable(True) - self.device_choice.Enable(True) - return + set_sdk_state(True) + self.update_widget_states() + if get_sdk_state(): + return + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Android Platform Tools version is not available or is too old.") print(" For your protection, disabling device selection.") print(" Please select valid Android SDK.\n") puml("#pink:For your protection, disabled device selection;\n") - self.scan_button.Enable(False) - self.wifi_adb.Enable(False) self.config.device = None self.device_choice.SetItems(['']) self.device_choice.Select(-1) - self.device_choice.Enable(False) return -1 @@ -452,7 +443,17 @@ def select_firmware(self): else: try: set_firmware_model(firmware[0]) - set_firmware_id(f"{firmware[0]}-{firmware[1]}") + if firmware[1] == 'ota': + set_firmware_id(f"{firmware[0]}-{firmware[1]}-{firmware[2]}") + set_ota(True) + self.enable_disable_radio_button('OTA', True, selected=True, just_select=True) + self.config.flash_mode = 'OTA' + else: + set_firmware_id(f"{firmware[0]}-{firmware[1]}") + if self.config.flash_mode == 'OTA': + self.config.flash_mode = 'dryRun' + self.enable_disable_radio_button('dryRun', True, selected=True, just_select=True) + set_ota(False) except Exception as e: set_firmware_model(None) set_firmware_id(filename) @@ -461,6 +462,7 @@ def select_firmware(self): else: self.flash_button.Disable() populate_boot_list(self) + self.update_widget_states() return firmware_hash else: print(f"{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: The selected file {firmware} is not a valid archive file.") @@ -490,9 +492,10 @@ def process_file(self, file_type): start_1 = time.time() checksum = '' + is_payload_bin = False + factory_images = os.path.join(config_path, 'factory_images') if file_type == 'firmware': file_to_process = self.config.firmware_path - factory_images = os.path.join(config_path, 'factory_images') package_sig = get_firmware_id() package_dir_full = os.path.join(factory_images, package_sig) found_flash_all_bat = check_archive_contains_file(archive_file_path=file_to_process, file_to_check="flash-all.bat", nested=False) @@ -515,23 +518,29 @@ def process_file(self, file_type): print(f"Detected Non Pixel firmware, with: {found_boot_img} {found_init_boot_img}") image_file_path = file_to_process elif check_zip_contains_file(file_to_process, "payload.bin"): - # TODO - print("Detected Unsupported firmware, with payload.bin, perhaps in a future version it could be supported.") - return + is_payload_bin = True + if get_firmware_hash_validity() and get_ota(): + print("Detected OTA file, please select a firmware file") + else: + print("Detected a firmware, with payload.bin") else: print("Detected Unsupported firmware file.") print("Aborting ...") return else: file_to_process = self.config.custom_rom_path - found_boot_img = check_zip_contains_file(file_to_process, "boot.img", False) - found_init_boot_img = check_zip_contains_file(file_to_process, "init_boot.img", False) + found_boot_img = check_archive_contains_file(archive_file_path=file_to_process, file_to_check="boot.img", nested=False) + found_init_boot_img = check_archive_contains_file(archive_file_path=file_to_process, file_to_check="init_boot.img", nested=False) set_rom_has_init_boot(False) if found_init_boot_img: set_rom_has_init_boot(True) + elif check_zip_contains_file(file_to_process, "payload.bin"): + print("Detected a ROM, with payload.bin") + is_payload_bin = True package_sig = get_custom_rom_id() + package_dir_full = os.path.join(factory_images, package_sig) image_file_path = file_to_process - puml(f"note right:{image_file_path}\n") + puml(f"note right:{image_file_path}\n") # see if we have a record for the firmware/rom being processed cursor.execute(f"SELECT ID, boot_hash FROM PACKAGE WHERE package_sig = '{package_sig}' AND file_path = '{file_to_process}'") @@ -547,42 +556,75 @@ def process_file(self, file_type): # delete all files in tmp folder to make sure we're dealing with new files only. delete_all(tmp_dir_full) - if not os.path.exists(image_file_path): - print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: The firmware file did not have the expected structure / contents.") - if file_type == 'firmware': - print(f"Please check {self.config.firmware_path} to make sure it is a valid factory image file.") - puml("#red:The selected firmware is not valid;\n") - print("Aborting ...\n") - return + if is_payload_bin: + # extract the payload.bin into a temporary directory + temp_dir = tempfile.TemporaryDirectory() + temp_dir_path = temp_dir.name + print(f"Extracting payload.bin from {file_to_process} ...") + puml(":Extract payload.bin;\n") + theCmd = f"\"{path_to_7z}\" x -bd -y -o\"{temp_dir_path}\" \"{file_to_process}\" payload.bin" + debug(f"{theCmd}") + res = run_shell(theCmd) + # expect ret 0 + if res.returncode != 0: + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Could not extract payload.bin.") + print(res.stderr) + puml("#red:ERROR: Could not extract payload.bin;\n") + print("Aborting ...\n") + return + # extract boot.img, init_boot.img, vbmeta.img from payload.bin + payload_file_path = os.path.join(temp_dir_path, "payload.bin") + if not os.path.exists(package_dir_full): + os.makedirs(package_dir_full, exist_ok=True) + extract_payload(payload_file_path, out=package_dir_full, diff=False, old='old', images='boot,vbmeta,init_boot') + if os.path.exists(os.path.join(package_dir_full, 'boot.img')): + boot_img_file = os.path.join(package_dir_full, 'boot.img') + shutil.copy(boot_img_file, os.path.join(tmp_dir_full, 'boot.img'), follow_symlinks=True) + boot_file_name = 'boot.img' + if os.path.exists(os.path.join(package_dir_full, 'init_boot.img')): + boot_img_file = os.path.join(package_dir_full, 'init_boot.img') + shutil.copy(boot_img_file, os.path.join(tmp_dir_full, 'init_boot.img'), follow_symlinks=True) + boot_file_name = 'init_boot.img' + found_init_boot_img = 'True' # This is intentionally a string, all we care is for it to not evalute to False + else: + if not os.path.exists(image_file_path): + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: The firmware file did not have the expected structure / contents.") + if file_type == 'firmware': + print(f"Please check {self.config.firmware_path} to make sure it is a valid factory image file.") + puml("#red:The selected firmware is not valid;\n") + print("Aborting ...\n") + return - files_to_extract = '' - if found_boot_img: - boot_file_name = 'boot.img' - files_to_extract += 'boot.img ' - if found_init_boot_img: - boot_file_name = 'init_boot.img' - files_to_extract += 'init_boot.img ' - files_to_extract = files_to_extract.strip() - - if not files_to_extract: - print(f"Nothing for extract from {file_type}") - print("Aborting ...") - puml("#red:Nothing for extract from {file_type};\n") - return + files_to_extract = '' + if found_boot_img: + boot_file_name = 'boot.img' + files_to_extract += 'boot.img ' + if found_init_boot_img: + boot_file_name = 'init_boot.img' + files_to_extract += 'init_boot.img ' + files_to_extract = files_to_extract.strip() + + if not files_to_extract: + print(f"Nothing for extract from {file_type}") + print("Aborting ...") + puml("#red:Nothing for extract from {file_type};\n") + return + + print(f"Extracting {boot_file_name} from {image_file_path} ...") + puml(f":Extract {boot_file_name};\n") + theCmd = f"\"{path_to_7z}\" x -bd -y -o\"{tmp_dir_full}\" \"{image_file_path}\" {files_to_extract}" + debug(f"{theCmd}") + res = run_shell(theCmd) + # expect ret 0 + if res.returncode != 0: + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Could not extract {boot_file_name}.") + print(res.stderr) + puml(f"#red:ERROR: Could not extract {boot_file_name};\n") + print("Aborting ...\n") + return - print(f"Extracting {boot_file_name} from {image_file_path} ...") - puml(f":Extract {boot_file_name};\n") - theCmd = f"\"{path_to_7z}\" x -bd -y -o\"{tmp_dir_full}\" \"{image_file_path}\" {files_to_extract}" - debug(f"{theCmd}") - res = run_shell(theCmd) - # expect ret 0 - if res.returncode != 0: - print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Could not extract {boot_file_name}.") - print(res.stderr) - puml(f"#red:ERROR: Could not extract {boot_file_name};\n") - print("Aborting ...\n") - return # sometimes the return code is 0 but no file to extract, handle that case. + # also handle the case of extraction from payload.bin boot_img_file = os.path.join(tmp_dir_full, boot_file_name) if not os.path.exists(boot_img_file): print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Could not extract {boot_file_name}, ") @@ -604,7 +646,7 @@ def process_file(self, file_type): os.makedirs(cached_boot_img_dir_full, exist_ok=True) if not os.path.exists(cached_boot_img_path): print(f"Cached copy of {boot_file_name} with sha1: {checksum} is not found.") - print(f"Copying {image_file_path} to {cached_boot_img_dir_full}") + print(f"Copying {boot_img_file} to {cached_boot_img_dir_full}") shutil.copy(boot_img_file, cached_boot_img_dir_full, follow_symlinks=True) if found_init_boot_img: # we need to copy boot.img for Pixel 7, 7P, 7a so that we can do live boot. @@ -2229,32 +2271,40 @@ def flash_phone(self): # if advanced options is set, and we have flash options ... fastboot_options = '' fastboot_options2 = '' + sideload_options = '' if self.config.advanced_options: if self.config.flash_both_slots: fastboot_options += '--slot all ' if self.config.disable_verity: fastboot_options += '--disable-verity ' fastboot_options2 += '--disable-verity ' + sideload_options += '--disable-verity ' if self.config.disable_verification: fastboot_options += '--disable-verification ' fastboot_options2 += '--disable-verification ' + sideload_options += '--disable-verification ' if self.config.fastboot_verbose: fastboot_options += '--verbose ' fastboot_options2 += '--verbose ' + sideload_options += '--verbose ' if self.config.fastboot_force: fastboot_options2 += '--force ' - message = f"Custom Flash Options: {self.config.advanced_options}\n" + if self.config.flash_mode == 'OTA': + fastboot_options = sideload_options + message = f"Custom Flash Options: {self.config.advanced_options}\n" if self.config.flash_mode == 'customFlash' and image_mode == 'SIDELOAD': - message = " ATTENTION! Flash Options Don\'t apply to Sideloading.\n" + message += " ATTENTION! Flash Options Don\'t apply to Sideloading. (Except: No Reboot)\n" else: - message = f"Custom Flash Options: {self.config.advanced_options}\n" + message = f"Custom Flash Options: {self.config.advanced_options}\n" message += f"Disable Verity: {self.config.disable_verity}\n" message += f"Disable Verification: {self.config.disable_verification}\n" - message += f"Flash Both Slots: {self.config.flash_both_slots}\n" - message += f"Force: {self.config.fastboot_force}\n" + if self.config.flash_mode != 'OTA': + message += f"Flash Both Slots: {self.config.flash_both_slots}\n" + message += f"Force: {self.config.fastboot_force}\n" message += f"Verbose Fastboot: {self.config.fastboot_verbose}\n" message += f"Temporary Root: {self.config.temporary_root}\n" - message += f"Flash To Inactive Slot: {self.config.flash_to_inactive_slot}\n" + if self.config.flash_mode != 'OTA': + message += f"Flash To Inactive Slot: {self.config.flash_to_inactive_slot}\n" if sys.platform == "win32": flash_pf_file = os.path.join(package_dir_full, "flash-pf.bat") @@ -2330,6 +2380,7 @@ def flash_phone(self): # do the standard flash mode #--------------------------- else: + add_echo ='' # check for boot file if not os.path.exists(boot.boot_path): print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: boot file: {boot.boot_path} is not found.") @@ -2349,8 +2400,8 @@ def flash_phone(self): puml("#red:boot file is not found;\n}\n") return - # check for rom file - if self.config.custom_rom and self.config.advanced_options: + # check for rom file (if not OTA) + if self.config.custom_rom and self.config.advanced_options and self.config.flash_mode != 'OTA': if not os.path.exists(self.config.custom_rom_path): print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: ROM file: {self.config.custom_rom_path} is not found.") print("Aborting ...\n") @@ -2401,23 +2452,46 @@ def flash_phone(self): puml("#pink:User Pressed Cancel to abort;\n}\n") return - # Check if the patch file is made by Magsik Zygote64_32 - if "zygote64_32" in boot.magisk_version.lower(): - # Check we have Magisk Zygote64_32 rooted system already - if device.rooted: - # Warn if current firmware is the same as the one being flashed and wipe is not selected. - if device.build.lower() in package_sig and not self.config.flash_mode == 'Wipe': + # ---------- + # If OTA + # ---------- + if self.config.flash_mode == 'OTA': + if sys.platform == "win32" and cp: + data = f"chcp {cp}\n" + data += f":: This is a generated file by PixelFlasher v{VERSION}\n" + data += f":: cd {package_dir_full}\n" + data += f":: pf_boot.img: {boot.boot_path}\n" + data += f":: Android Platform Tools Version: {get_sdk_version()}\n\n" + sleep_line = "ping -n 5 127.0.0.1 >nul\n" + else: + data = f"# This is a generated file by PixelFlasher v{VERSION}\n" + data += f"# cd {package_dir_full}\n" + data += f"# pf_boot.img: {boot.boot_path}\n" + data += f"# Android Platform Tools Version: {get_sdk_version()}\n\n" + sleep_line = "sleep 5\n" + data += f"\"{get_adb()}\" -s {device.id} sideload \"{self.config.firmware_path}\"\n" + + # ---------- + # If not OTA + # ---------- + else: + # Check if the patch file is made by Magsik Zygote64_32 + if "zygote64_32" in boot.magisk_version.lower(): + # Check we have Magisk Zygote64_32 rooted system already + if device.rooted: + # Warn if current firmware is the same as the one being flashed and wipe is not selected. + if device.build.lower() in package_sig and not self.config.flash_mode == 'Wipe': + warn = True + elif not self.config.flash_mode == 'Wipe': warn = True - elif not self.config.flash_mode == 'Wipe': - warn = True - if warn: - print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} WARNING: Wipe is required.") - print("Aborting ...\n") - puml("#red:Error WARNING, wipe is required;\n}\n") - # dialog to accept / abort - title = "Wipe is required." - buttons_text = ["Continue Flashing (I know what I'm doing)", "Cancel (Recommended)"] - message = ''' + if warn: + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} WARNING: Wipe is required.") + print("Aborting ...\n") + puml("#red:Error WARNING, wipe is required;\n}\n") + # dialog to accept / abort + title = "Wipe is required." + buttons_text = ["Continue Flashing (I know what I'm doing)", "Cancel (Recommended)"] + message = ''' The selected patch is created by [Magisk Zygote64_32](https://github.com/Namelesswonder/magisk-files).
**PixelFlasher** detected a condition where a wipe is necessary to avoid bootloops.
@@ -2430,124 +2504,137 @@ def flash_phone(self): If you insist to continue, you can press the **Continue** button, otherwise please press the **Cancel** button.
''' - clean_message = message.replace("
", "") - print(f"\n*** Dialog ***\n{clean_message}\n______________\n") - puml(":Dialog;\n", True) - puml(f"note right\n{clean_message}end note\n") - dlg = MessageBoxEx(parent=self, title=title, message=message, button_texts=buttons_text, default_button=2, is_md=True, size=[700,400]) - dlg.CentreOnParent(wx.BOTH) - result = dlg.ShowModal() - dlg.Destroy() - print(f"{datetime.now():%Y-%m-%d %H:%M:%S} User Pressed {buttons_text[result -1]}") - puml(f":User Pressed {buttons_text[result - 1]};\n") - if result == 2: - puml("}\n") - print("Aborting ...\n") - return + clean_message = message.replace("
", "") + print(f"\n*** Dialog ***\n{clean_message}\n______________\n") + puml(":Dialog;\n", True) + puml(f"note right\n{clean_message}end note\n") + dlg = MessageBoxEx(parent=self, title=title, message=message, button_texts=buttons_text, default_button=2, is_md=True, size=[700,400]) + dlg.CentreOnParent(wx.BOTH) + result = dlg.ShowModal() + dlg.Destroy() + print(f"{datetime.now():%Y-%m-%d %H:%M:%S} User Pressed {buttons_text[result -1]}") + puml(f":User Pressed {buttons_text[result - 1]};\n") + if result == 2: + puml("}\n") + print("Aborting ...\n") + return - # Process flash_all files - flash_all_win32 = process_flash_all_file(os.path.join(package_dir_full, "flash-all.bat")) - if (flash_all_win32 == 'ERROR'): - print("Aborting ...\n") - puml("#red:Error processing flash_all.bat file;\n}\n") - return - flash_all_linux = process_flash_all_file(os.path.join(package_dir_full, "flash-all.sh")) - if (flash_all_linux == 'ERROR'): - print("Aborting ...\n") - puml("#red:Error processing flash_all.sh file;\n}\n") - return - s1 = '' - s2 = '' - for f in flash_all_win32: - if f.sync_line: - s1 += f"{f.sync_line}\n" - for f in flash_all_linux: - if f.sync_line: - s2 += f"{f.sync_line}\n" - # check to see if we have consistent linux / windows files - if s1 != s2: - print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Found inconsistency between flash-all.bat and flash-all.sh files.") - puml("#yellow:Found an inconsistency between bat and sh files;\n") - debug(f"bat file:\n{s1}") - debug(f"\nsh file\n{s2}\n") - - if sys.platform == "win32" and cp: - data = f"chcp {cp}\n" - else: - data = '' - add_echo ='' - if self.config.flash_mode == 'dryRun': - add_echo = 'echo ' + # Process flash_all files + flash_all_win32 = process_flash_all_file(os.path.join(package_dir_full, "flash-all.bat")) + if (flash_all_win32 == 'ERROR'): + print("Aborting ...\n") + puml("#red:Error processing flash_all.bat file;\n}\n") + return + flash_all_linux = process_flash_all_file(os.path.join(package_dir_full, "flash-all.sh")) + if (flash_all_linux == 'ERROR'): + print("Aborting ...\n") + puml("#red:Error processing flash_all.sh file;\n}\n") + return + s1 = '' + s2 = '' + for f in flash_all_win32: + if f.sync_line: + s1 += f"{f.sync_line}\n" + for f in flash_all_linux: + if f.sync_line: + s2 += f"{f.sync_line}\n" + # check to see if we have consistent linux / windows files + if s1 != s2: + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Found inconsistency between flash-all.bat and flash-all.sh files.") + puml("#yellow:Found an inconsistency between bat and sh files;\n") + debug(f"bat file:\n{s1}") + debug(f"\nsh file\n{s2}\n") + + if sys.platform == "win32" and cp: + data = f"chcp {cp}\n" + else: + data = '' + if self.config.flash_mode == 'dryRun': + add_echo = 'echo ' - if sys.platform == "win32": - flash_all_file = flash_all_win32 - else: - flash_all_file = flash_all_linux - for f in flash_all_file: - if f.type == 'init': - data += f"{f.full_line}\n" - if sys.platform == "win32": - data += f":: This is a generated file by PixelFlasher v{VERSION}\n" - data += f":: cd {package_dir_full}\n" - data += f":: pf_boot.img: {boot.boot_path}\n" - data += f":: Android Platform Tools Version: {get_sdk_version()}\n\n" - else: - data += f"# This is a generated file by PixelFlasher v{VERSION}\n" - data += f"# cd {package_dir_full}\n" - data += f"# pf_boot.img: {boot.boot_path}\n" - data += f"# Android Platform Tools Version: {get_sdk_version()}\n\n" - if self.config.flash_to_inactive_slot: - data += "echo Switching active slot to the other ...\n" - data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} --set-active=other\n" - continue - if f.type in ['sleep']: - sleep_line = f"{f.full_line}\n" - data += f"{f.full_line}\n" - continue - if f.type in ['path']: - data += f"{f.full_line}\n" - continue - if f.action == 'reboot-bootloader': - data += f"\"{get_fastboot()}\" -s {device.id} {f.action} {f.arg1} {f.arg2}\n" - continue - if f.action == 'flash': - data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} {fastboot_options} {f.action} {f.arg1} {f.arg2}\n" - continue - if f.action == '-w update': - action = '--skip-reboot update' - arg1 = f.arg1 - if self.config.flash_mode == 'wipeData': - action = '--skip-reboot -w update' - if self.config.custom_rom and self.config.advanced_options: - arg1 = f"\"{get_custom_rom_file()}\"" - data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} {fastboot_options2} {action} {arg1}\n" - # flash on each slot separately - # https://forum.xda-developers.com/t/psa-do-not-try-to-boot-into-the-old-slot-after-updating-only-one-slot-to-android-13-unlocking-the-pixel-6-pro-bootloader-central-repository.4352027/post-87309913 - if self.config.advanced_options and self.config.flash_both_slots: - data += "echo Switching active slot to the other ...\n" - data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} --set-active=other\n" - data += "echo rebooting to bootloader ...\n" - data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} reboot bootloader\n" - data += "echo Sleeping 5-10 seconds ...\n" - data += sleep_line - data += sleep_line + if sys.platform == "win32": + flash_all_file = flash_all_win32 + else: + flash_all_file = flash_all_linux + for f in flash_all_file: + if f.type == 'init': + data += f"{f.full_line}\n" + if sys.platform == "win32": + data += f":: This is a generated file by PixelFlasher v{VERSION}\n" + data += f":: cd {package_dir_full}\n" + data += f":: pf_boot.img: {boot.boot_path}\n" + data += f":: Android Platform Tools Version: {get_sdk_version()}\n\n" + else: + data += f"# This is a generated file by PixelFlasher v{VERSION}\n" + data += f"# cd {package_dir_full}\n" + data += f"# pf_boot.img: {boot.boot_path}\n" + data += f"# Android Platform Tools Version: {get_sdk_version()}\n\n" + if self.config.flash_to_inactive_slot: + data += "echo Switching active slot to the other ...\n" + data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} --set-active=other\n" + continue + if f.type in ['sleep']: + sleep_line = f"{f.full_line}\n" + data += f"{f.full_line}\n" + continue + if f.type in ['path']: + data += f"{f.full_line}\n" + continue + if f.action == 'reboot-bootloader': + data += f"\"{get_fastboot()}\" -s {device.id} {f.action} {f.arg1} {f.arg2}\n" + continue + if f.action == 'flash': + data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} {fastboot_options} {f.action} {f.arg1} {f.arg2}\n" + continue + if f.action == '-w update': + action = '--skip-reboot update' + arg1 = f.arg1 + if self.config.flash_mode == 'wipeData': + action = '--skip-reboot -w update' + if self.config.custom_rom and self.config.advanced_options: + arg1 = f"\"{get_custom_rom_file()}\"" data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} {fastboot_options2} {action} {arg1}\n" - # echo add testing of fastbootd mode if we are in dry run mode and sdk < 34 - sdk_version_components = get_sdk_version().split('.') - sdk_major_version = int(sdk_version_components[0]) - if self.config.flash_mode == 'dryRun' and sdk_major_version < 34: - data += "echo This is a test for fastbootd mode ...\n" - data += "echo This process will wait for fastbootd indefinitly until it responds ...\n" - data += "echo WARNING! if your device does not boot to fastbootd PixelFlasher will hang and you'd have to kill it.. ...\n" - data += "echo rebooting to fastbootd ...\n" - data += f"\"{get_fastboot()}\" -s {device.id} reboot fastboot\n" - data += "echo It looks like fastbootd worked.\n" + # flash on each slot separately + # https://forum.xda-developers.com/t/psa-do-not-try-to-boot-into-the-old-slot-after-updating-only-one-slot-to-android-13-unlocking-the-pixel-6-pro-bootloader-central-repository.4352027/post-87309913 + if self.config.advanced_options and self.config.flash_both_slots: + data += "echo Switching active slot to the other ...\n" + data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} --set-active=other\n" + data += "echo rebooting to bootloader ...\n" + data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} reboot bootloader\n" + data += "echo Sleeping 5-10 seconds ...\n" + data += sleep_line + data += sleep_line + data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} {fastboot_options2} {action} {arg1}\n" + # echo add testing of fastbootd mode if we are in dry run mode and sdk < 34 + sdk_version_components = get_sdk_version().split('.') + sdk_major_version = int(sdk_version_components[0]) + if self.config.flash_mode == 'dryRun' and sdk_major_version < 34: + data += "echo This is a test for fastbootd mode ...\n" + data += "echo This process will wait for fastbootd indefinitly until it responds ...\n" + data += "echo WARNING! if your device does not boot to fastbootd PixelFlasher will hang and you'd have to kill it.. ...\n" + data += "echo rebooting to fastbootd ...\n" + data += f"\"{get_fastboot()}\" -s {device.id} reboot fastboot\n" + data += "echo It looks like fastbootd worked.\n" + + # --------------- + # OTA and Factory + # --------------- # add the boot.img flashing data += "echo rebooting to bootloader ...\n" - data += f"\"{get_fastboot()}\" -s {device.id} reboot bootloader\n" + if self.config.flash_mode == 'OTA': + data += f"\"{get_adb()}\" -s {device.id} reboot bootloader\n" + else: + data += f"\"{get_fastboot()}\" -s {device.id} reboot bootloader\n" data += "echo Sleeping 5-10 seconds ...\n" data += sleep_line data += sleep_line + + # flash vbmeta if disabling verity / verification + if self.config.flash_mode == 'OTA'and (self.config.disable_verity or self.config.disable_verification): + data += "echo flashing vbmeta ...\n" + data += f"\"{get_fastboot()}\" -s {device.id} {fastboot_options} flash vbmeta vbmeta.img\n" + + # are we doing temporary root? if self.config.temporary_root and boot.is_patched: data += "echo Live booting to pf_boot (temporary root) ...\n" data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} {fastboot_options} boot pf_boot.img\n" @@ -2557,7 +2644,8 @@ def flash_phone(self): data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} {fastboot_options} flash init_boot pf_boot.img\n" else: data += f"{add_echo}\"{get_fastboot()}\" -s {device.id} {fastboot_options} flash boot pf_boot.img\n" - # only reboot if no_reboot is not selected. + + # only reboot if no_reboot is not selected if not self.config.no_reboot: data += "echo rebooting to system ...\n" data += f"\"{get_fastboot()}\" -s {device.id} reboot" @@ -2607,10 +2695,15 @@ def flash_phone(self): puml(f"note right\n{message}end note\n") puml(":Script;\n") puml(f"note right\nFlash Script\n====\n{data}\nend note\n") - dlg = MessageBoxEx(parent=None, title=title, message=message, button_texts=["OK", "Edit script before continuing", "Cancel"], default_button=1) - dlg.CentreOnParent(wx.BOTH) - result = dlg.ShowModal() - dlg.Destroy() + try: + dlg = MessageBoxEx(parent=None, title=title, message=message, button_texts=["OK", "Edit script before continuing", "Cancel"], default_button=1) + dlg.CentreOnParent(wx.BOTH) + result = dlg.ShowModal() + dlg.Destroy() + except Exception as e: + print(f"\n{datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error.") + print(e) + if result == 1: # OK print(f"{datetime.now():%Y-%m-%d %H:%M:%S} User Pressed Ok.") puml(":User Pressed OK;\n") @@ -2651,8 +2744,8 @@ def flash_phone(self): print(f"Android Platform Tools Version: {get_sdk_version()}") puml(f"note right\nPixelFlasher {VERSION}\nAndroid Platform Tools Version: {get_sdk_version()}\nend note\n") - # If we're doing Sideload flashing - if self.config.advanced_options and self.config.flash_mode == 'customFlash' and image_mode == 'SIDELOAD': + # If we're doing Sideload image flashing or OTA + if self.config.flash_mode == 'OTA' or (self.config.advanced_options and self.config.flash_mode == 'customFlash' and image_mode == 'SIDELOAD'): device.reboot_sideload() print("Waiting 20 seconds ...") time.sleep(20) @@ -2664,6 +2757,9 @@ def flash_phone(self): theCmd = f"\"{theCmd}\"" debug(theCmd) run_shell2(theCmd) + if self.config.flash_mode != 'OTA' and not self.config.no_reboot: + time.sleep(5) + device.reboot_system() print(f"{datetime.now():%Y-%m-%d %H:%M:%S} Done!") endFlash = time.time() print(f"Flashing elapsed time: {math.ceil(endFlash - startFlash)} seconds") @@ -2672,6 +2768,12 @@ def flash_phone(self): puml("#cee7ee:End Flashing;\n", True) puml(f"note right:Flash time: {math.ceil(endFlash - startFlash)} seconds;\n") puml("}\n") + # clear the selected device option + set_phone(None) + self.device_label.Label = "ADB Connected Devices" + self.config.device = None + self.device_choice.SetItems(['']) + self.device_choice.Select(-1) return if device.mode == 'adb': diff --git a/payload_dumper.py b/payload_dumper.py new file mode 100644 index 0000000..444eaa1 --- /dev/null +++ b/payload_dumper.py @@ -0,0 +1,148 @@ +import struct +import hashlib +import bz2 +import sys +import bsdiff4 +import io +import os +try: + import lzma +except ImportError: + from backports import lzma + +import update_metadata_pb2 as um + + +def extract_payload(payload_file_path, out='output', diff=False, old='old', images=''): + def u32(x): + return struct.unpack('>I', x)[0] + + def u64(x): + return struct.unpack('>Q', x)[0] + + def verify_contiguous(exts): + blocks = 0 + + for ext in exts: + if ext.start_block != blocks: + return False + + blocks += ext.num_blocks + + return True + + def data_for_op(op, out_file, old_file): + payload_file.seek(data_offset + op.data_offset) + data = payload_file.read(op.data_length) + + # assert hashlib.sha256(data).digest() == op.data_sha256_hash, 'operation data hash mismatch' + + if op.type == op.REPLACE_XZ: + dec = lzma.LZMADecompressor() + data = dec.decompress(data) + out_file.seek(op.dst_extents[0].start_block * block_size) + out_file.write(data) + elif op.type == op.REPLACE_BZ: + dec = bz2.BZ2Decompressor() + data = dec.decompress(data) + out_file.seek(op.dst_extents[0].start_block * block_size) + out_file.write(data) + elif op.type == op.REPLACE: + out_file.seek(op.dst_extents[0].start_block * block_size) + out_file.write(data) + elif op.type == op.SOURCE_COPY: + if not diff: + print("SOURCE_COPY supported only for differential OTA") + sys.exit(-2) + out_file.seek(op.dst_extents[0].start_block * block_size) + for ext in op.src_extents: + old_file.seek(ext.start_block * block_size) + data = old_file.read(ext.num_blocks * block_size) + out_file.write(data) + elif op.type == op.SOURCE_BSDIFF: + if not diff: + print("SOURCE_BSDIFF supported only for differential OTA") + sys.exit(-3) + out_file.seek(op.dst_extents[0].start_block * block_size) + tmp_buff = io.BytesIO() + for ext in op.src_extents: + old_file.seek(ext.start_block * block_size) + old_data = old_file.read(ext.num_blocks * block_size) + tmp_buff.write(old_data) + tmp_buff.seek(0) + old_data = tmp_buff.read() + tmp_buff.seek(0) + tmp_buff.write(bsdiff4.patch(old_data, data)) + n = 0 + tmp_buff.seek(0) + for ext in op.dst_extents: + tmp_buff.seek(n * block_size) + n += ext.num_blocks + data = tmp_buff.read(ext.num_blocks * block_size) + out_file.seek(ext.start_block * block_size) + out_file.write(data) + elif op.type == op.ZERO: + for ext in op.dst_extents: + out_file.seek(ext.start_block * block_size) + out_file.write(b'\x00' * ext.num_blocks * block_size) + else: + print("Unsupported type = %d" % op.type) + sys.exit(-1) + + return data + + def dump_part(part): + sys.stdout.write("Processing %s partition" % part.partition_name) + sys.stdout.flush() + + with open('%s/%s.img' % (out, part.partition_name), 'wb') as out_file: + h = hashlib.sha256() + + if diff: + with open('%s/%s.img' % (old, part.partition_name), 'rb') as old_file: + for op in part.operations: + data = data_for_op(op, out_file, old_file) + sys.stdout.write(".") + sys.stdout.flush() + else: + for op in part.operations: + data = data_for_op(op, out_file, None) + sys.stdout.write(".") + sys.stdout.flush() + + print("Done") + + with open(payload_file_path, 'rb') as payload_file: + magic = payload_file.read(4) + assert magic == b'CrAU' + + file_format_version = u64(payload_file.read(8)) + assert file_format_version == 2 + + manifest_size = u64(payload_file.read(8)) + + metadata_signature_size = 0 + + if file_format_version > 1: + metadata_signature_size = u32(payload_file.read(4)) + + manifest = payload_file.read(manifest_size) + metadata_signature = payload_file.read(metadata_signature_size) + + data_offset = payload_file.tell() + + dam = um.DeltaArchiveManifest() + dam.ParseFromString(manifest) + block_size = dam.block_size + + if images == "": + for part in dam.partitions: + dump_part(part) + else: + images_list = images.split(",") + for image in images_list: + partition = [part for part in dam.partitions if part.partition_name == image] + if partition: + dump_part(partition[0]) + else: + sys.stderr.write("Partition %s not found in payload!\n" % image) diff --git a/requirements.txt b/requirements.txt index 9eabb34..9663d9c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ attrdict3>=2.0.2 -wxPython>=4.2.0 PyInstaller>=5.9.0 httplib2>=0.21.0 pyinstaller-versionfile>=2.1.1 @@ -8,4 +7,8 @@ requests>=2.28.1 darkdetect>=0.7.1 markdown>=3.4.1 clipboard>=0.0.4 +wxPython>=4.2.0 +protobuf>=3.19.3, <=3.20.1 +six>=1.16.0 +bsdiff4>=1.1.5 diff --git a/runtime.py b/runtime.py index 47932f7..35f1374 100644 --- a/runtime.py +++ b/runtime.py @@ -72,6 +72,8 @@ env_variables = os.environ.copy() boot_list_columns = 8 boot_column_widths = column_widths = [0] * boot_list_columns +is_ota = False +sdk_is_ok = False # ============================================================================ # Class Boot @@ -577,6 +579,38 @@ def set_recovery_patch_settings(value): recovery_patch = value +# ============================================================================ +# Function get_is_ota +# ============================================================================ +def get_ota(): + global is_ota + return is_ota + + +# ============================================================================ +# Function set_is_ota +# ============================================================================ +def set_ota(value): + global is_ota + is_ota = value + + +# ============================================================================ +# Function get_sdk_state +# ============================================================================ +def get_sdk_state(): + global sdk_is_ok + return sdk_is_ok + + +# ============================================================================ +# Function set_sdk_state +# ============================================================================ +def set_sdk_state(value): + global sdk_is_ok + sdk_is_ok = value + + # ============================================================================ # Function get_use_busybox_shell_settings # ============================================================================ diff --git a/update_metadata_pb2.py b/update_metadata_pb2.py new file mode 100644 index 0000000..927e899 --- /dev/null +++ b/update_metadata_pb2.py @@ -0,0 +1,669 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: update_metadata.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='update_metadata.proto', + package='chromeos_update_engine', + syntax='proto2', + serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"z\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1a*\n\tSignature\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"w\n\tImageInfo\x12\r\n\x05\x62oard\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x15\n\rbuild_channel\x18\x05 \x01(\t\x12\x15\n\rbuild_version\x18\x06 \x01(\t\"\xd3\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\r\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\r\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\x92\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x08\n\x04MOVE\x10\x02\x12\n\n\x06\x42SDIFF\x10\x03\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x0c\n\x08PUFFDIFF\x10\t\"\xa6\x03\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\"\xc4\x05\n\x14\x44\x65ltaArchiveManifest\x12\x44\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12K\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12>\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x39\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x39\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdateB\x02H\x03') +) + + + +_INSTALLOPERATION_TYPE = _descriptor.EnumDescriptor( + name='Type', + full_name='chromeos_update_engine.InstallOperation.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='REPLACE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REPLACE_BZ', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='MOVE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='BSDIFF', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SOURCE_COPY', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SOURCE_BSDIFF', index=5, number=5, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ZERO', index=6, number=6, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='DISCARD', index=7, number=7, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REPLACE_XZ', index=8, number=8, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='PUFFDIFF', index=9, number=9, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=712, + serialized_end=858, +) +_sym_db.RegisterEnumDescriptor(_INSTALLOPERATION_TYPE) + + +_EXTENT = _descriptor.Descriptor( + name='Extent', + full_name='chromeos_update_engine.Extent', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='start_block', full_name='chromeos_update_engine.Extent.start_block', index=0, + number=1, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='num_blocks', full_name='chromeos_update_engine.Extent.num_blocks', index=1, + number=2, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=49, + serialized_end=98, +) + + +_SIGNATURES_SIGNATURE = _descriptor.Descriptor( + name='Signature', + full_name='chromeos_update_engine.Signatures.Signature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='version', full_name='chromeos_update_engine.Signatures.Signature.version', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='data', full_name='chromeos_update_engine.Signatures.Signature.data', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=180, + serialized_end=222, +) + +_SIGNATURES = _descriptor.Descriptor( + name='Signatures', + full_name='chromeos_update_engine.Signatures', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='signatures', full_name='chromeos_update_engine.Signatures.signatures', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_SIGNATURES_SIGNATURE, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=100, + serialized_end=222, +) + + +_PARTITIONINFO = _descriptor.Descriptor( + name='PartitionInfo', + full_name='chromeos_update_engine.PartitionInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='size', full_name='chromeos_update_engine.PartitionInfo.size', index=0, + number=1, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='hash', full_name='chromeos_update_engine.PartitionInfo.hash', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=224, + serialized_end=267, +) + + +_IMAGEINFO = _descriptor.Descriptor( + name='ImageInfo', + full_name='chromeos_update_engine.ImageInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='board', full_name='chromeos_update_engine.ImageInfo.board', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='key', full_name='chromeos_update_engine.ImageInfo.key', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='channel', full_name='chromeos_update_engine.ImageInfo.channel', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='version', full_name='chromeos_update_engine.ImageInfo.version', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='build_channel', full_name='chromeos_update_engine.ImageInfo.build_channel', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='build_version', full_name='chromeos_update_engine.ImageInfo.build_version', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=269, + serialized_end=388, +) + + +_INSTALLOPERATION = _descriptor.Descriptor( + name='InstallOperation', + full_name='chromeos_update_engine.InstallOperation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', full_name='chromeos_update_engine.InstallOperation.type', index=0, + number=1, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='data_offset', full_name='chromeos_update_engine.InstallOperation.data_offset', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='data_length', full_name='chromeos_update_engine.InstallOperation.data_length', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='src_extents', full_name='chromeos_update_engine.InstallOperation.src_extents', index=3, + number=4, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='src_length', full_name='chromeos_update_engine.InstallOperation.src_length', index=4, + number=5, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='dst_extents', full_name='chromeos_update_engine.InstallOperation.dst_extents', index=5, + number=6, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='dst_length', full_name='chromeos_update_engine.InstallOperation.dst_length', index=6, + number=7, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='data_sha256_hash', full_name='chromeos_update_engine.InstallOperation.data_sha256_hash', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='src_sha256_hash', full_name='chromeos_update_engine.InstallOperation.src_sha256_hash', index=8, + number=9, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _INSTALLOPERATION_TYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=391, + serialized_end=858, +) + + +_PARTITIONUPDATE = _descriptor.Descriptor( + name='PartitionUpdate', + full_name='chromeos_update_engine.PartitionUpdate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='partition_name', full_name='chromeos_update_engine.PartitionUpdate.partition_name', index=0, + number=1, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='run_postinstall', full_name='chromeos_update_engine.PartitionUpdate.run_postinstall', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='postinstall_path', full_name='chromeos_update_engine.PartitionUpdate.postinstall_path', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='filesystem_type', full_name='chromeos_update_engine.PartitionUpdate.filesystem_type', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='new_partition_signature', full_name='chromeos_update_engine.PartitionUpdate.new_partition_signature', index=4, + number=5, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='old_partition_info', full_name='chromeos_update_engine.PartitionUpdate.old_partition_info', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='new_partition_info', full_name='chromeos_update_engine.PartitionUpdate.new_partition_info', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='operations', full_name='chromeos_update_engine.PartitionUpdate.operations', index=7, + number=8, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='postinstall_optional', full_name='chromeos_update_engine.PartitionUpdate.postinstall_optional', index=8, + number=9, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=861, + serialized_end=1283, +) + + +_DELTAARCHIVEMANIFEST = _descriptor.Descriptor( + name='DeltaArchiveManifest', + full_name='chromeos_update_engine.DeltaArchiveManifest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='install_operations', full_name='chromeos_update_engine.DeltaArchiveManifest.install_operations', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='kernel_install_operations', full_name='chromeos_update_engine.DeltaArchiveManifest.kernel_install_operations', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='block_size', full_name='chromeos_update_engine.DeltaArchiveManifest.block_size', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=True, default_value=4096, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='signatures_offset', full_name='chromeos_update_engine.DeltaArchiveManifest.signatures_offset', index=3, + number=4, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='signatures_size', full_name='chromeos_update_engine.DeltaArchiveManifest.signatures_size', index=4, + number=5, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='old_kernel_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_kernel_info', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='new_kernel_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_kernel_info', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='old_rootfs_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_rootfs_info', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='new_rootfs_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_rootfs_info', index=8, + number=9, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='old_image_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_image_info', index=9, + number=10, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='new_image_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_image_info', index=10, + number=11, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='minor_version', full_name='chromeos_update_engine.DeltaArchiveManifest.minor_version', index=11, + number=12, type=13, cpp_type=3, label=1, + has_default_value=True, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='partitions', full_name='chromeos_update_engine.DeltaArchiveManifest.partitions', index=12, + number=13, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1286, + serialized_end=1994, +) + +_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES +_SIGNATURES.fields_by_name['signatures'].message_type = _SIGNATURES_SIGNATURE +_INSTALLOPERATION.fields_by_name['type'].enum_type = _INSTALLOPERATION_TYPE +_INSTALLOPERATION.fields_by_name['src_extents'].message_type = _EXTENT +_INSTALLOPERATION.fields_by_name['dst_extents'].message_type = _EXTENT +_INSTALLOPERATION_TYPE.containing_type = _INSTALLOPERATION +_PARTITIONUPDATE.fields_by_name['new_partition_signature'].message_type = _SIGNATURES_SIGNATURE +_PARTITIONUPDATE.fields_by_name['old_partition_info'].message_type = _PARTITIONINFO +_PARTITIONUPDATE.fields_by_name['new_partition_info'].message_type = _PARTITIONINFO +_PARTITIONUPDATE.fields_by_name['operations'].message_type = _INSTALLOPERATION +_DELTAARCHIVEMANIFEST.fields_by_name['install_operations'].message_type = _INSTALLOPERATION +_DELTAARCHIVEMANIFEST.fields_by_name['kernel_install_operations'].message_type = _INSTALLOPERATION +_DELTAARCHIVEMANIFEST.fields_by_name['old_kernel_info'].message_type = _PARTITIONINFO +_DELTAARCHIVEMANIFEST.fields_by_name['new_kernel_info'].message_type = _PARTITIONINFO +_DELTAARCHIVEMANIFEST.fields_by_name['old_rootfs_info'].message_type = _PARTITIONINFO +_DELTAARCHIVEMANIFEST.fields_by_name['new_rootfs_info'].message_type = _PARTITIONINFO +_DELTAARCHIVEMANIFEST.fields_by_name['old_image_info'].message_type = _IMAGEINFO +_DELTAARCHIVEMANIFEST.fields_by_name['new_image_info'].message_type = _IMAGEINFO +_DELTAARCHIVEMANIFEST.fields_by_name['partitions'].message_type = _PARTITIONUPDATE +DESCRIPTOR.message_types_by_name['Extent'] = _EXTENT +DESCRIPTOR.message_types_by_name['Signatures'] = _SIGNATURES +DESCRIPTOR.message_types_by_name['PartitionInfo'] = _PARTITIONINFO +DESCRIPTOR.message_types_by_name['ImageInfo'] = _IMAGEINFO +DESCRIPTOR.message_types_by_name['InstallOperation'] = _INSTALLOPERATION +DESCRIPTOR.message_types_by_name['PartitionUpdate'] = _PARTITIONUPDATE +DESCRIPTOR.message_types_by_name['DeltaArchiveManifest'] = _DELTAARCHIVEMANIFEST +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +Extent = _reflection.GeneratedProtocolMessageType('Extent', (_message.Message,), dict( + DESCRIPTOR = _EXTENT, + __module__ = 'update_metadata_pb2' + # @@protoc_insertion_point(class_scope:chromeos_update_engine.Extent) + )) +_sym_db.RegisterMessage(Extent) + +Signatures = _reflection.GeneratedProtocolMessageType('Signatures', (_message.Message,), dict( + + Signature = _reflection.GeneratedProtocolMessageType('Signature', (_message.Message,), dict( + DESCRIPTOR = _SIGNATURES_SIGNATURE, + __module__ = 'update_metadata_pb2' + # @@protoc_insertion_point(class_scope:chromeos_update_engine.Signatures.Signature) + )) + , + DESCRIPTOR = _SIGNATURES, + __module__ = 'update_metadata_pb2' + # @@protoc_insertion_point(class_scope:chromeos_update_engine.Signatures) + )) +_sym_db.RegisterMessage(Signatures) +_sym_db.RegisterMessage(Signatures.Signature) + +PartitionInfo = _reflection.GeneratedProtocolMessageType('PartitionInfo', (_message.Message,), dict( + DESCRIPTOR = _PARTITIONINFO, + __module__ = 'update_metadata_pb2' + # @@protoc_insertion_point(class_scope:chromeos_update_engine.PartitionInfo) + )) +_sym_db.RegisterMessage(PartitionInfo) + +ImageInfo = _reflection.GeneratedProtocolMessageType('ImageInfo', (_message.Message,), dict( + DESCRIPTOR = _IMAGEINFO, + __module__ = 'update_metadata_pb2' + # @@protoc_insertion_point(class_scope:chromeos_update_engine.ImageInfo) + )) +_sym_db.RegisterMessage(ImageInfo) + +InstallOperation = _reflection.GeneratedProtocolMessageType('InstallOperation', (_message.Message,), dict( + DESCRIPTOR = _INSTALLOPERATION, + __module__ = 'update_metadata_pb2' + # @@protoc_insertion_point(class_scope:chromeos_update_engine.InstallOperation) + )) +_sym_db.RegisterMessage(InstallOperation) + +PartitionUpdate = _reflection.GeneratedProtocolMessageType('PartitionUpdate', (_message.Message,), dict( + DESCRIPTOR = _PARTITIONUPDATE, + __module__ = 'update_metadata_pb2' + # @@protoc_insertion_point(class_scope:chromeos_update_engine.PartitionUpdate) + )) +_sym_db.RegisterMessage(PartitionUpdate) + +DeltaArchiveManifest = _reflection.GeneratedProtocolMessageType('DeltaArchiveManifest', (_message.Message,), dict( + DESCRIPTOR = _DELTAARCHIVEMANIFEST, + __module__ = 'update_metadata_pb2' + # @@protoc_insertion_point(class_scope:chromeos_update_engine.DeltaArchiveManifest) + )) +_sym_db.RegisterMessage(DeltaArchiveManifest) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('H\003')) +# @@protoc_insertion_point(module_scope) \ No newline at end of file diff --git a/windows-metadata.yaml b/windows-metadata.yaml index e7ae0ea..f5ef2a9 100644 --- a/windows-metadata.yaml +++ b/windows-metadata.yaml @@ -1,6 +1,6 @@ # https://github.com/DudeNr33/pyinstaller-versionfile # create-version-file windows-metadata.yaml --outfile windows-version-info.txt -Version: 5.1.0.2 +Version: 5.2.0.0 FileDescription: PixelFlasher InternalName: PixelFlasher OriginalFilename: PixelFlasher.exe diff --git a/windows-version-info.txt b/windows-version-info.txt index ce7aaf9..1bc448f 100644 --- a/windows-version-info.txt +++ b/windows-version-info.txt @@ -7,8 +7,8 @@ VSVersionInfo( ffi=FixedFileInfo( # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) # Set not needed items to zero 0. Must always contain 4 elements. - filevers=(5,1,0,2), - prodvers=(5,1,0,2), + filevers=(5,2,0,0), + prodvers=(5,2,0,0), # Contains a bitmask that specifies the valid bits 'flags'r mask=0x3f, # Contains a bitmask that specifies the Boolean attributes of the file. @@ -32,12 +32,12 @@ VSVersionInfo( u'040904B0', [StringStruct(u'CompanyName', u''), StringStruct(u'FileDescription', u'PixelFlasher'), - StringStruct(u'FileVersion', u'5.1.0.2'), + StringStruct(u'FileVersion', u'5.2.0.0'), StringStruct(u'InternalName', u'PixelFlasher'), StringStruct(u'LegalCopyright', u''), StringStruct(u'OriginalFilename', u'PixelFlasher.exe'), StringStruct(u'ProductName', u'PixelFlasher'), - StringStruct(u'ProductVersion', u'5.1.0.2')]) + StringStruct(u'ProductVersion', u'5.2.0.0')]) ]), VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) ]