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/utils/ndk_binder.h"
18 
19 #ifndef GRPC_NO_BINDER
20 
21 #ifdef GPR_SUPPORT_BINDER_TRANSPORT
22 
23 #include <dlfcn.h>
24 
25 #include <grpc/support/log.h>
26 
27 #include "src/core/lib/gprpp/crash.h"
28 #include "src/core/lib/gprpp/sync.h"
29 
30 namespace {
GetNdkBinderHandle()31 void* GetNdkBinderHandle() {
32   // TODO(mingcl): Consider using RTLD_NOLOAD to check if it is already loaded
33   // first
34   static void* handle = dlopen("libbinder_ndk.so", RTLD_LAZY);
35   if (handle == nullptr) {
36     gpr_log(
37         GPR_ERROR,
38         "Cannot open libbinder_ndk.so. Does this device support API level 29?");
39     GPR_ASSERT(0);
40   }
41   return handle;
42 }
43 
44 JavaVM* g_jvm = nullptr;
45 grpc_core::Mutex g_jvm_mu;
46 
47 // Whether the thread has already attached to JVM (this is to prevent
48 // repeated attachment in `AttachJvm()`)
49 thread_local bool g_is_jvm_attached = false;
50 
SetJvm(JNIEnv * env)51 void SetJvm(JNIEnv* env) {
52   // OK to lock here since this function will only be called once for each
53   // connection.
54   grpc_core::MutexLock lock(&g_jvm_mu);
55   if (g_jvm != nullptr) {
56     return;
57   }
58   JavaVM* jvm = nullptr;
59   jint error = env->GetJavaVM(&jvm);
60   if (error != JNI_OK) {
61     gpr_log(GPR_ERROR, "Failed to get JVM");
62   }
63   g_jvm = jvm;
64   gpr_log(GPR_INFO, "JVM cached");
65 }
66 
67 // `SetJvm` need to be called in the process before `AttachJvm`. This is always
68 // the case because one of `AIBinder_fromJavaBinder`/`AIBinder_toJavaBinder`
69 // will be called before we actually uses the binder. Return `false` if not able
70 // to attach to JVM. Return `true` if JVM is attached (or already attached).
AttachJvm()71 bool AttachJvm() {
72   if (g_is_jvm_attached) {
73     return true;
74   }
75   // Note: The following code would be run at most once per thread.
76   grpc_core::MutexLock lock(&g_jvm_mu);
77   if (g_jvm == nullptr) {
78     gpr_log(GPR_ERROR, "JVM not cached yet");
79     return false;
80   }
81   JNIEnv* env_unused;
82   // Note that attach a thread that is already attached is a no-op, so it is
83   // fine to call this again if the thread has already been attached by other.
84   g_jvm->AttachCurrentThread(&env_unused, /* thr_args= */ nullptr);
85   gpr_log(GPR_INFO, "JVM attached successfully");
86   g_is_jvm_attached = true;
87   return true;
88 }
89 
90 }  // namespace
91 
92 namespace grpc_binder {
93 namespace ndk_util {
94 
95 // Helper macro to obtain the function pointer corresponding to the name
96 #define FORWARD(name)                                                  \
97   typedef decltype(&name) func_type;                                   \
98   static func_type ptr =                                               \
99       reinterpret_cast<func_type>(dlsym(GetNdkBinderHandle(), #name)); \
100   if (ptr == nullptr) {                                                \
101     gpr_log(GPR_ERROR,                                                 \
102             "dlsym failed. Cannot find %s in libbinder_ndk.so. "       \
103             "BinderTransport requires API level >= 33",                \
104             #name);                                                    \
105     GPR_ASSERT(0);                                                     \
106   }                                                                    \
107   return ptr
108 
AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class * clazz)109 void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) {
110   FORWARD(AIBinder_Class_disableInterfaceTokenHeader)(clazz);
111 }
112 
AIBinder_getUserData(AIBinder * binder)113 void* AIBinder_getUserData(AIBinder* binder) {
114   FORWARD(AIBinder_getUserData)(binder);
115 }
116 
AIBinder_getCallingUid()117 uid_t AIBinder_getCallingUid() { FORWARD(AIBinder_getCallingUid)(); }
118 
AIBinder_fromJavaBinder(JNIEnv * env,jobject binder)119 AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) {
120   SetJvm(env);
121   FORWARD(AIBinder_fromJavaBinder)(env, binder);
122 }
123 
AIBinder_Class_define(const char * interfaceDescriptor,AIBinder_Class_onCreate onCreate,AIBinder_Class_onDestroy onDestroy,AIBinder_Class_onTransact onTransact)124 AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
125                                       AIBinder_Class_onCreate onCreate,
126                                       AIBinder_Class_onDestroy onDestroy,
127                                       AIBinder_Class_onTransact onTransact) {
128   FORWARD(AIBinder_Class_define)
129   (interfaceDescriptor, onCreate, onDestroy, onTransact);
130 }
131 
AIBinder_new(const AIBinder_Class * clazz,void * args)132 AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
133   FORWARD(AIBinder_new)(clazz, args);
134 }
135 
AIBinder_associateClass(AIBinder * binder,const AIBinder_Class * clazz)136 bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) {
137   FORWARD(AIBinder_associateClass)(binder, clazz);
138 }
139 
AIBinder_incStrong(AIBinder * binder)140 void AIBinder_incStrong(AIBinder* binder) {
141   FORWARD(AIBinder_incStrong)(binder);
142 }
143 
AIBinder_decStrong(AIBinder * binder)144 void AIBinder_decStrong(AIBinder* binder) {
145   FORWARD(AIBinder_decStrong)(binder);
146 }
147 
AIBinder_transact(AIBinder * binder,transaction_code_t code,AParcel ** in,AParcel ** out,binder_flags_t flags)148 binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code,
149                                   AParcel** in, AParcel** out,
150                                   binder_flags_t flags) {
151   if (!AttachJvm()) {
152     gpr_log(GPR_ERROR, "failed to attach JVM. AIBinder_transact might fail.");
153   }
154   FORWARD(AIBinder_transact)(binder, code, in, out, flags);
155 }
156 
AParcel_readByteArray(const AParcel * parcel,void * arrayData,AParcel_byteArrayAllocator allocator)157 binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
158                                       AParcel_byteArrayAllocator allocator) {
159   FORWARD(AParcel_readByteArray)(parcel, arrayData, allocator);
160 }
161 
AParcel_delete(AParcel * parcel)162 void AParcel_delete(AParcel* parcel) { FORWARD(AParcel_delete)(parcel); }
AParcel_getDataSize(const AParcel * parcel)163 int32_t AParcel_getDataSize(const AParcel* parcel) {
164   FORWARD(AParcel_getDataSize)(parcel);
165 }
166 
AParcel_writeInt32(AParcel * parcel,int32_t value)167 binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) {
168   FORWARD(AParcel_writeInt32)(parcel, value);
169 }
170 
AParcel_writeInt64(AParcel * parcel,int64_t value)171 binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) {
172   FORWARD(AParcel_writeInt64)(parcel, value);
173 }
174 
AParcel_writeStrongBinder(AParcel * parcel,AIBinder * binder)175 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
176   FORWARD(AParcel_writeStrongBinder)(parcel, binder);
177 }
178 
AParcel_writeString(AParcel * parcel,const char * string,int32_t length)179 binder_status_t AParcel_writeString(AParcel* parcel, const char* string,
180                                     int32_t length) {
181   FORWARD(AParcel_writeString)(parcel, string, length);
182 }
183 
AParcel_readInt32(const AParcel * parcel,int32_t * value)184 binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) {
185   FORWARD(AParcel_readInt32)(parcel, value);
186 }
187 
AParcel_readInt64(const AParcel * parcel,int64_t * value)188 binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) {
189   FORWARD(AParcel_readInt64)(parcel, value);
190 }
191 
AParcel_readString(const AParcel * parcel,void * stringData,AParcel_stringAllocator allocator)192 binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
193                                    AParcel_stringAllocator allocator) {
194   FORWARD(AParcel_readString)(parcel, stringData, allocator);
195 }
196 
AParcel_readStrongBinder(const AParcel * parcel,AIBinder ** binder)197 binder_status_t AParcel_readStrongBinder(const AParcel* parcel,
198                                          AIBinder** binder) {
199   FORWARD(AParcel_readStrongBinder)(parcel, binder);
200 }
201 
AParcel_writeByteArray(AParcel * parcel,const int8_t * arrayData,int32_t length)202 binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData,
203                                        int32_t length) {
204   FORWARD(AParcel_writeByteArray)(parcel, arrayData, length);
205 }
206 
AIBinder_prepareTransaction(AIBinder * binder,AParcel ** in)207 binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
208   FORWARD(AIBinder_prepareTransaction)(binder, in);
209 }
210 
AIBinder_toJavaBinder(JNIEnv * env,AIBinder * binder)211 jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder) {
212   SetJvm(env);
213   FORWARD(AIBinder_toJavaBinder)(env, binder);
214 }
215 
216 }  // namespace ndk_util
217 }  // namespace grpc_binder
218 
219 #endif
220 #endif
221