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 index ffec2023630..7a60e908523 100644 --- a/examples/android/binder/java/io/grpc/binder/cpp/example/AndroidManifest.xml +++ b/examples/android/binder/java/io/grpc/binder/cpp/example/AndroidManifest.xml @@ -1,3 +1,4 @@ + + + + + #include +#include "examples/protos/helloworld.grpc.pb.h" +#include "examples/protos/helloworld.pb.h" #include "src/core/ext/transport/binder/client/channel_create.h" extern "C" JNIEXPORT jstring JNICALL @@ -23,12 +25,22 @@ Java_io_grpc_binder_cpp_example_ButtonPressHandler_native_1entry( __android_log_print(ANDROID_LOG_INFO, "Demo", "Line number %d", __LINE__); if (first) { first = false; - grpc::experimental::BindToOnDeviceServerService(env, application, "", ""); + grpc::experimental::BindToOnDeviceServerService( + env, application, "io.grpc.binder.cpp.exampleserver", + "io.grpc.binder.cpp.exampleserver.ExportedEndpointService"); return env->NewStringUTF("Clicked 1 time"); } else { - // Create a channel. For now we only want to make sure it compiles. auto channel = grpc::experimental::CreateBinderChannel(env, application, "", ""); - return env->NewStringUTF("Clicked more than 1 time"); + auto stub = helloworld::Greeter::NewStub(channel); + grpc::ClientContext context; + helloworld::HelloRequest request; + helloworld::HelloReply response; + request.set_name("BinderTransportClient"); + grpc::Status status = stub->SayHello(&context, request, &response); + if (status.ok()) { + return env->NewStringUTF(response.message().c_str()); + } + return env->NewStringUTF("Clicked more than 1 time. Status not ok"); } } diff --git a/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/AndroidManifest.xml b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/AndroidManifest.xml new file mode 100644 index 00000000000..fe2cd2e7d95 --- /dev/null +++ b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/AndroidManifest_endpoint.xml b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/AndroidManifest_endpoint.xml new file mode 100644 index 00000000000..a9c9d5c4f68 --- /dev/null +++ b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/AndroidManifest_endpoint.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/BUILD b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/BUILD new file mode 100644 index 00000000000..dda10b1337d --- /dev/null +++ b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/BUILD @@ -0,0 +1,65 @@ +# 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", + "-lm", + "-lbinder_ndk", + "-Wl,--no-undefined", + ], + deps = [ + # Temporarily directly depend on this target before we expose a public API + # TODO(mingcl): Uncomment this after server interfaces are merged + # "//src/core/ext/transport/binder/server:grpc_transport_binder_server", + "//:grpc++", + "//examples/protos:helloworld_cc_grpc", + ], + alwayslink = True, +) + +android_library( + name = "activity", + srcs = [ + "ButtonPressHandler.java", + "MainActivity.java", + ], + manifest = "AndroidManifest.xml", + resource_files = glob(["res/**"]), + deps = [ + ":endpoint", + ":jni_lib", + ], +) + +android_library( + name = "endpoint", + srcs = ["ExportedEndpointService.java"], + exports_manifest = True, + manifest = "AndroidManifest_endpoint.xml", + deps = [], +) + +android_binary( + name = "app", + manifest = "AndroidManifest.xml", + deps = [ + ":activity", + ], +) diff --git a/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/ButtonPressHandler.java b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/ButtonPressHandler.java new file mode 100644 index 00000000000..34d38ccf58a --- /dev/null +++ b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/ButtonPressHandler.java @@ -0,0 +1,13 @@ +package io.grpc.binder.cpp.exampleserver; + +import android.app.Application; + +public class ButtonPressHandler { + static { + System.loadLibrary("app"); + } + + public String onPressed(Application application) { + return "Server Button Pressed"; + } +} diff --git a/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/ExportedEndpointService.java b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/ExportedEndpointService.java new file mode 100644 index 00000000000..287b0662002 --- /dev/null +++ b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/ExportedEndpointService.java @@ -0,0 +1,28 @@ +package io.grpc.binder.cpp.exampleserver; + +import android.app.Service; +import android.os.IBinder; +import android.content.Intent; + +/** Exposes gRPC services running in the main process */ +public final class ExportedEndpointService extends Service { + private final IBinder binder; + + static { + System.loadLibrary("app"); + } + + public ExportedEndpointService() { + init_grpc_server(); + binder = get_endpoint_binder(); + } + + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + public native void init_grpc_server(); + + public native IBinder get_endpoint_binder(); +} diff --git a/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/MainActivity.java b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/MainActivity.java new file mode 100644 index 00000000000..d252e5f2bd3 --- /dev/null +++ b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/MainActivity.java @@ -0,0 +1,27 @@ +package io.grpc.binder.cpp.exampleserver; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.widget.Button; +import android.widget.TextView; +import io.grpc.binder.cpp.exampleserver.R; + +/** 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/exampleserver/native.cc b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/native.cc new file mode 100644 index 00000000000..a64a49a2db9 --- /dev/null +++ b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/native.cc @@ -0,0 +1,87 @@ +// 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 +#include +#include +#include +#include +#include + +#include "examples/protos/helloworld.grpc.pb.h" +#include "examples/protos/helloworld.pb.h" + +// TODO(mingcl): Uncomment this after server interfaces are merged +// #include "src/core/ext/transport/binder/server/binder_server.h" +// #include "src/core/ext/transport/binder/server/binder_server_credentials.h" + +namespace { +class GreeterService : public helloworld::Greeter::Service { + public: + grpc::Status SayHello(grpc::ServerContext*, + const helloworld::HelloRequest* request, + helloworld::HelloReply* response) override { + __android_log_print(ANDROID_LOG_INFO, "DemoServer", "Line number %d", + __LINE__); + __android_log_print(ANDROID_LOG_INFO, "DemoServer", "Got hello request: %s", + request->name().c_str()); + response->set_message("Hi, " + request->name()); + return grpc::Status::OK; + } +}; + +} // namespace + +extern "C" JNIEXPORT void JNICALL +Java_io_grpc_binder_cpp_exampleserver_ExportedEndpointService_init_1grpc_1server( + JNIEnv* env, jobject /*this*/) { + __android_log_print(ANDROID_LOG_INFO, "DemoServer", "Line number %d", + __LINE__); + static std::unique_ptr server = nullptr; + + if (server != nullptr) { + // Already initiated + return; + } + + static GreeterService service; + grpc::ServerBuilder server_builder; + server_builder.RegisterService(&service); + + // TODO(mingcl): Uncomment this after server interfaces are merged + // + // grpc_endpoint_binder_pool_init(); + // server_builder.AddListeningPort("binder://example.service", + // grpc::experimental::BinderServerCredentials()); + + server = server_builder.BuildAndStart(); +} + +extern "C" JNIEXPORT jobject JNICALL +Java_io_grpc_binder_cpp_exampleserver_ExportedEndpointService_get_1endpoint_1binder( + JNIEnv* env, jobject /*this*/) { + __android_log_print(ANDROID_LOG_INFO, "DemoServer", "Line number %d", + __LINE__); + + // TODO(mingcl): Uncomment this after server interfaces are merged + // auto ai_binder = + // static_cast(grpc::experimental::binder::GetEndpointBinder("example.service")); + + AIBinder* ai_binder = nullptr; + + __android_log_print(ANDROID_LOG_INFO, "DemoServer", "ai_binder = %p", + ai_binder); + return AIBinder_toJavaBinder(env, ai_binder); +} diff --git a/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/res/layout/activity_main.xml b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/res/layout/activity_main.xml new file mode 100644 index 00000000000..e866d8df894 --- /dev/null +++ b/examples/android/binder/java/io/grpc/binder/cpp/exampleserver/res/layout/activity_main.xml @@ -0,0 +1,24 @@ + + + + + +