Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4bc6fc52 authored by Daniel Jacob Chittoor's avatar Daniel Jacob Chittoor
Browse files

Improve flash reliability with delays and checks

Flash operations can timeout due to USB instability or device not being
ready. The current retry logic retries immediately, which often fails
again if the device needs time to stabilize.

bootloader.class.js:
- Add pre-flash device connection check
- Add 1 second delay between retries to let device recover
- Check device connection before each retry attempt
- Log flash size for debugging
- Improve error messages with troubleshooting hints

controller.manager.js:
- Add 500ms cooldown after each flash operation to prevent
  overwhelming the device with rapid successive writes

These changes reduce timeout likelihood by giving the device time to
process each operation. The root cause (library timeout threshold) may
still need investigation in @e/fastboot, but these mitigations improve
real-world reliability.
parent d22f2b42
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -159,14 +159,19 @@ export class Controller {
      }
      case Command.CMD_TYPE.erase:
        return this.deviceManager.erase(cmd.partition);
      case Command.CMD_TYPE.flash:
        return this.deviceManager.flash(
      case Command.CMD_TYPE.flash: {
        const FLASH_COOLDOWN_MS = 500; // Brief pause after flash to let device stabilize
        const result = await this.deviceManager.flash(
          cmd.file,
          cmd.partition,
          (done, total) => {
            this.view.onInstalling(cmd.file, done, total);
          },
        );
        // Small delay between flash operations to prevent overwhelming the device
        await new Promise(resolve => setTimeout(resolve, FLASH_COOLDOWN_MS));
        return result;
      }
      case Command.CMD_TYPE.unlock: {
        //check if unlocked to avoid unnecessary command
        let isUnlocked = false;
+21 −1
Original line number Diff line number Diff line
@@ -74,7 +74,15 @@ export class Bootloader extends Device {

  async flashBlob(partition, blob, onProgress, retryCount = 0) {
    const MAX_RETRIES = 3;
    const RETRY_DELAY_MS = 1000; // Wait before retry to let device stabilize

    // Pre-flash check: ensure device is still connected
    if (!this.device.isConnected) {
      throw new Error(`Device disconnected before flashing ${partition}`);
    }

    try {
      WDebug.log(`Flashing ${partition} (${(blob.size / 1024 / 1024).toFixed(1)} MB)...`);
      await this.device.flashBlob(partition, blob, (progress) => {
        onProgress(progress * blob.size, blob.size, partition);
      });
@@ -84,9 +92,21 @@ export class Bootloader extends Device {
      if (e instanceof TimeoutError) {
        WDebug.log(`Timeout on flashblob > ${partition} (attempt ${retryCount + 1}/${MAX_RETRIES})`);
        if (retryCount < MAX_RETRIES) {
          // Wait before retry to allow device to recover
          WDebug.log(`Waiting ${RETRY_DELAY_MS}ms before retry...`);
          await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS));

          // Check if device is still connected before retry
          if (!this.device.isConnected) {
            throw new Error(`Device disconnected during flash of ${partition}. Please reconnect and try again.`);
          }

          return await this.flashBlob(partition, blob, onProgress, retryCount + 1);
        }
        throw new Error(`Bootloader timeout: flashing ${partition} failed after ${MAX_RETRIES} retries`);
        throw new Error(
          `Bootloader timeout: flashing ${partition} failed after ${MAX_RETRIES} retries. ` +
          `Try using a different USB port or cable.`
        );
      } else {
        console.log("flashBlob error", e);
        throw new Error(`Bootloader error: ${e.message || e}`);