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

Commit 5f7edecf authored by Paula's avatar Paula
Browse files

update debug.manager to use a log class with date, level & origin of the log

parent f83d166d
Loading
Loading
Loading
Loading
+56 −37
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ import { COMMAND } from "./enums/command.enum.js";
import { Step } from "./utils/step.class.js";
import { DebugManager } from "./debug.manager.js";

const LOGGER = DebugManager.getLogger("ControllerManager");

/*
 * Class to manage process
 * Check and display the steps, interact with deviceManager
@@ -50,24 +52,26 @@ export class ControllerManager {
   * @returns {Promise<void>} Resolves when the next step is started.
   */
  async next() {
    const fn = "next";
    let current = this.steps[this.currentIndex];
    let next = this.steps[this.currentIndex + 1];

    DebugManager.log("Controller Manager Next", next);
    LOGGER.info(fn, "Advancing to", next.toString());

    if (next) {
      if (next.mode) {
        const alreadyInMode = this.inInMode(next.mode);
        DebugManager.log(
          `next() step="${next.name}" requires mode="${next.mode}", ` +
        LOGGER.info(
          fn,
          `${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
          DebugManager.log(`next() rebooting to ${next.mode}...`);
          LOGGER.info(fn, `Rebooting to ${next.mode}...`);
          await this.deviceManager.reboot(next.mode);
          DebugManager.log(`next() reboot to ${next.mode} completed`);
          LOGGER.info(fn, `Reboot to ${next.mode} completed`);
        }
        if (next.needUserGesture) {
          // Wait for the device to appear on the USB bus before showing the
@@ -75,23 +79,23 @@ export class ControllerManager {
          // devices after a mode switch. The actual connect happens via
          // executeStep when the user clicks (WebUSB requestDevice() requires
          // a user gesture).
          DebugManager.log(
            `next() waiting for device on USB bus (needUserGesture=true, deferring connect)...`,
          LOGGER.info(
            fn,
            `Waiting for device on USB bus (needUserGesture=true, deferring connect)...`,
          );
          await this.deviceManager.waitForDeviceOnBus();
          DebugManager.log(`next() device wait complete, showing step to user`);
          LOGGER.info(fn, "Device wait complete, showing step to user");
        } else {
          DebugManager.log(
            `next() connecting to ${next.mode} automatically...`,
          );
          LOGGER.info(fn, `Connecting to ${next.mode} automatically...`);
          await this.deviceManager.connect(next.mode);
          DebugManager.log(`next() auto-connect to ${next.mode} completed`);
          LOGGER.info(fn, `Auto-connect to ${next.mode} completed`);
        }
      }
      this.currentIndex++;
      current = this.steps[this.currentIndex];
      DebugManager.log(
        `next() advancing to step="${current.name}", needUserGesture=${current.needUserGesture}`,
      LOGGER.info(
        fn,
        `Advancing to step="${current.name}", needUserGesture=${current.needUserGesture}`,
      );
      this.view.onStepStarted(this.currentIndex, current);
      if (!current.needUserGesture) {
@@ -108,9 +112,10 @@ export class ControllerManager {
   * @returns {Promise<void>} Resolves when the step has been processed.
   */
  async executeStep(stepName, loader) {
    const fn = "executeStep";
    const current = this.steps[this.currentIndex];
    let this_command;
    DebugManager.log("ControllerManager Execute step", current);
    LOGGER.info(fn, "Executing", current);
    document.getElementById("error-message-state").style.display = "none";
    if (current.name === stepName) {
      let res = true;
@@ -119,7 +124,7 @@ export class ControllerManager {
        for (i = 0; i < current.commands.length && res; i++) {
          this_command = current.commands[i];
          res = await this.runCommand(this_command, loader);
          DebugManager.log("run command > ", this_command, "returns ", res);
          LOGGER.info(fn, this_command, "returns ", res);
        }
        const next = this.steps[this.currentIndex + 1];
        let previous = this.steps[this.currentIndex - 1];
@@ -168,7 +173,8 @@ export class ControllerManager {
   * @returns {Promise<boolean>} True when the command succeeds.
   */
  async runCommand(cmd, loader) {
    DebugManager.log("ControllerManager run command:", cmd);
    const fn = "runCommand";
    LOGGER.info(fn, "Running command", cmd);
    switch (cmd.type) {
      case COMMAND.download:
        return this.runDownloadCommand();
@@ -274,6 +280,7 @@ export class ControllerManager {
   * @returns {Promise<boolean>} True when flashing succeeds.
   */
  async runFlashCommand(cmd) {
    const fn = "runFlashCommand";
    const FLASH_COOLDOWN_MS = this.resources?.flash_cooldown_ms ?? 2500;
    const result = await this.deviceManager.flash(
      cmd.file,
@@ -282,7 +289,8 @@ export class ControllerManager {
        this.view.onInstalling(cmd.file, done, total);
      },
    );
    DebugManager.log(
    LOGGER.info(
      fn,
      `Flash cooldown: waiting ${FLASH_COOLDOWN_MS}ms before next operation`,
    );
    await new Promise((resolve) => setTimeout(resolve, FLASH_COOLDOWN_MS));
@@ -296,19 +304,21 @@ export class ControllerManager {
   * @returns {Promise<boolean>} True when unlock flow completes.
   */
  async runUnlockCommand(cmd) {
    const fn = "runUnlockCommand";
    let isUnlocked = false;
    let gotoStep = "";
    if (cmd.partition) {
      if (cmd.partition.startsWith("goto_")) {
        gotoStep = cmd.partition.substring(5);
        DebugManager.log("goto step", gotoStep);
        LOGGER.info(fn, "goto step", gotoStep);
        isUnlocked = await this.deviceManager.getUnlocked("unlocked");
      } else {
        isUnlocked = await this.deviceManager.getUnlocked(cmd.partition);
      }
    }
    DebugManager.log(
      "ControllerManager unlock: ",
    LOGGER.info(
      fn,
      "unlock:",
      this.deviceManager.adb.getProductName() + " isUnlocked = " + isUnlocked,
    );
    if (!isUnlocked) {
@@ -316,22 +326,23 @@ export class ControllerManager {
        await this.deviceManager.unlock(cmd.command);
      } catch (e) {
        if (e.bootloaderMessage?.includes("already")) {
          DebugManager.log("device already unlocked");
          LOGGER.info(fn, "device already unlocked");
        } else if (e.bootloaderMessage?.includes("not allowed")) {
          DebugManager.log("device unlock is not allowed");
          LOGGER.info(fn, "device unlock is not allowed");
          throw new Error(`Unlock not allowed: ${e.message || e}`);
        } else {
          throw e;
        }
      }
    } else {
      DebugManager.log("The phone is not locked - bypass lock process");
      LOGGER.warn(fn, "The phone is not locked - bypass lock process");
      if (gotoStep == "") {
        this.currentIndex++;
      } else {
        do {
          this.currentIndex++;
          DebugManager.log(
          LOGGER.info(
            fn,
            "Bypass step",
            this.steps[this.currentIndex].name +
              " " +
@@ -351,6 +362,7 @@ export class ControllerManager {
   * @returns {Promise<boolean>} True when lock flow completes.
   */
  async runLockCommand(cmd) {
    const fn = "runLockCommand";
    let isLocked = false;
    if (cmd.partition) {
      isLocked = !(await this.deviceManager.getUnlocked(cmd.partition));
@@ -361,7 +373,7 @@ export class ControllerManager {
        isLocked = true;
      } catch (e) {
        if (e.bootloaderMessage?.includes("already")) {
          DebugManager.log("device already locked");
          LOGGER.info(fn, "device already locked");
          isLocked = true;
        } else {
          throw new Error(`Lock failed: ${e.message || e}`);
@@ -419,7 +431,8 @@ export class ControllerManager {
   * @returns {Promise<boolean>} True when forwarded command finishes.
   */
  async runUnknownCommand(cmd) {
    DebugManager.log(`try unknown command ${cmd.command}`);
    const fn = "runUnknownCommand";
    LOGGER.info(fn, `try unknown command ${cmd.command}`);
    await this.deviceManager.runCommand(cmd.command);
    return true;
  }
@@ -430,12 +443,13 @@ export class ControllerManager {
   * @returns {Promise<void>} Resolves when device data is loaded.
   */
  async onDeviceConnected() {
    const fn = "onDeviceConnected";
    const productName = this.deviceManager.getProductName();
    if (this.deviceManager.isFirstConnection()) {
      this.deviceManager.markAsConnected();
      this.view.updateData("product-name", productName);
      this.model = productName;
      DebugManager.log("ControllerManager Model:", this.model);
      LOGGER.info(fn, "Model", this.model);
      try {
        const resources = await this.getResources();

@@ -459,8 +473,9 @@ export class ControllerManager {
   * @returns {Promise<void>} Resolves when version is valid.
   */
  async checkAndroidVersion(versionRequired) {
    const fn = "checkAndroidVersion";
    const android = await this.deviceManager.getAndroidVersion();
    DebugManager.log("current android version:", android);
    LOGGER.info(fn, "current android version:", android);
    if (android) {
      this.view.updateData("android-version", android);
      if (android < versionRequired) {
@@ -475,6 +490,7 @@ export class ControllerManager {
   * @returns {Promise<object>} Resource object or throws device-model-not-supported.
   */
  async getResources() {
    const fn = "getResources";
    let resources = null;
    try {
      let current_security_path_level = null;
@@ -482,17 +498,18 @@ export class ControllerManager {
        const security_patch = await this.deviceManager.adb.getProp(
          "ro.build.version.security_patch",
        );
        //DebugManager.log('security_patch', security_patch)
        //LOGGER.info('security_patch', security_patch)
        current_security_path_level = parseInt(
          security_patch.replace(/-/g, ""),
          10,
        );
        DebugManager.log(
        LOGGER.info(
          fn,
          "current_security_path_level",
          current_security_path_level,
        );
      } catch {
        DebugManager.log("Security patch Error");
        LOGGER.info(fn, "Security patch Error");
        current_security_path_level = null;
      }
      let this_model = this.deviceManager.adb.banner.device;
@@ -501,7 +518,7 @@ export class ControllerManager {
      if (model.includes("Teracube") && model.includes("2e")) {
        try {
          const serial = await this.deviceManager.adb.getSerialNumber();
          DebugManager.log("serial numer:", serial);
          LOGGER.info(fn, "serial numer:", serial);
          if (serial.startsWith("2021")) {
            this_model = "emerald";
          } else if (serial.startsWith("2020")) {
@@ -536,16 +553,18 @@ export class ControllerManager {
        current_security_path_level != null &&
        typeof resources.security_patch_level != "undefined"
      ) {
        DebugManager.log(
        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,
        );
        DebugManager.log(`New security patch ${new_security_path_level}`);
        LOGGER.info(fn, `New security patch ${new_security_path_level}`);
        if (current_security_path_level > new_security_path_level) {
          DebugManager.log(
          LOGGER.info(
            fn,
            "Bypass lock procedure",
            `resources/${this_model}-safe.json`,
          );
@@ -556,7 +575,7 @@ export class ControllerManager {
      }
    } catch (e) {
      resources = null;
      DebugManager.log("getResources Error: " + e);
      LOGGER.info(fn, "getResources Error: " + e);
      throw Error("device-model-not-supported");
    }

+90 −14
Original line number Diff line number Diff line
import { Log } from "./utils/log.class.js";

/**
 * Centralized debug logger used by controller components.
 */
export class DebugManager {
  constructor() {}
  /**
   * Creates a scoped logger bound to one origin string.
   *
   * @param {string} origin Source label for all logs emitted by this logger.
   * @returns {{info: (functionName: string, ...args: any[]) => void, verbose: (functionName: string, ...args: any[]) => void, warn: (functionName: string, ...args: any[]) => void, error: (functionName: string, ...args: any[]) => void}} Logger methods bound to origin.
   */
  static getLogger(origin) {
    if (!origin || typeof origin !== "string") {
      throw new Error(
        new Date(),
        "DebugManager.getLogger requires a non-empty origin",
      );
    }

    /**
   * Writes a debug message to the console.
     * Emits a log line built from the Log class.
     *
     * @param {"INFO"|"VERBOSE"|"WARN"|"ERROR"} type Log level.
     * @param {string} fn Function name where the log is emitted.
     * @param {...any} args Values to log.
     * @returns {void}
     */
  static log(...args) {
    console.log("[DEBUG]", ...args);
    const emit = (type, fn, ...args) => {
      const log = new Log(
        type,
        `${origin}.${fn}`,
        args.map((arg) => String(arg)).join(" "),
      );

      if (type === "WARN") {
        console.warn(log.toString());
        return;
      }

      if (type === "ERROR") {
        console.error(log.toString());
        return;
      }

      console.log(log.toString());
    };

    /**
     * Logs an info message.
     *
     * @param {string} fn Function name where the log is emitted.
     * @param {...any} args Values to log.
     * @returns {void}
     */
    const info = (fn, ...args) => {
      emit("INFO", fn, ...args);
    };

    /**
   * Writes an error message to the console.
     * Logs a verbose message.
     *
   * @param {...any} args Values to log as an error.
     * @param {string} fn Function name where the log is emitted.
     * @param {...any} args Values to log.
     * @returns {void}
     */
    const verbose = (fn, ...args) => {
      emit("VERBOSE", fn, ...args);
    };

    /**
     * Logs a warning message.
     *
     * @param {string} fn Function name where the log is emitted.
     * @param {...any} args Values to log.
     * @returns {void}
     */
  static error(...args) {
    console.error("[ERROR]", ...args);
    const warn = (fn, ...args) => {
      emit("WARN", fn, ...args);
    };

    /**
     * Logs an error message.
     *
     * @param {string} fn Function name where the log is emitted.
     * @param {...any} args Values to log.
     * @returns {void}
     */
    const error = (fn, ...args) => {
      emit("ERROR", fn, ...args);
    };

    return {
      info,
      verbose,
      warn,
      error,
    };
  }
}
+17 −17
Original line number Diff line number Diff line
@@ -6,13 +6,12 @@ import { Device } from "./device/device.class.js";
import { DebugManager } from "./debug.manager.js";
import { MODE } from "./enums/mode.enum.js";

const LOGGER = DebugManager.getLogger("DeviceManager");

/**
 * Facade over ADB, bootloader, recovery and download operations.
 */
export class DeviceManager {
  /**
   * Creates a new DeviceManager and initializes all sub-managers.
   */
  constructor() {
    this.model = "";
    this.rom = undefined;
@@ -334,31 +333,33 @@ export class DeviceManager {
   * @returns {Promise<void>} Resolves when device appears or timeout expires.
   */
  waitForDeviceOnBus(timeoutMs = 30000) {
    const fn = "waitForDeviceOnBus";
    const startTime = Date.now();
    return new Promise((resolve) => {
      const devices = navigator.usb.getDevices();
      devices.then((list) => {
        DebugManager.log(
          `waitForDeviceOnBus: getDevices() returned ${list.length} device(s)`,
        LOGGER.info(
          fn,
          `getDevices() returned ${list.length} device(s)`,
          list.map((d) => `${d.vendorId}:${d.productId} "${d.productName}"`),
        );
        if (list.length > 0) {
          DebugManager.log(
            "waitForDeviceOnBus: device already visible, no wait needed",
          );
          LOGGER.info(fn, "Device already visible, no wait needed");
          resolve();
          return;
        }

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

        const timeout = setTimeout(() => {
          navigator.usb.removeEventListener("connect", onConnect);
          const elapsed = Date.now() - startTime;
          DebugManager.log(
            `waitForDeviceOnBus: timeout after ${elapsed}ms, no device appeared. Proceeding anyway.`,
          LOGGER.info(
            fn,
            `Timeout after ${elapsed}ms, no device appeared. Proceeding anyway.`,
          );
          resolve();
        }, timeoutMs);
@@ -366,17 +367,16 @@ export class DeviceManager {
        const onConnect = (event) => {
          const elapsed = Date.now() - startTime;
          const d = event.device;
          DebugManager.log(
            `waitForDeviceOnBus: USB connect event after ${elapsed}ms - ` +
          LOGGER.info(
            fn,
            `USB connect event after ${elapsed}ms - ` +
              `vendorId=${d.vendorId} productId=${d.productId} ` +
              `productName="${d.productName}" serialNumber="${d.serialNumber}"`,
          );
          clearTimeout(timeout);
          navigator.usb.removeEventListener("connect", onConnect);
          // Small delay to let the device fully initialize after enumeration
          DebugManager.log(
            "waitForDeviceOnBus: waiting 1000ms for device to stabilize...",
          );
          LOGGER.info(fn, "Waiting 1000ms for device to stabilize...");
          setTimeout(resolve, 1000);
        };

+15 −9
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@ import { Device } from "./device.class.js";
import { DebugManager } from "../debug.manager.js";
import { AdbDevice } from "../../lib/index.ts";

const LOGGER = DebugManager.getLogger("ADB");

/**
 * ADB mode implementation backed by `AdbDevice`.
 */
@@ -29,8 +31,9 @@ export class ADB extends Device {
   * @returns {Promise<void>} Resolves when the device is connected.
   */
  async connect() {
    const fn = "connect";
    try {
      console.log("debug adb connect");
      LOGGER.info(fn);

      // Try to find a paired device first, then request if needed
      this._adbDevice = await AdbDevice.requestDevice();
@@ -39,14 +42,14 @@ export class ADB extends Device {
      this.device = { name: this._adbDevice.usbDevice.productName };

      const banner = this._adbDevice.banner;
      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("----------------------------------");
      LOGGER.info(fn, "----------------------------------");
      LOGGER.info(fn, "Model", banner.model);
      LOGGER.info(fn, "product", banner.product);
      LOGGER.info(fn, "Name", this._adbDevice.usbDevice.productName);
      LOGGER.info(fn, ">Device (codename)", banner.device);
      LOGGER.info(fn, "----------------------------------");
    } catch (e) {
      console.error(e);
      LOGGER.error(fn, `Cannot connect ADB ${e.message || e}`);
      this.device = null;
      throw new Error(`Cannot connect ADB ${e.message || e}`);
    }
@@ -105,7 +108,8 @@ export class ADB extends Device {
   * @returns {Promise<any>} Shell command result.
   */
  async runCommand(cmd) {
    DebugManager.log("ADB Run command>", cmd);
    const fn = "runCommand";
    LOGGER.info(fn, cmd);
    return await this._adbDevice.shell(cmd);
  }

@@ -116,6 +120,8 @@ export class ADB extends Device {
   * @returns {Promise<any>} Reboot command result.
   */
  async reboot(mode) {
    const fn = "reboot";
    LOGGER.info(fn, mode);
    return await this._adbDevice.reboot(mode);
  }
}
+51 −48

File changed.

Preview size limit exceeded, changes collapsed.

Loading