| 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 |