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