mirror of https://github.com/grpc/grpc.git
parent
7bdfd32f46
commit
b41b323fbe
49 changed files with 3861 additions and 23 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,82 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef GRPCPP_SECURITY_BINDER_SECURITY_POLICY_H |
||||||
|
#define GRPCPP_SECURITY_BINDER_SECURITY_POLICY_H |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#ifdef GPR_ANDROID |
||||||
|
|
||||||
|
#include <jni.h> |
||||||
|
|
||||||
|
#endif |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
namespace experimental { |
||||||
|
namespace binder { |
||||||
|
|
||||||
|
// EXPERIMENTAL Determinines if a connection is allowed to be
|
||||||
|
// established on Android. See https://source.android.com/security/app-sandbox
|
||||||
|
// for more info about UID.
|
||||||
|
class SecurityPolicy { |
||||||
|
public: |
||||||
|
virtual ~SecurityPolicy() = default; |
||||||
|
// Returns true if the UID is authorized to connect.
|
||||||
|
// Must return the same value for the same inputs so callers can safely cache
|
||||||
|
// the result.
|
||||||
|
virtual bool IsAuthorized(int uid) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
// EXPERIMENTAL Allows all connection. Anything on the Android device will be
|
||||||
|
// able to connect, use with caution!
|
||||||
|
class UntrustedSecurityPolicy : public SecurityPolicy { |
||||||
|
public: |
||||||
|
UntrustedSecurityPolicy(); |
||||||
|
~UntrustedSecurityPolicy() override; |
||||||
|
bool IsAuthorized(int uid) override; |
||||||
|
}; |
||||||
|
|
||||||
|
// EXPERIMENTAL Only allows the connections from processes with the same UID. In
|
||||||
|
// most cases this means "from the same APK".
|
||||||
|
class InternalOnlySecurityPolicy : public SecurityPolicy { |
||||||
|
public: |
||||||
|
InternalOnlySecurityPolicy(); |
||||||
|
~InternalOnlySecurityPolicy() override; |
||||||
|
bool IsAuthorized(int uid) override; |
||||||
|
}; |
||||||
|
|
||||||
|
#ifdef GPR_ANDROID |
||||||
|
|
||||||
|
// EXPERIMENTAL Only allows the connections from the APK that have the same
|
||||||
|
// signature.
|
||||||
|
class SameSignatureSecurityPolicy : public SecurityPolicy { |
||||||
|
public: |
||||||
|
// `context` is required for getting PackageManager Java class
|
||||||
|
SameSignatureSecurityPolicy(JavaVM* jvm, jobject context); |
||||||
|
~SameSignatureSecurityPolicy() override; |
||||||
|
bool IsAuthorized(int uid) override; |
||||||
|
|
||||||
|
private: |
||||||
|
JavaVM* jvm_; |
||||||
|
jobject context_; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
||||||
|
|
||||||
|
} // namespace binder
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc
|
||||||
|
|
||||||
|
#endif // GRPCPP_SECURITY_BINDER_SECURITY_POLICY_H
|
@ -0,0 +1,10 @@ |
|||||||
|
# Binder transport for cross process IPC on Android |
||||||
|
|
||||||
|
EXPERIMENTAL. API stability not guaranteed. |
||||||
|
|
||||||
|
This transport implements |
||||||
|
[BinderChannel for native cross-process communication on Android](https://github.com/grpc/proposal/blob/master/L73-java-binderchannel.md) and enables C++/Java cross-process communication on Android with gRPC. |
||||||
|
|
||||||
|
Tests: https://github.com/grpc/grpc/tree/master/test/core/transport/binder/ |
||||||
|
|
||||||
|
Example apps: https://github.com/grpc/grpc/tree/master/examples/android/binder/java/io/grpc/binder/cpp |
@ -0,0 +1,42 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CHANNEL_CREATE_IMPL_H |
||||||
|
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CHANNEL_CREATE_IMPL_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
#include <grpcpp/security/binder_security_policy.h> |
||||||
|
|
||||||
|
#include "src/core/ext/transport/binder/wire_format/binder.h" |
||||||
|
#include "src/core/lib/channel/channel_args.h" |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
namespace internal { |
||||||
|
|
||||||
|
// Creates a GRPC_CLIENT_DIRECT_CHANNEL channel from endpoint binder
|
||||||
|
// At this moment this is only used for testing.
|
||||||
|
grpc_channel* CreateDirectBinderChannelImplForTesting( |
||||||
|
std::unique_ptr<grpc_binder::Binder> endpoint_binder, |
||||||
|
const grpc_channel_args* args, |
||||||
|
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> |
||||||
|
security_policy); |
||||||
|
|
||||||
|
// Creates a GRPC_CLIENT_CHANNEL channel
|
||||||
|
grpc_channel* CreateClientBinderChannelImpl(std::string target, |
||||||
|
const grpc_channel_args* args); |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace grpc
|
||||||
|
|
||||||
|
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CHANNEL_CREATE_IMPL_H
|
@ -0,0 +1,69 @@ |
|||||||
|
// 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 "src/core/ext/transport/binder/client/connection_id_generator.h" |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#ifndef GRPC_NO_BINDER |
||||||
|
|
||||||
|
#include "absl/log/check.h" |
||||||
|
#include "absl/strings/str_cat.h" |
||||||
|
|
||||||
|
namespace { |
||||||
|
// Make sure `s` does not contain characters other than numbers, alphabets,
|
||||||
|
// period and underscore
|
||||||
|
std::string Normalize(absl::string_view str_view) { |
||||||
|
std::string s = std::string(str_view); |
||||||
|
for (size_t i = 0; i < s.length(); i++) { |
||||||
|
if (!isalnum(s[i]) && s[i] != '.') { |
||||||
|
s[i] = '_'; |
||||||
|
} |
||||||
|
} |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
// Remove prefix of the string if the string is longer than len
|
||||||
|
std::string StripToLength(const std::string& s, size_t len) { |
||||||
|
if (s.length() > len) { |
||||||
|
return s.substr(s.length() - len, len); |
||||||
|
} |
||||||
|
return s; |
||||||
|
} |
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace grpc_binder { |
||||||
|
|
||||||
|
std::string ConnectionIdGenerator::Generate(absl::string_view uri) { |
||||||
|
// reserve some room for serial number
|
||||||
|
const size_t kReserveForNumbers = 15; |
||||||
|
std::string s = |
||||||
|
StripToLength(Normalize(uri), kPathLengthLimit - kReserveForNumbers); |
||||||
|
std::string ret; |
||||||
|
{ |
||||||
|
grpc_core::MutexLock l(&m_); |
||||||
|
// Insert a hyphen before serial number
|
||||||
|
ret = absl::StrCat(s, "-", ++count_); |
||||||
|
} |
||||||
|
CHECK_LT(ret.length(), kPathLengthLimit); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
ConnectionIdGenerator* GetConnectionIdGenerator() { |
||||||
|
static ConnectionIdGenerator* cig = new ConnectionIdGenerator(); |
||||||
|
return cig; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_binder
|
||||||
|
#endif |
@ -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. |
||||||
|
|
||||||
|
# copybara: Import internal android_library rule here |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
android_library( |
||||||
|
name = "connection_helper", |
||||||
|
srcs = [ |
||||||
|
"GrpcBinderConnection.java", |
||||||
|
"GrpcCppServerBuilder.java", |
||||||
|
"NativeConnectionHelper.java", |
||||||
|
], |
||||||
|
visibility = ["//visibility:public"], |
||||||
|
deps = [ |
||||||
|
# copybara: Add proguard dependency here |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,104 @@ |
|||||||
|
// 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 static android.content.Intent.URI_ANDROID_APP_SCHEME; |
||||||
|
import static android.content.Intent.URI_INTENT_SCHEME; |
||||||
|
|
||||||
|
import android.annotation.TargetApi; |
||||||
|
import android.content.ComponentName; |
||||||
|
import android.content.Context; |
||||||
|
import android.content.Intent; |
||||||
|
import android.content.ServiceConnection; |
||||||
|
import android.os.IBinder; |
||||||
|
import android.util.Log; |
||||||
|
import java.net.URISyntaxException; |
||||||
|
|
||||||
|
/* Handles the binder connection state with OnDeviceServer server */ |
||||||
|
public class GrpcBinderConnection implements ServiceConnection { |
||||||
|
private static final String logTag = "GrpcBinderConnection"; |
||||||
|
|
||||||
|
private Context mContext; |
||||||
|
private IBinder mService; |
||||||
|
|
||||||
|
// A string that identifies this service connection
|
||||||
|
private final String mConnId; |
||||||
|
|
||||||
|
public GrpcBinderConnection(Context context, String connId) { |
||||||
|
mContext = context; |
||||||
|
mConnId = connId; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onNullBinding(ComponentName className) { |
||||||
|
// TODO(mingcl): Notify C++ that the connection is never going to happen
|
||||||
|
Log.e(logTag, "Service returned null IBinder. mConnId = " + mConnId); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onServiceConnected(ComponentName className, IBinder service) { |
||||||
|
Log.e(logTag, "Service has connected. mConnId = " + mConnId); |
||||||
|
if (service == null) { |
||||||
|
// This should not happen since onNullBinding should be invoked instead
|
||||||
|
throw new IllegalArgumentException("service was null"); |
||||||
|
} |
||||||
|
synchronized (this) { |
||||||
|
mService = service; |
||||||
|
} |
||||||
|
notifyConnected(mConnId, mService); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onServiceDisconnected(ComponentName className) { |
||||||
|
Log.e(logTag, "Service has disconnected. mConnId = " + mConnId); |
||||||
|
} |
||||||
|
|
||||||
|
public void tryConnect(String pkg, String cls, String action_name) { |
||||||
|
Intent intent = new Intent(action_name); |
||||||
|
ComponentName compName = new ComponentName(pkg, cls); |
||||||
|
intent.setComponent(compName); |
||||||
|
tryConnect(intent); |
||||||
|
} |
||||||
|
|
||||||
|
@TargetApi(22) |
||||||
|
public void tryConnect(String uri) { |
||||||
|
// Try connect with an URI that can be parsed as intent.
|
||||||
|
try { |
||||||
|
tryConnect(Intent.parseUri(uri, URI_ANDROID_APP_SCHEME | URI_INTENT_SCHEME)); |
||||||
|
} catch (URISyntaxException e) { |
||||||
|
Log.e(logTag, "Unable to parse the Uri: " + uri); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void tryConnect(Intent intent) { |
||||||
|
synchronized (this) { |
||||||
|
// 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 returns ok"); |
||||||
|
} else { |
||||||
|
Log.e( |
||||||
|
logTag, |
||||||
|
"bindService failed. Maybe the system couldn't find the service or the" |
||||||
|
+ " client doesn't have permission to bind to it."); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Calls a function defined in endpoint_binder_pool.cc
|
||||||
|
private static native void notifyConnected(String connId, IBinder service); |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
// 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.os.IBinder; |
||||||
|
import android.util.Log; |
||||||
|
|
||||||
|
/* EXPERIMENTAL. Provides a interface to get endpoint binder from C++ */ |
||||||
|
public class GrpcCppServerBuilder { |
||||||
|
private static final String logTag = "GrpcCppServerBuilder"; |
||||||
|
|
||||||
|
public static IBinder GetEndpointBinder(String uri) { |
||||||
|
String scheme = "binder:"; |
||||||
|
if (uri.startsWith(scheme)) { |
||||||
|
String path = uri.substring(scheme.length()); |
||||||
|
// TODO(mingcl): Consider if we would like to make sure the path only contain valid
|
||||||
|
// characters here
|
||||||
|
IBinder ibinder = GetEndpointBinderInternal(path); |
||||||
|
Log.e(logTag, "Returning binder=" + ibinder + " for URI=" + uri); |
||||||
|
return ibinder; |
||||||
|
} else { |
||||||
|
Log.e(logTag, "URI " + uri + " does not start with 'binder:'"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static native IBinder GetEndpointBinderInternal(String conn_id); |
||||||
|
} |
@ -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.Context; |
||||||
|
import android.content.pm.PackageManager; |
||||||
|
import android.os.Parcel; |
||||||
|
import android.util.Log; |
||||||
|
// copybara: Import proguard UsedByNative annotation here
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class will be invoked by gRPC binder transport internal implementation (from |
||||||
|
* src/core/ext/transport/binder/client/jni_utils.cc) to perform operations that are only possible |
||||||
|
* in Java |
||||||
|
*/ |
||||||
|
// copybara: Add @UsedByNative("jni_utils.cc")
|
||||||
|
final class NativeConnectionHelper { |
||||||
|
// Maps connection id to GrpcBinderConnection instances
|
||||||
|
static Map<String, GrpcBinderConnection> connectionIdToGrpcBinderConnectionMap = new HashMap<>(); |
||||||
|
|
||||||
|
// copybara: Add @UsedByNative("jni_utils.cc")
|
||||||
|
static void tryEstablishConnection( |
||||||
|
Context context, String pkg, String cls, String actionName, String connId) { |
||||||
|
// TODO(mingcl): Assert that connId is unique
|
||||||
|
connectionIdToGrpcBinderConnectionMap.put(connId, new GrpcBinderConnection(context, connId)); |
||||||
|
connectionIdToGrpcBinderConnectionMap.get(connId).tryConnect(pkg, cls, actionName); |
||||||
|
} |
||||||
|
|
||||||
|
// copybara: Add @UsedByNative("jni_utils.cc")
|
||||||
|
static void tryEstablishConnectionWithUri(Context context, String uri, String connId) { |
||||||
|
// TODO(mingcl): Assert that connId is unique
|
||||||
|
connectionIdToGrpcBinderConnectionMap.put(connId, new GrpcBinderConnection(context, connId)); |
||||||
|
connectionIdToGrpcBinderConnectionMap.get(connId).tryConnect(uri); |
||||||
|
} |
||||||
|
|
||||||
|
// Returns true if the packages signature of the 2 UIDs match.
|
||||||
|
// `context` is used to get PackageManager.
|
||||||
|
// Suppress unnecessary internal warnings related to checkSignatures compatibility issue.
|
||||||
|
// BinderTransport code is only used on newer Android platform versions so this is fine.
|
||||||
|
@SuppressWarnings("CheckSignatures") |
||||||
|
// copybara: Add @UsedByNative("jni_utils.cc")
|
||||||
|
static boolean isSignatureMatch(Context context, int uid1, int uid2) { |
||||||
|
int result = context.getPackageManager().checkSignatures(uid1, uid2); |
||||||
|
if (result == PackageManager.SIGNATURE_MATCH) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
Log.e( |
||||||
|
"NativeConnectionHelper", |
||||||
|
"Signatures does not match. checkSignature return value = " + result); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// copybara: Add @UsedByNative("jni_utils.cc")
|
||||||
|
static Parcel getEmptyParcel() { |
||||||
|
return Parcel.obtain(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_SECURITY_POLICY_SECURITY_POLICY_H |
||||||
|
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_SECURITY_POLICY_SECURITY_POLICY_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
namespace experimental { |
||||||
|
namespace binder { |
||||||
|
|
||||||
|
// This interface is for determining if a connection is allowed to be
|
||||||
|
// established on Android. See https://source.android.com/security/app-sandbox
|
||||||
|
// for more info about UID.
|
||||||
|
class SecurityPolicy { |
||||||
|
public: |
||||||
|
virtual ~SecurityPolicy() = default; |
||||||
|
// Returns true if the UID is authorized to connect.
|
||||||
|
// Must return the same value for the same inputs so callers can safely cache
|
||||||
|
// the result.
|
||||||
|
virtual bool IsAuthorized(int uid) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace binder
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc
|
||||||
|
|
||||||
|
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_SECURITY_POLICY_SECURITY_POLICY_H
|
@ -0,0 +1,117 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_STREAM_H |
||||||
|
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_STREAM_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/ext/transport/binder/transport/binder_transport.h" |
||||||
|
|
||||||
|
struct RecvInitialMetadataArgs { |
||||||
|
grpc_binder_stream* stream; |
||||||
|
grpc_binder_transport* transport; |
||||||
|
int tx_code; |
||||||
|
absl::StatusOr<grpc_binder::Metadata> initial_metadata; |
||||||
|
}; |
||||||
|
|
||||||
|
struct RecvMessageArgs { |
||||||
|
grpc_binder_stream* stream; |
||||||
|
grpc_binder_transport* transport; |
||||||
|
int tx_code; |
||||||
|
absl::StatusOr<std::string> message; |
||||||
|
}; |
||||||
|
|
||||||
|
struct RecvTrailingMetadataArgs { |
||||||
|
grpc_binder_stream* stream; |
||||||
|
grpc_binder_transport* transport; |
||||||
|
int tx_code; |
||||||
|
absl::StatusOr<grpc_binder::Metadata> trailing_metadata; |
||||||
|
int status; |
||||||
|
}; |
||||||
|
|
||||||
|
struct RegisterStreamArgs { |
||||||
|
grpc_binder_stream* stream; |
||||||
|
grpc_binder_transport* transport; |
||||||
|
}; |
||||||
|
|
||||||
|
// TODO(mingcl): Figure out if we want to use class instead of struct here
|
||||||
|
struct grpc_binder_stream { |
||||||
|
// server_data will be null for client, and for server it will be whatever
|
||||||
|
// passed in to the accept_stream_fn callback by client.
|
||||||
|
grpc_binder_stream(grpc_binder_transport* t, grpc_stream_refcount* refcount, |
||||||
|
const void* /*server_data*/, grpc_core::Arena* arena, |
||||||
|
int tx_code, bool is_client) |
||||||
|
: t(t), |
||||||
|
refcount(refcount), |
||||||
|
arena(arena), |
||||||
|
tx_code(tx_code), |
||||||
|
is_client(is_client), |
||||||
|
is_closed(false) { |
||||||
|
recv_initial_metadata_args.stream = this; |
||||||
|
recv_initial_metadata_args.transport = t; |
||||||
|
recv_message_args.stream = this; |
||||||
|
recv_message_args.transport = t; |
||||||
|
recv_trailing_metadata_args.stream = this; |
||||||
|
recv_trailing_metadata_args.transport = t; |
||||||
|
} |
||||||
|
|
||||||
|
~grpc_binder_stream() { |
||||||
|
if (destroy_stream_then_closure != nullptr) { |
||||||
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, destroy_stream_then_closure, |
||||||
|
absl::OkStatus()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int GetTxCode() const { return tx_code; } |
||||||
|
|
||||||
|
grpc_binder_transport* t; |
||||||
|
grpc_stream_refcount* refcount; |
||||||
|
grpc_core::Arena* arena; |
||||||
|
int tx_code; |
||||||
|
const bool is_client; |
||||||
|
bool is_closed; |
||||||
|
|
||||||
|
grpc_closure* destroy_stream_then_closure = nullptr; |
||||||
|
grpc_closure destroy_stream; |
||||||
|
|
||||||
|
// The reason why this stream is cancelled and closed.
|
||||||
|
grpc_error_handle cancel_self_error; |
||||||
|
|
||||||
|
grpc_closure recv_initial_metadata_closure; |
||||||
|
RecvInitialMetadataArgs recv_initial_metadata_args; |
||||||
|
grpc_closure recv_message_closure; |
||||||
|
RecvMessageArgs recv_message_args; |
||||||
|
grpc_closure recv_trailing_metadata_closure; |
||||||
|
RecvTrailingMetadataArgs recv_trailing_metadata_args; |
||||||
|
|
||||||
|
grpc_closure register_stream_closure; |
||||||
|
RegisterStreamArgs register_stream_args; |
||||||
|
|
||||||
|
// We store these fields passed from op batch, in order to access them through
|
||||||
|
// grpc_binder_stream
|
||||||
|
grpc_metadata_batch* recv_initial_metadata; |
||||||
|
grpc_closure* recv_initial_metadata_ready = nullptr; |
||||||
|
bool* trailing_metadata_available = nullptr; |
||||||
|
absl::optional<grpc_core::SliceBuffer>* recv_message; |
||||||
|
grpc_closure* recv_message_ready = nullptr; |
||||||
|
bool* call_failed_before_recv_message = nullptr; |
||||||
|
grpc_metadata_batch* recv_trailing_metadata; |
||||||
|
grpc_closure* recv_trailing_metadata_finished = nullptr; |
||||||
|
|
||||||
|
bool trailing_metadata_sent = false; |
||||||
|
bool need_to_call_trailing_metadata_callback = false; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_STREAM_H
|
@ -0,0 +1,76 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_BINDER_AUTO_UTILS_H |
||||||
|
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_BINDER_AUTO_UTILS_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#ifdef GPR_SUPPORT_BINDER_TRANSPORT |
||||||
|
|
||||||
|
#include "src/core/ext/transport/binder/utils/ndk_binder.h" |
||||||
|
|
||||||
|
namespace grpc_binder { |
||||||
|
namespace ndk_util { |
||||||
|
|
||||||
|
///
|
||||||
|
/// Represents one strong pointer to an AIBinder object.
|
||||||
|
/// Copied from binder/ndk/include_cpp/android/binder_auto_utils.h
|
||||||
|
///
|
||||||
|
class SpAIBinder { |
||||||
|
public: |
||||||
|
SpAIBinder() : mBinder(nullptr) {} |
||||||
|
explicit SpAIBinder(AIBinder* binder) : mBinder(binder) {} |
||||||
|
SpAIBinder(std::nullptr_t) |
||||||
|
: SpAIBinder() {} // NOLINT(google-explicit-constructor)
|
||||||
|
SpAIBinder(const SpAIBinder& other) { *this = other; } |
||||||
|
|
||||||
|
~SpAIBinder() { set(nullptr); } |
||||||
|
SpAIBinder& operator=(const SpAIBinder& other) { |
||||||
|
if (this == &other) { |
||||||
|
return *this; |
||||||
|
} |
||||||
|
AIBinder_incStrong(other.mBinder); |
||||||
|
set(other.mBinder); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
void set(AIBinder* binder) { |
||||||
|
AIBinder* old = *const_cast<AIBinder* volatile*>(&mBinder); |
||||||
|
if (old != nullptr) AIBinder_decStrong(old); |
||||||
|
if (old != *const_cast<AIBinder* volatile*>(&mBinder)) { |
||||||
|
__assert(__FILE__, __LINE__, "Race detected."); |
||||||
|
} |
||||||
|
mBinder = binder; |
||||||
|
} |
||||||
|
|
||||||
|
AIBinder* get() const { return mBinder; } |
||||||
|
AIBinder** getR() { return &mBinder; } |
||||||
|
|
||||||
|
bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); } |
||||||
|
bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); } |
||||||
|
bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); } |
||||||
|
bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); } |
||||||
|
bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); } |
||||||
|
bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); } |
||||||
|
|
||||||
|
private: |
||||||
|
AIBinder* mBinder = nullptr; |
||||||
|
}; |
||||||
|
} // namespace ndk_util
|
||||||
|
} // namespace grpc_binder
|
||||||
|
|
||||||
|
#endif |
||||||
|
|
||||||
|
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_BINDER_AUTO_UTILS_H
|
@ -0,0 +1,107 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_NDK_BINDER_H |
||||||
|
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_NDK_BINDER_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#ifdef GPR_SUPPORT_BINDER_TRANSPORT |
||||||
|
|
||||||
|
#include <assert.h> |
||||||
|
#include <jni.h> |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
|
||||||
|
// This file defines NdkBinder functions, variables, and types in
|
||||||
|
// grpc_binder::ndk_util namespace. This allows us to dynamically load
|
||||||
|
// libbinder_ndk at runtime, and make it possible to compile the code without
|
||||||
|
// the library present at compile time.
|
||||||
|
|
||||||
|
// TODO(mingcl): Consider if we want to check API level and include NDK headers
|
||||||
|
// normally if the level is high enough
|
||||||
|
|
||||||
|
namespace grpc_binder { |
||||||
|
namespace ndk_util { |
||||||
|
|
||||||
|
struct AIBinder; |
||||||
|
struct AParcel; |
||||||
|
struct AIBinder_Class; |
||||||
|
|
||||||
|
// Only enum values used by the project is defined here
|
||||||
|
enum { |
||||||
|
FLAG_ONEWAY = 0x01, |
||||||
|
}; |
||||||
|
enum { |
||||||
|
STATUS_OK = 0, |
||||||
|
STATUS_UNKNOWN_ERROR = (-2147483647 - 1), |
||||||
|
}; |
||||||
|
|
||||||
|
typedef int32_t binder_status_t; |
||||||
|
typedef uint32_t binder_flags_t; |
||||||
|
typedef uint32_t transaction_code_t; |
||||||
|
|
||||||
|
typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, |
||||||
|
int8_t** outBuffer); |
||||||
|
typedef bool (*AParcel_stringAllocator)(void* stringData, int32_t length, |
||||||
|
char** buffer); |
||||||
|
typedef void* (*AIBinder_Class_onCreate)(void* args); |
||||||
|
typedef void (*AIBinder_Class_onDestroy)(void* userData); |
||||||
|
typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, |
||||||
|
transaction_code_t code, |
||||||
|
const AParcel* in, |
||||||
|
AParcel* out); |
||||||
|
|
||||||
|
void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz); |
||||||
|
void* AIBinder_getUserData(AIBinder* binder); |
||||||
|
uid_t AIBinder_getCallingUid(); |
||||||
|
AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder); |
||||||
|
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor, |
||||||
|
AIBinder_Class_onCreate onCreate, |
||||||
|
AIBinder_Class_onDestroy onDestroy, |
||||||
|
AIBinder_Class_onTransact onTransact); |
||||||
|
AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args); |
||||||
|
bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz); |
||||||
|
void AIBinder_incStrong(AIBinder* binder); |
||||||
|
void AIBinder_decStrong(AIBinder* binder); |
||||||
|
binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, |
||||||
|
AParcel** in, AParcel** out, |
||||||
|
binder_flags_t flags); |
||||||
|
binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData, |
||||||
|
AParcel_byteArrayAllocator allocator); |
||||||
|
void AParcel_delete(AParcel* parcel); |
||||||
|
int32_t AParcel_getDataSize(const AParcel* parcel); |
||||||
|
binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value); |
||||||
|
binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value); |
||||||
|
binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder); |
||||||
|
binder_status_t AParcel_writeString(AParcel* parcel, const char* string, |
||||||
|
int32_t length); |
||||||
|
binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value); |
||||||
|
binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value); |
||||||
|
binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, |
||||||
|
AParcel_stringAllocator allocator); |
||||||
|
binder_status_t AParcel_readStrongBinder(const AParcel* parcel, |
||||||
|
AIBinder** binder); |
||||||
|
binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, |
||||||
|
int32_t length); |
||||||
|
binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in); |
||||||
|
jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder); |
||||||
|
|
||||||
|
} // namespace ndk_util
|
||||||
|
|
||||||
|
} // namespace grpc_binder
|
||||||
|
|
||||||
|
#endif // GPR_SUPPORT_BINDER_TRANSPORT
|
||||||
|
|
||||||
|
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_NDK_BINDER_H
|
@ -0,0 +1,29 @@ |
|||||||
|
// 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#ifndef GRPC_NO_BINDER |
||||||
|
|
||||||
|
#include "src/core/ext/transport/binder/wire_format/binder_constants.h" |
||||||
|
|
||||||
|
ABSL_CONST_INIT const int FIRST_CALL_TRANSACTION = 0x00000001; |
||||||
|
ABSL_CONST_INIT const int LAST_CALL_TRANSACTION = 0x00FFFFFF; |
||||||
|
|
||||||
|
namespace grpc_binder { |
||||||
|
|
||||||
|
ABSL_CONST_INIT const int kFirstCallId = FIRST_CALL_TRANSACTION + 1000; |
||||||
|
|
||||||
|
} // namespace grpc_binder
|
||||||
|
#endif |
@ -0,0 +1,33 @@ |
|||||||
|
// 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#ifndef GRPC_NO_BINDER |
||||||
|
|
||||||
|
#include "src/core/ext/transport/binder/wire_format/transaction.h" |
||||||
|
|
||||||
|
namespace grpc_binder { |
||||||
|
|
||||||
|
ABSL_CONST_INIT const int kFlagPrefix = 0x1; |
||||||
|
ABSL_CONST_INIT const int kFlagMessageData = 0x2; |
||||||
|
ABSL_CONST_INIT const int kFlagSuffix = 0x4; |
||||||
|
ABSL_CONST_INIT const int kFlagOutOfBandClose = 0x8; |
||||||
|
ABSL_CONST_INIT const int kFlagExpectSingleMessage = 0x10; |
||||||
|
ABSL_CONST_INIT const int kFlagStatusDescription = 0x20; |
||||||
|
ABSL_CONST_INIT const int kFlagMessageDataIsParcelable = 0x40; |
||||||
|
ABSL_CONST_INIT const int kFlagMessageDataIsPartial = 0x80; |
||||||
|
|
||||||
|
} // namespace grpc_binder
|
||||||
|
#endif |
@ -0,0 +1,9 @@ |
|||||||
|
Support for resolving the scheme used by binder transport implementation. |
||||||
|
|
||||||
|
The URI's authority is required to be empty. |
||||||
|
|
||||||
|
The path is used as the identifiers of endpoint binder objects and the length |
||||||
|
limit of the identifier is the same as unix socket length limit. |
||||||
|
|
||||||
|
The length limit of the path should at least be 100 characters long. This is |
||||||
|
guaranteed by `static_assert` in the implementation. |
@ -0,0 +1,133 @@ |
|||||||
|
# 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("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
grpc_package( |
||||||
|
name = "test/core/transport/binder", |
||||||
|
visibility = "tests", |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_library( |
||||||
|
name = "mock_objects", |
||||||
|
testonly = 1, |
||||||
|
srcs = ["mock_objects.cc"], |
||||||
|
hdrs = ["mock_objects.h"], |
||||||
|
external_deps = [ |
||||||
|
"absl/memory", |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
language = "C++", |
||||||
|
deps = [ |
||||||
|
"//:grpc++_binder", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "wire_writer_test", |
||||||
|
srcs = ["wire_writer_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"absl/memory", |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
language = "C++", |
||||||
|
tags = ["no_test_ios"], |
||||||
|
uses_event_engine = False, |
||||||
|
uses_polling = False, |
||||||
|
deps = [ |
||||||
|
":mock_objects", |
||||||
|
"//:grpc++_binder", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "wire_reader_test", |
||||||
|
srcs = ["wire_reader_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"absl/memory", |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
language = "C++", |
||||||
|
tags = ["no_test_ios"], |
||||||
|
uses_event_engine = False, |
||||||
|
uses_polling = False, |
||||||
|
deps = [ |
||||||
|
":mock_objects", |
||||||
|
"//:grpc++_binder", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "transport_stream_receiver_test", |
||||||
|
srcs = ["transport_stream_receiver_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"absl/memory", |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
language = "C++", |
||||||
|
tags = ["no_test_ios"], |
||||||
|
uses_event_engine = False, |
||||||
|
uses_polling = False, |
||||||
|
deps = [ |
||||||
|
"//:grpc++_binder", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "binder_transport_test", |
||||||
|
srcs = ["binder_transport_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"absl/memory", |
||||||
|
"absl/strings", |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
language = "C++", |
||||||
|
tags = [ |
||||||
|
# To avoid `symbolizer buffer too small` warning of UBSAN |
||||||
|
"noubsan", |
||||||
|
"no_test_ios", |
||||||
|
], |
||||||
|
uses_event_engine = False, |
||||||
|
uses_polling = False, |
||||||
|
deps = [ |
||||||
|
":mock_objects", |
||||||
|
"//:grpc", |
||||||
|
"//:grpc++_binder", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "endpoint_binder_pool_test", |
||||||
|
srcs = ["endpoint_binder_pool_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"absl/memory", |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
language = "C++", |
||||||
|
tags = ["no_test_ios"], |
||||||
|
uses_event_engine = False, |
||||||
|
uses_polling = False, |
||||||
|
deps = [ |
||||||
|
":mock_objects", |
||||||
|
"//:grpc", |
||||||
|
"//:grpc++_binder", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,119 @@ |
|||||||
|
# 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("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
grpc_package( |
||||||
|
name = "test/core/transport/binder/end2end", |
||||||
|
visibility = "tests", |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_library( |
||||||
|
name = "fake_binder", |
||||||
|
testonly = 1, |
||||||
|
srcs = ["fake_binder.cc"], |
||||||
|
hdrs = ["fake_binder.h"], |
||||||
|
external_deps = [ |
||||||
|
"absl/log:log", |
||||||
|
"absl/memory", |
||||||
|
"absl/random", |
||||||
|
"absl/strings", |
||||||
|
"absl/strings:str_format", |
||||||
|
"absl/time", |
||||||
|
"absl/types:variant", |
||||||
|
], |
||||||
|
deps = [ |
||||||
|
"//:gpr", |
||||||
|
"//:grpc++_binder", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "fake_binder_test", |
||||||
|
srcs = ["fake_binder_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"absl/strings", |
||||||
|
"absl/time", |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
language = "C++", |
||||||
|
tags = ["no_test_ios"], |
||||||
|
uses_event_engine = False, |
||||||
|
uses_polling = False, |
||||||
|
deps = [ |
||||||
|
":fake_binder", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_library( |
||||||
|
name = "end2end_binder_channel", |
||||||
|
testonly = 1, |
||||||
|
srcs = ["testing_channel_create.cc"], |
||||||
|
hdrs = ["testing_channel_create.h"], |
||||||
|
external_deps = ["absl/log:check"], |
||||||
|
deps = [ |
||||||
|
":fake_binder", |
||||||
|
"//:grpc++_base", |
||||||
|
"//:grpc++_binder", |
||||||
|
"//:grpc_base", |
||||||
|
"//src/core:channel_args", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "end2end_binder_transport_test", |
||||||
|
srcs = ["end2end_binder_transport_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"absl/memory", |
||||||
|
"absl/time", |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
flaky = True, |
||||||
|
language = "C++", |
||||||
|
tags = [ |
||||||
|
# Flaky on windows |
||||||
|
"no_windows", |
||||||
|
"no_mac", |
||||||
|
"no_test_ios", |
||||||
|
|
||||||
|
# Known race between stream creation and cancellation |
||||||
|
"notsan", |
||||||
|
], |
||||||
|
deps = [ |
||||||
|
":end2end_binder_channel", |
||||||
|
":fake_binder", |
||||||
|
"//:grpc++_binder", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
"//test/cpp/end2end:test_service_impl", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "binder_server_test", |
||||||
|
srcs = ["binder_server_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
tags = ["no_test_ios"], |
||||||
|
deps = [ |
||||||
|
"//:grpc++", |
||||||
|
"//:grpc++_binder", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
"//test/core/transport/binder/end2end:fake_binder", |
||||||
|
"//test/cpp/end2end:test_service_impl", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,101 @@ |
|||||||
|
# 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("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_package", "grpc_proto_library") |
||||||
|
load("//test/core/test_util:grpc_fuzzer.bzl", "grpc_proto_fuzzer") |
||||||
|
|
||||||
|
grpc_package( |
||||||
|
name = "test/core/transport/binder/end2end/fuzzers", |
||||||
|
features = [ |
||||||
|
"layering_check", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
# Protobuf messages for generating inputs. We manually define proto |
||||||
|
# library rule here so the same proto file can be shared between multiple |
||||||
|
# grpc_proto_fuzzer targets |
||||||
|
grpc_proto_library( |
||||||
|
name = "binder_transport_fuzzer_proto", |
||||||
|
srcs = ["binder_transport_fuzzer.proto"], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_cc_library( |
||||||
|
name = "fuzzer_utils", |
||||||
|
srcs = ["fuzzer_utils.cc"], |
||||||
|
external_deps = [ |
||||||
|
"absl/log:check", |
||||||
|
"absl/log:log", |
||||||
|
], |
||||||
|
language = "c++", |
||||||
|
public_hdrs = ["fuzzer_utils.h"], |
||||||
|
deps = [ |
||||||
|
"binder_transport_fuzzer_proto", |
||||||
|
"//:gpr", |
||||||
|
"//:grpc++", |
||||||
|
"//:grpc++_base", |
||||||
|
"//:grpc_base", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_proto_fuzzer( |
||||||
|
name = "binder_transport_client_fuzzer", |
||||||
|
srcs = [ |
||||||
|
"client_fuzzer.cc", |
||||||
|
], |
||||||
|
corpus = "binder_transport_client_fuzzer_corpus", |
||||||
|
external_deps = ["absl/log:check"], |
||||||
|
owner = "binder", |
||||||
|
proto = "client.proto", |
||||||
|
tags = [ |
||||||
|
"no_mac", |
||||||
|
"no_windows", |
||||||
|
], |
||||||
|
deps = [ |
||||||
|
"binder_transport_fuzzer_proto", |
||||||
|
":fuzzer_utils", |
||||||
|
"//:gpr", |
||||||
|
"//:grpc++", |
||||||
|
"//:grpc++_base", |
||||||
|
"//:grpc_base", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
grpc_proto_fuzzer( |
||||||
|
name = "binder_transport_server_fuzzer", |
||||||
|
srcs = [ |
||||||
|
"server_fuzzer.cc", |
||||||
|
], |
||||||
|
corpus = "binder_transport_server_fuzzer_corpus", |
||||||
|
external_deps = ["absl/log:check"], |
||||||
|
owner = "binder", |
||||||
|
proto = "server.proto", |
||||||
|
tags = [ |
||||||
|
"no_mac", |
||||||
|
"no_windows", |
||||||
|
], |
||||||
|
deps = [ |
||||||
|
"binder_transport_fuzzer_proto", |
||||||
|
":fuzzer_utils", |
||||||
|
"//:gpr", |
||||||
|
"//:grpc++", |
||||||
|
"//:grpc++_base", |
||||||
|
"//:grpc_base", |
||||||
|
"//src/core:slice", |
||||||
|
"//test/core/test_util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,81 @@ |
|||||||
|
// 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. |
||||||
|
|
||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
package binder_transport_fuzzer; |
||||||
|
|
||||||
|
message Binder {} |
||||||
|
|
||||||
|
message Value { |
||||||
|
oneof data_type { |
||||||
|
int32 i32 = 1; |
||||||
|
int64 i64 = 2; |
||||||
|
bytes byte_array = 3; |
||||||
|
// Strings in Parcel could also contain non UTF-8 data so we use bytes |
||||||
|
// to represent string here |
||||||
|
bytes str = 4; |
||||||
|
Binder binder = 5; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
message Parcel { |
||||||
|
repeated Value values = 1; |
||||||
|
|
||||||
|
// Simulates the return value of AParcel_getDataSize |
||||||
|
// (The value generated by protobuf libprotobuf-mutator might not always make sense |
||||||
|
// but the transport implementation should handle that) |
||||||
|
int32 data_size = 2; |
||||||
|
} |
||||||
|
|
||||||
|
enum TransactionCode { |
||||||
|
INVALID = 0; |
||||||
|
SETUP_TRANSPORT = 1; |
||||||
|
SHUTDOWN_TRANSPORT = 2; |
||||||
|
ACKNOWLEDGE_BYTES = 3; |
||||||
|
PING = 4; |
||||||
|
PING_RESPONSE = 5; |
||||||
|
} |
||||||
|
|
||||||
|
message Transaction { |
||||||
|
TransactionCode code = 1; |
||||||
|
int32 uid = 2; |
||||||
|
Parcel parcel = 3; |
||||||
|
} |
||||||
|
|
||||||
|
// Special parcel that used for setting up transport. |
||||||
|
// TODO(mingcl): Consider also fuzzing the setup transport code path |
||||||
|
message SetupTransportParcel { |
||||||
|
int32 version = 1; |
||||||
|
|
||||||
|
// Simulates the return value of AParcel_getDataSize |
||||||
|
// (The value generated by protobuf libprotobuf-mutator might not always make sense |
||||||
|
// but the transport implementation should handle that) |
||||||
|
int32 data_size = 2; |
||||||
|
} |
||||||
|
|
||||||
|
message SetupTransportTransaction { |
||||||
|
int32 uid = 1; |
||||||
|
SetupTransportParcel parcel = 2; |
||||||
|
} |
||||||
|
|
||||||
|
message IncomingParcels { |
||||||
|
SetupTransportTransaction setup_transport_transaction = 1; |
||||||
|
repeated Transaction transactions = 2; |
||||||
|
} |
||||||
|
|
||||||
|
message Input { |
||||||
|
IncomingParcels incoming_parcels = 1; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,17 @@ |
|||||||
|
// 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. |
||||||
|
|
||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
package binder_transport_fuzzer; |
@ -0,0 +1,157 @@ |
|||||||
|
// 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 "test/core/transport/binder/end2end/fuzzers/fuzzer_utils.h" |
||||||
|
|
||||||
|
#include "absl/log/check.h" |
||||||
|
#include "absl/log/log.h" |
||||||
|
|
||||||
|
namespace grpc_binder { |
||||||
|
namespace fuzzing { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
std::thread* g_fuzzing_thread = nullptr; |
||||||
|
|
||||||
|
template <typename... Args> |
||||||
|
void CreateFuzzingThread(Args&&... args) { |
||||||
|
CHECK_EQ(g_fuzzing_thread, nullptr); |
||||||
|
g_fuzzing_thread = new std::thread(std::forward<Args>(args)...); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void JoinFuzzingThread() { |
||||||
|
if (g_fuzzing_thread) { |
||||||
|
g_fuzzing_thread->join(); |
||||||
|
delete g_fuzzing_thread; |
||||||
|
g_fuzzing_thread = nullptr; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int32_t ReadableParcelForFuzzing::GetDataSize() const { |
||||||
|
return parcel_data_size_; |
||||||
|
} |
||||||
|
|
||||||
|
absl::Status ReadableParcelForFuzzing::ReadInt32(int32_t* data) { |
||||||
|
if (consumed_data_size_ >= kParcelDataSizeLimit) { |
||||||
|
return absl::InternalError("Parcel size limit exceeds"); |
||||||
|
} |
||||||
|
if (values_.empty() || !values_.front().has_i32()) { |
||||||
|
return absl::InternalError("error"); |
||||||
|
} |
||||||
|
*data = values_.front().i32(); |
||||||
|
values_.pop(); |
||||||
|
consumed_data_size_ += sizeof(int32_t); |
||||||
|
return absl::OkStatus(); |
||||||
|
} |
||||||
|
|
||||||
|
absl::Status ReadableParcelForFuzzing::ReadInt64(int64_t* data) { |
||||||
|
if (consumed_data_size_ >= kParcelDataSizeLimit) { |
||||||
|
return absl::InternalError("Parcel size limit exceeds"); |
||||||
|
} |
||||||
|
if (values_.empty() || !values_.front().has_i64()) { |
||||||
|
return absl::InternalError("error"); |
||||||
|
} |
||||||
|
*data = values_.front().i64(); |
||||||
|
values_.pop(); |
||||||
|
consumed_data_size_ += sizeof(int64_t); |
||||||
|
return absl::OkStatus(); |
||||||
|
} |
||||||
|
|
||||||
|
absl::Status ReadableParcelForFuzzing::ReadBinder( |
||||||
|
std::unique_ptr<Binder>* binder) { |
||||||
|
if (consumed_data_size_ >= kParcelDataSizeLimit) { |
||||||
|
return absl::InternalError("Parcel size limit exceeds"); |
||||||
|
} |
||||||
|
if (values_.empty() || !values_.front().has_binder()) { |
||||||
|
return absl::InternalError("error"); |
||||||
|
} |
||||||
|
*binder = std::make_unique<BinderForFuzzing>(); |
||||||
|
values_.pop(); |
||||||
|
consumed_data_size_ += sizeof(void*); |
||||||
|
return absl::OkStatus(); |
||||||
|
} |
||||||
|
|
||||||
|
absl::Status ReadableParcelForFuzzing::ReadByteArray(std::string* data) { |
||||||
|
if (consumed_data_size_ >= kParcelDataSizeLimit) { |
||||||
|
return absl::InternalError("Parcel size limit exceeds"); |
||||||
|
} |
||||||
|
if (values_.empty() || !values_.front().has_byte_array()) { |
||||||
|
return absl::InternalError("error"); |
||||||
|
} |
||||||
|
*data = values_.front().byte_array(); |
||||||
|
values_.pop(); |
||||||
|
consumed_data_size_ += data->size(); |
||||||
|
return absl::OkStatus(); |
||||||
|
} |
||||||
|
|
||||||
|
absl::Status ReadableParcelForFuzzing::ReadString(std::string* data) { |
||||||
|
if (consumed_data_size_ >= kParcelDataSizeLimit) { |
||||||
|
return absl::InternalError("Parcel size limit exceeds"); |
||||||
|
} |
||||||
|
if (values_.empty() || !values_.front().has_str()) { |
||||||
|
return absl::InternalError("error"); |
||||||
|
} |
||||||
|
*data = values_.front().str(); |
||||||
|
values_.pop(); |
||||||
|
consumed_data_size_ += data->size(); |
||||||
|
return absl::OkStatus(); |
||||||
|
} |
||||||
|
|
||||||
|
void FuzzingLoop( |
||||||
|
binder_transport_fuzzer::IncomingParcels incoming_parcels, |
||||||
|
grpc_core::RefCountedPtr<grpc_binder::WireReader> wire_reader_ref, |
||||||
|
grpc_binder::TransactionReceiver::OnTransactCb callback) { |
||||||
|
{ |
||||||
|
// Send SETUP_TRANSPORT request.
|
||||||
|
std::unique_ptr<grpc_binder::ReadableParcel> parcel = |
||||||
|
std::make_unique<ReadableParcelForFuzzing>( |
||||||
|
incoming_parcels.setup_transport_transaction().parcel()); |
||||||
|
callback(static_cast<transaction_code_t>( |
||||||
|
grpc_binder::BinderTransportTxCode::SETUP_TRANSPORT), |
||||||
|
parcel.get(), |
||||||
|
/*uid=*/incoming_parcels.setup_transport_transaction().uid()) |
||||||
|
.IgnoreError(); |
||||||
|
} |
||||||
|
for (const auto& tx_iter : incoming_parcels.transactions()) { |
||||||
|
transaction_code_t tx_code = tx_iter.code(); |
||||||
|
std::unique_ptr<grpc_binder::ReadableParcel> parcel = |
||||||
|
std::make_unique<ReadableParcelForFuzzing>(tx_iter.parcel()); |
||||||
|
callback(tx_code, parcel.get(), |
||||||
|
/*uid=*/tx_iter.uid()) |
||||||
|
.IgnoreError(); |
||||||
|
} |
||||||
|
wire_reader_ref = nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
TransactionReceiverForFuzzing::TransactionReceiverForFuzzing( |
||||||
|
binder_transport_fuzzer::IncomingParcels incoming_parcels, |
||||||
|
grpc_core::RefCountedPtr<WireReader> wire_reader_ref, |
||||||
|
TransactionReceiver::OnTransactCb cb) { |
||||||
|
LOG(INFO) << "Construct TransactionReceiverForFuzzing"; |
||||||
|
CreateFuzzingThread(FuzzingLoop, std::move(incoming_parcels), |
||||||
|
std::move(wire_reader_ref), std::move(cb)); |
||||||
|
} |
||||||
|
|
||||||
|
std::unique_ptr<TransactionReceiver> BinderForFuzzing::ConstructTxReceiver( |
||||||
|
grpc_core::RefCountedPtr<WireReader> wire_reader_ref, |
||||||
|
TransactionReceiver::OnTransactCb cb) const { |
||||||
|
auto tx_receiver = std::make_unique<TransactionReceiverForFuzzing>( |
||||||
|
incoming_parcels_, wire_reader_ref, cb); |
||||||
|
return tx_receiver; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace fuzzing
|
||||||
|
} // namespace grpc_binder
|
@ -0,0 +1,17 @@ |
|||||||
|
// 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. |
||||||
|
|
||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
package binder_transport_fuzzer; |
@ -0,0 +1,55 @@ |
|||||||
|
// 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 "test/core/transport/binder/mock_objects.h" |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#include "absl/memory/memory.h" |
||||||
|
|
||||||
|
namespace grpc_binder { |
||||||
|
|
||||||
|
using ::testing::Return; |
||||||
|
|
||||||
|
MockReadableParcel::MockReadableParcel() { |
||||||
|
ON_CALL(*this, ReadBinder).WillByDefault([](std::unique_ptr<Binder>* binder) { |
||||||
|
*binder = std::make_unique<MockBinder>(); |
||||||
|
return absl::OkStatus(); |
||||||
|
}); |
||||||
|
ON_CALL(*this, ReadInt32).WillByDefault(Return(absl::OkStatus())); |
||||||
|
ON_CALL(*this, ReadByteArray).WillByDefault(Return(absl::OkStatus())); |
||||||
|
ON_CALL(*this, ReadString).WillByDefault(Return(absl::OkStatus())); |
||||||
|
} |
||||||
|
|
||||||
|
MockWritableParcel::MockWritableParcel() { |
||||||
|
ON_CALL(*this, WriteInt32).WillByDefault(Return(absl::OkStatus())); |
||||||
|
ON_CALL(*this, WriteBinder).WillByDefault(Return(absl::OkStatus())); |
||||||
|
ON_CALL(*this, WriteString).WillByDefault(Return(absl::OkStatus())); |
||||||
|
ON_CALL(*this, WriteByteArray).WillByDefault(Return(absl::OkStatus())); |
||||||
|
} |
||||||
|
|
||||||
|
MockBinder::MockBinder() { |
||||||
|
ON_CALL(*this, PrepareTransaction).WillByDefault(Return(absl::OkStatus())); |
||||||
|
ON_CALL(*this, Transact).WillByDefault(Return(absl::OkStatus())); |
||||||
|
ON_CALL(*this, GetWritableParcel).WillByDefault(Return(&mock_input_)); |
||||||
|
ON_CALL(*this, ConstructTxReceiver) |
||||||
|
.WillByDefault( |
||||||
|
[this](grpc_core::RefCountedPtr<WireReader> /*wire_reader_ref*/, |
||||||
|
TransactionReceiver::OnTransactCb cb) { |
||||||
|
return std::make_unique<MockTransactionReceiver>( |
||||||
|
cb, BinderTransportTxCode::SETUP_TRANSPORT, &mock_output_); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_binder
|
@ -0,0 +1,121 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_TEST_CORE_TRANSPORT_BINDER_MOCK_OBJECTS_H |
||||||
|
#define GRPC_TEST_CORE_TRANSPORT_BINDER_MOCK_OBJECTS_H |
||||||
|
|
||||||
|
#include <gmock/gmock.h> |
||||||
|
|
||||||
|
#include "src/core/ext/transport/binder/utils/transport_stream_receiver.h" |
||||||
|
#include "src/core/ext/transport/binder/wire_format/binder.h" |
||||||
|
#include "src/core/ext/transport/binder/wire_format/binder_constants.h" |
||||||
|
#include "src/core/ext/transport/binder/wire_format/wire_reader.h" |
||||||
|
#include "src/core/ext/transport/binder/wire_format/wire_writer.h" |
||||||
|
|
||||||
|
namespace grpc_binder { |
||||||
|
|
||||||
|
class MockWritableParcel : public WritableParcel { |
||||||
|
public: |
||||||
|
MOCK_METHOD(int32_t, GetDataSize, (), (const, override)); |
||||||
|
MOCK_METHOD(absl::Status, WriteInt32, (int32_t), (override)); |
||||||
|
MOCK_METHOD(absl::Status, WriteInt64, (int64_t), (override)); |
||||||
|
MOCK_METHOD(absl::Status, WriteBinder, (HasRawBinder*), (override)); |
||||||
|
MOCK_METHOD(absl::Status, WriteString, (absl::string_view), (override)); |
||||||
|
MOCK_METHOD(absl::Status, WriteByteArray, (const int8_t*, int32_t), |
||||||
|
(override)); |
||||||
|
|
||||||
|
MockWritableParcel(); |
||||||
|
}; |
||||||
|
|
||||||
|
class MockReadableParcel : public ReadableParcel { |
||||||
|
public: |
||||||
|
MOCK_METHOD(int32_t, GetDataSize, (), (const, override)); |
||||||
|
MOCK_METHOD(absl::Status, ReadInt32, (int32_t*), (override)); |
||||||
|
MOCK_METHOD(absl::Status, ReadInt64, (int64_t*), (override)); |
||||||
|
MOCK_METHOD(absl::Status, ReadBinder, (std::unique_ptr<Binder>*), (override)); |
||||||
|
MOCK_METHOD(absl::Status, ReadByteArray, (std::string*), (override)); |
||||||
|
MOCK_METHOD(absl::Status, ReadString, (std::string*), (override)); |
||||||
|
|
||||||
|
MockReadableParcel(); |
||||||
|
}; |
||||||
|
|
||||||
|
class MockBinder : public Binder { |
||||||
|
public: |
||||||
|
MOCK_METHOD(void, Initialize, (), (override)); |
||||||
|
MOCK_METHOD(absl::Status, PrepareTransaction, (), (override)); |
||||||
|
MOCK_METHOD(absl::Status, Transact, (BinderTransportTxCode), (override)); |
||||||
|
MOCK_METHOD(WritableParcel*, GetWritableParcel, (), (const, override)); |
||||||
|
MOCK_METHOD(std::unique_ptr<TransactionReceiver>, ConstructTxReceiver, |
||||||
|
(grpc_core::RefCountedPtr<WireReader>, |
||||||
|
TransactionReceiver::OnTransactCb), |
||||||
|
(const, override)); |
||||||
|
MOCK_METHOD(void*, GetRawBinder, (), (override)); |
||||||
|
|
||||||
|
MockBinder(); |
||||||
|
MockWritableParcel& GetWriter() { return mock_input_; } |
||||||
|
MockReadableParcel& GetReader() { return mock_output_; } |
||||||
|
|
||||||
|
private: |
||||||
|
MockWritableParcel mock_input_; |
||||||
|
MockReadableParcel mock_output_; |
||||||
|
}; |
||||||
|
|
||||||
|
// TODO(waynetu): Implement transaction injection later for more thorough
|
||||||
|
// testing.
|
||||||
|
class MockTransactionReceiver : public TransactionReceiver { |
||||||
|
public: |
||||||
|
explicit MockTransactionReceiver(OnTransactCb transact_cb, |
||||||
|
BinderTransportTxCode code, |
||||||
|
MockReadableParcel* output) { |
||||||
|
if (code == BinderTransportTxCode::SETUP_TRANSPORT) { |
||||||
|
EXPECT_CALL(*output, ReadInt32).WillOnce([](int32_t* version) { |
||||||
|
*version = 1; |
||||||
|
return absl::OkStatus(); |
||||||
|
}); |
||||||
|
} |
||||||
|
transact_cb(static_cast<transaction_code_t>(code), output, /*uid=*/0) |
||||||
|
.IgnoreError(); |
||||||
|
} |
||||||
|
|
||||||
|
MOCK_METHOD(void*, GetRawBinder, (), (override)); |
||||||
|
}; |
||||||
|
|
||||||
|
class MockWireWriter : public WireWriter { |
||||||
|
public: |
||||||
|
MOCK_METHOD(absl::Status, RpcCall, (std::unique_ptr<Transaction>), |
||||||
|
(override)); |
||||||
|
MOCK_METHOD(absl::Status, SendAck, (int64_t), (override)); |
||||||
|
MOCK_METHOD(void, OnAckReceived, (int64_t), (override)); |
||||||
|
}; |
||||||
|
|
||||||
|
class MockTransportStreamReceiver : public TransportStreamReceiver { |
||||||
|
public: |
||||||
|
MOCK_METHOD(void, RegisterRecvInitialMetadata, |
||||||
|
(StreamIdentifier, InitialMetadataCallbackType), (override)); |
||||||
|
MOCK_METHOD(void, RegisterRecvMessage, |
||||||
|
(StreamIdentifier, MessageDataCallbackType), (override)); |
||||||
|
MOCK_METHOD(void, RegisterRecvTrailingMetadata, |
||||||
|
(StreamIdentifier, TrailingMetadataCallbackType), (override)); |
||||||
|
MOCK_METHOD(void, NotifyRecvInitialMetadata, |
||||||
|
(StreamIdentifier, absl::StatusOr<Metadata>), (override)); |
||||||
|
MOCK_METHOD(void, NotifyRecvMessage, |
||||||
|
(StreamIdentifier, absl::StatusOr<std::string>), (override)); |
||||||
|
MOCK_METHOD(void, NotifyRecvTrailingMetadata, |
||||||
|
(StreamIdentifier, absl::StatusOr<Metadata>, int), (override)); |
||||||
|
MOCK_METHOD(void, CancelStream, (StreamIdentifier), (override)); |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_binder
|
||||||
|
|
||||||
|
#endif // GRPC_TEST_CORE_TRANSPORT_BINDER_MOCK_OBJECTS_H
|
@ -0,0 +1,40 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
# 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. |
||||||
|
|
||||||
|
set -ex |
||||||
|
|
||||||
|
echo $ANDROID_HOME |
||||||
|
echo $ANDROID_NDK_HOME |
||||||
|
|
||||||
|
# Android platforms only works with Bazel >= 7.0 |
||||||
|
export OVERRIDE_BAZEL_VERSION=7.3.1 |
||||||
|
|
||||||
|
python3 tools/run_tests/python_utils/bazel_report_helper.py --report_path bazel_binder_example_app |
||||||
|
bazel_binder_example_app/bazel_wrapper \ |
||||||
|
--bazelrc=tools/remote_build/include/test_locally_with_resultstore_results.bazelrc \ |
||||||
|
build \ |
||||||
|
--extra_toolchains=@androidndk//:all \ |
||||||
|
--android_platforms=//bazel/platforms/android:x86_64,//bazel/platforms/android:armeabi-v7a,//bazel/platforms/android:arm64-v8a \ |
||||||
|
//examples/android/binder/java/io/grpc/binder/cpp/exampleclient: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 |
||||||
|
python3 tools/run_tests/python_utils/bazel_report_helper.py --report_path bazel_binder_connection_helper |
||||||
|
bazel_binder_connection_helper/bazel_wrapper \ |
||||||
|
--bazelrc=tools/remote_build/include/test_locally_with_resultstore_results.bazelrc \ |
||||||
|
build \ |
||||||
|
--define=use_strict_warning=true \ |
||||||
|
@binder_transport_android_helper//io/grpc/binder/cpp:connection_helper |
Loading…
Reference in new issue