Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / build / android / pylib / device / device_utils.py
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
3 # found in the LICENSE file.
4
5 """Provides a variety of device interactions based on adb.
6
7 Eventually, this will be based on adb_wrapper.
8 """
9 # pylint: disable=W0613
10
11 import sys
12 import time
13
14 import pylib.android_commands
15 from pylib.device import adb_wrapper
16 from pylib.device import decorators
17 from pylib.device import device_errors
18 from pylib.utils import apk_helper
19 from pylib.utils import parallelizer
20
21 _DEFAULT_TIMEOUT = 30
22 _DEFAULT_RETRIES = 3
23
24
25 @decorators.WithExplicitTimeoutAndRetries(
26     _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
27 def GetAVDs():
28   """Returns a list of Android Virtual Devices.
29
30   Returns:
31     A list containing the configured AVDs.
32   """
33   return pylib.android_commands.GetAVDs()
34
35
36 @decorators.WithExplicitTimeoutAndRetries(
37     _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
38 def RestartServer():
39   """Restarts the adb server.
40
41   Raises:
42     CommandFailedError if we fail to kill or restart the server.
43   """
44   pylib.android_commands.AndroidCommands().RestartAdbServer()
45
46
47 class DeviceUtils(object):
48
49   def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT,
50                default_retries=_DEFAULT_RETRIES):
51     """DeviceUtils constructor.
52
53     Args:
54       device: Either a device serial, an existing AdbWrapper instance, an
55               an existing AndroidCommands instance, or nothing.
56       default_timeout: An integer containing the default number of seconds to
57                        wait for an operation to complete if no explicit value
58                        is provided.
59       default_retries: An integer containing the default number or times an
60                        operation should be retried on failure if no explicit
61                        value is provided.
62     """
63     self.old_interface = None
64     if isinstance(device, basestring):
65       self.old_interface = pylib.android_commands.AndroidCommands(device)
66     elif isinstance(device, adb_wrapper.AdbWrapper):
67       self.old_interface = pylib.android_commands.AndroidCommands(str(device))
68     elif isinstance(device, pylib.android_commands.AndroidCommands):
69       self.old_interface = device
70     elif not device:
71       self.old_interface = pylib.android_commands.AndroidCommands()
72     else:
73       raise ValueError('Unsupported type passed for argument "device"')
74     self._default_timeout = default_timeout
75     self._default_retries = default_retries
76     assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR))
77     assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR))
78
79   @decorators.WithTimeoutAndRetriesFromInstance()
80   def IsOnline(self, timeout=None, retries=None):
81     """Checks whether the device is online.
82
83     Args:
84       timeout: timeout in seconds
85       retries: number of retries
86
87     Returns:
88       True if the device is online, False otherwise.
89
90     Raises:
91       CommandTimeoutError on timeout.
92     """
93     return self.old_interface.IsOnline()
94
95   @decorators.WithTimeoutAndRetriesFromInstance()
96   def HasRoot(self, timeout=None, retries=None):
97     """Checks whether or not adbd has root privileges.
98
99     Args:
100       timeout: timeout in seconds
101       retries: number of retries
102
103     Returns:
104       True if adbd has root privileges, False otherwise.
105
106     Raises:
107       CommandTimeoutError on timeout.
108       DeviceUnreachableError on missing device.
109     """
110     return self._HasRootImpl()
111
112   def _HasRootImpl(self):
113     """Implementation of HasRoot.
114
115     This is split from HasRoot to allow other DeviceUtils methods to call
116     HasRoot without spawning a new timeout thread.
117
118     Returns:
119       Same as for |HasRoot|.
120
121     Raises:
122       Same as for |HasRoot|.
123     """
124     return self.old_interface.IsRootEnabled()
125
126   @decorators.WithTimeoutAndRetriesFromInstance()
127   def EnableRoot(self, timeout=None, retries=None):
128     """Restarts adbd with root privileges.
129
130     Args:
131       timeout: timeout in seconds
132       retries: number of retries
133
134     Raises:
135       CommandFailedError if root could not be enabled.
136       CommandTimeoutError on timeout.
137     """
138     if not self.old_interface.EnableAdbRoot():
139       raise device_errors.CommandFailedError(
140           'Could not enable root.', device=str(self))
141
142   @decorators.WithTimeoutAndRetriesFromInstance()
143   def GetExternalStoragePath(self, timeout=None, retries=None):
144     """Get the device's path to its SD card.
145
146     Args:
147       timeout: timeout in seconds
148       retries: number of retries
149
150     Returns:
151       The device's path to its SD card.
152
153     Raises:
154       CommandFailedError if the external storage path could not be determined.
155       CommandTimeoutError on timeout.
156       DeviceUnreachableError on missing device.
157     """
158     try:
159       return self.old_interface.GetExternalStorage()
160     except AssertionError as e:
161       raise device_errors.CommandFailedError(
162           str(e), device=str(self)), None, sys.exc_info()[2]
163
164   @decorators.WithTimeoutAndRetriesFromInstance()
165   def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None):
166     """Wait for the device to fully boot.
167
168     This means waiting for the device to boot, the package manager to be
169     available, and the SD card to be ready. It can optionally mean waiting
170     for wifi to come up, too.
171
172     Args:
173       wifi: A boolean indicating if we should wait for wifi to come up or not.
174       timeout: timeout in seconds
175       retries: number of retries
176
177     Raises:
178       CommandFailedError on failure.
179       CommandTimeoutError if one of the component waits times out.
180       DeviceUnreachableError if the device becomes unresponsive.
181     """
182     self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout)
183
184   def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None):
185     """Implementation of WaitUntilFullyBooted.
186
187     This is split from WaitUntilFullyBooted to allow other DeviceUtils methods
188     to call WaitUntilFullyBooted without spawning a new timeout thread.
189
190     TODO(jbudorick) Remove the timeout parameter once this is no longer
191     implemented via AndroidCommands.
192
193     Args:
194       wifi: Same as for |WaitUntilFullyBooted|.
195       timeout: timeout in seconds
196
197     Raises:
198       Same as for |WaitUntilFullyBooted|.
199     """
200     if timeout is None:
201       timeout = self._default_timeout
202     self.old_interface.WaitForSystemBootCompleted(timeout)
203     self.old_interface.WaitForDevicePm()
204     self.old_interface.WaitForSdCardReady(timeout)
205     if wifi:
206       while not 'Wi-Fi is enabled' in (
207           self._RunShellCommandImpl('dumpsys wifi')):
208         time.sleep(1)
209
210   REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
211   REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES
212
213   @decorators.WithTimeoutAndRetriesDefaults(
214       REBOOT_DEFAULT_TIMEOUT,
215       REBOOT_DEFAULT_RETRIES)
216   def Reboot(self, block=True, timeout=None, retries=None):
217     """Reboot the device.
218
219     Args:
220       block: A boolean indicating if we should wait for the reboot to complete.
221       timeout: timeout in seconds
222       retries: number of retries
223
224     Raises:
225       CommandTimeoutError on timeout.
226       DeviceUnreachableError on missing device.
227     """
228     self.old_interface.Reboot()
229     if block:
230       self._WaitUntilFullyBootedImpl(timeout=timeout)
231
232   INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT
233   INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES
234
235   @decorators.WithTimeoutAndRetriesDefaults(
236       INSTALL_DEFAULT_TIMEOUT,
237       INSTALL_DEFAULT_RETRIES)
238   def Install(self, apk_path, reinstall=False, timeout=None, retries=None):
239     """Install an APK.
240
241     Noop if an identical APK is already installed.
242
243     Args:
244       apk_path: A string containing the path to the APK to install.
245       reinstall: A boolean indicating if we should keep any existing app data.
246       timeout: timeout in seconds
247       retries: number of retries
248
249     Raises:
250       CommandFailedError if the installation fails.
251       CommandTimeoutError if the installation times out.
252       DeviceUnreachableError on missing device.
253     """
254     package_name = apk_helper.GetPackageName(apk_path)
255     device_path = self.old_interface.GetApplicationPath(package_name)
256     if device_path is not None:
257       files_changed = self.old_interface.GetFilesChanged(
258           apk_path, device_path, ignore_filenames=True)
259       if len(files_changed) > 0:
260         should_install = True
261         if not reinstall:
262           out = self.old_interface.Uninstall(package_name)
263           for line in out.splitlines():
264             if 'Failure' in line:
265               raise device_errors.CommandFailedError(
266                   line.strip(), device=str(self))
267       else:
268         should_install = False
269     else:
270       should_install = True
271     if should_install:
272       try:
273         out = self.old_interface.Install(apk_path, reinstall=reinstall)
274         for line in out.splitlines():
275           if 'Failure' in line:
276             raise device_errors.CommandFailedError(
277                 line.strip(), device=str(self))
278       except AssertionError as e:
279         raise device_errors.CommandFailedError(
280             str(e), device=str(self)), None, sys.exc_info()[2]
281
282   @decorators.WithTimeoutAndRetriesFromInstance()
283   def RunShellCommand(self, cmd, check_return=False, as_root=False,
284                       timeout=None, retries=None):
285     """Run an ADB shell command.
286
287     TODO(jbudorick) Switch the default value of check_return to True after
288     AndroidCommands is gone.
289
290     Args:
291       cmd: A list containing the command to run on the device and any arguments.
292       check_return: A boolean indicating whether or not the return code should
293                     be checked.
294       as_root: A boolean indicating whether the shell command should be run
295                with root privileges.
296       timeout: timeout in seconds
297       retries: number of retries
298
299     Returns:
300       The output of the command.
301
302     Raises:
303       CommandFailedError if check_return is True and the return code is nozero.
304       CommandTimeoutError on timeout.
305       DeviceUnreachableError on missing device.
306     """
307     return self._RunShellCommandImpl(cmd, check_return=check_return,
308                                      as_root=as_root, timeout=timeout)
309
310   def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False,
311                            timeout=None):
312     """Implementation of RunShellCommand.
313
314     This is split from RunShellCommand to allow other DeviceUtils methods to
315     call RunShellCommand without spawning a new timeout thread.
316
317     TODO(jbudorick) Remove the timeout parameter once this is no longer
318     implemented via AndroidCommands.
319
320     Args:
321       cmd: Same as for |RunShellCommand|.
322       check_return: Same as for |RunShellCommand|.
323       as_root: Same as for |RunShellCommand|.
324       timeout: timeout in seconds
325
326     Raises:
327       Same as for |RunShellCommand|.
328
329     Returns:
330       Same as for |RunShellCommand|.
331     """
332     if isinstance(cmd, list):
333       cmd = ' '.join(cmd)
334     if as_root and not self.HasRoot():
335       cmd = 'su -c %s' % cmd
336     if check_return:
337       code, output = self.old_interface.GetShellCommandStatusAndOutput(
338           cmd, timeout_time=timeout)
339       if int(code) != 0:
340         raise device_errors.AdbCommandFailedError(
341             cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self))
342     else:
343       output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout)
344     return output
345
346   @decorators.WithTimeoutAndRetriesFromInstance()
347   def KillAll(self, process_name, signum=9, as_root=False, blocking=False,
348               timeout=None, retries=None):
349     """Kill all processes with the given name on the device.
350
351     Args:
352       process_name: A string containing the name of the process to kill.
353       signum: An integer containing the signal number to send to kill. Defaults
354               to 9 (SIGKILL).
355       as_root: A boolean indicating whether the kill should be executed with
356                root privileges.
357       blocking: A boolean indicating whether we should wait until all processes
358                 with the given |process_name| are dead.
359       timeout: timeout in seconds
360       retries: number of retries
361
362     Raises:
363       CommandFailedError if no process was killed.
364       CommandTimeoutError on timeout.
365       DeviceUnreachableError on missing device.
366     """
367     pids = self.old_interface.ExtractPid(process_name)
368     if len(pids) == 0:
369       raise device_errors.CommandFailedError(
370           'No process "%s"' % process_name, device=str(self))
371
372     if blocking:
373       total_killed = self.old_interface.KillAllBlocking(
374           process_name, signum=signum, with_su=as_root, timeout_sec=timeout)
375     else:
376       total_killed = self.old_interface.KillAll(
377           process_name, signum=signum, with_su=as_root)
378     if total_killed == 0:
379       raise device_errors.CommandFailedError(
380           'Failed to kill "%s"' % process_name, device=str(self))
381
382   @decorators.WithTimeoutAndRetriesFromInstance()
383   def StartActivity(self, intent, blocking=False, trace_file_name=None,
384                     force_stop=False, timeout=None, retries=None):
385     """Start package's activity on the device.
386
387     Args:
388       intent: An Intent to send.
389       blocking: A boolean indicating whether we should wait for the activity to
390                 finish launching.
391       trace_file_name: If present, a string that both indicates that we want to
392                        profile the activity and contains the path to which the
393                        trace should be saved.
394       force_stop: A boolean indicating whether we should stop the activity
395                   before starting it.
396       timeout: timeout in seconds
397       retries: number of retries
398
399     Raises:
400       CommandFailedError if the activity could not be started.
401       CommandTimeoutError on timeout.
402       DeviceUnreachableError on missing device.
403     """
404     single_category = (intent.category[0] if isinstance(intent.category, list)
405                                           else intent.category)
406     output = self.old_interface.StartActivity(
407         intent.package, intent.activity, wait_for_completion=blocking,
408         action=intent.action, category=single_category, data=intent.data,
409         extras=intent.extras, trace_file_name=trace_file_name,
410         force_stop=force_stop, flags=intent.flags)
411     for l in output:
412       if l.startswith('Error:'):
413         raise device_errors.CommandFailedError(l, device=str(self))
414
415   @decorators.WithTimeoutAndRetriesFromInstance()
416   def BroadcastIntent(self, intent, timeout=None, retries=None):
417     """Send a broadcast intent.
418
419     Args:
420       intent: An Intent to broadcast.
421       timeout: timeout in seconds
422       retries: number of retries
423
424     Raises:
425       CommandTimeoutError on timeout.
426       DeviceUnreachableError on missing device.
427     """
428     package, old_intent = intent.action.rsplit('.', 1)
429     if intent.extras is None:
430       args = []
431     else:
432       args = ['-e %s%s' % (k, ' "%s"' % v if v else '')
433               for k, v in intent.extras.items() if len(k) > 0]
434     self.old_interface.BroadcastIntent(package, old_intent, *args)
435
436   @decorators.WithTimeoutAndRetriesFromInstance()
437   def GoHome(self, timeout=None, retries=None):
438     """Return to the home screen.
439
440     Args:
441       timeout: timeout in seconds
442       retries: number of retries
443
444     Raises:
445       CommandTimeoutError on timeout.
446       DeviceUnreachableError on missing device.
447     """
448     self.old_interface.GoHome()
449
450   @decorators.WithTimeoutAndRetriesFromInstance()
451   def ForceStop(self, package, timeout=None, retries=None):
452     """Close the application.
453
454     Args:
455       package: A string containing the name of the package to stop.
456       timeout: timeout in seconds
457       retries: number of retries
458
459     Raises:
460       CommandTimeoutError on timeout.
461       DeviceUnreachableError on missing device.
462     """
463     self.old_interface.CloseApplication(package)
464
465   @decorators.WithTimeoutAndRetriesFromInstance()
466   def ClearApplicationState(self, package, timeout=None, retries=None):
467     """Clear all state for the given package.
468
469     Args:
470       package: A string containing the name of the package to stop.
471       timeout: timeout in seconds
472       retries: number of retries
473
474     Raises:
475       CommandTimeoutError on timeout.
476       DeviceUnreachableError on missing device.
477     """
478     self.old_interface.ClearApplicationState(package)
479
480   @decorators.WithTimeoutAndRetriesFromInstance()
481   def SendKeyEvent(self, keycode, timeout=None, retries=None):
482     """Sends a keycode to the device.
483
484     See: http://developer.android.com/reference/android/view/KeyEvent.html
485
486     Args:
487       keycode: A integer keycode to send to the device.
488       timeout: timeout in seconds
489       retries: number of retries
490
491     Raises:
492       CommandTimeoutError on timeout.
493       DeviceUnreachableError on missing device.
494     """
495     self.old_interface.SendKeyEvent(keycode)
496
497   PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
498   PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES
499
500   @decorators.WithTimeoutAndRetriesDefaults(
501       PUSH_CHANGED_FILES_DEFAULT_TIMEOUT,
502       PUSH_CHANGED_FILES_DEFAULT_RETRIES)
503   def PushChangedFiles(self, host_path, device_path, timeout=None,
504                        retries=None):
505     """Push files to the device, skipping files that don't need updating.
506
507     Args:
508       host_path: A string containing the absolute path to the file or directory
509                  on the host that should be minimally pushed to the device.
510       device_path: A string containing the absolute path of the destination on
511                    the device.
512       timeout: timeout in seconds
513       retries: number of retries
514
515     Raises:
516       CommandFailedError on failure.
517       CommandTimeoutError on timeout.
518       DeviceUnreachableError on missing device.
519     """
520     self.old_interface.PushIfNeeded(host_path, device_path)
521
522   @decorators.WithTimeoutAndRetriesFromInstance()
523   def FileExists(self, device_path, timeout=None, retries=None):
524     """Checks whether the given file exists on the device.
525
526     Args:
527       device_path: A string containing the absolute path to the file on the
528                    device.
529       timeout: timeout in seconds
530       retries: number of retries
531
532     Returns:
533       True if the file exists on the device, False otherwise.
534
535     Raises:
536       CommandTimeoutError on timeout.
537       DeviceUnreachableError on missing device.
538     """
539     return self._FileExistsImpl(device_path)
540
541   def _FileExistsImpl(self, device_path):
542     """Implementation of FileExists.
543
544     This is split from FileExists to allow other DeviceUtils methods to call
545     FileExists without spawning a new timeout thread.
546
547     Args:
548       device_path: Same as for |FileExists|.
549
550     Returns:
551       True if the file exists on the device, False otherwise.
552
553     Raises:
554       Same as for |FileExists|.
555     """
556     return self.old_interface.FileExistsOnDevice(device_path)
557
558   @decorators.WithTimeoutAndRetriesFromInstance()
559   def PullFile(self, device_path, host_path, timeout=None, retries=None):
560     """Pull a file from the device.
561
562     Args:
563       device_path: A string containing the absolute path of the file to pull
564                    from the device.
565       host_path: A string containing the absolute path of the destination on
566                  the host.
567       timeout: timeout in seconds
568       retries: number of retries
569
570     Raises:
571       CommandFailedError on failure.
572       CommandTimeoutError on timeout.
573     """
574     try:
575       self.old_interface.PullFileFromDevice(device_path, host_path)
576     except AssertionError as e:
577       raise device_errors.CommandFailedError(
578           str(e), device=str(self)), None, sys.exc_info()[2]
579
580   @decorators.WithTimeoutAndRetriesFromInstance()
581   def ReadFile(self, device_path, as_root=False, timeout=None, retries=None):
582     """Reads the contents of a file from the device.
583
584     Args:
585       device_path: A string containing the absolute path of the file to read
586                    from the device.
587       as_root: A boolean indicating whether the read should be executed with
588                root privileges.
589       timeout: timeout in seconds
590       retries: number of retries
591
592     Returns:
593       The contents of the file at |device_path| as a list of lines.
594
595     Raises:
596       CommandFailedError if the file can't be read.
597       CommandTimeoutError on timeout.
598       DeviceUnreachableError on missing device.
599     """
600     # TODO(jbudorick) Evaluate whether we awant to return a list of lines after
601     # the implementation switch, and if file not found should raise exception.
602     if as_root:
603       if not self.old_interface.CanAccessProtectedFileContents():
604         raise device_errors.CommandFailedError(
605           'Cannot read from %s with root privileges.' % device_path)
606       return self.old_interface.GetProtectedFileContents(device_path)
607     else:
608       return self.old_interface.GetFileContents(device_path)
609
610   @decorators.WithTimeoutAndRetriesFromInstance()
611   def WriteFile(self, device_path, contents, as_root=False, timeout=None,
612                 retries=None):
613     """Writes |contents| to a file on the device.
614
615     Args:
616       device_path: A string containing the absolute path to the file to write
617                    on the device.
618       contents: A string containing the data to write to the device.
619       as_root: A boolean indicating whether the write should be executed with
620                root privileges.
621       timeout: timeout in seconds
622       retries: number of retries
623
624     Raises:
625       CommandFailedError if the file could not be written on the device.
626       CommandTimeoutError on timeout.
627       DeviceUnreachableError on missing device.
628     """
629     if as_root:
630       if not self.old_interface.CanAccessProtectedFileContents():
631         raise device_errors.CommandFailedError(
632             'Cannot write to %s with root privileges.' % device_path)
633       self.old_interface.SetProtectedFileContents(device_path, contents)
634     else:
635       self.old_interface.SetFileContents(device_path, contents)
636
637   @decorators.WithTimeoutAndRetriesFromInstance()
638   def Ls(self, device_path, timeout=None, retries=None):
639     """Lists the contents of a directory on the device.
640
641     Args:
642       device_path: A string containing the path of the directory on the device
643                    to list.
644       timeout: timeout in seconds
645       retries: number of retries
646
647     Returns:
648       The contents of the directory specified by |device_path|.
649
650     Raises:
651       CommandTimeoutError on timeout.
652       DeviceUnreachableError on missing device.
653     """
654     return self.old_interface.ListPathContents(device_path)
655
656   @decorators.WithTimeoutAndRetriesFromInstance()
657   def SetJavaAsserts(self, enabled, timeout=None, retries=None):
658     """Enables or disables Java asserts.
659
660     Args:
661       enabled: A boolean indicating whether Java asserts should be enabled
662                or disabled.
663       timeout: timeout in seconds
664       retries: number of retries
665
666     Raises:
667       CommandTimeoutError on timeout.
668     """
669     self.old_interface.SetJavaAssertsEnabled(enabled)
670
671   @decorators.WithTimeoutAndRetriesFromInstance()
672   def GetProp(self, property_name, timeout=None, retries=None):
673     """Gets a property from the device.
674
675     Args:
676       property_name: A string containing the name of the property to get from
677                      the device.
678       timeout: timeout in seconds
679       retries: number of retries
680
681     Returns:
682       The value of the device's |property_name| property.
683
684     Raises:
685       CommandTimeoutError on timeout.
686     """
687     return self.old_interface.system_properties[property_name]
688
689   @decorators.WithTimeoutAndRetriesFromInstance()
690   def SetProp(self, property_name, value, timeout=None, retries=None):
691     """Sets a property on the device.
692
693     Args:
694       property_name: A string containing the name of the property to set on
695                      the device.
696       value: A string containing the value to set to the property on the
697              device.
698       timeout: timeout in seconds
699       retries: number of retries
700
701     Raises:
702       CommandTimeoutError on timeout.
703     """
704     self.old_interface.system_properties[property_name] = value
705
706   @decorators.WithTimeoutAndRetriesFromInstance()
707   def GetPids(self, process_name, timeout=None, retries=None):
708     """Returns the PIDs of processes with the given name.
709
710     Note that the |process_name| is often the package name.
711
712     Args:
713       process_name: A string containing the process name to get the PIDs for.
714       timeout: timeout in seconds
715       retries: number of retries
716
717     Returns:
718       A dict mapping process name to PID for each process that contained the
719       provided |process_name|.
720
721     Raises:
722       CommandTimeoutError on timeout.
723       DeviceUnreachableError on missing device.
724     """
725     procs_pids = {}
726     for line in self._RunShellCommandImpl('ps'):
727       try:
728         ps_data = line.split()
729         if process_name in ps_data[-1]:
730           procs_pids[ps_data[-1]] = ps_data[1]
731       except IndexError:
732         pass
733     return procs_pids
734
735   @decorators.WithTimeoutAndRetriesFromInstance()
736   def TakeScreenshot(self, host_path=None, timeout=None, retries=None):
737     """Takes a screenshot of the device.
738
739     Args:
740       host_path: A string containing the path on the host to save the
741                  screenshot to. If None, a file name will be generated.
742       timeout: timeout in seconds
743       retries: number of retries
744
745     Returns:
746       The name of the file on the host to which the screenshot was saved.
747
748     Raises:
749       CommandFailedError on failure.
750       CommandTimeoutError on timeout.
751       DeviceUnreachableError on missing device.
752     """
753     return self.old_interface.TakeScreenshot(host_path)
754
755   @decorators.WithTimeoutAndRetriesFromInstance()
756   def GetIOStats(self, timeout=None, retries=None):
757     """Gets cumulative disk IO stats since boot for all processes.
758
759     Args:
760       timeout: timeout in seconds
761       retries: number of retries
762
763     Returns:
764       A dict containing |num_reads|, |num_writes|, |read_ms|, and |write_ms|.
765
766     Raises:
767       CommandTimeoutError on timeout.
768       DeviceUnreachableError on missing device.
769     """
770     return self.old_interface.GetIoStats()
771
772   @decorators.WithTimeoutAndRetriesFromInstance()
773   def GetMemoryUsageForPid(self, pid, timeout=None, retries=None):
774     """Gets the memory usage for the given PID.
775
776     Args:
777       pid: PID of the process.
778       timeout: timeout in seconds
779       retries: number of retries
780
781     Returns:
782       A 2-tuple containing:
783         - A dict containing the overall memory usage statistics for the PID.
784         - A dict containing memory usage statistics broken down by mapping.
785
786     Raises:
787       CommandTimeoutError on timeout.
788     """
789     return self.old_interface.GetMemoryUsageForPid(pid)
790
791   def __str__(self):
792     """Returns the device serial."""
793     s = self.old_interface.GetDevice()
794     if not s:
795       s = self.old_interface.Adb().GetSerialNumber()
796       if s == 'unknown':
797         raise device_errors.NoDevicesError()
798     return s
799
800   @staticmethod
801   def parallel(devices=None, async=False):
802     """Creates a Parallelizer to operate over the provided list of devices.
803
804     If |devices| is either |None| or an empty list, the Parallelizer will
805     operate over all attached devices.
806
807     Args:
808       devices: A list of either DeviceUtils instances or objects from
809                from which DeviceUtils instances can be constructed. If None,
810                all attached devices will be used.
811       async: If true, returns a Parallelizer that runs operations
812              asynchronously.
813
814     Returns:
815       A Parallelizer operating over |devices|.
816     """
817     if not devices or len(devices) == 0:
818       devices = pylib.android_commands.GetAttachedDevices()
819     parallelizer_type = (parallelizer.Parallelizer if async
820                          else parallelizer.SyncParallelizer)
821     return parallelizer_type([
822         d if isinstance(d, DeviceUtils) else DeviceUtils(d)
823         for d in devices])
824