apk_operations.py: Deobfuscate java stack traces in logcat

Applicable only when building release.
Disable via --no-deobfuscate

Bug: 620323, 758670
Change-Id: Ib1289e6eae6bb326a1879c791e673cdeba331eab
Reviewed-on: https://chromium-review.googlesource.com/656720
Reviewed-by: John Budorick <jbudorick@chromium.org>
Reviewed-by: Peter Wen <wnwen@chromium.org>
Commit-Queue: Andrew Grieve <agrieve@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#501645}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 52668623db4ab636e6631b7a3598ad48f3bb292a
This commit is contained in:
Andrew Grieve 2017-09-13 16:10:17 +00:00 коммит произвёл Commit Bot
Родитель 465f7fab27
Коммит 749b1d8cdd
4 изменённых файлов: 83 добавлений и 38 удалений

Просмотреть файл

@ -12,7 +12,6 @@ import posixpath
import random
import re
import shlex
import subprocess
import sys
import devil_chromium
@ -32,6 +31,7 @@ with devil_env.SysPath(os.path.join(os.path.dirname(__file__), '..', '..',
from incremental_install import installer
from pylib import constants
from pylib.symbols import deobfuscator
def _Colorize(color, text):
@ -354,7 +354,15 @@ def _RunDiskUsage(devices, package_name, verbose):
print 'Total: %skb (%.1fmb)' % (total, total / 1024.0)
def _RunLogcat(device, package_name, verbose):
def _RunLogcat(device, package_name, verbose, mapping_path):
if mapping_path:
try:
deobfuscate = deobfuscator.Deobfuscator(mapping_path)
except OSError:
sys.stderr.write('Error executing "bin/java_deobfuscate". '
'Did you forget to build it?\n')
sys.exit(1)
def get_my_pids():
my_pids = []
for pids in device.GetPids(package_name).values():
@ -363,46 +371,52 @@ def _RunLogcat(device, package_name, verbose):
def process_line(line, fast=False):
if verbose:
if not fast:
sys.stdout.write(line)
if fast:
return
else:
if line.startswith('------'):
if not line or line.startswith('------'):
return
tokens = line.split(None, 4)
pid = int(tokens[2])
priority = tokens[4]
if pid in my_pids or (not fast and priority == 'F'):
sys.stdout.write(line)
pass # write
elif pid in not_my_pids:
return
elif fast:
# Skip checking whether our package spawned new processes.
not_my_pids.add(pid)
return
else:
# Check and add the pid if it is a new one from our package.
my_pids.update(get_my_pids())
if pid in my_pids:
sys.stdout.write(line)
else:
if pid not in my_pids:
not_my_pids.add(pid)
return
if mapping_path:
line = '\n'.join(deobfuscate.TransformLines([line.rstrip()])) + '\n'
sys.stdout.write(line)
adb_path = adb_wrapper.AdbWrapper.GetAdbPath()
cmd = [adb_path, '-s', device.serial, 'logcat', '-v', 'threadtime']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=1)
my_pids = set(get_my_pids())
not_my_pids = set()
nonce = 'apk_wrappers.py nonce={}'.format(random.random())
device.RunShellCommand(['log', nonce])
fast = True
try:
while True:
line = process.stdout.readline()
process_line(line, fast)
my_pids = set(get_my_pids())
not_my_pids = set()
nonce = 'apk_wrappers.py nonce={}'.format(random.random())
device.RunShellCommand(['log', nonce])
fast = True
for line in device.adb.Logcat(logcat_format='threadtime'):
try:
process_line(line, fast)
except:
sys.stderr.write('Failed to process line: ' + line)
raise
if fast and nonce in line:
fast = False
except KeyboardInterrupt:
process.terminate()
pass # Don't show stack trace upon Ctrl-C
finally:
if mapping_path:
deobfuscate.Close()
def _RunPs(devices, package_name):
@ -788,8 +802,20 @@ class _LogcatCommand(_Command):
calls_exec = True
def Run(self):
mapping = self.args.proguard_mapping_path
if self.args.no_deobfuscate:
mapping = None
_RunLogcat(self.devices[0], self.args.package_name,
bool(self.args.verbose_count))
bool(self.args.verbose_count), mapping)
def _RegisterExtraArgs(self, group):
if self._from_wrapper_script:
group.add_argument('--no-deobfuscate', action='store_true',
help='Disables ProGuard deobfuscation of logcat.')
else:
group.set_defaults(no_deobfuscate=False)
group.add_argument('--proguard-mapping-path',
help='Path to ProGuard map (enables deobfuscation)')
class _PsCommand(_Command):
@ -913,7 +939,7 @@ def _RunInternal(parser, output_directory=None):
# TODO(agrieve): Remove =None from target_cpu on or after October 2017.
# It exists only so that stale wrapper scripts continue to work.
def Run(output_directory, apk_path, incremental_json, command_line_flags_file,
target_cpu=None):
target_cpu, proguard_mapping_path):
"""Entry point for generated wrapper scripts."""
constants.SetOutputDirectory(output_directory)
devil_chromium.Initialize(output_directory=output_directory)
@ -923,7 +949,8 @@ def Run(output_directory, apk_path, incremental_json, command_line_flags_file,
command_line_flags_file=command_line_flags_file,
target_cpu=target_cpu,
apk_path=exists_or_none(apk_path),
incremental_json=exists_or_none(incremental_json))
incremental_json=exists_or_none(incremental_json),
proguard_mapping_path=proguard_mapping_path)
_RunInternal(parser, output_directory=output_directory)
@ -933,4 +960,4 @@ def main():
if __name__ == '__main__':
sys.exit(main())
main()

Просмотреть файл

@ -26,11 +26,13 @@ def main():
import apk_operations
output_dir = resolve(${OUTPUT_DIR})
try:
apk_operations.Run(output_dir,
resolve(${APK_PATH}),
resolve(${INC_JSON_PATH}),
${FLAGS_FILE},
target_cpu=${TARGET_CPU})
apk_operations.Run(
output_dir,
resolve(${APK_PATH}),
resolve(${INC_JSON_PATH}),
${FLAGS_FILE},
${TARGET_CPU},
resolve(${MAPPING_PATH}))
except TypeError:
rel_output_dir = os.path.relpath(output_dir)
rel_script_path = os.path.relpath(sys.argv[0], output_dir)
@ -52,6 +54,7 @@ def main(args):
parser.add_argument('--incremental-install-json-path')
parser.add_argument('--command-line-flags-file')
parser.add_argument('--target-cpu')
parser.add_argument('--proguard-mapping-path')
args = parser.parse_args(args)
def relativize(path):
@ -68,6 +71,7 @@ def main(args):
'OUTPUT_DIR': repr(relativize('.')),
'APK_PATH': repr(relativize(args.apk_path)),
'INC_JSON_PATH': repr(relativize(args.incremental_install_json_path)),
'MAPPING_PATH': repr(relativize(args.proguard_mapping_path)),
'FLAGS_FILE': repr(args.command_line_flags_file),
'TARGET_CPU': repr(args.target_cpu),
}

Просмотреть файл

@ -21,13 +21,15 @@ class Deobfuscator(object):
script_path = os.path.join(
constants.GetOutDirectory(), 'bin', 'java_deobfuscate')
cmd = [script_path, mapping_path]
# Allow only one thread to call TransformLines() at a time.
self._lock = threading.Lock()
self._closed_called = False
# Assign to None so that attribute exists if Popen() throws.
self._proc = None
# Start process eagerly to hide start-up latency.
self._proc = subprocess.Popen(
cmd, bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
close_fds=True)
# Allow only one thread to call TransformLines() at a time.
self._lock = threading.Lock()
self._closed_called = False
def IsClosed(self):
return self._closed_called or self._proc.returncode is not None
@ -113,7 +115,8 @@ class Deobfuscator(object):
self._proc.wait()
def __del__(self):
if not self._closed_called:
# self._proc is None when Popen() fails.
if not self._closed_called and self._proc:
logging.error('Forgot to Close() deobfuscator')

Просмотреть файл

@ -2492,6 +2492,12 @@ if (enable_java_templates) {
outputs = [
_generated_script,
]
if (_proguard_enabled) {
# Required by logcat command.
data_deps = [
"//build/android/stacktrace:java_deobfuscate",
]
}
args = [
"--script-output-path",
rebase_path(_generated_script, root_build_dir),
@ -2511,6 +2517,12 @@ if (enable_java_templates) {
rebase_path(_incremental_install_json_path, root_build_dir),
]
}
if (_proguard_enabled) {
args += [
"--proguard-mapping-path",
rebase_path("$_final_apk_path.mapping", root_build_dir),
]
}
}
_apk_operations += [ ":$_apk_operations_target_name" ]
_incremental_apk_operations += [ ":$_apk_operations_target_name" ]
@ -2686,7 +2698,6 @@ if (enable_java_templates) {
proguard_configs = []
}
proguard_configs += [ "//testing/android/proguard_for_test.flags" ]
data_deps += [ "//build/android/stacktrace:java_deobfuscate" ]
if (defined(final_apk_path)) {
_final_apk_path = final_apk_path
} else {
@ -2828,11 +2839,11 @@ if (enable_java_templates) {
}
shared_libraries = [ invoker.shared_library ]
deps += [
":${target_name}__runtime_deps",
":${target_name}__secondary_abi_runtime_deps",
"//base:base_java",
"//testing/android/appurify_support:appurify_support_java",
"//testing/android/reporter:reporter_java",
":${target_name}__runtime_deps",
":${target_name}__secondary_abi_runtime_deps",
]
data_deps += [
"//build/android/pylib/device/commands",