OLD | NEW |
---|---|
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 | 26 |
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 | 27 import errors |
32 import run_command | 28 import run_command |
33 | 29 |
34 class EmulatorLaunchException(Exception): | 30 class EmulatorLaunchException(Exception): |
35 """Emulator failed to launch.""" | 31 """Emulator failed to launch.""" |
36 pass | 32 pass |
37 | 33 |
38 def _KillAllEmulators(): | 34 def _KillAllEmulators(): |
39 """Kill all running emulators that look like ones we started. | 35 """Kill all running emulators that look like ones we started. |
40 | 36 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
94 """Returns an available TCP port for the console.""" | 90 """Returns an available TCP port for the console.""" |
95 used_ports = [] | 91 used_ports = [] |
96 emulators = android_commands.GetEmulators() | 92 emulators = android_commands.GetEmulators() |
97 for emulator in emulators: | 93 for emulator in emulators: |
98 used_ports.append(emulator.split('-')[1]) | 94 used_ports.append(emulator.split('-')[1]) |
99 for port in PortPool.port_range(): | 95 for port in PortPool.port_range(): |
100 if str(port) not in used_ports: | 96 if str(port) not in used_ports: |
101 return port | 97 return port |
102 | 98 |
103 | 99 |
104 def LaunchEmulators(emulator_count, wait_for_boot=True): | 100 def LaunchEmulators(android_sdk_root, emulator_count, abi, wait_for_boot=True): |
105 """Launch multiple emulators and wait for them to boot. | 101 """Launch multiple emulators and wait for them to boot. |
106 | 102 |
107 Args: | 103 Args: |
104 android_sdk_root: location of SDK with the system images installed | |
108 emulator_count: number of emulators to launch. | 105 emulator_count: number of emulators to launch. |
106 abi: the emulator target platform | |
107 wait_for_boot: whether or not to wait for emulators to boot up | |
109 | 108 |
110 Returns: | 109 Returns: |
111 List of emulators. | 110 List of emulators. |
112 """ | 111 """ |
113 emulators = [] | 112 emulators = [] |
113 print 'emulator_count: %s' % emulator_count | |
114 for n in xrange(emulator_count): | 114 for n in xrange(emulator_count): |
115 t = time_profile.TimeProfile('Emulator launch %d' % n) | 115 t = time_profile.TimeProfile('Emulator launch %d' % n) |
116 avd_name = None | 116 # Creates a temporary AVD |
pasko-google - do not use
2013/03/21 12:08:37
nitty nit: full stop at the end of the sentence
navabi
2013/03/26 21:27:30
Done (assuming you mean period at the end of the s
| |
117 if n > 0: | 117 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) | 118 logging.info('Emulator launch %d with avd_name=%s', n, avd_name) |
121 emulator = Emulator(avd_name) | 119 emulator = Emulator(android_sdk_root, avd_name, abi) |
122 emulator.Launch(kill_all_emulators=n == 0) | 120 emulator.Launch(kill_all_emulators=n == 0) |
123 t.Stop() | 121 t.Stop() |
124 emulators.append(emulator) | 122 emulators.append(emulator) |
125 # Wait for all emulators to boot completed. | 123 # Wait for all emulators to boot completed. |
126 if wait_for_boot: | 124 if wait_for_boot: |
127 for emulator in emulators: | 125 for emulator in emulators: |
128 emulator.ConfirmLaunch(True) | 126 emulator.ConfirmLaunch(True) |
129 return emulators | 127 return emulators |
130 | 128 |
131 | 129 |
(...skipping 20 matching lines...) Expand all Loading... | |
152 # the time to launch the emulator and a wait-for-device command. | 150 # the time to launch the emulator and a wait-for-device command. |
153 _LAUNCH_TIMEOUT = 120 | 151 _LAUNCH_TIMEOUT = 120 |
154 | 152 |
155 # Timeout interval of wait-for-device command before bouncing to a a | 153 # Timeout interval of wait-for-device command before bouncing to a a |
156 # process life check. | 154 # process life check. |
157 _WAITFORDEVICE_TIMEOUT = 5 | 155 _WAITFORDEVICE_TIMEOUT = 5 |
158 | 156 |
159 # Time to wait for a "wait for boot complete" (property set on device). | 157 # Time to wait for a "wait for boot complete" (property set on device). |
160 _WAITFORBOOT_TIMEOUT = 300 | 158 _WAITFORBOOT_TIMEOUT = 300 |
161 | 159 |
162 def __init__(self, new_avd_name): | 160 def __init__(self, android_sdk_root, avd_name, abi='x86'): |
163 """Init an Emulator. | 161 """Init an Emulator. |
164 | 162 |
165 Args: | 163 Args: |
166 nwe_avd_name: If set, will create a new temporary AVD. | 164 android_sdk_root: location of SDK with the system images installed |
165 avd_name: name of the AVD to create | |
166 abi: target platform for emulator being created | |
167 """ | 167 """ |
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') | 168 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') |
175 self.android = os.path.join(android_sdk_root, 'tools', 'android') | 169 self.android = os.path.join(android_sdk_root, 'tools', 'android') |
176 self.popen = None | 170 self.popen = None |
177 self.device = None | 171 self.device = None |
178 self.default_avd = True | 172 self.abi = abi |
179 self.abi = 'armeabi-v7a' | 173 self.avd_name = avd_name |
180 self.avd = 'avd_armeabi' | 174 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 | 175 |
188 def _DeviceName(self): | 176 def _DeviceName(self): |
189 """Return our device name.""" | 177 """Return our device name.""" |
190 port = _GetAvailablePort() | 178 port = _GetAvailablePort() |
191 return ('emulator-%d' % port, port) | 179 return ('emulator-%d' % port, port) |
192 | 180 |
193 def _CreateAVD(self, avd_name): | 181 def _CreateAVD(self): |
194 """Creates an AVD with the given name. | 182 """Creates an AVD with the given name. |
195 | 183 |
196 Return avd_name. | 184 Return avd_name. |
197 """ | 185 """ |
186 print 'self.android: ' + self.android | |
198 avd_command = [ | 187 avd_command = [ |
199 self.android, | 188 self.android, |
200 '--silent', | 189 '--silent', |
201 'create', 'avd', | 190 'create', 'avd', |
202 '--name', avd_name, | 191 '--name', self.avd_name, |
203 '--abi', self.abi, | 192 '--abi', self.abi, |
204 '--target', 'android-16', | 193 '--target', 'android-17', |
pasko-google - do not use
2013/03/21 12:08:37
we are repeating 'android-17' here and in install-
navabi
2013/03/26 21:27:30
Done.
| |
205 '-c', '128M', | 194 '-c', '128M', |
206 '--force', | 195 '--force', |
207 ] | 196 ] |
208 avd_process = subprocess.Popen(args=avd_command, | 197 avd_process = subprocess.Popen(args=avd_command, |
209 stdin=subprocess.PIPE, | 198 stdin=subprocess.PIPE, |
210 stdout=subprocess.PIPE, | 199 stdout=subprocess.PIPE, |
211 stderr=subprocess.STDOUT) | 200 stderr=subprocess.STDOUT) |
212 avd_process.stdin.write('no\n') | 201 avd_process.stdin.write('no\n') |
213 avd_process.wait() | 202 avd_process.wait() |
214 logging.info('Create AVD command: %s', ' '.join(avd_command)) | 203 logging.info('Create AVD command: %s', ' '.join(avd_command)) |
215 return avd_name | 204 return self.avd_name |
216 | 205 |
217 def _DeleteAVD(self): | 206 def _DeleteAVD(self): |
218 """Delete the AVD of this emulator.""" | 207 """Delete the AVD of this emulator.""" |
219 avd_command = [ | 208 avd_command = [ |
220 self.android, | 209 self.android, |
221 '--silent', | 210 '--silent', |
222 'delete', | 211 'delete', |
223 'avd', | 212 'avd', |
224 '--name', self.avd, | 213 '--name', self.avd, |
225 ] | 214 ] |
(...skipping 13 matching lines...) Expand all Loading... | |
239 _KillAllEmulators() # just to be sure | 228 _KillAllEmulators() # just to be sure |
240 self._AggressiveImageCleanup() | 229 self._AggressiveImageCleanup() |
241 (self.device, port) = self._DeviceName() | 230 (self.device, port) = self._DeviceName() |
242 emulator_command = [ | 231 emulator_command = [ |
243 self.emulator, | 232 self.emulator, |
244 # Speed up emulator launch by 40%. Really. | 233 # Speed up emulator launch by 40%. Really. |
245 '-no-boot-anim', | 234 '-no-boot-anim', |
246 # The default /data size is 64M. | 235 # The default /data size is 64M. |
247 # That's not enough for 8 unit test bundles and their data. | 236 # That's not enough for 8 unit test bundles and their data. |
248 '-partition-size', '512', | 237 '-partition-size', '512', |
238 # Use a familiar name and port. | |
239 '-avd', self.avd_name, | |
240 '-port', str(port), | |
241 # Wipe the data. We've seen cases where an emulator gets 'stuck' if we | |
242 # don't do this (every thousand runs or so). | |
243 '-wipe-data', | |
249 # Enable GPU by default. | 244 # Enable GPU by default. |
250 '-gpu', 'on', | 245 '-gpu', 'on', |
251 # Use a familiar name and port. | 246 '-qemu', '-m', '1024', |
252 '-avd', self.avd, | 247 ] |
253 '-port', str(port)] | 248 print 'self.abi = %s' % self.abi |
254 emulator_command.extend([ | 249 if self.abi == 'x86': |
255 # Wipe the data. We've seen cases where an emulator | 250 emulator_command.extend([ |
256 # gets 'stuck' if we don't do this (every thousand runs or | 251 # For x86 emulator --enable-kvm will fail early, avoiding accidental |
257 # so). | 252 # runs in a slow mode (i.e. without Intel's virtualization support). |
pasko-google - do not use
2013/03/21 12:08:37
s/Intel's/hardware/
navabi
2013/03/26 21:27:30
Done.
| |
258 '-wipe-data', | 253 '--enable-kvm', |
259 ]) | 254 ]) |
255 | |
260 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) | 256 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) |
261 self.popen = subprocess.Popen(args=emulator_command, | 257 self.popen = subprocess.Popen(args=emulator_command, |
262 stderr=subprocess.STDOUT) | 258 stderr=subprocess.STDOUT) |
263 self._InstallKillHandler() | 259 self._InstallKillHandler() |
264 | 260 |
265 def _AggressiveImageCleanup(self): | 261 def _AggressiveImageCleanup(self): |
266 """Aggressive cleanup of emulator images. | 262 """Aggressive cleanup of emulator images. |
267 | 263 |
268 Experimentally it looks like our current emulator use on the bot | 264 Experimentally it looks like our current emulator use on the bot |
269 leaves image files around in /tmp/android-$USER. If a "random" | 265 leaves image files around in /tmp/android-$USER. If a "random" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 raise EmulatorLaunchException('TIMEOUT with wait-for-device') | 306 raise EmulatorLaunchException('TIMEOUT with wait-for-device') |
311 logging.info('Seconds waited on wait-for-device: %d', seconds_waited) | 307 logging.info('Seconds waited on wait-for-device: %d', seconds_waited) |
312 if wait_for_boot: | 308 if wait_for_boot: |
313 # Now that we checked for obvious problems, wait for a boot complete. | 309 # Now that we checked for obvious problems, wait for a boot complete. |
314 # Waiting for the package manager is sometimes problematic. | 310 # Waiting for the package manager is sometimes problematic. |
315 a = android_commands.AndroidCommands(self.device) | 311 a = android_commands.AndroidCommands(self.device) |
316 a.WaitForSystemBootCompleted(self._WAITFORBOOT_TIMEOUT) | 312 a.WaitForSystemBootCompleted(self._WAITFORBOOT_TIMEOUT) |
317 | 313 |
318 def Shutdown(self): | 314 def Shutdown(self): |
319 """Shuts down the process started by launch.""" | 315 """Shuts down the process started by launch.""" |
320 if not self.default_avd: | 316 if not self.default_avd: |
pasko-google - do not use
2013/03/21 12:08:37
this condition is always true, simplify?
navabi
2013/03/26 21:27:30
Done.
| |
321 self._DeleteAVD() | 317 self._DeleteAVD() |
322 if self.popen: | 318 if self.popen: |
323 self.popen.poll() | 319 self.popen.poll() |
324 if self.popen.returncode == None: | 320 if self.popen.returncode == None: |
325 self.popen.kill() | 321 self.popen.kill() |
326 self.popen = None | 322 self.popen = None |
327 | 323 |
328 def _ShutdownOnSignal(self, signum, frame): | 324 def _ShutdownOnSignal(self, signum, frame): |
329 logging.critical('emulator _ShutdownOnSignal') | 325 logging.critical('emulator _ShutdownOnSignal') |
330 for sig in self._SIGNALS: | 326 for sig in self._SIGNALS: |
331 signal.signal(sig, signal.SIG_DFL) | 327 signal.signal(sig, signal.SIG_DFL) |
332 self.Shutdown() | 328 self.Shutdown() |
333 raise KeyboardInterrupt # print a stack | 329 raise KeyboardInterrupt # print a stack |
334 | 330 |
335 def _InstallKillHandler(self): | 331 def _InstallKillHandler(self): |
336 """Install a handler to kill the emulator when we exit unexpectedly.""" | 332 """Install a handler to kill the emulator when we exit unexpectedly.""" |
337 for sig in self._SIGNALS: | 333 for sig in self._SIGNALS: |
338 signal.signal(sig, self._ShutdownOnSignal) | 334 signal.signal(sig, self._ShutdownOnSignal) |
OLD | NEW |