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

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

Issue 700983006: Add NeedsSu for RunShellCommand to check whether it needs SU (Closed) Base URL: https://chromium.googlesource.com/chromium/src.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
« no previous file with comments | « no previous file | build/android/pylib/device/device_utils_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 timeout: timeout in seconds 123 timeout: timeout in seconds
124 retries: number of retries 124 retries: number of retries
125 125
126 Returns: 126 Returns:
127 True if adbd has root privileges, False otherwise. 127 True if adbd has root privileges, False otherwise.
128 128
129 Raises: 129 Raises:
130 CommandTimeoutError on timeout. 130 CommandTimeoutError on timeout.
131 DeviceUnreachableError on missing device. 131 DeviceUnreachableError on missing device.
132 """ 132 """
133 return self._HasRootImpl()
134
135 def _HasRootImpl(self):
136 try: 133 try:
137 self._RunShellCommandImpl('ls /root', check_return=True) 134 self.RunShellCommand('ls /root', check_return=True)
138 return True 135 return True
139 except device_errors.AdbShellCommandFailedError: 136 except device_errors.AdbShellCommandFailedError:
140 return False 137 return False
141 138
139 def NeedsSU(self, timeout=None, retries=None):
140 """Checks whether 'su' is needed to access protected resources.
141
142 Args:
143 timeout: timeout in seconds
144 retries: number of retries
145
146 Returns:
147 True if 'su' is available on the device and is needed to to access
148 protected resources; False otherwise if either 'su' is not available
149 (e.g. because the device has a user build), or not needed (because adbd
150 already has root privileges).
151
152 Raises:
153 CommandTimeoutError on timeout.
154 DeviceUnreachableError on missing device.
155 """
156 if 'needs_su' not in self._cache:
157 try:
158 self.RunShellCommand('su -c ls /root && ! ls /root', check_return=True,
159 timeout=timeout, retries=retries)
160 self._cache['needs_su'] = True
161 except device_errors.AdbShellCommandFailedError:
162 self._cache['needs_su'] = False
163 return self._cache['needs_su']
164
165
142 @decorators.WithTimeoutAndRetriesFromInstance() 166 @decorators.WithTimeoutAndRetriesFromInstance()
143 def EnableRoot(self, timeout=None, retries=None): 167 def EnableRoot(self, timeout=None, retries=None):
144 """Restarts adbd with root privileges. 168 """Restarts adbd with root privileges.
145 169
146 Args: 170 Args:
147 timeout: timeout in seconds 171 timeout: timeout in seconds
148 retries: number of retries 172 retries: number of retries
149 173
150 Raises: 174 Raises:
151 CommandFailedError if root could not be enabled. 175 CommandFailedError if root could not be enabled.
152 CommandTimeoutError on timeout. 176 CommandTimeoutError on timeout.
153 """ 177 """
178 if 'needs_su' in self._cache:
179 del self._cache['needs_su']
154 if not self.old_interface.EnableAdbRoot(): 180 if not self.old_interface.EnableAdbRoot():
155 raise device_errors.CommandFailedError( 181 raise device_errors.CommandFailedError(
156 'Could not enable root.', device=str(self)) 182 'Could not enable root.', device=str(self))
157 183
158 @decorators.WithTimeoutAndRetriesFromInstance() 184 @decorators.WithTimeoutAndRetriesFromInstance()
159 def IsUserBuild(self, timeout=None, retries=None): 185 def IsUserBuild(self, timeout=None, retries=None):
160 """Checks whether or not the device is running a user build. 186 """Checks whether or not the device is running a user build.
161 187
162 Args: 188 Args:
163 timeout: timeout in seconds 189 timeout: timeout in seconds
(...skipping 24 matching lines...) Expand all
188 CommandFailedError if the external storage path could not be determined. 214 CommandFailedError if the external storage path could not be determined.
189 CommandTimeoutError on timeout. 215 CommandTimeoutError on timeout.
190 DeviceUnreachableError on missing device. 216 DeviceUnreachableError on missing device.
191 """ 217 """
192 return self._GetExternalStoragePathImpl() 218 return self._GetExternalStoragePathImpl()
193 219
194 def _GetExternalStoragePathImpl(self): 220 def _GetExternalStoragePathImpl(self):
195 if 'external_storage' in self._cache: 221 if 'external_storage' in self._cache:
196 return self._cache['external_storage'] 222 return self._cache['external_storage']
197 223
198 value = self._RunShellCommandImpl('echo $EXTERNAL_STORAGE', 224 value = self.RunShellCommand('echo $EXTERNAL_STORAGE',
199 single_line=True, 225 single_line=True,
200 check_return=True) 226 check_return=True)
201 if not value: 227 if not value:
202 raise device_errors.CommandFailedError('$EXTERNAL_STORAGE is not set', 228 raise device_errors.CommandFailedError('$EXTERNAL_STORAGE is not set',
203 str(self)) 229 str(self))
204 self._cache['external_storage'] = value 230 self._cache['external_storage'] = value
205 return value 231 return value
206 232
207 @decorators.WithTimeoutAndRetriesFromInstance() 233 @decorators.WithTimeoutAndRetriesFromInstance()
208 def GetApplicationPath(self, package, timeout=None, retries=None): 234 def GetApplicationPath(self, package, timeout=None, retries=None):
209 """Get the path of the installed apk on the device for the given package. 235 """Get the path of the installed apk on the device for the given package.
210 236
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 (with the optional newline at the end stripped). 412 (with the optional newline at the end stripped).
387 413
388 Raises: 414 Raises:
389 AdbShellCommandFailedError if check_return is True and the exit code of 415 AdbShellCommandFailedError if check_return is True and the exit code of
390 the command run on the device is non-zero. 416 the command run on the device is non-zero.
391 CommandFailedError if single_line is True but the output contains two or 417 CommandFailedError if single_line is True but the output contains two or
392 more lines. 418 more lines.
393 CommandTimeoutError on timeout. 419 CommandTimeoutError on timeout.
394 DeviceUnreachableError on missing device. 420 DeviceUnreachableError on missing device.
395 """ 421 """
396 return self._RunShellCommandImpl(cmd, check_return=check_return, cwd=cwd,
397 env=env, as_root=as_root, single_line=single_line, timeout=timeout)
398
399 def _RunShellCommandImpl(self, cmd, check_return=False, cwd=None, env=None,
jbudorick 2014/11/06 00:33:45 Nice cleanup!
400 as_root=False, single_line=False, timeout=None):
401 def env_quote(key, value): 422 def env_quote(key, value):
402 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key): 423 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key):
403 raise KeyError('Invalid shell variable name %r' % key) 424 raise KeyError('Invalid shell variable name %r' % key)
404 # using double quotes here to allow interpolation of shell variables 425 # using double quotes here to allow interpolation of shell variables
405 return '%s=%s' % (key, cmd_helper.DoubleQuote(value)) 426 return '%s=%s' % (key, cmd_helper.DoubleQuote(value))
406 427
407 if not isinstance(cmd, basestring): 428 if not isinstance(cmd, basestring):
408 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) 429 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd)
409 if as_root and not self._HasRootImpl(): 430 if as_root and self.NeedsSU():
410 cmd = 'su -c %s' % cmd 431 cmd = 'su -c %s' % cmd
411 if env: 432 if env:
412 env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) 433 env = ' '.join(env_quote(k, v) for k, v in env.iteritems())
413 cmd = '%s %s' % (env, cmd) 434 cmd = '%s %s' % (env, cmd)
414 if cwd: 435 if cwd:
415 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) 436 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd)
416 if timeout is None: 437 if timeout is None:
417 timeout = self._default_timeout 438 timeout = self._default_timeout
418 439
419 try: 440 try:
420 # TODO(perezju) still need to make sure that we call a version of 441 output = self.adb.Shell(cmd, expect_rc=0)
421 # adb.Shell without a timeout-and-retries wrapper.
422 output = self.adb.Shell(cmd, expect_rc=0, timeout=timeout, retries=0)
423 except device_errors.AdbShellCommandFailedError as e: 442 except device_errors.AdbShellCommandFailedError as e:
424 if check_return: 443 if check_return:
425 raise 444 raise
426 else: 445 else:
427 output = e.output 446 output = e.output
428 447
429 output = output.splitlines() 448 output = output.splitlines()
430 if single_line: 449 if single_line:
431 if not output: 450 if not output:
432 return '' 451 return ''
(...skipping 25 matching lines...) Expand all
458 CommandFailedError if no process was killed. 477 CommandFailedError if no process was killed.
459 CommandTimeoutError on timeout. 478 CommandTimeoutError on timeout.
460 DeviceUnreachableError on missing device. 479 DeviceUnreachableError on missing device.
461 """ 480 """
462 pids = self._GetPidsImpl(process_name) 481 pids = self._GetPidsImpl(process_name)
463 if not pids: 482 if not pids:
464 raise device_errors.CommandFailedError( 483 raise device_errors.CommandFailedError(
465 'No process "%s"' % process_name, device=str(self)) 484 'No process "%s"' % process_name, device=str(self))
466 485
467 cmd = ['kill', '-%d' % signum] + pids.values() 486 cmd = ['kill', '-%d' % signum] + pids.values()
468 self._RunShellCommandImpl(cmd, as_root=as_root, check_return=True) 487 self.RunShellCommand(cmd, as_root=as_root, check_return=True)
469 488
470 if blocking: 489 if blocking:
471 wait_period = 0.1 490 wait_period = 0.1
472 while self._GetPidsImpl(process_name): 491 while self._GetPidsImpl(process_name):
473 time.sleep(wait_period) 492 time.sleep(wait_period)
474 493
475 return len(pids) 494 return len(pids)
476 495
477 @decorators.WithTimeoutAndRetriesFromInstance() 496 @decorators.WithTimeoutAndRetriesFromInstance()
478 def StartActivity(self, intent, blocking=False, trace_file_name=None, 497 def StartActivity(self, intent, blocking=False, trace_file_name=None,
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 628
610 Raises: 629 Raises:
611 CommandFailedError on failure. 630 CommandFailedError on failure.
612 CommandTimeoutError on timeout. 631 CommandTimeoutError on timeout.
613 DeviceUnreachableError on missing device. 632 DeviceUnreachableError on missing device.
614 """ 633 """
615 634
616 files = [] 635 files = []
617 for h, d in host_device_tuples: 636 for h, d in host_device_tuples:
618 if os.path.isdir(h): 637 if os.path.isdir(h):
619 self._RunShellCommandImpl(['mkdir', '-p', d], check_return=True) 638 self.RunShellCommand(['mkdir', '-p', d], check_return=True)
620 files += self._GetChangedFilesImpl(h, d) 639 files += self._GetChangedFilesImpl(h, d)
621 640
622 if not files: 641 if not files:
623 return 642 return
624 643
625 size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files) 644 size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files)
626 file_count = len(files) 645 file_count = len(files)
627 dir_size = sum(host_utils.GetRecursiveDiskUsage(h) 646 dir_size = sum(host_utils.GetRecursiveDiskUsage(h)
628 for h, _ in host_device_tuples) 647 for h, _ in host_device_tuples)
629 dir_file_count = 0 648 dir_file_count = 0
(...skipping 11 matching lines...) Expand all
641 660
642 self._InstallCommands() 661 self._InstallCommands()
643 662
644 if dir_push_duration < push_duration and ( 663 if dir_push_duration < push_duration and (
645 dir_push_duration < zip_duration or not self._commands_installed): 664 dir_push_duration < zip_duration or not self._commands_installed):
646 self._PushChangedFilesIndividually(host_device_tuples) 665 self._PushChangedFilesIndividually(host_device_tuples)
647 elif push_duration < zip_duration or not self._commands_installed: 666 elif push_duration < zip_duration or not self._commands_installed:
648 self._PushChangedFilesIndividually(files) 667 self._PushChangedFilesIndividually(files)
649 else: 668 else:
650 self._PushChangedFilesZipped(files) 669 self._PushChangedFilesZipped(files)
651 self._RunShellCommandImpl( 670 self.RunShellCommand(
652 ['chmod', '-R', '777'] + [d for _, d in host_device_tuples], 671 ['chmod', '-R', '777'] + [d for _, d in host_device_tuples],
653 as_root=True, check_return=True) 672 as_root=True, check_return=True)
654 673
655 def _GetChangedFilesImpl(self, host_path, device_path): 674 def _GetChangedFilesImpl(self, host_path, device_path):
656 real_host_path = os.path.realpath(host_path) 675 real_host_path = os.path.realpath(host_path)
657 try: 676 try:
658 real_device_path = self._RunShellCommandImpl( 677 real_device_path = self.RunShellCommand(
659 ['realpath', device_path], single_line=True, check_return=True) 678 ['realpath', device_path], single_line=True, check_return=True)
660 except device_errors.CommandFailedError: 679 except device_errors.CommandFailedError:
661 real_device_path = None 680 real_device_path = None
662 if not real_device_path: 681 if not real_device_path:
663 return [(host_path, device_path)] 682 return [(host_path, device_path)]
664 683
665 # TODO(jbudorick): Move the md5 logic up into DeviceUtils or base 684 # TODO(jbudorick): Move the md5 logic up into DeviceUtils or base
666 # this function on mtime. 685 # this function on mtime.
667 # pylint: disable=W0212 686 # pylint: disable=W0212
668 host_hash_tuples, device_hash_tuples = self.old_interface._RunMd5Sum( 687 host_hash_tuples, device_hash_tuples = self.old_interface._RunMd5Sum(
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
741 with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file: 760 with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
742 zip_proc = multiprocessing.Process( 761 zip_proc = multiprocessing.Process(
743 target=DeviceUtils._CreateDeviceZip, 762 target=DeviceUtils._CreateDeviceZip,
744 args=(zip_file.name, files)) 763 args=(zip_file.name, files))
745 zip_proc.start() 764 zip_proc.start()
746 zip_proc.join() 765 zip_proc.join()
747 766
748 zip_on_device = '%s/tmp.zip' % self._GetExternalStoragePathImpl() 767 zip_on_device = '%s/tmp.zip' % self._GetExternalStoragePathImpl()
749 try: 768 try:
750 self.adb.Push(zip_file.name, zip_on_device) 769 self.adb.Push(zip_file.name, zip_on_device)
751 self._RunShellCommandImpl( 770 self.RunShellCommand(
752 ['unzip', zip_on_device], 771 ['unzip', zip_on_device],
753 as_root=True, 772 as_root=True,
754 env={'PATH': '$PATH:%s' % install_commands.BIN_DIR}, 773 env={'PATH': '$PATH:%s' % install_commands.BIN_DIR},
755 check_return=True) 774 check_return=True)
756 finally: 775 finally:
757 if zip_proc.is_alive(): 776 if zip_proc.is_alive():
758 zip_proc.terminate() 777 zip_proc.terminate()
759 if self.IsOnline(): 778 if self.IsOnline():
760 self._RunShellCommandImpl(['rm', zip_on_device], check_return=True) 779 self.RunShellCommand(['rm', zip_on_device], check_return=True)
761 780
762 @staticmethod 781 @staticmethod
763 def _CreateDeviceZip(zip_path, host_device_tuples): 782 def _CreateDeviceZip(zip_path, host_device_tuples):
764 with zipfile.ZipFile(zip_path, 'w') as zip_file: 783 with zipfile.ZipFile(zip_path, 'w') as zip_file:
765 for host_path, device_path in host_device_tuples: 784 for host_path, device_path in host_device_tuples:
766 if os.path.isfile(host_path): 785 if os.path.isfile(host_path):
767 zip_file.write(host_path, device_path, zipfile.ZIP_DEFLATED) 786 zip_file.write(host_path, device_path, zipfile.ZIP_DEFLATED)
768 else: 787 else:
769 for hd, _, files in os.walk(host_path): 788 for hd, _, files in os.walk(host_path):
770 dd = '%s/%s' % (device_path, os.path.relpath(host_path, hd)) 789 dd = '%s/%s' % (device_path, os.path.relpath(host_path, hd))
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
888 timeout: timeout in seconds 907 timeout: timeout in seconds
889 retries: number of retries 908 retries: number of retries
890 909
891 Raises: 910 Raises:
892 CommandFailedError if the file could not be written on the device. 911 CommandFailedError if the file could not be written on the device.
893 CommandTimeoutError on timeout. 912 CommandTimeoutError on timeout.
894 DeviceUnreachableError on missing device. 913 DeviceUnreachableError on missing device.
895 """ 914 """
896 cmd = 'echo %s > %s' % (cmd_helper.SingleQuote(text), 915 cmd = 'echo %s > %s' % (cmd_helper.SingleQuote(text),
897 cmd_helper.SingleQuote(device_path)) 916 cmd_helper.SingleQuote(device_path))
898 self._RunShellCommandImpl(cmd, as_root=as_root, check_return=True) 917 self.RunShellCommand(cmd, as_root=as_root, check_return=True)
899 918
900 @decorators.WithTimeoutAndRetriesFromInstance() 919 @decorators.WithTimeoutAndRetriesFromInstance()
901 def Ls(self, device_path, timeout=None, retries=None): 920 def Ls(self, device_path, timeout=None, retries=None):
902 """Lists the contents of a directory on the device. 921 """Lists the contents of a directory on the device.
903 922
904 Args: 923 Args:
905 device_path: A string containing the path of the directory on the device 924 device_path: A string containing the path of the directory on the device
906 to list. 925 to list.
907 timeout: timeout in seconds 926 timeout: timeout in seconds
908 retries: number of retries 927 retries: number of retries
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1031 provided |process_name|. 1050 provided |process_name|.
1032 1051
1033 Raises: 1052 Raises:
1034 CommandTimeoutError on timeout. 1053 CommandTimeoutError on timeout.
1035 DeviceUnreachableError on missing device. 1054 DeviceUnreachableError on missing device.
1036 """ 1055 """
1037 return self._GetPidsImpl(process_name) 1056 return self._GetPidsImpl(process_name)
1038 1057
1039 def _GetPidsImpl(self, process_name): 1058 def _GetPidsImpl(self, process_name):
1040 procs_pids = {} 1059 procs_pids = {}
1041 for line in self._RunShellCommandImpl('ps', check_return=True): 1060 for line in self.RunShellCommand('ps', check_return=True):
1042 try: 1061 try:
1043 ps_data = line.split() 1062 ps_data = line.split()
1044 if process_name in ps_data[-1]: 1063 if process_name in ps_data[-1]:
1045 procs_pids[ps_data[-1]] = ps_data[1] 1064 procs_pids[ps_data[-1]] = ps_data[1]
1046 except IndexError: 1065 except IndexError:
1047 pass 1066 pass
1048 return procs_pids 1067 return procs_pids
1049 1068
1050 @decorators.WithTimeoutAndRetriesFromInstance() 1069 @decorators.WithTimeoutAndRetriesFromInstance()
1051 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): 1070 def TakeScreenshot(self, host_path=None, timeout=None, retries=None):
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1129 Returns: 1148 Returns:
1130 A Parallelizer operating over |devices|. 1149 A Parallelizer operating over |devices|.
1131 """ 1150 """
1132 if not devices or len(devices) == 0: 1151 if not devices or len(devices) == 0:
1133 devices = pylib.android_commands.GetAttachedDevices() 1152 devices = pylib.android_commands.GetAttachedDevices()
1134 parallelizer_type = (parallelizer.Parallelizer if async 1153 parallelizer_type = (parallelizer.Parallelizer if async
1135 else parallelizer.SyncParallelizer) 1154 else parallelizer.SyncParallelizer)
1136 return parallelizer_type([ 1155 return parallelizer_type([
1137 d if isinstance(d, DeviceUtils) else DeviceUtils(d) 1156 d if isinstance(d, DeviceUtils) else DeviceUtils(d)
1138 for d in devices]) 1157 for d in devices])
OLDNEW
« no previous file with comments | « no previous file | build/android/pylib/device/device_utils_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698