blob: 1fb6a6125f0831b8533cbc4052b74d27c5c964ce [file] [log] [blame]
// +build android
package main
import (
"flag"
"fmt"
"unsafe"
"veyron2/ipc"
"veyron2/rt"
"veyron2/verror"
)
// #include <stdlib.h>
// #include "jni_wrapper.h"
import "C"
var (
// Global reference for com.veyron2.ipc.VeyronException class.
jVeyronExceptionClass C.jclass
// Global reference for com.veyron.runtimes.google.ipc.IDLInvoker class.
jIDLInvokerClass C.jclass
// Global reference for java.lang.Throwable class.
jThrowableClass C.jclass
// Global reference for java.lang.String class.
jStringClass C.jclass
)
// refs stores references to instances of various Go types, namely instances
// that are referenced only by the Java code. The only purpose of this store
// is to prevent Go runtime from garbage collecting those instances.
var refs = newSafeSet()
// serverPtr returns the pointer to the provided server instance, as a Java's
// C.jlong type.
func serverPtr(s ipc.Server) C.jlong {
return C.jlong(uintptr(unsafe.Pointer(&s)))
}
// getServer returns the server referenced by the provided pointer, or nil if
// the pointer is 0.
func getServer(env *C.JNIEnv, ptr C.jlong) ipc.Server {
if ptr == C.jlong(0) {
jThrow(env, "Go server pointer is nil")
return nil
}
return *(*ipc.Server)(unsafe.Pointer(uintptr(ptr)))
}
// serverPtr returns the pointer to the provided client instance, as a Java's
// C.jlong type.
func clientPtr(c *client) C.jlong {
return C.jlong(uintptr(unsafe.Pointer(c)))
}
// getClient returns the client referenced by the provided pointer, or nil if
// the pointer is 0.
func getClient(env *C.JNIEnv, ptr C.jlong) *client {
if ptr == C.jlong(0) {
jThrow(env, "Go client pointer is nil")
return nil
}
return (*client)(unsafe.Pointer(uintptr(ptr)))
}
// serverPtr returns the pointer to the provided clientCall instance, as a
// Java's C.jlong type.
func clientCallPtr(c *clientCall) C.jlong {
return C.jlong(uintptr(unsafe.Pointer(c)))
}
// getCall returns the clientCall referenced by the provided pointer,
// or nil if the pointer is 0.
func getCall(env *C.JNIEnv, ptr C.jlong) *clientCall {
if ptr == C.jlong(0) {
jThrow(env, "Go client call pointer is nil")
return nil
}
return (*clientCall)(unsafe.Pointer(uintptr(ptr)))
}
//export JNI_OnLoad
func JNI_OnLoad(jVM *C.JavaVM, reserved unsafe.Pointer) C.jint {
return C.JNI_VERSION_1_6
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_nativeInit
func Java_com_veyron_runtimes_google_ipc_Runtime_nativeInit(env *C.JNIEnv, jRuntime C.jclass) {
// Cache global references to all Java classes used by the package. This is
// necessary because JNI gets access to the class loader only in the system
// thread, so we aren't able to invoke FindClass in other threads.
jVeyronExceptionClass = jFindClassOrDie(env, "com/veyron2/ipc/VeyronException")
jIDLInvokerClass = jFindClassOrDie(env, "com/veyron/runtimes/google/ipc/IDLInvoker")
jThrowableClass = jFindClassOrDie(env, "java/lang/Throwable")
jStringClass = jFindClassOrDie(env, "java/lang/String")
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeInit
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeInit(env *C.JNIEnv, jServer C.jobject) C.jlong {
s, err := rt.R().NewServer()
if err != nil {
jThrow(env, fmt.Sprintf("Couldn't get new server from go runtime: %v", err))
return C.jlong(0)
}
// Ref.
refs.insert(s)
return serverPtr(s)
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeRegister
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeRegister(env *C.JNIEnv, jServer C.jobject, goServerPtr C.jlong, prefix C.jstring, dispatcher C.jobject) {
s := getServer(env, goServerPtr)
if s == nil {
jThrow(env, fmt.Sprintf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
return
}
// Create a new Dispatcher
d, err := newJNIDispatcher(env, dispatcher)
if err != nil {
jThrow(env, err.Error())
return
}
s.Register(goString(env, prefix), d)
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeListen
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeListen(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong, protocol C.jstring, address C.jstring) C.jstring {
s := getServer(env, goServerPtr)
if s == nil {
jThrow(env, fmt.Sprintf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
return nil
}
ep, err := s.Listen(goString(env, protocol), goString(env, address))
if err != nil {
jThrow(env, err.Error())
return nil
}
return jString(env, ep.String())
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativePublish
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativePublish(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong, name C.jstring) {
s := getServer(env, goServerPtr)
if s == nil {
jThrow(env, fmt.Sprintf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
return
}
if err := s.Publish(goString(env, name)); err != nil {
jThrow(env, err.Error())
return
}
}
//export Java_com_veyron_runtimes_google_ipc_jni_Runtime_00024Server_nativeStop
func Java_com_veyron_runtimes_google_ipc_jni_Runtime_00024Server_nativeStop(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong) {
s := getServer(env, goServerPtr)
if s == nil {
jThrow(env, fmt.Sprintf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
return
}
if err := s.Stop(); err != nil {
jThrow(env, err.Error())
return
}
}
//export Java_com_veyron_runtimes_google_ipc_jni_Runtime_00024Server_nativeFinalize
func Java_com_veyron_runtimes_google_ipc_jni_Runtime_00024Server_nativeFinalize(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong) {
s := getServer(env, goServerPtr)
if s != nil {
// Unref.
refs.delete(s)
}
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeInit
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeInit(env *C.JNIEnv, jClient C.jobject) C.jlong {
c, err := newClient()
if err != nil {
jThrow(env, fmt.Sprintf("Couldn't get new client from go runtime: %v", err))
return C.jlong(0)
}
// Ref.
refs.insert(c)
return clientPtr(c)
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeStartCall
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeStartCall(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong, name C.jstring, method C.jstring, jsonArgs C.jobjectArray, jPath C.jstring, timeoutMillis C.jlong) C.jlong {
c := getClient(env, goClientPtr)
if c == nil {
jThrow(env, fmt.Sprintf("Couldn't find Go client with pointer: %d", int(goClientPtr)))
return C.jlong(0)
}
call, err := c.StartCall(env, goString(env, name), goString(env, method), jsonArgs, jPath, timeoutMillis)
if err != nil {
jThrow(env, fmt.Sprintf("Couldn't start Go call: %v", err))
return C.jlong(0)
}
return clientCallPtr(call)
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeClose
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeClose(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong) {
c := getClient(env, goClientPtr)
if c != nil {
c.Close()
}
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeFinalize
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeFinalize(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong) {
c := getClient(env, goClientPtr)
if c != nil {
// Unref.
refs.delete(c)
}
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeFinish
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeFinish(env *C.JNIEnv, jClient C.jobject, goCallPtr C.jlong) C.jobjectArray {
c := getCall(env, goCallPtr)
if c == nil {
jThrow(env, fmt.Sprintf("Couldn't find Go client with pointer: %d", int(goCallPtr)))
return nil
}
ret, err := c.Finish(env)
if err != nil {
// Could be an application error, so we throw it with jThrowV.
jThrowV(env, verror.Convert(err))
return nil
}
// Unref.
refs.delete(c)
return ret
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeCancel
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeCancel(env *C.JNIEnv, jClient C.jobject, goCallPtr C.jlong) {
c := getCall(env, goCallPtr)
if c != nil {
c.Cancel()
}
}
//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeFinalize
func Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeFinalize(env *C.JNIEnv, jClient C.jobject, goCallPtr C.jlong) {
c := getCall(env, goCallPtr)
if c != nil {
refs.delete(c)
}
}
func main() {
// Send all logging to stderr, so that the output is visible in Android. Note that if this
// flag is removed, the process will likely crash as android requires that all logs are written
// into a specific directory.
flag.Set("logtostderr", "true")
rt.Init()
}