build: support newer Android NDK versions

- Update build.rs to support recent NDK (19 or later) build instruction.
- You can still get previous NDK support using `--features ndk-old-gcc`.
- build_android_ndk19.sh is an example script to build using NDK >= 19.
- travis: android build will try both way.
diff --git a/.travis.yml b/.travis.yml
index c6dbc49..9ad50bc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -120,7 +120,8 @@
      language: android
      dist: trusty
      env:
-       NDK_VER=r13b
+       NDK_VER_OLD=r13b
+       NDK_VER=r21
        CMAKE_VER=3.6.4111459
      android:
        components:
@@ -136,17 +137,29 @@
       # Additional Android components
       - echo y | sdkmanager "cmake;$CMAKE_VER"
       - export PATH=$ANDROID_HOME/cmake/$CMAKE_VER/bin/:$PATH
-      # NDK download and install
+     script:
+      #
+      # Old NDK. Here we use 13b
+      #
       - NDK_URL=https://dl.google.com/android/repository/android-ndk-%s-linux-x86_64.zip
-      - curl -ondk.zip -q $(printf $NDK_URL $NDK_VER)
+      - curl -ondk.zip -q $(printf $NDK_URL $NDK_VER_OLD)
       - unzip -q ndk.zip -d $HOME
-      - export ANDROID_NDK_HOME=$HOME/android-ndk-$NDK_VER
+      - export ANDROID_NDK_HOME=$HOME/android-ndk-$NDK_VER_OLD
       # Setup android toolchain
       - export TOOLCHAIN_DIR=$(pwd)/toolchain
       - mkdir -p $TOOLCHAIN_DIR
       - tools/setup_android.sh
-     script:
-      - tools/build_android.sh --verbose
+      - tools/build_android.sh --verbose --features ndk-old-gcc
+      - rm -fr $TOOLCHAIN_DIR && rm -f .cargo/config
+      #
+      # NDK 19 or higher. Here we use 21 (long term support)
+      #
+      - curl -ondk.zip -q $(printf $NDK_URL $NDK_VER)
+      - unzip -q ndk.zip -d $HOME
+      - export ANDROID_NDK_HOME=$HOME/android-ndk-$NDK_VER
+      - cargo install cargo-ndk
+      - cargo clean
+      - tools/build_android_ndk19.sh --verbose
    - name: "NGINX"
      language: rust
      rust: stable
diff --git a/Cargo.toml b/Cargo.toml
index a1e815e..b4ca6ec 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -43,6 +43,9 @@
 # Equivalent to "--cfg fuzzing", but can also be checked in build.rs.
 fuzzing = []
 
+# For building with Android NDK < 18 and GCC.
+ndk-old-gcc = []
+
 [package.metadata.docs.rs]
 default-features = false
 
diff --git a/README.md b/README.md
index 6955b21..1b7d328 100644
--- a/README.md
+++ b/README.md
@@ -250,20 +250,53 @@
 
 To build quiche for Android, you need the following:
 
-- Install Android NDK (13b or higher), using Android Studio or directly.
-- Set `ANDROID_NDK_HOME` environment variable to NDK path, e.g. using bash:
+- Install the [Android NDK] (13b or higher), using Android Studio or directly.
+- Set `ANDROID_NDK_HOME` environment variable to NDK path, e.g.
 
 ```bash
  $ export ANDROID_NDK_HOME=/usr/local/share/android-ndk
 ```
 
-- Install the Rust toolchain for Android architectures:
+- Install the Rust toolchain for Android architectures needed:
 
 ```bash
- $ rustup target add aarch64-linux-android arm-linux-androideabi armv7-linux-androideabi i686-linux-android
+ $ rustup target add aarch64-linux-android arm-linux-androideabi armv7-linux-androideabi i686-linux-android x86_64-linux-android
 ```
 
-Then, to prepare the cross-compiling toolchain, run the following command:
+Note that the minimum API level is 21 for all target architectures.
+
+Depending on the NDK version used, you can take one of the following procedures:
+
+[Android NDK]: https://developer.android.com/ndk
+
+#### NDK version >= 19
+
+For NDK version 19 or higher (21 recommended), you can build in a simpler
+way using [cargo-ndk]. You need to install [cargo-ndk] first.
+
+```bash
+ $ cargo install cargo-ndk
+```
+
+You can build the quiche library using the following procedure. Note that
+`--target` and `--android-platform` are mandatory.
+
+```bash
+ $ cargo ndk --target aarch64-linux-android --android-platform 21 -- build
+```
+
+See [build_android_ndk19.sh] for more information.
+
+Note that building with NDK version 18 appears to be broken.
+
+[cargo-ndk]: https://docs.rs/crate/cargo-ndk
+[build_android_ndk19.sh]: https://github.com/cloudflare/quiche/blob/master/tools/build_android_ndk19.sh
+
+#### NDK version < 18
+
+If you need to use NDK version < 18 (gcc), you can build quiche in the following way.
+
+To prepare the cross-compiling toolchain, run the following command:
 
 ```bash
  $ tools/setup_android.sh
@@ -271,13 +304,12 @@
 
 It will create a standalone toolchain for arm64/arm/x86 architectures under the
 `$TOOLCHAIN_DIR/arch` directory. If you didn't set `TOOLCHAIN_DIR` environment
-variable, the current directory will be used. Note that the minimum API level is
-21 for all target architectures.
+variable, the current directory will be used.
 
 After it run successfully, run the following script to build libquiche:
 
 ```bash
- $ tools/build_android.sh
+ $ tools/build_android.sh --features ndk-old-gcc
 ```
 
 It will build binaries for aarch64, armv7 and i686. You can pass parameters to
@@ -285,7 +317,7 @@
 with verbose logs, do the following:
 
 ```bash
- $ tools/build_android.sh --release -vv
+ $ tools/build_android.sh --features ndk-old-gcc --release -vv
 ```
 
 ### Building for iOS
diff --git a/src/build.rs b/src/build.rs
index bd7872e..b76fba4 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -1,41 +1,31 @@
 // Additional parameters for Android build of BoringSSL.
-const CMAKE_PARAMS_ANDROID: &[(&str, &[(&str, &str)])] = &[
-    ("aarch64", &[
-        ("ANDROID_TOOLCHAIN_NAME", "aarch64-linux-android-4.9"),
-        ("ANDROID_NATIVE_API_LEVEL", "21"),
-        (
-            "CMAKE_TOOLCHAIN_FILE",
-            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
-        ),
-        ("ANDROID_STL", "c++_shared"),
-    ]),
-    ("arm", &[
-        ("ANDROID_TOOLCHAIN_NAME", "arm-linux-androideabi-4.9"),
-        ("ANDROID_NATIVE_API_LEVEL", "21"),
-        (
-            "CMAKE_TOOLCHAIN_FILE",
-            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
-        ),
-        ("ANDROID_STL", "c++_shared"),
-    ]),
-    ("x86", &[
-        ("ANDROID_TOOLCHAIN_NAME", "x86-linux-android-4.9"),
-        ("ANDROID_NATIVE_API_LEVEL", "21"),
-        (
-            "CMAKE_TOOLCHAIN_FILE",
-            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
-        ),
-        ("ANDROID_STL", "c++_shared"),
-    ]),
-    ("x86_64", &[
-        ("ANDROID_TOOLCHAIN_NAME", "x86_64-linux-android-4.9"),
-        ("ANDROID_NATIVE_API_LEVEL", "21"),
-        (
-            "CMAKE_TOOLCHAIN_FILE",
-            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
-        ),
-        ("ANDROID_STL", "c++_shared"),
-    ]),
+//
+// Android NDK < 18 with GCC.
+const CMAKE_PARAMS_ANDROID_NDK_OLD_GCC: &[(&str, &[(&str, &str)])] = &[
+    ("aarch64", &[(
+        "ANDROID_TOOLCHAIN_NAME",
+        "aarch64-linux-android-4.9",
+    )]),
+    ("arm", &[(
+        "ANDROID_TOOLCHAIN_NAME",
+        "arm-linux-androideabi-4.9",
+    )]),
+    ("x86", &[(
+        "ANDROID_TOOLCHAIN_NAME",
+        "x86-linux-android-4.9",
+    )]),
+    ("x86_64", &[(
+        "ANDROID_TOOLCHAIN_NAME",
+        "x86_64-linux-android-4.9",
+    )]),
+];
+
+// Android NDK >= 19.
+const CMAKE_PARAMS_ANDROID_NDK: &[(&str, &[(&str, &str)])] = &[
+    ("aarch64", &[("ANDROID_ABI", "arm64-v8a")]),
+    ("arm", &[("ANDROID_ABI", "armeabi-v7a")]),
+    ("x86", &[("ANDROID_ABI", "x86")]),
+    ("x86_64", &[("ANDROID_ABI", "x86_64")]),
 ];
 
 const CMAKE_PARAMS_IOS: &[(&str, &[(&str, &str)])] = &[
@@ -87,19 +77,32 @@
     // Add platform-specific parameters.
     return match os.as_ref() {
         "android" => {
+            let mut cmake_params_android = CMAKE_PARAMS_ANDROID_NDK;
+            if cfg!(feature = "ndk-old-gcc") {
+                cmake_params_android = CMAKE_PARAMS_ANDROID_NDK_OLD_GCC;
+            }
+
             // We need ANDROID_NDK_HOME to be set properly.
             let android_ndk_home = std::env::var("ANDROID_NDK_HOME")
                 .expect("Please set ANDROID_NDK_HOME for Android build");
-            for (android_arch, params) in CMAKE_PARAMS_ANDROID {
+            let android_ndk_home = std::path::Path::new(&android_ndk_home);
+            for (android_arch, params) in cmake_params_android {
                 if *android_arch == arch {
                     for (name, value) in *params {
-                        let value = value
-                            .replace("${ANDROID_NDK_HOME}", &android_ndk_home);
                         eprintln!("android arch={} add {}={}", arch, name, value);
                         boringssl_cmake.define(name, value);
                     }
                 }
             }
+            let toolchain_file =
+                android_ndk_home.join("build/cmake/android.toolchain.cmake");
+            let toolchain_file = toolchain_file.to_str().unwrap();
+            eprintln!("android toolchain={}", toolchain_file);
+            boringssl_cmake.define("CMAKE_TOOLCHAIN_FILE", toolchain_file);
+
+            // 21 is the minimum level tested. You can give higher value.
+            boringssl_cmake.define("ANDROID_NATIVE_API_LEVEL", "21");
+            boringssl_cmake.define("ANDROID_STL", "c++_shared");
 
             boringssl_cmake
         },
diff --git a/tools/build_android_ndk19.sh b/tools/build_android_ndk19.sh
new file mode 100755
index 0000000..aff1dec
--- /dev/null
+++ b/tools/build_android_ndk19.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# Build quiche for Android NDK 19 or higher
+#
+# ANDROID_NDK_HOME : android ndk location
+# TOOLCHAIN_DIR : where create a toolchain (optional)
+#
+set -eu
+
+# Change this value if you need a different API level
+# 21 is the minimum API tested
+API_LEVEL=21
+
+if [ ! -d "${ANDROID_NDK_HOME-}" ]; then
+    ANDROID_NDK_HOME=/usr/local/share/android-ndk
+fi
+
+if [ ! -d "${TOOLCHAIN_DIR-}" ]; then
+    TOOLCHAIN_DIR=$(pwd)
+fi
+
+echo "> building quiche for android API $API_LEVEL..."
+
+for target in \
+    aarch64-linux-android \
+    armv7-linux-androideabi \
+    i686-linux-android
+do
+    echo "> buliding $target..."
+    cargo ndk --target $target --android-platform $API_LEVEL -- build $*
+done
diff --git a/tools/setup_android.sh b/tools/setup_android.sh
index c8eda8f..8ca4868 100755
--- a/tools/setup_android.sh
+++ b/tools/setup_android.sh
@@ -7,6 +7,10 @@
 #
 set -eu
 
+# Change this value if you need a different API level
+# 21 is the minimum API tested
+API_LEVEL=21
+
 if [ ! -d "${ANDROID_NDK_HOME-}" ]; then
     ANDROID_NDK_HOME=/usr/local/share/android-ndk
 fi
@@ -31,9 +35,9 @@
 echo "> Toolchain Directory: ${TOOLCHAIN_DIR}"
 
 mkdir -p ${TOOLCHAIN_DIR}/arch
-make_standalone_toolchain arm64 21
-make_standalone_toolchain arm 21
-make_standalone_toolchain x86 21
+make_standalone_toolchain arm64 $API_LEVEL
+make_standalone_toolchain arm $API_LEVEL
+make_standalone_toolchain x86 $API_LEVEL
 
 CARGO_CONFIG=cargo-config.toml
 sed 's@$TOOLCHAIN_DIR@'"${TOOLCHAIN_DIR}"'@g' > $CARGO_CONFIG <<CARGO_CONFIG_EOF