[BinderTransport] Allow finding Java class using custom class finder (#28348)

In some some situation it is not feasible to invoke
`InitializeBinderChannelJavaClass` in non-native threads.
And the intended way to find Java class is through class loader cached
at program initialization.

This commit adds a new API that accepts a class finder from user and
uses the function to find and cache binder transport Java util class.
diff --git a/include/grpcpp/create_channel_binder.h b/include/grpcpp/create_channel_binder.h
index 6a9f6b4..a8f963d 100644
--- a/include/grpcpp/create_channel_binder.h
+++ b/include/grpcpp/create_channel_binder.h
@@ -78,6 +78,15 @@
 /// Returns true when the initialization is successful.
 bool InitializeBinderChannelJavaClass(void* jni_env_void);
 
+/// EXPERIMENTAL Alternative version of `InitializeBinderChannelJavaClass(void*
+/// jni_env_void)`. This version used a user-specified function to find the
+/// required internal Java class. When a class is found, the `class_finder`
+/// function should return a local reference to the class (jclass type). The
+/// returned jclass will then be used to create global reference for gRPC to use
+/// it later. After that, gRPC will DeleteLocalRef the returned local reference.
+bool InitializeBinderChannelJavaClass(
+    void* jni_env_void, std::function<void*(std::string)> class_finder);
+
 }  // namespace experimental
 }  // namespace grpc
 
diff --git a/src/core/ext/transport/binder/client/channel_create.cc b/src/core/ext/transport/binder/client/channel_create.cc
index 0d7fb3c..27b6960 100644
--- a/src/core/ext/transport/binder/client/channel_create.cc
+++ b/src/core/ext/transport/binder/client/channel_create.cc
@@ -50,6 +50,7 @@
 #include "src/core/ext/transport/binder/wire_format/binder.h"
 #include "src/core/ext/transport/binder/wire_format/binder_android.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/transport/transport.h"
 #include "src/cpp/client/create_channel_internal.h"
@@ -122,6 +123,12 @@
              static_cast<JNIEnv*>(jni_env_void)) != nullptr;
 }
 
+bool InitializeBinderChannelJavaClass(
+    void* jni_env_void, std::function<void*(std::string)> class_finder) {
+  return grpc_binder::FindNativeConnectionHelper(
+             static_cast<JNIEnv*>(jni_env_void), class_finder) != nullptr;
+}
+
 }  // namespace experimental
 }  // namespace grpc
 
@@ -162,6 +169,16 @@
   return {};
 }
 
+bool InitializeBinderChannelJavaClass(
+    void* jni_env_void, std::function<void*(std::string)> class_finder) {
+  gpr_log(GPR_ERROR,
+          "This APK is compiled with Android API level = %d, which is not "
+          "supported. See port_platform.h for supported versions.",
+          __ANDROID_API__);
+  GPR_ASSERT(0);
+  return {};
+}
+
 }  // namespace experimental
 }  // namespace grpc
 
diff --git a/src/core/ext/transport/binder/client/jni_utils.cc b/src/core/ext/transport/binder/client/jni_utils.cc
index 035e40e..0dde0e1 100644
--- a/src/core/ext/transport/binder/client/jni_utils.cc
+++ b/src/core/ext/transport/binder/client/jni_utils.cc
@@ -25,12 +25,20 @@
 namespace grpc_binder {
 
 jclass FindNativeConnectionHelper(JNIEnv* env) {
-  auto do_find = [env]() {
-    jclass cl = env->FindClass("io/grpc/binder/cpp/NativeConnectionHelper");
+  return FindNativeConnectionHelper(
+      env, [env](std::string cl) { return env->FindClass(cl.c_str()); });
+}
+
+jclass FindNativeConnectionHelper(
+    JNIEnv* env, std::function<void*(std::string)> class_finder) {
+  auto do_find = [env, class_finder]() {
+    jclass cl = static_cast<jclass>(
+        class_finder("io/grpc/binder/cpp/NativeConnectionHelper"));
     if (cl == nullptr) {
       return cl;
     }
     jclass global_cl = static_cast<jclass>(env->NewGlobalRef(cl));
+    env->DeleteLocalRef(cl);
     GPR_ASSERT(global_cl != nullptr);
     return global_cl;
   };
diff --git a/src/core/ext/transport/binder/client/jni_utils.h b/src/core/ext/transport/binder/client/jni_utils.h
index 24fd9c0..bd065fb 100644
--- a/src/core/ext/transport/binder/client/jni_utils.h
+++ b/src/core/ext/transport/binder/client/jni_utils.h
@@ -31,6 +31,9 @@
 // JNI_OnLoad) so subsequent BinderTransport code can find Java class
 jclass FindNativeConnectionHelper(JNIEnv* env);
 
+jclass FindNativeConnectionHelper(
+    JNIEnv* env, std::function<void*(std::string)> class_finder);
+
 // Calls Java method NativeConnectionHelper.tryEstablishConnection
 void TryEstablishConnection(JNIEnv* env, jobject application,
                             absl::string_view pkg, absl::string_view cls,