OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Provides an interface to start and stop Android emulator. | 5 """Provides an interface to start and stop Android emulator. |
6 | 6 |
7 Assumes system environment ANDROID_NDK_ROOT has been set. | 7 Assumes system environment ANDROID_NDK_ROOT has been set. |
8 | 8 |
9 Emulator: The class provides the methods to launch/shutdown the emulator with | 9 Emulator: The class provides the methods to launch/shutdown the emulator with |
10 the android virtual device named 'avd_armeabi' . | 10 the android virtual device named 'avd_armeabi' . |
(...skipping 10 matching lines...) Expand all Loading... |
21 import time_profile | 21 import time_profile |
22 # TODO(craigdh): Move these pylib dependencies to pylib/utils/. | 22 # TODO(craigdh): Move these pylib dependencies to pylib/utils/. |
23 from pylib import android_commands | 23 from pylib import android_commands |
24 from pylib import cmd_helper | 24 from pylib import cmd_helper |
25 from pylib import constants | 25 from pylib import constants |
26 from pylib import pexpect | 26 from pylib import pexpect |
27 | 27 |
28 import errors | 28 import errors |
29 import run_command | 29 import run_command |
30 | 30 |
31 # Android API level | |
32 API_TARGET = 'android-%s' % constants.ANDROID_SDK_VERSION | |
33 | |
34 # SD card size | 31 # SD card size |
35 SDCARD_SIZE = '512M' | 32 SDCARD_SIZE = '512M' |
36 | 33 |
| 34 # Template used to generate config.ini files for the emulator |
| 35 CONFIG_TEMPLATE = """avd.ini.encoding=ISO-8859-1 |
| 36 hw.dPad=no |
| 37 hw.lcd.density=320 |
| 38 sdcard.size=512M |
| 39 hw.cpu.arch={hw.cpu.arch} |
| 40 hw.device.hash=-708107041 |
| 41 hw.camera.back=none |
| 42 disk.dataPartition.size=800M |
| 43 hw.gpu.enabled=yes |
| 44 skin.path=720x1280 |
| 45 skin.dynamic=yes |
| 46 hw.keyboard=yes |
| 47 hw.ramSize=1024 |
| 48 hw.device.manufacturer=Google |
| 49 hw.sdCard=yes |
| 50 hw.mainKeys=no |
| 51 hw.accelerometer=yes |
| 52 skin.name=720x1280 |
| 53 abi.type={abi.type} |
| 54 hw.trackBall=no |
| 55 hw.device.name=Galaxy Nexus |
| 56 hw.battery=yes |
| 57 hw.sensors.proximity=yes |
| 58 image.sysdir.1=system-images/android-{api.level}/{abi.type}/ |
| 59 hw.sensors.orientation=yes |
| 60 hw.audioInput=yes |
| 61 hw.camera.front=none |
| 62 hw.gps=yes |
| 63 vm.heapSize=128 |
| 64 {extras}""" |
| 65 |
| 66 CONFIG_REPLACEMENTS = { |
| 67 'x86': { |
| 68 '{hw.cpu.arch}': 'x86', |
| 69 '{abi.type}': 'x86', |
| 70 '{extras}': '' |
| 71 }, |
| 72 'arm': { |
| 73 '{hw.cpu.arch}': 'arm', |
| 74 '{abi.type}': 'armeabi-v7a', |
| 75 '{extras}': 'hw.cpu.model=cortex-a8\n' |
| 76 }, |
| 77 'mips': { |
| 78 '{hw.cpu.arch}': 'mips', |
| 79 '{abi.type}': 'mips', |
| 80 '{extras}': '' |
| 81 } |
| 82 } |
| 83 |
37 class EmulatorLaunchException(Exception): | 84 class EmulatorLaunchException(Exception): |
38 """Emulator failed to launch.""" | 85 """Emulator failed to launch.""" |
39 pass | 86 pass |
40 | 87 |
41 def _KillAllEmulators(): | 88 def _KillAllEmulators(): |
42 """Kill all running emulators that look like ones we started. | 89 """Kill all running emulators that look like ones we started. |
43 | 90 |
44 There are odd 'sticky' cases where there can be no emulator process | 91 There are odd 'sticky' cases where there can be no emulator process |
45 running but a device slot is taken. A little bot trouble and and | 92 running but a device slot is taken. A little bot trouble and and |
46 we're out of room forever. | 93 we're out of room forever. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 """Returns an available TCP port for the console.""" | 144 """Returns an available TCP port for the console.""" |
98 used_ports = [] | 145 used_ports = [] |
99 emulators = android_commands.GetAttachedDevices(hardware=False) | 146 emulators = android_commands.GetAttachedDevices(hardware=False) |
100 for emulator in emulators: | 147 for emulator in emulators: |
101 used_ports.append(emulator.split('-')[1]) | 148 used_ports.append(emulator.split('-')[1]) |
102 for port in PortPool.port_range(): | 149 for port in PortPool.port_range(): |
103 if str(port) not in used_ports: | 150 if str(port) not in used_ports: |
104 return port | 151 return port |
105 | 152 |
106 | 153 |
107 def LaunchEmulators(emulator_count, abi, wait_for_boot=True): | 154 def LaunchEmulators(emulator_count, abi, api_level, wait_for_boot=True): |
108 """Launch multiple emulators and wait for them to boot. | 155 """Launch multiple emulators and wait for them to boot. |
109 | 156 |
110 Args: | 157 Args: |
111 emulator_count: number of emulators to launch. | 158 emulator_count: number of emulators to launch. |
112 abi: the emulator target platform | 159 abi: the emulator target platform |
| 160 api_level: the api level (e.g., 19 for Android v4.4 - KitKat release) |
113 wait_for_boot: whether or not to wait for emulators to boot up | 161 wait_for_boot: whether or not to wait for emulators to boot up |
114 | 162 |
115 Returns: | 163 Returns: |
116 List of emulators. | 164 List of emulators. |
117 """ | 165 """ |
118 emulators = [] | 166 emulators = [] |
119 for n in xrange(emulator_count): | 167 for n in xrange(emulator_count): |
120 t = time_profile.TimeProfile('Emulator launch %d' % n) | 168 t = time_profile.TimeProfile('Emulator launch %d' % n) |
121 # Creates a temporary AVD. | 169 # Creates a temporary AVD. |
122 avd_name = 'run_tests_avd_%d' % n | 170 avd_name = 'run_tests_avd_%d' % n |
123 logging.info('Emulator launch %d with avd_name=%s', n, avd_name) | 171 logging.info('Emulator launch %d with avd_name=%s and api=%d', |
124 emulator = Emulator(avd_name, abi) | 172 n, avd_name, api_level) |
| 173 emulator = Emulator(avd_name, abi, api_level) |
125 emulator.Launch(kill_all_emulators=n == 0) | 174 emulator.Launch(kill_all_emulators=n == 0) |
126 t.Stop() | 175 t.Stop() |
127 emulators.append(emulator) | 176 emulators.append(emulator) |
128 # Wait for all emulators to boot completed. | 177 # Wait for all emulators to boot completed. |
129 if wait_for_boot: | 178 if wait_for_boot: |
130 for emulator in emulators: | 179 for emulator in emulators: |
131 emulator.ConfirmLaunch(True) | 180 emulator.ConfirmLaunch(True) |
132 return emulators | 181 return emulators |
133 | 182 |
134 | 183 |
(...skipping 20 matching lines...) Expand all Loading... |
155 # the time to launch the emulator and a wait-for-device command. | 204 # the time to launch the emulator and a wait-for-device command. |
156 _LAUNCH_TIMEOUT = 120 | 205 _LAUNCH_TIMEOUT = 120 |
157 | 206 |
158 # Timeout interval of wait-for-device command before bouncing to a a | 207 # Timeout interval of wait-for-device command before bouncing to a a |
159 # process life check. | 208 # process life check. |
160 _WAITFORDEVICE_TIMEOUT = 5 | 209 _WAITFORDEVICE_TIMEOUT = 5 |
161 | 210 |
162 # Time to wait for a "wait for boot complete" (property set on device). | 211 # Time to wait for a "wait for boot complete" (property set on device). |
163 _WAITFORBOOT_TIMEOUT = 300 | 212 _WAITFORBOOT_TIMEOUT = 300 |
164 | 213 |
165 def __init__(self, avd_name, abi): | 214 def __init__(self, avd_name, abi, api_level): |
166 """Init an Emulator. | 215 """Init an Emulator. |
167 | 216 |
168 Args: | 217 Args: |
169 avd_name: name of the AVD to create | 218 avd_name: name of the AVD to create |
170 abi: target platform for emulator being created | 219 abi: target platform for emulator being created, defaults to x86 |
| 220 api_level: the api level of the image |
171 """ | 221 """ |
172 android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk') | 222 android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk') |
173 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') | 223 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') |
174 self.android = os.path.join(android_sdk_root, 'tools', 'android') | 224 self.android = os.path.join(android_sdk_root, 'tools', 'android') |
175 self.popen = None | 225 self.popen = None |
176 self.device = None | 226 self.device = None |
177 self.abi = abi | 227 self.abi = abi |
178 self.avd_name = avd_name | 228 self.avd_name = avd_name |
| 229 self.api_level = api_level |
179 self._CreateAVD() | 230 self._CreateAVD() |
180 | 231 |
181 def _DeviceName(self): | 232 def _DeviceName(self): |
182 """Return our device name.""" | 233 """Return our device name.""" |
183 port = _GetAvailablePort() | 234 port = _GetAvailablePort() |
184 return ('emulator-%d' % port, port) | 235 return ('emulator-%d' % port, port) |
185 | 236 |
186 def _CreateAVD(self): | 237 def _CreateAVD(self): |
187 """Creates an AVD with the given name. | 238 """Creates an AVD with the given name. |
188 | 239 |
189 Return avd_name. | 240 Return avd_name. |
190 """ | 241 """ |
191 | 242 |
192 if self.abi == 'arm': | 243 if self.abi == 'arm': |
193 abi_option = 'armeabi-v7a' | 244 abi_option = 'armeabi-v7a' |
| 245 elif self.abi == 'mips': |
| 246 abi_option = 'mips' |
194 else: | 247 else: |
195 abi_option = 'x86' | 248 abi_option = 'x86' |
196 | 249 |
| 250 api_target = 'android-%s' % self.api_level |
| 251 |
197 avd_command = [ | 252 avd_command = [ |
198 self.android, | 253 self.android, |
199 '--silent', | 254 '--silent', |
200 'create', 'avd', | 255 'create', 'avd', |
201 '--name', self.avd_name, | 256 '--name', self.avd_name, |
202 '--abi', abi_option, | 257 '--abi', abi_option, |
203 '--target', API_TARGET, | 258 '--target', api_target, |
204 '--sdcard', SDCARD_SIZE, | 259 '--sdcard', SDCARD_SIZE, |
205 '--force', | 260 '--force', |
206 ] | 261 ] |
207 avd_cmd_str = ' '.join(avd_command) | 262 avd_cmd_str = ' '.join(avd_command) |
208 logging.info('Create AVD command: %s', avd_cmd_str) | 263 logging.info('Create AVD command: %s', avd_cmd_str) |
209 avd_process = pexpect.spawn(avd_cmd_str) | 264 avd_process = pexpect.spawn(avd_cmd_str) |
210 | 265 |
211 # Instead of creating a custom profile, we overwrite config files. | 266 # Instead of creating a custom profile, we overwrite config files. |
212 avd_process.expect('Do you wish to create a custom hardware profile') | 267 avd_process.expect('Do you wish to create a custom hardware profile') |
213 avd_process.sendline('no\n') | 268 avd_process.sendline('no\n') |
214 avd_process.expect('Created AVD \'%s\'' % self.avd_name) | 269 avd_process.expect('Created AVD \'%s\'' % self.avd_name) |
215 | 270 |
216 # Setup test device as default Galaxy Nexus AVD | |
217 avd_config_dir = os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android', | |
218 'avd_configs') | |
219 avd_config_ini = os.path.join(avd_config_dir, | |
220 'AVD_for_Galaxy_Nexus_by_Google_%s.avd' % | |
221 self.abi, 'config.ini') | |
222 | |
223 # Replace current configuration with default Galaxy Nexus config. | 271 # Replace current configuration with default Galaxy Nexus config. |
224 avds_dir = os.path.join(os.path.expanduser('~'), '.android', 'avd') | 272 avds_dir = os.path.join(os.path.expanduser('~'), '.android', 'avd') |
225 ini_file = os.path.join(avds_dir, '%s.ini' % self.avd_name) | 273 ini_file = os.path.join(avds_dir, '%s.ini' % self.avd_name) |
226 new_config_ini = os.path.join(avds_dir, '%s.avd' % self.avd_name, | 274 new_config_ini = os.path.join(avds_dir, '%s.avd' % self.avd_name, |
227 'config.ini') | 275 'config.ini') |
228 | 276 |
229 # Remove config files with defaults to replace with Google's GN settings. | 277 # Remove config files with defaults to replace with Google's GN settings. |
230 os.unlink(ini_file) | 278 os.unlink(ini_file) |
231 os.unlink(new_config_ini) | 279 os.unlink(new_config_ini) |
232 | 280 |
233 # Create new configuration files with Galaxy Nexus by Google settings. | 281 # Create new configuration files with Galaxy Nexus by Google settings. |
234 with open(ini_file, 'w') as new_ini: | 282 with open(ini_file, 'w') as new_ini: |
235 new_ini.write('avd.ini.encoding=ISO-8859-1\n') | 283 new_ini.write('avd.ini.encoding=ISO-8859-1\n') |
236 new_ini.write('target=%s\n' % API_TARGET) | 284 new_ini.write('target=%s\n' % api_target) |
237 new_ini.write('path=%s/%s.avd\n' % (avds_dir, self.avd_name)) | 285 new_ini.write('path=%s/%s.avd\n' % (avds_dir, self.avd_name)) |
238 new_ini.write('path.rel=avd/%s.avd\n' % self.avd_name) | 286 new_ini.write('path.rel=avd/%s.avd\n' % self.avd_name) |
239 | 287 |
240 shutil.copy(avd_config_ini, new_config_ini) | 288 custom_config = CONFIG_TEMPLATE |
| 289 replacements = CONFIG_REPLACEMENTS[self.abi] |
| 290 for key in replacements: |
| 291 custom_config = custom_config.replace(key, replacements[key]) |
| 292 custom_config = custom_config.replace('{api.level}', str(self.api_level)) |
| 293 |
| 294 with open(new_config_ini, 'w') as new_config_ini: |
| 295 new_config_ini.write(custom_config) |
| 296 |
241 return self.avd_name | 297 return self.avd_name |
242 | 298 |
243 | 299 |
244 def _DeleteAVD(self): | 300 def _DeleteAVD(self): |
245 """Delete the AVD of this emulator.""" | 301 """Delete the AVD of this emulator.""" |
246 avd_command = [ | 302 avd_command = [ |
247 self.android, | 303 self.android, |
248 '--silent', | 304 '--silent', |
249 'delete', | 305 'delete', |
250 'avd', | 306 'avd', |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 logging.critical('emulator _ShutdownOnSignal') | 415 logging.critical('emulator _ShutdownOnSignal') |
360 for sig in self._SIGNALS: | 416 for sig in self._SIGNALS: |
361 signal.signal(sig, signal.SIG_DFL) | 417 signal.signal(sig, signal.SIG_DFL) |
362 self.Shutdown() | 418 self.Shutdown() |
363 raise KeyboardInterrupt # print a stack | 419 raise KeyboardInterrupt # print a stack |
364 | 420 |
365 def _InstallKillHandler(self): | 421 def _InstallKillHandler(self): |
366 """Install a handler to kill the emulator when we exit unexpectedly.""" | 422 """Install a handler to kill the emulator when we exit unexpectedly.""" |
367 for sig in self._SIGNALS: | 423 for sig in self._SIGNALS: |
368 signal.signal(sig, self._ShutdownOnSignal) | 424 signal.signal(sig, self._ShutdownOnSignal) |
OLD | NEW |