Skip to content

Instantly share code, notes, and snippets.

@phhusson
Last active September 11, 2023 16:20
Show Gist options
  • Save phhusson/e28eb236da6d9a1e653fcf4431f3804c to your computer and use it in GitHub Desktop.
Save phhusson/e28eb236da6d9a1e653fcf4431f3804c to your computer and use it in GitHub Desktop.
Streaming AB OTA on Android
var h = URL(otaUrl).openConnection() as HttpsURLConnection
var zis = ZipInputStream(h.inputStream)
var props = ""
var offset = 0L
val FIXED_HEADER_SIZE = 30
var payload_offset = 0L
var payload_size = 0L
while(true) {
val entry = zis.nextEntry
if(entry == null) break
val size = entry.size
val n = entry.name.length
val m = if (entry.extra == null) 0 else entry.extra.size
val headerSize = FIXED_HEADER_SIZE + n + m
offset += headerSize
l("Entry $entry")
if (entry.name.equals("payload.bin")) {
payload_offset = offset
payload_size = entry.compressedSize
val nextEntryOffset = payload_offset + entry.compressedSize
zis.close()
l("Payload starts at $payload_offset ends at $nextEntryOffset")
h = URL(otaUrl).openConnection() as HttpsURLConnection
h.setRequestProperty("Range", "bytes=$nextEntryOffset-")
zis = ZipInputStream(h.inputStream)
}
offset += entry.compressedSize
if(entry.name == "payload_properties.txt") {
val barr = ByteArray(size.toInt())
zis.read(barr)
props = String(barr, Charsets.UTF_8)
l("Payload properties is $props")
}
zis.closeEntry()
}
l("Got payload offset $payload_offset")
val p = props
.split("\n")
.filter { it.contains("=") }
.map { it.trim() }
.toTypedArray()
l("props")
for(i in p) {
l("- $i")
}
val svc = Class.forName("android.os.UpdateEngine")
.getConstructor().newInstance()
svc.javaClass
.getMethod("applyPayload", String::class.java, Long::class.java, Long::class.java, Array<String>::class.java)
.invoke(svc, otaUrl, payload_offset, payload_size, p)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment