jni: Ensure global ref of client is created during async call.

Sometimes a java client gets garbage collected while an async
startcall is happening. This cleans up the ref count for the go client,
which causes a panic when we try to invoke start call.

This changes creates a general way for DoAsyncCall to release resources
(ie. call DeleteGlobalRef) after the call is complete. For this particular
problem, this allows us to create a global ref for the java client,
preventing it from being collected during the duration of startcall.

Change-Id: Ifadeabbc374aee2c3ab4320eb1dcb7e2e1c1c7f9
diff --git a/impl/google/rpc/jni.go b/impl/google/rpc/jni.go
index 5719220..549b4de 100644
--- a/impl/google/rpc/jni.go
+++ b/impl/google/rpc/jni.go
@@ -294,7 +294,9 @@
 }
 
 //export Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall
-func Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall(jenv *C.JNIEnv, jClient C.jobject, goRef C.jlong, jContext C.jobject, jName C.jstring, jMethod C.jstring, jVomArgs C.jobjectArray, jNameResolutionAuthorizerObj, jServerAuthorizerObj C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall(jenv *C.JNIEnv, jClientObj C.jobject, goRef C.jlong,
+	jContext C.jobject, jName C.jstring, jMethod C.jstring, jVomArgs C.jobjectArray, jNameResolutionAuthorizerObj,
+	jServerAuthorizerObj C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	name := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jName))))
 	method := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jMethod))))
@@ -328,8 +330,17 @@
 		}
 		opts = append(opts, options.ServerAuthorizer{auth})
 	}
+	// Create a global reference to the client object for the duration of the call
+	// so that the java object doesn't get garbage collected while the async call
+	// is happening. This is an issue because if the java object is garbage collected,
+	// the go ref will also be collected causing doStartCall to panic.
+	jClient := jutil.NewGlobalRef(env, jutil.Object(uintptr(unsafe.Pointer(jClientObj))))
 	jutil.DoAsyncCall(env, jCallback, func() (jutil.Object, error) {
-		return doStartCall(ctx, cancel, name, method, opts, goRef, args)
+		obj, err := doStartCall(ctx, cancel, name, method, opts, goRef, args)
+		env, freeFunc := jutil.GetEnv()
+		jutil.DeleteGlobalRef(env, jClient)
+		freeFunc()
+		return obj, err
 	})
 }