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

Commit ca1c3c8c authored by Daniel Jacob Chittoor's avatar Daniel Jacob Chittoor Committed by Jackeagle
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 7d39eb2f
Loading
Loading
Loading
Loading
+7 −2
Original line number Original line Diff line number Diff line
@@ -164,14 +164,19 @@ export class Controller {
      }
      }
      case Command.CMD_TYPE.erase:
      case Command.CMD_TYPE.erase:
        return this.deviceManager.erase(cmd.partition);
        return this.deviceManager.erase(cmd.partition);
      case Command.CMD_TYPE.flash:
      case Command.CMD_TYPE.flash: {
        return this.deviceManager.flash(
        const FLASH_COOLDOWN_MS = 500; // Brief pause after flash to let device stabilize
        const result = await this.deviceManager.flash(
          cmd.file,
          cmd.file,
          cmd.partition,
          cmd.partition,
          (done, total) => {
          (done, total) => {
            this.view.onInstalling(cmd.file, 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: {
      case Command.CMD_TYPE.unlock: {
        //check if unlocked to avoid unnecessary command
        //check if unlocked to avoid unnecessary command
        let isUnlocked = false;
        let isUnlocked = false;
+21 −1
Original line number Original line Diff line number Diff line
@@ -74,7 +74,15 @@ export class Bootloader extends Device {


  async flashBlob(partition, blob, onProgress, retryCount = 0) {
  async flashBlob(partition, blob, onProgress, retryCount = 0) {
    const MAX_RETRIES = 3;
    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 {
    try {
      WDebug.log(`Flashing ${partition} (${(blob.size / 1024 / 1024).toFixed(1)} MB)...`);
      await this.device.flashBlob(partition, blob, (progress) => {
      await this.device.flashBlob(partition, blob, (progress) => {
        onProgress(progress * blob.size, blob.size, partition);
        onProgress(progress * blob.size, blob.size, partition);
      });
      });
@@ -84,9 +92,21 @@ export class Bootloader extends Device {
      if (e instanceof TimeoutError) {
      if (e instanceof TimeoutError) {
        WDebug.log(`Timeout on flashblob > ${partition} (attempt ${retryCount + 1}/${MAX_RETRIES})`);
        WDebug.log(`Timeout on flashblob > ${partition} (attempt ${retryCount + 1}/${MAX_RETRIES})`);
        if (retryCount < 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);
          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 {
      } else {
        console.log("flashBlob error", e);
        console.log("flashBlob error", e);
        throw new Error(`Bootloader error: ${e.message || e}`);
        throw new Error(`Bootloader error: ${e.message || e}`);