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 @@ + + + + + +