@aepyornis/fastboot.ts 0.0.1
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/.prettierignore +1 -0
- package/.prettierrc.json +3 -0
- package/README.md +56 -0
- package/eslint.config.mjs +10 -0
- package/package.json +27 -0
- package/src/client.ts +344 -0
- package/src/device.ts +258 -0
- package/src/flasher.ts +174 -0
- package/src/images.ts +218 -0
- package/src/index.ts +3 -0
- package/src/sparse.ts +408 -0
- package/tsconfig.json +15 -0
package/src/flasher.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ZipReader,
|
|
3
|
+
BlobReader,
|
|
4
|
+
BlobWriter,
|
|
5
|
+
TextWriter,
|
|
6
|
+
Entry,
|
|
7
|
+
} from "@zip.js/zip.js"
|
|
8
|
+
import type { FastbootClient } from "./client"
|
|
9
|
+
|
|
10
|
+
type CommandName =
|
|
11
|
+
| "update"
|
|
12
|
+
| "flashall"
|
|
13
|
+
| "flash"
|
|
14
|
+
| "flashing"
|
|
15
|
+
| "erase"
|
|
16
|
+
| "format"
|
|
17
|
+
| "getvar"
|
|
18
|
+
| "set_active"
|
|
19
|
+
| "boot"
|
|
20
|
+
| "devices"
|
|
21
|
+
| "continue"
|
|
22
|
+
| "reboot"
|
|
23
|
+
| "reboot-bootloader"
|
|
24
|
+
| "help"
|
|
25
|
+
|
|
26
|
+
type Instruction = {
|
|
27
|
+
command: CommandName
|
|
28
|
+
args: string[]
|
|
29
|
+
options: object
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getEntry(entries: Entry[], filename: string): Entry {
|
|
33
|
+
const entry = entries.find(
|
|
34
|
+
(e) => e.filename.split(/[\\/]/).pop() === filename,
|
|
35
|
+
)
|
|
36
|
+
if (entry) {
|
|
37
|
+
return entry
|
|
38
|
+
} else {
|
|
39
|
+
throw new Error(`${filename} not found in zip`)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseInstruction(text: string): Instruction {
|
|
44
|
+
if (text.slice(0, 8) === "fastboot") {
|
|
45
|
+
text = text.slice(8).trim()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let command: CommandName
|
|
49
|
+
const args = []
|
|
50
|
+
const options = {}
|
|
51
|
+
|
|
52
|
+
const words = text.split(" ").map((x) => x.trim())
|
|
53
|
+
|
|
54
|
+
for (const word of words) {
|
|
55
|
+
if (word[0] === "-") {
|
|
56
|
+
if (word === "-w" || word === "--wipe") {
|
|
57
|
+
options.wipe = true
|
|
58
|
+
} else if (word === "--set-active=other") {
|
|
59
|
+
options.setActive = "other"
|
|
60
|
+
} else if (word === '--slot-other') {
|
|
61
|
+
options.slot = 'other'
|
|
62
|
+
} else if (word.slice(0, 6) === "--slot") {
|
|
63
|
+
const slot = word.split("=")[1]
|
|
64
|
+
if (!["current", "other", "a", "b"].includes(slot)) {
|
|
65
|
+
throw new Error(`unknown slot: ${slot}`)
|
|
66
|
+
}
|
|
67
|
+
options.slot = slot
|
|
68
|
+
} else if (word === "--skip-reboot") {
|
|
69
|
+
options.skipReboot = true
|
|
70
|
+
} else if (word === "--apply-vbmeta") {
|
|
71
|
+
options.applyVbmeta = true
|
|
72
|
+
} else {
|
|
73
|
+
console.warn(`Unknown option: ${word}`)
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
if (command) {
|
|
77
|
+
args.push(word)
|
|
78
|
+
} else {
|
|
79
|
+
command = word
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { command, args, options }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function parseInstructions(text: string): Instruction[] {
|
|
87
|
+
return text
|
|
88
|
+
.split("\n")
|
|
89
|
+
.map((x) => x.trim())
|
|
90
|
+
.filter((x) => x !== "")
|
|
91
|
+
.filter((x) => x[0] !== "#")
|
|
92
|
+
.map(parseInstruction)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class FastbootFlasher {
|
|
96
|
+
client: FastbootClient
|
|
97
|
+
reader: ZipReader
|
|
98
|
+
|
|
99
|
+
constructor(client: FastbootClient, blob: Blob) {
|
|
100
|
+
this.client = client
|
|
101
|
+
this.reader = new ZipReader(new BlobReader(blob))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async run(instructions: text) {
|
|
105
|
+
const entries: Entry[] = await this.reader.getEntries() // io with factory.zip
|
|
106
|
+
const commands: Instruction[] = parseInstructions(instructions)
|
|
107
|
+
console.log(commands)
|
|
108
|
+
|
|
109
|
+
for (const command of commands) {
|
|
110
|
+
this.client.logger.log(`‣ ${JSON.stringify(command)}`)
|
|
111
|
+
if (command.command === "flash") {
|
|
112
|
+
const partition = command.args[0]
|
|
113
|
+
const filename = command.args[1]
|
|
114
|
+
const slot = command.options.slot || "current"
|
|
115
|
+
const entry = getEntry(entries, filename)
|
|
116
|
+
const blob = await entry.getData(
|
|
117
|
+
new BlobWriter("application/octet-stream"),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
await this.client.doFlash(
|
|
121
|
+
partition,
|
|
122
|
+
blob,
|
|
123
|
+
slot,
|
|
124
|
+
Boolean(command.options.applyVbmeta),
|
|
125
|
+
)
|
|
126
|
+
} else if (command.command === "reboot-bootloader") {
|
|
127
|
+
if (command.options.setActive === "other") {
|
|
128
|
+
await this.client.setActiveOtherSlot()
|
|
129
|
+
}
|
|
130
|
+
await this.client.rebootBootloader()
|
|
131
|
+
} else if (command.command === "update") {
|
|
132
|
+
const nestedZipEntry = getEntry(entries, command.args[0])
|
|
133
|
+
const zipBlob = await nestedZipEntry.getData(
|
|
134
|
+
new BlobWriter("application/zip"),
|
|
135
|
+
)
|
|
136
|
+
const zipReader = new ZipReader(new BlobReader(zipBlob))
|
|
137
|
+
const nestedEntries = await zipReader.getEntries()
|
|
138
|
+
const fastbootInfoFile = nestedEntries.find(
|
|
139
|
+
(e) => e.filename === "fastboot-info.txt",
|
|
140
|
+
)
|
|
141
|
+
const fastbootInfoText = await fastbootInfoFile.getData(
|
|
142
|
+
new TextWriter(),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
this.client.logger.log(`fastboot-info.txt: ${fastbootInfoText}`)
|
|
146
|
+
|
|
147
|
+
// fastboot -w update image-lynx-bp1a.250305.019.zip
|
|
148
|
+
await this.client.fastbootInfo(
|
|
149
|
+
nestedEntries,
|
|
150
|
+
fastbootInfoText,
|
|
151
|
+
Boolean(command.options.wipe),
|
|
152
|
+
)
|
|
153
|
+
} else if (command.command === "flashing") {
|
|
154
|
+
if (command.args[0] === "lock") {
|
|
155
|
+
await this.client.lock()
|
|
156
|
+
} else if (command.args[0] === "unlock") {
|
|
157
|
+
await this.client.unlock()
|
|
158
|
+
} else {
|
|
159
|
+
throw new Error(`Unknown command`)
|
|
160
|
+
}
|
|
161
|
+
} else if (command.command === "getvar") {
|
|
162
|
+
const clientVar = await this.client.getVar(command.args[0])
|
|
163
|
+
this.client.logger(`getVar(${command.args[0]}) => ${clientVar}`)
|
|
164
|
+
} else if (command.command === "erase") {
|
|
165
|
+
await this.client.erase(command.args[0])
|
|
166
|
+
} else if (command.command === "sleep") {
|
|
167
|
+
const ms = command.args[0] ? parseInt(command.args[0]) * 1000 : 5000
|
|
168
|
+
await new Promise((resolve) => setTimeout(resolve, ms))
|
|
169
|
+
} else {
|
|
170
|
+
throw new Error(`Fastboot command ${command.command} not implemented`)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
package/src/images.ts
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
export const IMAGES = [
|
|
2
|
+
{
|
|
3
|
+
nickname: "boot",
|
|
4
|
+
img_name: "boot.img",
|
|
5
|
+
sig_name: "boot.sig",
|
|
6
|
+
part_name: "boot",
|
|
7
|
+
optional: false,
|
|
8
|
+
type: "BootCritical",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
nickname: "bootloader",
|
|
12
|
+
img_name: "bootloader.img",
|
|
13
|
+
sig_name: "",
|
|
14
|
+
part_name: "bootloader",
|
|
15
|
+
optional: true,
|
|
16
|
+
type: "Extra",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
nickname: "init_boot",
|
|
20
|
+
img_name: "init_boot.img",
|
|
21
|
+
sig_name: "init_boot.sig",
|
|
22
|
+
part_name: "init_boot",
|
|
23
|
+
optional: true,
|
|
24
|
+
type: "BootCritical",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
nickname: "",
|
|
28
|
+
img_name: "boot_other.img",
|
|
29
|
+
sig_name: "boot.sig",
|
|
30
|
+
part_name: "boot",
|
|
31
|
+
optional: true,
|
|
32
|
+
type: "Normal",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
nickname: "cache",
|
|
36
|
+
img_name: "cache.img",
|
|
37
|
+
sig_name: "cache.sig",
|
|
38
|
+
part_name: "cache",
|
|
39
|
+
optional: true,
|
|
40
|
+
type: "Extra",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
nickname: "dtbo",
|
|
44
|
+
img_name: "dtbo.img",
|
|
45
|
+
sig_name: "dtbo.sig",
|
|
46
|
+
part_name: "dtbo",
|
|
47
|
+
optional: true,
|
|
48
|
+
type: "BootCritical",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
nickname: "dts",
|
|
52
|
+
img_name: "dt.img",
|
|
53
|
+
sig_name: "dt.sig",
|
|
54
|
+
part_name: "dts",
|
|
55
|
+
optional: true,
|
|
56
|
+
type: "BootCritical",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
nickname: "odm",
|
|
60
|
+
img_name: "odm.img",
|
|
61
|
+
sig_name: "odm.sig",
|
|
62
|
+
part_name: "odm",
|
|
63
|
+
optional: true,
|
|
64
|
+
type: "Normal",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
nickname: "odm_dlkm",
|
|
68
|
+
img_name: "odm_dlkm.img",
|
|
69
|
+
sig_name: "odm_dlkm.sig",
|
|
70
|
+
part_name: "odm_dlkm",
|
|
71
|
+
optional: true,
|
|
72
|
+
type: "Normal",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
nickname: "product",
|
|
76
|
+
img_name: "product.img",
|
|
77
|
+
sig_name: "product.sig",
|
|
78
|
+
part_name: "product",
|
|
79
|
+
optional: true,
|
|
80
|
+
type: "Normal",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
nickname: "pvmfw",
|
|
84
|
+
img_name: "pvmfw.img",
|
|
85
|
+
sig_name: "pvmfw.sig",
|
|
86
|
+
part_name: "pvmfw",
|
|
87
|
+
optional: true,
|
|
88
|
+
type: "BootCritical",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
nickname: "radio",
|
|
92
|
+
img_name: "radio.img",
|
|
93
|
+
sig_name: "",
|
|
94
|
+
part_name: "radio",
|
|
95
|
+
optional: true,
|
|
96
|
+
type: "Extra",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
nickname: "recovery",
|
|
100
|
+
img_name: "recovery.img",
|
|
101
|
+
sig_name: "recovery.sig",
|
|
102
|
+
part_name: "recovery",
|
|
103
|
+
optional: true,
|
|
104
|
+
type: "BootCritical",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
nickname: "super",
|
|
108
|
+
img_name: "super.img",
|
|
109
|
+
sig_name: "super.sig",
|
|
110
|
+
part_name: "super",
|
|
111
|
+
optional: true,
|
|
112
|
+
type: "Extra",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
nickname: "system",
|
|
116
|
+
img_name: "system.img",
|
|
117
|
+
sig_name: "system.sig",
|
|
118
|
+
part_name: "system",
|
|
119
|
+
optional: false,
|
|
120
|
+
type: "Normal",
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
nickname: "system_dlkm",
|
|
124
|
+
img_name: "system_dlkm.img",
|
|
125
|
+
sig_name: "system_dlkm.sig",
|
|
126
|
+
part_name: "system_dlkm",
|
|
127
|
+
optional: true,
|
|
128
|
+
type: "Normal",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
nickname: "system_ext",
|
|
132
|
+
img_name: "system_ext.img",
|
|
133
|
+
sig_name: "system_ext.sig",
|
|
134
|
+
part_name: "system_ext",
|
|
135
|
+
optional: true,
|
|
136
|
+
type: "Normal",
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
nickname: "",
|
|
140
|
+
img_name: "system_other.img",
|
|
141
|
+
sig_name: "system.sig",
|
|
142
|
+
part_name: "system",
|
|
143
|
+
optional: true,
|
|
144
|
+
type: "Normal",
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
nickname: "userdata",
|
|
148
|
+
img_name: "userdata.img",
|
|
149
|
+
sig_name: "userdata.sig",
|
|
150
|
+
part_name: "userdata",
|
|
151
|
+
optional: true,
|
|
152
|
+
type: "Extra",
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
nickname: "vbmeta",
|
|
156
|
+
img_name: "vbmeta.img",
|
|
157
|
+
sig_name: "vbmeta.sig",
|
|
158
|
+
part_name: "vbmeta",
|
|
159
|
+
optional: true,
|
|
160
|
+
type: "BootCritical",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
nickname: "vbmeta_system",
|
|
164
|
+
img_name: "vbmeta_system.img",
|
|
165
|
+
sig_name: "vbmeta_system.sig",
|
|
166
|
+
part_name: "vbmeta_system",
|
|
167
|
+
optional: true,
|
|
168
|
+
type: "BootCritical",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
nickname: "vbmeta_vendor",
|
|
172
|
+
img_name: "vbmeta_vendor.img",
|
|
173
|
+
sig_name: "vbmeta_vendor.sig",
|
|
174
|
+
part_name: "vbmeta_vendor",
|
|
175
|
+
optional: true,
|
|
176
|
+
type: "BootCritical",
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
nickname: "vendor",
|
|
180
|
+
img_name: "vendor.img",
|
|
181
|
+
sig_name: "vendor.sig",
|
|
182
|
+
part_name: "vendor",
|
|
183
|
+
optional: true,
|
|
184
|
+
type: "Normal",
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
nickname: "vendor_boot",
|
|
188
|
+
img_name: "vendor_boot.img",
|
|
189
|
+
sig_name: "vendor_boot.sig",
|
|
190
|
+
part_name: "vendor_boot",
|
|
191
|
+
optional: true,
|
|
192
|
+
type: "BootCritical",
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
nickname: "vendor_dlkm",
|
|
196
|
+
img_name: "vendor_dlkm.img",
|
|
197
|
+
sig_name: "vendor_dlkm.sig",
|
|
198
|
+
part_name: "vendor_dlkm",
|
|
199
|
+
optional: true,
|
|
200
|
+
type: "Normal",
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
nickname: "vendor_kernel_boot",
|
|
204
|
+
img_name: "vendor_kernel_boot.img",
|
|
205
|
+
sig_name: "vendor_kernel_boot.sig",
|
|
206
|
+
part_name: "vendor_kernel_boot",
|
|
207
|
+
optional: true,
|
|
208
|
+
type: "BootCritical",
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
nickname: "",
|
|
212
|
+
img_name: "vendor_other.img",
|
|
213
|
+
sig_name: "vendor.sig",
|
|
214
|
+
part_name: "vendor",
|
|
215
|
+
optional: true,
|
|
216
|
+
type: "Normal",
|
|
217
|
+
},
|
|
218
|
+
]
|
package/src/index.ts
ADDED