Add BinderTransport example server app (#27067)

Some code are commented out because the server interface has not been
merged yet.

After this, user should be able to install both apps on Android device
and test if basic unary call works or not
pull/27183/head
Ming-Chuan 3 years ago committed by GitHub
parent 013a45ccc4
commit 73003f8527
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      examples/android/binder/java/io/grpc/binder/cpp/example/AndroidManifest.xml
  2. 1
      examples/android/binder/java/io/grpc/binder/cpp/example/BUILD
  3. 18
      examples/android/binder/java/io/grpc/binder/cpp/example/native.cc
  4. 21
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/AndroidManifest.xml
  5. 10
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/AndroidManifest_endpoint.xml
  6. 65
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/BUILD
  7. 13
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/ButtonPressHandler.java
  8. 28
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/ExportedEndpointService.java
  9. 27
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/MainActivity.java
  10. 87
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/native.cc
  11. 24
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/res/layout/activity_main.xml
  12. 5
      examples/android/binder/java/io/grpc/binder/cpp/exampleserver/res/values/strings.xml
  13. 3
      tools/internal_ci/linux/grpc_binder_transport_apk_build_in_docker.sh

@ -1,3 +1,4 @@
<!-- TODO(mingcl): Rename this app to exampleclient -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.grpc.binder.cpp.example"
android:versionCode="1"
@ -7,6 +8,10 @@
android:minSdkVersion="29"
android:targetSdkVersion="30" />
<queries>
<package android:name="io.grpc.binder.cpp.exampleserver" />
</queries>
<application
android:label="gRPC BinderTransport Cpp">
<activity

@ -27,6 +27,7 @@ cc_library(
deps = [
# Temporarily directly depend on this target before we expose a public API
"//src/core/ext/transport/binder/client:grpc_transport_binder_client",
"//examples/protos:helloworld_cc_grpc",
],
alwayslink = True,
)

@ -14,6 +14,8 @@
#include <android/log.h>
#include <jni.h>
#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");
}
}

@ -0,0 +1,21 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.grpc.binder.cpp.exampleserver"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="29"
android:targetSdkVersion="30" />
<application
android:label="gRPC BinderTransport Server Cpp">
<activity
android:name=".MainActivity"
android:label="gRPC BinderTransport Server Cpp" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.grpc.binder.cpp.exampleserver">
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="30"/>
<application>
<service
android:name=".ExportedEndpointService"
android:exported="true"/>
</application>
</manifest>

@ -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",
],
)

@ -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";
}
}

@ -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();
}

@ -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())));
}
}

@ -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 <android/binder_auto_utils.h>
#include <android/binder_ibinder.h>
#include <android/binder_ibinder_jni.h>
#include <android/binder_interface_utils.h>
#include <android/log.h>
#include <grpcpp/grpcpp.h>
#include <jni.h>
#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<grpc::Server> 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<AIBinder*>(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);
}

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="16dp"
android:orientation="vertical"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/exampleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="32dp"
android:text="@string/thinking_face"/>
<Button
android:id="@+id/clickMeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:text="@string/click_me_button"/>
</LinearLayout>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="click_me_button">Run example</string>
<string name="thinking_face">🤔</string>
</resources>

@ -35,7 +35,8 @@ echo $ANDROID_NDK_HOME
bazel build --define=use_strict_warning=true \
--fat_apk_cpu=x86_64,arm64-v8a \
--extra_toolchains=@rules_python//python:autodetecting_toolchain_nonstrict \
//examples/android/binder/java/io/grpc/binder/cpp/example:app
//examples/android/binder/java/io/grpc/binder/cpp/example:app \
//examples/android/binder/java/io/grpc/binder/cpp/exampleserver:app
# Make sure the Java code that will be invoked by binder transport
# implementation builds

Loading…
Cancel
Save