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

Commit 7bd964ca authored by Paula's avatar Paula
Browse files

use ProcessError at low level & InstructionError at hight level

parent 9f93cb3e
Loading
Loading
Loading
Loading
+177 −136
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ export class ControllerManager {
    const current = this.steps[this.currentIndex];
    LOGGER.info(fn, "Executing", current);
    document.getElementById("error-message-state").style.display = "none";
    try {
      if (current.name === stepName) {
        let res = true;
        let i;
@@ -144,6 +145,9 @@ export class ControllerManager {
        LOGGER.error(fn, err.toString());
        throw err;
      }
    } catch (error) {
      throw this.processError(fn, error);
    }
  }

  /**
@@ -202,7 +206,6 @@ export class ControllerManager {
   * @returns {Promise<boolean>} True when all files are downloaded successfully.
   */
  async runDownloadCommand() {
    try {
    await this.deviceManager.downloadAll(
      (loaded, total, name) => {
        this.view.onDownloading(name, loaded, total);
@@ -216,11 +219,6 @@ export class ControllerManager {
    );
    this.view.onDownloadingEnd();
    return true;
    } catch (e) {
      const err = new InstructionError(e, false, false);
      LOGGER.error("runDownloadCommand", err.toString());
      throw err;
    }
  }

  /**
@@ -242,17 +240,12 @@ export class ControllerManager {
   * @returns {Promise<boolean>} True when connection succeeds.
   */
  async runConnectCommand(cmd, loader) {
    try {
    await this.deviceManager.connect(cmd.mode);
    await this.onDeviceConnected();
    if (loader) {
      loader.style.display = "none";
    }
    return true;
    } catch (e) {
      const err = new InstructionError(e, false, true);
      throw err;
    }
  }

  /**
@@ -515,107 +508,120 @@ export class ControllerManager {
    const fn = "getResources";
    let resources = null;
    try {
      let current_security_path_level = null;
      try {
        const security_patch = await this.deviceManager.adb.getProp(
          "ro.build.version.security_patch",
      const model = await this.getDeviceModel();
      resources = await (await fetch(`resources/${model}.json`)).json();
    } catch (e) {
      resources = null;
      const err = new ProcessError({
        origin: ORIGIN,
        fn,
        error: e,
        code: ERROR_CODE.device_model_not_supported,
        message: "device-model-not-supported",
        details: { model },
      });
      LOGGER.error(fn, err.toString());
      throw err;
    }

    if (resources.security_patch_level) {
      const eosSecurityPatchLevel = parseInt(
        resources.security_patch_level.replace(/-/g, ""),
        10,
      );
        //LOGGER.info('security_patch', security_patch)
        current_security_path_level = parseInt(
          security_patch.replace(/-/g, ""),
      const deviceSecurityPatch =
        await this.deviceManager.adb.getSecurityPatch();
      const deviceSecurityPatchLevel = parseInt(
        deviceSecurityPatch.replace(/-/g, ""),
        10,
      );
        LOGGER.info(
      const isUnsafe = deviceSecurityPatchLevel > eosSecurityPatchLevel;
      if (isUnsafe) {
        LOGGER.warn(
          fn,
          "current_security_path_level",
          current_security_path_level,
          "Security patch level is not safe, trying to load safe resource with limited features",
          `resources/${model}-safe.json`,
        );
      } catch {
        LOGGER.info(fn, "Security patch Error");
        current_security_path_level = null;
        resources = await (await fetch(`resources/${model}-safe.json`)).json();
        if (!resources) {
          const err = new ProcessError({
            origin: ORIGIN,
            fn,
            code: ERROR_CODE.security_patch_level_not_safe,
            message: `Security patch ${resources.security_patch_level} for ${model} is not safe and no fallback resource found`,
          });
          LOGGER.error(fn, err.toString());
          throw err;
        }
      const banner = this.deviceManager.adb.getBanner();
      let this_model = banner.device;
      //    https://gitlab.e.foundation/e/os/backlog/-/issues/2604#note_609234
      const model = banner.model;
      if (model.includes("Teracube") && model.includes("2e")) {
      }
    }
    return resources;
  }

  async getDeviceModel() {
    const fn = "getDeviceModel";
    let device;
    let model;
    try {
          const serial = await this.deviceManager.adb.getSerialNumber();
          LOGGER.info(fn, "serial numer:", serial);
          if (serial.startsWith("2021")) {
            this_model = "emerald";
          } else if (serial.startsWith("2020")) {
            this_model = "Teracube_2e";
          } else {
            const id = `model ${banner.model} product ${banner.product} name ${this.deviceManager.adb.getProductName()} device ${banner.device}`;
      const banner = this.deviceManager.adb.getBanner();
      LOGGER.info(
        fn,
        "ADB Banner",
        `Model= ${banner.model} Product= ${banner.product} Device(codename)= ${banner.device}`,
      );
      model = banner.model;
      device = banner.device;
      if (!model || !device) {
        throw new Error("Model or device is undefined in ADB banner");
      }
    } catch (error) {
      const err = new ProcessError({
        origin: ORIGIN,
        fn,
              code: ERROR_CODE.device_resource_not_found,
        error,
        code: ERROR_CODE.device_resource_lookup_failed,
        message: "Cannot find device resource",
              details: { id, model: banner.model, product: banner.product },
      });
      LOGGER.error(fn, err.toString());
      throw err;
    }
    // https://gitlab.e.foundation/e/os/backlog/-/issues/2604#note_609234
    if (model.includes("Teracube") && model.includes("2e")) {
      let serial = "";
      try {
        serial = await this.deviceManager.adb.getSerialNumber();
        LOGGER.info(fn, "serial numer:", serial);
      } catch {
          const id = `model ${banner.model} product ${banner.product} name ${this.deviceManager.adb.getProductName()} device ${banner.device}`;
        const err = new ProcessError({
          origin: ORIGIN,
          fn,
          code: ERROR_CODE.device_resource_lookup_failed,
          message: "Error on getting device resource",
            details: { id, model: banner.model, product: banner.product },
          details: { model, serial },
        });
        LOGGER.error(fn, err.toString());
        throw err;
      }
      }

      if (model.includes("A015")) {
        this_model = "tetris";
      }

      resources = await (await fetch(`resources/${this_model}.json`)).json();
      if (
        current_security_path_level != null &&
        typeof resources.security_patch_level != "undefined"
      ) {
        LOGGER.info(
          fn,
          `EOS Rom has security patch ${current_security_path_level}`,
        );
        const new_security_path_level = parseInt(
          resources.security_patch_level.replace(/-/g, ""),
          10,
        );
        LOGGER.info(fn, `New security patch ${new_security_path_level}`);
        if (current_security_path_level > new_security_path_level) {
          LOGGER.info(
            fn,
            "Bypass lock procedure",
            `resources/${this_model}-safe.json`,
          );
          resources = await (
            await fetch(`resources/${this_model}-safe.json`)
          ).json();
        }
      }
    } catch (e) {
      resources = null;
      if (serial.startsWith("2021")) {
        return "emerald";
      } else if (serial.startsWith("2020")) {
        return "Teracube_2e";
      } else {
        const err = new ProcessError({
          origin: ORIGIN,
          fn,
        error: e,
        code: ERROR_CODE.device_model_not_supported,
        message: "device-model-not-supported",
        details: { model: this.model },
          code: ERROR_CODE.device_resource_lookup_failed,
          message: "Cannot find device resource",
          details: { model },
        });
        LOGGER.error(fn, err.toString());
        throw err;
      }

    return resources;
    }
    if (model.includes("A015")) {
      return "tetris";
    }
    return device;
  }

  /**
@@ -664,4 +670,39 @@ export class ControllerManager {
  clearLocalZip() {
    this.deviceManager.clearLocalZipFile();
  }

  processError(fn, error) {
    if (error instanceof InstructionError) {
      LOGGER.warn(fn, "InstructionError already processed, pass through");
      return error; //weird, this function is used to process error and convert ProcessError to InstructionError so it should not be already an InstructionError
    } else {
      if (!(error instanceof ProcessError)) {
        error = new ProcessError({
          origin: ORIGIN,
          fn,
          error,
          code: ERROR_CODE.unknown_error,
          message: `Unknown error: ${error.message || error}`,
        });
      }
      switch (
        error.code //list of error that can be handled by the instruction error and should not be displayed as a process error
      ) {
        case ERROR_CODE.unlock_not_allowed:
        case ERROR_CODE.adb_connect_failed:
        case ERROR_CODE.adb_request_failed:
        case ERROR_CODE.bootloader_connect_failed:
        case ERROR_CODE.offline_before_fetch:
        case ERROR_CODE.android_version_not_supported:
          return new InstructionError(error, false, true);
        default: // by default, unknown error are considered as critical
          return new InstructionError(
            error,
            true,
            false,
            ERROR_CODE.unknown_error,
          );
      }
    }
  }
}
+19 −20
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ export class DeviceManager {
    this.recovery = new Recovery();
    this.adb = new ADB();
    this.downloader = new DownloaderManager();
    this.downloader = new DownloaderManager();
    this.wasConnected = false;
  }

@@ -263,22 +262,7 @@ export class DeviceManager {
      LOGGER.error("flash", err.toString());
      throw err;
    }
    let flashed = false;
    try {
      flashed = await this.bootloader.flashBlob(partition, blob, onProgress);
    } catch (e) {
      const err = new ProcessError({
        origin: ORIGIN,
        fn: "flash",
        error: e,
        code: ERROR_CODE.flash_failed,
        message: `error flashing file ${file} ${e.message || e}`,
        details: { file, partition },
      });
      LOGGER.error("flash", err.toString());
      throw err;
    }
    return flashed;
    return this.bootloader.flashBlob(partition, blob, onProgress);
  }

  /**
@@ -293,10 +277,25 @@ export class DeviceManager {
  /**
   * Returns the serial number of the connected device.
   *
   * @returns {string|undefined} Serial number string or undefined.
   * @returns {Promise<string|undefined>} Serial number string or undefined.
   */
  getSerialNumber() {
    return this.device.getSerialNumber();
  async getSerialNumber() {
    const fn = "getSerialNumber";
    try {
      const serial = await this.device.getSerialNumber();
      LOGGER.info(fn, "serial numer:", serial);
      return serial;
    } catch (error) {
      const err = new ProcessError({
        fn,
        origin: ORIGIN,
        code: ERROR_CODE.device_resource_lookup_failed,
        message: "Error on getting device resource",
        error,
      });
      LOGGER.error(fn, err.toString());
      throw err;
    }
  }

  /**
+9 −0
Original line number Diff line number Diff line
@@ -113,6 +113,15 @@ export class ADB extends Device {
    return this._adbDevice.getProp("ro.build.version.release");
  }

  /**
   * Returns the security patch level of the connected device.
   *
   * @returns {Promise<string>} Security patch string.
   */
  async getSecurityPatch() {
    return this._adbDevice.getProp("ro.build.version.security_patch");
  }

  /**
   * Returns the serial number of the connected device via ADB property.
   *
+2 −2
Original line number Diff line number Diff line
@@ -92,9 +92,9 @@ export class Device {
  /**
   * Returns the serial number. Override in subclass.
   *
   * @returns {undefined} Base implementation returns undefined.
   * @returns {Promise<undefined>} Base implementation returns undefined.
   */
  getSerialNumber() {
  async getSerialNumber() {
    return undefined;
  }

+1 −1
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ export class Recovery extends Device {
   *
   * @returns {string|undefined} Serial number or undefined.
   */
  getSerialNumber() {
  async getSerialNumber() {
    return this._adbDevice?.usbDevice?.serialNumber;
  }
}
Loading