Chromium Code Reviews| 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 23 matching lines...) Expand all Loading... | |
| 34 | 34 |
| 35 """ | 35 """ |
| 36 # pylint: disable=R0201 | 36 # pylint: disable=R0201 |
| 37 | 37 |
| 38 import logging | 38 import logging |
| 39 import os | 39 import os |
| 40 import re | 40 import re |
| 41 import time | 41 import time |
| 42 | 42 |
| 43 from pylib import constants | 43 from pylib import constants |
| 44 from pylib import android_commands | |
| 45 from pylib.base import base_test_result | 44 from pylib.base import base_test_result |
| 46 | 45 |
| 47 | 46 |
| 48 ResultType = base_test_result.ResultType | 47 ResultType = base_test_result.ResultType |
| 49 | 48 |
| 50 _PACKAGE_NAME = 'org.chromium.chromium_linker_test_apk' | 49 _PACKAGE_NAME = 'org.chromium.chromium_linker_test_apk' |
| 51 _ACTIVITY_NAME = '.ChromiumLinkerTestActivity' | 50 _ACTIVITY_NAME = '.ChromiumLinkerTestActivity' |
| 52 _COMMAND_LINE_FILE = '/data/local/tmp/chromium-linker-test-command-line' | 51 _COMMAND_LINE_FILE = '/data/local/tmp/chromium-linker-test-command-line' |
| 53 | 52 |
| 54 # Path to the Linker.java source file. | 53 # Path to the Linker.java source file. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 102 return None | 101 return None |
| 103 | 102 |
| 104 if configs[0] not in ['NEVER', 'LOW_RAM_ONLY', 'ALWAYS']: | 103 if configs[0] not in ['NEVER', 'LOW_RAM_ONLY', 'ALWAYS']: |
| 105 logging.error('Unexpected browser config value: ' + configs[0]) | 104 logging.error('Unexpected browser config value: ' + configs[0]) |
| 106 return None | 105 return None |
| 107 | 106 |
| 108 logging.info('Found linker browser shared RELRO config: ' + configs[0]) | 107 logging.info('Found linker browser shared RELRO config: ' + configs[0]) |
| 109 return configs[0] | 108 return configs[0] |
| 110 | 109 |
| 111 | 110 |
| 112 def _WriteCommandLineFile(adb, command_line, command_line_file): | 111 def _WriteCommandLineFile(device, command_line, command_line_file): |
| 113 """Create a command-line file on the device. This does not use FlagChanger | 112 """Create a command-line file on the device. This does not use FlagChanger |
| 114 because its implementation assumes the device has 'su', and thus does | 113 because its implementation assumes the device has 'su', and thus does |
|
craigdh
2014/04/09 15:55:02
I believe I fixed FlagChanger a while back so the
jbudorick
2014/04/09 20:03:33
The only use of _WriteCommandLineFile attempts to
| |
| 115 not work at all with production devices.""" | 114 not work at all with production devices.""" |
| 116 adb.RunShellCommand('echo "%s" > %s' % (command_line, command_line_file)) | 115 device.old_interface.RunShellCommand( |
| 116 'echo "%s" > %s' % (command_line, command_line_file)) | |
| 117 | 117 |
| 118 | 118 |
| 119 def _CheckLinkerTestStatus(logcat): | 119 def _CheckLinkerTestStatus(logcat): |
| 120 """Parse the content of |logcat| and checks for both a browser and | 120 """Parse the content of |logcat| and checks for both a browser and |
| 121 renderer status line. | 121 renderer status line. |
| 122 | 122 |
| 123 Args: | 123 Args: |
| 124 logcat: A string to parse. Can include line separators. | 124 logcat: A string to parse. Can include line separators. |
| 125 | 125 |
| 126 Returns: | 126 Returns: |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 141 else: | 141 else: |
| 142 assert False, 'Invalid process type ' + process_type | 142 assert False, 'Invalid process type ' + process_type |
| 143 | 143 |
| 144 if browser_found and renderer_found: | 144 if browser_found and renderer_found: |
| 145 return (True, browser_success, renderer_success) | 145 return (True, browser_success, renderer_success) |
| 146 | 146 |
| 147 # Didn't find anything. | 147 # Didn't find anything. |
| 148 return (False, None, None) | 148 return (False, None, None) |
| 149 | 149 |
| 150 | 150 |
| 151 def _StartActivityAndWaitForLinkerTestStatus(adb, timeout): | 151 def _StartActivityAndWaitForLinkerTestStatus(device, timeout): |
| 152 """Force-start an activity and wait up to |timeout| seconds until the full | 152 """Force-start an activity and wait up to |timeout| seconds until the full |
| 153 linker test status lines appear in the logcat, recorded through |adb|. | 153 linker test status lines appear in the logcat, recorded through |device|. |
| 154 Args: | 154 Args: |
| 155 adb: An AndroidCommands instance. | 155 device: A DeviceUtils instance. |
| 156 timeout: Timeout in seconds | 156 timeout: Timeout in seconds |
| 157 Returns: | 157 Returns: |
| 158 A (status, logs) tuple, where status is a ResultType constant, and logs | 158 A (status, logs) tuple, where status is a ResultType constant, and logs |
| 159 if the final logcat output as a string. | 159 if the final logcat output as a string. |
| 160 """ | 160 """ |
| 161 # 1. Start recording logcat with appropriate filters. | 161 # 1. Start recording logcat with appropriate filters. |
| 162 adb.StartRecordingLogcat(clear=True, filters=_LOGCAT_FILTERS) | 162 device.old_interface.StartRecordingLogcat( |
| 163 clear=True, filters=_LOGCAT_FILTERS) | |
| 163 | 164 |
| 164 try: | 165 try: |
| 165 # 2. Force-start activity. | 166 # 2. Force-start activity. |
| 166 adb.StartActivity(package=_PACKAGE_NAME, | 167 device.old_interface.StartActivity( |
| 167 activity=_ACTIVITY_NAME, | 168 package=_PACKAGE_NAME, activity=_ACTIVITY_NAME, force_stop=True) |
| 168 force_stop=True) | |
| 169 | 169 |
| 170 # 3. Wait up to |timeout| seconds until the test status is in the logcat. | 170 # 3. Wait up to |timeout| seconds until the test status is in the logcat. |
| 171 num_tries = 0 | 171 num_tries = 0 |
| 172 max_tries = timeout | 172 max_tries = timeout |
| 173 found = False | 173 found = False |
| 174 while num_tries < max_tries: | 174 while num_tries < max_tries: |
| 175 time.sleep(1) | 175 time.sleep(1) |
| 176 num_tries += 1 | 176 num_tries += 1 |
| 177 found, browser_ok, renderer_ok = _CheckLinkerTestStatus( | 177 found, browser_ok, renderer_ok = _CheckLinkerTestStatus( |
| 178 adb.GetCurrentRecordedLogcat()) | 178 device.old_interface.GetCurrentRecordedLogcat()) |
| 179 if found: | 179 if found: |
| 180 break | 180 break |
| 181 | 181 |
| 182 finally: | 182 finally: |
| 183 logs = adb.StopRecordingLogcat() | 183 logs = device.old_interface.StopRecordingLogcat() |
| 184 | 184 |
| 185 if num_tries >= max_tries: | 185 if num_tries >= max_tries: |
| 186 return ResultType.TIMEOUT, logs | 186 return ResultType.TIMEOUT, logs |
| 187 | 187 |
| 188 if browser_ok and renderer_ok: | 188 if browser_ok and renderer_ok: |
| 189 return ResultType.PASS, logs | 189 return ResultType.PASS, logs |
| 190 | 190 |
| 191 return ResultType.FAIL, logs | 191 return ResultType.FAIL, logs |
| 192 | 192 |
| 193 | 193 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 288 """ | 288 """ |
| 289 self.is_low_memory = is_low_memory | 289 self.is_low_memory = is_low_memory |
| 290 if is_low_memory: | 290 if is_low_memory: |
| 291 test_suffix = 'ForLowMemoryDevice' | 291 test_suffix = 'ForLowMemoryDevice' |
| 292 else: | 292 else: |
| 293 test_suffix = 'ForRegularDevice' | 293 test_suffix = 'ForRegularDevice' |
| 294 class_name = self.__class__.__name__ | 294 class_name = self.__class__.__name__ |
| 295 self.qualified_name = '%s.%s' % (class_name, test_suffix) | 295 self.qualified_name = '%s.%s' % (class_name, test_suffix) |
| 296 self.tagged_name = self.qualified_name | 296 self.tagged_name = self.qualified_name |
| 297 | 297 |
| 298 def _RunTest(self, _adb): | 298 def _RunTest(self, _device): |
| 299 """Run the test, must be overriden. | 299 """Run the test, must be overriden. |
| 300 Args: | 300 Args: |
| 301 _adb: An AndroidCommands instance to the device. | 301 _device: A DeviceUtils interface. |
| 302 Returns: | 302 Returns: |
| 303 A (status, log) tuple, where <status> is a ResultType constant, and <log> | 303 A (status, log) tuple, where <status> is a ResultType constant, and <log> |
| 304 is the logcat output captured during the test in case of error, or None | 304 is the logcat output captured during the test in case of error, or None |
| 305 in case of success. | 305 in case of success. |
| 306 """ | 306 """ |
| 307 return ResultType.FAIL, 'Unimplemented _RunTest() method!' | 307 return ResultType.FAIL, 'Unimplemented _RunTest() method!' |
| 308 | 308 |
| 309 def Run(self, device): | 309 def Run(self, device): |
| 310 """Run the test on a given device. | 310 """Run the test on a given device. |
| 311 Args: | 311 Args: |
| 312 device: Name of target device where to run the test. | 312 device: Name of target device where to run the test. |
| 313 Returns: | 313 Returns: |
| 314 A base_test_result.TestRunResult() instance. | 314 A base_test_result.TestRunResult() instance. |
| 315 """ | 315 """ |
| 316 margin = 8 | 316 margin = 8 |
| 317 print '[ %-*s ] %s' % (margin, 'RUN', self.tagged_name) | 317 print '[ %-*s ] %s' % (margin, 'RUN', self.tagged_name) |
| 318 logging.info('Running linker test: %s', self.tagged_name) | 318 logging.info('Running linker test: %s', self.tagged_name) |
| 319 adb = android_commands.AndroidCommands(device) | |
| 320 | 319 |
| 321 # Create command-line file on device. | 320 # Create command-line file on device. |
| 322 command_line_flags = '' | 321 command_line_flags = '' |
| 323 if self.is_low_memory: | 322 if self.is_low_memory: |
| 324 command_line_flags = '--low-memory-device' | 323 command_line_flags = '--low-memory-device' |
| 325 _WriteCommandLineFile(adb, command_line_flags, _COMMAND_LINE_FILE) | 324 _WriteCommandLineFile(device, command_line_flags, _COMMAND_LINE_FILE) |
| 326 | 325 |
| 327 # Run the test. | 326 # Run the test. |
| 328 status, logs = self._RunTest(adb) | 327 status, logs = self._RunTest(device) |
| 329 | 328 |
| 330 result_text = 'OK' | 329 result_text = 'OK' |
| 331 if status == ResultType.FAIL: | 330 if status == ResultType.FAIL: |
| 332 result_text = 'FAILED' | 331 result_text = 'FAILED' |
| 333 elif status == ResultType.TIMEOUT: | 332 elif status == ResultType.TIMEOUT: |
| 334 result_text = 'TIMEOUT' | 333 result_text = 'TIMEOUT' |
| 335 print '[ %*s ] %s' % (margin, result_text, self.tagged_name) | 334 print '[ %*s ] %s' % (margin, result_text, self.tagged_name) |
| 336 | 335 |
| 337 results = base_test_result.TestRunResults() | 336 results = base_test_result.TestRunResults() |
| 338 results.AddResult( | 337 results.AddResult( |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 367 where <status> can be either FAIL or SUCCESS. These lines can appear | 366 where <status> can be either FAIL or SUCCESS. These lines can appear |
| 368 in any order in the logcat. Once both browser and renderer status are | 367 in any order in the logcat. Once both browser and renderer status are |
| 369 found, stop the loop. Otherwise timeout after 30 seconds. | 368 found, stop the loop. Otherwise timeout after 30 seconds. |
| 370 | 369 |
| 371 Note that there can be other lines beginning with BROWSER_LINKER_TEST: | 370 Note that there can be other lines beginning with BROWSER_LINKER_TEST: |
| 372 and RENDERER_LINKER_TEST:, but are not followed by a <status> code. | 371 and RENDERER_LINKER_TEST:, but are not followed by a <status> code. |
| 373 | 372 |
| 374 - The test case passes if the <status> for both the browser and renderer | 373 - The test case passes if the <status> for both the browser and renderer |
| 375 process are SUCCESS. Otherwise its a fail. | 374 process are SUCCESS. Otherwise its a fail. |
| 376 """ | 375 """ |
| 377 def _RunTest(self, adb): | 376 def _RunTest(self, device): |
| 378 # Wait up to 30 seconds until the linker test status is in the logcat. | 377 # Wait up to 30 seconds until the linker test status is in the logcat. |
| 379 return _StartActivityAndWaitForLinkerTestStatus(adb, timeout=30) | 378 return _StartActivityAndWaitForLinkerTestStatus(device, timeout=30) |
| 380 | 379 |
| 381 | 380 |
| 382 class LinkerLibraryAddressTest(LinkerTestCaseBase): | 381 class LinkerLibraryAddressTest(LinkerTestCaseBase): |
| 383 """A test case that verifies library load addresses. | 382 """A test case that verifies library load addresses. |
| 384 | 383 |
| 385 The point of this check is to ensure that the libraries are loaded | 384 The point of this check is to ensure that the libraries are loaded |
| 386 according to the following rules: | 385 according to the following rules: |
| 387 | 386 |
| 388 - For low-memory devices, they should always be loaded at the same address | 387 - For low-memory devices, they should always be loaded at the same address |
| 389 in both browser and renderer processes, both below 0x4000_0000. | 388 in both browser and renderer processes, both below 0x4000_0000. |
| 390 | 389 |
| 391 - For regular devices, the browser process should load libraries above | 390 - For regular devices, the browser process should load libraries above |
| 392 0x4000_0000, and renderer ones below it. | 391 0x4000_0000, and renderer ones below it. |
| 393 """ | 392 """ |
| 394 def _RunTest(self, adb): | 393 def _RunTest(self, device): |
| 395 result, logs = _StartActivityAndWaitForLinkerTestStatus(adb, timeout=30) | 394 result, logs = _StartActivityAndWaitForLinkerTestStatus(device, timeout=30) |
| 396 | 395 |
| 397 # Return immediately in case of timeout. | 396 # Return immediately in case of timeout. |
| 398 if result == ResultType.TIMEOUT: | 397 if result == ResultType.TIMEOUT: |
| 399 return result, logs | 398 return result, logs |
| 400 | 399 |
| 401 # Collect the library load addresses in the browser and renderer processes. | 400 # Collect the library load addresses in the browser and renderer processes. |
| 402 browser_libs, renderer_libs = _ExtractLibraryLoadAddressesFromLogcat(logs) | 401 browser_libs, renderer_libs = _ExtractLibraryLoadAddressesFromLogcat(logs) |
| 403 | 402 |
| 404 logging.info('Browser libraries: %s', browser_libs) | 403 logging.info('Browser libraries: %s', browser_libs) |
| 405 logging.info('Renderer libraries: %s', renderer_libs) | 404 logging.info('Renderer libraries: %s', renderer_libs) |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 471 | 470 |
| 472 This starts the activity several time (each time forcing a new process | 471 This starts the activity several time (each time forcing a new process |
| 473 creation) and compares the load addresses of the libraries in them to | 472 creation) and compares the load addresses of the libraries in them to |
| 474 detect that they have changed. | 473 detect that they have changed. |
| 475 | 474 |
| 476 In theory, two successive runs could (very rarely) use the same load | 475 In theory, two successive runs could (very rarely) use the same load |
| 477 address, so loop 5 times and compare the values there. It is assumed | 476 address, so loop 5 times and compare the values there. It is assumed |
| 478 that if there are more than one pair of identical addresses, then the | 477 that if there are more than one pair of identical addresses, then the |
| 479 load addresses are not random enough for this test. | 478 load addresses are not random enough for this test. |
| 480 """ | 479 """ |
| 481 def _RunTest(self, adb): | 480 def _RunTest(self, device): |
| 482 max_loops = 5 | 481 max_loops = 5 |
| 483 browser_lib_map_list = [] | 482 browser_lib_map_list = [] |
| 484 renderer_lib_map_list = [] | 483 renderer_lib_map_list = [] |
| 485 logs_list = [] | 484 logs_list = [] |
| 486 for _ in range(max_loops): | 485 for _ in range(max_loops): |
| 487 # Start the activity. | 486 # Start the activity. |
| 488 result, logs = _StartActivityAndWaitForLinkerTestStatus(adb, timeout=30) | 487 result, logs = _StartActivityAndWaitForLinkerTestStatus( |
| 488 device, timeout=30) | |
| 489 if result == ResultType.TIMEOUT: | 489 if result == ResultType.TIMEOUT: |
| 490 # Something bad happened. Return immediately. | 490 # Something bad happened. Return immediately. |
| 491 return result, logs | 491 return result, logs |
| 492 | 492 |
| 493 # Collect library addresses. | 493 # Collect library addresses. |
| 494 browser_libs, renderer_libs = _ExtractLibraryLoadAddressesFromLogcat(logs) | 494 browser_libs, renderer_libs = _ExtractLibraryLoadAddressesFromLogcat(logs) |
| 495 browser_lib_map_list.append(browser_libs) | 495 browser_lib_map_list.append(browser_libs) |
| 496 renderer_lib_map_list.append(renderer_libs) | 496 renderer_lib_map_list.append(renderer_libs) |
| 497 logs_list.append(logs) | 497 logs_list.append(logs) |
| 498 | 498 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 531 # Note that this behaviour doesn't seem to happen when starting an | 531 # Note that this behaviour doesn't seem to happen when starting an |
| 532 # application 'normally', i.e. when using the application launcher to | 532 # application 'normally', i.e. when using the application launcher to |
| 533 # start the activity. | 533 # start the activity. |
| 534 logging.info('Ignoring system\'s low randomization of browser libraries' + | 534 logging.info('Ignoring system\'s low randomization of browser libraries' + |
| 535 ' for regular devices') | 535 ' for regular devices') |
| 536 | 536 |
| 537 if not renderer_status: | 537 if not renderer_status: |
| 538 return ResultType.FAIL, renderer_logs | 538 return ResultType.FAIL, renderer_logs |
| 539 | 539 |
| 540 return ResultType.PASS, logs | 540 return ResultType.PASS, logs |
| OLD | NEW |