Skip to content

Commit d50f287

Browse files
committed
Fix how the script gets data from apks.
The previous code used unzip to get the offsets of the files in the zip file. This was an estimate, and it turns out to be wrong in many cases. Replace that with zipinfo -v which gives the exact offset of the files in the zip. Also update the tmp files so that they are in a dictionary of their own by apk, instead of embedded in the offset list. Bug: 29050779 (cherry picked from commit abe22f4) Change-Id: I4e33704c5b26cd238ff7e316bca9de729480c59c
1 parent 6d99fa2 commit d50f287

File tree

1 file changed

+49
-26
lines changed

1 file changed

+49
-26
lines changed

scripts/stack_core.py

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ class TraceConverter:
4343
sanitizer_trace_line = re.compile("$a")
4444
value_line = re.compile("$a")
4545
code_line = re.compile("$a")
46-
unzip_line = re.compile("\s*(\d+)\s+\S+\s+\S+\s+(\S+)")
46+
zipinfo_central_directory_line = re.compile("Central\s+directory\s+entry")
47+
zipinfo_central_info_match = re.compile(
48+
"^\s*(\S+)$\s*offset of local header from start of archive:\s*(\d+)"
49+
".*^\s*compressed size:\s+(\d+)", re.M | re.S)
4750
trace_lines = []
4851
value_lines = []
4952
last_frame = -1
@@ -163,10 +166,9 @@ def PrintDivider(self):
163166
print "-----------------------------------------------------\n"
164167

165168
def DeleteApkTmpFiles(self):
166-
for _, offset_list in self.apk_info.values():
167-
for _, _, tmp_file in offset_list:
168-
if tmp_file:
169-
os.unlink(tmp_file)
169+
for _, _, tmp_files in self.apk_info.values():
170+
for tmp_file in tmp_files.values():
171+
os.unlink(tmp_file)
170172

171173
def ConvertTrace(self, lines):
172174
lines = map(self.CleanLine, lines)
@@ -216,20 +218,31 @@ def ExtractLibFromApk(self, apk, shared_lib_name):
216218
os.unlink(tmp_file)
217219
return None
218220

221+
def ProcessCentralInfo(self, offset_list, central_info):
222+
match = self.zipinfo_central_info_match.search(central_info)
223+
if not match:
224+
raise Exception("Cannot find all info from zipinfo\n" + central_info)
225+
name = match.group(1)
226+
start = int(match.group(2))
227+
end = start + int(match.group(3))
228+
229+
offset_list.append([name, start, end])
230+
return name, start, end
231+
219232
def GetLibFromApk(self, apk, offset):
220233
# Convert the string to hex.
221234
offset = int(offset, 16)
222235

223236
# Check if we already have information about this offset.
224237
if apk in self.apk_info:
225-
apk_full_path, offset_list = self.apk_info[apk]
226-
for current_offset, file_name, tmp_file in offset_list:
227-
if offset <= current_offset:
228-
if tmp_file:
229-
return file_name, tmp_file
230-
# This modifies the value in offset_list.
238+
apk_full_path, offset_list, tmp_files = self.apk_info[apk]
239+
for file_name, start, end in offset_list:
240+
if offset >= start and offset < end:
241+
if file_name in tmp_files:
242+
return file_name, tmp_files[file_name]
231243
tmp_file = self.ExtractLibFromApk(apk_full_path, file_name)
232244
if tmp_file:
245+
tmp_files[file_name] = tmp_file
233246
return file_name, tmp_file
234247
break
235248
return None, None
@@ -249,28 +262,38 @@ def GetLibFromApk(self, apk, offset):
249262
print "Cannot find apk " + apk;
250263
return None, None
251264

252-
cmd = subprocess.Popen(["unzip", "-lqq", apk_full_path], stdout=subprocess.PIPE)
253-
current_offset = 0
254-
file_entry = None
265+
cmd = subprocess.Popen(["zipinfo", "-v", apk_full_path], stdout=subprocess.PIPE)
266+
# Find the first central info marker.
267+
for line in cmd.stdout:
268+
if self.zipinfo_central_directory_line.search(line):
269+
break
270+
271+
central_info = ""
272+
file_name = None
255273
offset_list = []
256274
for line in cmd.stdout:
257-
match = self.unzip_line.match(line)
275+
match = self.zipinfo_central_directory_line.search(line)
258276
if match:
259-
# Round the size up to a page boundary.
260-
current_offset += (int(match.group(1), 10) + 0x1000) & ~0xfff
261-
offset_entry = [current_offset - 1, match.group(2), None]
262-
offset_list.append(offset_entry)
263-
if offset < current_offset and not file_entry:
264-
file_entry = offset_entry
277+
cur_name, start, end = self.ProcessCentralInfo(offset_list, central_info)
278+
if not file_name and offset >= start and offset < end:
279+
file_name = cur_name
280+
central_info = ""
281+
else:
282+
central_info += line
283+
if central_info:
284+
cur_name, start, end = self.ProcessCentralInfo(offset_list, central_info)
285+
if not file_name and offset >= start and offset < end:
286+
file_name = cur_name
265287

266288
# Save the information from the zip.
267-
self.apk_info[apk] = [apk_full_path, offset_list]
268-
if not file_entry:
289+
tmp_files = dict()
290+
self.apk_info[apk] = [apk_full_path, offset_list, tmp_files]
291+
if not file_name:
269292
return None, None
270-
tmp_shared_lib = self.ExtractLibFromApk(apk_full_path, file_entry[1])
293+
tmp_shared_lib = self.ExtractLibFromApk(apk_full_path, file_name)
271294
if tmp_shared_lib:
272-
file_entry[2] = tmp_shared_lib
273-
return file_entry[1], file_entry[2]
295+
tmp_files[file_name] = tmp_shared_lib
296+
return file_name, tmp_shared_lib
274297
return None, None
275298

276299
def ProcessLine(self, line):

0 commit comments

Comments
 (0)