Loading app/index.html +1 −1 Original line number Diff line number Diff line Loading @@ -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"> Loading app/src/controller.manager.js→app/src/controller/controller.manager.js +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), Loading Loading @@ -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 Loading @@ -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); Loading @@ -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; Loading @@ -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]; Loading Loading @@ -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) => { Loading @@ -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 { Loading @@ -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, Loading @@ -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 + " " + Loading @@ -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)); Loading @@ -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}`); Loading @@ -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); Loading @@ -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(); Loading @@ -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(); Loading @@ -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) { Loading @@ -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; Loading @@ -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")) { Loading Loading @@ -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`, ); Loading @@ -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"); } Loading app/src/debug.js→app/src/controller/debug.manager.js +1 −1 Original line number Diff line number Diff line export class WDebug { export class DebugManager { constructor() {} static log(...args) { Loading app/src/controller/device.manager.js +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 Loading @@ -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; } Loading Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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}"`, Loading @@ -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); Loading app/src/controller/device/adb.class.js +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 { Loading @@ -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; Loading Loading @@ -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 Loading
app/index.html +1 −1 Original line number Diff line number Diff line Loading @@ -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"> Loading
app/src/controller.manager.js→app/src/controller/controller.manager.js +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), Loading Loading @@ -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 Loading @@ -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); Loading @@ -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; Loading @@ -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]; Loading Loading @@ -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) => { Loading @@ -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 { Loading @@ -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, Loading @@ -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 + " " + Loading @@ -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)); Loading @@ -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}`); Loading @@ -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); Loading @@ -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(); Loading @@ -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(); Loading @@ -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) { Loading @@ -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; Loading @@ -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")) { Loading Loading @@ -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`, ); Loading @@ -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"); } Loading
app/src/debug.js→app/src/controller/debug.manager.js +1 −1 Original line number Diff line number Diff line export class WDebug { export class DebugManager { constructor() {} static log(...args) { Loading
app/src/controller/device.manager.js +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 Loading @@ -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; } Loading Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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}"`, Loading @@ -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); Loading
app/src/controller/device/adb.class.js +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 { Loading @@ -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; Loading Loading @@ -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