| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Installs deps for using SDK emulator for testing. | 6 """Installs deps for using SDK emulator for testing. |
| 7 | 7 |
| 8 The script will download the SDK and system images, if they are not present, and | 8 The script will download the SDK and system images, if they are not present, and |
| 9 install and enable KVM, if virtualization has been enabled in the BIOS. | 9 install and enable KVM, if virtualization has been enabled in the BIOS. |
| 10 """ | 10 """ |
| 11 | 11 |
| 12 | 12 |
| 13 import logging | 13 import logging |
| 14 import optparse | 14 import optparse |
| 15 import os | 15 import os |
| 16 import re | 16 import re |
| 17 import sys | 17 import sys |
| 18 | 18 |
| 19 from devil.utils import cmd_helper | 19 from devil.utils import cmd_helper |
| 20 from devil.utils import run_tests_helper | 20 from devil.utils import run_tests_helper |
| 21 from pylib import constants | 21 from pylib import constants |
| 22 from pylib import pexpect | 22 from pylib import pexpect |
| 23 | 23 |
| 24 # Android API level | 24 # Android API level |
| 25 DEFAULT_ANDROID_API_LEVEL = constants.ANDROID_SDK_VERSION | 25 DEFAULT_ANDROID_API_LEVEL = constants.ANDROID_SDK_VERSION |
| 26 # Android ABI/Arch |
| 27 DEFAULT_ABI = 'x86' |
| 26 | 28 |
| 27 # Default Time out for downloading SDK component | 29 # Default Time out for downloading SDK component |
| 28 DOWNLOAD_SYSTEM_IMAGE_TIMEOUT = 30 | 30 DOWNLOAD_SYSTEM_IMAGE_TIMEOUT = 30 |
| 29 DOWNLOAD_SDK_PLATFORM_TIMEOUT = 60 | 31 DOWNLOAD_SDK_PLATFORM_TIMEOUT = 60 |
| 30 | 32 |
| 31 def CheckSDK(): | 33 def CheckSDK(): |
| 32 """Check if SDK is already installed. | 34 """Check if SDK is already installed. |
| 33 | 35 |
| 34 Returns: | 36 Returns: |
| 35 True if the emulator SDK directory (src/android_emulator_sdk/) exists. | 37 True if the emulator SDK directory (src/android_emulator_sdk/) exists. |
| 36 """ | 38 """ |
| 37 return os.path.exists(constants.ANDROID_SDK_ROOT) | 39 return os.path.exists(constants.ANDROID_SDK_ROOT) |
| 38 | 40 |
| 39 | 41 |
| 40 def CheckSDKPlatform(api_level=DEFAULT_ANDROID_API_LEVEL): | 42 def CheckSDKPlatform(api_level=DEFAULT_ANDROID_API_LEVEL, google=False): |
| 41 """Check if the "SDK Platform" for the specified API level is installed. | 43 """Check if the "SDK Platform" for the specified API level is installed. |
| 42 This is necessary in order for the emulator to run when the target | 44 This is necessary in order for the emulator to run when the target |
| 43 is specified. | 45 is specified. |
| 44 | 46 |
| 45 Args: | 47 Args: |
| 48 abi: target abi, x86 or arm |
| 46 api_level: the Android API level to check; defaults to the latest API. | 49 api_level: the Android API level to check; defaults to the latest API. |
| 50 google: use Google build system image instead of AOSP build |
| 47 | 51 |
| 48 Returns: | 52 Returns: |
| 49 True if the platform is already installed. | 53 True if the platform is already installed. |
| 50 """ | 54 """ |
| 51 android_binary = os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'android') | 55 android_binary = os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'android') |
| 52 pattern = re.compile('id: [0-9]+ or "android-%d"' % api_level) | 56 if google: |
| 57 pattern = re.compile('id: [0-9]+ or "Google Inc.:Google APIs:%s"' % |
| 58 api_level) |
| 59 else: |
| 60 pattern = re.compile('id: [0-9]+ or "android-%d"' % api_level) |
| 61 |
| 53 try: | 62 try: |
| 54 exit_code, stdout = cmd_helper.GetCmdStatusAndOutput( | 63 exit_code, stdout = cmd_helper.GetCmdStatusAndOutput( |
| 55 [android_binary, 'list']) | 64 [android_binary, 'list']) |
| 56 if exit_code != 0: | 65 if exit_code != 0: |
| 57 raise Exception('\'android list\' command failed') | 66 raise Exception('\'android list\' command failed') |
| 58 for line in stdout.split('\n'): | 67 for line in stdout.split('\n'): |
| 59 if pattern.match(line): | 68 if pattern.match(line): |
| 60 return True | 69 return True |
| 61 return False | 70 return False |
| 62 except OSError: | 71 except OSError: |
| 63 logging.exception('Unable to execute \'android list\'') | 72 logging.exception('Unable to execute \'android list\'') |
| 64 return False | 73 return False |
| 65 | 74 |
| 66 | 75 |
| 67 def CheckX86Image(api_level=DEFAULT_ANDROID_API_LEVEL): | 76 def CheckSystemImage(abi, api_level=DEFAULT_ANDROID_API_LEVEL, google=False): |
| 68 """Check if Android system images have been installed. | 77 """Check if Android system images have been installed. |
| 69 | 78 |
| 70 Args: | 79 Args: |
| 80 abi: target abi, x86 or arm |
| 71 api_level: the Android API level to check for; defaults to the latest API. | 81 api_level: the Android API level to check for; defaults to the latest API. |
| 82 google: use Google build system image instead of AOSP build |
| 72 | 83 |
| 73 Returns: | 84 Returns: |
| 74 True if x86 image has been previously downloaded. | 85 True if x86 image has been previously downloaded. |
| 75 """ | 86 """ |
| 76 api_target = 'android-%d' % api_level | 87 api_target = 'android-%d' % api_level |
| 77 return os.path.exists(os.path.join(constants.ANDROID_SDK_ROOT, | 88 system_image_root = os.path.join(constants.ANDROID_SDK_ROOT, |
| 78 'system-images', api_target, 'default', | 89 'system-images', api_target) |
| 79 'x86')) | 90 if abi == 'x86': |
| 80 | 91 if google: |
| 92 return os.path.exists(os.path.join(system_image_root, 'google_apis', |
| 93 'x86')) |
| 94 else: |
| 95 return os.path.exists(os.path.join(system_image_root, 'default', 'x86')) |
| 96 elif abi == 'arm': |
| 97 if google: |
| 98 return os.path.exists(os.path.join(system_image_root, 'google_apis', |
| 99 'armeabi-v7a')) |
| 100 else: |
| 101 return os.path.exists(os.path.join(system_image_root, 'default', |
| 102 'armeabi-v7a')) |
| 103 else: |
| 104 raise Exception("abi option invalid") |
| 81 | 105 |
| 82 def CheckKVM(): | 106 def CheckKVM(): |
| 83 """Quickly check whether KVM is enabled. | 107 """Quickly check whether KVM is enabled. |
| 84 | 108 |
| 85 Returns: | 109 Returns: |
| 86 True iff /dev/kvm exists (Linux only). | 110 True iff /dev/kvm exists (Linux only). |
| 87 """ | 111 """ |
| 88 return os.path.exists('/dev/kvm') | 112 return os.path.exists('/dev/kvm') |
| 89 | 113 |
| 90 | |
| 91 def RunKvmOk(): | 114 def RunKvmOk(): |
| 92 """Run kvm-ok as root to check that KVM is properly enabled after installation | 115 """Run kvm-ok as root to check that KVM is properly enabled after installation |
| 93 of the required packages. | 116 of the required packages. |
| 94 | 117 |
| 95 Returns: | 118 Returns: |
| 96 True iff KVM is enabled (/dev/kvm exists). On failure, returns False | 119 True iff KVM is enabled (/dev/kvm exists). On failure, returns False |
| 97 but also print detailed information explaining why KVM isn't enabled | 120 but also print detailed information explaining why KVM isn't enabled |
| 98 (e.g. CPU doesn't support it, or BIOS disabled it). | 121 (e.g. CPU doesn't support it, or BIOS disabled it). |
| 99 """ | 122 """ |
| 100 try: | 123 try: |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 update_process.sendline('y') | 182 update_process.sendline('y') |
| 160 if update_process.expect( | 183 if update_process.expect( |
| 161 'Done. 1 package installed.', timeout=timeout) == 0: | 184 'Done. 1 package installed.', timeout=timeout) == 0: |
| 162 logging.info('Successfully installed %s for API level %d', | 185 logging.info('Successfully installed %s for API level %d', |
| 163 package_name, api_level) | 186 package_name, api_level) |
| 164 return | 187 return |
| 165 else: | 188 else: |
| 166 raise Exception('Failed to install platform update') | 189 raise Exception('Failed to install platform update') |
| 167 raise Exception('Could not find android-%d update for the SDK!' % api_level) | 190 raise Exception('Could not find android-%d update for the SDK!' % api_level) |
| 168 | 191 |
| 169 def GetX86Image(api_level=DEFAULT_ANDROID_API_LEVEL): | 192 def GetSystemImage(abi, api_level=DEFAULT_ANDROID_API_LEVEL, google=False): |
| 170 """Download x86 system image from Intel's website. | 193 """Download system image files |
| 171 | 194 |
| 172 Args: | 195 Args: |
| 196 abi: target abi, x86 or arm |
| 173 api_level: the Android API level to download for. | 197 api_level: the Android API level to download for. |
| 198 google: use Google build system image instead of AOSP build |
| 174 """ | 199 """ |
| 175 logging.info('Download x86 system image directory into sdk directory.') | 200 logging.info('Download x86 system image directory into sdk directory.') |
| 176 | 201 |
| 177 x86_package_pattern = re.compile( | 202 if abi == 'x86': |
| 178 r'\s*([0-9]+)- Intel x86 Atom System Image, Android API %d.*' % api_level) | 203 if google: |
| 204 package_name = 'Google Intel x86 Atom System Image' |
| 205 pattern = re.compile( |
| 206 r'\s*([0-9]+)- Google APIs Intel x86 Atom System Image, Google Inc.' |
| 207 ' API %d.*' % api_level) |
| 208 else: |
| 209 package_name = 'Intel x86 system image' |
| 210 pattern = re.compile( |
| 211 r'\s*([0-9]+)- Intel x86 Atom System Image, Android API %d.*' |
| 212 % api_level) |
| 213 elif abi == 'arm': |
| 214 if google: |
| 215 package_name = 'Google arm system image' |
| 216 pattern = re.compile( |
| 217 r'\s*([0-9]+)- Google APIs ARM EABI v7a System Image, Google Inc. API ' |
| 218 '%d.*' % api_level) |
| 219 else: |
| 220 package_name = 'Android arm system image' |
| 221 pattern = re.compile( |
| 222 r'\s*([0-9]+)- ARM EABI v7a System Image, Android API %d.*' % api_level) |
| 223 else: |
| 224 raise Exception('abi option is invalid') |
| 179 | 225 |
| 180 UpdateSDK(api_level, 'x86 system image', x86_package_pattern, | 226 UpdateSDK(api_level, package_name, pattern, DOWNLOAD_SYSTEM_IMAGE_TIMEOUT) |
| 181 DOWNLOAD_SYSTEM_IMAGE_TIMEOUT) | |
| 182 | 227 |
| 183 def GetSDKPlatform(api_level=DEFAULT_ANDROID_API_LEVEL): | 228 def GetSDKPlatform(api_level=DEFAULT_ANDROID_API_LEVEL, google=False): |
| 184 """Update the SDK to include the platform specified. | 229 """Update the SDK to include the platform specified. |
| 185 | 230 |
| 186 Args: | 231 Args: |
| 187 api_level: the Android API level to download | 232 api_level: the Android API level to download |
| 233 google: use Google build system image instead of AOSP build |
| 188 """ | 234 """ |
| 189 logging.info('Download SDK Platform directory into sdk directory.') | 235 logging.info('Download SDK Platform directory into sdk directory.') |
| 190 | 236 |
| 191 platform_package_pattern = re.compile( | 237 platform_package_pattern = re.compile( |
| 192 r'\s*([0-9]+)- SDK Platform Android [\.,0-9]+, API %d.*' % api_level) | 238 r'\s*([0-9]+)- SDK Platform Android [\.,0-9]+, API %d.*' % api_level) |
| 193 | 239 |
| 194 UpdateSDK(api_level, 'SDK Platform', platform_package_pattern, | 240 UpdateSDK(api_level, 'SDK Platform', platform_package_pattern, |
| 195 DOWNLOAD_SDK_PLATFORM_TIMEOUT) | 241 DOWNLOAD_SDK_PLATFORM_TIMEOUT) |
| 196 | 242 |
| 243 if google: |
| 244 google_api_package_pattern = re.compile( |
| 245 r'\s*([0-9]+)- Google APIs, Android API %d.*' % api_level) |
| 246 UpdateSDK(api_level, 'Google APIs', google_api_package_pattern, |
| 247 DOWNLOAD_SDK_PLATFORM_TIMEOUT) |
| 248 |
| 197 | 249 |
| 198 def main(argv): | 250 def main(argv): |
| 199 opt_parser = optparse.OptionParser( | 251 opt_parser = optparse.OptionParser( |
| 200 description='Install dependencies for running the Android emulator') | 252 description='Install dependencies for running the Android emulator') |
| 253 opt_parser.add_option('--abi', |
| 254 dest='abi', |
| 255 help='The targeted abi for emulator system image', |
| 256 type='string', |
| 257 default=DEFAULT_ABI) |
| 201 opt_parser.add_option('--api-level', | 258 opt_parser.add_option('--api-level', |
| 202 dest='api_level', | 259 dest='api_level', |
| 203 help=('The API level (e.g., 19 for Android 4.4) to ' | 260 help=('The API level (e.g., 19 for Android 4.4) to ' |
| 204 'ensure is available'), | 261 'ensure is available'), |
| 205 type='int', | 262 type='int', |
| 206 default=DEFAULT_ANDROID_API_LEVEL) | 263 default=DEFAULT_ANDROID_API_LEVEL) |
| 207 opt_parser.add_option('-v', | 264 opt_parser.add_option('-v', |
| 208 dest='verbosity', | 265 dest='verbosity', |
| 209 default=1, | 266 default=1, |
| 210 action='count', | 267 action='count', |
| 211 help='Verbose level (multiple times for more)') | 268 help='Verbose level (multiple times for more)') |
| 269 opt_parser.add_option('--google', |
| 270 dest='google', |
| 271 action='store_true', |
| 272 default=False, |
| 273 help='Install Google System Image instead of AOSP') |
| 274 |
| 212 options, _ = opt_parser.parse_args(argv[1:]) | 275 options, _ = opt_parser.parse_args(argv[1:]) |
| 213 | 276 |
| 214 run_tests_helper.SetLogLevel(verbose_count=options.verbosity) | 277 run_tests_helper.SetLogLevel(verbose_count=options.verbosity) |
| 215 | 278 |
| 216 # Calls below will download emulator SDK and/or system images only if needed. | 279 # Calls below will download emulator SDK and/or system images only if needed. |
| 217 if CheckSDK(): | 280 if CheckSDK(): |
| 218 logging.info('android_emulator_sdk/ exists') | 281 logging.info('android_emulator_sdk/ exists') |
| 219 else: | 282 else: |
| 220 logging.critical('ERROR: Emulator SDK not installed in %s' | 283 logging.critical('ERROR: Emulator SDK not installed in %s' |
| 221 , constants.ANDROID_SDK_ROOT) | 284 , constants.ANDROID_SDK_ROOT) |
| 222 return 1 | 285 return 1 |
| 223 | 286 |
| 224 # Check target. The target has to be installed in order to run the emulator. | 287 # Check target. The target has to be installed in order to run the emulator. |
| 225 if CheckSDKPlatform(options.api_level): | 288 if CheckSDKPlatform(options.api_level, options.google): |
| 226 logging.info('SDK platform android-%d already present, skipping.', | 289 logging.info('SDK platform %s %s android-%d already present, skipping.', |
| 290 'Google' if options.google else 'AOSP', options.abi, |
| 227 options.api_level) | 291 options.api_level) |
| 228 else: | 292 else: |
| 229 logging.info('SDK platform android-%d not present, installing.', | 293 logging.info('SDK platform %s %s android-%d not present, installing.', |
| 294 'Google' if options.google else 'AOSP', options.abi, |
| 230 options.api_level) | 295 options.api_level) |
| 231 GetSDKPlatform(options.api_level) | 296 GetSDKPlatform(options.api_level, options.google) |
| 232 | 297 |
| 233 # Download the x86 system image only if needed. | 298 # Download the system image needed |
| 234 if CheckX86Image(options.api_level): | 299 if CheckSystemImage(options.abi, options.api_level, options.google): |
| 235 logging.info('x86 image for android-%d already present, skipping.', | 300 logging.info('system image for %s %s android-%d already present, skipping.', |
| 301 'Google' if options.google else 'AOSP', options.abi, |
| 236 options.api_level) | 302 options.api_level) |
| 237 else: | 303 else: |
| 238 GetX86Image(options.api_level) | 304 GetSystemImage(options.abi, options.api_level, options.google) |
| 239 | 305 |
| 240 # Make sure KVM packages are installed and enabled. | 306 # Make sure KVM packages are installed and enabled. |
| 241 if CheckKVM(): | 307 if options.abi == 'x86': |
| 242 logging.info('KVM already installed and enabled.') | 308 if CheckKVM(): |
| 243 else: | 309 logging.info('KVM already installed and enabled.') |
| 244 logging.warning('KVM is not installed or enabled.') | 310 else: |
| 311 logging.warning('KVM is not installed or enabled.') |
| 245 | 312 |
| 246 | 313 |
| 247 if __name__ == '__main__': | 314 if __name__ == '__main__': |
| 248 sys.exit(main(sys.argv)) | 315 sys.exit(main(sys.argv)) |
| OLD | NEW |