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

Side by Side Diff: build/android/pylib/utils/emulator.py

Issue 12407004: Add script to download SDK, system images and create and start AVDs for testing. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Do not catch exceptions so that stack trace is revealed. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/android/pylib/constants.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
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Provides an interface to start and stop Android emulator. 7 """Provides an interface to start and stop Android emulator.
8 8
9 Assumes system environment ANDROID_NDK_ROOT has been set. 9 Assumes system environment ANDROID_NDK_ROOT has been set.
10 10
11 Emulator: The class provides the methods to launch/shutdown the emulator with 11 Emulator: The class provides the methods to launch/shutdown the emulator with
12 the android virtual device named 'avd_armeabi' . 12 the android virtual device named 'avd_armeabi' .
13 """ 13 """
14 14
15 import logging 15 import logging
16 import os 16 import os
17 import signal 17 import signal
18 import subprocess 18 import subprocess
19 import sys 19 import sys
20 import time 20 import time
21 21
22 import time_profile 22 import time_profile
23 # TODO(craigdh): Move these pylib dependencies to pylib/utils/. 23 # TODO(craigdh): Move these pylib dependencies to pylib/utils/.
24 from pylib import android_commands 24 from pylib import android_commands
25 from pylib import cmd_helper 25 from pylib import cmd_helper
26 from pylib import constants
26 27
27 # adb_interface.py is under ../../third_party/android_testrunner/
28 sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..',
29 '..', 'third_party', 'android_testrunner'))
30 import adb_interface
31 import errors 28 import errors
32 import run_command 29 import run_command
33 30
31 # Android API level
32 API_TARGET = 'android-%s' % constants.ANDROID_SDK_VERSION
33
34
34 class EmulatorLaunchException(Exception): 35 class EmulatorLaunchException(Exception):
35 """Emulator failed to launch.""" 36 """Emulator failed to launch."""
36 pass 37 pass
37 38
38 def _KillAllEmulators(): 39 def _KillAllEmulators():
39 """Kill all running emulators that look like ones we started. 40 """Kill all running emulators that look like ones we started.
40 41
41 There are odd 'sticky' cases where there can be no emulator process 42 There are odd 'sticky' cases where there can be no emulator process
42 running but a device slot is taken. A little bot trouble and and 43 running but a device slot is taken. A little bot trouble and and
43 we're out of room forever. 44 we're out of room forever.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 """Returns an available TCP port for the console.""" 95 """Returns an available TCP port for the console."""
95 used_ports = [] 96 used_ports = []
96 emulators = android_commands.GetEmulators() 97 emulators = android_commands.GetEmulators()
97 for emulator in emulators: 98 for emulator in emulators:
98 used_ports.append(emulator.split('-')[1]) 99 used_ports.append(emulator.split('-')[1])
99 for port in PortPool.port_range(): 100 for port in PortPool.port_range():
100 if str(port) not in used_ports: 101 if str(port) not in used_ports:
101 return port 102 return port
102 103
103 104
104 def LaunchEmulators(emulator_count, wait_for_boot=True): 105 def LaunchEmulators(emulator_count, abi, wait_for_boot=True):
105 """Launch multiple emulators and wait for them to boot. 106 """Launch multiple emulators and wait for them to boot.
106 107
107 Args: 108 Args:
108 emulator_count: number of emulators to launch. 109 emulator_count: number of emulators to launch.
110 abi: the emulator target platform
111 wait_for_boot: whether or not to wait for emulators to boot up
109 112
110 Returns: 113 Returns:
111 List of emulators. 114 List of emulators.
112 """ 115 """
113 emulators = [] 116 emulators = []
114 for n in xrange(emulator_count): 117 for n in xrange(emulator_count):
115 t = time_profile.TimeProfile('Emulator launch %d' % n) 118 t = time_profile.TimeProfile('Emulator launch %d' % n)
116 avd_name = None 119 # Creates a temporary AVD.
117 if n > 0: 120 avd_name = 'run_tests_avd_%d' % n
118 # Creates a temporary AVD for the extra emulators.
119 avd_name = 'run_tests_avd_%d' % n
120 logging.info('Emulator launch %d with avd_name=%s', n, avd_name) 121 logging.info('Emulator launch %d with avd_name=%s', n, avd_name)
121 emulator = Emulator(avd_name) 122 emulator = Emulator(avd_name, abi)
122 emulator.Launch(kill_all_emulators=n == 0) 123 emulator.Launch(kill_all_emulators=n == 0)
123 t.Stop() 124 t.Stop()
124 emulators.append(emulator) 125 emulators.append(emulator)
125 # Wait for all emulators to boot completed. 126 # Wait for all emulators to boot completed.
126 if wait_for_boot: 127 if wait_for_boot:
127 for emulator in emulators: 128 for emulator in emulators:
128 emulator.ConfirmLaunch(True) 129 emulator.ConfirmLaunch(True)
129 return emulators 130 return emulators
130 131
131 132
(...skipping 20 matching lines...) Expand all
152 # the time to launch the emulator and a wait-for-device command. 153 # the time to launch the emulator and a wait-for-device command.
153 _LAUNCH_TIMEOUT = 120 154 _LAUNCH_TIMEOUT = 120
154 155
155 # Timeout interval of wait-for-device command before bouncing to a a 156 # Timeout interval of wait-for-device command before bouncing to a a
156 # process life check. 157 # process life check.
157 _WAITFORDEVICE_TIMEOUT = 5 158 _WAITFORDEVICE_TIMEOUT = 5
158 159
159 # Time to wait for a "wait for boot complete" (property set on device). 160 # Time to wait for a "wait for boot complete" (property set on device).
160 _WAITFORBOOT_TIMEOUT = 300 161 _WAITFORBOOT_TIMEOUT = 300
161 162
162 def __init__(self, new_avd_name): 163 def __init__(self, avd_name, abi='x86'):
163 """Init an Emulator. 164 """Init an Emulator.
164 165
165 Args: 166 Args:
166 nwe_avd_name: If set, will create a new temporary AVD. 167 avd_name: name of the AVD to create
168 abi: target platform for emulator being created
167 """ 169 """
168 try: 170 android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT,
169 android_sdk_root = os.environ['ANDROID_SDK_ROOT'] 171 'android_tools', 'sdk')
170 except KeyError:
171 logging.critical('The ANDROID_SDK_ROOT must be set to run the test on '
172 'emulator.')
173 raise
174 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') 172 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator')
175 self.android = os.path.join(android_sdk_root, 'tools', 'android') 173 self.android = os.path.join(android_sdk_root, 'tools', 'android')
176 self.popen = None 174 self.popen = None
177 self.device = None 175 self.device = None
178 self.default_avd = True 176 self.abi = abi
179 self.abi = 'armeabi-v7a' 177 self.avd_name = avd_name
180 self.avd = 'avd_armeabi' 178 self._CreateAVD()
181 if 'x86' in os.environ.get('TARGET_PRODUCT', ''):
182 self.abi = 'x86'
183 self.avd = 'avd_x86'
184 if new_avd_name:
185 self.default_avd = False
186 self.avd = self._CreateAVD(new_avd_name)
187 179
188 def _DeviceName(self): 180 def _DeviceName(self):
189 """Return our device name.""" 181 """Return our device name."""
190 port = _GetAvailablePort() 182 port = _GetAvailablePort()
191 return ('emulator-%d' % port, port) 183 return ('emulator-%d' % port, port)
192 184
193 def _CreateAVD(self, avd_name): 185 def _CreateAVD(self):
194 """Creates an AVD with the given name. 186 """Creates an AVD with the given name.
195 187
196 Return avd_name. 188 Return avd_name.
197 """ 189 """
198 avd_command = [ 190 avd_command = [
199 self.android, 191 self.android,
200 '--silent', 192 '--silent',
201 'create', 'avd', 193 'create', 'avd',
202 '--name', avd_name, 194 '--name', self.avd_name,
203 '--abi', self.abi, 195 '--abi', self.abi,
204 '--target', 'android-16', 196 '--target', API_TARGET,
205 '-c', '128M', 197 '-c', '128M',
206 '--force', 198 '--force',
207 ] 199 ]
208 avd_process = subprocess.Popen(args=avd_command, 200 avd_process = subprocess.Popen(args=avd_command,
209 stdin=subprocess.PIPE, 201 stdin=subprocess.PIPE,
210 stdout=subprocess.PIPE, 202 stdout=subprocess.PIPE,
211 stderr=subprocess.STDOUT) 203 stderr=subprocess.STDOUT)
212 avd_process.stdin.write('no\n') 204 avd_process.stdin.write('no\n')
213 avd_process.wait() 205 avd_process.wait()
214 logging.info('Create AVD command: %s', ' '.join(avd_command)) 206 logging.info('Create AVD command: %s', ' '.join(avd_command))
215 return avd_name 207 return self.avd_name
216 208
217 def _DeleteAVD(self): 209 def _DeleteAVD(self):
218 """Delete the AVD of this emulator.""" 210 """Delete the AVD of this emulator."""
219 avd_command = [ 211 avd_command = [
220 self.android, 212 self.android,
221 '--silent', 213 '--silent',
222 'delete', 214 'delete',
223 'avd', 215 'avd',
224 '--name', self.avd, 216 '--name', self.avd,
225 ] 217 ]
(...skipping 13 matching lines...) Expand all
239 _KillAllEmulators() # just to be sure 231 _KillAllEmulators() # just to be sure
240 self._AggressiveImageCleanup() 232 self._AggressiveImageCleanup()
241 (self.device, port) = self._DeviceName() 233 (self.device, port) = self._DeviceName()
242 emulator_command = [ 234 emulator_command = [
243 self.emulator, 235 self.emulator,
244 # Speed up emulator launch by 40%. Really. 236 # Speed up emulator launch by 40%. Really.
245 '-no-boot-anim', 237 '-no-boot-anim',
246 # The default /data size is 64M. 238 # The default /data size is 64M.
247 # That's not enough for 8 unit test bundles and their data. 239 # That's not enough for 8 unit test bundles and their data.
248 '-partition-size', '512', 240 '-partition-size', '512',
241 # Use a familiar name and port.
242 '-avd', self.avd_name,
243 '-port', str(port),
244 # Wipe the data. We've seen cases where an emulator gets 'stuck' if we
245 # don't do this (every thousand runs or so).
246 '-wipe-data',
249 # Enable GPU by default. 247 # Enable GPU by default.
250 '-gpu', 'on', 248 '-gpu', 'on',
251 # Use a familiar name and port. 249 '-qemu', '-m', '1024',
252 '-avd', self.avd, 250 ]
253 '-port', str(port)] 251 if self.abi == 'x86':
254 emulator_command.extend([ 252 emulator_command.extend([
255 # Wipe the data. We've seen cases where an emulator 253 # For x86 emulator --enable-kvm will fail early, avoiding accidental
256 # gets 'stuck' if we don't do this (every thousand runs or 254 # runs in a slow mode (i.e. without hardware virtualization support).
257 # so). 255 '--enable-kvm',
258 '-wipe-data', 256 ])
259 ]) 257
260 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) 258 logging.info('Emulator launch command: %s', ' '.join(emulator_command))
261 self.popen = subprocess.Popen(args=emulator_command, 259 self.popen = subprocess.Popen(args=emulator_command,
262 stderr=subprocess.STDOUT) 260 stderr=subprocess.STDOUT)
263 self._InstallKillHandler() 261 self._InstallKillHandler()
264 262
265 def _AggressiveImageCleanup(self): 263 def _AggressiveImageCleanup(self):
266 """Aggressive cleanup of emulator images. 264 """Aggressive cleanup of emulator images.
267 265
268 Experimentally it looks like our current emulator use on the bot 266 Experimentally it looks like our current emulator use on the bot
269 leaves image files around in /tmp/android-$USER. If a "random" 267 leaves image files around in /tmp/android-$USER. If a "random"
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 raise EmulatorLaunchException('TIMEOUT with wait-for-device') 308 raise EmulatorLaunchException('TIMEOUT with wait-for-device')
311 logging.info('Seconds waited on wait-for-device: %d', seconds_waited) 309 logging.info('Seconds waited on wait-for-device: %d', seconds_waited)
312 if wait_for_boot: 310 if wait_for_boot:
313 # Now that we checked for obvious problems, wait for a boot complete. 311 # Now that we checked for obvious problems, wait for a boot complete.
314 # Waiting for the package manager is sometimes problematic. 312 # Waiting for the package manager is sometimes problematic.
315 a = android_commands.AndroidCommands(self.device) 313 a = android_commands.AndroidCommands(self.device)
316 a.WaitForSystemBootCompleted(self._WAITFORBOOT_TIMEOUT) 314 a.WaitForSystemBootCompleted(self._WAITFORBOOT_TIMEOUT)
317 315
318 def Shutdown(self): 316 def Shutdown(self):
319 """Shuts down the process started by launch.""" 317 """Shuts down the process started by launch."""
320 if not self.default_avd: 318 self._DeleteAVD()
321 self._DeleteAVD()
322 if self.popen: 319 if self.popen:
323 self.popen.poll() 320 self.popen.poll()
324 if self.popen.returncode == None: 321 if self.popen.returncode == None:
325 self.popen.kill() 322 self.popen.kill()
326 self.popen = None 323 self.popen = None
327 324
328 def _ShutdownOnSignal(self, signum, frame): 325 def _ShutdownOnSignal(self, signum, frame):
329 logging.critical('emulator _ShutdownOnSignal') 326 logging.critical('emulator _ShutdownOnSignal')
330 for sig in self._SIGNALS: 327 for sig in self._SIGNALS:
331 signal.signal(sig, signal.SIG_DFL) 328 signal.signal(sig, signal.SIG_DFL)
332 self.Shutdown() 329 self.Shutdown()
333 raise KeyboardInterrupt # print a stack 330 raise KeyboardInterrupt # print a stack
334 331
335 def _InstallKillHandler(self): 332 def _InstallKillHandler(self):
336 """Install a handler to kill the emulator when we exit unexpectedly.""" 333 """Install a handler to kill the emulator when we exit unexpectedly."""
337 for sig in self._SIGNALS: 334 for sig in self._SIGNALS:
338 signal.signal(sig, self._ShutdownOnSignal) 335 signal.signal(sig, self._ShutdownOnSignal)
OLDNEW
« no previous file with comments | « build/android/pylib/constants.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698