| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Base class for linker-specific test cases. | 5 """Base class for linker-specific test cases. |
| 6 | 6 |
| 7 The custom dynamic linker can only be tested through a custom test case | 7 The custom dynamic linker can only be tested through a custom test case |
| 8 for various technical reasons: | 8 for various technical reasons: |
| 9 | 9 |
| 10 - It's an 'invisible feature', i.e. it doesn't expose a new API or | 10 - It's an 'invisible feature', i.e. it doesn't expose a new API or |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 | 26 |
| 27 Host-driven tests have also been tried, but since they're really | 27 Host-driven tests have also been tried, but since they're really |
| 28 sub-classes of instrumentation tests, they didn't work well either. | 28 sub-classes of instrumentation tests, they didn't work well either. |
| 29 | 29 |
| 30 To build and run the linker tests, do the following: | 30 To build and run the linker tests, do the following: |
| 31 | 31 |
| 32 ninja -C out/Debug content_linker_test_apk | 32 ninja -C out/Debug content_linker_test_apk |
| 33 build/android/test_runner.py linker | 33 build/android/test_runner.py linker |
| 34 | 34 |
| 35 """ | 35 """ |
| 36 # pylint: disable=R0201 |
| 36 | 37 |
| 37 import logging | 38 import logging |
| 38 import os | 39 import os |
| 39 import re | 40 import re |
| 40 import StringIO | |
| 41 import subprocess | |
| 42 import tempfile | |
| 43 import time | 41 import time |
| 44 | 42 |
| 45 from pylib import constants | 43 from pylib import constants |
| 46 from pylib import android_commands | 44 from pylib import android_commands |
| 47 from pylib import flag_changer | |
| 48 from pylib.base import base_test_result | 45 from pylib.base import base_test_result |
| 49 | 46 |
| 47 |
| 50 ResultType = base_test_result.ResultType | 48 ResultType = base_test_result.ResultType |
| 51 | 49 |
| 52 _PACKAGE_NAME='org.chromium.content_linker_test_apk' | 50 _PACKAGE_NAME = 'org.chromium.content_linker_test_apk' |
| 53 _ACTIVITY_NAME='.ContentLinkerTestActivity' | 51 _ACTIVITY_NAME = '.ContentLinkerTestActivity' |
| 54 _COMMAND_LINE_FILE='/data/local/tmp/content-linker-test-command-line' | 52 _COMMAND_LINE_FILE = '/data/local/tmp/content-linker-test-command-line' |
| 55 | 53 |
| 56 # Path to the Linker.java source file. | 54 # Path to the Linker.java source file. |
| 57 _LINKER_JAVA_SOURCE_PATH = \ | 55 _LINKER_JAVA_SOURCE_PATH = ( |
| 58 'content/public/android/java/src/org/chromium/content/app/Linker.java' | 56 'content/public/android/java/src/org/chromium/content/app/Linker.java') |
| 59 | 57 |
| 60 # A regular expression used to extract the browser shared RELRO configuration | 58 # A regular expression used to extract the browser shared RELRO configuration |
| 61 # from the Java source file above. | 59 # from the Java source file above. |
| 62 _RE_LINKER_BROWSER_CONFIG = \ | 60 _RE_LINKER_BROWSER_CONFIG = re.compile( |
| 63 re.compile(r'.*BROWSER_SHARED_RELRO_CONFIG\s+=\s+' + \ | 61 r'.*BROWSER_SHARED_RELRO_CONFIG\s+=\s+' + |
| 64 'BROWSER_SHARED_RELRO_CONFIG_(\S+)\s*;.*', | 62 'BROWSER_SHARED_RELRO_CONFIG_(\S+)\s*;.*', |
| 65 re.MULTILINE | re.DOTALL) | 63 re.MULTILINE | re.DOTALL) |
| 66 | 64 |
| 67 # Logcat filters used during each test. Only the 'chromium' one is really | 65 # Logcat filters used during each test. Only the 'chromium' one is really |
| 68 # needed, but the logs are added to the TestResult in case of error, and | 66 # needed, but the logs are added to the TestResult in case of error, and |
| 69 # it is handy to have the 'content_android_linker' ones as well when | 67 # it is handy to have the 'content_android_linker' ones as well when |
| 70 # troubleshooting. | 68 # troubleshooting. |
| 71 _LOGCAT_FILTERS = [ '*:s', 'chromium:v', 'content_android_linker:v' ] | 69 _LOGCAT_FILTERS = [ '*:s', 'chromium:v', 'content_android_linker:v' ] |
| 72 #_LOGCAT_FILTERS = [ '*:v' ] ## DEBUG | 70 #_LOGCAT_FILTERS = [ '*:v' ] ## DEBUG |
| 73 | 71 |
| 74 # Regular expression used to match status lines in logcat. | 72 # Regular expression used to match status lines in logcat. |
| 75 re_status_line = re.compile(r'(BROWSER|RENDERER)_LINKER_TEST: (FAIL|SUCCESS)') | 73 re_status_line = re.compile(r'(BROWSER|RENDERER)_LINKER_TEST: (FAIL|SUCCESS)') |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 else: | 141 else: |
| 144 assert False, 'Invalid process type ' + process_type | 142 assert False, 'Invalid process type ' + process_type |
| 145 | 143 |
| 146 if browser_found and renderer_found: | 144 if browser_found and renderer_found: |
| 147 return (True, browser_success, renderer_success) | 145 return (True, browser_success, renderer_success) |
| 148 | 146 |
| 149 # Didn't find anything. | 147 # Didn't find anything. |
| 150 return (False, None, None) | 148 return (False, None, None) |
| 151 | 149 |
| 152 | 150 |
| 153 def _WaitForLinkerTestStatus(adb, timeout): | 151 def _WaitForLinkerTestStatus(_adb, _timeout): |
| 154 """Wait up to |timeout| seconds until the full linker test status lines appear | 152 """Wait up to |timeout| seconds until the full linker test status lines appear |
| 155 in the logcat being recorded with |adb|. | 153 in the logcat being recorded with |adb|. |
| 156 Args: | 154 Args: |
| 157 adb: An AndroidCommands instance. This assumes adb.StartRecordingLogcat() | 155 adb: An AndroidCommands instance. This assumes adb.StartRecordingLogcat() |
| 158 was called previously. | 156 was called previously. |
| 159 timeout: Timeout in seconds. | 157 timeout: Timeout in seconds. |
| 160 Returns: | 158 Returns: |
| 161 ResultType.TIMEOUT in case of timeout, ResulType.PASS if both status lines | 159 ResultType.TIMEOUT in case of timeout, ResulType.PASS if both status lines |
| 162 report 'SUCCESS', or ResulType.FAIL otherwise. | 160 report 'SUCCESS', or ResulType.FAIL otherwise. |
| 163 """ | 161 """ |
| 162 pass |
| 164 | 163 |
| 165 | 164 |
| 166 def _StartActivityAndWaitForLinkerTestStatus(adb, timeout): | 165 def _StartActivityAndWaitForLinkerTestStatus(adb, timeout): |
| 167 """Force-start an activity and wait up to |timeout| seconds until the full | 166 """Force-start an activity and wait up to |timeout| seconds until the full |
| 168 linker test status lines appear in the logcat, recorded through |adb|. | 167 linker test status lines appear in the logcat, recorded through |adb|. |
| 169 Args: | 168 Args: |
| 170 adb: An AndroidCommands instance. | 169 adb: An AndroidCommands instance. |
| 171 timeout: Timeout in seconds | 170 timeout: Timeout in seconds |
| 172 Returns: | 171 Returns: |
| 173 A (status, logs) tuple, where status is a ResultType constant, and logs | 172 A (status, logs) tuple, where status is a ResultType constant, and logs |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 for lib_map in lib_map_list: | 268 for lib_map in lib_map_list: |
| 270 for lib_name, lib_address in lib_map.iteritems(): | 269 for lib_name, lib_address in lib_map.iteritems(): |
| 271 if lib_name not in lib_addr_map: | 270 if lib_name not in lib_addr_map: |
| 272 lib_addr_map[lib_name] = AddressList() | 271 lib_addr_map[lib_name] = AddressList() |
| 273 lib_addr_map[lib_name].append(lib_address) | 272 lib_addr_map[lib_name].append(lib_address) |
| 274 | 273 |
| 275 logging.info('%s library load map: %s', process_type, lib_addr_map) | 274 logging.info('%s library load map: %s', process_type, lib_addr_map) |
| 276 | 275 |
| 277 # For each library, check the randomness of its load addresses. | 276 # For each library, check the randomness of its load addresses. |
| 278 bad_libs = {} | 277 bad_libs = {} |
| 279 success = True | |
| 280 for lib_name, lib_address_list in lib_addr_map.iteritems(): | 278 for lib_name, lib_address_list in lib_addr_map.iteritems(): |
| 281 # If all addresses are different, skip to next item. | 279 # If all addresses are different, skip to next item. |
| 282 lib_address_set = set(lib_address_list) | 280 lib_address_set = set(lib_address_list) |
| 283 # Consider that if there is more than one pair of identical addresses in | 281 # Consider that if there is more than one pair of identical addresses in |
| 284 # the list, then randomization is broken. | 282 # the list, then randomization is broken. |
| 285 if len(lib_address_set) < len(lib_address_list) - 1: | 283 if len(lib_address_set) < len(lib_address_list) - 1: |
| 286 bad_libs[lib_name] = lib_address_list | 284 bad_libs[lib_name] = lib_address_list |
| 287 | 285 |
| 288 | 286 |
| 289 if bad_libs: | 287 if bad_libs: |
| 290 return False, '%s libraries failed randomization: %s' % \ | 288 return False, '%s libraries failed randomization: %s' % \ |
| 291 (process_type, bad_libs) | 289 (process_type, bad_libs) |
| 292 | 290 |
| 293 return True, '%s libraries properly randomized: %s' % \ | 291 return True, '%s libraries properly randomized: %s' % \ |
| 294 (process_type, lib_addr_map) | 292 (process_type, lib_addr_map) |
| 295 | 293 |
| 296 | 294 |
| 297 class LinkerTestCaseBase(object): | 295 class LinkerTestCaseBase(object): |
| 298 """Base class for linker test cases.""" | 296 """Base class for linker test cases.""" |
| 299 | 297 |
| 300 def __init__(self, is_low_memory=False): | 298 def __init__(self, is_low_memory=False): |
| 301 """Create a test case. | 299 """Create a test case. |
| 302 Args: | 300 Args: |
| 303 is_low_memory: True to simulate a low-memory device, False otherwise. | 301 is_low_memory: True to simulate a low-memory device, False otherwise. |
| 304 """ | 302 """ |
| 305 self.is_low_memory = is_low_memory | 303 self.is_low_memory = is_low_memory |
| 306 if is_low_memory: | 304 if is_low_memory: |
| 307 test_suffix = 'ForLowMemoryDevice' | 305 test_suffix = 'ForLowMemoryDevice' |
| 308 else: | 306 else: |
| 309 test_suffix = 'ForRegularDevice' | 307 test_suffix = 'ForRegularDevice' |
| 310 class_name = self.__class__.__name__ | 308 class_name = self.__class__.__name__ |
| 311 self.qualified_name = '%s.%s' % (class_name, test_suffix) | 309 self.qualified_name = '%s.%s' % (class_name, test_suffix) |
| 312 self.tagged_name = self.qualified_name | 310 self.tagged_name = self.qualified_name |
| 313 | 311 |
| 314 def _RunTest(self, adb): | 312 def _RunTest(self, _adb): |
| 315 """Run the test, must be overriden. | 313 """Run the test, must be overriden. |
| 316 Args: | 314 Args: |
| 317 adb: An AndroidCommands instance to the device. | 315 _adb: An AndroidCommands instance to the device. |
| 318 Returns: | 316 Returns: |
| 319 A (status, log) tuple, where <status> is a ResultType constant, and <log> | 317 A (status, log) tuple, where <status> is a ResultType constant, and <log> |
| 320 is the logcat output captured during the test in case of error, or None | 318 is the logcat output captured during the test in case of error, or None |
| 321 in case of success. | 319 in case of success. |
| 322 """ | 320 """ |
| 323 return ResultType.FAIL, 'Unimplemented _RunTest() method!' | 321 return ResultType.FAIL, 'Unimplemented _RunTest() method!' |
| 324 | 322 |
| 325 def Run(self, device): | 323 def Run(self, device): |
| 326 """Run the test on a given device. | 324 """Run the test on a given device. |
| 327 Args: | 325 Args: |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 In theory, two successive runs could (very rarely) use the same load | 490 In theory, two successive runs could (very rarely) use the same load |
| 493 address, so loop 5 times and compare the values there. It is assumed | 491 address, so loop 5 times and compare the values there. It is assumed |
| 494 that if there are more than one pair of identical addresses, then the | 492 that if there are more than one pair of identical addresses, then the |
| 495 load addresses are not random enough for this test. | 493 load addresses are not random enough for this test. |
| 496 """ | 494 """ |
| 497 def _RunTest(self, adb): | 495 def _RunTest(self, adb): |
| 498 max_loops = 5 | 496 max_loops = 5 |
| 499 browser_lib_map_list = [] | 497 browser_lib_map_list = [] |
| 500 renderer_lib_map_list = [] | 498 renderer_lib_map_list = [] |
| 501 logs_list = [] | 499 logs_list = [] |
| 502 for loop in range(max_loops): | 500 for _loop in range(max_loops): |
| 503 # Start the activity. | 501 # Start the activity. |
| 504 result, logs = _StartActivityAndWaitForLinkerTestStatus(adb, timeout=30) | 502 result, logs = _StartActivityAndWaitForLinkerTestStatus(adb, timeout=30) |
| 505 if result == ResultType.TIMEOUT: | 503 if result == ResultType.TIMEOUT: |
| 506 # Something bad happened. Return immediately. | 504 # Something bad happened. Return immediately. |
| 507 return result, logs | 505 return result, logs |
| 508 | 506 |
| 509 # Collect library addresses. | 507 # Collect library addresses. |
| 510 browser_libs, renderer_libs = _ExtractLibraryLoadAddressesFromLogcat(logs) | 508 browser_libs, renderer_libs = _ExtractLibraryLoadAddressesFromLogcat(logs) |
| 511 browser_lib_map_list.append(browser_libs) | 509 browser_lib_map_list.append(browser_libs) |
| 512 renderer_lib_map_list.append(renderer_libs) | 510 renderer_lib_map_list.append(renderer_libs) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 # Note that this behaviour doesn't seem to happen when starting an | 545 # Note that this behaviour doesn't seem to happen when starting an |
| 548 # application 'normally', i.e. when using the application launcher to | 546 # application 'normally', i.e. when using the application launcher to |
| 549 # start the activity. | 547 # start the activity. |
| 550 logging.info('Ignoring system\'s low randomization of browser libraries' + | 548 logging.info('Ignoring system\'s low randomization of browser libraries' + |
| 551 ' for regular devices') | 549 ' for regular devices') |
| 552 | 550 |
| 553 if not renderer_status: | 551 if not renderer_status: |
| 554 return ResultType.FAIL, renderer_logs | 552 return ResultType.FAIL, renderer_logs |
| 555 | 553 |
| 556 return ResultType.PASS, logs | 554 return ResultType.PASS, logs |
| OLD | NEW |