summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornavabi@google.com <navabi@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-28 00:23:22 +0000
committernavabi@google.com <navabi@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-28 00:23:22 +0000
commit8afcc5a5e98a4c944260dfe3cfbef5a36321466e (patch)
tree62fefab8e635cd64194cd6387bb23bb06cc5db4d
parentb1ba95542aefdb07d07df44f7af1c3ab99fc5301 (diff)
downloadchromium_src-8afcc5a5e98a4c944260dfe3cfbef5a36321466e.zip
chromium_src-8afcc5a5e98a4c944260dfe3cfbef5a36321466e.tar.gz
chromium_src-8afcc5a5e98a4c944260dfe3cfbef5a36321466e.tar.bz2
Add script to download SDK, system images and create and start AVDs for testing.
BUG=164911 Review URL: https://chromiumcodereview.appspot.com/12407004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@191075 0039d316-1c4b-4281-b951-d872f2087c98
-rwxr-xr-xbuild/android/avd.py65
-rwxr-xr-xbuild/android/emulator.py32
-rwxr-xr-xbuild/android/install_emulator_deps.py147
-rw-r--r--build/android/pylib/constants.py2
-rwxr-xr-xbuild/android/pylib/utils/emulator.py81
5 files changed, 253 insertions, 74 deletions
diff --git a/build/android/avd.py b/build/android/avd.py
new file mode 100755
index 0000000..c9da30f
--- /dev/null
+++ b/build/android/avd.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Launches Android Virtual Devices with a set configuration for testing Chrome.
+
+The script will launch a specified number of Android Virtual Devices (AVD's).
+"""
+
+
+import install_emulator_deps
+import logging
+import optparse
+import os
+import subprocess
+import sys
+
+from pylib import constants
+from pylib.utils import emulator
+
+
+def main(argv):
+ # ANDROID_SDK_ROOT needs to be set to the location of the SDK used to launch
+ # the emulator to find the system images upon launch.
+ emulator_sdk = os.path.join(constants.EMULATOR_SDK_ROOT, 'android_tools',
+ 'sdk')
+ os.environ['ANDROID_SDK_ROOT'] = emulator_sdk
+
+ opt_parser = optparse.OptionParser(description='AVD script.')
+ opt_parser.add_option('-n', '--num', dest='emulator_count',
+ help='Number of emulators to launch.',
+ type='int', default='1')
+ opt_parser.add_option('--abi', default='arm',
+ help='Platform of emulators to launch.')
+
+ options, _ = opt_parser.parse_args(argv[1:])
+ if options.abi == 'arm':
+ options.abi = 'armeabi-v7a'
+
+ logging.basicConfig(level=logging.INFO,
+ format='# %(asctime)-15s: %(message)s')
+ logging.root.setLevel(logging.INFO)
+
+ # Check if KVM is enabled for x86 AVD's and check for x86 system images.
+ if options.abi =='x86':
+ if not install_emulator_deps.CheckKVM():
+ logging.critical('ERROR: KVM must be enabled in BIOS, and installed. Run '
+ 'install_emulator_deps.py')
+ return 1
+ elif not install_emulator_deps.CheckX86Image():
+ logging.critical('ERROR: System image for x86 AVD not installed. Run '
+ 'install_emulator_deps.py')
+ return 1
+
+ if not install_emulator_deps.CheckSDK():
+ logging.critical('ERROR: Emulator SDK not installed. Run '
+ 'install_emulator_deps.py.')
+ return 1
+
+ emulator.LaunchEmulators(options.emulator_count, options.abi, True)
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/build/android/emulator.py b/build/android/emulator.py
deleted file mode 100755
index 1c4fb55..0000000
--- a/build/android/emulator.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Script to launch Android emulators.
-
-Assumes system environment ANDROID_NDK_ROOT has been set.
-"""
-
-import optparse
-import sys
-
-from pylib.utils import emulator
-
-
-def main(argv):
- option_parser = optparse.OptionParser()
- option_parser.add_option('-n', '--num', dest='emulator_count',
- help='Number of emulators to launch.',
- type='int',
- default=1)
- option_parser.add_option('-w', '--wait', dest='wait_for_boot',
- action='store_true',
- help='If set, wait for the emulators to boot.')
- options, args = option_parser.parse_args(argv)
- emulator.LaunchEmulators(options.emulator_count, options.wait_for_boot)
-
-
-if __name__ == '__main__':
- main(sys.argv)
diff --git a/build/android/install_emulator_deps.py b/build/android/install_emulator_deps.py
new file mode 100755
index 0000000..ff84367
--- /dev/null
+++ b/build/android/install_emulator_deps.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Installs deps for using SDK emulator for testing.
+
+The script will download the SDK and system images, if they are not present, and
+install and enable KVM, if virtualization has been enabled in the BIOS.
+"""
+
+
+import logging
+import os
+import shutil
+import subprocess
+import sys
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.utils import run_tests_helper
+
+# From the Android Developer's website.
+SDK_BASE_URL = 'http://dl.google.com/android/adt'
+SDK_ZIP = 'adt-bundle-linux-x86_64-20130219.zip'
+
+# Android x86 system image from the Intel website:
+# http://software.intel.com/en-us/articles/intel-eula-x86-android-4-2-jelly-bean-bin
+X86_IMG_URL = 'http://download-software.intel.com/sites/landingpage/android/sysimg_x86-17_r01.zip'
+
+# Android API level
+API_TARGET = 'android-%s' % constants.ANDROID_SDK_VERSION
+
+
+def CheckSDK():
+ """Check if SDK is already installed.
+
+ Returns:
+ True if android_tools directory exists in current directory.
+ """
+ return os.path.exists(os.path.join(constants.EMULATOR_SDK_ROOT,
+ 'android_tools'))
+
+
+def CheckX86Image():
+ """Check if Android system images have been installed.
+
+ Returns:
+ True if android_tools/sdk/system-images directory exists.
+ """
+ return os.path.exists(os.path.join(constants.EMULATOR_SDK_ROOT,
+ 'android_tools', 'sdk', 'system-images',
+ API_TARGET, 'x86'))
+
+
+def CheckKVM():
+ """Check if KVM is enabled.
+
+ Returns:
+ True if kvm-ok returns 0 (already enabled)
+ """
+ rc = cmd_helper.RunCmd(['kvm-ok'])
+ return not rc
+
+
+def GetSDK():
+ """Download the SDK and unzip in android_tools directory."""
+ logging.info('Download Android SDK.')
+ sdk_url = '%s/%s' % (SDK_BASE_URL, SDK_ZIP)
+ try:
+ cmd_helper.RunCmd(['curl', '-o', '/tmp/sdk.zip', sdk_url])
+ print 'curled unzipping...'
+ rc = cmd_helper.RunCmd(['unzip', '-o', '/tmp/sdk.zip', '-d', '/tmp/'])
+ if rc:
+ logging.critical('ERROR: could not download/unzip Android SDK.')
+ raise
+ # Get the name of the sub-directory that everything will be extracted to.
+ dirname, _ = os.path.splitext(SDK_ZIP)
+ zip_dir = '/tmp/%s' % dirname
+ # Move the extracted directory to EMULATOR_SDK_ROOT
+ dst = os.path.join(constants.EMULATOR_SDK_ROOT, 'android_tools')
+ shutil.move(zip_dir, dst)
+ finally:
+ os.unlink('/tmp/sdk.zip')
+
+
+def InstallKVM():
+ """Installs KVM packages."""
+ rc = cmd_helper.RunCmd(['sudo', 'apt-get', 'install', 'kvm'])
+ if rc:
+ logging.critical('ERROR: Did not install KVM. Make sure hardware '
+ 'virtualization is enabled in BIOS (i.e. Intel VT-x or '
+ 'AMD SVM).')
+ # TODO(navabi): Use modprobe kvm-amd on AMD processors.
+ rc = cmd_helper.RunCmd(['sudo', 'modprobe', 'kvm-intel'])
+ if rc:
+ logging.critical('ERROR: Did not add KVM module to Linux Kernal. Make sure '
+ 'hardware virtualization is enabled in BIOS.')
+ # Now check to ensure KVM acceleration can be used.
+ rc = cmd_helper.RunCmd(['kvm-ok'])
+ if rc:
+ logging.critical('ERROR: Can not use KVM acceleration. Make sure hardware '
+ 'virtualization is enabled in BIOS (i.e. Intel VT-x or '
+ 'AMD SVM).')
+
+
+def GetX86Image():
+ """Download x86 system image from Intel's website."""
+ logging.info('Download x86 system image directory into sdk directory.')
+ try:
+ cmd_helper.RunCmd(['curl', '-o', '/tmp/x86_img.zip', X86_IMG_URL])
+ rc = cmd_helper.RunCmd(['unzip', '-o', '/tmp/x86_img.zip', '-d', '/tmp/'])
+ if rc:
+ logging.critical('ERROR: Could not download/unzip image zip.')
+ raise
+ sys_imgs = os.path.join(constants.EMULATOR_SDK_ROOT, 'android_tools', 'sdk',
+ 'system-images', API_TARGET, 'x86')
+ shutil.move('/tmp/x86', sys_imgs)
+ finally:
+ os.unlink('/tmp/x86_img.zip')
+
+
+def main(argv):
+ logging.basicConfig(level=logging.INFO,
+ format='# %(asctime)-15s: %(message)s')
+ run_tests_helper.SetLogLevel(verbose_count=1)
+
+ # Calls below will download emulator SDK and/or system images only if needed.
+ if CheckSDK():
+ logging.info('android_tools directory already exists (not downloading).')
+ else:
+ GetSDK()
+
+ if CheckX86Image():
+ logging.info('system-images directory already exists.')
+ else:
+ GetX86Image()
+
+ # Make sure KVM packages are installed and enabled.
+ if CheckKVM():
+ logging.info('KVM already installed and enabled.')
+ else:
+ InstallKVM()
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/build/android/pylib/constants.py b/build/android/pylib/constants.py
index 7e001c9..4b2413e 100644
--- a/build/android/pylib/constants.py
+++ b/build/android/pylib/constants.py
@@ -9,6 +9,8 @@ import os
CHROME_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir, os.pardir))
+EMULATOR_SDK_ROOT = os.path.abspath(os.path.join(CHROME_DIR, os.pardir,
+ os.pardir))
CHROME_PACKAGE = 'com.google.android.apps.chrome'
CHROME_ACTIVITY = 'com.google.android.apps.chrome.Main'
diff --git a/build/android/pylib/utils/emulator.py b/build/android/pylib/utils/emulator.py
index 70afffb..df77c52 100755
--- a/build/android/pylib/utils/emulator.py
+++ b/build/android/pylib/utils/emulator.py
@@ -23,14 +23,15 @@ import time_profile
# TODO(craigdh): Move these pylib dependencies to pylib/utils/.
from pylib import android_commands
from pylib import cmd_helper
+from pylib import constants
-# adb_interface.py is under ../../third_party/android_testrunner/
-sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..',
- '..', 'third_party', 'android_testrunner'))
-import adb_interface
import errors
import run_command
+# Android API level
+API_TARGET = 'android-%s' % constants.ANDROID_SDK_VERSION
+
+
class EmulatorLaunchException(Exception):
"""Emulator failed to launch."""
pass
@@ -101,11 +102,13 @@ def _GetAvailablePort():
return port
-def LaunchEmulators(emulator_count, wait_for_boot=True):
+def LaunchEmulators(emulator_count, abi, wait_for_boot=True):
"""Launch multiple emulators and wait for them to boot.
Args:
emulator_count: number of emulators to launch.
+ abi: the emulator target platform
+ wait_for_boot: whether or not to wait for emulators to boot up
Returns:
List of emulators.
@@ -113,12 +116,10 @@ def LaunchEmulators(emulator_count, wait_for_boot=True):
emulators = []
for n in xrange(emulator_count):
t = time_profile.TimeProfile('Emulator launch %d' % n)
- avd_name = None
- if n > 0:
- # Creates a temporary AVD for the extra emulators.
- avd_name = 'run_tests_avd_%d' % n
+ # Creates a temporary AVD.
+ avd_name = 'run_tests_avd_%d' % n
logging.info('Emulator launch %d with avd_name=%s', n, avd_name)
- emulator = Emulator(avd_name)
+ emulator = Emulator(avd_name, abi)
emulator.Launch(kill_all_emulators=n == 0)
t.Stop()
emulators.append(emulator)
@@ -159,38 +160,29 @@ class Emulator(object):
# Time to wait for a "wait for boot complete" (property set on device).
_WAITFORBOOT_TIMEOUT = 300
- def __init__(self, new_avd_name):
+ def __init__(self, avd_name, abi='x86'):
"""Init an Emulator.
Args:
- nwe_avd_name: If set, will create a new temporary AVD.
+ avd_name: name of the AVD to create
+ abi: target platform for emulator being created
"""
- try:
- android_sdk_root = os.environ['ANDROID_SDK_ROOT']
- except KeyError:
- logging.critical('The ANDROID_SDK_ROOT must be set to run the test on '
- 'emulator.')
- raise
+ android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT,
+ 'android_tools', 'sdk')
self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator')
self.android = os.path.join(android_sdk_root, 'tools', 'android')
self.popen = None
self.device = None
- self.default_avd = True
- self.abi = 'armeabi-v7a'
- self.avd = 'avd_armeabi'
- if 'x86' in os.environ.get('TARGET_PRODUCT', ''):
- self.abi = 'x86'
- self.avd = 'avd_x86'
- if new_avd_name:
- self.default_avd = False
- self.avd = self._CreateAVD(new_avd_name)
+ self.abi = abi
+ self.avd_name = avd_name
+ self._CreateAVD()
def _DeviceName(self):
"""Return our device name."""
port = _GetAvailablePort()
return ('emulator-%d' % port, port)
- def _CreateAVD(self, avd_name):
+ def _CreateAVD(self):
"""Creates an AVD with the given name.
Return avd_name.
@@ -199,9 +191,9 @@ class Emulator(object):
self.android,
'--silent',
'create', 'avd',
- '--name', avd_name,
+ '--name', self.avd_name,
'--abi', self.abi,
- '--target', 'android-16',
+ '--target', API_TARGET,
'-c', '128M',
'--force',
]
@@ -212,7 +204,7 @@ class Emulator(object):
avd_process.stdin.write('no\n')
avd_process.wait()
logging.info('Create AVD command: %s', ' '.join(avd_command))
- return avd_name
+ return self.avd_name
def _DeleteAVD(self):
"""Delete the AVD of this emulator."""
@@ -246,17 +238,23 @@ class Emulator(object):
# The default /data size is 64M.
# That's not enough for 8 unit test bundles and their data.
'-partition-size', '512',
- # Enable GPU by default.
- '-gpu', 'on',
# Use a familiar name and port.
- '-avd', self.avd,
- '-port', str(port)]
- emulator_command.extend([
- # Wipe the data. We've seen cases where an emulator
- # gets 'stuck' if we don't do this (every thousand runs or
- # so).
+ '-avd', self.avd_name,
+ '-port', str(port),
+ # Wipe the data. We've seen cases where an emulator gets 'stuck' if we
+ # don't do this (every thousand runs or so).
'-wipe-data',
- ])
+ # Enable GPU by default.
+ '-gpu', 'on',
+ '-qemu', '-m', '1024',
+ ]
+ if self.abi == 'x86':
+ emulator_command.extend([
+ # For x86 emulator --enable-kvm will fail early, avoiding accidental
+ # runs in a slow mode (i.e. without hardware virtualization support).
+ '--enable-kvm',
+ ])
+
logging.info('Emulator launch command: %s', ' '.join(emulator_command))
self.popen = subprocess.Popen(args=emulator_command,
stderr=subprocess.STDOUT)
@@ -317,8 +315,7 @@ class Emulator(object):
def Shutdown(self):
"""Shuts down the process started by launch."""
- if not self.default_avd:
- self._DeleteAVD()
+ self._DeleteAVD()
if self.popen:
self.popen.poll()
if self.popen.returncode == None: