diff --git a/app/public/resources/GS290.json b/app/public/resources/GS290.json index 71e1e904cb3bd553345f802e7ed21189b250609f..e3fdb54c0209c1d24208d3d9e776b2dc0dea0a31 100644 --- a/app/public/resources/GS290.json +++ b/app/public/resources/GS290.json @@ -1,41 +1,51 @@ { "$schema": "../schemas/devices.schema.json", + "skip_clear_halt": true, "steps": [ { - "mode": "bootloader", + "command": ["reboot bootloader", "delay 15"] + }, + { "id": "connect-bootloader", - "command": ["connect bootloader", "flashing unlock unlocked"], + "command": ["connect bootloader"], "needUserGesture": true }, { "id": "unlocking-gs290", - "needUserGesture": true + "needUserGesture": true, + "command": ["flashing unlock goto_flashing", "delay 5"] }, { "id": "flashing", "mode": "bootloader", "command": [ - "flash system system.img", - "flash vendor vendor.img", "flash boot boot.img", "flash dtbo dtbo.img", "flash recovery recovery.img", - "flash logo logo.img", - "flash md1dsp md1dsp.img", - "flash md1img md1img.img", - "flash spmfw spmfw.img", - "flash lk lk.img", - "flash lk2 lk.img", - "flash sspm_1 sspm.img", - "flash sspm_2 sspm.img", - "flash tee1 trustzone1.bin", - "flash tee2 trustzone2.bin", - "flash preloader preloader.img", - "erase userdata", - "erase metadata", - "reboot adb" + "reboot recovery" ] }, + { + "id": "format-device", + "needUserGesture": true + }, + { + "id": "go-to-apply-update", + "needUserGesture": true + }, + { + "id": "sideload", + "command": "sideload GS290-sideload-rom.zip" + }, + { + "id": "sideload-ended", + "needUserGesture": true + }, + { + "id": "connect-bootloader", + "command": ["connect bootloader", "reboot"], + "needUserGesture": true + }, { "id": "murena-workspace-account", "needUserGesture": true @@ -46,9 +56,18 @@ ], "folder": [ { - "name": "GS290 installer", + "name": "GS290-recovery-images.zip", + "path": "https://images.ecloud.global/official/GS290/recovery-IMG-e-latest-a15-official-GS290.zip", "unzip": true, - "path": "https://images.ecloud.global/official/GS290/IMG-e-latest-s-official-GS290.zip" + "mapping": { + "^dtbo.*img$": "dtbo.img", + "^boot.*img$": "boot.img", + "^recovery.*img$": "recovery.img" + } + }, + { + "name": "GS290-sideload-rom.zip", + "path": "https://images.ecloud.global/official/GS290/e-latest-a15-official-GS290.zip" } ] } diff --git a/app/src/controller/controller.manager.js b/app/src/controller/controller.manager.js index 2d0a0a2bd3131c6da5d04145e82f78dab1c89947..7fd6149c5e5114f77b57b3490dcdaedc68e405e5 100644 --- a/app/src/controller/controller.manager.js +++ b/app/src/controller/controller.manager.js @@ -374,7 +374,9 @@ export class ControllerManager { async runSideloadCommand(cmd) { try { await this.deviceManager.connect("recovery"); - await this.deviceManager.sideload(cmd.file); + await this.deviceManager.sideload(cmd.file, (block, total) => { + this.view.onInstalling(cmd.file, block, total); + }); return true; } catch (e) { throw new Error(`Sideload ${cmd.file} failed: ${e.message || e}`); diff --git a/app/src/controller/device.manager.js b/app/src/controller/device.manager.js index c84d417e94eafd38ff3adf7f5178746e2d38d96e..9ef661c5e2549ef7a16598b890a571c5b19ed7d5 100644 --- a/app/src/controller/device.manager.js +++ b/app/src/controller/device.manager.js @@ -301,13 +301,13 @@ export class DeviceManager { * @param {string} file Filename in downloader cache. * @returns {Promise} Sideload result from the active device. */ - async sideload(file) { + async sideload(file, onProgress) { let blob = await this.downloader.getFile(file); if (!blob) { throw new Error(`error getting blob file ${file}`); } - return await this.device.sideload(blob); + return await this.device.sideload(blob, onProgress); } /** diff --git a/app/src/controller/device/recovery.class.js b/app/src/controller/device/recovery.class.js index b6f8c4435ed9a57919b022e4b875af3d7d636e94..ddb7a200bd2488295ad55f8561e419f475ca7e68 100644 --- a/app/src/controller/device/recovery.class.js +++ b/app/src/controller/device/recovery.class.js @@ -49,12 +49,13 @@ export class Recovery extends Device { * @param {Blob} blob Zip blob to sideload. * @returns {Promise} Resolves when sideload completes. */ - async sideload(blob) { + async sideload(blob, onProgress) { try { await this._adbDevice.sideload(blob, (block, totalBlocks) => { if (block % 10 === 0) { DebugManager.log(`Sideloading block ${block}/${totalBlocks}`); } + onProgress?.(block, totalBlocks); }); } catch (e) { throw new Error(`Sideload fails ${e.message || e}`); diff --git a/app/src/lib/adb/adb-device.ts b/app/src/lib/adb/adb-device.ts index 360c719377b6d86e380918167dfc34bba9107518..ef08267a5d75adba4ac8ec82e3c33bec7da32248 100644 --- a/app/src/lib/adb/adb-device.ts +++ b/app/src/lib/adb/adb-device.ts @@ -234,10 +234,13 @@ export class AdbDevice { onProgress?: SideloadProgressCallback, ): Promise { this.ensureConnected(); + // Set 5min as uperbound timeout; userdebug devices stop sending ack after vertification stage + // and actual install starts after that. + const SIDELOAD_TIMEOUT_MS = 5 * 60_000; await performSideload( this._transport, blob, - () => this.receivePacket(), + () => readPacket((length) => this._transport.receiveWithTimeout(length, SIDELOAD_TIMEOUT_MS)), undefined, onProgress, ); diff --git a/app/src/view/view.manager.js b/app/src/view/view.manager.js index 56505921b5600903aae18c62d79b587590711a0a..0ff7c454d0d9e11ae67f74cd4067f5b2bfeb1a7d 100644 --- a/app/src/view/view.manager.js +++ b/app/src/view/view.manager.js @@ -323,7 +323,7 @@ export default class ViewManager { $progress.innerText = `Installing ${name}: ${v}/${100}`; } this.DebugManager.log( - `Installing ${name}: ${Math.round(v * 100)}/${100}`, + `Installing ${name}: ${v}/${100}`, `installing-${name}`, ); }