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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 """Restarts the adb server. | 51 """Restarts the adb server. |
52 | 52 |
53 Raises: | 53 Raises: |
54 CommandFailedError if we fail to kill or restart the server. | 54 CommandFailedError if we fail to kill or restart the server. |
55 """ | 55 """ |
56 pylib.android_commands.AndroidCommands().RestartAdbServer() | 56 pylib.android_commands.AndroidCommands().RestartAdbServer() |
57 | 57 |
58 | 58 |
59 class DeviceUtils(object): | 59 class DeviceUtils(object): |
60 | 60 |
61 _MAX_ADB_COMMAND_LENGTH = 512 | |
62 _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') | 61 _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') |
63 | 62 |
64 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, | 63 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, |
65 default_retries=_DEFAULT_RETRIES): | 64 default_retries=_DEFAULT_RETRIES): |
66 """DeviceUtils constructor. | 65 """DeviceUtils constructor. |
67 | 66 |
68 Args: | 67 Args: |
69 device: Either a device serial, an existing AdbWrapper instance, or an | 68 device: Either a device serial, an existing AdbWrapper instance, or an |
70 an existing AndroidCommands instance. | 69 an existing AndroidCommands instance. |
71 default_timeout: An integer containing the default number of seconds to | 70 default_timeout: An integer containing the default number of seconds to |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 more lines. | 419 more lines. |
421 CommandTimeoutError on timeout. | 420 CommandTimeoutError on timeout. |
422 DeviceUnreachableError on missing device. | 421 DeviceUnreachableError on missing device. |
423 """ | 422 """ |
424 def env_quote(key, value): | 423 def env_quote(key, value): |
425 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key): | 424 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key): |
426 raise KeyError('Invalid shell variable name %r' % key) | 425 raise KeyError('Invalid shell variable name %r' % key) |
427 # using double quotes here to allow interpolation of shell variables | 426 # using double quotes here to allow interpolation of shell variables |
428 return '%s=%s' % (key, cmd_helper.DoubleQuote(value)) | 427 return '%s=%s' % (key, cmd_helper.DoubleQuote(value)) |
429 | 428 |
430 def do_run(cmd): | |
431 try: | |
432 return self.adb.Shell(cmd) | |
433 except device_errors.AdbCommandFailedError as exc: | |
434 if check_return: | |
435 raise | |
436 else: | |
437 return exc.output | |
438 | |
439 if not isinstance(cmd, basestring): | 429 if not isinstance(cmd, basestring): |
440 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) | 430 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) |
441 if env: | 431 if env: |
442 env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) | 432 env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) |
443 cmd = '%s %s' % (env, cmd) | 433 cmd = '%s %s' % (env, cmd) |
444 if cwd: | 434 if cwd: |
445 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) | 435 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) |
446 if as_root and self.NeedsSU(): | 436 if as_root and self.NeedsSU(): |
447 # "su -c sh -c" allows using shell features in |cmd| | 437 # "su -c sh -c" allows using shell features in |cmd| |
448 cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd) | 438 cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd) |
449 if timeout is None: | 439 if timeout is None: |
450 timeout = self._default_timeout | 440 timeout = self._default_timeout |
451 | 441 |
452 if len(cmd) < self._MAX_ADB_COMMAND_LENGTH: | 442 try: |
453 output = do_run(cmd) | 443 output = self.adb.Shell(cmd) |
454 else: | 444 except device_errors.AdbCommandFailedError as e: |
455 with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script: | 445 if check_return: |
456 self._WriteFileWithPush(script.name, cmd) | 446 raise |
457 output = do_run('sh %s' % script.name_quoted) | 447 else: |
| 448 output = e.output |
458 | 449 |
459 output = output.splitlines() | 450 output = output.splitlines() |
460 if single_line: | 451 if single_line: |
461 if not output: | 452 if not output: |
462 return '' | 453 return '' |
463 elif len(output) == 1: | 454 elif len(output) == 1: |
464 return output[0] | 455 return output[0] |
465 else: | 456 else: |
466 msg = 'one line of output was expected, but got: %s' | 457 msg = 'one line of output was expected, but got: %s' |
467 raise device_errors.CommandFailedError(msg % output, str(self)) | 458 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 | 884 # 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. | 885 # the implementation switch, and if file not found should raise exception. |
895 if as_root: | 886 if as_root: |
896 if not self.old_interface.CanAccessProtectedFileContents(): | 887 if not self.old_interface.CanAccessProtectedFileContents(): |
897 raise device_errors.CommandFailedError( | 888 raise device_errors.CommandFailedError( |
898 'Cannot read from %s with root privileges.' % device_path) | 889 'Cannot read from %s with root privileges.' % device_path) |
899 return self.old_interface.GetProtectedFileContents(device_path) | 890 return self.old_interface.GetProtectedFileContents(device_path) |
900 else: | 891 else: |
901 return self.old_interface.GetFileContents(device_path) | 892 return self.old_interface.GetFileContents(device_path) |
902 | 893 |
903 def _WriteFileWithPush(self, device_path, contents): | |
904 with tempfile.NamedTemporaryFile() as host_temp: | |
905 host_temp.write(contents) | |
906 host_temp.flush() | |
907 self.adb.Push(host_temp.name, device_path) | |
908 | |
909 @decorators.WithTimeoutAndRetriesFromInstance() | 894 @decorators.WithTimeoutAndRetriesFromInstance() |
910 def WriteFile(self, device_path, contents, as_root=False, force_push=False, | 895 def WriteFile(self, device_path, contents, as_root=False, force_push=False, |
911 timeout=None, retries=None): | 896 timeout=None, retries=None): |
912 """Writes |contents| to a file on the device. | 897 """Writes |contents| to a file on the device. |
913 | 898 |
914 Args: | 899 Args: |
915 device_path: A string containing the absolute path to the file to write | 900 device_path: A string containing the absolute path to the file to write |
916 on the device. | 901 on the device. |
917 contents: A string containing the data to write to the device. | 902 contents: A string containing the data to write to the device. |
918 as_root: A boolean indicating whether the write should be executed with | 903 as_root: A boolean indicating whether the write should be executed with |
919 root privileges (if available). | 904 root privileges (if available). |
920 force_push: A boolean indicating whether to force the operation to be | 905 force_push: A boolean indicating whether to force the operation to be |
921 performed by pushing a file to the device. The default is, when the | 906 performed by pushing a file to the device. The default is, when the |
922 contents are short, to pass the contents using a shell script instead. | 907 contents are short, to pass the contents using a shell script instead. |
923 timeout: timeout in seconds | 908 timeout: timeout in seconds |
924 retries: number of retries | 909 retries: number of retries |
925 | 910 |
926 Raises: | 911 Raises: |
927 CommandFailedError if the file could not be written on the device. | 912 CommandFailedError if the file could not be written on the device. |
928 CommandTimeoutError on timeout. | 913 CommandTimeoutError on timeout. |
929 DeviceUnreachableError on missing device. | 914 DeviceUnreachableError on missing device. |
930 """ | 915 """ |
931 if not force_push and len(contents) < self._MAX_ADB_COMMAND_LENGTH: | 916 if len(contents) < 512 and not force_push: |
932 # If the contents are small, for efficieny we write the contents using | |
933 # using a shell command rather than push | |
934 cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents), | 917 cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents), |
935 cmd_helper.SingleQuote(device_path)) | 918 cmd_helper.SingleQuote(device_path)) |
936 self.RunShellCommand(cmd, as_root=as_root, check_return=True) | 919 self.RunShellCommand(cmd, as_root=as_root, check_return=True) |
937 elif as_root and self.NeedsSU(): | |
938 # Adb does not allow to "push with su", so we first push to a temp file | |
939 # on a safe location, and then copy it to the desired location with su | |
940 with device_temp_file.DeviceTempFile(self.adb) as device_temp: | |
941 self._WriteFileWithPush(device_temp.name, contents) | |
942 # Here we need 'cp' rather than 'mv' because the temp and | |
943 # destination files might be on different file systems (e.g. | |
944 # on internal storage and an external sd card) | |
945 self.RunShellCommand(['cp', device_temp.name, device_path], | |
946 as_root=True, check_return=True) | |
947 else: | 920 else: |
948 # If root is not needed, we can push directly to the desired location | 921 with tempfile.NamedTemporaryFile() as host_temp: |
949 self._WriteFileWithPush(device_path, contents) | 922 host_temp.write(contents) |
| 923 host_temp.flush() |
| 924 if as_root and self.NeedsSU(): |
| 925 with device_temp_file.DeviceTempFile(self) as device_temp: |
| 926 self.adb.Push(host_temp.name, device_temp.name) |
| 927 # Here we need 'cp' rather than 'mv' because the temp and |
| 928 # destination files might be on different file systems (e.g. |
| 929 # on internal storage and an external sd card) |
| 930 self.RunShellCommand(['cp', device_temp.name, device_path], |
| 931 as_root=True, check_return=True) |
| 932 else: |
| 933 self.adb.Push(host_temp.name, device_path) |
950 | 934 |
951 @decorators.WithTimeoutAndRetriesFromInstance() | 935 @decorators.WithTimeoutAndRetriesFromInstance() |
952 def Ls(self, device_path, timeout=None, retries=None): | 936 def Ls(self, device_path, timeout=None, retries=None): |
953 """Lists the contents of a directory on the device. | 937 """Lists the contents of a directory on the device. |
954 | 938 |
955 Args: | 939 Args: |
956 device_path: A string containing the path of the directory on the device | 940 device_path: A string containing the path of the directory on the device |
957 to list. | 941 to list. |
958 timeout: timeout in seconds | 942 timeout: timeout in seconds |
959 retries: number of retries | 943 retries: number of retries |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1210 Returns: | 1194 Returns: |
1211 A Parallelizer operating over |devices|. | 1195 A Parallelizer operating over |devices|. |
1212 """ | 1196 """ |
1213 if not devices or len(devices) == 0: | 1197 if not devices or len(devices) == 0: |
1214 devices = pylib.android_commands.GetAttachedDevices() | 1198 devices = pylib.android_commands.GetAttachedDevices() |
1215 parallelizer_type = (parallelizer.Parallelizer if async | 1199 parallelizer_type = (parallelizer.Parallelizer if async |
1216 else parallelizer.SyncParallelizer) | 1200 else parallelizer.SyncParallelizer) |
1217 return parallelizer_type([ | 1201 return parallelizer_type([ |
1218 d if isinstance(d, DeviceUtils) else DeviceUtils(d) | 1202 d if isinstance(d, DeviceUtils) else DeviceUtils(d) |
1219 for d in devices]) | 1203 for d in devices]) |
OLD | NEW |