java_deobfuscate_test.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #!/usr/bin/env vpython3
  2. #
  3. # Copyright 2017 The Chromium Authors. All rights reserved.
  4. # Use of this source code is governed by a BSD-style license that can be
  5. # found in the LICENSE file.
  6. """Tests for java_deobfuscate."""
  7. import argparse
  8. import os
  9. import subprocess
  10. import sys
  11. import tempfile
  12. import unittest
  13. # Set by command-line argument.
  14. _JAVA_DEOBFUSCATE_PATH = None
  15. LINE_PREFIXES = [
  16. '',
  17. # logcat -v threadtime
  18. '09-08 14:38:35.535 18029 18084 E qcom_sensors_hal: ',
  19. # logcat
  20. 'W/GCM (15158): ',
  21. 'W/GCM ( 158): ',
  22. ]
  23. TEST_MAP = """\
  24. this.was.Deobfuscated -> FOO:
  25. int[] mFontFamily -> a
  26. 1:3:void someMethod(int,android.os.Bundle):65:67 -> bar
  27. never.Deobfuscated -> NOTFOO:
  28. int[] mFontFamily -> a
  29. 1:3:void someMethod(int,android.os.Bundle):65:67 -> bar
  30. """
  31. TEST_DATA = [
  32. '',
  33. 'FOO',
  34. 'FOO.bar',
  35. 'Here is a FOO',
  36. 'Here is a class FOO',
  37. 'Here is a class FOO baz',
  38. 'Here is a "FOO" baz',
  39. 'Here is a type "FOO" baz',
  40. 'Here is a "FOO.bar" baz',
  41. 'SomeError: SomeFrameworkClass in isTestClass for FOO',
  42. 'Here is a FOO.bar',
  43. 'Here is a FOO.bar baz',
  44. 'END FOO#bar',
  45. 'new-instance 3810 (LSome/Framework/Class;) in LFOO;',
  46. 'FOO: Error message',
  47. 'Caused by: FOO: Error message',
  48. '\tat FOO.bar(PG:1)',
  49. '\t at\t FOO.bar\t (\t PG:\t 1\t )',
  50. '0xfff \t( \tPG:\t 1 \t)\tFOO.bar',
  51. ('Unable to start activity ComponentInfo{garbage.in/here.test}:'
  52. ' java.lang.NullPointerException: Attempt to invoke interface method'
  53. ' \'void FOO.bar(int,android.os.Bundle)\' on a null object reference'),
  54. ('Caused by: java.lang.NullPointerException: Attempt to read from field'
  55. ' \'int[] FOO.a\' on a null object reference'),
  56. 'java.lang.VerifyError: FOO',
  57. ('java.lang.NoSuchFieldError: No instance field a of type '
  58. 'Ljava/lang/Class; in class LFOO;'),
  59. 'NOTFOO: Object of type FOO was not destroyed...',
  60. ]
  61. EXPECTED_OUTPUT = [
  62. '',
  63. 'this.was.Deobfuscated',
  64. 'this.was.Deobfuscated.someMethod',
  65. 'Here is a FOO',
  66. 'Here is a class this.was.Deobfuscated',
  67. 'Here is a class FOO baz',
  68. 'Here is a "FOO" baz',
  69. 'Here is a type "this.was.Deobfuscated" baz',
  70. 'Here is a "this.was.Deobfuscated.someMethod" baz',
  71. 'SomeError: SomeFrameworkClass in isTestClass for this.was.Deobfuscated',
  72. 'Here is a this.was.Deobfuscated.someMethod',
  73. 'Here is a FOO.bar baz',
  74. 'END this.was.Deobfuscated#someMethod',
  75. 'new-instance 3810 (LSome/Framework/Class;) in Lthis/was/Deobfuscated;',
  76. 'this.was.Deobfuscated: Error message',
  77. 'Caused by: this.was.Deobfuscated: Error message',
  78. '\tat this.was.Deobfuscated.someMethod(Deobfuscated.java:65)',
  79. ('\t at\t this.was.Deobfuscated.someMethod\t '
  80. '(\t Deobfuscated.java:\t 65\t )'),
  81. '0xfff \t( \tDeobfuscated.java:\t 65 \t)\tthis.was.Deobfuscated.someMethod',
  82. ('Unable to start activity ComponentInfo{garbage.in/here.test}:'
  83. ' java.lang.NullPointerException: Attempt to invoke interface method'
  84. ' \'void this.was.Deobfuscated.someMethod(int,android.os.Bundle)\' on a'
  85. ' null object reference'),
  86. ('Caused by: java.lang.NullPointerException: Attempt to read from field'
  87. ' \'int[] this.was.Deobfuscated.mFontFamily\' on a null object reference'),
  88. 'java.lang.VerifyError: this.was.Deobfuscated',
  89. ('java.lang.NoSuchFieldError: No instance field mFontFamily of type '
  90. 'Ljava/lang/Class; in class Lthis/was/Deobfuscated;'),
  91. 'NOTFOO: Object of type this.was.Deobfuscated was not destroyed...',
  92. ]
  93. TEST_DATA = [s + '\n' for s in TEST_DATA]
  94. EXPECTED_OUTPUT = [s + '\n' for s in EXPECTED_OUTPUT]
  95. class JavaDeobfuscateTest(unittest.TestCase):
  96. def __init__(self, *args, **kwargs):
  97. super().__init__(*args, **kwargs)
  98. self._map_file = None
  99. def setUp(self):
  100. self._map_file = tempfile.NamedTemporaryFile()
  101. self._map_file.write(TEST_MAP.encode('utf-8'))
  102. self._map_file.flush()
  103. def tearDown(self):
  104. if self._map_file:
  105. self._map_file.close()
  106. def _testImpl(self, input_lines=None, expected_output_lines=None,
  107. prefix=''):
  108. self.assertTrue(bool(input_lines) == bool(expected_output_lines))
  109. if not input_lines:
  110. input_lines = [prefix + x for x in TEST_DATA]
  111. if not expected_output_lines:
  112. expected_output_lines = [prefix + x for x in EXPECTED_OUTPUT]
  113. cmd = [_JAVA_DEOBFUSCATE_PATH, self._map_file.name]
  114. proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
  115. proc_output, _ = proc.communicate(''.join(input_lines).encode())
  116. actual_output_lines = proc_output.decode().splitlines(True)
  117. for actual, expected in zip(actual_output_lines, expected_output_lines):
  118. self.assertTrue(
  119. actual == expected or actual.replace('bar', 'someMethod') == expected,
  120. msg=''.join([
  121. 'Deobfuscation failed.\n',
  122. ' actual: %s' % actual,
  123. ' expected: %s' % expected]))
  124. def testNoPrefix(self):
  125. self._testImpl(prefix='')
  126. def testThreadtimePrefix(self):
  127. self._testImpl(prefix='09-08 14:38:35.535 18029 18084 E qcom_sensors_hal: ')
  128. def testStandardPrefix(self):
  129. self._testImpl(prefix='W/GCM (15158): ')
  130. def testStandardPrefixWithPadding(self):
  131. self._testImpl(prefix='W/GCM ( 158): ')
  132. @unittest.skip('causes java_deobfuscate to hang, see crbug.com/876539')
  133. def testIndefiniteHang(self):
  134. # Test for crbug.com/876539.
  135. self._testImpl(
  136. input_lines=[
  137. 'VFY: unable to resolve virtual method 2: LFOO;'
  138. + '.onDescendantInvalidated '
  139. + '(Landroid/view/View;Landroid/view/View;)V',
  140. ],
  141. expected_output_lines=[
  142. 'VFY: unable to resolve virtual method 2: Lthis.was.Deobfuscated;'
  143. + '.onDescendantInvalidated '
  144. + '(Landroid/view/View;Landroid/view/View;)V',
  145. ])
  146. if __name__ == '__main__':
  147. parser = argparse.ArgumentParser()
  148. parser.add_argument('--java-deobfuscate-path', type=os.path.realpath,
  149. required=True)
  150. known_args, unittest_args = parser.parse_known_args()
  151. _JAVA_DEOBFUSCATE_PATH = known_args.java_deobfuscate_path
  152. unittest_args = [sys.argv[0]] + unittest_args
  153. unittest.main(argv=unittest_args)