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

Side by Side Diff: telemetry/telemetry/internal/platform/android_platform_backend.py

Issue 2709523005: [Telemetry] Switch RunShellCommand clients to check_return=True (Closed)
Patch Set: revert change in chown command Created 3 years, 10 months 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 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2013 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 import logging 5 import logging
6 import os 6 import os
7 import posixpath 7 import posixpath
8 import re 8 import re
9 import subprocess 9 import subprocess
10 import tempfile 10 import tempfile
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 This can be used to make memory measurements more stable. Requires root. 265 This can be used to make memory measurements more stable. Requires root.
266 """ 266 """
267 if not self._can_elevate_privilege: 267 if not self._can_elevate_privilege:
268 logging.warning('Cannot run purge_ashmem. Requires a rooted device.') 268 logging.warning('Cannot run purge_ashmem. Requires a rooted device.')
269 return 269 return
270 270
271 if not android_prebuilt_profiler_helper.InstallOnDevice( 271 if not android_prebuilt_profiler_helper.InstallOnDevice(
272 self._device, 'purge_ashmem'): 272 self._device, 'purge_ashmem'):
273 raise Exception('Error installing purge_ashmem.') 273 raise Exception('Error installing purge_ashmem.')
274 output = self._device.RunShellCommand([ 274 output = self._device.RunShellCommand([
275 android_prebuilt_profiler_helper.GetDevicePath('purge_ashmem')]) 275 android_prebuilt_profiler_helper.GetDevicePath('purge_ashmem')],
276 check_return=True)
276 for l in output: 277 for l in output:
277 logging.info(l) 278 logging.info(l)
278 279
279 @decorators.Deprecated( 280 @decorators.Deprecated(
280 2017, 11, 4, 281 2017, 11, 4,
281 'Clients should use tracing and memory-infra in new Telemetry ' 282 'Clients should use tracing and memory-infra in new Telemetry '
282 'benchmarks. See for context: https://crbug.com/632021') 283 'benchmarks. See for context: https://crbug.com/632021')
283 def GetMemoryStats(self, pid): 284 def GetMemoryStats(self, pid):
284 memory_usage = self._device.GetMemoryUsageForPid(pid) 285 memory_usage = self._device.GetMemoryUsageForPid(pid)
285 if not memory_usage: 286 if not memory_usage:
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 331
331 def FlushEntireSystemCache(self): 332 def FlushEntireSystemCache(self):
332 cache = cache_control.CacheControl(self._device) 333 cache = cache_control.CacheControl(self._device)
333 cache.DropRamCaches() 334 cache.DropRamCaches()
334 335
335 def FlushSystemCacheForDirectory(self, directory): 336 def FlushSystemCacheForDirectory(self, directory):
336 raise NotImplementedError() 337 raise NotImplementedError()
337 338
338 def FlushDnsCache(self): 339 def FlushDnsCache(self):
339 self._device.RunShellCommand( 340 self._device.RunShellCommand(
340 ['ndc', 'resolver', 'flushdefaultif'], as_root=True) 341 ['ndc', 'resolver', 'flushdefaultif'], as_root=True, check_return=True)
341 342
342 def StopApplication(self, application): 343 def StopApplication(self, application):
343 """Stop the given |application|. 344 """Stop the given |application|.
344 345
345 Args: 346 Args:
346 application: The full package name string of the application to stop. 347 application: The full package name string of the application to stop.
347 """ 348 """
348 self._device.ForceStop(application) 349 self._device.ForceStop(application)
349 350
350 def KillApplication(self, application): 351 def KillApplication(self, application):
(...skipping 11 matching lines...) Expand all
362 self, application, parameters=None, elevate_privilege=False): 363 self, application, parameters=None, elevate_privilege=False):
363 """Launches the given |application| with a list of |parameters| on the OS. 364 """Launches the given |application| with a list of |parameters| on the OS.
364 365
365 Args: 366 Args:
366 application: The full package name string of the application to launch. 367 application: The full package name string of the application to launch.
367 parameters: A list of parameters to be passed to the ActivityManager. 368 parameters: A list of parameters to be passed to the ActivityManager.
368 elevate_privilege: Currently unimplemented on Android. 369 elevate_privilege: Currently unimplemented on Android.
369 """ 370 """
370 if elevate_privilege: 371 if elevate_privilege:
371 raise NotImplementedError("elevate_privilege isn't supported on android.") 372 raise NotImplementedError("elevate_privilege isn't supported on android.")
373 # TODO(catapult:#3215): Migrate to StartActivity.
372 cmd = ['am', 'start'] 374 cmd = ['am', 'start']
373 if parameters: 375 if parameters:
374 cmd.extend(parameters) 376 cmd.extend(parameters)
375 cmd.append(application) 377 cmd.append(application)
376 result_lines = self._device.RunShellCommand(cmd) 378 result_lines = self._device.RunShellCommand(cmd, check_return=True)
377 for line in result_lines: 379 for line in result_lines:
378 if line.startswith('Error: '): 380 if line.startswith('Error: '):
379 raise ValueError('Failed to start "%s" with error\n %s' % 381 raise ValueError('Failed to start "%s" with error\n %s' %
380 (application, line)) 382 (application, line))
381 383
382 def IsApplicationRunning(self, application): 384 def IsApplicationRunning(self, application):
383 return len(self._device.GetPids(application)) > 0 385 return len(self._device.GetPids(application)) > 0
384 386
385 def CanLaunchApplication(self, application): 387 def CanLaunchApplication(self, application):
386 if not self._installed_applications: 388 if not self._installed_applications:
387 self._installed_applications = self._device.RunShellCommand( 389 self._installed_applications = self._device.RunShellCommand(
388 ['pm', 'list', 'packages']) 390 ['pm', 'list', 'packages'], check_return=True)
389 return 'package:' + application in self._installed_applications 391 return 'package:' + application in self._installed_applications
390 392
391 def InstallApplication(self, application): 393 def InstallApplication(self, application):
392 self._installed_applications = None 394 self._installed_applications = None
393 self._device.Install(application) 395 self._device.Install(application)
394 396
395 @decorators.Cache 397 @decorators.Cache
396 def CanCaptureVideo(self): 398 def CanCaptureVideo(self):
397 return self.GetOSVersionName() >= 'K' 399 return self.GetOSVersionName() >= 'K'
398 400
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 448
447 def GetFileContents(self, fname): 449 def GetFileContents(self, fname):
448 if not self._can_elevate_privilege: 450 if not self._can_elevate_privilege:
449 logging.warning('%s cannot be retrieved on non-rooted device.', fname) 451 logging.warning('%s cannot be retrieved on non-rooted device.', fname)
450 return '' 452 return ''
451 return self._device.ReadFile(fname, as_root=True) 453 return self._device.ReadFile(fname, as_root=True)
452 454
453 def GetPsOutput(self, columns, pid=None): 455 def GetPsOutput(self, columns, pid=None):
454 assert columns == ['pid', 'name'] or columns == ['pid'], \ 456 assert columns == ['pid', 'name'] or columns == ['pid'], \
455 'Only know how to return pid and name. Requested: ' + columns 457 'Only know how to return pid and name. Requested: ' + columns
458 # TODO(catapult:#3215): Migrate to GetPids.
456 cmd = ['ps'] 459 cmd = ['ps']
457 if pid: 460 if pid:
458 cmd.extend(['-p', str(pid)]) 461 cmd.extend(['-p', str(pid)])
459 ps = self._device.RunShellCommand(cmd, large_output=True)[1:] 462 ps = self._device.RunShellCommand(
463 cmd, check_return=True, large_output=True)[1:]
460 output = [] 464 output = []
461 for line in ps: 465 for line in ps:
462 data = line.split() 466 data = line.split()
463 curr_pid = data[1] 467 curr_pid = data[1]
464 curr_name = data[-1] 468 curr_name = data[-1]
465 if columns == ['pid', 'name']: 469 if columns == ['pid', 'name']:
466 output.append([curr_pid, curr_name]) 470 output.append([curr_pid, curr_name])
467 else: 471 else:
468 output.append([curr_pid]) 472 output.append([curr_pid])
469 return output 473 return output
470 474
471 def RunCommand(self, command): 475 def RunCommand(self, command):
472 return '\n'.join(self._device.RunShellCommand(command)) 476 return self._device.RunShellCommand(
477 command, check_return=True, raw_output=True)
473 478
474 @staticmethod 479 @staticmethod
475 def ParseCStateSample(sample): 480 def ParseCStateSample(sample):
476 sample_stats = {} 481 sample_stats = {}
477 for cpu in sample: 482 for cpu in sample:
478 values = sample[cpu].splitlines() 483 values = sample[cpu].splitlines()
479 # Each state has three values after excluding the time value. 484 # Each state has three values after excluding the time value.
480 num_states = (len(values) - 1) / 3 485 num_states = (len(values) - 1) / 3
481 names = values[:num_states] 486 names = values[:num_states]
482 times = values[num_states:2 * num_states] 487 times = values[num_states:2 * num_states]
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 # the base name; so we now need to get the base name from the directory. 588 # the base name; so we now need to get the base name from the directory.
584 if not profile_base: 589 if not profile_base:
585 profile_base = os.path.basename(profile_parent) 590 profile_base = os.path.basename(profile_parent)
586 591
587 saved_profile_location = '/sdcard/profile/%s' % profile_base 592 saved_profile_location = '/sdcard/profile/%s' % profile_base
588 self._device.PushChangedFiles([(new_profile_dir, saved_profile_location)]) 593 self._device.PushChangedFiles([(new_profile_dir, saved_profile_location)])
589 594
590 profile_dir = self._GetProfileDir(package) 595 profile_dir = self._GetProfileDir(package)
591 self._EfficientDeviceDirectoryCopy( 596 self._EfficientDeviceDirectoryCopy(
592 saved_profile_location, profile_dir) 597 saved_profile_location, profile_dir)
593 dumpsys = self._device.RunShellCommand(['dumpsys', 'package', package]) 598 dumpsys = self._device.RunShellCommand(
599 ['dumpsys', 'package', package], check_return=True)
594 id_line = next(line for line in dumpsys if 'userId=' in line) 600 id_line = next(line for line in dumpsys if 'userId=' in line)
595 uid = re.search(r'\d+', id_line).group() 601 uid = re.search(r'\d+', id_line).group()
596 files = self._device.ListDirectory(profile_dir, as_root=True) 602 files = self._device.ListDirectory(profile_dir, as_root=True)
597 paths = [posixpath.join(profile_dir, f) for f in files if f != 'lib'] 603 paths = [posixpath.join(profile_dir, f) for f in files if f != 'lib']
598 for path in paths: 604 for path in paths:
605 # TODO(crbug.com/628617): Implement without ignoring shell errors.
599 # Note: need to pass command as a string for the shell to expand the *'s. 606 # Note: need to pass command as a string for the shell to expand the *'s.
600 extended_path = '%s %s/* %s/*/* %s/*/*/*' % (path, path, path, path) 607 extended_path = '%s %s/* %s/*/* %s/*/*/*' % (path, path, path, path)
601 self._device.RunShellCommand( 608 self._device.RunShellCommand(
602 'chown %s.%s %s' % (uid, uid, extended_path)) 609 'chown %s.%s %s' % (uid, uid, extended_path), check_return=False)
603 610
604 def _EfficientDeviceDirectoryCopy(self, source, dest): 611 def _EfficientDeviceDirectoryCopy(self, source, dest):
605 if not self._device_copy_script: 612 if not self._device_copy_script:
606 self._device.adb.Push( 613 self._device.adb.Push(
607 _DEVICE_COPY_SCRIPT_FILE, 614 _DEVICE_COPY_SCRIPT_FILE,
608 _DEVICE_COPY_SCRIPT_LOCATION) 615 _DEVICE_COPY_SCRIPT_LOCATION)
609 self._device_copy_script = _DEVICE_COPY_SCRIPT_FILE 616 self._device_copy_script = _DEVICE_COPY_SCRIPT_LOCATION
610 self._device.RunShellCommand( 617 self._device.RunShellCommand(
611 ['sh', self._device_copy_script, source, dest]) 618 ['sh', self._device_copy_script, source, dest], check_return=True)
612 619
613 def GetPortPairForForwarding(self, local_port): 620 def GetPortPairForForwarding(self, local_port):
614 return forwarders.PortPair(local_port=local_port, remote_port=0) 621 return forwarders.PortPair(local_port=local_port, remote_port=0)
615 622
616 def RemoveProfile(self, package, ignore_list): 623 def RemoveProfile(self, package, ignore_list):
617 """Delete application profile on device. 624 """Delete application profile on device.
618 625
619 Args: 626 Args:
620 package: The full package name string of the application for which the 627 package: The full package name string of the application for which the
621 profile is to be deleted. 628 profile is to be deleted.
622 ignore_list: List of files to keep. 629 ignore_list: List of files to keep.
623 """ 630 """
624 profile_dir = self._GetProfileDir(package) 631 profile_dir = self._GetProfileDir(package)
625 if not self._device.PathExists(profile_dir): 632 if not self._device.PathExists(profile_dir):
626 return 633 return
627 files = [ 634 files = [
628 posixpath.join(profile_dir, f) 635 posixpath.join(profile_dir, f)
629 for f in self._device.ListDirectory(profile_dir, as_root=True) 636 for f in self._device.ListDirectory(profile_dir, as_root=True)
630 if f not in ignore_list] 637 if f not in ignore_list]
631 if not files: 638 if not files:
632 return 639 return
633 cmd = ['rm', '-r'] 640 self._device.RemovePath(files, recursive=True, as_root=True)
634 cmd.extend(files)
635 self._device.RunShellCommand(cmd, as_root=True, check_return=True)
636 641
637 def PullProfile(self, package, output_profile_path): 642 def PullProfile(self, package, output_profile_path):
638 """Copy application profile from device to host machine. 643 """Copy application profile from device to host machine.
639 644
640 Args: 645 Args:
641 package: The full package name string of the application for which the 646 package: The full package name string of the application for which the
642 profile is to be copied. 647 profile is to be copied.
643 output_profile_dir: Location where profile to be stored on host machine. 648 output_profile_dir: Location where profile to be stored on host machine.
644 """ 649 """
645 profile_dir = self._GetProfileDir(package) 650 profile_dir = self._GetProfileDir(package)
646 logging.info("Pulling profile directory from device: '%s'->'%s'.", 651 logging.info("Pulling profile directory from device: '%s'->'%s'.",
647 profile_dir, output_profile_path) 652 profile_dir, output_profile_path)
648 # To minimize bandwidth it might be good to look at whether all the data 653 # To minimize bandwidth it might be good to look at whether all the data
649 # pulled down is really needed e.g. .pak files. 654 # pulled down is really needed e.g. .pak files.
650 if not os.path.exists(output_profile_path): 655 if not os.path.exists(output_profile_path):
651 os.makedirs(output_profile_path) 656 os.makedirs(output_profile_path)
652 files = self._device.ListDirectory(profile_dir, as_root=True) 657 problem_files = []
653 for f in files: 658 for filename in self._device.ListDirectory(profile_dir, as_root=True):
654 # Don't pull lib, since it is created by the installer. 659 # Don't pull lib, since it is created by the installer.
655 if f != 'lib': 660 if filename == 'lib':
656 source = posixpath.join(profile_dir, f) 661 continue
657 dest = os.path.join(output_profile_path, f) 662 source = posixpath.join(profile_dir, filename)
658 try: 663 dest = os.path.join(output_profile_path, filename)
659 self._device.PullFile(source, dest, timeout=240) 664 try:
660 except device_errors.CommandFailedError: 665 self._device.PullFile(source, dest, timeout=240)
661 logging.exception('Failed to pull %s to %s', source, dest) 666 except device_errors.CommandFailedError:
667 problem_files.append(source)
668 if problem_files:
669 # Some paths (e.g. 'files', 'app_textures') consistently fail to be
670 # pulled from the device.
671 logging.warning(
672 'There were errors retrieving the following paths from the profile:')
673 for filepath in problem_files:
674 logging.warning('- %s', filepath)
662 675
663 def _GetProfileDir(self, package): 676 def _GetProfileDir(self, package):
664 """Returns the on-device location where the application profile is stored 677 """Returns the on-device location where the application profile is stored
665 based on Android convention. 678 based on Android convention.
666 679
667 Args: 680 Args:
668 package: The full package name string of the application. 681 package: The full package name string of the application.
669 """ 682 """
670 return '/data/data/%s/' % package 683 return '/data/data/%s/' % package
671 684
672 def SetDebugApp(self, package): 685 def SetDebugApp(self, package):
673 """Set application to debugging. 686 """Set application to debugging.
674 687
675 Args: 688 Args:
676 package: The full package name string of the application. 689 package: The full package name string of the application.
677 """ 690 """
678 if self._device.IsUserBuild(): 691 if self._device.IsUserBuild():
679 logging.debug('User build device, setting debug app') 692 logging.debug('User build device, setting debug app')
680 self._device.RunShellCommand( 693 self._device.RunShellCommand(
681 ['am', 'set-debug-app', '--persistent', package]) 694 ['am', 'set-debug-app', '--persistent', package],
695 check_return=True)
682 696
683 def GetLogCat(self, number_of_lines=500): 697 def GetLogCat(self, number_of_lines=500):
684 """Returns most recent lines of logcat dump. 698 """Returns most recent lines of logcat dump.
685 699
686 Args: 700 Args:
687 number_of_lines: Number of lines of log to return. 701 number_of_lines: Number of lines of log to return.
688 """ 702 """
689 def decode_line(line): 703 def decode_line(line):
690 try: 704 try:
691 uline = unicode(line, encoding='utf-8') 705 uline = unicode(line, encoding='utf-8')
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 # Use linux instead of Android because when determining what tests to run on 801 # Use linux instead of Android because when determining what tests to run on
788 # a bot the individual device could be down, which would make BattOr tests 802 # a bot the individual device could be down, which would make BattOr tests
789 # not run on any device. BattOrs communicate with the host and not android 803 # not run on any device. BattOrs communicate with the host and not android
790 # devices. 804 # devices.
791 return battor_wrapper.IsBattOrConnected('linux') 805 return battor_wrapper.IsBattOrConnected('linux')
792 806
793 def Log(self, message): 807 def Log(self, message):
794 """Prints line to logcat.""" 808 """Prints line to logcat."""
795 TELEMETRY_LOGCAT_TAG = 'Telemetry' 809 TELEMETRY_LOGCAT_TAG = 'Telemetry'
796 self._device.RunShellCommand( 810 self._device.RunShellCommand(
797 ['log', '-p', 'i', '-t', TELEMETRY_LOGCAT_TAG, message]) 811 ['log', '-p', 'i', '-t', TELEMETRY_LOGCAT_TAG, message],
812 check_return=True)
798 813
799 def WaitForTemperature(self, temp): 814 def WaitForTemperature(self, temp):
800 # Temperature is in tenths of a degree C, so we convert to that scale. 815 # Temperature is in tenths of a degree C, so we convert to that scale.
801 self._battery.LetBatteryCoolToTemperature(temp * 10) 816 self._battery.LetBatteryCoolToTemperature(temp * 10)
802 817
803 def _FixPossibleAdbInstability(): 818 def _FixPossibleAdbInstability():
804 """Host side workaround for crbug.com/268450 (adb instability). 819 """Host side workaround for crbug.com/268450 (adb instability).
805 820
806 The adb server has a race which is mitigated by binding to a single core. 821 The adb server has a race which is mitigated by binding to a single core.
807 """ 822 """
808 if not psutil: 823 if not psutil:
809 return 824 return
810 for process in psutil.process_iter(): 825 for process in psutil.process_iter():
811 try: 826 try:
812 if psutil.version_info >= (2, 0): 827 if psutil.version_info >= (2, 0):
813 if 'adb' in process.name(): 828 if 'adb' in process.name():
814 process.cpu_affinity([0]) 829 process.cpu_affinity([0])
815 else: 830 else:
816 if 'adb' in process.name: 831 if 'adb' in process.name:
817 process.set_cpu_affinity([0]) 832 process.set_cpu_affinity([0])
818 except (psutil.NoSuchProcess, psutil.AccessDenied): 833 except (psutil.NoSuchProcess, psutil.AccessDenied):
819 logging.warn('Failed to set adb process CPU affinity') 834 logging.warn('Failed to set adb process CPU affinity')
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698