Android A/B 系统基础入门系列《Android A/B 系统》已完结,文章列表:
Android A/B System OTA分析(一)概览
Android A/B System OTA分析(二)系统image的生成
Android A/B System OTA分析(三)主系统和bootloader的通信
Android A/B System OTA分析(四)系统的启动和升级
Android A/B System OTA分析(五)客户端参数
Android A/B System OTA分析(六)如何获取 payload 的 offset 和 size
更多关于 Android OTA 升级相关文章,请参考《Android OTA 升级系列专栏文章导读》。
上一篇《Android A/B System OTA分析(五)客户端升级的参数》提到升级时 offset 和 size 参数分别用于升级时设置远程文件中 payload 数据的起始地址和长度,但并没有提到如何获得这个 offset 和 size 值。本篇详细说明如何计算和获取这两个参数。
我写东西通常想把来龙去脉都写清楚,因此也会很繁琐,以下是对本文快速导航:
* 如果你只想知道 Android O 开始,脚本中是如何计算 offset 和 size 参数的,请转到 2.1 节。
* 如果你只想知道命令行如何手工获取 offset 和 size 参数,请转到第 2.2 节。
* 如果你想找一个单独的脚本工具计算 offset 和 size,请转到第 3.3 节
1. zip 文件的格式
要想知道压缩包中每个文件的 offset 和 size 是如何计算的,就先需要了解下 zip 文件的格式。
对于这种要了解标准或文件格式的情况,我一般推荐阅读官方文档。官方文档虽然枯燥,但是是第一手信息。再配上网上其它的分析文章,这样阅读理解起来会比较容易,也不容易出现错误。
维基百科页面《ZIP (file format) 》提供了多个 zip 文件格式的历史版本链接, 目前最新的版本是 v6.3.9(文档日期 2020/07/15),这里使用 v6.3.2 版本的文档作为参考(文档日期 2007/09/28):
《APPNOTE.TXT - .ZIP File Format Specification》: https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.2.TXT
关于 zip 文件的历史,有兴趣的也请自行参考维基百科:《ZIP (file format) 》
在 v6.3.2 版文档的第 V 节详细描述了 zip 文件的格式。
1.1 zip 文件的总体格式
Overall .ZIP file format:
[local file header 1]
[file data 1]
[data descriptor 1]
.
.
.
[local file header n]
[file data n]
[data descriptor n]
[archive decryption header]
[archive extra data record]
[central directory]
[zip64 end of central directory record]
[zip64 end of central directory locator]
[end of central directory record]
总体来说,zip 文件由多个文件组成,每个文件由 “loacal file header”, “file data” 和 “data descriptor” 3 部分组成,多个文件时各文件数据依次排列。
在文件结束后有一些其它数据,由于我们只关心每个文件的 offset 和 size,所以可以暂时不用考虑文件末尾的那些数据,虽然可能也很重要。
1.2 local file header
zip 文件中,每个文件的第一部分就是 local file header,用于描述文件的各种属性。
Local file header:
local file header signature 4 bytes (0x04034b50)
version needed to extract 2 bytes
general purpose bit flag 2 bytes
compression method 2 bytes
last mod file time 2 bytes
last mod file date 2 bytes
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
file name length 2 bytes
extra field length 2 bytes
file name (variable size)
extra field (variable size)
在 local file header 中,前面的是定长部分的数据,一共 30 bytes;后面还有两个变长的部分 file name 和 extra field,这两部分的具体长度由定长部分的 file name length 和 extra filed length 指定。
因此 len(local file header) = 30 + len(file name) + len(extra filed)
1.3 file data
紧挨着 local file header 的是文件数据 file data,根据具体的情况,这里的数据可能是压缩的,也可能是没有压缩的,具体长度由 local file header 中的 compressed size 指定。
1.4 data descriptor
file data 之后是 data descriptor:
Data descriptor:
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
这部分数据并不是必须的,只有当 local file header 结构中 general purpose bit flag 的 bit 3 被设置以后才存在,其内容也是用来指定文件数据长度的。
为什么会出现这种情况呢? 这是因为有些情况下,一开始是不知道文件数据大小的。例如,用录像机录像时,其数据压缩存储,一开始录制的时候并不能确定最终文件多大,但这些数据又需要不断写入存储介质,所以就在开始的时候设置一个标志位,表示其大小存储在数据结束的地方。
1.5 offset 和 size 的计算
由于我们这里只关心 offset 和 size 的计算,所以 zip 文件后面的那些数据暂时不管了。
只需要拿到每个文件在 zip 包中的 local file header 数据就可以计算得到 offset 和 size 数值。
文件数据的起始位置(offset):
offset(data) = offset(local file header) + size(local file header)
= offset(local file header) + 30 + len(file name) + len(extra filed)
文件数据的大小(size):
# 压缩后数据大小
size = comressed size
# 原始数据大小
size = uncompressed size
最后,一张图描述 zip 文件的主要结构,方便参考:
1.6 关于 encryption header
从 APPNOTE.TXT - .ZIP File Format Specification Version, 6.3.3 开始,zip 文件新增了一个 encryption header,位于 local file header 之后, file data 之前,如下所示:
Overall .ZIP file format:
[local file header 1]
[encryption header 1]
[file data 1]
[data descriptor 1]
.
.
.
[local file header n]
[encryption header n]
[file data n]
[data descriptor n]
[archive decryption header]
[archive extra data record]
[central directory header 1]
.
.
.
[central directory header n]
[zip64 end of central directory record]
[zip64 end of central directory locator]
[end of central directory record]
这里的 encryption header 只有在压缩包的数据被加密的情况下才会出现,由于 Android 的 update.zip 包并未加密,不会出现 encryption header,因此接下来的讨论都默认没有 encryption header 。
2. 获取 offset 和 size 的三种方式
上一节介绍了 zip 文件的结构,接下来就可以根据这个结构去获取 offset 和 size 数据。
2.1 Android O 开始自动生成 offset 和 size 数据
1. metadata 示例
从 Android 8.0 (O) 开始,制作升级包时,会自动计算 payload 的 offset 和 size 并输出到 zip 包的 META-INF/com/android/metadata 文件中,像下面这样:
$ cat META-INF/com/android/metadata
ota-required-cache=0
ota-streaming-property-files=payload.bin:738:271041806,payload_properties.txt:271042602:154,care_map.txt:474:217,metadata:69:357
ota-type=AB
post-build=bcm/b604usff/b604usff:8.0.0/OPR6.170623.021/rg935701131615:userdebug/test-keys
post-build-incremental=eng.rg9357.20220113.161532
post-timestamp=1642061732
pre-device=b604usff
这里的 ota-streaming-property-files 键值对就记录了多个文件的 offset 和 size 值,包括:
* payload.bin, offset: 738, size: 271041806
* payload_propterites.txt, offset: 271042602, size: 154
* care_map.txt, offset: 474, size: 217
* metadata, offset: 6957, size: 357
2. metadata 生成的代码分析
这里涉及的Android代码:android-8.0.0_r12(BUILD_ID=OPR6.170623.021)
生成 offset 和 size 数据的代码位于脚本 ota_from_target_files 中,见下面的代码片段:
* 计算多个文件的 offset 和 size
从第 971 行开始,定义了函数 ComputeStreamingMetadata 用于提取指定压缩包的 offset 和 size 信息
def ComputeStreamingMetadata(zip_file, reserve_space=False,
expected_length=None):
"""Compute the streaming metadata for a given zip.
When 'reserve_space' is True, we reserve extra space for the offset and
length of the metadata entry itself, although we don't know the final
values until the package gets signed. This function will be called again
after signing. We then write the actual values and pad the string to the
length we set earlier. Note that we can't use the actual length of the
metadata entry in the second run. Otherwise the offsets for other entries
will be changing again.
"""
#
# 根据文件名 name, 获取对应文件的 offset 和 size 并用这样的格式输出: 'filename:offset:size'
# 如: payload.bin:738:271041806
#
def ComputeEntryOffsetSize(name):
"""Compute the zip entry offset and size."""
# 提取文件名 name 对应的 zipinfo 对象
info = zip_file.getinfo(name)
# 根据 zipinfo 对象的 header_offset 和 FileHeader 长度, 得到文件数据的 offset
offset = info.header_offset + len(info.FileHeader())
# 使用 zipinfo 对象的 file_size 作为 size (这里的 file_size 是文件压缩前的大小,压缩后的大小为 compress_size)
size = info.file_size
return '%s:%d:%d' % (os.path.basename(name), offset, size)
#
# 获取以下文件的 offset 和 size 数据:
# 1. payload.bin
# 2. payload_properties.txt
# 3. care_map.txt
# 4. compatibility.zip
# 5. metadata
#
# payload.bin and payload_properties.txt must exist.
offsets = [ComputeEntryOffsetSize('payload.bin'),
ComputeEntryOffsetSize('payload_properties.txt')]
# care_map.txt is available only if dm-verity is enabled.
if 'care_map.txt' in zip_file.namelist():
offsets.append(ComputeEntryOffsetSize('care_map.txt'))
if 'compatibility.zip' in zip_file.namelist():
offsets.append(ComputeEntryOffsetSize('compatibility.zip'))
#
# 计算 'META-INF/com/android/metadata' 文件的 offset 和 size 时,预留了格式: 'metadata: ' (10个空格)
#
# 'META-INF/com/android/metadata' is required. We don't know its actual
# offset and length (as well as the values for other entries). So we
# reserve 10-byte as a placeholder, which is to cover the space for metadata
# entry ('xx:xxx', since it's ZIP_STORED which should appear at the
# beginning of the zip), as well as the possible value changes in other
# entries.
if reserve_space:
offsets.append('metadata:' + ' ' * 10)
else:
offsets.append(ComputeEntryOffsetSize(METADATA_NAME))
# 将所有文件的 'name:offset:size' 数据用逗号连接成一个字符串返回
value = ','.join(offsets)
if expected_length is not None:
assert len(value) <= expected_length, \
'Insufficient reserved space: reserved=%d, actual=%d' % (
expected_length, len(value))
value += ' ' * (expected_length - len(value))
return value
* 将获取的 offset 和 size 写入 metadata 文件
第 1213 行代码开始,计算输出的 zip 文件的 offset 和 size 信息写入 metadata 文件的 ota-streaming-property-files 键值对中。但这里 metadata 文件自身的 offset 和 size 并没有计算。
# Open the signed zip. Compute the final metadata that's needed for streaming.
prelim_zip = zipfile.ZipFile(prelim_signing, "r",
compression=zipfile.ZIP_DEFLATED)
expected_length = len(metadata['ota-streaming-property-files'])
metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
prelim_zip, reserve_space=False, expected_length=expected_length)
...
# Now write the final metadata entry.
WriteMetadata(metadata, output_zip)
2.2 使用 zipinfo 手工计算
linux 命令行工具 zipinfo 可以用来提取 zip 文件的信息。
1. 安装 zipinfo
这个工具默认情况下没有安装,ubuntu 上可以通过以下命令安装:
sudo apt install unzip
2. 使用 zipinfo 解析 update.zip 文件
* zipinfo 帮助信息
可以通过 zipinfo 查看简略的帮助信息,或者通过 man zipinfo 查看详尽的内容
$ zipinfo
ZipInfo 3.00 of 20 April 2009, by Greg Roelofs and the Info-ZIP group.
List name, date/time, attribute, size, compression method, etc., about files
in list (excluding those in xlist) contained in the specified .zip archive(s).
"file[.zip]" may be a wildcard name containing *, ?, [] (e.g., "[a-j]*.zip").
usage: zipinfo [-12smlvChMtTz] file[.zip] [list...] [-x xlist...]
or: unzip -Z [-12smlvChMtTz] file[.zip] [list...] [-x xlist...]
main listing-format options: -s short Unix "ls -l" format (def.)
-1 filenames ONLY, one per line -m medium Unix "ls -l" format
-2 just filenames but allow -h/-t/-z -l long Unix "ls -l" format
-v verbose, multi-page format
miscellaneous options:
-h print header line -t print totals for listed files or for all
-z print zipfile comment ⚌-T⚌ print file times in sortable decimal format
⚌-C⚌ be case-insensitive zipinfo -x exclude filenames that follow from listing
-O CHARSET specify a character encoding for DOS, Windows and OS/2 archives
-I CHARSET specify a character encoding for UNIX and other archives
$ man zipinfo
* 不带参数, 列举 update.zip 中的文件
$ zipinfo
ZipInfo 3.00 of 20 April 2009, by Greg Roelofs and the Info-ZIP group.
List name, date/time, attribute, size, compression method, etc., about files
in list (excluding those in xlist) contained in the specified .zip archive(s).
"file[.zip]" may be a wildcard name containing *, ?, [] (e.g., "[a-j]*.zip").
usage: zipinfo [-12smlvChMtTz] file[.zip] [list...] [-x xlist...]
or: unzip -Z [-12smlvChMtTz] file[.zip] [list...] [-x xlist...]
main listing-format options: -s short Unix "ls -l" format (def.)
-1 filenames ONLY, one per line -m medium Unix "ls -l" format
-2 just filenames but allow -h/-t/-z -l long Unix "ls -l" format
-v verbose, multi-page format
miscellaneous options:
-h print header line -t print totals for listed files or for all
-z print zipfile comment ⚌-T⚌ print file times in sortable decimal format
⚌-C⚌ be case-insensitive zipinfo -x exclude filenames that follow from listing
-O CHARSET specify a character encoding for DOS, Windows and OS/2 archives
-I CHARSET specify a character encoding for UNIX and other archives
$ man zipinfo
* -v 选项解析 zip 文件详信息
$ zipinfo -v update.zip
Archive: update.zip
The zipfile comment is 1738 bytes long and contains the following text:
======================== zipfile comment begins ==========================
signed by SignApk
========================= zipfile comment ends ===========================
End-of-central-directory record:
-------------------------------
Zip archive file size: 271045893 (000000001027D505h)
Actual end-cent-dir record offset: 271044133 (000000001027CE25h)
Expected end-cent-dir record offset: 271044133 (000000001027CE25h)
(based on the length of the central directory and its expected offset)
This zipfile constitutes the sole disk of a single-part archive; its
central directory contains 5 entries.
The central directory is 360 (0000000000000168h) bytes long,
and its (expected) offset in bytes from the beginning of the zipfile
is 271043773 (000000001027CCBDh).
Central directory entry #1:
---------------------------
META-INF/com/android/metadata
offset of local header from start of archive: 0
(0000000000000000h) bytes
file system or operating system of origin: MS-DOS, OS/2 or NT FAT
version of encoding software: 1.0
minimum file system compatibility required: MS-DOS, OS/2 or NT FAT
minimum software version required to extract: 1.0
compression method: none (stored)
file security status: not encrypted
extended local header: no
file last modified on (DOS date/time): 2009 Jan 1 00:00:00
32-bit CRC value (hex): 982fa5b5
compressed size: 357 bytes
uncompressed size: 357 bytes
length of filename: 29 characters
length of extra field: 10 bytes
length of file comment: 0 characters
disk number on which file begins: disk 1
apparent file type: binary
non-MSDOS external file attributes: 000000 hex
MS-DOS file attributes (00 hex): none
The central-directory extra field contains:
- A subfield with ID 0xcafe (unknown) and 0 data bytes.
- A subfield with ID 0xd935 (unknown) and 2 data bytes:
00 00.
There is no file comment.
Central directory entry #2:
---------------------------
care_map.txt
offset of local header from start of archive: 426
(00000000000001AAh) bytes
file system or operating system of origin: MS-DOS, OS/2 or NT FAT
version of encoding software: 1.0
minimum file system compatibility required: MS-DOS, OS/2 or NT FAT
minimum software version required to extract: 1.0
compression method: none (stored)
file security status: not encrypted
extended local header: no
file last modified on (DOS date/time): 2009 Jan 1 00:00:00
32-bit CRC value (hex): 03053f05
compressed size: 217 bytes
uncompressed size: 217 bytes
length of filename: 12 characters
length of extra field: 6 bytes
length of file comment: 0 characters
disk number on which file begins: disk 1
apparent file type: binary
non-MSDOS external file attributes: 000000 hex
MS-DOS file attributes (00 hex): none
The central-directory extra field contains:
- A subfield with ID 0xd935 (unknown) and 2 data bytes:
00 00.
There is no file comment.
Central directory entry #3:
---------------------------
payload.bin
offset of local header from start of archive: 691
(00000000000002B3h) bytes
file system or operating system of origin: MS-DOS, OS/2 or NT FAT
version of encoding software: 1.0
minimum file system compatibility required: MS-DOS, OS/2 or NT FAT
minimum software version required to extract: 1.0
compression method: none (stored)
file security status: not encrypted
extended local header: no
file last modified on (DOS date/time): 2009 Jan 1 00:00:00
32-bit CRC value (hex): eba210d4
compressed size: 271041806 bytes
uncompressed size: 271041806 bytes
length of filename: 11 characters
length of extra field: 6 bytes
length of file comment: 0 characters
disk number on which file begins: disk 1
apparent file type: binary
non-MSDOS external file attributes: 000000 hex
MS-DOS file attributes (00 hex): none
The central-directory extra field contains:
- A subfield with ID 0xd935 (unknown) and 2 data bytes:
00 00.
There is no file comment.
Central directory entry #4:
---------------------------
payload_properties.txt
offset of local header from start of archive: 271042544
(000000001027C7F0h) bytes
file system or operating system of origin: MS-DOS, OS/2 or NT FAT
version of encoding software: 1.0
minimum file system compatibility required: MS-DOS, OS/2 or NT FAT
minimum software version required to extract: 1.0
compression method: none (stored)
file security status: not encrypted
extended local header: no
file last modified on (DOS date/time): 2009 Jan 1 00:00:00
32-bit CRC value (hex): 21aa275c
compressed size: 154 bytes
uncompressed size: 154 bytes
length of filename: 22 characters
length of extra field: 6 bytes
length of file comment: 0 characters
disk number on which file begins: disk 1
apparent file type: binary
non-MSDOS external file attributes: 000000 hex
MS-DOS file attributes (00 hex): none
The central-directory extra field contains:
- A subfield with ID 0xd935 (unknown) and 2 data bytes:
00 00.
There is no file comment.
Central directory entry #5:
---------------------------
META-INF/com/android/otacert
offset of local header from start of archive: 271042756
(000000001027C8C4h) bytes
file system or operating system of origin: MS-DOS, OS/2 or NT FAT
version of encoding software: 2.0
minimum file system compatibility required: MS-DOS, OS/2 or NT FAT
minimum software version required to extract: 2.0
compression method: deflated
compression sub-type (deflation): normal
file security status: not encrypted
extended local header: yes
file last modified on (DOS date/time): 2009 Jan 1 00:00:00
32-bit CRC value (hex): c3fc0954
compressed size: 943 bytes
uncompressed size: 1675 bytes
length of filename: 28 characters
length of extra field: 0 bytes
length of file comment: 0 characters
disk number on which file begins: disk 1
apparent file type: binary
non-MSDOS external file attributes: 000000 hex
MS-DOS file attributes (00 hex): none
There is no file comment.
上面执行命令 zipinfo -v update.zip,会打印了 update.zip 包中所有文件的详细信息。
如果只想查看单个文件的信息,可以在后面添加想查看的文件名,如: zipinfo -v update.zip payload.bin:
$ zipinfo -v update.zip payload.bin
Archive: update.zip
The zipfile comment is 1738 bytes long and contains the following text:
======================== zipfile comment begins ==========================
signed by SignApk
========================= zipfile comment ends ===========================
End-of-central-directory record:
-------------------------------
Zip archive file size: 271045893 (000000001027D505h)
Actual end-cent-dir record offset: 271044133 (000000001027CE25h)
Expected end-cent-dir record offset: 271044133 (000000001027CE25h)
(based on the length of the central directory and its expected offset)
This zipfile constitutes the sole disk of a single-part archive; its
central directory contains 5 entries.
The central directory is 360 (0000000000000168h) bytes long,
and its (expected) offset in bytes from the beginning of the zipfile
is 271043773 (000000001027CCBDh).
Central directory entry #3:
---------------------------
payload.bin
offset of local header from start of archive: 691
(00000000000002B3h) bytes
file system or operating system of origin: MS-DOS, OS/2 or NT FAT
version of encoding software: 1.0
minimum file system compatibility required: MS-DOS, OS/2 or NT FAT
minimum software version required to extract: 1.0
compression method: none (stored)
file security status: not encrypted
extended local header: no
file last modified on (DOS date/time): 2009 Jan 1 00:00:00
32-bit CRC value (hex): eba210d4
compressed size: 271041806 bytes
uncompressed size: 271041806 bytes
length of filename: 11 characters
length of extra field: 6 bytes
length of file comment: 0 characters
disk number on which file begins: disk 1
apparent file type: binary
non-MSDOS external file attributes: 000000 hex
MS-DOS file attributes (00 hex): none
The central-directory extra field contains:
- A subfield with ID 0xd935 (unknown) and 2 data bytes:
00 00.
There is no file comment.
这里就只显示了 payload.bin 文件的详细信息。
3. 从 zipinfo 结果中手工计算 offset 和 size
从上面的解析可以得到以下的信息:
* payload.bin 文件的 local file header 的偏移为 691 bytes
* filename 和 extra field 的长度分别为 11 bytes 和 6 bytes
* compressed size 和 uncompressed size 大小一样,都是 271041806 bytes
因此,payload.bin 文件的数据在 update.zip 包中的偏移量:
offset(data) = offset(local file header) + size(local file header)
= offset(local file header) + 30 + len(file name) + len(extra filed)
= 691 + 30 + 11 + 6
= 738
另外,这里compressed size 和 uncompressed size 大小一样,都是 271041806 bytes 说明 payload.bin 文件并没有被压缩,只是打包到了 zip 文件而已,在数据被压缩的情况下,则其在压缩包中的大小应该是 compressed size。
在前面的 python 代码中,其 zipinfo.file_size 就是这里的 uncompressed size,否则应该使用 compressed size 数据。
所以,我觉得脚本中应该使用 zipinfo.compress_size 作为 size 大小最为合适,offset ~ compress_size 才是 payload.bin 在 zip 包中的具体数据。
2.3 使用 python 脚本计算
简单修改一下 Android O 脚本中的代码,就可以生成一个计算 offset 和 size 的工具 zip_info.py:
#!/usr/bin/env python3
import os
import zipfile
def show_zipfile(filename):
zf = zipfile.ZipFile(filename, 'r')
print('{}:\n'.format(filename))
print('{:>25s} {:>15s} {:>15s} {:>15s}'.format("name", "offset", "size", "compress_size"))
print('{:>25s} {:>15s} {:>15s} {:>15s}'.format('-' * 25, '-' * 15, '-' * 15, '-' * 15))
for x in zf.namelist():
info = zf.getinfo(x)
offset = info.header_offset + len(info.FileHeader())
size = info.file_size
compress_size = info.compress_size
print('{:>25s} {:>15d} {:>15d} {:>15d}'.format(os.path.basename(x), offset, size, compress_size))
zf.close()
if __name__ == "__main__":
filename = 'update.zip'
show_zipfile(filename)
计算当前目录下 “update.zip” 压缩包内各文件的 offset 和 size:
$ python3 zip_info.py
update.zip:
name offset size compress_size
------------------------- --------------- --------------- ---------------
metadata 69 357 357
care_map.txt 474 217 217
payload.bin 738 271041806 271041806
payload_properties.txt 271042602 154 154
otacert 271042814 1675 943
3. 总结
1. 从 Android 8.0 (O) 开始,制作升级包时会同时将 offset 和 size 信息输出到 META-INF/com/android/metadata 文件中。
2. 通过 zipinfo 工具,使用命令 zipinfo -v update.zip payload.bin 获取 payload.bin 文件的详细信息,然后通过下面的方式计算 offset:
offset(data) = offset(local file header) + size(local file header)
= offset(local file header) + 30 + len(file name) + len(extra filed)
具体的分析请参考 2.2 节。
3. 使用这里提供的 python3 工具计算 update.zip 包内各数据的 offset 和 size 信息
具体的代码和样例输出,参考 2.3 节。
4. 其它
到目前为止,我写过 Android OTA 升级相关的话题包括:文章来源:https://www.toymoban.com/news/detail-814957.html
基础入门:《Android A/B 系统》系列
核心模块:《Android Update Engine 分析》 系列
动态分区:《Android 动态分区》 系列
虚拟 A/B:《Android 虚拟 A/B 分区》系列
升级工具:《Android OTA 相关工具》系列
更多这些关于 Android OTA 升级相关文章的内容,请参考《Android OTA 升级系列专栏文章导读》。
————————————————
版权声明:本文为CSDN博主「洛奇看世界」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guyongqiangx/article/details/122498561文章来源地址https://www.toymoban.com/news/detail-814957.html
到了这里,关于Android A/B System OTA分析(六)如何获取 payload 的 offset 和 size的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!