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 |