1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <grpc/support/port_platform.h>
16
17 #include "src/core/ext/transport/binder/client/jni_utils.h"
18
19 #ifndef GRPC_NO_BINDER
20
21 #include <grpc/support/log.h>
22
23 #include "src/core/lib/gprpp/crash.h"
24
25 #if defined(ANDROID) || defined(__ANDROID__)
26
27 namespace grpc_binder {
28
FindNativeConnectionHelper(JNIEnv * env)29 jclass FindNativeConnectionHelper(JNIEnv* env) {
30 return FindNativeConnectionHelper(
31 env, [env](std::string cl) { return env->FindClass(cl.c_str()); });
32 }
33
FindNativeConnectionHelper(JNIEnv * env,std::function<void * (std::string)> class_finder)34 jclass FindNativeConnectionHelper(
35 JNIEnv* env, std::function<void*(std::string)> class_finder) {
36 auto do_find = [env, class_finder]() {
37 jclass cl = static_cast<jclass>(
38 class_finder("io/grpc/binder/cpp/NativeConnectionHelper"));
39 if (cl == nullptr) {
40 return cl;
41 }
42 jclass global_cl = static_cast<jclass>(env->NewGlobalRef(cl));
43 env->DeleteLocalRef(cl);
44 GPR_ASSERT(global_cl != nullptr);
45 return global_cl;
46 };
47 static jclass connection_helper_class = do_find();
48 if (connection_helper_class != nullptr) {
49 return connection_helper_class;
50 }
51 // Some possible reasons:
52 // * There is no Java class in the call stack and this is not invoked
53 // from JNI_OnLoad
54 // * The APK does not correctly depends on the helper class, or the
55 // class get shrinked
56 gpr_log(GPR_ERROR,
57 "Cannot find binder transport Java helper class. Did you invoke "
58 "grpc::experimental::InitializeBinderChannelJavaClass correctly "
59 "beforehand? Did the APK correctly include the connection helper "
60 "class (i.e depends on build target "
61 "src/core/ext/transport/binder/java/io/grpc/binder/"
62 "cpp:connection_helper) ?");
63 // TODO(mingcl): Maybe it is worth to try again so the failure can be fixed
64 // by invoking this function again at a different thread.
65 return nullptr;
66 }
67
TryEstablishConnection(JNIEnv * env,jobject application,absl::string_view pkg,absl::string_view cls,absl::string_view action_name,absl::string_view conn_id)68 void TryEstablishConnection(JNIEnv* env, jobject application,
69 absl::string_view pkg, absl::string_view cls,
70 absl::string_view action_name,
71 absl::string_view conn_id) {
72 std::string method = "tryEstablishConnection";
73 std::string type =
74 "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/"
75 "lang/String;Ljava/lang/String;)V";
76
77 jclass cl = FindNativeConnectionHelper(env);
78 if (cl == nullptr) {
79 return;
80 }
81
82 jmethodID mid = env->GetStaticMethodID(cl, method.c_str(), type.c_str());
83 if (mid == nullptr) {
84 gpr_log(GPR_ERROR, "No method id %s", method.c_str());
85 }
86
87 env->CallStaticVoidMethod(cl, mid, application,
88 env->NewStringUTF(std::string(pkg).c_str()),
89 env->NewStringUTF(std::string(cls).c_str()),
90 env->NewStringUTF(std::string(action_name).c_str()),
91 env->NewStringUTF(std::string(conn_id).c_str()));
92 }
93
TryEstablishConnectionWithUri(JNIEnv * env,jobject application,absl::string_view uri,absl::string_view conn_id)94 void TryEstablishConnectionWithUri(JNIEnv* env, jobject application,
95 absl::string_view uri,
96 absl::string_view conn_id) {
97 std::string method = "tryEstablishConnectionWithUri";
98 std::string type =
99 "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V";
100
101 jclass cl = FindNativeConnectionHelper(env);
102 if (cl == nullptr) {
103 return;
104 }
105
106 jmethodID mid = env->GetStaticMethodID(cl, method.c_str(), type.c_str());
107 if (mid == nullptr) {
108 gpr_log(GPR_ERROR, "No method id %s", method.c_str());
109 }
110
111 env->CallStaticVoidMethod(cl, mid, application,
112 env->NewStringUTF(std::string(uri).c_str()),
113 env->NewStringUTF(std::string(conn_id).c_str()));
114 }
115
IsSignatureMatch(JNIEnv * env,jobject context,int uid1,int uid2)116 bool IsSignatureMatch(JNIEnv* env, jobject context, int uid1, int uid2) {
117 const std::string method = "isSignatureMatch";
118 const std::string type = "(Landroid/content/Context;II)Z";
119
120 jclass cl = FindNativeConnectionHelper(env);
121 if (cl == nullptr) {
122 return false;
123 }
124
125 jmethodID mid = env->GetStaticMethodID(cl, method.c_str(), type.c_str());
126 if (mid == nullptr) {
127 gpr_log(GPR_ERROR, "No method id %s", method.c_str());
128 }
129
130 jboolean result = env->CallStaticBooleanMethod(cl, mid, context, uid1, uid2);
131 return result == JNI_TRUE;
132 }
133
134 } // namespace grpc_binder
135
136 #endif
137 #endif
138