OLD | NEW |
---|---|
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 a variety of device interactions based on adb. | 5 """Provides a variety of device interactions based on adb. |
6 | 6 |
7 Eventually, this will be based on adb_wrapper. | 7 Eventually, this will be based on adb_wrapper. |
8 """ | 8 """ |
9 # pylint: disable=W0613 | 9 # pylint: disable=W0613 |
10 | 10 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
67 """Restarts the adb server. | 67 """Restarts the adb server. |
68 | 68 |
69 Raises: | 69 Raises: |
70 CommandFailedError if we fail to kill or restart the server. | 70 CommandFailedError if we fail to kill or restart the server. |
71 """ | 71 """ |
72 pylib.android_commands.AndroidCommands().RestartAdbServer() | 72 pylib.android_commands.AndroidCommands().RestartAdbServer() |
73 | 73 |
74 | 74 |
75 class DeviceUtils(object): | 75 class DeviceUtils(object): |
76 | 76 |
77 _MAX_ADB_COMMAND_LENGTH = 512 | |
77 _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') | 78 _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') |
78 | 79 |
79 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, | 80 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, |
80 default_retries=_DEFAULT_RETRIES): | 81 default_retries=_DEFAULT_RETRIES): |
81 """DeviceUtils constructor. | 82 """DeviceUtils constructor. |
82 | 83 |
83 Args: | 84 Args: |
84 device: Either a device serial, an existing AdbWrapper instance, or an | 85 device: Either a device serial, an existing AdbWrapper instance, or an |
85 an existing AndroidCommands instance. | 86 an existing AndroidCommands instance. |
86 default_timeout: An integer containing the default number of seconds to | 87 default_timeout: An integer containing the default number of seconds to |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
428 more lines. | 429 more lines. |
429 CommandTimeoutError on timeout. | 430 CommandTimeoutError on timeout. |
430 DeviceUnreachableError on missing device. | 431 DeviceUnreachableError on missing device. |
431 """ | 432 """ |
432 def env_quote(key, value): | 433 def env_quote(key, value): |
433 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key): | 434 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key): |
434 raise KeyError('Invalid shell variable name %r' % key) | 435 raise KeyError('Invalid shell variable name %r' % key) |
435 # using double quotes here to allow interpolation of shell variables | 436 # using double quotes here to allow interpolation of shell variables |
436 return '%s=%s' % (key, cmd_helper.DoubleQuote(value)) | 437 return '%s=%s' % (key, cmd_helper.DoubleQuote(value)) |
437 | 438 |
439 def do_run(cmd): | |
440 try: | |
441 return self.adb.Shell(cmd) | |
442 except device_errors.AdbCommandFailedError as exc: | |
443 if check_return: | |
444 raise | |
445 else: | |
446 return exc.output | |
447 | |
438 if not isinstance(cmd, basestring): | 448 if not isinstance(cmd, basestring): |
439 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) | 449 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) |
440 if env: | 450 if env: |
441 env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) | 451 env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) |
442 cmd = '%s %s' % (env, cmd) | 452 cmd = '%s %s' % (env, cmd) |
443 if cwd: | 453 if cwd: |
444 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) | 454 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) |
445 if as_root and self.NeedsSU(): | 455 if as_root and self.NeedsSU(): |
446 # "su -c sh -c" allows using shell features in |cmd| | 456 # "su -c sh -c" allows using shell features in |cmd| |
447 cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd) | 457 cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd) |
448 if timeout is None: | 458 if timeout is None: |
449 timeout = self._default_timeout | 459 timeout = self._default_timeout |
450 | 460 |
451 try: | 461 if len(cmd) < self._MAX_ADB_COMMAND_LENGTH: |
452 output = self.adb.Shell(cmd) | 462 output = do_run(cmd) |
453 except device_errors.AdbCommandFailedError as e: | 463 else: |
454 if check_return: | 464 with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script: |
455 raise | 465 self._WriteFileWithPush(script.name, cmd) |
456 else: | 466 logging.info('Large shell command will be run from file: %s ...', |
457 output = e.output | 467 cmd[:100]) |
perezju
2014/12/15 15:48:59
I've noted that running large shell commands in th
jbudorick
2014/12/15 23:18:28
sgtm
| |
468 output = do_run('sh %s' % script.name_quoted) | |
458 | 469 |
459 output = output.splitlines() | 470 output = output.splitlines() |
460 if single_line: | 471 if single_line: |
461 if not output: | 472 if not output: |
462 return '' | 473 return '' |
463 elif len(output) == 1: | 474 elif len(output) == 1: |
464 return output[0] | 475 return output[0] |
465 else: | 476 else: |
466 msg = 'one line of output was expected, but got: %s' | 477 msg = 'one line of output was expected, but got: %s' |
467 raise device_errors.CommandFailedError(msg % output, str(self)) | 478 raise device_errors.CommandFailedError(msg % output, str(self)) |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
893 # TODO(jbudorick) Evaluate whether we want to return a list of lines after | 904 # TODO(jbudorick) Evaluate whether we want to return a list of lines after |
894 # the implementation switch, and if file not found should raise exception. | 905 # the implementation switch, and if file not found should raise exception. |
895 if as_root: | 906 if as_root: |
896 if not self.old_interface.CanAccessProtectedFileContents(): | 907 if not self.old_interface.CanAccessProtectedFileContents(): |
897 raise device_errors.CommandFailedError( | 908 raise device_errors.CommandFailedError( |
898 'Cannot read from %s with root privileges.' % device_path) | 909 'Cannot read from %s with root privileges.' % device_path) |
899 return self.old_interface.GetProtectedFileContents(device_path) | 910 return self.old_interface.GetProtectedFileContents(device_path) |
900 else: | 911 else: |
901 return self.old_interface.GetFileContents(device_path) | 912 return self.old_interface.GetFileContents(device_path) |
902 | 913 |
914 def _WriteFileWithPush(self, device_path, contents): | |
915 with tempfile.NamedTemporaryFile() as host_temp: | |
916 host_temp.write(contents) | |
917 host_temp.flush() | |
918 self.adb.Push(host_temp.name, device_path) | |
919 | |
903 @decorators.WithTimeoutAndRetriesFromInstance() | 920 @decorators.WithTimeoutAndRetriesFromInstance() |
904 def WriteFile(self, device_path, contents, as_root=False, force_push=False, | 921 def WriteFile(self, device_path, contents, as_root=False, force_push=False, |
905 timeout=None, retries=None): | 922 timeout=None, retries=None): |
906 """Writes |contents| to a file on the device. | 923 """Writes |contents| to a file on the device. |
907 | 924 |
908 Args: | 925 Args: |
909 device_path: A string containing the absolute path to the file to write | 926 device_path: A string containing the absolute path to the file to write |
910 on the device. | 927 on the device. |
911 contents: A string containing the data to write to the device. | 928 contents: A string containing the data to write to the device. |
912 as_root: A boolean indicating whether the write should be executed with | 929 as_root: A boolean indicating whether the write should be executed with |
913 root privileges (if available). | 930 root privileges (if available). |
914 force_push: A boolean indicating whether to force the operation to be | 931 force_push: A boolean indicating whether to force the operation to be |
915 performed by pushing a file to the device. The default is, when the | 932 performed by pushing a file to the device. The default is, when the |
916 contents are short, to pass the contents using a shell script instead. | 933 contents are short, to pass the contents using a shell script instead. |
917 timeout: timeout in seconds | 934 timeout: timeout in seconds |
918 retries: number of retries | 935 retries: number of retries |
919 | 936 |
920 Raises: | 937 Raises: |
921 CommandFailedError if the file could not be written on the device. | 938 CommandFailedError if the file could not be written on the device. |
922 CommandTimeoutError on timeout. | 939 CommandTimeoutError on timeout. |
923 DeviceUnreachableError on missing device. | 940 DeviceUnreachableError on missing device. |
924 """ | 941 """ |
925 if len(contents) < 512 and not force_push: | 942 if not force_push and len(contents) < self._MAX_ADB_COMMAND_LENGTH: |
943 # If the contents are small, for efficieny we write the contents with | |
944 # a shell command rather than pushing a file. | |
926 cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents), | 945 cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents), |
927 cmd_helper.SingleQuote(device_path)) | 946 cmd_helper.SingleQuote(device_path)) |
928 self.RunShellCommand(cmd, as_root=as_root, check_return=True) | 947 self.RunShellCommand(cmd, as_root=as_root, check_return=True) |
948 elif as_root and self.NeedsSU(): | |
949 # Adb does not allow to "push with su", so we first push to a temp file | |
950 # on a safe location, and then copy it to the desired location with su. | |
951 with device_temp_file.DeviceTempFile(self.adb) as device_temp: | |
952 self._WriteFileWithPush(device_temp.name, contents) | |
953 # Here we need 'cp' rather than 'mv' because the temp and | |
954 # destination files might be on different file systems (e.g. | |
955 # on internal storage and an external sd card). | |
956 self.RunShellCommand(['cp', device_temp.name, device_path], | |
957 as_root=True, check_return=True) | |
929 else: | 958 else: |
930 with tempfile.NamedTemporaryFile() as host_temp: | 959 # If root is not needed, we can push directly to the desired location. |
931 host_temp.write(contents) | 960 self._WriteFileWithPush(device_path, contents) |
932 host_temp.flush() | |
933 if as_root and self.NeedsSU(): | |
934 with device_temp_file.DeviceTempFile(self.adb) as device_temp: | |
935 self.adb.Push(host_temp.name, device_temp.name) | |
936 # Here we need 'cp' rather than 'mv' because the temp and | |
937 # destination files might be on different file systems (e.g. | |
938 # on internal storage and an external sd card) | |
939 self.RunShellCommand(['cp', device_temp.name, device_path], | |
940 as_root=True, check_return=True) | |
941 else: | |
942 self.adb.Push(host_temp.name, device_path) | |
943 | 961 |
944 @decorators.WithTimeoutAndRetriesFromInstance() | 962 @decorators.WithTimeoutAndRetriesFromInstance() |
945 def Ls(self, device_path, timeout=None, retries=None): | 963 def Ls(self, device_path, timeout=None, retries=None): |
946 """Lists the contents of a directory on the device. | 964 """Lists the contents of a directory on the device. |
947 | 965 |
948 Args: | 966 Args: |
949 device_path: A string containing the path of the directory on the device | 967 device_path: A string containing the path of the directory on the device |
950 to list. | 968 to list. |
951 timeout: timeout in seconds | 969 timeout: timeout in seconds |
952 retries: number of retries | 970 retries: number of retries |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1269 Returns: | 1287 Returns: |
1270 A Parallelizer operating over |devices|. | 1288 A Parallelizer operating over |devices|. |
1271 """ | 1289 """ |
1272 if not devices: | 1290 if not devices: |
1273 devices = adb_wrapper.AdbWrapper.GetDevices() | 1291 devices = adb_wrapper.AdbWrapper.GetDevices() |
1274 devices = [d if isinstance(d, cls) else cls(d) for d in devices] | 1292 devices = [d if isinstance(d, cls) else cls(d) for d in devices] |
1275 if async: | 1293 if async: |
1276 return parallelizer.Parallelizer(devices) | 1294 return parallelizer.Parallelizer(devices) |
1277 else: | 1295 else: |
1278 return parallelizer.SyncParallelizer(devices) | 1296 return parallelizer.SyncParallelizer(devices) |
OLD | NEW |