| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
| 6 | 6 |
| 7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
| 8 """ | 8 """ |
| 9 | 9 |
| 10 import collections | 10 import collections |
| 11 import datetime | 11 import datetime |
| 12 import io_stats_parser | |
| 13 import logging | 12 import logging |
| 14 import optparse | |
| 15 import os | 13 import os |
| 16 import pexpect | |
| 17 import re | 14 import re |
| 18 import shlex | 15 import shlex |
| 19 import subprocess | 16 import subprocess |
| 20 import sys | 17 import sys |
| 21 import tempfile | 18 import tempfile |
| 22 import time | 19 import time |
| 23 | 20 |
| 21 import pexpect |
| 22 import io_stats_parser |
| 24 | 23 |
| 25 # adb_interface.py is under ../../../third_party/android_testrunner/ | 24 # adb_interface.py is under ../../../third_party/android_testrunner/ |
| 26 sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', | 25 sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', |
| 27 '..', '..', 'third_party', 'android_testrunner')) | 26 '..', '..', 'third_party', 'android_testrunner')) |
| 28 import adb_interface | 27 import adb_interface |
| 29 import cmd_helper | 28 import cmd_helper |
| 30 import errors # is under ../../../third_party/android_testrunner/errors.py | 29 import errors # is under ../../../third_party/android_testrunner/errors.py |
| 31 | 30 |
| 32 | 31 |
| 33 # Pattern to search for the next whole line of pexpect output and capture it | 32 # Pattern to search for the next whole line of pexpect output and capture it |
| 34 # into a match group. We can't use ^ and $ for line start end with pexpect, | 33 # into a match group. We can't use ^ and $ for line start end with pexpect, |
| 35 # see http://www.noah.org/python/pexpect/#doc for explanation why. | 34 # see http://www.noah.org/python/pexpect/#doc for explanation why. |
| 36 PEXPECT_LINE_RE = re.compile('\n([^\r]*)\r') | 35 PEXPECT_LINE_RE = re.compile('\n([^\r]*)\r') |
| 37 | 36 |
| 38 # Set the adb shell prompt to be a unique marker that will [hopefully] not | 37 # Set the adb shell prompt to be a unique marker that will [hopefully] not |
| 39 # appear at the start of any line of a command's output. | 38 # appear at the start of any line of a command's output. |
| 40 SHELL_PROMPT = '~+~PQ\x17RS~+~' | 39 SHELL_PROMPT = '~+~PQ\x17RS~+~' |
| 41 | 40 |
| 42 # This only works for single core devices. | 41 # This only works for single core devices. |
| 43 SCALING_GOVERNOR = '/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor' | 42 SCALING_GOVERNOR = '/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor' |
| 44 DROP_CACHES = '/proc/sys/vm/drop_caches' | 43 DROP_CACHES = '/proc/sys/vm/drop_caches' |
| 45 | 44 |
| 46 # Java properties file | 45 # Java properties file |
| 47 LOCAL_PROPERTIES_PATH = '/data/local.prop' | 46 LOCAL_PROPERTIES_PATH = '/data/local.prop' |
| 48 | 47 |
| 49 # Property in /data/local.prop that controls Java assertions. | 48 # Property in /data/local.prop that controls Java assertions. |
| 50 JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' | 49 JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' |
| 51 | 50 |
| 52 BOOT_COMPLETE_RE = re.compile( | 51 BOOT_COMPLETE_RE = re.compile( |
| 53 'android.intent.action.MEDIA_MOUNTED path: /\w+/sdcard\d?' | 52 'android.intent.action.MEDIA_MOUNTED path: /\w+/sdcard\d?' |
| 54 + '|' + 'PowerManagerService(\(\s+\d+\))?: bootCompleted') | 53 '|PowerManagerService(\(\s+\d+\))?: bootCompleted') |
| 55 | 54 |
| 56 MEMORY_INFO_RE = re.compile('^(?P<key>\w+):\s+(?P<usage_kb>\d+) kB$') | 55 MEMORY_INFO_RE = re.compile('^(?P<key>\w+):\s+(?P<usage_kb>\d+) kB$') |
| 57 NVIDIA_MEMORY_INFO_RE = re.compile('^\s*(?P<user>\S+)\s*(?P<name>\S+)\s*' | 56 NVIDIA_MEMORY_INFO_RE = re.compile('^\s*(?P<user>\S+)\s*(?P<name>\S+)\s*' |
| 58 '(?P<pid>\d+)\s*(?P<usage_bytes>\d+)$') | 57 '(?P<pid>\d+)\s*(?P<usage_bytes>\d+)$') |
| 59 | 58 |
| 60 # Keycode "enum" suitable for passing to AndroidCommands.SendKey(). | 59 # Keycode "enum" suitable for passing to AndroidCommands.SendKey(). |
| 61 KEYCODE_HOME = 3 | 60 KEYCODE_HOME = 3 |
| 62 KEYCODE_BACK = 4 | 61 KEYCODE_BACK = 4 |
| 63 KEYCODE_DPAD_UP = 19 | 62 KEYCODE_DPAD_UP = 19 |
| 64 KEYCODE_DPAD_DOWN = 20 | 63 KEYCODE_DPAD_DOWN = 20 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 Example output: | 99 Example output: |
| 101 | 100 |
| 102 * daemon not running. starting it now on port 5037 * | 101 * daemon not running. starting it now on port 5037 * |
| 103 * daemon started successfully * | 102 * daemon started successfully * |
| 104 List of devices attached | 103 List of devices attached |
| 105 027c10494100b4d7 device | 104 027c10494100b4d7 device |
| 106 emulator-5554 offline | 105 emulator-5554 offline |
| 107 """ | 106 """ |
| 108 re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE) | 107 re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE) |
| 109 devices = re_device.findall(cmd_helper.GetCmdOutput(['adb', 'devices'])) | 108 devices = re_device.findall(cmd_helper.GetCmdOutput(['adb', 'devices'])) |
| 110 preferred_device = os.environ.get("ANDROID_SERIAL") | 109 preferred_device = os.environ.get('ANDROID_SERIAL') |
| 111 if preferred_device in devices: | 110 if preferred_device in devices: |
| 112 devices.remove(preferred_device) | 111 devices.remove(preferred_device) |
| 113 devices.insert(0, preferred_device) | 112 devices.insert(0, preferred_device) |
| 114 return devices | 113 return devices |
| 115 | 114 |
| 116 | 115 |
| 117 def _GetHostFileInfo(file_name): | 116 def _GetHostFileInfo(file_name): |
| 118 """Returns a tuple containing size and modified UTC time for file_name.""" | 117 """Returns a tuple containing size and modified UTC time for file_name.""" |
| 119 # The time accuracy on device is only to minute level, remove the second and | 118 # The time accuracy on device is only to minute level, remove the second and |
| 120 # microsecond from host results. | 119 # microsecond from host results. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 filename = filename[len(path_dir)+1:] | 188 filename = filename[len(path_dir)+1:] |
| 190 lastmod = datetime.datetime.strptime( | 189 lastmod = datetime.datetime.strptime( |
| 191 file_match.group('date') + ' ' + file_match.group('time')[:5], | 190 file_match.group('date') + ' ' + file_match.group('time')[:5], |
| 192 '%Y-%m-%d %H:%M') | 191 '%Y-%m-%d %H:%M') |
| 193 if not utc_offset and 'timezone' in re_file.groupindex: | 192 if not utc_offset and 'timezone' in re_file.groupindex: |
| 194 utc_offset = file_match.group('timezone') | 193 utc_offset = file_match.group('timezone') |
| 195 if isinstance(utc_offset, str) and len(utc_offset) == 5: | 194 if isinstance(utc_offset, str) and len(utc_offset) == 5: |
| 196 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), | 195 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), |
| 197 minutes=int(utc_offset[3:5])) | 196 minutes=int(utc_offset[3:5])) |
| 198 if utc_offset[0:1] == '-': | 197 if utc_offset[0:1] == '-': |
| 199 utc_delta = -utc_delta; | 198 utc_delta = -utc_delta |
| 200 lastmod -= utc_delta | 199 lastmod -= utc_delta |
| 201 files[filename] = (int(file_match.group('size')), lastmod) | 200 files[filename] = (int(file_match.group('size')), lastmod) |
| 202 return files | 201 return files |
| 203 | 202 |
| 204 | 203 |
| 205 def GetLogTimestamp(log_line, year): | 204 def GetLogTimestamp(log_line, year): |
| 206 """Returns the timestamp of the given |log_line| in the given year.""" | 205 """Returns the timestamp of the given |log_line| in the given year.""" |
| 207 try: | 206 try: |
| 208 return datetime.datetime.strptime('%s-%s' % (year, log_line[:18]), | 207 return datetime.datetime.strptime('%s-%s' % (year, log_line[:18]), |
| 209 '%Y-%m-%d %H:%M:%S.%f') | 208 '%Y-%m-%d %H:%M:%S.%f') |
| (...skipping 24 matching lines...) Expand all Loading... |
| 234 | 233 |
| 235 def Adb(self): | 234 def Adb(self): |
| 236 """Returns our AdbInterface to avoid us wrapping all its methods.""" | 235 """Returns our AdbInterface to avoid us wrapping all its methods.""" |
| 237 return self._adb | 236 return self._adb |
| 238 | 237 |
| 239 def IsRootEnabled(self): | 238 def IsRootEnabled(self): |
| 240 """Returns whether or not _adb.EnabledAdbRoot() has succeeded.""" | 239 """Returns whether or not _adb.EnabledAdbRoot() has succeeded.""" |
| 241 return self._root_enabled | 240 return self._root_enabled |
| 242 | 241 |
| 243 def GetDeviceYear(self): | 242 def GetDeviceYear(self): |
| 244 """Returns the year information of the date on device""" | 243 """Returns the year information of the date on device.""" |
| 245 return self.RunShellCommand('date +%Y')[0] | 244 return self.RunShellCommand('date +%Y')[0] |
| 246 | 245 |
| 247 def WaitForDevicePm(self): | 246 def WaitForDevicePm(self): |
| 248 """Blocks until the device's package manager is available. | 247 """Blocks until the device's package manager is available. |
| 249 | 248 |
| 250 To workaround http://b/5201039, we restart the shell and retry if the | 249 To workaround http://b/5201039, we restart the shell and retry if the |
| 251 package manager isn't back after 120 seconds. | 250 package manager isn't back after 120 seconds. |
| 252 | 251 |
| 253 Raises: | 252 Raises: |
| 254 errors.WaitForResponseTimedOutError after max retries reached. | 253 errors.WaitForResponseTimedOutError after max retries reached. |
| 255 """ | 254 """ |
| 256 last_err = None | 255 last_err = None |
| 257 retries = 3 | 256 retries = 3 |
| 258 while retries: | 257 while retries: |
| 259 try: | 258 try: |
| 260 self._adb.WaitForDevicePm() | 259 self._adb.WaitForDevicePm() |
| 261 return # Success | 260 return # Success |
| 262 except errors.WaitForResponseTimedOutError as e: | 261 except errors.WaitForResponseTimedOutError as e: |
| 263 last_err = e | 262 last_err = e |
| 264 logging.warning('Restarting and retrying after timeout: %s' % str(e)) | 263 logging.warning('Restarting and retrying after timeout: %s', e) |
| 265 retries -= 1 | 264 retries -= 1 |
| 266 self.RestartShell() | 265 self.RestartShell() |
| 267 raise last_err # Only reached after max retries, re-raise the last error. | 266 raise last_err # Only reached after max retries, re-raise the last error. |
| 268 | 267 |
| 269 def SynchronizeDateTime(self): | 268 def SynchronizeDateTime(self): |
| 270 """Synchronize date/time between host and device.""" | 269 """Synchronize date/time between host and device.""" |
| 271 self._adb.SendShellCommand('date -u %f' % time.time()) | 270 self._adb.SendShellCommand('date -u %f' % time.time()) |
| 272 | 271 |
| 273 def RestartShell(self): | 272 def RestartShell(self): |
| 274 """Restarts the shell on the device. Does not block for it to return.""" | 273 """Restarts the shell on the device. Does not block for it to return.""" |
| 275 self.RunShellCommand('stop') | 274 self.RunShellCommand('stop') |
| 276 self.RunShellCommand('start') | 275 self.RunShellCommand('start') |
| 277 | 276 |
| 278 def Reboot(self, full_reboot=True): | 277 def Reboot(self, full_reboot=True): |
| 279 """Reboots the device and waits for the package manager to return. | 278 """Reboots the device and waits for the package manager to return. |
| 280 | 279 |
| 281 Args: | 280 Args: |
| 282 full_reboot: Whether to fully reboot the device or just restart the shell. | 281 full_reboot: Whether to fully reboot the device or just restart the shell. |
| 283 """ | 282 """ |
| 284 # TODO(torne): hive can't reboot the device either way without breaking the | 283 # TODO(torne): hive can't reboot the device either way without breaking the |
| 285 # connection; work out if we can handle this better | 284 # connection; work out if we can handle this better |
| 286 if os.environ.get('USING_HIVE'): | 285 if os.environ.get('USING_HIVE'): |
| 287 logging.warning('Ignoring reboot request as we are on hive') | 286 logging.warning('Ignoring reboot request as we are on hive') |
| 288 return | 287 return |
| 289 if full_reboot: | 288 if full_reboot or not self.IsRootEnabled(): |
| 290 self._adb.SendCommand('reboot') | 289 self._adb.SendCommand('reboot') |
| 290 timeout = 300 |
| 291 else: | 291 else: |
| 292 self.RestartShell() | 292 self.RestartShell() |
| 293 timeout = 120 |
| 293 self.WaitForDevicePm() | 294 self.WaitForDevicePm() |
| 294 self.StartMonitoringLogcat(timeout=120) | 295 self.StartMonitoringLogcat(timeout=timeout) |
| 295 self.WaitForLogMatch(BOOT_COMPLETE_RE, None) | 296 self.WaitForLogMatch(BOOT_COMPLETE_RE, None) |
| 296 | 297 |
| 297 def Uninstall(self, package): | 298 def Uninstall(self, package): |
| 298 """Uninstalls the specified package from the device. | 299 """Uninstalls the specified package from the device. |
| 299 | 300 |
| 300 Args: | 301 Args: |
| 301 package: Name of the package to remove. | 302 package: Name of the package to remove. |
| 302 | 303 |
| 303 Returns: | 304 Returns: |
| 304 A status string returned by adb uninstall | 305 A status string returned by adb uninstall |
| 305 """ | 306 """ |
| 306 uninstall_command = 'uninstall %s' % package | 307 uninstall_command = 'uninstall %s' % package |
| 307 | 308 |
| 308 logging.info('>>> $' + uninstall_command) | 309 logging.info('>>> $' + uninstall_command) |
| 309 return self._adb.SendCommand(uninstall_command, timeout_time=60) | 310 return self._adb.SendCommand(uninstall_command, timeout_time=60) |
| 310 | 311 |
| 311 def Install(self, package_file_path): | 312 def Install(self, package_file_path, reinstall=False): |
| 312 """Installs the specified package to the device. | 313 """Installs the specified package to the device. |
| 313 | 314 |
| 314 Args: | 315 Args: |
| 315 package_file_path: Path to .apk file to install. | 316 package_file_path: Path to .apk file to install. |
| 317 reinstall: Whether to reinstall over existing package |
| 316 | 318 |
| 317 Returns: | 319 Returns: |
| 318 A status string returned by adb install | 320 A status string returned by adb install |
| 319 """ | 321 """ |
| 320 assert os.path.isfile(package_file_path) | 322 assert os.path.isfile(package_file_path) |
| 321 | 323 |
| 322 install_command = 'install %s' % package_file_path | 324 if reinstall: |
| 325 install_cmd = 'install -r %s' |
| 326 else: |
| 327 install_cmd = 'install %s' |
| 323 | 328 |
| 324 logging.info('>>> $' + install_command) | 329 return self._adb.SendCommand(install_cmd % package_file_path, |
| 325 return self._adb.SendCommand(install_command, timeout_time=2*60) | 330 timeout_time=2*60, retry_count=0) |
| 331 |
| 332 def ManagedInstall(self, apk_path, keep_data, package_name=None, |
| 333 reboots_on_failure=2): |
| 334 """Installs specified package and reboots device on timeouts. |
| 335 |
| 336 Args: |
| 337 apk_path: Path to .apk file to install. |
| 338 keep_data: Whether to keep data if package already exists |
| 339 package_name: Package name (only needed if keep_data=False) |
| 340 reboots_on_failure: number of time to reboot if package manager is frozen. |
| 341 |
| 342 Returns: |
| 343 A status string returned by adb install |
| 344 """ |
| 345 reboots_left = reboots_on_failure |
| 346 while True: |
| 347 try: |
| 348 if not keep_data: |
| 349 self.Uninstall(package_name) |
| 350 install_status = self.Install(apk_path, keep_data) |
| 351 if 'Success' in install_status: |
| 352 return install_status |
| 353 except errors.WaitForResponseTimedOutError: |
| 354 logging.info('Timout on installing %s' % apk_path) |
| 355 |
| 356 if reboots_left <= 0: |
| 357 raise Exception('Install failure') |
| 358 |
| 359 # Force a hard reboot on last attempt |
| 360 self.Reboot(full_reboot=(reboots_left == 1)) |
| 361 reboots_left -= 1 |
| 326 | 362 |
| 327 def MakeSystemFolderWritable(self): | 363 def MakeSystemFolderWritable(self): |
| 328 """Remounts the /system folder rw. """ | 364 """Remounts the /system folder rw.""" |
| 329 out = self._adb.SendCommand('remount') | 365 out = self._adb.SendCommand('remount') |
| 330 if out.strip() != 'remount succeeded': | 366 if out.strip() != 'remount succeeded': |
| 331 raise errors.MsgException('Remount failed: %s' % out) | 367 raise errors.MsgException('Remount failed: %s' % out) |
| 332 | 368 |
| 333 def RestartAdbServer(self): | 369 def RestartAdbServer(self): |
| 334 """Restart the adb server.""" | 370 """Restart the adb server.""" |
| 335 self.KillAdbServer() | 371 self.KillAdbServer() |
| 336 self.StartAdbServer() | 372 self.StartAdbServer() |
| 337 | 373 |
| 338 def KillAdbServer(self): | 374 def KillAdbServer(self): |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 'sys.boot_completed flag was not set after %s seconds' % wait_time) | 417 'sys.boot_completed flag was not set after %s seconds' % wait_time) |
| 382 | 418 |
| 383 def WaitForSdCardReady(self, timeout_time): | 419 def WaitForSdCardReady(self, timeout_time): |
| 384 """Wait for the SD card ready before pushing data into it.""" | 420 """Wait for the SD card ready before pushing data into it.""" |
| 385 logging.info('Waiting for SD card ready...') | 421 logging.info('Waiting for SD card ready...') |
| 386 sdcard_ready = False | 422 sdcard_ready = False |
| 387 attempts = 0 | 423 attempts = 0 |
| 388 wait_period = 5 | 424 wait_period = 5 |
| 389 while not sdcard_ready and attempts * wait_period < timeout_time: | 425 while not sdcard_ready and attempts * wait_period < timeout_time: |
| 390 output = self.RunShellCommand('ls /sdcard/') | 426 output = self.RunShellCommand('ls /sdcard/') |
| 391 if len(output) > 0: | 427 if output: |
| 392 sdcard_ready = True | 428 sdcard_ready = True |
| 393 else: | 429 else: |
| 394 time.sleep(wait_period) | 430 time.sleep(wait_period) |
| 395 attempts += 1 | 431 attempts += 1 |
| 396 if not sdcard_ready: | 432 if not sdcard_ready: |
| 397 raise errors.WaitForResponseTimedOutError( | 433 raise errors.WaitForResponseTimedOutError( |
| 398 'SD card not ready after %s seconds' % timeout_time) | 434 'SD card not ready after %s seconds' % timeout_time) |
| 399 | 435 |
| 400 # It is tempting to turn this function into a generator, however this is not | 436 # It is tempting to turn this function into a generator, however this is not |
| 401 # possible without using a private (local) adb_shell instance (to ensure no | 437 # possible without using a private (local) adb_shell instance (to ensure no |
| 402 # other command interleaves usage of it), which would defeat the main aim of | 438 # other command interleaves usage of it), which would defeat the main aim of |
| 403 # being able to reuse the adb shell instance across commands. | 439 # being able to reuse the adb shell instance across commands. |
| 404 def RunShellCommand(self, command, timeout_time=20, log_result=True): | 440 def RunShellCommand(self, command, timeout_time=20, log_result=True): |
| 405 """Send a command to the adb shell and return the result. | 441 """Send a command to the adb shell and return the result. |
| 406 | 442 |
| 407 Args: | 443 Args: |
| 408 command: String containing the shell command to send. Must not include | 444 command: String containing the shell command to send. Must not include |
| 409 the single quotes as we use them to escape the whole command. | 445 the single quotes as we use them to escape the whole command. |
| 410 timeout_time: Number of seconds to wait for command to respond before | 446 timeout_time: Number of seconds to wait for command to respond before |
| 411 retrying, used by AdbInterface.SendShellCommand. | 447 retrying, used by AdbInterface.SendShellCommand. |
| 412 log_result: Boolean to indicate whether we should log the result of the | 448 log_result: Boolean to indicate whether we should log the result of the |
| 413 shell command. | 449 shell command. |
| 414 | 450 |
| 415 Returns: | 451 Returns: |
| 416 list containing the lines of output received from running the command | 452 list containing the lines of output received from running the command |
| 417 """ | 453 """ |
| 418 logging.info('>>> $' + command) | 454 logging.info('>>> $' + command) |
| 419 if "'" in command: logging.warning(command + " contains ' quotes") | 455 if "'" in command: logging.warning(command + " contains ' quotes") |
| 420 result = self._adb.SendShellCommand("'%s'" % command, | 456 result = self._adb.SendShellCommand( |
| 421 timeout_time).splitlines() | 457 "'%s'" % command, timeout_time).splitlines() |
| 458 if ['error: device not found'] == result: |
| 459 raise errors.DeviceUnresponsiveError('device not found') |
| 422 if log_result: | 460 if log_result: |
| 423 logging.info('\n>>> '.join(result)) | 461 logging.info('\n>>> '.join(result)) |
| 424 return result | 462 return result |
| 425 | 463 |
| 426 def KillAll(self, process): | 464 def KillAll(self, process): |
| 427 """Android version of killall, connected via adb. | 465 """Android version of killall, connected via adb. |
| 428 | 466 |
| 429 Args: | 467 Args: |
| 430 process: name of the process to kill off | 468 process: name of the process to kill off |
| 431 | 469 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 elif isinstance(value, int): | 511 elif isinstance(value, int): |
| 474 cmd += ' --ei' | 512 cmd += ' --ei' |
| 475 else: | 513 else: |
| 476 raise NotImplementedError( | 514 raise NotImplementedError( |
| 477 'Need to teach StartActivity how to pass %s extras' % type(value)) | 515 'Need to teach StartActivity how to pass %s extras' % type(value)) |
| 478 cmd += ' %s %s' % (key, value) | 516 cmd += ' %s %s' % (key, value) |
| 479 if trace_file_name: | 517 if trace_file_name: |
| 480 cmd += ' --start-profiler ' + trace_file_name | 518 cmd += ' --start-profiler ' + trace_file_name |
| 481 self.RunShellCommand(cmd) | 519 self.RunShellCommand(cmd) |
| 482 | 520 |
| 483 | |
| 484 def CloseApplication(self, package): | 521 def CloseApplication(self, package): |
| 485 """Attempt to close down the application, using increasing violence. | 522 """Attempt to close down the application, using increasing violence. |
| 486 | 523 |
| 487 Args: | 524 Args: |
| 488 package: Name of the process to kill off, e.g. | 525 package: Name of the process to kill off, e.g. |
| 489 com.google.android.apps.chrome | 526 com.google.android.apps.chrome |
| 490 """ | 527 """ |
| 491 self.RunShellCommand('am force-stop ' + package) | 528 self.RunShellCommand('am force-stop ' + package) |
| 492 | 529 |
| 493 def ClearApplicationState(self, package): | 530 def ClearApplicationState(self, package): |
| (...skipping 28 matching lines...) Expand all Loading... |
| 522 local_contents = ListHostPathContents(local_path) | 559 local_contents = ListHostPathContents(local_path) |
| 523 device_contents = self.ListPathContents(device_path) | 560 device_contents = self.ListPathContents(device_path) |
| 524 # Only compare the size and timestamp if only copying a file because | 561 # Only compare the size and timestamp if only copying a file because |
| 525 # the filename on device can be renamed. | 562 # the filename on device can be renamed. |
| 526 if os.path.isfile(local_path): | 563 if os.path.isfile(local_path): |
| 527 assert len(local_contents) == 1 | 564 assert len(local_contents) == 1 |
| 528 is_equal = local_contents.values() == device_contents.values() | 565 is_equal = local_contents.values() == device_contents.values() |
| 529 else: | 566 else: |
| 530 is_equal = local_contents == device_contents | 567 is_equal = local_contents == device_contents |
| 531 if is_equal: | 568 if is_equal: |
| 532 logging.info('%s is up-to-date. Skipping file push.' % device_path) | 569 logging.info('%s is up-to-date. Skipping file push.', device_path) |
| 533 return | 570 return |
| 534 | 571 |
| 535 # They don't match, so remove everything first and then create it. | 572 # They don't match, so remove everything first and then create it. |
| 536 if os.path.isdir(local_path): | 573 if os.path.isdir(local_path): |
| 537 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2*60) | 574 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2*60) |
| 538 self.RunShellCommand('mkdir -p %s' % device_path) | 575 self.RunShellCommand('mkdir -p %s' % device_path) |
| 539 | 576 |
| 540 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of | 577 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of |
| 541 # 60 seconds which isn't sufficient for a lot of users of this method. | 578 # 60 seconds which isn't sufficient for a lot of users of this method. |
| 542 push_command = 'push %s %s' % (local_path, device_path) | 579 push_command = 'push %s %s' % (local_path, device_path) |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 | 675 |
| 639 self.RunShellCommand('setprop %s "%s"' % (JAVA_ASSERT_PROPERTY, | 676 self.RunShellCommand('setprop %s "%s"' % (JAVA_ASSERT_PROPERTY, |
| 640 enable and 'all' or '')) | 677 enable and 'all' or '')) |
| 641 return True | 678 return True |
| 642 | 679 |
| 643 def DropRamCaches(self): | 680 def DropRamCaches(self): |
| 644 """Drops the filesystem ram caches for performance testing.""" | 681 """Drops the filesystem ram caches for performance testing.""" |
| 645 self.RunShellCommand('echo 3 > ' + DROP_CACHES) | 682 self.RunShellCommand('echo 3 > ' + DROP_CACHES) |
| 646 | 683 |
| 647 def StartMonitoringLogcat(self, clear=True, timeout=10, logfile=None, | 684 def StartMonitoringLogcat(self, clear=True, timeout=10, logfile=None, |
| 648 filters=[]): | 685 filters=None): |
| 649 """Starts monitoring the output of logcat, for use with WaitForLogMatch. | 686 """Starts monitoring the output of logcat, for use with WaitForLogMatch. |
| 650 | 687 |
| 651 Args: | 688 Args: |
| 652 clear: If True the existing logcat output will be cleared, to avoiding | 689 clear: If True the existing logcat output will be cleared, to avoiding |
| 653 matching historical output lurking in the log. | 690 matching historical output lurking in the log. |
| 654 timeout: How long WaitForLogMatch will wait for the given match | 691 timeout: How long WaitForLogMatch will wait for the given match |
| 655 filters: A list of logcat filters to be used. | 692 filters: A list of logcat filters to be used. |
| 656 """ | 693 """ |
| 657 if clear: | 694 if clear: |
| 658 self.RunShellCommand('logcat -c') | 695 self.RunShellCommand('logcat -c') |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 | 786 |
| 750 Returns: | 787 Returns: |
| 751 The logcat output as a string or an empty string if logcat was not | 788 The logcat output as a string or an empty string if logcat was not |
| 752 being recorded at the time. | 789 being recorded at the time. |
| 753 """ | 790 """ |
| 754 if not self.logcat_process: | 791 if not self.logcat_process: |
| 755 return '' | 792 return '' |
| 756 # Cannot evaluate directly as 0 is a possible value. | 793 # Cannot evaluate directly as 0 is a possible value. |
| 757 # Better to read the self.logcat_process.stdout before killing it, | 794 # Better to read the self.logcat_process.stdout before killing it, |
| 758 # Otherwise the communicate may return incomplete output due to pipe break. | 795 # Otherwise the communicate may return incomplete output due to pipe break. |
| 759 if self.logcat_process.poll() == None: | 796 if self.logcat_process.poll() is None: |
| 760 self.logcat_process.kill() | 797 self.logcat_process.kill() |
| 761 (output, _) = self.logcat_process.communicate() | 798 (output, _) = self.logcat_process.communicate() |
| 762 self.logcat_process = None | 799 self.logcat_process = None |
| 763 return output | 800 return output |
| 764 | 801 |
| 765 def SearchLogcatRecord(self, record, message, thread_id=None, proc_id=None, | 802 def SearchLogcatRecord(self, record, message, thread_id=None, proc_id=None, |
| 766 log_level=None, component=None): | 803 log_level=None, component=None): |
| 767 """Searches the specified logcat output and returns results. | 804 """Searches the specified logcat output and returns results. |
| 768 | 805 |
| 769 This method searches through the logcat output specified by record for a | 806 This method searches through the logcat output specified by record for a |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 usage_bytes = int(match.group('usage_bytes')) | 925 usage_bytes = int(match.group('usage_bytes')) |
| 889 usage_dict['Nvidia'] = int(round(usage_bytes / 1000.0)) # kB | 926 usage_dict['Nvidia'] = int(round(usage_bytes / 1000.0)) # kB |
| 890 break | 927 break |
| 891 | 928 |
| 892 return (usage_dict, smaps) | 929 return (usage_dict, smaps) |
| 893 | 930 |
| 894 def GetMemoryUsageForPackage(self, package): | 931 def GetMemoryUsageForPackage(self, package): |
| 895 """Returns the memory usage for all processes whose name contains |pacakge|. | 932 """Returns the memory usage for all processes whose name contains |pacakge|. |
| 896 | 933 |
| 897 Args: | 934 Args: |
| 898 name: A string holding process name to lookup pid list for. | 935 package: A string holding process name to lookup pid list for. |
| 899 | 936 |
| 900 Returns: | 937 Returns: |
| 901 A tuple containg: | 938 A tuple containg: |
| 902 [0]: Dict of {metric:usage_kb}, summed over all pids associated with | 939 [0]: Dict of {metric:usage_kb}, summed over all pids associated with |
| 903 |name|. | 940 |name|. |
| 904 The metric keys which may be included are: Size, Rss, Pss, Shared_Clean, | 941 The metric keys which may be included are: Size, Rss, Pss, Shared_Clean, |
| 905 Shared_Dirty, Private_Clean, Private_Dirty, Referenced, Swap, | 942 Shared_Dirty, Private_Clean, Private_Dirty, Referenced, Swap, |
| 906 KernelPageSize, MMUPageSize, Nvidia (tablet only). | 943 KernelPageSize, MMUPageSize, Nvidia (tablet only). |
| 907 [1]: a list with detailed /proc/[PID]/smaps information. | 944 [1]: a list with detailed /proc/[PID]/smaps information. |
| 908 """ | 945 """ |
| 909 usage_dict = collections.defaultdict(int) | 946 usage_dict = collections.defaultdict(int) |
| 910 pid_list = self.ExtractPid(package) | 947 pid_list = self.ExtractPid(package) |
| 911 smaps = collections.defaultdict(dict) | 948 smaps = collections.defaultdict(dict) |
| 912 | 949 |
| 913 for pid in pid_list: | 950 for pid in pid_list: |
| 914 usage_dict_per_pid, smaps_per_pid = self.GetMemoryUsageForPid(pid) | 951 usage_dict_per_pid, smaps_per_pid = self.GetMemoryUsageForPid(pid) |
| 915 smaps[pid] = smaps_per_pid | 952 smaps[pid] = smaps_per_pid |
| 916 for (key, value) in usage_dict_per_pid.items(): | 953 for (key, value) in usage_dict_per_pid.items(): |
| 917 usage_dict[key] += value | 954 usage_dict[key] += value |
| 918 | 955 |
| 919 return usage_dict, smaps | 956 return usage_dict, smaps |
| 920 | 957 |
| 921 def ProcessesUsingDevicePort(self, device_port): | 958 def ProcessesUsingDevicePort(self, device_port): |
| 922 """Lists the processes using the specified device port on loopback | 959 """Lists processes using the specified device port on loopback interface. |
| 923 interface. | |
| 924 | 960 |
| 925 Args: | 961 Args: |
| 926 device_port: Port on device we want to check. | 962 device_port: Port on device we want to check. |
| 927 | 963 |
| 928 Returns: | 964 Returns: |
| 929 A list of (pid, process_name) tuples using the specified port. | 965 A list of (pid, process_name) tuples using the specified port. |
| 930 """ | 966 """ |
| 931 tcp_results = self.RunShellCommand('cat /proc/net/tcp', log_result=False) | 967 tcp_results = self.RunShellCommand('cat /proc/net/tcp', log_result=False) |
| 932 tcp_address = "0100007F:%04X" % device_port | 968 tcp_address = '0100007F:%04X' % device_port |
| 933 pids = [] | 969 pids = [] |
| 934 for single_connect in tcp_results: | 970 for single_connect in tcp_results: |
| 935 connect_results = single_connect.split() | 971 connect_results = single_connect.split() |
| 936 # Column 1 is the TCP port, and Column 9 is the inode of the socket | 972 # Column 1 is the TCP port, and Column 9 is the inode of the socket |
| 937 if connect_results[1] == tcp_address: | 973 if connect_results[1] == tcp_address: |
| 938 socket_inode = connect_results[9] | 974 socket_inode = connect_results[9] |
| 939 socket_name = 'socket:[%s]' % socket_inode | 975 socket_name = 'socket:[%s]' % socket_inode |
| 940 lsof_results = self.RunShellCommand('lsof', log_result=False) | 976 lsof_results = self.RunShellCommand('lsof', log_result=False) |
| 941 for single_process in lsof_results: | 977 for single_process in lsof_results: |
| 942 process_results = single_process.split() | 978 process_results = single_process.split() |
| 943 # Ignore the line if it has less than nine columns in it, which may | 979 # Ignore the line if it has less than nine columns in it, which may |
| 944 # be the case when a process stops while lsof is executing. | 980 # be the case when a process stops while lsof is executing. |
| 945 if len(process_results) <= 8: | 981 if len(process_results) <= 8: |
| 946 continue | 982 continue |
| 947 # Column 0 is the executable name | 983 # Column 0 is the executable name |
| 948 # Column 1 is the pid | 984 # Column 1 is the pid |
| 949 # Column 8 is the Inode in use | 985 # Column 8 is the Inode in use |
| 950 if process_results[8] == socket_name: | 986 if process_results[8] == socket_name: |
| 951 pids.append( (int(process_results[1]), process_results[0]) ) | 987 pids.append((int(process_results[1]), process_results[0])) |
| 952 break | 988 break |
| 953 logging.info('PidsUsingDevicePort: %s', pids) | 989 logging.info('PidsUsingDevicePort: %s', pids) |
| 954 return pids | 990 return pids |
| OLD | NEW |