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

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

Issue 64553012: [android] Adds AdbWrapper which is the base of the eventual AndroidCommands replacement. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase after crrev.com/60043003 Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « build/android/pylib/device/__init__.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (c) 2013 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 """Module wrapping Android's Adb tool."""
frankf 2013/11/20 19:28:39 "adb"
craigdh 2013/11/21 00:35:48 Done.
6
7 from pylib import cmd_helper
8
9 from pylib.utils import reraiser_thread
10 from pylib.utils import timeout_retry
11
12 _DEFAULT_TIMEOUT = 30
frankf 2013/11/20 19:28:39 add comments for each global constant
13 _DEFAULT_RETRIES = 2
14
15
16 class BaseError(Exception):
17 pass
18
19
20 class CommandFailedError(BaseError):
21 """Exception for command failures."""
22 def __init__(self, cmd, msg, device=None):
23 super(CommandFailedError, self).__init__(
24 (('%s: ' % device) if device else '') +
25 'adb command \'%s\' failed with message: %s' % (cmd, msg))
frankf 2013/11/20 19:28:39 add quotation marks around msg
craigdh 2013/11/21 00:35:48 Done.
26
27
28 class CommandTimeoutError(BaseError):
frankf 2013/11/20 19:28:39 docstring, run pylint
craigdh 2013/11/21 00:35:48 Done.
29 pass
30
31
32 class AdbWrapper(object):
33 """A wrapper around a local Android Debug Bridge executable."""
34
35 def __init__(self, device_serial):
36 """Initializes the AdbWrapper.
37
38 Args:
39 device_serial: The device serial number as a string.
40 """
41 self._device_serial = str(device_serial)
frankf 2013/11/20 19:28:39 hmm, why wouldn't this be a str?
craigdh 2013/11/21 00:35:48 To be pythonic and support ducktyping with anythin
42
43 @classmethod
44 def _AdbCmd(cls, arg_list, timeout, retries, check_error=True):
45 """Runs an adb command with a timeout and retries.
46
47 Args:
48 arg_list: a list of arguments to adb.
49 timeout: timeout in seconds.
50 retries: number of retries.
51 check_error: check that the command doesn't return an error message.
frankf 2013/11/20 19:28:39 Expand this comment to state that this doesn't wor
craigdh 2013/11/21 00:35:48 Clarified.
52
53 Returns:
54 The output of the command.
55 """
56 cmd = ['adb'] + list(arg_list)
frankf 2013/11/20 19:28:39 same here, do you mean to assert it's a list? If s
craigdh 2013/11/21 00:35:48 Not, list concatenation only works for lists but I
57
58 # This method runs inside the timeout/retries.
59 def RunCmd():
60 exit_code, output = cmd_helper.GetCmdStatusAndOutput(cmd)
61 if exit_code != 0:
62 raise CommandFailedError(
63 'Command \'%s\' failed with code %d' % (' '.join(cmd), exit_code))
64 if check_error and output[:len('error:')] == 'error:':
65 raise CommandFailedError(arg_list, output)
66 return output
67
68 try:
69 return timeout_retry.Run(RunCmd, timeout, retries)
70 except reraiser_thread.TimeoutError as e:
71 raise CommandTimeoutError(str(e))
72
73 def _DeviceAdbCmd(self, arg_list, timeout, retries, check_error=True):
74 """Runs an adb command on the device associated with this object.
75
76 Args:
77 arg_list: a list of arguments to adb.
78 timeout: timeout in seconds.
79 retries: number of retries.
80 check_error: check that the command doesn't return an error message.
81
82 Returns:
83 The output of the command.
84 """
85 return self._AdbCmd(
86 ['-s', self._device_serial] + list(arg_list), timeout, retries,
87 check_error=check_error)
88
89 def __eq__(self, other):
90 """Consider instances equal if they refer to the same device.
91
92 Args:
93 other: the instance to compare equality with.
94
95 Returns:
96 True if the instances are considered equal, false otherwise.
97 """
98 return self._device_serial == str(other)
99
100 def __str__(self):
101 """The string representation of an instance.
102
103 Returns:
104 The device serial number as a string.
105 """
106 return self._device_serial
107
108 def __repr__(self):
109 return '%s(\'%s\')' % (self.__class__.__name__, str(self))
110
111 # TODO(craigdh): Determine the filter criteria that should be supported.
112 @classmethod
113 def GetDevices(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
frankf 2013/11/20 19:28:39 Take a look at current adb_commands. You want to g
craigdh 2013/11/21 00:35:48 Yes, that falls under the TODO.
114 """Get the list of active attached devices.
115
116 Args:
117 timeout: timeout per try in seconds.
118 retries: number of retries to attempt.
119
120 Yields:
121 AdbWrapper instances.
122 """
123 output = cls._AdbCmd(['devices'], timeout, retries)
124 for line in output.split('\n'):
125 fields = line.split()
126 if len(fields) == 2 and fields[1] == 'device':
127 yield AdbWrapper(fields[0])
128
129 def GetDeviceSerial(self):
130 """Gets the device serial number associated with this object.
131
132 Returns:
133 Device serial number as a string.
134 """
135 return self._device_serial
136
137 def Push(self, local, remote, timeout=_DEFAULT_TIMEOUT,
138 retries=_DEFAULT_RETRIES):
139 """Pushes a file from the host to the device.
140
141 Args:
142 local: path on the host filesystem.
143 remote: path on the device filesystem.
144 timeout: timeout per try in seconds.
145 retries: number of retries to attempt.
146 """
147 self._DeviceAdbCmd(['push', local, remote], timeout, retries)
frankf 2013/11/20 19:28:39 YOu need check preconditions for these operations
craigdh 2013/11/21 00:35:48 Done.
craigdh 2013/11/21 00:35:48 Done.
148
149 def Pull(self, remote, local, timeout=_DEFAULT_TIMEOUT,
150 retries=_DEFAULT_RETRIES):
151 """Pulls a file from the device to the host.
152
153 Args:
154 remote: path on the device filesystem.
155 local: path on the host filesystem.
156 timeout: timeout per try in seconds.
157 retries: number of retries to attempt.
158 """
159 self._DeviceAdbCmd(['pull', local, remote], timeout, retries)
160
161 def Shell(self, command, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
frankf 2013/11/20 19:28:39 how about returning the rc in the shell?
craigdh 2013/11/21 00:35:48 Done.
162 """Runs a shell command on the device.
163
164 Args:
165 command: the shell command to run.
166 timeout: timeout per try in seconds.
167 retries: number of retries to attempt.
168
169 Returns:
170 The output of the shell command as a string.
171 """
172 return self._DeviceAdbCmd(
173 ['shell', command], timeout, retries, check_error=False)
174
175 def Logcat(self, filter_spec=None, timeout=_DEFAULT_TIMEOUT,
176 retries=_DEFAULT_RETRIES):
177 """Get the logcat output.
178
179 Args:
180 filter_spec: optional spec to filter the logcat.
181 timeout: timeout per try in seconds.
182 retries: number of retries to attempt.
183
184 Returns:
185 logcat output as a string.
186 """
187 cmd = ['logcat']
188 if filter_spec is not None:
189 cmd.append(filter_spec)
190 return self._DeviceAdbCmd(cmd, timeout, retries, check_error=False)
191
192 def Forward(self, local, remote, timeout=_DEFAULT_TIMEOUT,
193 retries=_DEFAULT_RETRIES):
194 """Forward socket connections from the local socket to the remote socket.
195
196 Sockets are specified by one of:
197 tcp:<port>
198 localabstract:<unix domain socket name>
199 localreserved:<unix domain socket name>
200 localfilesystem:<unix domain socket name>
201 dev:<character device name>
202 jdwp:<process pid> (remote only)
203
204 Args:
205 local: the host socket.
206 remote: the device socket.
207 timeout: timeout per try in seconds.
208 retries: number of retries to attempt.
209 """
210 self._DeviceAdbCmd(['forward', local, remote], timeout, retries)
211
212 def JDWP(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
213 """List of PIDs of processes hosting a JDWP transport.
214
215 Args:
216 timeout: timeout per try in seconds.
217 retries: number of retries to attempt.
218
219 Returns:
220 A list of PIDs as strings.
221 """
222 return [a.strip() for a in
223 self._DeviceAdbCmd(['jdwp'], timeout, retries).split('\n')]
224
225 def Install(self, apk_path, forward_lock=False, reinstall=False,
226 sd_card=False, timeout=_DEFAULT_TIMEOUT,
227 retries=_DEFAULT_RETRIES):
228 """Push a package file to the device and install it.
229
230 Args:
231 apk_path: host path to the APK file.
232 forward_lock: optional, if set forward-locks the app.
233 reinstall: optional, if set reinstalls the app, keeping its data.
234 sd_card: optional, if set installs on the SD card.
235 timeout: timeout per try in seconds.
236 retries: number of retries to attempt.
237 """
238 cmd = ['install']
239 if forward_lock:
240 cmd.append('-l')
241 if reinstall:
242 cmd.append('-r')
243 if sd_card:
244 cmd.append('-s')
245 cmd.append(apk_path)
246 output = self._DeviceAdbCmd(cmd, timeout, retries)
247 if 'Success' not in output:
248 raise CommandFailedError(cmd, output)
249
250 def Uninstall(self, package, keep_data=False, timeout=_DEFAULT_TIMEOUT,
251 retries=_DEFAULT_RETRIES):
252 """Remove the app |package| from the device.
253
254 Args:
255 package: the package to uninstall.
256 keep_data: optional, if set keep the data and cache directories.
257 timeout: timeout per try in seconds.
258 retries: number of retries to attempt.
259 """
260 cmd = ['uninstall']
261 if keep_data:
262 cmd.append('-k')
263 cmd.append(package)
264 return self._DeviceAdbCmd(cmd, timeout, retries)
265
266 def Backup(self, path, packages=None, apk=False, shared=False,
267 nosystem=True, include_all=False, timeout=_DEFAULT_TIMEOUT,
268 retries=_DEFAULT_RETRIES):
269 """Write an archive of the device's data to |path|.
270
271 Args:
272 path: local path to store the backup file.
273 packages: list of to packages to be backed up.
274 apk: optional, if set include the .apk files in the archive.
275 shared: optional, if set buckup the device's SD card.
276 nosystem: optional, if set exclude system applications.
277 include_all: optional, if set back up all installed applications and
278 |packages| is optional.
279 timeout: timeout per try in seconds.
280 retries: number of retries to attempt.
281 """
282 cmd = ['backup', path]
283 if apk:
284 cmd.append('-apk')
285 if shared:
286 cmd.append('-shared')
287 if nosystem:
288 cmd.append('-nosystem')
289 if include_all:
290 cmd.append('-all')
291 if packages:
292 cmd.extend(packages)
293 assert bool(packages) ^ bool(include_all), (
294 'Provide \'packages\' or set \'include_all\' but not both.')
295 return self._DeviceAdbCmd(cmd, timeout, retries)
296
297 def Restore(self, path, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
298 """Restore device contents from the backup archive.
299
300 Args:
301 path: host path to the backup archive.
302 timeout: timeout per try in seconds.
303 retries: number of retries to attempt.
304 """
305 self._DeviceAdbCmd(['restore'] + [path], timeout, retries)
306
307 def WaitForDevice(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
308 """Block until the device is online.
309
310 Args:
311 timeout: timeout per try in seconds.
312 retries: number of retries to attempt.
313 """
314 self._DeviceAdbCmd(['wait-for-device'], timeout, retries)
315
316 def GetState(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
317 """Get device state.
318
319 Args:
320 timeout: timeout per try in seconds.
321 retries: number of retries to attempt.
322
323 Returns:
324 One of 'offline', 'bootloader', or 'device'.
325 """
326 return self._DeviceAdbCmd(['get-state'], timeout, retries)
327
328 def GetDevPath(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
329 """Gets the device path.
330
331 Args:
332 timeout: timeout per try in seconds.
333 retries: number of retries to attempt.
334
335 Returns:
336 The device path (e.g. usb:3-4)
337 """
338 return self._DeviceAdbCmd(['get-devpath'], timeout, retries)
339
340 def Remount(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
341 """Remounts the /system partition on the device read-write."""
342 self._DeviceAdbCmd(['remount'], timeout, retries)
343
344 def Reboot(self, to_bootloader=False, timeout=_DEFAULT_TIMEOUT,
345 retries=_DEFAULT_RETRIES):
346 """Reboots the device.
347
348 Args:
349 to_bootloader: optional, if set reboots to the bootloader.
350 timeout: timeout per try in seconds.
351 retries: number of retries to attempt.
352 """
353 if to_bootloader:
354 cmd = ['reboot-bootloader']
355 else:
356 cmd = ['reboot']
357 self._DeviceAdbCmd(cmd, timeout, retries)
358
359 def Root(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
360 """Restarts the adbd daemon with root permissions, if possible.
361
362 Args:
363 timeout: timeout per try in seconds.
364 retries: number of retries to attempt.
365 """
366 output = self._DeviceAdbCmd('root', timeout, retries)
367 if 'cannot' in output:
368 raise CommandFailedError('root', output)
369
OLDNEW
« no previous file with comments | « build/android/pylib/device/__init__.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698