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

Commit f054f585 authored by Paula's avatar Paula
Browse files

refractoring filenames & and splitting downloader.manager into subfiles

parent cec82a0c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
    <link rel="stylesheet" href="/css/styles.css" />
    <link rel="stylesheet" href="/css/loader.css" />
    <title>/e/OS Installer</title>
    <script type="module" src="/src/viewManager.js"></script>
    <script type="module" src="/src/vue/view.manager.js"></script>
    <script type="module" src="/src/before-leave-app.js"></script>
  </head>
  <body id="body">
+216 −177
Original line number Diff line number Diff line
import { DeviceManager } from "./controller/device.manager.js";
import { Command } from "./controller/device/command.class.js";
import { Step } from "./controller/utils/step.class.js";
import { WDebug } from "./debug.js";
import { DeviceManager } from "./device.manager.js";
import { COMMAND } from "./enums/command.enum.js";
import { Step } from "./utils/step.class.js";
import { DebugManager } from "./debug.manager.js";
/*
 * Class to manage process
 * Check and display the steps, interact with deviceManager
 */
export class Controller {
export class ControllerManager {
  constructor() {
    this.steps = [
      new Step("let-s-get-started", undefined, true),
@@ -35,21 +35,21 @@ export class Controller {
    let current = this.steps[this.currentIndex];
    let next = this.steps[this.currentIndex + 1];

    WDebug.log("Controller Manager Next", next);
    DebugManager.log("Controller Manager Next", next);

    if (next) {
      if (next.mode) {
        const alreadyInMode = this.inInMode(next.mode);
        WDebug.log(
        DebugManager.log(
          `next() step="${next.name}" requires mode="${next.mode}", ` +
            `alreadyInMode=${alreadyInMode}, needUserGesture=${next.needUserGesture}`,
        );
        //if next step require another mode [adb|fastboot|bootloader]
        if (!alreadyInMode) {
          //we need reboot
          WDebug.log(`next() rebooting to ${next.mode}...`);
          DebugManager.log(`next() rebooting to ${next.mode}...`);
          await this.deviceManager.reboot(next.mode);
          WDebug.log(`next() reboot to ${next.mode} completed`);
          DebugManager.log(`next() reboot to ${next.mode} completed`);
        }
        if (next.needUserGesture) {
          // Wait for the device to appear on the USB bus before showing the
@@ -57,20 +57,22 @@ export class Controller {
          // devices after a mode switch. The actual connect happens via
          // executeStep when the user clicks (WebUSB requestDevice() requires
          // a user gesture).
          WDebug.log(
          DebugManager.log(
            `next() waiting for device on USB bus (needUserGesture=true, deferring connect)...`,
          );
          await this.deviceManager.waitForDeviceOnBus();
          WDebug.log(`next() device wait complete, showing step to user`);
          DebugManager.log(`next() device wait complete, showing step to user`);
        } else {
          WDebug.log(`next() connecting to ${next.mode} automatically...`);
          DebugManager.log(
            `next() connecting to ${next.mode} automatically...`,
          );
          await this.deviceManager.connect(next.mode);
          WDebug.log(`next() auto-connect to ${next.mode} completed`);
          DebugManager.log(`next() auto-connect to ${next.mode} completed`);
        }
      }
      this.currentIndex++;
      current = this.steps[this.currentIndex];
      WDebug.log(
      DebugManager.log(
        `next() advancing to step="${current.name}", needUserGesture=${current.needUserGesture}`,
      );
      this.view.onStepStarted(this.currentIndex, current);
@@ -83,7 +85,7 @@ export class Controller {
  async executeStep(stepName, loader) {
    const current = this.steps[this.currentIndex];
    let this_command;
    WDebug.log("ControllerManager Execute step", current);
    DebugManager.log("ControllerManager Execute step", current);
    document.getElementById("error-message-state").style.display = "none";
    if (current.name === stepName) {
      let res = true;
@@ -92,7 +94,7 @@ export class Controller {
        for (i = 0; i < current.commands.length && res; i++) {
          this_command = current.commands[i];
          res = await this.runCommand(this_command, loader);
          WDebug.log("run command > ", this_command, "returns ", res);
          DebugManager.log("run command > ", this_command, "returns ", res);
        }
        const next = this.steps[this.currentIndex + 1];
        let previous = this.steps[this.currentIndex - 1];
@@ -139,9 +141,39 @@ export class Controller {
    error should contain a proposal to solve the issue.
    */
  async runCommand(cmd, loader) {
    WDebug.log("ControllerManager run command:", cmd);
    DebugManager.log("ControllerManager run command:", cmd);
    switch (cmd.type) {
      case Command.CMD_TYPE.download:
      case COMMAND.download:
        return this.runDownloadCommand();
      case COMMAND.reboot:
        return this.runRebootCommand(cmd);
      case COMMAND.connect: {
        return this.runConnectCommand(cmd, loader);
      }
      case COMMAND.erase:
        return this.deviceManager.erase(cmd.partition);
      case COMMAND.flash: {
        return this.runFlashCommand(cmd);
      }
      case COMMAND.unlock: {
        return this.runUnlockCommand(cmd);
      }
      case COMMAND.lock: {
        return this.runLockCommand(cmd);
      }
      case COMMAND.sideload:
        return this.runSideloadCommand(cmd);
      case COMMAND.format:
        return this.runFormatCommand(cmd);
      case COMMAND.delay:
        return this.runDelayCommand(cmd);

      default:
        return this.runUnknownCommand(cmd);
    }
  }

  async runDownloadCommand() {
    try {
      await this.deviceManager.downloadAll(
        (loaded, total, name) => {
@@ -162,14 +194,18 @@ export class Controller {
        `Cannot download <br/> ${e.message || e} <br/> ${proposal}`,
      );
    }
      case Command.CMD_TYPE.reboot:
  }

  async runRebootCommand(cmd) {
    try {
      await this.deviceManager.reboot(cmd.mode);
      return true;
    } catch (e) {
      throw new Error(`Reboot to ${cmd.mode} failed: ${e.message || e}`);
    }
      case Command.CMD_TYPE.connect: {
  }

  async runConnectCommand(cmd, loader) {
    const proposal =
      "Proposal: Check connection and that no other program is using the phone and retry.";
    try {
@@ -185,9 +221,8 @@ export class Controller {
      );
    }
  }
      case Command.CMD_TYPE.erase:
        return this.deviceManager.erase(cmd.partition);
      case Command.CMD_TYPE.flash: {

  async runFlashCommand(cmd) {
    const FLASH_COOLDOWN_MS = this.resources?.flash_cooldown_ms ?? 2500;
    const result = await this.deviceManager.flash(
      cmd.file,
@@ -196,56 +231,50 @@ export class Controller {
        this.view.onInstalling(cmd.file, done, total);
      },
    );
        // Small delay between flash operations to prevent overwhelming the device
        WDebug.log(
    DebugManager.log(
      `Flash cooldown: waiting ${FLASH_COOLDOWN_MS}ms before next operation`,
    );
    await new Promise((resolve) => setTimeout(resolve, FLASH_COOLDOWN_MS));
    return result;
  }
      case Command.CMD_TYPE.unlock: {
        //check if unlocked to avoid unnecessary command

  async runUnlockCommand(cmd) {
    let isUnlocked = false;
    let gotoStep = "";
    if (cmd.partition) {
      if (cmd.partition.startsWith("goto_")) {
        gotoStep = cmd.partition.substring(5);
            WDebug.log("goto step", gotoStep);
        DebugManager.log("goto step", gotoStep);
        isUnlocked = await this.deviceManager.getUnlocked("unlocked");
      } else {
        isUnlocked = await this.deviceManager.getUnlocked(cmd.partition);
      }
    }
        WDebug.log(
    DebugManager.log(
      "ControllerManager unlock: ",
          this.deviceManager.adb.getProductName() +
            " isUnlocked = " +
            isUnlocked,
      this.deviceManager.adb.getProductName() + " isUnlocked = " + isUnlocked,
    );
    if (!isUnlocked) {
      try {
        await this.deviceManager.unlock(cmd.command);
      } catch (e) {
            //on some device, check unlocked does not work but when we try the command, it throws an error with "already unlocked"
        if (e.bootloaderMessage?.includes("already")) {
              WDebug.log("device already unlocked");
          DebugManager.log("device already unlocked");
        } else if (e.bootloaderMessage?.includes("not allowed")) {
              WDebug.log("device unlock is not allowed");
          DebugManager.log("device unlock is not allowed");
          throw new Error(`Unlock not allowed: ${e.message || e}`);
        } else {
          throw e;
        }
      }
    } else {
          WDebug.log("The phone is not locked - bypass lock process");
      DebugManager.log("The phone is not locked - bypass lock process");
      if (gotoStep == "") {
            // Goto the next step.
        this.currentIndex++;
      } else {
            // Goto the maned step.
        do {
          this.currentIndex++;
              WDebug.log(
          DebugManager.log(
            "Bypass step",
            this.steps[this.currentIndex].name +
              " " +
@@ -257,7 +286,8 @@ export class Controller {
    }
    return true;
  }
      case Command.CMD_TYPE.lock: {

  async runLockCommand(cmd) {
    let isLocked = false;
    if (cmd.partition) {
      isLocked = !(await this.deviceManager.getUnlocked(cmd.partition));
@@ -267,9 +297,8 @@ export class Controller {
        await this.deviceManager.lock(cmd.command);
        isLocked = true;
      } catch (e) {
            //on some device, check unlocked does not work but when we try the command, it throws an error with "already locked"
        if (e.bootloaderMessage?.includes("already")) {
              WDebug.log("device already locked");
          DebugManager.log("device already locked");
          isLocked = true;
        } else {
          throw new Error(`Lock failed: ${e.message || e}`);
@@ -278,7 +307,8 @@ export class Controller {
    }
    return true;
  }
      case Command.CMD_TYPE.sideload:

  async runSideloadCommand(cmd) {
    try {
      await this.deviceManager.connect("recovery");
      await this.deviceManager.sideload(cmd.file);
@@ -286,22 +316,26 @@ export class Controller {
    } catch (e) {
      throw new Error(`Sideload ${cmd.file} failed: ${e.message || e}`);
    }
      case Command.CMD_TYPE.format:
  }

  async runFormatCommand(cmd) {
    try {
      return this.deviceManager.format(cmd.partition);
    } catch (e) {
      throw new Error(`Format ${cmd.partition} failed: ${e.message || e}`);
    }
      case Command.CMD_TYPE.delay:
  }

  async runDelayCommand(cmd) {
    await new Promise((resolve) => setTimeout(resolve, cmd.partition));
    return true;
  }

      default:
        WDebug.log(`try unknown command ${cmd.command}`);
  async runUnknownCommand(cmd) {
    DebugManager.log(`try unknown command ${cmd.command}`);
    await this.deviceManager.runCommand(cmd.command);
    return true;
  }
  }

  async onDeviceConnected() {
    const productName = this.deviceManager.getProductName();
@@ -309,7 +343,7 @@ export class Controller {
      this.deviceManager.markAsConnected();
      this.view.updateData("product-name", productName);
      this.model = productName;
      WDebug.log("ControllerManager Model:", this.model);
      DebugManager.log("ControllerManager Model:", this.model);
      try {
        const resources = await this.getResources();

@@ -327,7 +361,7 @@ export class Controller {
  }
  async checkAndroidVersion(versionRequired) {
    const android = await this.deviceManager.getAndroidVersion();
    WDebug.log("current android version:", android);
    DebugManager.log("current android version:", android);
    if (android) {
      this.view.updateData("android-version", android);
      if (android < versionRequired) {
@@ -343,14 +377,17 @@ export class Controller {
        const security_patch = await this.deviceManager.adb.getProp(
          "ro.build.version.security_patch",
        );
        //WDebug.log('security_patch', security_patch)
        //DebugManager.log('security_patch', security_patch)
        current_security_path_level = parseInt(
          security_patch.replace(/-/g, ""),
          10,
        );
        WDebug.log("current_security_path_level", current_security_path_level);
        DebugManager.log(
          "current_security_path_level",
          current_security_path_level,
        );
      } catch {
        WDebug.log("Security patch Error");
        DebugManager.log("Security patch Error");
        current_security_path_level = null;
      }
      let this_model = this.deviceManager.adb.banner.device;
@@ -359,7 +396,7 @@ export class Controller {
      if (model.includes("Teracube") && model.includes("2e")) {
        try {
          const serial = await this.deviceManager.adb.getSerialNumber();
          WDebug.log("serial numer:", serial);
          DebugManager.log("serial numer:", serial);
          if (serial.startsWith("2021")) {
            this_model = "emerald";
          } else if (serial.startsWith("2020")) {
@@ -421,14 +458,16 @@ export class Controller {
        current_security_path_level != null &&
        typeof resources.security_patch_level != "undefined"
      ) {
        WDebug.log(`EOS Rom has security patch ${current_security_path_level}`);
        DebugManager.log(
          `EOS Rom has security patch ${current_security_path_level}`,
        );
        const new_security_path_level = parseInt(
          resources.security_patch_level.replace(/-/g, ""),
          10,
        );
        WDebug.log(`New security patch ${new_security_path_level}`);
        DebugManager.log(`New security patch ${new_security_path_level}`);
        if (current_security_path_level > new_security_path_level) {
          WDebug.log(
          DebugManager.log(
            "Bypass lock procedure",
            `resources/${this_model}-safe.json`,
          );
@@ -439,7 +478,7 @@ export class Controller {
      }
    } catch (e) {
      resources = null;
      WDebug.log("getResources Error: " + e);
      DebugManager.log("getResources Error: " + e);
      throw Error("device-model-not-supported");
    }

+1 −1
Original line number Diff line number Diff line
export class WDebug {
export class DebugManager {
  constructor() {}

  static log(...args) {
+13 −17
Original line number Diff line number Diff line
import { Bootloader } from "./device/bootloader.class.js";
import { Downloader } from "./downloader.manager.js";
import { DownloaderManager } from "./downloader.manager.js";
import { ADB } from "./device/adb.class.js";
import { Recovery } from "./device/recovery.class.js";
import { Device } from "./device/device.class.js";
import { WDebug } from "../debug.js";
const MODE = {
  adb: "adb",
  recovery: "recovery",
  bootloader: "bootloader",
};
import { DebugManager } from "./debug.manager.js";
import { MODE } from "./enums/mode.enum.js";

/**
 * wrap device functions
@@ -24,7 +20,7 @@ export class DeviceManager {
    this.bootloader = new Bootloader();
    this.recovery = new Recovery();
    this.adb = new ADB();
    this.downloader = new Downloader();
    this.downloader = new DownloaderManager();
    this.wasConnected = false;
  }

@@ -121,11 +117,11 @@ export class DeviceManager {
   */
  isInMode(mode) {
    switch (mode) {
      case "bootloader":
      case MODE.bootloader:
        return this.device.isBootloader();
      case "adb":
      case MODE.adb:
        return this.device.isADB();
      case "recovery":
      case MODE.recovery:
        return this.device.isRecovery();
    }
    return false;
@@ -214,26 +210,26 @@ export class DeviceManager {
    return new Promise((resolve) => {
      const devices = navigator.usb.getDevices();
      devices.then((list) => {
        WDebug.log(
        DebugManager.log(
          `waitForDeviceOnBus: getDevices() returned ${list.length} device(s)`,
          list.map((d) => `${d.vendorId}:${d.productId} "${d.productName}"`),
        );
        if (list.length > 0) {
          WDebug.log(
          DebugManager.log(
            "waitForDeviceOnBus: device already visible, no wait needed",
          );
          resolve();
          return;
        }

        WDebug.log(
        DebugManager.log(
          `waitForDeviceOnBus: no devices found, listening for USB connect event (timeout=${timeoutMs}ms)...`,
        );

        const timeout = setTimeout(() => {
          navigator.usb.removeEventListener("connect", onConnect);
          const elapsed = Date.now() - startTime;
          WDebug.log(
          DebugManager.log(
            `waitForDeviceOnBus: timeout after ${elapsed}ms, no device appeared. Proceeding anyway.`,
          );
          resolve();
@@ -242,7 +238,7 @@ export class DeviceManager {
        const onConnect = (event) => {
          const elapsed = Date.now() - startTime;
          const d = event.device;
          WDebug.log(
          DebugManager.log(
            `waitForDeviceOnBus: USB connect event after ${elapsed}ms - ` +
              `vendorId=${d.vendorId} productId=${d.productId} ` +
              `productName="${d.productName}" serialNumber="${d.serialNumber}"`,
@@ -250,7 +246,7 @@ export class DeviceManager {
          clearTimeout(timeout);
          navigator.usb.removeEventListener("connect", onConnect);
          // Small delay to let the device fully initialize after enumeration
          WDebug.log(
          DebugManager.log(
            "waitForDeviceOnBus: waiting 1000ms for device to stabilize...",
          );
          setTimeout(resolve, 1000);
+8 −8
Original line number Diff line number Diff line
import { Device } from "./device.class.js";
import { WDebug } from "../../debug.js";
import { DebugManager } from "../debug.manager.js";
import { AdbDevice } from "../../lib/index.ts";

export class ADB extends Device {
@@ -23,12 +23,12 @@ export class ADB extends Device {
      this.device = { name: this._adbDevice.usbDevice.productName };

      const banner = this._adbDevice.banner;
      WDebug.log("----------------------------------");
      WDebug.log("Model", banner.model);
      WDebug.log("product", banner.product);
      WDebug.log("Name", this._adbDevice.usbDevice.productName);
      WDebug.log(">Device (codename)", banner.device);
      WDebug.log("----------------------------------");
      DebugManager.log("----------------------------------");
      DebugManager.log("Model", banner.model);
      DebugManager.log("product", banner.product);
      DebugManager.log("Name", this._adbDevice.usbDevice.productName);
      DebugManager.log(">Device (codename)", banner.device);
      DebugManager.log("----------------------------------");
    } catch (e) {
      console.error(e);
      this.device = null;
@@ -57,7 +57,7 @@ export class ADB extends Device {
  }

  async runCommand(cmd) {
    WDebug.log("ADB Run command>", cmd);
    DebugManager.log("ADB Run command>", cmd);
    return await this._adbDevice.shell(cmd);
  }

Loading