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 | |
16 import signal | 15 import signal |
17 import subprocess | 16 import subprocess |
18 import sys | |
19 import time | 17 import time |
20 | 18 |
21 import time_profile | |
22 # TODO(craigdh): Move these pylib dependencies to pylib/utils/. | 19 # TODO(craigdh): Move these pylib dependencies to pylib/utils/. |
23 from pylib import android_commands | 20 from pylib import android_commands |
24 from pylib import cmd_helper | 21 from pylib import cmd_helper |
25 from pylib import constants | 22 from pylib import constants |
26 from pylib import pexpect | 23 from pylib import pexpect |
| 24 from pylib.utils import time_profile |
27 | 25 |
28 import errors | 26 import errors |
29 import run_command | 27 import run_command |
30 | 28 |
31 # SD card size | 29 # SD card size |
32 SDCARD_SIZE = '512M' | 30 SDCARD_SIZE = '512M' |
33 | 31 |
34 # Template used to generate config.ini files for the emulator | 32 # Template used to generate config.ini files for the emulator |
35 CONFIG_TEMPLATE = """avd.ini.encoding=ISO-8859-1 | 33 CONFIG_TEMPLATE = """avd.ini.encoding=ISO-8859-1 |
36 hw.dPad=no | 34 hw.dPad=no |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 There are odd 'sticky' cases where there can be no emulator process | 89 There are odd 'sticky' cases where there can be no emulator process |
92 running but a device slot is taken. A little bot trouble and and | 90 running but a device slot is taken. A little bot trouble and and |
93 we're out of room forever. | 91 we're out of room forever. |
94 """ | 92 """ |
95 emulators = android_commands.GetAttachedDevices(hardware=False) | 93 emulators = android_commands.GetAttachedDevices(hardware=False) |
96 if not emulators: | 94 if not emulators: |
97 return | 95 return |
98 for emu_name in emulators: | 96 for emu_name in emulators: |
99 cmd_helper.RunCmd(['adb', '-s', emu_name, 'emu', 'kill']) | 97 cmd_helper.RunCmd(['adb', '-s', emu_name, 'emu', 'kill']) |
100 logging.info('Emulator killing is async; give a few seconds for all to die.') | 98 logging.info('Emulator killing is async; give a few seconds for all to die.') |
101 for i in range(5): | 99 for _ in range(5): |
102 if not android_commands.GetAttachedDevices(hardware=False): | 100 if not android_commands.GetAttachedDevices(hardware=False): |
103 return | 101 return |
104 time.sleep(1) | 102 time.sleep(1) |
105 | 103 |
106 | 104 |
107 def DeleteAllTempAVDs(): | 105 def DeleteAllTempAVDs(): |
108 """Delete all temporary AVDs which are created for tests. | 106 """Delete all temporary AVDs which are created for tests. |
109 | 107 |
110 If the test exits abnormally and some temporary AVDs created when testing may | 108 If the test exits abnormally and some temporary AVDs created when testing may |
111 be left in the system. Clean these AVDs. | 109 be left in the system. Clean these AVDs. |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk') | 220 android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk') |
223 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') | 221 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') |
224 self.android = os.path.join(android_sdk_root, 'tools', 'android') | 222 self.android = os.path.join(android_sdk_root, 'tools', 'android') |
225 self.popen = None | 223 self.popen = None |
226 self.device = None | 224 self.device = None |
227 self.abi = abi | 225 self.abi = abi |
228 self.avd_name = avd_name | 226 self.avd_name = avd_name |
229 self.api_level = api_level | 227 self.api_level = api_level |
230 self._CreateAVD() | 228 self._CreateAVD() |
231 | 229 |
232 def _DeviceName(self): | 230 @staticmethod |
| 231 def _DeviceName(): |
233 """Return our device name.""" | 232 """Return our device name.""" |
234 port = _GetAvailablePort() | 233 port = _GetAvailablePort() |
235 return ('emulator-%d' % port, port) | 234 return ('emulator-%d' % port, port) |
236 | 235 |
237 def _CreateAVD(self): | 236 def _CreateAVD(self): |
238 """Creates an AVD with the given name. | 237 """Creates an AVD with the given name. |
239 | 238 |
240 Return avd_name. | 239 Return avd_name. |
241 """ | 240 """ |
242 | 241 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 # For x86 emulator --enable-kvm will fail early, avoiding accidental | 341 # For x86 emulator --enable-kvm will fail early, avoiding accidental |
343 # runs in a slow mode (i.e. without hardware virtualization support). | 342 # runs in a slow mode (i.e. without hardware virtualization support). |
344 '--enable-kvm', | 343 '--enable-kvm', |
345 ]) | 344 ]) |
346 | 345 |
347 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) | 346 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) |
348 self.popen = subprocess.Popen(args=emulator_command, | 347 self.popen = subprocess.Popen(args=emulator_command, |
349 stderr=subprocess.STDOUT) | 348 stderr=subprocess.STDOUT) |
350 self._InstallKillHandler() | 349 self._InstallKillHandler() |
351 | 350 |
352 def _AggressiveImageCleanup(self): | 351 @staticmethod |
| 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 as e: | 389 except errors.WaitForResponseTimedOutError: |
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 |