-
Notifications
You must be signed in to change notification settings - Fork 19
/
extract_incremental_ota.patch
114 lines (108 loc) · 4.03 KB
/
extract_incremental_ota.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
diff --git a/extract_android_ota_payload.py b/extract_android_ota_payload.py
index 7688ecd..6c0b593 100644
--- a/extract_android_ota_payload.py
+++ b/extract_android_ota_payload.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
+import argparse
import hashlib
import os
import os.path
@@ -87,7 +88,7 @@ def decompress_payload(command, data, size, hash):
print("Hash mismatch")
return r
-def parse_payload(payload_f, partition, out_f):
+def parse_payload(payload_f, partition, out_f, block_size, output_dir, source_dir):
BLOCK_SIZE = 4096
for operation in partition.operations:
e = operation.dst_extents[0]
@@ -101,10 +102,57 @@ def parse_payload(payload_f, partition, out_f):
elif operation.type == update_metadata_pb2.InstallOperation.REPLACE_BZ:
r = decompress_payload('bzcat', data, e.num_blocks * BLOCK_SIZE, operation.data_sha256_hash)
out_f.write(r)
+ elif operation.type in [
+ update_metadata_pb2.InstallOperation.SOURCE_COPY,
+ update_metadata_pb2.InstallOperation.SOURCE_BSDIFF
+ ]:
+ src_blocks = []
+ for src_extent in operation.src_extents:
+ src_blocks.extend(range(src_extent.start_block, src_extent.start_block + src_extent.num_blocks))
+
+ dst_blocks = []
+ for dst_extent in operation.dst_extents:
+ dst_blocks.extend(range(dst_extent.start_block, dst_extent.start_block + dst_extent.num_blocks))
+
+ name = partition.partition_name + '.img'
+
+ if operation.type == update_metadata_pb2.InstallOperation.SOURCE_COPY:
+ with open(os.path.join(source_dir, name)) as in_f:
+ for src_block, dst_block in zip(src_blocks, dst_blocks):
+ in_f.seek(src_block * block_size)
+ out_f.seek(dst_block * block_size)
+ out_f.write(in_f.read(block_size))
+
+ elif operation.type == update_metadata_pb2.InstallOperation.SOURCE_BSDIFF:
+ src_data = bytearray()
+ with open(os.path.join(source_dir, name)) as in_f:
+ for src_block in src_blocks:
+ in_f.seek(src_block * block_size)
+ src_data.extend(in_f.read(block_size))
+
+ src = os.path.join(output_dir, name + '.src')
+ with open(src, 'wb') as src_f:
+ src_f.write(src_data)
+
+ patch = os.path.join(output_dir, name + '.patch')
+ with open(patch, 'wb') as patch_f:
+ patch_f.write(data)
+
+ dst = os.path.join(output_dir, name + '.dst')
+ subprocess.call(['bspatch', src, dst, patch])
+
+ with open(dst, 'rb') as dst_f:
+ for dst_block in dst_blocks:
+ out_f.seek(dst_block * block_size)
+ out_f.write(dst_f.read(block_size))
+
+ os.remove(src)
+ os.remove(patch)
+ os.remove(dst)
else:
raise PayloadError('Unhandled operation type (%d)' % operation.type)
-def main(filename, output_dir):
+def main(filename, output_dir, source_dir):
if filename.endswith('.zip'):
print("Extracting 'payload.bin' from OTA file...")
ota_zf = zipfile.ZipFile(filename)
@@ -121,25 +169,20 @@ def main(filename, output_dir):
fname = os.path.join(output_dir, name)
out_f = open(fname, 'w')
try:
- parse_payload(payload, p, out_f)
+ parse_payload(payload, p, out_f, payload.manifest.block_size, output_dir, source_dir)
except PayloadError as e:
print('Failed: %s' % e)
out_f.close()
os.unlink(fname)
if __name__ == '__main__':
- try:
- filename = sys.argv[1]
- except:
- print('Usage: %s payload.bin [output_dir]' % sys.argv[0])
- sys.exit()
+ parser = argparse.ArgumentParser()
+ parser.add_argument('filename')
+ parser.add_argument('-o', '--output_dir', default=os.getcwd())
+ parser.add_argument('-s', '--source_dir')
+ args = parser.parse_args()
- try:
- output_dir = sys.argv[2]
- except IndexError:
- output_dir = os.getcwd()
+ if not os.path.exists(args.output_dir):
+ os.makedirs(args.output_dir)
- if not os.path.exists(output_dir):
- os.makedirs(output_dir)
-
- main(filename, output_dir)
+ main(args.filename, args.output_dir, args.source_dir)