OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 """Provides an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
6 | 6 |
7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
8 """ | 8 """ |
9 # pylint: disable-all | 9 # pylint: disable-all |
10 | 10 |
11 import collections | 11 import collections |
12 import datetime | 12 import datetime |
13 import inspect | 13 import inspect |
14 import json | |
15 import logging | 14 import logging |
16 import os | 15 import os |
17 import re | 16 import re |
18 import shlex | 17 import shlex |
19 import signal | 18 import signal |
20 import subprocess | 19 import subprocess |
21 import sys | 20 import sys |
22 import tempfile | 21 import tempfile |
23 import time | 22 import time |
24 | 23 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 KEYCODE_HOME = 3 | 58 KEYCODE_HOME = 3 |
60 KEYCODE_BACK = 4 | 59 KEYCODE_BACK = 4 |
61 KEYCODE_DPAD_UP = 19 | 60 KEYCODE_DPAD_UP = 19 |
62 KEYCODE_DPAD_DOWN = 20 | 61 KEYCODE_DPAD_DOWN = 20 |
63 KEYCODE_DPAD_RIGHT = 22 | 62 KEYCODE_DPAD_RIGHT = 22 |
64 KEYCODE_ENTER = 66 | 63 KEYCODE_ENTER = 66 |
65 KEYCODE_MENU = 82 | 64 KEYCODE_MENU = 82 |
66 | 65 |
67 MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/' | 66 MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/' |
68 MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin' | 67 MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin' |
69 MD5SUM_LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % MD5SUM_DEVICE_FOLDER | 68 |
| 69 PIE_WRAPPER_PATH = constants.TEST_EXECUTABLE_DIR + '/run_pie' |
70 | 70 |
71 CONTROL_USB_CHARGING_COMMANDS = [ | 71 CONTROL_USB_CHARGING_COMMANDS = [ |
72 { | 72 { |
73 # Nexus 4 | 73 # Nexus 4 |
74 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', | 74 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', |
75 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', | 75 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', |
76 'disable_command': | 76 'disable_command': |
77 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', | 77 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', |
78 }, | 78 }, |
79 ] | 79 ] |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 self._external_storage = '' | 288 self._external_storage = '' |
289 self._util_wrapper = '' | 289 self._util_wrapper = '' |
290 self._system_properties = system_properties.SystemProperties(self.Adb()) | 290 self._system_properties = system_properties.SystemProperties(self.Adb()) |
291 self._push_if_needed_cache = {} | 291 self._push_if_needed_cache = {} |
292 self._control_usb_charging_command = { | 292 self._control_usb_charging_command = { |
293 'command': None, | 293 'command': None, |
294 'cached': False, | 294 'cached': False, |
295 } | 295 } |
296 self._protected_file_access_method_initialized = None | 296 self._protected_file_access_method_initialized = None |
297 self._privileged_command_runner = None | 297 self._privileged_command_runner = None |
| 298 self._pie_wrapper = None |
298 | 299 |
299 @property | 300 @property |
300 def system_properties(self): | 301 def system_properties(self): |
301 return self._system_properties | 302 return self._system_properties |
302 | 303 |
303 def _LogShell(self, cmd): | 304 def _LogShell(self, cmd): |
304 """Logs the adb shell command.""" | 305 """Logs the adb shell command.""" |
305 if self._device: | 306 if self._device: |
306 device_repr = self._device[-4:] | 307 device_repr = self._device[-4:] |
307 else: | 308 else: |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 | 641 |
641 base_command = shlex.split(command)[0].strip(';') | 642 base_command = shlex.split(command)[0].strip(';') |
642 if (base_command in preferred_apis and | 643 if (base_command in preferred_apis and |
643 (base_command not in whitelisted_callers or | 644 (base_command not in whitelisted_callers or |
644 whitelisted_callers[base_command] not in [ | 645 whitelisted_callers[base_command] not in [ |
645 f[3] for f in inspect.stack()])): | 646 f[3] for f in inspect.stack()])): |
646 error_msg = ('%s should not be run directly. Instead use: %s' % | 647 error_msg = ('%s should not be run directly. Instead use: %s' % |
647 (base_command, preferred_apis[base_command])) | 648 (base_command, preferred_apis[base_command])) |
648 raise ValueError(error_msg) | 649 raise ValueError(error_msg) |
649 | 650 |
| 651 def GetAndroidToolStatusAndOutput(self, command, lib_path=None, *args, **kw): |
| 652 """Runs a native Android binary, wrapping the command as necessary. |
| 653 |
| 654 This is a specialization of GetShellCommandStatusAndOutput, which is meant |
| 655 for running tools/android/ binaries and handle properly: (1) setting the |
| 656 lib path (for component=shared_library), (2) using the PIE wrapper on ICS. |
| 657 See crbug.com/373219 for more context. |
| 658 |
| 659 Args: |
| 660 command: String containing the command to send. |
| 661 lib_path: (optional) path to the folder containing the dependent libs. |
| 662 Same other arguments of GetCmdStatusAndOutput. |
| 663 """ |
| 664 # The first time this command is run the device is inspected to check |
| 665 # whether a wrapper for running PIE executable is needed (only Android ICS) |
| 666 # or not. The results is cached, so the wrapper is pushed only once. |
| 667 if self._pie_wrapper is None: |
| 668 # None: did not check; '': did check and not needed; '/path': use /path. |
| 669 self._pie_wrapper = '' |
| 670 if self.GetBuildId().startswith('I'): # Ixxxx = Android ICS. |
| 671 run_pie_dist_path = os.path.join(constants.GetOutDirectory(), 'run_pie') |
| 672 assert os.path.exists(run_pie_dist_path), 'Please build run_pie' |
| 673 # The PIE loader must be pushed manually (i.e. no PushIfNeeded) because |
| 674 # PushIfNeeded requires md5sum and md5sum requires the wrapper as well. |
| 675 command = 'push %s %s' % (run_pie_dist_path, PIE_WRAPPER_PATH) |
| 676 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) |
| 677 self._pie_wrapper = PIE_WRAPPER_PATH |
| 678 |
| 679 if self._pie_wrapper: |
| 680 command = '%s %s' % (self._pie_wrapper, command) |
| 681 if lib_path: |
| 682 command = 'LD_LIBRARY_PATH=%s %s' % (lib_path, command) |
| 683 return self.GetShellCommandStatusAndOutput(command, *args, **kw) |
| 684 |
650 # It is tempting to turn this function into a generator, however this is not | 685 # It is tempting to turn this function into a generator, however this is not |
651 # possible without using a private (local) adb_shell instance (to ensure no | 686 # possible without using a private (local) adb_shell instance (to ensure no |
652 # other command interleaves usage of it), which would defeat the main aim of | 687 # other command interleaves usage of it), which would defeat the main aim of |
653 # being able to reuse the adb shell instance across commands. | 688 # being able to reuse the adb shell instance across commands. |
654 def RunShellCommand(self, command, timeout_time=20, log_result=False): | 689 def RunShellCommand(self, command, timeout_time=20, log_result=False): |
655 """Send a command to the adb shell and return the result. | 690 """Send a command to the adb shell and return the result. |
656 | 691 |
657 Args: | 692 Args: |
658 command: String containing the shell command to send. Must not include | 693 command: String containing the shell command to send. Must not include |
659 the single quotes as we use them to escape the whole command. | 694 the single quotes as we use them to escape the whole command. |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
917 Returns: | 952 Returns: |
918 A tuple containing lists of the host and device md5sum results as | 953 A tuple containing lists of the host and device md5sum results as |
919 created by _ParseMd5SumOutput(). | 954 created by _ParseMd5SumOutput(). |
920 """ | 955 """ |
921 md5sum_dist_path = os.path.join(constants.GetOutDirectory(), | 956 md5sum_dist_path = os.path.join(constants.GetOutDirectory(), |
922 'md5sum_dist') | 957 'md5sum_dist') |
923 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' | 958 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' |
924 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) | 959 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) |
925 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) | 960 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) |
926 | 961 |
927 cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' + | 962 (_, md5_device_output) = self.GetAndroidToolStatusAndOutput( |
928 MD5SUM_DEVICE_PATH + ' ' + device_path) | 963 self._util_wrapper + ' ' + MD5SUM_DEVICE_PATH + ' ' + device_path, |
929 device_hash_tuples = _ParseMd5SumOutput( | 964 lib_path=MD5SUM_DEVICE_FOLDER, |
930 self.RunShellCommand(cmd, timeout_time=2 * 60)) | 965 timeout_time=2 * 60) |
| 966 device_hash_tuples = _ParseMd5SumOutput(md5_device_output) |
931 assert os.path.exists(host_path), 'Local path not found %s' % host_path | 967 assert os.path.exists(host_path), 'Local path not found %s' % host_path |
932 md5sum_output = cmd_helper.GetCmdOutput( | 968 md5sum_output = cmd_helper.GetCmdOutput( |
933 [os.path.join(constants.GetOutDirectory(), 'md5sum_bin_host'), | 969 [os.path.join(constants.GetOutDirectory(), 'md5sum_bin_host'), |
934 host_path]) | 970 host_path]) |
935 host_hash_tuples = _ParseMd5SumOutput(md5sum_output.splitlines()) | 971 host_hash_tuples = _ParseMd5SumOutput(md5sum_output.splitlines()) |
936 return (host_hash_tuples, device_hash_tuples) | 972 return (host_hash_tuples, device_hash_tuples) |
937 | 973 |
938 def GetFilesChanged(self, host_path, device_path, ignore_filenames=False): | 974 def GetFilesChanged(self, host_path, device_path, ignore_filenames=False): |
939 """Compares the md5sum of a host path against a device path. | 975 """Compares the md5sum of a host path against a device path. |
940 | 976 |
(...skipping 983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1924 """ | 1960 """ |
1925 def __init__(self, output): | 1961 def __init__(self, output): |
1926 self._output = output | 1962 self._output = output |
1927 | 1963 |
1928 def write(self, data): | 1964 def write(self, data): |
1929 data = data.replace('\r\r\n', '\n') | 1965 data = data.replace('\r\r\n', '\n') |
1930 self._output.write(data) | 1966 self._output.write(data) |
1931 | 1967 |
1932 def flush(self): | 1968 def flush(self): |
1933 self._output.flush() | 1969 self._output.flush() |
OLD | NEW |