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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 KEYCODE_HOME = 3 | 62 KEYCODE_HOME = 3 |
64 KEYCODE_BACK = 4 | 63 KEYCODE_BACK = 4 |
65 KEYCODE_DPAD_UP = 19 | 64 KEYCODE_DPAD_UP = 19 |
66 KEYCODE_DPAD_DOWN = 20 | 65 KEYCODE_DPAD_DOWN = 20 |
67 KEYCODE_DPAD_RIGHT = 22 | 66 KEYCODE_DPAD_RIGHT = 22 |
68 KEYCODE_ENTER = 66 | 67 KEYCODE_ENTER = 66 |
69 KEYCODE_MENU = 82 | 68 KEYCODE_MENU = 82 |
70 | 69 |
71 MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/' | 70 MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/' |
72 MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin' | 71 MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin' |
73 MD5SUM_LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % MD5SUM_DEVICE_FOLDER | 72 |
73 PIE_WRAPPER_PATH = constants.TEST_EXECUTABLE_DIR + '/run_pie' | |
74 | 74 |
75 CONTROL_USB_CHARGING_COMMANDS = [ | 75 CONTROL_USB_CHARGING_COMMANDS = [ |
76 { | 76 { |
77 # Nexus 4 | 77 # Nexus 4 |
78 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', | 78 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', |
79 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', | 79 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', |
80 'disable_command': | 80 'disable_command': |
81 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', | 81 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', |
82 }, | 82 }, |
83 ] | 83 ] |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
292 self._external_storage = '' | 292 self._external_storage = '' |
293 self._util_wrapper = '' | 293 self._util_wrapper = '' |
294 self._system_properties = system_properties.SystemProperties(self.Adb()) | 294 self._system_properties = system_properties.SystemProperties(self.Adb()) |
295 self._push_if_needed_cache = {} | 295 self._push_if_needed_cache = {} |
296 self._control_usb_charging_command = { | 296 self._control_usb_charging_command = { |
297 'command': None, | 297 'command': None, |
298 'cached': False, | 298 'cached': False, |
299 } | 299 } |
300 self._protected_file_access_method_initialized = None | 300 self._protected_file_access_method_initialized = None |
301 self._privileged_command_runner = None | 301 self._privileged_command_runner = None |
302 self._pie_wrapper = None | |
302 | 303 |
303 @property | 304 @property |
304 def system_properties(self): | 305 def system_properties(self): |
305 return self._system_properties | 306 return self._system_properties |
306 | 307 |
307 def _LogShell(self, cmd): | 308 def _LogShell(self, cmd): |
308 """Logs the adb shell command.""" | 309 """Logs the adb shell command.""" |
309 if self._device: | 310 if self._device: |
310 device_repr = self._device[-4:] | 311 device_repr = self._device[-4:] |
311 else: | 312 else: |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
644 | 645 |
645 base_command = shlex.split(command)[0].strip(';') | 646 base_command = shlex.split(command)[0].strip(';') |
646 if (base_command in preferred_apis and | 647 if (base_command in preferred_apis and |
647 (base_command not in whitelisted_callers or | 648 (base_command not in whitelisted_callers or |
648 whitelisted_callers[base_command] not in [ | 649 whitelisted_callers[base_command] not in [ |
649 f[3] for f in inspect.stack()])): | 650 f[3] for f in inspect.stack()])): |
650 error_msg = ('%s should not be run directly. Instead use: %s' % | 651 error_msg = ('%s should not be run directly. Instead use: %s' % |
651 (base_command, preferred_apis[base_command])) | 652 (base_command, preferred_apis[base_command])) |
652 raise ValueError(error_msg) | 653 raise ValueError(error_msg) |
653 | 654 |
655 def GetAndroidToolStatusAndOutput(self, command, lib_path=None, *args, **kw): | |
656 """Runs a native Android binary, wrapping the command as necessary. | |
657 | |
658 This is a specialization of GetShellCommandStatusAndOutput, which is meant | |
659 for running tools/android/ binaries and handle properly: (1) setting the | |
660 lib path (for component=shared_library), (2) using the PIE wrapper wrapper | |
Dominik Grewe
2014/05/14 13:57:54
nit: "PIE wrapper wrapper"?
Primiano Tucci (use gerrit)
2014/05/14 14:23:40
Essentially, a burrito :P
| |
661 on ICS. See crbug.com/373219 for more context. | |
662 | |
663 Args: | |
664 command: String containing the command to send. | |
665 lib_path: (optional) path to the folder containing the dependent libs. | |
666 Same other arguments of GetCmdStatusAndOutput. | |
667 """ | |
668 # The first time this command is run the device is inspected to check | |
669 # whether a wrapper for running PIE executable is needed (only Android ICS) | |
670 # or not. The results is cached, so the wrapper is pushed only once. | |
671 if self._pie_wrapper is None: | |
672 # None: did not check; '': did check and not needed; '/path': use /path. | |
673 self._pie_wrapper = '' | |
674 if self.GetBuildId().startswith('I'): # Ixxxx = Android ICS. | |
675 run_pie_dist_path = os.path.join(constants.GetOutDirectory(), 'run_pie') | |
676 assert os.path.exists(run_pie_dist_path), 'Please build run_pie' | |
677 # The PIE loader must be pushed manually (i.e. no PushIfNeeded) because | |
678 # PushIfNeeded requires md5sum and md5sum requires the wrapper as well. | |
679 command = 'push %s %s' % (run_pie_dist_path, PIE_WRAPPER_PATH) | |
680 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) | |
681 self._pie_wrapper = PIE_WRAPPER_PATH | |
682 | |
683 if self._pie_wrapper: | |
684 command = '%s %s' % (self._pie_wrapper, command) | |
685 if lib_path: | |
686 command = 'LD_LIBRARY_PATH=%s %s' % (lib_path, command) | |
687 return self.GetShellCommandStatusAndOutput(command, *args, **kw) | |
688 | |
654 # It is tempting to turn this function into a generator, however this is not | 689 # It is tempting to turn this function into a generator, however this is not |
655 # possible without using a private (local) adb_shell instance (to ensure no | 690 # possible without using a private (local) adb_shell instance (to ensure no |
656 # other command interleaves usage of it), which would defeat the main aim of | 691 # other command interleaves usage of it), which would defeat the main aim of |
657 # being able to reuse the adb shell instance across commands. | 692 # being able to reuse the adb shell instance across commands. |
658 def RunShellCommand(self, command, timeout_time=20, log_result=False): | 693 def RunShellCommand(self, command, timeout_time=20, log_result=False): |
659 """Send a command to the adb shell and return the result. | 694 """Send a command to the adb shell and return the result. |
660 | 695 |
661 Args: | 696 Args: |
662 command: String containing the shell command to send. Must not include | 697 command: String containing the shell command to send. Must not include |
663 the single quotes as we use them to escape the whole command. | 698 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... | |
921 Returns: | 956 Returns: |
922 A tuple containing lists of the host and device md5sum results as | 957 A tuple containing lists of the host and device md5sum results as |
923 created by _ParseMd5SumOutput(). | 958 created by _ParseMd5SumOutput(). |
924 """ | 959 """ |
925 md5sum_dist_path = os.path.join(constants.GetOutDirectory(), | 960 md5sum_dist_path = os.path.join(constants.GetOutDirectory(), |
926 'md5sum_dist') | 961 'md5sum_dist') |
927 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' | 962 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' |
928 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) | 963 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) |
929 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) | 964 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) |
930 | 965 |
931 cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' + | 966 (_, md5_device_output) = self.GetAndroidToolStatusAndOutput( |
932 MD5SUM_DEVICE_PATH + ' ' + device_path) | 967 self._util_wrapper + ' ' + MD5SUM_DEVICE_PATH + ' ' + device_path, |
933 device_hash_tuples = _ParseMd5SumOutput( | 968 lib_path=MD5SUM_DEVICE_FOLDER, |
934 self.RunShellCommand(cmd, timeout_time=2 * 60)) | 969 timeout_time=2 * 60) |
970 device_hash_tuples = _ParseMd5SumOutput(md5_device_output) | |
935 assert os.path.exists(host_path), 'Local path not found %s' % host_path | 971 assert os.path.exists(host_path), 'Local path not found %s' % host_path |
936 md5sum_output = cmd_helper.GetCmdOutput( | 972 md5sum_output = cmd_helper.GetCmdOutput( |
937 [os.path.join(constants.GetOutDirectory(), 'md5sum_bin_host'), | 973 [os.path.join(constants.GetOutDirectory(), 'md5sum_bin_host'), |
938 host_path]) | 974 host_path]) |
939 host_hash_tuples = _ParseMd5SumOutput(md5sum_output.splitlines()) | 975 host_hash_tuples = _ParseMd5SumOutput(md5sum_output.splitlines()) |
940 return (host_hash_tuples, device_hash_tuples) | 976 return (host_hash_tuples, device_hash_tuples) |
941 | 977 |
942 def GetFilesChanged(self, host_path, device_path, ignore_filenames=False): | 978 def GetFilesChanged(self, host_path, device_path, ignore_filenames=False): |
943 """Compares the md5sum of a host path against a device path. | 979 """Compares the md5sum of a host path against a device path. |
944 | 980 |
(...skipping 1024 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1969 """ | 2005 """ |
1970 def __init__(self, output): | 2006 def __init__(self, output): |
1971 self._output = output | 2007 self._output = output |
1972 | 2008 |
1973 def write(self, data): | 2009 def write(self, data): |
1974 data = data.replace('\r\r\n', '\n') | 2010 data = data.replace('\r\r\n', '\n') |
1975 self._output.write(data) | 2011 self._output.write(data) |
1976 | 2012 |
1977 def flush(self): | 2013 def flush(self): |
1978 self._output.flush() | 2014 self._output.flush() |
OLD | NEW |