Add Android emulator support

Add prebuilts and scripts for the Android emulator
and all the required SDK harness.
Also introduces a run_android_emulator script that
sets up the necessary .avd files and starts the
emulator using the configuration files checked in
into //build/android_emulators.
In the next CLs this will be wired up to tests.

Change-Id: I56b7cecaaea48ab5f28682c2f341f443c04b134b
diff --git a/build/android_emulators/arm.ini b/build/android_emulators/arm.ini
new file mode 100644
index 0000000..ee724ae
--- /dev/null
+++ b/build/android_emulators/arm.ini
@@ -0,0 +1,21 @@
+avd.ini.encoding=UTF-8
+abi.type=armeabi-v7a
+disk.dataPartition.size=64M
+hw.accelerometer=no
+hw.audioInput=no
+hw.battery=no
+hw.camera.back=none
+hw.camera.front=none
+hw.cpu.arch=arm
+hw.dPad=no
+hw.gps=no
+hw.keyboard=yes
+hw.lcd.density=480
+hw.mainKeys=no
+hw.ramSize=512
+hw.sdCard=no
+hw.sensors.orientation=yes
+hw.sensors.proximity=yes
+hw.trackBall=no
+image.sysdir.1=system-images/android-24/default/armeabi-v7a/
+vm.heapSize=64
diff --git a/build/android_emulators/arm64.ini b/build/android_emulators/arm64.ini
new file mode 100644
index 0000000..c1d56f8
--- /dev/null
+++ b/build/android_emulators/arm64.ini
@@ -0,0 +1,21 @@
+avd.ini.encoding=UTF-8
+abi.type=arm64-v8a
+disk.dataPartition.size=64M
+hw.accelerometer=no
+hw.audioInput=no
+hw.battery=no
+hw.camera.back=none
+hw.camera.front=none
+hw.cpu.arch=arm64
+hw.dPad=no
+hw.gps=no
+hw.keyboard=yes
+hw.lcd.density=480
+hw.mainKeys=no
+hw.ramSize=512
+hw.sdCard=no
+hw.sensors.orientation=yes
+hw.sensors.proximity=yes
+hw.trackBall=no
+image.sysdir.1=system-images/android-24/default/arm64-v8a/
+vm.heapSize=64
diff --git a/build/install-build-deps b/build/install-build-deps
index 5958ea7..69c7d53 100755
--- a/build/install-build-deps
+++ b/build/install-build-deps
@@ -23,7 +23,10 @@
 import urllib
 import zipfile
 
-PREBUILTS = (
+from collections import namedtuple
+
+# Dependencies required to build code on the host or when targeting desktop OS.
+BUILD_DEPS_HOST = [
   # GN
   ('buildtools/mac/gn',
    'https://storage.googleapis.com/chromium-gn/c2c934d4dda1f470a6511b1015dda9a9fb1ce50b',
@@ -48,6 +51,39 @@
    'linux2'
   ),
 
+  # Keep in sync with Android's //external/googletest/README.version.
+  ('buildtools/googletest.zip',
+   'https://github.com/google/googletest/archive/ff07a5de0e81580547f1685e101194ed1a4fcd56.zip',
+   'c7edec7d7e6db1fc37a20710de9c4d89e3a3893b',
+   'all'
+  ),
+
+  # Keep in sync with Android's //external/protobuf/README.version.
+  ('buildtools/protobuf.zip',
+   'https://github.com/google/protobuf/releases/download/v3.0.0-beta-3/protobuf-cpp-3.0.0-beta-3.zip',
+   '3caec60aa9d8eefc8c3c3201b6b8ca19935edb89',
+   'all'
+  ),
+
+  # libc++ and libc++abi, for clang msan that require rebuilding the C++ lib
+  # from sources. Keep the SHA1s in sync with Chrome's src/buildtools/DEPS.
+  ('buildtools/libcxx',
+   'https://chromium.googlesource.com/chromium/llvm-project/libcxx.git',
+   '3a07dd740be63878167a0ea19fe81869954badd7',
+   'all'
+  ),
+  ('buildtools/libcxxabi',
+   'https://chromium.googlesource.com/chromium/llvm-project/libcxxabi.git',
+   '4072e8fd76febee37f60aeda76d6d9f5e3791daa',
+   'all'
+  ),
+]
+
+# Dependencies required to build Android code.
+# URLs and SHA1s taken from:
+# - https://dl.google.com/android/repository/repository-11.xml
+# - https://dl.google.com/android/repository/sys-img/android/sys-img.xml
+BUILD_DEPS_ANDROID = [
   # Android NDK
   ('buildtools/ndk.zip',
    'https://dl.google.com/android/repository/android-ndk-r15c-darwin-x86_64.zip',
@@ -59,36 +95,46 @@
    '0bf02d4e8b85fd770fd7b9b2cdec57f9441f27a2',
    'linux2'
   ),
+]
 
-  # Keep in sync with Android's //external/googletest/README.version .
-  ('buildtools/googletest.zip',
-   'https://github.com/google/googletest/archive/ff07a5de0e81580547f1685e101194ed1a4fcd56.zip',
-   'c7edec7d7e6db1fc37a20710de9c4d89e3a3893b',
-   'all'
+# Dependencies required to run Android tests.
+TEST_DEPS_ANDROID = [
+  # tools.zip contains the emulator binaries.
+  ('buildtools/android_sdk/tools.zip',
+   'https://dl.google.com/android/repository/tools_r25.2.5-macosx.zip',
+   'd2168d963ac5b616e3d3ddaf21511d084baf3659',
+   'darwin'
+  ),
+  ('buildtools/android_sdk/tools.zip',
+   'https://dl.google.com/android/repository/tools_r25.2.5-linux.zip',
+   '72df3aa1988c0a9003ccdfd7a13a7b8bd0f47fc1',
+   'linux2'
   ),
 
-  # Keep in sync with Android's //external/protobuf/README.version .
-  ('buildtools/protobuf.zip',
-   'https://github.com/google/protobuf/releases/download/v3.0.0-beta-3/protobuf-cpp-3.0.0-beta-3.zip',
-   '3caec60aa9d8eefc8c3c3201b6b8ca19935edb89',
-   'all'
+  # platform-tools.zip contains adb binaries.
+  ('buildtools/android_sdk/platform-tools.zip',
+   'https://dl.google.com/android/repository/platform-tools_r26.0.0-darwin.zip',
+   'e75b6137dc444f777eb02f44a6d9819b3aabff82',
+   'darwin'
+  ),
+  ('buildtools/android_sdk/platform-tools.zip',
+   'https://dl.google.com/android/repository/platform-tools_r26.0.0-linux.zip',
+   '00de8a6631405b617c10f68cd11ff2e1cd528e23',
+   'linux2'
   ),
 
-  # libc++ and libc++abi, for clang msan that require rebuilding the C++ lib
-  # from sources. Keep the SHA1s in sync with Chrome's src/buildtools/DEPS .
-  ('buildtools/libcxx',
-   'https://chromium.googlesource.com/chromium/llvm-project/libcxx.git',
-   '3a07dd740be63878167a0ea19fe81869954badd7',
+  # Android emulator images.
+  ('buildtools/android_sdk/system-images/android-24/default/armeabi-v7a.zip',
+   'https://dl.google.com/android/repository/sys-img/android/armeabi-v7a-24_r07.zip',
+   '3454546b4eed2d6c3dd06d47757d6da9f4176033',
    'all'
   ),
-  ('buildtools/libcxxabi',
-   'https://chromium.googlesource.com/chromium/llvm-project/libcxxabi.git',
-   '4072e8fd76febee37f60aeda76d6d9f5e3791daa',
+  ('buildtools/android_sdk/system-images/android-24/default/arm64-v8a.zip',
+   'https://dl.google.com/android/repository/sys-img/android/arm64-v8a-24_r07.zip',
+   'e8ab2e49e4efe4b064232b33b5eeaded61437d7f',
    'all'
   ),
-
-
-)
+]
 
 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
@@ -143,15 +189,14 @@
 
 def Main():
   parser = argparse.ArgumentParser()
-  parser.add_argument('--skip', action='append', default=[])
+  parser.add_argument('--no-android', action='store_true')
   args = parser.parse_args()
-  skip_set = set(args.skip)
-  for rel_path, url, expected_sha1, platform in PREBUILTS:
+  deps = BUILD_DEPS_HOST
+  if not args.no_android:
+    deps += BUILD_DEPS_ANDROID + TEST_DEPS_ANDROID
+  for rel_path, url, expected_sha1, platform in deps:
     if platform != 'all' and platform != sys.platform:
       continue
-    if os.path.basename(rel_path) in skip_set:
-      logging.info('Skipping %s because of --skip cmdline arg', rel_path)
-      continue
     local_path = os.path.join(ROOT_DIR, rel_path)
     if url.endswith('.git'):
       CheckoutGitRepo(local_path, url, expected_sha1)
diff --git a/build/run_android_emulator b/build/run_android_emulator
new file mode 100755
index 0000000..32f024f
--- /dev/null
+++ b/build/run_android_emulator
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import os
+import shutil
+import sys
+
+
+def Main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--verbose', '-v', action='store_true')
+  parser.add_argument('--pid', help='(optional) save pid into given file')
+  parser.add_argument('image', help='arm|arm64 (see //build/android_emulators)')
+  args = parser.parse_args()
+
+  root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+  ini = os.path.join(root_dir, 'build', 'android_emulators', args.image + '.ini')
+  assert os.path.exists(ini), 'File not found: ' + ini
+
+  avd_dir = os.path.join(root_dir, 'buildtools', 'emulator_images')
+  if not os.path.exists(avd_dir):
+    os.makedirs(avd_dir)
+
+  emu_img_dir = os.path.join(avd_dir, args.image + '.avd')
+  if not os.path.exists(emu_img_dir):
+    os.makedirs(emu_img_dir)
+  shutil.copyfile(ini, os.path.join(emu_img_dir, 'config.ini'))
+
+  with open(os.path.join(avd_dir, args.image + '.ini'), 'w') as f:
+    f.write('path=' + emu_img_dir)
+
+  sdk_dir = os.path.join(root_dir, 'buildtools', 'android_sdk')
+  env = {
+      # Travis CI doesn't set this and causes the emulator to fallback in
+      # 32-bit mode with a "Cannot decide host bitness because $SHELL" error.
+      'SHELL': '/bin/bash',
+      'ANDROID_EMULATOR_DEBUG': '1' if args.verbose else '0',
+      'ANDROID_SDK_ROOT': sdk_dir,
+      'ANDROID_AVD_HOME': avd_dir,
+      'DYLD_LIBRARY_PATH': os.path.join(sdk_dir, 'tools', 'lib64', 'qt', 'lib'),
+  }
+  emulator_bin = os.path.join(sdk_dir, 'tools', 'emulator')
+  emulator_args = ['-no-window', '-no-snapshot',  '-gpu', 'off', '-wipe-data',
+                   '-avd', args.image]
+  print '\n'.join('='.join(x) for x in env.items())
+  print ' '.join([emulator_bin] + emulator_args)
+  if args.pid:
+    with open(args.pid, 'w') as f:
+      f.write(str(os.getpid()))
+  os.execve(emulator_bin, [emulator_bin] + emulator_args, env)
+
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/buildtools/.gitignore b/buildtools/.gitignore
index 79d7ef2..594bce1 100644
--- a/buildtools/.gitignore
+++ b/buildtools/.gitignore
@@ -1,7 +1,9 @@
+android_sdk/
+emulator_images/
 googletest/
+libcxx/
+libcxxabi/
 linux/
 mac/
 ndk/
 protobuf/
-libcxx/
-libcxxabi/