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

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: Addressed frankf's comments. 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
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(android_sdk_root, 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:
109 android_sdk_root: location of SDK with the system images installed
108 emulator_count: number of emulators to launch. 110 emulator_count: number of emulators to launch.
111 abi: the emulator target platform
112 wait_for_boot: whether or not to wait for emulators to boot up
109 113
110 Returns: 114 Returns:
111 List of emulators. 115 List of emulators.
112 """ 116 """
113 emulators = [] 117 emulators = []
118 print 'emulator_count: %s' % emulator_count
frankf 2013/03/27 05:16:08 we use logging not print in pylib
navabi 2013/03/27 17:13:36 Done. (removed, debugging artifact).
114 for n in xrange(emulator_count): 119 for n in xrange(emulator_count):
115 t = time_profile.TimeProfile('Emulator launch %d' % n) 120 t = time_profile.TimeProfile('Emulator launch %d' % n)
116 avd_name = None 121 # Creates a temporary AVD.
117 if n > 0: 122 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) 123 logging.info('Emulator launch %d with avd_name=%s', n, avd_name)
121 emulator = Emulator(avd_name) 124 emulator = Emulator(android_sdk_root, avd_name, abi)
122 emulator.Launch(kill_all_emulators=n == 0) 125 emulator.Launch(kill_all_emulators=n == 0)
123 t.Stop() 126 t.Stop()
124 emulators.append(emulator) 127 emulators.append(emulator)
125 # Wait for all emulators to boot completed. 128 # Wait for all emulators to boot completed.
126 if wait_for_boot: 129 if wait_for_boot:
127 for emulator in emulators: 130 for emulator in emulators:
128 emulator.ConfirmLaunch(True) 131 emulator.ConfirmLaunch(True)
129 return emulators 132 return emulators
130 133
131 134
(...skipping 20 matching lines...) Expand all
152 # the time to launch the emulator and a wait-for-device command. 155 # the time to launch the emulator and a wait-for-device command.
153 _LAUNCH_TIMEOUT = 120 156 _LAUNCH_TIMEOUT = 120
154 157
155 # Timeout interval of wait-for-device command before bouncing to a a 158 # Timeout interval of wait-for-device command before bouncing to a a
156 # process life check. 159 # process life check.
157 _WAITFORDEVICE_TIMEOUT = 5 160 _WAITFORDEVICE_TIMEOUT = 5
158 161
159 # Time to wait for a "wait for boot complete" (property set on device). 162 # Time to wait for a "wait for boot complete" (property set on device).
160 _WAITFORBOOT_TIMEOUT = 300 163 _WAITFORBOOT_TIMEOUT = 300
161 164
162 def __init__(self, new_avd_name): 165 def __init__(self, android_sdk_root, avd_name, abi='x86'):
163 """Init an Emulator. 166 """Init an Emulator.
164 167
165 Args: 168 Args:
166 nwe_avd_name: If set, will create a new temporary AVD. 169 android_sdk_root: location of SDK with the system images installed
170 avd_name: name of the AVD to create
171 abi: target platform for emulator being created
167 """ 172 """
168 try:
169 android_sdk_root = os.environ['ANDROID_SDK_ROOT']
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') 173 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator')
175 self.android = os.path.join(android_sdk_root, 'tools', 'android') 174 self.android = os.path.join(android_sdk_root, 'tools', 'android')
176 self.popen = None 175 self.popen = None
177 self.device = None 176 self.device = None
178 self.default_avd = True 177 self.abi = abi
179 self.abi = 'armeabi-v7a' 178 self.avd_name = avd_name
180 self.avd = 'avd_armeabi' 179 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 180
188 def _DeviceName(self): 181 def _DeviceName(self):
189 """Return our device name.""" 182 """Return our device name."""
190 port = _GetAvailablePort() 183 port = _GetAvailablePort()
191 return ('emulator-%d' % port, port) 184 return ('emulator-%d' % port, port)
192 185
193 def _CreateAVD(self, avd_name): 186 def _CreateAVD(self):
194 """Creates an AVD with the given name. 187 """Creates an AVD with the given name.
195 188
196 Return avd_name. 189 Return avd_name.
197 """ 190 """
191 print 'self.android: ' + self.android
frankf 2013/03/27 05:16:08 same here. Was this a debugging artifact?
navabi 2013/03/27 17:13:36 Done. (removed, yes it was a debugging artifact).
198 avd_command = [ 192 avd_command = [
199 self.android, 193 self.android,
200 '--silent', 194 '--silent',
201 'create', 'avd', 195 'create', 'avd',
202 '--name', avd_name, 196 '--name', self.avd_name,
203 '--abi', self.abi, 197 '--abi', self.abi,
204 '--target', 'android-16', 198 '--target', API_TARGET,
205 '-c', '128M', 199 '-c', '128M',
206 '--force', 200 '--force',
207 ] 201 ]
208 avd_process = subprocess.Popen(args=avd_command, 202 avd_process = subprocess.Popen(args=avd_command,
209 stdin=subprocess.PIPE, 203 stdin=subprocess.PIPE,
210 stdout=subprocess.PIPE, 204 stdout=subprocess.PIPE,
211 stderr=subprocess.STDOUT) 205 stderr=subprocess.STDOUT)
212 avd_process.stdin.write('no\n') 206 avd_process.stdin.write('no\n')
213 avd_process.wait() 207 avd_process.wait()
214 logging.info('Create AVD command: %s', ' '.join(avd_command)) 208 logging.info('Create AVD command: %s', ' '.join(avd_command))
215 return avd_name 209 return self.avd_name
216 210
217 def _DeleteAVD(self): 211 def _DeleteAVD(self):
218 """Delete the AVD of this emulator.""" 212 """Delete the AVD of this emulator."""
219 avd_command = [ 213 avd_command = [
220 self.android, 214 self.android,
221 '--silent', 215 '--silent',
222 'delete', 216 'delete',
223 'avd', 217 'avd',
224 '--name', self.avd, 218 '--name', self.avd,
225 ] 219 ]
(...skipping 13 matching lines...) Expand all
239 _KillAllEmulators() # just to be sure 233 _KillAllEmulators() # just to be sure
240 self._AggressiveImageCleanup() 234 self._AggressiveImageCleanup()
241 (self.device, port) = self._DeviceName() 235 (self.device, port) = self._DeviceName()
242 emulator_command = [ 236 emulator_command = [
243 self.emulator, 237 self.emulator,
244 # Speed up emulator launch by 40%. Really. 238 # Speed up emulator launch by 40%. Really.
245 '-no-boot-anim', 239 '-no-boot-anim',
246 # The default /data size is 64M. 240 # The default /data size is 64M.
247 # That's not enough for 8 unit test bundles and their data. 241 # That's not enough for 8 unit test bundles and their data.
248 '-partition-size', '512', 242 '-partition-size', '512',
243 # Use a familiar name and port.
244 '-avd', self.avd_name,
245 '-port', str(port),
246 # Wipe the data. We've seen cases where an emulator gets 'stuck' if we
247 # don't do this (every thousand runs or so).
248 '-wipe-data',
249 # Enable GPU by default. 249 # Enable GPU by default.
250 '-gpu', 'on', 250 '-gpu', 'on',
251 # Use a familiar name and port. 251 '-qemu', '-m', '1024',
252 '-avd', self.avd, 252 ]
253 '-port', str(port)] 253 print 'self.abi = %s' % self.abi
frankf 2013/03/27 05:16:08 ditto
navabi 2013/03/27 17:13:36 Done.
254 emulator_command.extend([ 254 if self.abi == 'x86':
255 # Wipe the data. We've seen cases where an emulator 255 emulator_command.extend([
256 # gets 'stuck' if we don't do this (every thousand runs or 256 # For x86 emulator --enable-kvm will fail early, avoiding accidental
257 # so). 257 # runs in a slow mode (i.e. without hardware virtualization support).
258 '-wipe-data', 258 '--enable-kvm',
259 ]) 259 ])
260
260 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) 261 logging.info('Emulator launch command: %s', ' '.join(emulator_command))
261 self.popen = subprocess.Popen(args=emulator_command, 262 self.popen = subprocess.Popen(args=emulator_command,
262 stderr=subprocess.STDOUT) 263 stderr=subprocess.STDOUT)
263 self._InstallKillHandler() 264 self._InstallKillHandler()
264 265
265 def _AggressiveImageCleanup(self): 266 def _AggressiveImageCleanup(self):
266 """Aggressive cleanup of emulator images. 267 """Aggressive cleanup of emulator images.
267 268
268 Experimentally it looks like our current emulator use on the bot 269 Experimentally it looks like our current emulator use on the bot
269 leaves image files around in /tmp/android-$USER. If a "random" 270 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') 311 raise EmulatorLaunchException('TIMEOUT with wait-for-device')
311 logging.info('Seconds waited on wait-for-device: %d', seconds_waited) 312 logging.info('Seconds waited on wait-for-device: %d', seconds_waited)
312 if wait_for_boot: 313 if wait_for_boot:
313 # Now that we checked for obvious problems, wait for a boot complete. 314 # Now that we checked for obvious problems, wait for a boot complete.
314 # Waiting for the package manager is sometimes problematic. 315 # Waiting for the package manager is sometimes problematic.
315 a = android_commands.AndroidCommands(self.device) 316 a = android_commands.AndroidCommands(self.device)
316 a.WaitForSystemBootCompleted(self._WAITFORBOOT_TIMEOUT) 317 a.WaitForSystemBootCompleted(self._WAITFORBOOT_TIMEOUT)
317 318
318 def Shutdown(self): 319 def Shutdown(self):
319 """Shuts down the process started by launch.""" 320 """Shuts down the process started by launch."""
320 if not self.default_avd: 321 self._DeleteAVD()
321 self._DeleteAVD()
322 if self.popen: 322 if self.popen:
323 self.popen.poll() 323 self.popen.poll()
324 if self.popen.returncode == None: 324 if self.popen.returncode == None:
325 self.popen.kill() 325 self.popen.kill()
326 self.popen = None 326 self.popen = None
327 327
328 def _ShutdownOnSignal(self, signum, frame): 328 def _ShutdownOnSignal(self, signum, frame):
329 logging.critical('emulator _ShutdownOnSignal') 329 logging.critical('emulator _ShutdownOnSignal')
330 for sig in self._SIGNALS: 330 for sig in self._SIGNALS:
331 signal.signal(sig, signal.SIG_DFL) 331 signal.signal(sig, signal.SIG_DFL)
332 self.Shutdown() 332 self.Shutdown()
333 raise KeyboardInterrupt # print a stack 333 raise KeyboardInterrupt # print a stack
334 334
335 def _InstallKillHandler(self): 335 def _InstallKillHandler(self):
336 """Install a handler to kill the emulator when we exit unexpectedly.""" 336 """Install a handler to kill the emulator when we exit unexpectedly."""
337 for sig in self._SIGNALS: 337 for sig in self._SIGNALS:
338 signal.signal(sig, self._ShutdownOnSignal) 338 signal.signal(sig, self._ShutdownOnSignal)
OLDNEW
« build/android/install-emulator-deps.py ('K') | « build/android/install-emulator-deps.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698