@aepyornis/fastboot.ts 0.0.4 → 0.0.6

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 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,11 @@ 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, FashbootFlasher } from "@aepyornis/fastboot.ts"
16
+ import {
17
+ FastbootDevice,
18
+ FastbootClient,
19
+ FastbootFlasher,
20
+ } from "@aepyornis/fastboot.ts"
15
21
 
16
22
  const client = await FastbootClient.create()
17
23
 
@@ -21,31 +27,12 @@ await client.getVar("product")
21
27
 
22
28
  // flash CalyxOS
23
29
  import OpfsBlobStore from "@aepyornis/opfs_blob_store"
24
- const bs = await OpfsBlobStore.create()
25
- const hash = "a4434edb21e5e12a00ab9949f48f06c48169adcaeb4dce644857e1528b275274"
26
- const url = "https://release.calyxinstitute.org/lynx-factory-25605200.zip"
27
- await bs.fetch(hash, url)
28
- const file = await bs.get(hash)
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
-
30
+ const opfs = await OpfsBlobStore.create()
31
+ const hash = "db9ab330a1b5d5ebf131f378dca8b5f6400337f438a97aef2a09a1ba88f3935c"
32
+ const url = "https://release.calyxinstitute.org/bangkk-factory-25608210.zip"
33
+ await opfs.fetch(hash, url)
34
+ const file = await opfs.get(hash)
48
35
  const client = await FastbootClient.create()
49
- const deviceFlasher = new FastbootFlasher()
50
- await deviceFlasher.run(instructions)
36
+ const deviceFlasher = new FastbootFlasher(client, file)
37
+ await deviceFlasher.runFlashAll()
51
38
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aepyornis/fastboot.ts",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Fastboot using WebUSB",
5
5
  "main": "src/index.ts",
6
6
  "scripts": {
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,10 +150,16 @@ 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
- await this.fd.waitForReconnect()
155
+
156
+ // some devices register before we have a chance to call
157
+ // waitForReconnect()
158
+ if ((await navigator.usb.getDevices()).length > 0) {
159
+ await this.fd.reconnect()
160
+ } else {
161
+ await this.fd.waitForReconnect()
162
+ }
146
163
  }
147
164
 
148
165
  // run text, typically the contents of fastboot-info.txt
@@ -273,11 +290,21 @@ export class FastbootClient {
273
290
  }
274
291
 
275
292
  async unlocked() {
276
- return (await this.getVar("unlocked")) === "yes"
293
+ const product = await this.getVarCache("product")
294
+ if (product === "bangkk") {
295
+ return (await this.getVar("securestate")) === "flashing_unlocked"
296
+ } else {
297
+ return (await this.getVar("unlocked")) === "yes"
298
+ }
277
299
  }
278
300
 
279
301
  async locked() {
280
- return (await this.getVar("unlocked")) === "no"
302
+ const product = await this.getVarCache("product")
303
+ if (product === "bangkk") {
304
+ return (await this.getVar("securestate")) === "flashing_locked"
305
+ } else {
306
+ return (await this.getVar("unlocked")) === "no"
307
+ }
281
308
  }
282
309
 
283
310
  async currentSlot() {
@@ -301,6 +328,32 @@ export class FastbootClient {
301
328
  return (await this.getVar("is-userspace")) === "yes"
302
329
  }
303
330
 
331
+ // tested on bangkk only
332
+ async getUnlockData() {
333
+ await client.fd.exec(`oem get_unlock_data`)
334
+
335
+ let data = ""
336
+
337
+ for (let packet of client.fd.session.packets) {
338
+ if (packet.command) {
339
+ continue
340
+ } else if (packet.status === "INFO") {
341
+ let message = packet.message.replace("(bootloader)", "").trim()
342
+ if (message === "Unlock data:") {
343
+ continue
344
+ } else {
345
+ data += message
346
+ }
347
+ } else if (packet.status === "OKAY") {
348
+ break
349
+ } else {
350
+ throw new Error(`packet status == ${packet.status}`)
351
+ }
352
+ }
353
+
354
+ return data
355
+ }
356
+
304
357
  static async create() {
305
358
  return new FastbootClient(await this.requestUsbDevice(), window.console)
306
359
  }
package/src/flasher.ts CHANGED
@@ -57,6 +57,8 @@ function parseInstruction(text: string): Instruction {
57
57
  options.wipe = true
58
58
  } else if (word === "--set-active=other") {
59
59
  options.setActive = "other"
60
+ } else if (word === "--set-active=a" || word === "--set-active=b") {
61
+ options.setActive = word.slice(-1)
60
62
  } else if (word === "--slot-other") {
61
63
  options.slot = "other"
62
64
  } else if (word.slice(0, 6) === "--slot") {
@@ -105,12 +107,14 @@ export class FastbootFlasher {
105
107
  // except fastboot or sleep
106
108
  async runFlashAll() {
107
109
  const entries: Entry[] = await this.reader.getEntries()
108
- const flashAllSh = await getEntry(entries, "flash-all.sh").getData(new TextWriter())
110
+ const flashAllSh = await getEntry(entries, "flash-all.sh").getData(
111
+ new TextWriter(),
112
+ )
109
113
 
110
114
  const instructions = flashAllSh
111
115
  .split("\n")
112
116
  .map((x) => x.trim())
113
- .filter(x => (x.slice(0,9) === "fastboot " || x.slice(0,5) === "sleep"))
117
+ .filter((x) => x.slice(0, 9) === "fastboot " || x.slice(0, 5) === "sleep")
114
118
  .join("\n")
115
119
 
116
120
  return this.run(instructions)
@@ -141,6 +145,10 @@ export class FastbootFlasher {
141
145
  } else if (command.command === "reboot-bootloader") {
142
146
  if (command.options.setActive === "other") {
143
147
  await this.client.setActiveOtherSlot()
148
+ } else if (command.options.setActive === "a") {
149
+ await this.client.fd.exec("set_active:a")
150
+ } else if (command.options.setActive === "b") {
151
+ await this.client.fd.exec("set_active:b")
144
152
  }
145
153
  await this.client.rebootBootloader()
146
154
  } else if (command.command === "update") {
@@ -181,6 +189,19 @@ export class FastbootFlasher {
181
189
  } else if (command.command === "sleep") {
182
190
  const ms = command.args[0] ? parseInt(command.args[0]) * 1000 : 5000
183
191
  await new Promise((resolve) => setTimeout(resolve, ms))
192
+ // do_oem_command in cpp is raw command?
193
+ } else if (command.command === "oem") {
194
+ // motorola setting that does nothing useful here?
195
+ if (
196
+ command.args[0] === "fb_mode_set" ||
197
+ command.args[0] === "fb_mode_clear"
198
+ ) {
199
+ await new Promise((resolve) => setTimeout(resolve, 10))
200
+ } else {
201
+ throw new Error(
202
+ `Fastboot oem command ${command.args[0]} not implemented`,
203
+ )
204
+ }
184
205
  } else {
185
206
  throw new Error(`Fastboot command ${command.command} not implemented`)
186
207
  }