@aepyornis/fastboot.ts 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -27
- package/package.json +1 -1
- package/src/client.ts +50 -4
- package/src/flasher.ts +17 -0
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# fastboot.ts
|
|
2
2
|
|
|
3
|
+
Android Fastboot implementation for WebUSB
|
|
4
|
+
|
|
3
5
|
```sh
|
|
4
6
|
npm install
|
|
5
7
|
npm run build
|
|
@@ -11,7 +13,7 @@ npm run build
|
|
|
11
13
|
src/sparse.ts sparse image utilities Copyright (c) 2021 Danny Lin <danny@kdrag0n.dev>
|
|
12
14
|
|
|
13
15
|
```js
|
|
14
|
-
import { FastbootClient,
|
|
16
|
+
import { FastbootClient, FastbootFlasher } from "@aepyornis/fastboot.ts"
|
|
15
17
|
|
|
16
18
|
const client = await FastbootClient.create()
|
|
17
19
|
|
|
@@ -21,31 +23,12 @@ await client.getVar("product")
|
|
|
21
23
|
|
|
22
24
|
// flash CalyxOS
|
|
23
25
|
import OpfsBlobStore from "@aepyornis/opfs_blob_store"
|
|
24
|
-
const
|
|
25
|
-
const hash = "
|
|
26
|
-
const url = "https://release.calyxinstitute.org/
|
|
27
|
-
await
|
|
28
|
-
const file = await
|
|
29
|
-
|
|
30
|
-
const instructions = `
|
|
31
|
-
fastboot --set-active=other reboot-bootloader
|
|
32
|
-
sleep 5
|
|
33
|
-
fastboot flash --slot=other bootloader bootloader-lynx-lynx-15.2-12878710.img
|
|
34
|
-
fastboot --set-active=other reboot-bootloader
|
|
35
|
-
sleep 5
|
|
36
|
-
fastboot flash --slot=other radio radio-lynx-g5300q-241205-250127-B-12973597.img
|
|
37
|
-
fastboot --set-active=other reboot-bootloader
|
|
38
|
-
sleep 5
|
|
39
|
-
fastboot flash --slot=other radio radio-lynx-g5300q-241205-250127-B-12973597.img
|
|
40
|
-
fastboot --set-active=other reboot-bootloader
|
|
41
|
-
sleep 5
|
|
42
|
-
fastboot erase avb_custom_key
|
|
43
|
-
fastboot flash avb_custom_key avb_custom_key.img
|
|
44
|
-
fastboot --skip-reboot -w update image-lynx-bp1a.250305.019.zip
|
|
45
|
-
fastboot reboot-bootloader
|
|
46
|
-
`
|
|
47
|
-
|
|
26
|
+
const opfs = await OpfsBlobStore.create()
|
|
27
|
+
const hash = "db9ab330a1b5d5ebf131f378dca8b5f6400337f438a97aef2a09a1ba88f3935c"
|
|
28
|
+
const url = "https://release.calyxinstitute.org/bangkk-factory-25608210.zip"
|
|
29
|
+
await opfs.fetch(hash, url)
|
|
30
|
+
const file = await opfs.get(hash)
|
|
48
31
|
const client = await FastbootClient.create()
|
|
49
|
-
const deviceFlasher = new FastbootFlasher()
|
|
50
|
-
await deviceFlasher.
|
|
32
|
+
const deviceFlasher = new FastbootFlasher(client, file)
|
|
33
|
+
await deviceFlasher.runFlashAll()
|
|
51
34
|
```
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BlobWriter, Entry } from "@zip.js/zip.js"
|
|
2
2
|
import { IMAGES } from "./images"
|
|
3
3
|
import { parseBlobHeader, splitBlob, fromRaw } from "./sparse"
|
|
4
|
-
import { FastbootDevice } from "./device"
|
|
4
|
+
import { FastbootDevice, FastbootDeviceError } from "./device"
|
|
5
5
|
|
|
6
6
|
export class FastbootError extends Error {}
|
|
7
7
|
|
|
@@ -20,16 +20,27 @@ interface Logger {
|
|
|
20
20
|
export class FastbootClient {
|
|
21
21
|
fd: FastbootDevice
|
|
22
22
|
logger: Logger
|
|
23
|
+
var_cache: Object
|
|
23
24
|
|
|
24
25
|
constructor(usb_device: USBDevice, logger: Logger = window.console) {
|
|
25
26
|
this.fd = new FastbootDevice(usb_device, logger)
|
|
26
27
|
this.logger = logger
|
|
28
|
+
this.var_cache = {}
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
async getVar(variable: string) {
|
|
30
32
|
return this.fd.getVar(variable)
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
async getVarCache(variable: string) {
|
|
36
|
+
if (this.var_cache[variable]) {
|
|
37
|
+
return this.var_cache[variable]
|
|
38
|
+
} else {
|
|
39
|
+
this.var_cache[variable] = await this.getVar(variable)
|
|
40
|
+
return this.var_cache[variable]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
33
44
|
async lock() {
|
|
34
45
|
await this.flashing("lock")
|
|
35
46
|
if (await this.unlocked()) {
|
|
@@ -139,7 +150,6 @@ export class FastbootClient {
|
|
|
139
150
|
) {
|
|
140
151
|
return true
|
|
141
152
|
}
|
|
142
|
-
|
|
143
153
|
this.logger.log(`ACTION NEEDED: flashing ${command}`)
|
|
144
154
|
await this.fd.exec(`flashing ${command}`)
|
|
145
155
|
await this.fd.waitForReconnect()
|
|
@@ -273,11 +283,21 @@ export class FastbootClient {
|
|
|
273
283
|
}
|
|
274
284
|
|
|
275
285
|
async unlocked() {
|
|
276
|
-
|
|
286
|
+
const product = await this.getVarCache("product")
|
|
287
|
+
if (product === "bangkk") {
|
|
288
|
+
return (await this.getVar("securestate")) === "flashing_unlocked"
|
|
289
|
+
} else {
|
|
290
|
+
return (await this.getVar("unlocked")) === "yes"
|
|
291
|
+
}
|
|
277
292
|
}
|
|
278
293
|
|
|
279
294
|
async locked() {
|
|
280
|
-
|
|
295
|
+
const product = await this.getVarCache("product")
|
|
296
|
+
if (product === "bangkk") {
|
|
297
|
+
return (await this.getVar("securestate")) === "flashing_locked"
|
|
298
|
+
} else {
|
|
299
|
+
return (await this.getVar("unlocked")) === "no"
|
|
300
|
+
}
|
|
281
301
|
}
|
|
282
302
|
|
|
283
303
|
async currentSlot() {
|
|
@@ -301,6 +321,32 @@ export class FastbootClient {
|
|
|
301
321
|
return (await this.getVar("is-userspace")) === "yes"
|
|
302
322
|
}
|
|
303
323
|
|
|
324
|
+
// tested on bangkk only
|
|
325
|
+
async getUnlockData() {
|
|
326
|
+
await client.fd.exec(`oem get_unlock_data`)
|
|
327
|
+
|
|
328
|
+
let data = ""
|
|
329
|
+
|
|
330
|
+
for (let packet of client.fd.session.packets) {
|
|
331
|
+
if (packet.command) {
|
|
332
|
+
continue
|
|
333
|
+
} else if (packet.status === "INFO") {
|
|
334
|
+
let message = packet.message.replace("(bootloader)", "").trim()
|
|
335
|
+
if (message === "Unlock data:") {
|
|
336
|
+
continue
|
|
337
|
+
} else {
|
|
338
|
+
data += message
|
|
339
|
+
}
|
|
340
|
+
} else if (packet.status === "OKAY") {
|
|
341
|
+
break
|
|
342
|
+
} else {
|
|
343
|
+
throw new Error(`packet status == ${packet.status}`)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return data
|
|
348
|
+
}
|
|
349
|
+
|
|
304
350
|
static async create() {
|
|
305
351
|
return new FastbootClient(await this.requestUsbDevice(), window.console)
|
|
306
352
|
}
|
package/src/flasher.ts
CHANGED
|
@@ -101,6 +101,23 @@ export class FastbootFlasher {
|
|
|
101
101
|
this.reader = new ZipReader(new BlobReader(blob))
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
// parses and runs flash-all.sh. it ignores all shell commands
|
|
105
|
+
// except fastboot or sleep
|
|
106
|
+
async runFlashAll() {
|
|
107
|
+
const entries: Entry[] = await this.reader.getEntries()
|
|
108
|
+
const flashAllSh = await getEntry(entries, "flash-all.sh").getData(
|
|
109
|
+
new TextWriter(),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
const instructions = flashAllSh
|
|
113
|
+
.split("\n")
|
|
114
|
+
.map((x) => x.trim())
|
|
115
|
+
.filter((x) => x.slice(0, 9) === "fastboot " || x.slice(0, 5) === "sleep")
|
|
116
|
+
.join("\n")
|
|
117
|
+
|
|
118
|
+
return this.run(instructions)
|
|
119
|
+
}
|
|
120
|
+
|
|
104
121
|
async run(instructions: text) {
|
|
105
122
|
const entries: Entry[] = await this.reader.getEntries() // io with factory.zip
|
|
106
123
|
const commands: Instruction[] = parseInstructions(instructions)
|