Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: build/android/pylib/device/device_utils.py

Issue 754433003: Update from https://crrev.com/305340 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
11 import logging 11 import logging
12 import multiprocessing 12 import multiprocessing
13 import os 13 import os
14 import re 14 import re
15 import sys 15 import sys
16 import tempfile 16 import tempfile
17 import time 17 import time
18 import zipfile 18 import zipfile
19 19
20 import pylib.android_commands 20 import pylib.android_commands
21 from pylib import cmd_helper 21 from pylib import cmd_helper
22 from pylib.device import adb_wrapper 22 from pylib.device import adb_wrapper
23 from pylib.device import decorators 23 from pylib.device import decorators
24 from pylib.device import device_errors 24 from pylib.device import device_errors
25 from pylib.device.commands import install_commands 25 from pylib.device.commands import install_commands
26 from pylib.utils import apk_helper 26 from pylib.utils import apk_helper
27 from pylib.utils import device_temp_file
27 from pylib.utils import host_utils 28 from pylib.utils import host_utils
29 from pylib.utils import md5sum
28 from pylib.utils import parallelizer 30 from pylib.utils import parallelizer
29 from pylib.utils import timeout_retry 31 from pylib.utils import timeout_retry
30 32
31 _DEFAULT_TIMEOUT = 30 33 _DEFAULT_TIMEOUT = 30
32 _DEFAULT_RETRIES = 3 34 _DEFAULT_RETRIES = 3
33 35
34 36
35 @decorators.WithExplicitTimeoutAndRetries( 37 @decorators.WithExplicitTimeoutAndRetries(
36 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) 38 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
37 def GetAVDs(): 39 def GetAVDs():
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 self.old_interface = device 87 self.old_interface = device
86 elif not device: 88 elif not device:
87 self.adb = adb_wrapper.AdbWrapper('') 89 self.adb = adb_wrapper.AdbWrapper('')
88 self.old_interface = pylib.android_commands.AndroidCommands() 90 self.old_interface = pylib.android_commands.AndroidCommands()
89 else: 91 else:
90 raise ValueError('Unsupported type passed for argument "device"') 92 raise ValueError('Unsupported type passed for argument "device"')
91 self._commands_installed = None 93 self._commands_installed = None
92 self._default_timeout = default_timeout 94 self._default_timeout = default_timeout
93 self._default_retries = default_retries 95 self._default_retries = default_retries
94 self._cache = {} 96 self._cache = {}
95 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) 97 assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
96 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) 98 assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
97 99
98 @decorators.WithTimeoutAndRetriesFromInstance() 100 @decorators.WithTimeoutAndRetriesFromInstance()
99 def IsOnline(self, timeout=None, retries=None): 101 def IsOnline(self, timeout=None, retries=None):
100 """Checks whether the device is online. 102 """Checks whether the device is online.
101 103
102 Args: 104 Args:
103 timeout: timeout in seconds 105 timeout: timeout in seconds
104 retries: number of retries 106 retries: number of retries
105 107
106 Returns: 108 Returns:
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 DeviceUnreachableError on missing device. 424 DeviceUnreachableError on missing device.
423 """ 425 """
424 def env_quote(key, value): 426 def env_quote(key, value):
425 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key): 427 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key):
426 raise KeyError('Invalid shell variable name %r' % key) 428 raise KeyError('Invalid shell variable name %r' % key)
427 # using double quotes here to allow interpolation of shell variables 429 # using double quotes here to allow interpolation of shell variables
428 return '%s=%s' % (key, cmd_helper.DoubleQuote(value)) 430 return '%s=%s' % (key, cmd_helper.DoubleQuote(value))
429 431
430 if not isinstance(cmd, basestring): 432 if not isinstance(cmd, basestring):
431 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) 433 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd)
432 if as_root and self.NeedsSU():
433 cmd = 'su -c %s' % cmd
434 if env: 434 if env:
435 env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) 435 env = ' '.join(env_quote(k, v) for k, v in env.iteritems())
436 cmd = '%s %s' % (env, cmd) 436 cmd = '%s %s' % (env, cmd)
437 if cwd: 437 if cwd:
438 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) 438 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd)
439 if as_root and self.NeedsSU():
440 # "su -c sh -c" allows using shell features in |cmd|
441 cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd)
439 if timeout is None: 442 if timeout is None:
440 timeout = self._default_timeout 443 timeout = self._default_timeout
441 444
442 try: 445 try:
443 output = self.adb.Shell(cmd) 446 output = self.adb.Shell(cmd)
444 except device_errors.AdbShellCommandFailedError as e: 447 except device_errors.AdbShellCommandFailedError as e:
445 if check_return: 448 if check_return:
446 raise 449 raise
447 else: 450 else:
448 output = e.output 451 output = e.output
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 def _GetChangedFilesImpl(self, host_path, device_path): 695 def _GetChangedFilesImpl(self, host_path, device_path):
693 real_host_path = os.path.realpath(host_path) 696 real_host_path = os.path.realpath(host_path)
694 try: 697 try:
695 real_device_path = self.RunShellCommand( 698 real_device_path = self.RunShellCommand(
696 ['realpath', device_path], single_line=True, check_return=True) 699 ['realpath', device_path], single_line=True, check_return=True)
697 except device_errors.CommandFailedError: 700 except device_errors.CommandFailedError:
698 real_device_path = None 701 real_device_path = None
699 if not real_device_path: 702 if not real_device_path:
700 return [(host_path, device_path)] 703 return [(host_path, device_path)]
701 704
702 # TODO(jbudorick): Move the md5 logic up into DeviceUtils or base 705 host_hash_tuples = md5sum.CalculateHostMd5Sums([real_host_path])
703 # this function on mtime. 706 device_paths_to_md5 = (
704 # pylint: disable=W0212 707 real_device_path if os.path.isfile(real_host_path)
705 host_hash_tuples, device_hash_tuples = self.old_interface._RunMd5Sum( 708 else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path))
706 real_host_path, real_device_path) 709 for _, p in host_hash_tuples))
707 # pylint: enable=W0212 710 device_hash_tuples = md5sum.CalculateDeviceMd5Sums(
711 device_paths_to_md5, self)
708 712
709 if os.path.isfile(host_path): 713 if os.path.isfile(host_path):
710 if (not device_hash_tuples 714 if (not device_hash_tuples
711 or device_hash_tuples[0].hash != host_hash_tuples[0].hash): 715 or device_hash_tuples[0].hash != host_hash_tuples[0].hash):
712 return [(host_path, device_path)] 716 return [(host_path, device_path)]
713 else: 717 else:
714 return [] 718 return []
715 else: 719 else:
716 device_tuple_dict = dict((d.path, d.hash) for d in device_hash_tuples) 720 device_tuple_dict = dict((d.path, d.hash) for d in device_hash_tuples)
717 to_push = [] 721 to_push = []
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 COMPRESSION_RATIO = 2.0 # unitless 762 COMPRESSION_RATIO = 2.0 # unitless
759 763
760 adb_call_time = ADB_CALL_PENALTY * adb_calls 764 adb_call_time = ADB_CALL_PENALTY * adb_calls
761 adb_push_setup_time = ADB_PUSH_PENALTY * file_count 765 adb_push_setup_time = ADB_PUSH_PENALTY * file_count
762 if is_zipping: 766 if is_zipping:
763 zip_time = ZIP_PENALTY + byte_count / ZIP_RATE 767 zip_time = ZIP_PENALTY + byte_count / ZIP_RATE
764 transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO) 768 transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO)
765 else: 769 else:
766 zip_time = 0 770 zip_time = 0
767 transfer_time = byte_count / TRANSFER_RATE 771 transfer_time = byte_count / TRANSFER_RATE
768 return (adb_call_time + adb_push_setup_time + zip_time + transfer_time) 772 return adb_call_time + adb_push_setup_time + zip_time + transfer_time
769 773
770 def _PushChangedFilesIndividually(self, files): 774 def _PushChangedFilesIndividually(self, files):
771 for h, d in files: 775 for h, d in files:
772 self.adb.Push(h, d) 776 self.adb.Push(h, d)
773 777
774 def _PushChangedFilesZipped(self, files): 778 def _PushChangedFilesZipped(self, files):
775 if not files: 779 if not files:
776 return 780 return
777 781
778 with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file: 782 with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
875 # the implementation switch, and if file not found should raise exception. 879 # the implementation switch, and if file not found should raise exception.
876 if as_root: 880 if as_root:
877 if not self.old_interface.CanAccessProtectedFileContents(): 881 if not self.old_interface.CanAccessProtectedFileContents():
878 raise device_errors.CommandFailedError( 882 raise device_errors.CommandFailedError(
879 'Cannot read from %s with root privileges.' % device_path) 883 'Cannot read from %s with root privileges.' % device_path)
880 return self.old_interface.GetProtectedFileContents(device_path) 884 return self.old_interface.GetProtectedFileContents(device_path)
881 else: 885 else:
882 return self.old_interface.GetFileContents(device_path) 886 return self.old_interface.GetFileContents(device_path)
883 887
884 @decorators.WithTimeoutAndRetriesFromInstance() 888 @decorators.WithTimeoutAndRetriesFromInstance()
885 def WriteFile(self, device_path, contents, as_root=False, timeout=None, 889 def WriteFile(self, device_path, contents, as_root=False, force_push=False,
886 retries=None): 890 timeout=None, retries=None):
887 """Writes |contents| to a file on the device. 891 """Writes |contents| to a file on the device.
888 892
889 Args: 893 Args:
890 device_path: A string containing the absolute path to the file to write 894 device_path: A string containing the absolute path to the file to write
891 on the device. 895 on the device.
892 contents: A string containing the data to write to the device. 896 contents: A string containing the data to write to the device.
893 as_root: A boolean indicating whether the write should be executed with 897 as_root: A boolean indicating whether the write should be executed with
894 root privileges. 898 root privileges (if available).
899 force_push: A boolean indicating whether to force the operation to be
900 performed by pushing a file to the device. The default is, when the
901 contents are short, to pass the contents using a shell script instead.
895 timeout: timeout in seconds 902 timeout: timeout in seconds
896 retries: number of retries 903 retries: number of retries
897 904
898 Raises: 905 Raises:
899 CommandFailedError if the file could not be written on the device. 906 CommandFailedError if the file could not be written on the device.
900 CommandTimeoutError on timeout. 907 CommandTimeoutError on timeout.
901 DeviceUnreachableError on missing device. 908 DeviceUnreachableError on missing device.
902 """ 909 """
903 if as_root: 910 if len(contents) < 512 and not force_push:
904 if not self.old_interface.CanAccessProtectedFileContents(): 911 cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents),
905 raise device_errors.CommandFailedError( 912 cmd_helper.SingleQuote(device_path))
906 'Cannot write to %s with root privileges.' % device_path) 913 self.RunShellCommand(cmd, as_root=as_root, check_return=True)
907 self.old_interface.SetProtectedFileContents(device_path, contents)
908 else: 914 else:
909 self.old_interface.SetFileContents(device_path, contents) 915 with tempfile.NamedTemporaryFile() as host_temp:
910 916 host_temp.write(contents)
911 @decorators.WithTimeoutAndRetriesFromInstance() 917 host_temp.flush()
912 def WriteTextFile(self, device_path, text, as_root=False, timeout=None, 918 if as_root and self.NeedsSU():
913 retries=None): 919 with device_temp_file.DeviceTempFile(self) as device_temp:
914 """Writes |text| to a file on the device. 920 self.adb.Push(host_temp.name, device_temp.name)
915 921 # Here we need 'cp' rather than 'mv' because the temp and
916 Assuming that |text| is a small string, this is typically more efficient 922 # destination files might be on different file systems (e.g.
917 than |WriteFile|, as no files are pushed into the device. 923 # on internal storage and an external sd card)
918 924 self.RunShellCommand(['cp', device_temp.name, device_path],
919 Args: 925 as_root=True, check_return=True)
920 device_path: A string containing the absolute path to the file to write 926 else:
921 on the device. 927 self.adb.Push(host_temp.name, device_path)
922 text: A short string of text to write to the file on the device.
923 as_root: A boolean indicating whether the write should be executed with
924 root privileges.
925 timeout: timeout in seconds
926 retries: number of retries
927
928 Raises:
929 CommandFailedError if the file could not be written on the device.
930 CommandTimeoutError on timeout.
931 DeviceUnreachableError on missing device.
932 """
933 cmd = 'echo %s > %s' % (cmd_helper.SingleQuote(text),
934 cmd_helper.SingleQuote(device_path))
935 self.RunShellCommand(cmd, as_root=as_root, check_return=True)
936 928
937 @decorators.WithTimeoutAndRetriesFromInstance() 929 @decorators.WithTimeoutAndRetriesFromInstance()
938 def Ls(self, device_path, timeout=None, retries=None): 930 def Ls(self, device_path, timeout=None, retries=None):
939 """Lists the contents of a directory on the device. 931 """Lists the contents of a directory on the device.
940 932
941 Args: 933 Args:
942 device_path: A string containing the path of the directory on the device 934 device_path: A string containing the path of the directory on the device
943 to list. 935 to list.
944 timeout: timeout in seconds 936 timeout: timeout in seconds
945 retries: number of retries 937 retries: number of retries
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
1166 Returns: 1158 Returns:
1167 A Parallelizer operating over |devices|. 1159 A Parallelizer operating over |devices|.
1168 """ 1160 """
1169 if not devices or len(devices) == 0: 1161 if not devices or len(devices) == 0:
1170 devices = pylib.android_commands.GetAttachedDevices() 1162 devices = pylib.android_commands.GetAttachedDevices()
1171 parallelizer_type = (parallelizer.Parallelizer if async 1163 parallelizer_type = (parallelizer.Parallelizer if async
1172 else parallelizer.SyncParallelizer) 1164 else parallelizer.SyncParallelizer)
1173 return parallelizer_type([ 1165 return parallelizer_type([
1174 d if isinstance(d, DeviceUtils) else DeviceUtils(d) 1166 d if isinstance(d, DeviceUtils) else DeviceUtils(d)
1175 for d in devices]) 1167 for d in devices])
OLDNEW
« no previous file with comments | « build/android/pylib/device/decorators_test.py ('k') | build/android/pylib/device/device_utils_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698