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 |