diff --git a/WORKSPACE b/WORKSPACE
index 5d772805c8d..9f7b7e5e51e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -69,6 +69,27 @@ rbe_autoconfig(
load("@bazel_toolchains//rules:environments.bzl", "clang_env")
load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+ name = "build_bazel_rules_android",
+ sha256 = "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806",
+ strip_prefix = "rules_android-0.1.1",
+ urls = ["https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip"],
+)
+
+android_sdk_repository(
+ name = "androidsdk",
+ # version 31.0.0 won't work https://stackoverflow.com/a/68036845
+ build_tools_version = "30.0.3",
+)
+
+android_ndk_repository(
+ name = "androidndk",
+ # Note that Bazel does not support NDK 22 yet, and Bazel 3.7.1 only
+ # supports up to API level 29 for NDK 21
+ # https://github.com/bazelbuild/bazel/issues/13421
+)
# Create msan toolchain configuration for remote execution.
rbe_autoconfig(
diff --git a/examples/android/binder/java/io/grpc/binder/cpp/example/AndroidManifest.xml b/examples/android/binder/java/io/grpc/binder/cpp/example/AndroidManifest.xml
new file mode 100644
index 00000000000..ffec2023630
--- /dev/null
+++ b/examples/android/binder/java/io/grpc/binder/cpp/example/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/android/binder/java/io/grpc/binder/cpp/example/BUILD b/examples/android/binder/java/io/grpc/binder/cpp/example/BUILD
new file mode 100644
index 00000000000..2b789275345
--- /dev/null
+++ b/examples/android/binder/java/io/grpc/binder/cpp/example/BUILD
@@ -0,0 +1,48 @@
+# Copyright 2021 gRPC authors.
+#
+# 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.
+
+load("@build_bazel_rules_android//android:rules.bzl", "android_binary", "android_library")
+
+cc_library(
+ name = "jni_lib",
+ srcs = ["native.cc"],
+ linkopts = [
+ "-ldl",
+ "-llog",
+ "-Wl,--no-undefined",
+ ],
+ deps = [],
+ alwayslink = True,
+)
+
+android_library(
+ name = "activity",
+ srcs = [
+ "ButtonPressHandler.java",
+ "MainActivity.java",
+ ],
+ manifest = "AndroidManifest.xml",
+ resource_files = glob(["res/**"]),
+ deps = [
+ ":jni_lib",
+ ],
+)
+
+android_binary(
+ name = "app",
+ manifest = "AndroidManifest.xml",
+ deps = [
+ ":activity",
+ ],
+)
diff --git a/examples/android/binder/java/io/grpc/binder/cpp/example/ButtonPressHandler.java b/examples/android/binder/java/io/grpc/binder/cpp/example/ButtonPressHandler.java
new file mode 100644
index 00000000000..44e1e08509a
--- /dev/null
+++ b/examples/android/binder/java/io/grpc/binder/cpp/example/ButtonPressHandler.java
@@ -0,0 +1,15 @@
+package io.grpc.binder.cpp.example;
+
+import android.app.Application;
+
+public class ButtonPressHandler {
+ static {
+ System.loadLibrary("app");
+ }
+
+ public native String native_entry(Application application);
+
+ public String onPressed(Application application) {
+ return native_entry(application);
+ }
+}
diff --git a/examples/android/binder/java/io/grpc/binder/cpp/example/MainActivity.java b/examples/android/binder/java/io/grpc/binder/cpp/example/MainActivity.java
new file mode 100644
index 00000000000..0c87b2bbcfe
--- /dev/null
+++ b/examples/android/binder/java/io/grpc/binder/cpp/example/MainActivity.java
@@ -0,0 +1,26 @@
+package io.grpc.binder.cpp.example;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.TextView;
+
+/** Main class for the example app. */
+public class MainActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.v("Example", "hello, world");
+
+ setContentView(R.layout.activity_main);
+
+ Button clickMeButton = findViewById(R.id.clickMeButton);
+ TextView exampleTextView = findViewById(R.id.exampleTextView);
+
+ ButtonPressHandler h = new ButtonPressHandler();
+
+ clickMeButton.setOnClickListener(
+ v -> exampleTextView.setText(h.onPressed(getApplication())));
+ }
+}
diff --git a/examples/android/binder/java/io/grpc/binder/cpp/example/README.md b/examples/android/binder/java/io/grpc/binder/cpp/example/README.md
new file mode 100644
index 00000000000..bbc1545ecf6
--- /dev/null
+++ b/examples/android/binder/java/io/grpc/binder/cpp/example/README.md
@@ -0,0 +1,18 @@
+# gRPC-core BinderTransport example app
+
+WIP.
+
+## Build Instruction
+
+1. Install Android SDK and NDK. Currently we only support SDK version 30.0.3 and
+ NDK version 21.4.7075529 . Make sure you get these exact versions otherwise
+ Bazel might complain.
+
+2. Point environment variables to install locations of SDK and NDK
+ ```
+ export ANDROID_HOME=$HOME/Android/Sdk/
+ export ANDROID_NDK_HOME=$HOME/Android/Sdk/ndk/21.4.7075529
+ ```
+3. `bazel build //examples/android/binder/java/io/grpc/binder/cpp/example:app`
+4. `adb install
+ bazel-bin/examples/android/binder/java/io/grpc/binder/cpp/example/app.apk`
diff --git a/examples/android/binder/java/io/grpc/binder/cpp/example/native.cc b/examples/android/binder/java/io/grpc/binder/cpp/example/native.cc
new file mode 100644
index 00000000000..e9cdf984b29
--- /dev/null
+++ b/examples/android/binder/java/io/grpc/binder/cpp/example/native.cc
@@ -0,0 +1,30 @@
+// Copyright 2021 gRPC authors.
+//
+// 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.
+
+
+#include
+#include
+
+extern "C" JNIEXPORT jstring JNICALL
+Java_io_grpc_binder_cpp_example_ButtonPressHandler_native_1entry(
+ JNIEnv* env, jobject /*this*/, jobject /*application*/) {
+ static bool first = true;
+ __android_log_print(ANDROID_LOG_INFO, "Demo", "Line number %d", __LINE__);
+ if (first) {
+ first = false;
+ return env->NewStringUTF("Clicked 1 time");
+ } else {
+ return env->NewStringUTF("Clicked more than 1 time");
+ }
+}
diff --git a/examples/android/binder/java/io/grpc/binder/cpp/example/res/layout/activity_main.xml b/examples/android/binder/java/io/grpc/binder/cpp/example/res/layout/activity_main.xml
new file mode 100644
index 00000000000..e866d8df894
--- /dev/null
+++ b/examples/android/binder/java/io/grpc/binder/cpp/example/res/layout/activity_main.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/examples/android/binder/java/io/grpc/binder/cpp/example/res/values/strings.xml b/examples/android/binder/java/io/grpc/binder/cpp/example/res/values/strings.xml
new file mode 100644
index 00000000000..7593624fa84
--- /dev/null
+++ b/examples/android/binder/java/io/grpc/binder/cpp/example/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Run example
+ 🤔
+
diff --git a/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh b/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
index 623086aefd2..21c4bb2472e 100755
--- a/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
+++ b/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
@@ -27,12 +27,16 @@ cd /var/local/git/grpc
# Build all basic targets using the strict warning option which leverages the
# clang compiler to check if sources can pass a set of warning options.
+# For now //examples/android/binder/ are excluded because it needs Android
+# SDK/NDK to be installed to build
bazel build --define=use_strict_warning=true \
+ -- \
:all \
//src/core/... \
//src/compiler/... \
//test/... \
- //examples/...
+ //examples/... \
+ -//examples/android/binder/...
# TODO(jtattersmusch): Adding a build here for --define=grpc_no_xds is not ideal
# and we should find a better place for this. Refer