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' . |
11 """ | 11 """ |
12 | 12 |
13 import logging | 13 import logging |
14 import os | 14 import os |
| 15 import shutil |
15 import signal | 16 import signal |
16 import subprocess | 17 import subprocess |
| 18 import sys |
17 import time | 19 import time |
18 | 20 |
| 21 import time_profile |
19 # TODO(craigdh): Move these pylib dependencies to pylib/utils/. | 22 # TODO(craigdh): Move these pylib dependencies to pylib/utils/. |
20 from pylib import android_commands | 23 from pylib import android_commands |
21 from pylib import cmd_helper | 24 from pylib import cmd_helper |
22 from pylib import constants | 25 from pylib import constants |
23 from pylib import pexpect | 26 from pylib import pexpect |
24 from pylib.utils import time_profile | |
25 | 27 |
26 import errors | 28 import errors |
27 import run_command | 29 import run_command |
28 | 30 |
29 # SD card size | 31 # SD card size |
30 SDCARD_SIZE = '512M' | 32 SDCARD_SIZE = '512M' |
31 | 33 |
32 # Template used to generate config.ini files for the emulator | 34 # Template used to generate config.ini files for the emulator |
33 CONFIG_TEMPLATE = """avd.ini.encoding=ISO-8859-1 | 35 CONFIG_TEMPLATE = """avd.ini.encoding=ISO-8859-1 |
34 hw.dPad=no | 36 hw.dPad=no |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 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 |
90 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 |
91 we're out of room forever. | 93 we're out of room forever. |
92 """ | 94 """ |
93 emulators = android_commands.GetAttachedDevices(hardware=False) | 95 emulators = android_commands.GetAttachedDevices(hardware=False) |
94 if not emulators: | 96 if not emulators: |
95 return | 97 return |
96 for emu_name in emulators: | 98 for emu_name in emulators: |
97 cmd_helper.RunCmd(['adb', '-s', emu_name, 'emu', 'kill']) | 99 cmd_helper.RunCmd(['adb', '-s', emu_name, 'emu', 'kill']) |
98 logging.info('Emulator killing is async; give a few seconds for all to die.') | 100 logging.info('Emulator killing is async; give a few seconds for all to die.') |
99 for _ in range(5): | 101 for i in range(5): |
100 if not android_commands.GetAttachedDevices(hardware=False): | 102 if not android_commands.GetAttachedDevices(hardware=False): |
101 return | 103 return |
102 time.sleep(1) | 104 time.sleep(1) |
103 | 105 |
104 | 106 |
105 def DeleteAllTempAVDs(): | 107 def DeleteAllTempAVDs(): |
106 """Delete all temporary AVDs which are created for tests. | 108 """Delete all temporary AVDs which are created for tests. |
107 | 109 |
108 If the test exits abnormally and some temporary AVDs created when testing may | 110 If the test exits abnormally and some temporary AVDs created when testing may |
109 be left in the system. Clean these AVDs. | 111 be left in the system. Clean these AVDs. |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk') | 222 android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk') |
221 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') | 223 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') |
222 self.android = os.path.join(android_sdk_root, 'tools', 'android') | 224 self.android = os.path.join(android_sdk_root, 'tools', 'android') |
223 self.popen = None | 225 self.popen = None |
224 self.device = None | 226 self.device = None |
225 self.abi = abi | 227 self.abi = abi |
226 self.avd_name = avd_name | 228 self.avd_name = avd_name |
227 self.api_level = api_level | 229 self.api_level = api_level |
228 self._CreateAVD() | 230 self._CreateAVD() |
229 | 231 |
230 @staticmethod | 232 def _DeviceName(self): |
231 def _DeviceName(): | |
232 """Return our device name.""" | 233 """Return our device name.""" |
233 port = _GetAvailablePort() | 234 port = _GetAvailablePort() |
234 return ('emulator-%d' % port, port) | 235 return ('emulator-%d' % port, port) |
235 | 236 |
236 def _CreateAVD(self): | 237 def _CreateAVD(self): |
237 """Creates an AVD with the given name. | 238 """Creates an AVD with the given name. |
238 | 239 |
239 Return avd_name. | 240 Return avd_name. |
240 """ | 241 """ |
241 | 242 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 # For x86 emulator --enable-kvm will fail early, avoiding accidental | 342 # For x86 emulator --enable-kvm will fail early, avoiding accidental |
342 # runs in a slow mode (i.e. without hardware virtualization support). | 343 # runs in a slow mode (i.e. without hardware virtualization support). |
343 '--enable-kvm', | 344 '--enable-kvm', |
344 ]) | 345 ]) |
345 | 346 |
346 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) | 347 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) |
347 self.popen = subprocess.Popen(args=emulator_command, | 348 self.popen = subprocess.Popen(args=emulator_command, |
348 stderr=subprocess.STDOUT) | 349 stderr=subprocess.STDOUT) |
349 self._InstallKillHandler() | 350 self._InstallKillHandler() |
350 | 351 |
351 @staticmethod | 352 def _AggressiveImageCleanup(self): |
352 def _AggressiveImageCleanup(): | |
353 """Aggressive cleanup of emulator images. | 353 """Aggressive cleanup of emulator images. |
354 | 354 |
355 Experimentally it looks like our current emulator use on the bot | 355 Experimentally it looks like our current emulator use on the bot |
356 leaves image files around in /tmp/android-$USER. If a "random" | 356 leaves image files around in /tmp/android-$USER. If a "random" |
357 name gets reused, we choke with a 'File exists' error. | 357 name gets reused, we choke with a 'File exists' error. |
358 TODO(jrg): is there a less hacky way to accomplish the same goal? | 358 TODO(jrg): is there a less hacky way to accomplish the same goal? |
359 """ | 359 """ |
360 logging.info('Aggressive Image Cleanup') | 360 logging.info('Aggressive Image Cleanup') |
361 emulator_imagedir = '/tmp/android-%s' % os.environ['USER'] | 361 emulator_imagedir = '/tmp/android-%s' % os.environ['USER'] |
362 if not os.path.exists(emulator_imagedir): | 362 if not os.path.exists(emulator_imagedir): |
(...skipping 16 matching lines...) Expand all Loading... |
379 number_of_waits = 2 # Make sure we can wfd twice | 379 number_of_waits = 2 # Make sure we can wfd twice |
380 adb_cmd = "adb -s %s %s" % (self.device, 'wait-for-device') | 380 adb_cmd = "adb -s %s %s" % (self.device, 'wait-for-device') |
381 while seconds_waited < self._LAUNCH_TIMEOUT: | 381 while seconds_waited < self._LAUNCH_TIMEOUT: |
382 try: | 382 try: |
383 run_command.RunCommand(adb_cmd, | 383 run_command.RunCommand(adb_cmd, |
384 timeout_time=self._WAITFORDEVICE_TIMEOUT, | 384 timeout_time=self._WAITFORDEVICE_TIMEOUT, |
385 retry_count=1) | 385 retry_count=1) |
386 number_of_waits -= 1 | 386 number_of_waits -= 1 |
387 if not number_of_waits: | 387 if not number_of_waits: |
388 break | 388 break |
389 except errors.WaitForResponseTimedOutError: | 389 except errors.WaitForResponseTimedOutError as e: |
390 seconds_waited += self._WAITFORDEVICE_TIMEOUT | 390 seconds_waited += self._WAITFORDEVICE_TIMEOUT |
391 adb_cmd = "adb -s %s %s" % (self.device, 'kill-server') | 391 adb_cmd = "adb -s %s %s" % (self.device, 'kill-server') |
392 run_command.RunCommand(adb_cmd) | 392 run_command.RunCommand(adb_cmd) |
393 self.popen.poll() | 393 self.popen.poll() |
394 if self.popen.returncode != None: | 394 if self.popen.returncode != None: |
395 raise EmulatorLaunchException('EMULATOR DIED') | 395 raise EmulatorLaunchException('EMULATOR DIED') |
396 if seconds_waited >= self._LAUNCH_TIMEOUT: | 396 if seconds_waited >= self._LAUNCH_TIMEOUT: |
397 raise EmulatorLaunchException('TIMEOUT with wait-for-device') | 397 raise EmulatorLaunchException('TIMEOUT with wait-for-device') |
398 logging.info('Seconds waited on wait-for-device: %d', seconds_waited) | 398 logging.info('Seconds waited on wait-for-device: %d', seconds_waited) |
399 if wait_for_boot: | 399 if wait_for_boot: |
400 # Now that we checked for obvious problems, wait for a boot complete. | 400 # Now that we checked for obvious problems, wait for a boot complete. |
401 # Waiting for the package manager is sometimes problematic. | 401 # Waiting for the package manager is sometimes problematic. |
402 a = android_commands.AndroidCommands(self.device) | 402 a = android_commands.AndroidCommands(self.device) |
403 a.WaitForSystemBootCompleted(self._WAITFORBOOT_TIMEOUT) | 403 a.WaitForSystemBootCompleted(self._WAITFORBOOT_TIMEOUT) |
404 | 404 |
405 def Shutdown(self): | 405 def Shutdown(self): |
406 """Shuts down the process started by launch.""" | 406 """Shuts down the process started by launch.""" |
407 self._DeleteAVD() | 407 self._DeleteAVD() |
408 if self.popen: | 408 if self.popen: |
409 self.popen.poll() | 409 self.popen.poll() |
410 if self.popen.returncode == None: | 410 if self.popen.returncode == None: |
411 self.popen.kill() | 411 self.popen.kill() |
412 self.popen = None | 412 self.popen = None |
413 | 413 |
414 def _ShutdownOnSignal(self, _signum, _frame): | 414 def _ShutdownOnSignal(self, signum, frame): |
415 logging.critical('emulator _ShutdownOnSignal') | 415 logging.critical('emulator _ShutdownOnSignal') |
416 for sig in self._SIGNALS: | 416 for sig in self._SIGNALS: |
417 signal.signal(sig, signal.SIG_DFL) | 417 signal.signal(sig, signal.SIG_DFL) |
418 self.Shutdown() | 418 self.Shutdown() |
419 raise KeyboardInterrupt # print a stack | 419 raise KeyboardInterrupt # print a stack |
420 | 420 |
421 def _InstallKillHandler(self): | 421 def _InstallKillHandler(self): |
422 """Install a handler to kill the emulator when we exit unexpectedly.""" | 422 """Install a handler to kill the emulator when we exit unexpectedly.""" |
423 for sig in self._SIGNALS: | 423 for sig in self._SIGNALS: |
424 signal.signal(sig, self._ShutdownOnSignal) | 424 signal.signal(sig, self._ShutdownOnSignal) |
OLD | NEW |