Add Java helper code for establishing binder transport connection (#26862)

These Java code will be invoked by binder transport C++ implementation
through JNI to establish the connection between client and server.

The code is locally tested with other pending changes to make sure it
works correctly.

For now we only make sure it builds in CI. We will port proper tests
from internal repository later.

A new local repository is created for the Android-only Java code because
1. The analysis of its BUILD will fail without Android SDK configured
2. We want to prevent clang-tidy (and maybe other scripts)'s automatic
expansion of '...' to include it as they typically don't have Android
SDK installed
pull/27006/head
Ming-Chuan 3 years ago committed by GitHub
parent 3e34e3aac7
commit f0489c8f5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      WORKSPACE
  2. 0
      src/core/ext/transport/binder/java/WORKSPACE
  3. 27
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/BUILD
  4. 43
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/NativeConnectionHelper.java
  5. 71
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/SyncServiceConnection.java
  6. 5
      tools/internal_ci/linux/grpc_binder_transport_apk_build_in_docker.sh

@ -91,6 +91,16 @@ android_ndk_repository(
# https://github.com/bazelbuild/bazel/issues/13421
)
# Prevents bazel's '...' expansion from including the following folder.
# This is required because the BUILD file in the following folder
# will trigger bazel failure when Android SDK is not configured.
# The targets in the following folder need to be included in APK and will
# be invoked by binder transport implementation through JNI.
local_repository(
name = "binder_transport_android_helper",
path = "./src/core/ext/transport/binder/java",
)
# Create msan toolchain configuration for remote execution.
rbe_autoconfig(
name = "rbe_msan",

@ -0,0 +1,27 @@
# 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_library")
licenses(["notice"])
android_library(
name = "connection_helper",
srcs = [
"NativeConnectionHelper.java",
"SyncServiceConnection.java",
],
visibility = ["//visibility:public"],
deps = [],
)

@ -0,0 +1,43 @@
// 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.
package io.grpc.binder.cpp;
import android.content.Context;
import android.os.IBinder;
import android.os.Parcel;
/**
* This class will be invoked by gRPC binder transport internal implementation to perform operations
* that are only possible in Java
*/
final class NativeConnectionHelper {
static SyncServiceConnection s;
static void tryEstablishConnection(Context context) {
s = new SyncServiceConnection(context);
s.tryConnect();
}
// TODO(mingcl): We should notify C++ once we got the service binder so they don't need to call
// this function to check. For now we assume that this function will only be called after
// successful connection
static IBinder getServiceBinder() {
return s.getIBinder();
}
static Parcel getEmptyParcel() {
return Parcel.obtain();
}
}

@ -0,0 +1,71 @@
// 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.
package io.grpc.binder.cpp;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
/* Connects to a service synchronously */
public class SyncServiceConnection implements ServiceConnection {
private final String logTag = "SyncServiceConnection";
private Context mContext;
private IBinder mService;
public SyncServiceConnection(Context context) {
mContext = context;
}
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.e(logTag, "Service has connected: ");
synchronized (this) {
mService = service;
}
}
@Override
public void onServiceDisconnected(ComponentName className) {
Log.e(logTag, "Service has disconnected: ");
}
public void tryConnect() {
synchronized (this) {
Intent intent = new Intent("grpc.io.action.BIND");
// TODO(mingcl): The component name is currently hard-coded here and should be changed
// manually before compile. We should pump the component name from C++ to here instead after
// we have a server ready for integration test.
ComponentName compName = new ComponentName("redacted", "redacted");
intent.setComponent(compName);
// Will return true if the system is in the process of bringing up a service that your client
// has permission to bind to; false if the system couldn't find the service or if your client
// doesn't have permission to bind to it
boolean result = mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
if (result) {
Log.e(logTag, "bindService ok");
} else {
Log.e(logTag, "bindService not ok");
}
}
}
public IBinder getIBinder() {
return mService;
}
}

@ -31,3 +31,8 @@ echo $ANDROID_NDK_HOME
# clang compiler to check if sources can pass a set of warning options.
bazel build --define=use_strict_warning=true \
//examples/android/binder/java/io/grpc/binder/cpp/example:app
# Make sure the Java code that will be invoked by binder transport
# implementation builds
bazel build --define=use_strict_warning=true \
@binder_transport_android_helper//io/grpc/binder/cpp:connection_helper

Loading…
Cancel
Save