Merge "veyron/lib/exec: moving the veyron exec library under mgmt."
diff --git a/runtimes/google/ipc/jni/client.go b/runtimes/google/ipc/jni/client.go
index c55adff..a78c0ab 100644
--- a/runtimes/google/ipc/jni/client.go
+++ b/runtimes/google/ipc/jni/client.go
@@ -8,6 +8,7 @@
"strings"
"time"
+ "veyron/runtimes/google/jni/util"
"veyron2"
"veyron2/ipc"
)
@@ -34,17 +35,17 @@
// Convert Java argument array into []string.
argStrs := make([]string, int(C.GetArrayLength(env, C.jarray(jArgs))))
for i := 0; i < len(argStrs); i++ {
- argStrs[i] = goString(env, C.jstring(C.GetObjectArrayElement(env, jArgs, C.jsize(i))))
+ argStrs[i] = util.GoString(env, C.GetObjectArrayElement(env, jArgs, C.jsize(i)))
}
// Get argument instances that correspond to the provided method.
- vdlPackagePath := strings.Join(strings.Split(goString(env, jPath), ".")[1:], "/")
+ vdlPackagePath := strings.Join(strings.Split(util.GoString(env, jPath), ".")[1:], "/")
getter, err := newArgGetter([]string{vdlPackagePath})
if err != nil {
return nil, err
}
mArgs := getter.FindMethod(method, len(argStrs))
if mArgs == nil {
- return nil, fmt.Errorf("couldn't find method %s with %d args in VDL interface at path %q", method, len(argStrs), goString(env, jPath))
+ return nil, fmt.Errorf("couldn't find method %s with %d args in VDL interface at path %q", method, len(argStrs), util.GoString(env, jPath))
}
argptrs := mArgs.InPtrs()
if len(argptrs) != len(argStrs) {
@@ -58,7 +59,7 @@
}
// Remove the pointer from the argument. Simply *argptr[i] doesn't work
// as argptr[i] is of type interface{}.
- args[i] = derefOrDie(argptrs[i])
+ args[i] = util.DerefOrDie(argptrs[i])
}
// Process options.
options := []ipc.CallOpt{}
@@ -110,7 +111,7 @@
for i, resultptr := range resultptrs {
// Remove the pointer from the result. Simply *resultptr doesn't work
// as resultptr is of type interface{}.
- result := derefOrDie(resultptr)
+ result := util.DerefOrDie(resultptr)
var err error
jsonResults[i], err = json.Marshal(result)
if err != nil {
@@ -121,7 +122,7 @@
// Convert to Java array of C.jstring.
ret := C.NewObjectArray(env, C.jsize(len(jsonResults)), jStringClass, nil)
for i, result := range jsonResults {
- C.SetObjectArrayElement(env, ret, C.jsize(i), C.jobject(jString(env, string(result))))
+ C.SetObjectArrayElement(env, ret, C.jsize(i), C.jobject(util.JStringPtr(env, string(result))))
}
return ret, nil
}
diff --git a/runtimes/google/ipc/jni/dispatcher.go b/runtimes/google/ipc/jni/dispatcher.go
index f8fa818..a913b3b 100644
--- a/runtimes/google/ipc/jni/dispatcher.go
+++ b/runtimes/google/ipc/jni/dispatcher.go
@@ -6,6 +6,7 @@
"fmt"
"runtime"
+ "veyron/runtimes/google/jni/util"
"veyron2/ipc"
"veyron2/security"
)
@@ -19,7 +20,7 @@
// }
import "C"
-func newJNIDispatcher(env *C.JNIEnv, jDispatcher C.jobject) (ipc.Dispatcher, error) {
+func newDispatcher(env *C.JNIEnv, jDispatcher C.jobject) (*dispatcher, error) {
// We cannot cache Java environments as they are only valid in the current
// thread. We can, however, cache the Java VM and obtain an environment
// from it in whatever thread happens to be running at the time.
@@ -31,35 +32,35 @@
// dispatcher created below is garbage-collected (through the finalizer
// callback we setup below).
jDispatcher = C.NewGlobalRef(env, jDispatcher)
- d := &jniDispatcher{
- jVM: jVM,
- jDObj: jDispatcher,
+ d := &dispatcher{
+ jVM: jVM,
+ jDispatcher: jDispatcher,
}
- runtime.SetFinalizer(d, func(d *jniDispatcher) {
+ runtime.SetFinalizer(d, func(d *dispatcher) {
var env *C.JNIEnv
C.AttachCurrentThread(d.jVM, &env, nil)
defer C.DetachCurrentThread(d.jVM)
- C.DeleteGlobalRef(env, d.jDObj)
+ C.DeleteGlobalRef(env, d.jDispatcher)
})
return d, nil
}
-type jniDispatcher struct {
- jVM *C.JavaVM
- jDObj C.jobject
+type dispatcher struct {
+ jVM *C.JavaVM
+ jDispatcher C.jobject
}
-func (d *jniDispatcher) Lookup(suffix string) (ipc.Invoker, security.Authorizer, error) {
+func (d *dispatcher) Lookup(suffix string) (ipc.Invoker, security.Authorizer, error) {
// Get Java environment.
var env *C.JNIEnv
C.AttachCurrentThread(d.jVM, &env, nil)
defer C.DetachCurrentThread(d.jVM)
// Call Java dispatcher's lookup() method.
- lid := jMethodID(env, C.GetObjectClass(env, d.jDObj), "lookup", fmt.Sprintf("(%s)%s", stringSign, objectSign))
- jObj := C.CallLookupMethod(env, d.jDObj, lid, jString(env, suffix))
- if err := jExceptionMsg(env); err != nil {
+ lid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, d.jDispatcher), "lookup", fmt.Sprintf("(%s)%s", util.StringSign, util.ObjectSign)))
+ jObj := C.CallLookupMethod(env, d.jDispatcher, lid, C.jstring(util.JStringPtr(env, suffix)))
+ if err := util.JExceptionMsg(env); err != nil {
return nil, nil, fmt.Errorf("error invoking Java dispatcher's lookup() method: %v", err)
}
if jObj == nil {
@@ -67,7 +68,7 @@
// handling the object - this is not an error.
return nil, nil, nil
}
- i, err := newJNIInvoker(env, d.jVM, jObj)
+ i, err := newInvoker(env, d.jVM, jObj)
if err != nil {
return nil, nil, err
}
diff --git a/runtimes/google/ipc/jni/invoker.go b/runtimes/google/ipc/jni/invoker.go
index 5835d86..0c9ba2a 100644
--- a/runtimes/google/ipc/jni/invoker.go
+++ b/runtimes/google/ipc/jni/invoker.go
@@ -7,6 +7,7 @@
"fmt"
"runtime"
+ "veyron/runtimes/google/jni/util"
"veyron2/ipc"
"veyron2/security"
"veyron2/verror"
@@ -33,17 +34,17 @@
// }
import "C"
-func newJNIInvoker(env *C.JNIEnv, jVM *C.JavaVM, jObj C.jobject) (ipc.Invoker, error) {
+func newInvoker(env *C.JNIEnv, jVM *C.JavaVM, jObj C.jobject) (*invoker, error) {
// Create a new Java VDLInvoker object.
- cid := jMethodID(env, jVDLInvokerClass, "<init>", fmt.Sprintf("(%s)%s", objectSign, voidSign))
+ cid := C.jmethodID(util.JMethodIDPtr(env, jVDLInvokerClass, "<init>", fmt.Sprintf("(%s)%s", util.ObjectSign, util.VoidSign)))
jInvoker := C.CallNewInvokerObject(env, jVDLInvokerClass, cid, jObj)
- if err := jExceptionMsg(env); err != nil {
+ if err := util.JExceptionMsg(env); err != nil {
return nil, fmt.Errorf("error creating Java VDLInvoker object: %v", err)
}
// Fetch the argGetter for the object.
- pid := jMethodID(env, jVDLInvokerClass, "getImplementedServices", fmt.Sprintf("()%s", arraySign(stringSign)))
+ pid := C.jmethodID(util.JMethodIDPtr(env, jVDLInvokerClass, "getImplementedServices", fmt.Sprintf("()%s", util.ArraySign(util.StringSign))))
jPathArray := C.jobjectArray(C.CallGetInterfacePath(env, jInvoker, pid))
- paths := goStringArray(env, jPathArray)
+ paths := util.GoStringArray(env, jPathArray)
getter, err := newArgGetter(paths)
if err != nil {
return nil, err
@@ -52,12 +53,12 @@
// created below is garbage-collected (through the finalizer callback we
// setup just below).
jInvoker = C.NewGlobalRef(env, jInvoker)
- i := &jniInvoker{
+ i := &invoker{
jVM: jVM,
jInvoker: jInvoker,
argGetter: getter,
}
- runtime.SetFinalizer(i, func(i *jniInvoker) {
+ runtime.SetFinalizer(i, func(i *invoker) {
var env *C.JNIEnv
C.AttachCurrentThread(i.jVM, &env, nil)
defer C.DetachCurrentThread(i.jVM)
@@ -66,13 +67,13 @@
return i, nil
}
-type jniInvoker struct {
+type invoker struct {
jVM *C.JavaVM
jInvoker C.jobject
argGetter *argGetter
}
-func (i *jniInvoker) Prepare(method string, numArgs int) (argptrs []interface{}, label security.Label, err error) {
+func (i *invoker) Prepare(method string, numArgs int) (argptrs []interface{}, label security.Label, err error) {
// NOTE(spetrovic): In the long-term, this method will return an array of
// []vom.Value. This will in turn result in VOM decoding all input
// arguments into vom.Value objects, which we shall then de-serialize into
@@ -89,7 +90,7 @@
return
}
-func (i *jniInvoker) Invoke(method string, call ipc.ServerCall, argptrs []interface{}) (results []interface{}, err error) {
+func (i *invoker) Invoke(method string, call ipc.ServerCall, argptrs []interface{}) (results []interface{}, err error) {
// NOTE(spetrovic): In the long-term, all input arguments will be of
// vom.Value type (see comments for Prepare() method above). Through JNI,
// we will call Java functions that transform a serialized vom.Value into
@@ -107,9 +108,9 @@
err = fmt.Errorf("couldn't find VDL method %q with %d args", method, len(argptrs))
}
sCall := newServerCall(call, mArgs)
- cid := jMethodID(env, jServerCallClass, "<init>", fmt.Sprintf("(%s)%s", longSign, voidSign))
- jServerCall := C.CallNewServerCallObject(env, jServerCallClass, cid, ptrValue(sCall))
- goRef(sCall) // unref-ed when jServerCall is garbage-collected
+ cid := C.jmethodID(util.JMethodIDPtr(env, jServerCallClass, "<init>", fmt.Sprintf("(%s)%s", util.LongSign, util.VoidSign)))
+ jServerCall := C.CallNewServerCallObject(env, jServerCallClass, cid, C.jlong(util.PtrValue(sCall)))
+ util.GoRef(sCall) // unref-ed when jServerCall is garbage-collected
// Translate input args to JSON.
jArgs, err := i.encodeArgs(env, argptrs)
@@ -119,9 +120,9 @@
// Invoke the method.
const callSign = "Lcom/veyron2/ipc/ServerCall;"
const replySign = "Lcom/veyron/runtimes/google/VDLInvoker$InvokeReply;"
- mid := jMethodID(env, C.GetObjectClass(env, i.jInvoker), "invoke", fmt.Sprintf("(%s%s[%s)%s", stringSign, callSign, stringSign, replySign))
- jReply := C.CallInvokeMethod(env, i.jInvoker, mid, jString(env, camelCase(method)), jServerCall, jArgs)
- if err := jExceptionMsg(env); err != nil {
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, i.jInvoker), "invoke", fmt.Sprintf("(%s%s[%s)%s", util.StringSign, callSign, util.StringSign, replySign)))
+ jReply := C.CallInvokeMethod(env, i.jInvoker, mid, C.jstring(util.JStringPtr(env, util.CamelCase(method))), jServerCall, jArgs)
+ if err := util.JExceptionMsg(env); err != nil {
return nil, fmt.Errorf("error invoking Java method %q: %v", method, err)
}
// Decode and return results.
@@ -130,13 +131,13 @@
// encodeArgs JSON-encodes the provided argument pointers, converts them into
// Java strings, and returns a Java string array response.
-func (*jniInvoker) encodeArgs(env *C.JNIEnv, argptrs []interface{}) (C.jobjectArray, error) {
+func (*invoker) encodeArgs(env *C.JNIEnv, argptrs []interface{}) (C.jobjectArray, error) {
// JSON encode.
jsonArgs := make([][]byte, len(argptrs))
for i, argptr := range argptrs {
// Remove the pointer from the argument. Simply *argptr doesn't work
// as argptr is of type interface{}.
- arg := derefOrDie(argptr)
+ arg := util.DerefOrDie(argptr)
var err error
jsonArgs[i], err = json.Marshal(arg)
if err != nil {
@@ -147,19 +148,19 @@
// Convert to Java array of C.jstring.
ret := C.NewObjectArray(env, C.jsize(len(argptrs)), jStringClass, nil)
for i, arg := range jsonArgs {
- C.SetObjectArrayElement(env, ret, C.jsize(i), C.jobject(jString(env, string(arg))))
+ C.SetObjectArrayElement(env, ret, C.jsize(i), C.jobject(util.JStringPtr(env, string(arg))))
}
return ret, nil
}
// decodeResults JSON-decodes replies stored in the Java reply object and
// returns an array of Go reply objects.
-func (i *jniInvoker) decodeResults(env *C.JNIEnv, method string, numArgs int, jReply C.jobject) ([]interface{}, error) {
+func (i *invoker) decodeResults(env *C.JNIEnv, method string, numArgs int, jReply C.jobject) ([]interface{}, error) {
// Unpack the replies.
- results := jStringArrayField(env, jReply, "results")
- hasAppErr := jBoolField(env, jReply, "hasApplicationError")
- errorID := jStringField(env, jReply, "errorID")
- errorMsg := jStringField(env, jReply, "errorMsg")
+ results := util.JStringArrayField(env, jReply, "results")
+ hasAppErr := util.JBoolField(env, jReply, "hasApplicationError")
+ errorID := util.JStringField(env, jReply, "errorID")
+ errorMsg := util.JStringField(env, jReply, "errorMsg")
// Get result instances.
mArgs := i.argGetter.FindMethod(method, numArgs)
@@ -189,7 +190,7 @@
func resultsWithError(resultptrs []interface{}, err error) []interface{} {
ret := make([]interface{}, len(resultptrs)+1)
for i, resultptr := range resultptrs {
- ret[i] = derefOrDie(resultptr)
+ ret[i] = util.DerefOrDie(resultptr)
}
ret[len(resultptrs)] = err
return ret
diff --git a/runtimes/google/ipc/jni/jni.go b/runtimes/google/ipc/jni/jni.go
index 204a9f0..36c5b90 100644
--- a/runtimes/google/ipc/jni/jni.go
+++ b/runtimes/google/ipc/jni/jni.go
@@ -3,46 +3,47 @@
package jni
import (
- "fmt"
"io"
"time"
+ "unsafe"
+ "veyron/runtimes/google/jni/util"
"veyron2"
ctx "veyron2/context"
"veyron2/ipc"
"veyron2/rt"
)
+// #cgo LDFLAGS: -ljniwrapper
+// #include "jni_wrapper.h"
// #include <stdlib.h>
-// #include <jni.h>
import "C"
var (
- // Global reference for com.veyron2.ipc.VeyronException class.
- jVeyronExceptionClass C.jclass
// Global reference for com.veyron.runtimes.google.ipc.Runtime$ServerCall class.
jServerCallClass C.jclass
// Global reference for com.veyron.runtimes.google.ipc.VDLInvoker class.
jVDLInvokerClass C.jclass
- // Global reference for java.lang.Throwable class.
- jThrowableClass C.jclass
- // Global reference for java.lang.String class.
- jStringClass C.jclass
// Global reference for java.io.EOFException class.
jEOFExceptionClass C.jclass
+ // Global reference for java.lang.String class.
+ jStringClass C.jclass
)
-//export Java_com_veyron_runtimes_google_Runtime_nativeGlobalInit
-func Java_com_veyron_runtimes_google_Runtime_nativeGlobalInit(env *C.JNIEnv, jRuntime C.jclass) {
+// Init initializes the JNI code with the given Java environment. This method
+// must be called from the main Java thread.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java environment is passed in an empty
+// interface and then cast into the package-local environment type.
+func Init(jEnv interface{}) {
+ env := (*C.JNIEnv)(unsafe.Pointer(util.PtrValue(jEnv)))
// 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")
- jServerCallClass = jFindClassOrDie(env, "com/veyron/runtimes/google/Runtime$ServerCall")
- jVDLInvokerClass = jFindClassOrDie(env, "com/veyron/runtimes/google/VDLInvoker")
- jThrowableClass = jFindClassOrDie(env, "java/lang/Throwable")
- jStringClass = jFindClassOrDie(env, "java/lang/String")
- jEOFExceptionClass = jFindClassOrDie(env, "java/io/EOFException")
+ jServerCallClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron/runtimes/google/Runtime$ServerCall"))
+ jVDLInvokerClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron/runtimes/google/VDLInvoker"))
+ jEOFExceptionClass = C.jclass(util.JFindClassPtrOrDie(env, "java/io/EOFException"))
+ jStringClass = C.jclass(util.JFindClassPtrOrDie(env, "java/lang/String"))
}
//export Java_com_veyron_runtimes_google_Runtime_nativeInit
@@ -52,204 +53,158 @@
var err error
r, err = rt.New()
if err != nil {
- jThrowV(env, err)
+ util.JThrowV(env, err)
}
}
- goRef(&r)
- return ptrValue(&r)
+ util.GoRef(&r) // Un-refed when the Java Runtime object is finalized.
+ return C.jlong(util.PtrValue(&r))
}
//export Java_com_veyron_runtimes_google_Runtime_nativeNewClient
func Java_com_veyron_runtimes_google_Runtime_nativeNewClient(env *C.JNIEnv, jRuntime C.jobject, goRuntimePtr C.jlong, timeoutMillis C.jlong) C.jlong {
- r := (*veyron2.Runtime)(ptr(goRuntimePtr))
- if r == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go runtime with pointer: %d", int(goRuntimePtr)))
- return C.jlong(0)
- }
+ r := (*veyron2.Runtime)(util.Ptr(goRuntimePtr))
options := []ipc.ClientOpt{}
if int(timeoutMillis) > 0 {
options = append(options, veyron2.CallTimeout(time.Duration(timeoutMillis)*time.Millisecond))
}
rc, err := (*r).NewClient(options...)
if err != nil {
- jThrowV(env, err)
+ util.JThrowV(env, err)
return C.jlong(0)
}
c := newClient(rc)
- goRef(c)
- return ptrValue(c)
+ util.GoRef(c) // Un-refed when the Java Client object is finalized.
+ return C.jlong(util.PtrValue(c))
}
//export Java_com_veyron_runtimes_google_Runtime_nativeNewServer
func Java_com_veyron_runtimes_google_Runtime_nativeNewServer(env *C.JNIEnv, jRuntime C.jobject, goRuntimePtr C.jlong) C.jlong {
- r := (*veyron2.Runtime)(ptr(goRuntimePtr))
- if r == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go runtime with pointer: %d", int(goRuntimePtr)))
- return C.jlong(0)
- }
+ r := (*veyron2.Runtime)(util.Ptr(goRuntimePtr))
s, err := (*r).NewServer()
if err != nil {
- jThrowV(env, err)
+ util.JThrowV(env, err)
return C.jlong(0)
}
- goRef(&s)
- return ptrValue(&s)
+ util.GoRef(&s) // Un-refed when the Java Server object is finalized.
+ return C.jlong(util.PtrValue(&s))
}
//export Java_com_veyron_runtimes_google_Runtime_nativeGetClient
func Java_com_veyron_runtimes_google_Runtime_nativeGetClient(env *C.JNIEnv, jRuntime C.jobject, goRuntimePtr C.jlong) C.jlong {
- r := (*veyron2.Runtime)(ptr(goRuntimePtr))
- if r == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go runtime with pointer: %d", int(goRuntimePtr)))
- return C.jlong(0)
- }
+ r := (*veyron2.Runtime)(util.Ptr(goRuntimePtr))
rc := (*r).Client()
c := newClient(rc)
- goRef(c)
- return ptrValue(c)
+ util.GoRef(c) // Un-refed when the Java Client object is finalized.
+ return C.jlong(util.PtrValue(c))
}
//export Java_com_veyron_runtimes_google_Runtime_nativeNewContext
func Java_com_veyron_runtimes_google_Runtime_nativeNewContext(env *C.JNIEnv, jRuntime C.jobject, goRuntimePtr C.jlong) C.jlong {
- r := (*veyron2.Runtime)(ptr(goRuntimePtr))
- if r == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go runtime with pointer: %d", int(goRuntimePtr)))
- return C.jlong(0)
- }
+ r := (*veyron2.Runtime)(util.Ptr(goRuntimePtr))
c := (*r).NewContext()
- goRef(&c)
- return ptrValue(&c)
+ util.GoRef(&c) // Un-refed when the Java context object is finalized.
+ return C.jlong(util.PtrValue(&c))
}
//export Java_com_veyron_runtimes_google_Runtime_nativeFinalize
func Java_com_veyron_runtimes_google_Runtime_nativeFinalize(env *C.JNIEnv, jRuntime C.jobject, goRuntimePtr C.jlong) {
- r := (*veyron2.Runtime)(ptr(goRuntimePtr))
- if r != nil {
- goUnref(r)
- }
-}
-
-//export Java_com_veyron_runtimes_google_Runtime_00024Server_nativeServe
-func Java_com_veyron_runtimes_google_Runtime_00024Server_nativeServe(env *C.JNIEnv, jServer C.jobject, goServerPtr C.jlong, name C.jstring, dispatcher C.jobject) {
- s := (*ipc.Server)(ptr(goServerPtr))
- if s == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
- return
- }
- // Create a new Dispatcher
- d, err := newJNIDispatcher(env, dispatcher)
- if err != nil {
- jThrowV(env, err)
- return
- }
- if err := (*s).Serve(goString(env, name), d); err != nil {
- jThrowV(env, err)
- return
- }
+ util.GoUnref((*veyron2.Runtime)(util.Ptr(goRuntimePtr)))
}
//export Java_com_veyron_runtimes_google_Runtime_00024Server_nativeListen
func Java_com_veyron_runtimes_google_Runtime_00024Server_nativeListen(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong, protocol C.jstring, address C.jstring) C.jstring {
- s := (*ipc.Server)(ptr(goServerPtr))
- if s == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
- return nil
- }
- ep, err := (*s).Listen(goString(env, protocol), goString(env, address))
+ s := (*ipc.Server)(util.Ptr(goServerPtr))
+ ep, err := (*s).Listen(util.GoString(env, protocol), util.GoString(env, address))
if err != nil {
- jThrowV(env, err)
+ util.JThrowV(env, err)
return nil
}
- return jString(env, ep.String())
+ return C.jstring(util.JStringPtr(env, ep.String()))
+}
+
+//export Java_com_veyron_runtimes_google_Runtime_00024Server_nativeServe
+func Java_com_veyron_runtimes_google_Runtime_00024Server_nativeServe(env *C.JNIEnv, jServer C.jobject, goServerPtr C.jlong, name C.jstring, jDispatcher C.jobject) {
+ s := (*ipc.Server)(util.Ptr(goServerPtr))
+ d, err := newDispatcher(env, jDispatcher)
+ if err != nil {
+ util.JThrowV(env, err)
+ return
+ }
+ if err := (*s).Serve(util.GoString(env, name), d); err != nil {
+ util.JThrowV(env, err)
+ return
+ }
+}
+
+//export Java_com_veyron_runtimes_google_Runtime_00024Server_nativeGetPublishedNames
+func Java_com_veyron_runtimes_google_Runtime_00024Server_nativeGetPublishedNames(env *C.JNIEnv, jServer C.jobject, goServerPtr C.jlong) C.jobjectArray {
+ names, err := (*(*ipc.Server)(util.Ptr(goServerPtr))).Published()
+ if err != nil {
+ util.JThrowV(env, err)
+ return nil
+ }
+ ret := C.NewObjectArray(env, C.jsize(len(names)), jStringClass, nil)
+ for i, name := range names {
+ C.SetObjectArrayElement(env, ret, C.jsize(i), C.jobject(util.JStringPtr(env, string(name))))
+ }
+ return ret
}
//export Java_com_veyron_runtimes_google_Runtime_00024Server_nativeStop
func Java_com_veyron_runtimes_google_Runtime_00024Server_nativeStop(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong) {
- s := (*ipc.Server)(ptr(goServerPtr))
- if s == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
- return
- }
+ s := (*ipc.Server)(util.Ptr(goServerPtr))
if err := (*s).Stop(); err != nil {
- jThrowV(env, err)
+ util.JThrowV(env, err)
return
}
}
-//export Java_com_veyron_runtimes_google_Runtime_00024Server_nativeFinalize
-func Java_com_veyron_runtimes_google_Runtime_00024Server_nativeFinalize(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong) {
- s := (*ipc.Server)(ptr(goServerPtr))
- if s != nil {
- goUnref(s)
- }
+//export Java_com_veyron_runtimes_google_jni_Runtime_00024Server_nativeFinalize
+func Java_com_veyron_runtimes_google_jni_Runtime_00024Server_nativeFinalize(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong) {
+ util.GoUnref((*ipc.Server)(util.Ptr(goServerPtr)))
}
//export Java_com_veyron_runtimes_google_Runtime_00024Client_nativeStartCall
func Java_com_veyron_runtimes_google_Runtime_00024Client_nativeStartCall(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong, jContext C.jobject, name C.jstring, method C.jstring, jsonArgs C.jobjectArray, jPath C.jstring, timeoutMillis C.jlong) C.jlong {
- c := (*client)(ptr(goClientPtr))
- if c == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go client with pointer: %d", int(goClientPtr)))
- return C.jlong(0)
- }
- call, err := c.StartCall(env, jContext, goString(env, name), goString(env, method), jsonArgs, jPath, timeoutMillis)
+ c := (*client)(util.Ptr(goClientPtr))
+ call, err := c.StartCall(env, jContext, util.GoString(env, name), util.GoString(env, method), jsonArgs, jPath, timeoutMillis)
if err != nil {
- jThrowV(env, err)
+ util.JThrowV(env, err)
return C.jlong(0)
}
- goRef(call)
- return ptrValue(call)
+ util.GoRef(call)
+ return C.jlong(util.PtrValue(call))
}
//export Java_com_veyron_runtimes_google_Runtime_00024Client_nativeClose
func Java_com_veyron_runtimes_google_Runtime_00024Client_nativeClose(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong) {
- c := (*client)(ptr(goClientPtr))
- if c == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go client with pointer: %d", int(goClientPtr)))
- return
- }
- c.Close()
+ (*client)(util.Ptr(goClientPtr)).Close()
}
//export Java_com_veyron_runtimes_google_Runtime_00024Client_nativeFinalize
func Java_com_veyron_runtimes_google_Runtime_00024Client_nativeFinalize(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong) {
- c := (*client)(ptr(goClientPtr))
- if c != nil {
- goUnref(c)
- }
+ util.GoUnref((*client)(util.Ptr(goClientPtr)))
}
//export Java_com_veyron_runtimes_google_Runtime_00024Context_nativeFinalize
func Java_com_veyron_runtimes_google_Runtime_00024Context_nativeFinalize(env *C.JNIEnv, jClient C.jobject, goContextPtr C.jlong) {
- c := (*ctx.T)(ptr(goContextPtr))
- if c != nil {
- goUnref(c)
- }
+ util.GoUnref((*ctx.T)(util.Ptr(goContextPtr)))
}
//export Java_com_veyron_runtimes_google_Runtime_00024Stream_nativeSend
func Java_com_veyron_runtimes_google_Runtime_00024Stream_nativeSend(env *C.JNIEnv, jStream C.jobject, goStreamPtr C.jlong, jItem C.jstring) {
- s := (*stream)(ptr(goStreamPtr))
- if s == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go stream with pointer: %d", int(goStreamPtr)))
- return
- }
- s.Send(env, jItem)
+ (*stream)(util.Ptr(goStreamPtr)).Send(env, jItem)
}
//export Java_com_veyron_runtimes_google_Runtime_00024Stream_nativeRecv
func Java_com_veyron_runtimes_google_Runtime_00024Stream_nativeRecv(env *C.JNIEnv, jStream C.jobject, goStreamPtr C.jlong) C.jstring {
- s := (*stream)(ptr(goStreamPtr))
- if s == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go stream with pointer: %d", int(goStreamPtr)))
- return nil
- }
- ret, err := s.Recv(env)
+ ret, err := (*stream)(util.Ptr(goStreamPtr)).Recv(env)
if err != nil {
if err == io.EOF {
- jThrow(env, jEOFExceptionClass, err.Error())
+ util.JThrow(env, jEOFExceptionClass, err.Error())
return nil
}
- jThrowV(env, err)
+ util.JThrowV(env, err)
return nil
}
return ret
@@ -257,14 +212,9 @@
//export Java_com_veyron_runtimes_google_Runtime_00024ClientCall_nativeFinish
func Java_com_veyron_runtimes_google_Runtime_00024ClientCall_nativeFinish(env *C.JNIEnv, jClientCall C.jobject, goClientCallPtr C.jlong) C.jobjectArray {
- c := (*clientCall)(ptr(goClientCallPtr))
- if c == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go client call with pointer: %d", int(goClientCallPtr)))
- return nil
- }
- ret, err := c.Finish(env)
+ ret, err := (*clientCall)(util.Ptr(goClientCallPtr)).Finish(env)
if err != nil {
- jThrowV(env, err)
+ util.JThrowV(env, err)
return nil
}
return ret
@@ -272,29 +222,24 @@
//export Java_com_veyron_runtimes_google_Runtime_00024ClientCall_nativeCancel
func Java_com_veyron_runtimes_google_Runtime_00024ClientCall_nativeCancel(env *C.JNIEnv, jClientCall C.jobject, goClientCallPtr C.jlong) {
- c := (*clientCall)(ptr(goClientCallPtr))
- if c == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go client call with pointer: %d", int(goClientCallPtr)))
- return
- }
- c.Cancel()
+ (*clientCall)(util.Ptr(goClientCallPtr)).Cancel()
}
//export Java_com_veyron_runtimes_google_Runtime_00024ClientCall_nativeFinalize
func Java_com_veyron_runtimes_google_Runtime_00024ClientCall_nativeFinalize(env *C.JNIEnv, jClientCall C.jobject, goClientCallPtr C.jlong) {
- c := (*clientCall)(ptr(goClientCallPtr))
- if c != nil {
- goUnref(c)
- }
+ util.GoUnref((*clientCall)(util.Ptr(goClientCallPtr)))
+}
+
+//export Java_com_veyron_runtimes_google_Runtime_00024ServerCall_nativeBlessing
+func Java_com_veyron_runtimes_google_Runtime_00024ServerCall_nativeBlessing(env *C.JNIEnv, jServerCall C.jobject, goServerCallPtr C.jlong) C.jlong {
+ id := (*serverCall)(util.Ptr(goServerCallPtr)).Blessing()
+ util.GoRef(&id) // Un-refed when the Java PublicID object is finalized.
+ return C.jlong(util.PtrValue(&id))
}
//export Java_com_veyron_runtimes_google_Runtime_00024ServerCall_nativeDeadline
func Java_com_veyron_runtimes_google_Runtime_00024ServerCall_nativeDeadline(env *C.JNIEnv, jServerCall C.jobject, goServerCallPtr C.jlong) C.jlong {
- s := (*serverCall)(ptr(goServerCallPtr))
- if s == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go server call with pointer: %d", int(goServerCallPtr)))
- return C.jlong(0)
- }
+ s := (*serverCall)(util.Ptr(goServerCallPtr))
var d time.Time
if s == nil {
// Error, return current time as deadline.
@@ -307,21 +252,9 @@
//export Java_com_veyron_runtimes_google_Runtime_00024ServerCall_nativeClosed
func Java_com_veyron_runtimes_google_Runtime_00024ServerCall_nativeClosed(env *C.JNIEnv, jServerCall C.jobject, goServerCallPtr C.jlong) C.jboolean {
- s := (*serverCall)(ptr(goServerCallPtr))
- if s == nil {
- jThrowV(env, fmt.Errorf("Couldn't find Go server call with pointer: %d", int(goServerCallPtr)))
- return C.JNI_FALSE
- }
+ s := (*serverCall)(util.Ptr(goServerCallPtr))
if s.IsClosed() {
return C.JNI_TRUE
}
return C.JNI_FALSE
}
-
-//export Java_com_veyron_runtimes_google_Runtime_00024ServerCall_nativeFinalize
-func Java_com_veyron_runtimes_google_Runtime_00024ServerCall_nativeFinalize(env *C.JNIEnv, jServerCall C.jobject, goServerCallPtr C.jlong) {
- s := (*serverCall)(ptr(goServerCallPtr))
- if s != nil {
- goUnref(s)
- }
-}
diff --git a/runtimes/google/ipc/jni/stream.go b/runtimes/google/ipc/jni/stream.go
index 0ef6751..56aa121 100644
--- a/runtimes/google/ipc/jni/stream.go
+++ b/runtimes/google/ipc/jni/stream.go
@@ -6,6 +6,7 @@
"encoding/json"
"fmt"
+ "veyron/runtimes/google/jni/util"
"veyron2/ipc"
)
@@ -26,7 +27,7 @@
}
func (s *stream) Send(env *C.JNIEnv, jItem C.jstring) error {
- argStr := goString(env, jItem)
+ argStr := util.GoString(env, jItem)
argptr := s.mArgs.StreamSendPtr()
if argptr == nil {
return fmt.Errorf("nil stream input argument, expected a non-nil type for argument %q", argStr)
@@ -34,7 +35,7 @@
if err := json.Unmarshal([]byte(argStr), argptr); err != nil {
return err
}
- return s.stream.Send(derefOrDie(argptr))
+ return s.stream.Send(util.DerefOrDie(argptr))
}
func (s *stream) Recv(env *C.JNIEnv) (C.jstring, error) {
@@ -46,9 +47,9 @@
return nil, err
}
// JSON encode the result.
- result, err := json.Marshal(derefOrDie(argptr))
+ result, err := json.Marshal(util.DerefOrDie(argptr))
if err != nil {
return nil, err
}
- return jString(env, string(result)), nil
+ return C.jstring(util.JStringPtr(env, string(result))), nil
}
diff --git a/runtimes/google/ipc/jni/util.go b/runtimes/google/ipc/jni/util.go
deleted file mode 100644
index d87f3bd..0000000
--- a/runtimes/google/ipc/jni/util.go
+++ /dev/null
@@ -1,241 +0,0 @@
-// +build android
-
-package jni
-
-import (
- "errors"
- "fmt"
- "reflect"
- "sync"
- "unicode"
- "unicode/utf8"
- "unsafe"
-
- "veyron2/verror"
-)
-
-// #cgo LDFLAGS: -ljniwrapper
-// #include <stdlib.h>
-// #include "jni_wrapper.h"
-// // CGO doesn't support variadic functions so we have to hard-code these
-// // functions to match the invoking code. Ugh!
-// static jobject CallNewVeyronExceptionObject(JNIEnv* env, jclass class, jmethodID mid, jstring msg, jstring id) {
-// return (*env)->NewObject(env, class, mid, msg, id);
-// }
-// static jstring CallGetMessage(JNIEnv* env, jobject obj, jmethodID id) {
-// return (jstring)(*env)->CallObjectMethod(env, obj, id);
-// }
-import "C"
-
-const (
- voidSign = "V"
- boolSign = "Z"
- longSign = "J"
- stringSign = "Ljava/lang/String;"
- objectSign = "Ljava/lang/Object;"
-)
-
-func arraySign(sign string) string {
- return "[" + sign
-}
-
-// 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()
-
-// goRef creates a new reference to the value addressed by the provided pointer.
-// The value will remain referenced until it is explicitly unreferenced using
-// goUnref().
-func goRef(valptr interface{}) {
- if !isPointer(valptr) {
- panic("must pass pointer value to goRef")
- }
- refs.insert(valptr)
-}
-
-// goUnref removes a previously added reference to the value addressed by the
-// provided pointer. If the value hasn't been ref-ed (a bug?), this unref will
-// be a no-op.
-func goUnref(valptr interface{}) {
- if !isPointer(valptr) {
- panic("must pass pointer value to goUnref")
- }
- refs.delete(valptr)
-}
-
-// ptrValue returns the value of the pointer as a Java C.jlong type.
-func ptrValue(ptr interface{}) C.jlong {
- v := reflect.ValueOf(ptr)
- if v.Kind() != reflect.Ptr {
- panic("must pass pointer value to ptrValue")
- }
- return C.jlong(v.Pointer())
-}
-
-// ptr returns the pointer represented by the provided (Java C.jlong) value.
-func ptr(ptrValue C.jlong) unsafe.Pointer {
- return unsafe.Pointer(uintptr(ptrValue))
-}
-
-// isPointer returns true iff the provided value is a pointer.
-func isPointer(val interface{}) bool {
- return reflect.ValueOf(val).Kind() == reflect.Ptr
-}
-
-// goString returns a Go string given the Java string.
-func goString(env *C.JNIEnv, str C.jstring) string {
- if str == nil {
- return ""
- }
- cString := C.GetStringUTFChars(env, str, nil)
- defer C.ReleaseStringUTFChars(env, str, cString)
- return C.GoString(cString)
-}
-
-// jString returns a Java string given the Go string.
-func jString(env *C.JNIEnv, str string) C.jstring {
- cString := C.CString(str)
- defer C.free(unsafe.Pointer(cString))
- return C.NewStringUTF(env, cString)
-}
-
-// goStringArray converts a Java string array to a go string array.
-func goStringArray(env *C.JNIEnv, jStrArray C.jobjectArray) []string {
- if jStrArray == nil {
- return nil
- }
- length := C.GetArrayLength(env, C.jarray(jStrArray))
- ret := make([]string, int(length))
- for i := 0; i < int(length); i++ {
- ret[i] = goString(env, C.jstring(C.GetObjectArrayElement(env, jStrArray, C.jsize(i))))
- }
- return ret
-}
-
-// jThrow throws a new Java exception of the provided type with the given message.
-func jThrow(env *C.JNIEnv, class C.jclass, msg string) {
- s := C.CString(msg)
- defer C.free(unsafe.Pointer(s))
- C.ThrowNew(env, class, s)
-}
-
-// jThrowV throws a new Java VeyronException corresponding to the given error.
-func jThrowV(env *C.JNIEnv, err error) {
- verr := verror.Convert(err)
- id := jMethodID(env, jVeyronExceptionClass, "<init>", fmt.Sprintf("(%s%s)%s", stringSign, stringSign, voidSign))
- obj := C.jthrowable(C.CallNewVeyronExceptionObject(env, jVeyronExceptionClass, id, jString(env, verr.Error()), jString(env, string(verr.ErrorID()))))
- C.Throw(env, obj)
-}
-
-// jExceptionMsg returns the exception message if an exception occurred, or
-// nil otherwise.
-func jExceptionMsg(env *C.JNIEnv) error {
- e := C.ExceptionOccurred(env)
- if e == nil { // no exception
- return nil
- }
- C.ExceptionClear(env)
- id := jMethodID(env, jThrowableClass, "getMessage", fmt.Sprintf("()%s", stringSign))
- jMsg := C.CallGetMessage(env, C.jobject(e), id)
- //return errors.New("blah")
- return errors.New(goString(env, jMsg))
-}
-
-// camelCase converts ThisString to thisString.
-func camelCase(s string) string {
- if s == "" {
- return ""
- }
- r, n := utf8.DecodeRuneInString(s)
- return string(unicode.ToLower(r)) + s[n:]
-}
-
-// jBoolField returns the value of the provided object's boolean field.
-func jBoolField(env *C.JNIEnv, obj C.jobject, field string) bool {
- cField := C.CString(field)
- defer C.free(unsafe.Pointer(cField))
- cSig := C.CString(boolSign)
- defer C.free(unsafe.Pointer(cSig))
- fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
- return C.GetBooleanField(env, obj, fid) != C.JNI_FALSE
-}
-
-// jStringField returns the value of the provided object's String field,
-// as a Go string.
-func jStringField(env *C.JNIEnv, obj C.jobject, field string) string {
- cField := C.CString(field)
- defer C.free(unsafe.Pointer(cField))
- cSig := C.CString(stringSign)
- defer C.free(unsafe.Pointer(cSig))
- fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
- jStr := C.jstring(C.GetObjectField(env, obj, fid))
- return goString(env, jStr)
-}
-
-// jStringArrayField returns the value of the provided object's String[] field,
-// as a slice of Go strings.
-func jStringArrayField(env *C.JNIEnv, obj C.jobject, field string) []string {
- cField := C.CString(field)
- defer C.free(unsafe.Pointer(cField))
- cSig := C.CString("[" + stringSign)
- defer C.free(unsafe.Pointer(cSig))
- fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
- jStrArray := C.jobjectArray(C.GetObjectField(env, obj, fid))
- return goStringArray(env, jStrArray)
-}
-
-// jMethodID returns the Java method ID for the given method.
-func jMethodID(env *C.JNIEnv, class C.jclass, name, signature string) C.jmethodID {
- cName := C.CString(name)
- defer C.free(unsafe.Pointer(cName))
- cSignature := C.CString(signature)
- defer C.free(unsafe.Pointer(cSignature))
- return C.GetMethodID(env, class, cName, cSignature)
-}
-
-// jFindClassOrDie returns the global references to the Java class with the
-// given pathname, or panic-s if the class cannot be found.
-func jFindClassOrDie(env *C.JNIEnv, name string) C.jclass {
- cName := C.CString(name)
- defer C.free(unsafe.Pointer(cName))
- class := C.FindClass(env, cName)
- if err := jExceptionMsg(env); err != nil || class == nil {
- panic(fmt.Sprintf("couldn't find class %s: %v", name, err))
- }
- return C.jclass(C.NewGlobalRef(env, C.jobject(class)))
-}
-
-// derefOrDie dereferences the provided (pointer) value, or panic-s if the value
-// isn't of pointer type.
-func derefOrDie(i interface{}) interface{} {
- v := reflect.ValueOf(i)
- if v.Kind() != reflect.Ptr {
- panic(fmt.Sprintf("want reflect.Ptr value for %v, have %v", i, v.Kind()))
- }
- return v.Elem().Interface()
-}
-
-func newSafeSet() *safeSet {
- return &safeSet{
- items: make(map[interface{}]bool),
- }
-}
-
-// safeSet is a thread-safe set.
-type safeSet struct {
- lock sync.Mutex
- items map[interface{}]bool
-}
-
-func (s *safeSet) insert(item interface{}) {
- s.lock.Lock()
- defer s.lock.Unlock()
- s.items[item] = true
-}
-
-func (s *safeSet) delete(item interface{}) {
- s.lock.Lock()
- defer s.lock.Unlock()
- delete(s.items, item)
-}
diff --git a/runtimes/google/jni/jni.go b/runtimes/google/jni/jni.go
new file mode 100644
index 0000000..4df2de1
--- /dev/null
+++ b/runtimes/google/jni/jni.go
@@ -0,0 +1,48 @@
+// +build android
+
+package main
+
+import (
+ "flag"
+ "log"
+ "unsafe"
+
+ ipc "veyron/runtimes/google/ipc/jni"
+ "veyron/runtimes/google/jni/util"
+ security "veyron/runtimes/google/security/jni"
+)
+
+// #cgo LDFLAGS: -ljniwrapper
+// #include "jni_wrapper.h"
+import "C"
+
+//export JNI_OnLoad
+func JNI_OnLoad(jVM *C.JavaVM, reserved unsafe.Pointer) C.jint {
+ log.Println("On_Load")
+ var env *C.JNIEnv
+ if C.GetEnv(jVM, &env, C.JNI_VERSION_1_6) != C.JNI_OK {
+ // This should never happen as OnLoad is invoked from the main Java thread.
+ C.AttachCurrentThread(jVM, &env, nil)
+ defer C.DetachCurrentThread(jVM)
+ }
+ log.Println("Here1")
+ util.Init(env)
+ log.Println("Here2")
+ ipc.Init(env)
+ log.Println("Here3")
+ security.Init(env)
+ log.Println("Here4")
+ log.Println("Here4")
+ log.Println("Here4")
+ log.Println("Here4")
+ log.Println("Here4")
+ log.Println("Here4")
+ return C.JNI_VERSION_1_6
+}
+
+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")
+}
diff --git a/runtimes/google/jni/util/util.go b/runtimes/google/jni/util/util.go
new file mode 100644
index 0000000..85e73a7
--- /dev/null
+++ b/runtimes/google/jni/util/util.go
@@ -0,0 +1,427 @@
+// +build android
+
+// Package util provides various JNI utilities shared across our JNI code.
+package util
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "sync"
+ "unicode"
+ "unicode/utf8"
+ "unsafe"
+
+ "veyron2/verror"
+)
+
+// #cgo LDFLAGS: -ljniwrapper
+// #include <stdlib.h>
+// #include "jni_wrapper.h"
+// // CGO doesn't support variadic functions so we have to hard-code these
+// // functions to match the invoking code. Ugh!
+// static jobject CallNewVeyronExceptionObject(JNIEnv* env, jclass class, jmethodID mid, jstring msg, jstring id) {
+// return (*env)->NewObject(env, class, mid, msg, id);
+// }
+// static jstring CallGetExceptionMessage(JNIEnv* env, jobject obj, jmethodID id) {
+// return (jstring)(*env)->CallObjectMethod(env, obj, id);
+// }
+import "C"
+
+const (
+ // VoidSign denotes a signature of a Java void type.
+ VoidSign = "V"
+ // ByteSign denotes a signature of a Java byte type.
+ ByteSign = "B"
+ // BoolSign denotes a signature of a Java boolean type.
+ BoolSign = "Z"
+ // IntSign denotes a signature of a Java int type.
+ IntSign = "I"
+ // LongSign denotes a signature of a Java long type.
+ LongSign = "J"
+ // StringSign denotes a signature of a Java String type.
+ StringSign = "Ljava/lang/String;"
+ // ObjectSign denotes a signature of a Java Object type.
+ ObjectSign = "Ljava/lang/Object;"
+)
+
+// ArraySign returns the array signature, given the underlying array type.
+func ArraySign(sign string) string {
+ return "[" + sign
+}
+
+var (
+ // Global reference for com.veyron2.ipc.VeyronException class.
+ jVeyronExceptionClass C.jclass
+ // Global reference for java.lang.Throwable class.
+ jThrowableClass C.jclass
+ // Global reference for java.lang.String class.
+ jStringClass C.jclass
+)
+
+// Init initializes the JNI code with the given Java environment. This method
+// must be invoked before any other method in this package and must be called
+// from the main Java thread (e.g., On_Load()).
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func Init(jEnv interface{}) {
+ env := getEnv(jEnv)
+ jVeyronExceptionClass = C.jclass(JFindClassPtrOrDie(env, "com/veyron2/ipc/VeyronException"))
+ jThrowableClass = C.jclass(JFindClassPtrOrDie(env, "java/lang/Throwable"))
+ jStringClass = C.jclass(JFindClassPtrOrDie(env, "java/lang/String"))
+}
+
+// GoRef creates a new reference to the value addressed by the provided pointer.
+// The value will remain referenced until it is explicitly unreferenced using
+// goUnref().
+func GoRef(valptr interface{}) {
+ if !IsPointer(valptr) {
+ panic("must pass pointer value to goRef")
+ }
+ refs.insert(valptr)
+}
+
+// GoUnref removes a previously added reference to the value addressed by the
+// provided pointer. If the value hasn't been ref-ed (a bug?), this unref will
+// be a no-op.
+func GoUnref(valptr interface{}) {
+ if !IsPointer(valptr) {
+ panic("must pass pointer value to goUnref")
+ }
+ refs.delete(valptr)
+}
+
+// IsPointer returns true iff the provided value is a pointer.
+func IsPointer(val interface{}) bool {
+ return reflect.ValueOf(val).Kind() == reflect.Ptr
+}
+
+// DerefOrDie dereferences the provided (pointer) value, or panic-s if the value
+// isn't of pointer type.
+func DerefOrDie(i interface{}) interface{} {
+ v := reflect.ValueOf(i)
+ if v.Kind() != reflect.Ptr {
+ panic(fmt.Sprintf("want reflect.Ptr value for %v, have %v", i, v.Kind()))
+ }
+ return v.Elem().Interface()
+}
+
+// Ptr returns the value of the provided Java pointer (of type C.jlong) as an
+// unsafe.Pointer.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func Ptr(jPtr interface{}) unsafe.Pointer {
+ v := reflect.ValueOf(jPtr)
+ return unsafe.Pointer(uintptr(v.Int()))
+}
+
+// PtrValue returns the value of the pointer as a uintptr.
+func PtrValue(ptr interface{}) uintptr {
+ v := reflect.ValueOf(ptr)
+ if v.Kind() != reflect.Ptr && v.Kind() != reflect.UnsafePointer {
+ panic("must pass pointer value to PtrValue")
+ }
+ return v.Pointer()
+}
+
+// CamelCase converts ThisString to thisString.
+func CamelCase(s string) string {
+ if s == "" {
+ return ""
+ }
+ r, n := utf8.DecodeRuneInString(s)
+ return string(unicode.ToLower(r)) + s[n:]
+}
+
+// GoString returns a Go string given the Java string.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func GoString(jEnv, jStr interface{}) string {
+ env := getEnv(jEnv)
+ str := getString(jStr)
+ if str == nil {
+ return ""
+ }
+ cString := C.GetStringUTFChars(env, str, nil)
+ defer C.ReleaseStringUTFChars(env, str, cString)
+ return C.GoString(cString)
+}
+
+// JString returns a Java string given the Go string.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JStringPtr(jEnv interface{}, str string) unsafe.Pointer {
+ env := getEnv(jEnv)
+ cString := C.CString(str)
+ defer C.free(unsafe.Pointer(cString))
+ return unsafe.Pointer(C.NewStringUTF(env, cString))
+}
+
+// JThrow throws a new Java exception of the provided type with the given message.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JThrow(jEnv, jClass interface{}, msg string) {
+ env := getEnv(jEnv)
+ class := getClass(jClass)
+ s := C.CString(msg)
+ defer C.free(unsafe.Pointer(s))
+ C.ThrowNew(env, class, s)
+}
+
+// JThrowV throws a new Java VeyronException corresponding to the given error.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JThrowV(jEnv interface{}, err error) {
+ env := getEnv(jEnv)
+ verr := verror.Convert(err)
+ id := C.jmethodID(JMethodIDPtr(env, jVeyronExceptionClass, "<init>", fmt.Sprintf("(%s%s)%s", StringSign, StringSign, VoidSign)))
+ obj := C.jthrowable(C.CallNewVeyronExceptionObject(env, jVeyronExceptionClass, id, C.jstring(JStringPtr(env, verr.Error())), C.jstring(JStringPtr(env, string(verr.ErrorID())))))
+ C.Throw(env, obj)
+}
+
+// JExceptionMsg returns the exception message if an exception occurred, or
+// nil otherwise.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JExceptionMsg(jEnv interface{}) error {
+ env := getEnv(jEnv)
+ e := C.ExceptionOccurred(env)
+ if e == nil { // no exception
+ return nil
+ }
+ C.ExceptionClear(env)
+ id := C.jmethodID(JMethodIDPtr(env, jThrowableClass, "getMessage", fmt.Sprintf("()%s", StringSign)))
+ jMsg := C.CallGetExceptionMessage(env, C.jobject(e), id)
+ return errors.New(GoString(env, jMsg))
+}
+
+// JBoolField returns the value of the provided Java object's boolean field.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JBoolField(jEnv, jObj interface{}, field string) bool {
+ env := getEnv(jEnv)
+ obj := getObject(jObj)
+ cField := C.CString(field)
+ defer C.free(unsafe.Pointer(cField))
+ cSig := C.CString(BoolSign)
+ defer C.free(unsafe.Pointer(cSig))
+ fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
+ return C.GetBooleanField(env, obj, fid) != C.JNI_FALSE
+}
+
+// JIntField returns the value of the provided Java object's int field.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JIntField(jEnv, jObj interface{}, field string) int {
+ env := getEnv(jEnv)
+ obj := getObject(jObj)
+ cField := C.CString(field)
+ defer C.free(unsafe.Pointer(cField))
+ cSig := C.CString(IntSign)
+ defer C.free(unsafe.Pointer(cSig))
+ fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
+ return int(C.GetIntField(env, obj, fid))
+}
+
+// JStringField returns the value of the provided Java object's String field,
+// as a Go string.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JStringField(jEnv, jObj interface{}, field string) string {
+ env := getEnv(jEnv)
+ obj := getObject(jObj)
+ cField := C.CString(field)
+ defer C.free(unsafe.Pointer(cField))
+ cSig := C.CString(StringSign)
+ defer C.free(unsafe.Pointer(cSig))
+ fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
+ jStr := C.jstring(C.GetObjectField(env, obj, fid))
+ return GoString(env, jStr)
+}
+
+// JStringArrayField returns the value of the provided object's String[] field,
+// as a slice of Go strings.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JStringArrayField(jEnv, jObj interface{}, field string) []string {
+ env := getEnv(jEnv)
+ obj := getObject(jObj)
+ cField := C.CString(field)
+ defer C.free(unsafe.Pointer(cField))
+ cSig := C.CString("[" + StringSign)
+ defer C.free(unsafe.Pointer(cSig))
+ fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
+ jStrArray := C.jobjectArray(C.GetObjectField(env, obj, fid))
+ return GoStringArray(env, jStrArray)
+}
+
+// JByteArrayField returns the value of the provided object's byte[] field as a
+// Go byte slice.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JByteArrayField(jEnv, jObj interface{}, field string) []byte {
+ env := getEnv(jEnv)
+ obj := getObject(jObj)
+ cField := C.CString(field)
+ defer C.free(unsafe.Pointer(cField))
+ cSig := C.CString("[" + StringSign)
+ defer C.free(unsafe.Pointer(cSig))
+ fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
+ arr := C.jbyteArray(C.GetObjectField(env, obj, fid))
+ if arr == nil {
+ return nil
+ }
+ return GoByteArray(env, arr)
+}
+
+// JStringArray converts the provided slice of Go strings into a Java array of strings.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JStringArrayPtr(jEnv interface{}, strs []string) unsafe.Pointer {
+ env := getEnv(jEnv)
+ ret := C.NewObjectArray(env, C.jsize(len(strs)), jStringClass, nil)
+ for i, str := range strs {
+ C.SetObjectArrayElement(env, ret, C.jsize(i), C.jobject(JStringPtr(env, str)))
+ }
+ return unsafe.Pointer(ret)
+}
+
+// GoStringArray converts a Java string array to a Go string array.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func GoStringArray(jEnv, jStrArray interface{}) []string {
+ env := getEnv(jEnv)
+ jArr := getObjectArray(jStrArray)
+ if jArr == nil {
+ return nil
+ }
+ length := C.GetArrayLength(env, C.jarray(jArr))
+ ret := make([]string, int(length))
+ for i := 0; i < int(length); i++ {
+ ret[i] = GoString(env, C.jstring(C.GetObjectArrayElement(env, jArr, C.jsize(i))))
+ }
+ return ret
+}
+
+// JByteArray converts the provided Go byte slice into a Java byte array.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JByteArrayPtr(jEnv interface{}, bytes []byte) unsafe.Pointer {
+ env := getEnv(jEnv)
+ ret := C.NewByteArray(env, C.jsize(len(bytes)))
+ C.SetByteArrayRegion(env, ret, 0, C.jsize(len(bytes)), (*C.jbyte)(unsafe.Pointer(&bytes[0])))
+ return unsafe.Pointer(ret)
+}
+
+// GoByteArray converts the provided Java byte array into a Go byte slice.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func GoByteArray(jEnv, jArr interface{}) (ret []byte) {
+ env := getEnv(jEnv)
+ arr := getByteArray(jArr)
+ length := int(C.GetArrayLength(env, C.jarray(arr)))
+ ret = make([]byte, length)
+ bytes := C.GetByteArrayElements(env, arr, nil)
+ for i := 0; i < length; i++ {
+ ret[i] = byte(*bytes)
+ bytes = (*C.jbyte)(unsafe.Pointer(uintptr(unsafe.Pointer(bytes)) + unsafe.Sizeof(*bytes)))
+ }
+ return
+}
+
+// JMethodID returns the Java method ID for the given method.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JMethodIDPtr(jEnv, jClass interface{}, name, signature string) unsafe.Pointer {
+ env := getEnv(jEnv)
+ class := getClass(jClass)
+ cName := C.CString(name)
+ defer C.free(unsafe.Pointer(cName))
+ cSignature := C.CString(signature)
+ defer C.free(unsafe.Pointer(cSignature))
+ return unsafe.Pointer(C.GetMethodID(env, class, cName, cSignature))
+}
+
+// JFindClassOrDie returns the global references to the Java class with the
+// given pathname, or panic-s if the class cannot be found.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func JFindClassPtrOrDie(jEnv interface{}, name string) unsafe.Pointer {
+ env := getEnv(jEnv)
+ cName := C.CString(name)
+ defer C.free(unsafe.Pointer(cName))
+ class := C.FindClass(env, cName)
+ if err := JExceptionMsg(env); err != nil || class == nil {
+ panic(fmt.Sprintf("couldn't find class %s: %v", name, err))
+ }
+ return unsafe.Pointer(C.NewGlobalRef(env, C.jobject(class)))
+}
+
+// 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()
+
+// newSafeSet returns a new instance of a thread-safe set.
+func newSafeSet() *safeSet {
+ return &safeSet{
+ items: make(map[interface{}]bool),
+ }
+}
+
+// safeSet is a thread-safe set.
+type safeSet struct {
+ lock sync.Mutex
+ items map[interface{}]bool
+}
+
+func (s *safeSet) insert(item interface{}) {
+ s.lock.Lock()
+ defer s.lock.Unlock()
+ s.items[item] = true
+}
+
+func (s *safeSet) delete(item interface{}) {
+ s.lock.Lock()
+ defer s.lock.Unlock()
+ delete(s.items, item)
+}
+
+// Various functions that cast CGO types from various other packages into this
+// package's types.
+func getEnv(jEnv interface{}) *C.JNIEnv {
+ return (*C.JNIEnv)(unsafe.Pointer(PtrValue(jEnv)))
+}
+func getByteArray(jByteArray interface{}) C.jbyteArray {
+ return C.jbyteArray(unsafe.Pointer(PtrValue(jByteArray)))
+}
+func getObject(jObj interface{}) C.jobject {
+ return C.jobject(unsafe.Pointer(PtrValue(jObj)))
+}
+func getClass(jClass interface{}) C.jclass {
+ return C.jclass(unsafe.Pointer(PtrValue(jClass)))
+}
+func getString(jString interface{}) C.jstring {
+ return C.jstring(unsafe.Pointer(PtrValue(jString)))
+}
+func getObjectArray(jArray interface{}) C.jobjectArray {
+ return C.jobjectArray(unsafe.Pointer(PtrValue(jArray)))
+}
diff --git a/runtimes/google/security/jni/authorizer.go b/runtimes/google/security/jni/authorizer.go
new file mode 100644
index 0000000..9a00b91
--- /dev/null
+++ b/runtimes/google/security/jni/authorizer.go
@@ -0,0 +1,82 @@
+// +build android
+
+package jni
+
+import (
+ "fmt"
+ "runtime"
+ "unsafe"
+
+ "veyron/runtimes/google/jni/util"
+ "veyron2/security"
+)
+
+// #cgo LDFLAGS: -ljniwrapper
+// #include "jni_wrapper.h"
+// // CGO doesn't support variadic functions so we have to hard-code these
+// // functions to match the invoking code. Ugh!
+// static jobject CallAuthorizerNewContextObject(JNIEnv* env, jclass class, jmethodID id, jlong goContextPtr) {
+// return (*env)->NewObject(env, class, id, goContextPtr);
+// }
+// static void CallAuthorizerAuthorizeMethod(JNIEnv* env, jobject obj, jmethodID id, jobject context) {
+// (*env)->CallObjectMethod(env, obj, id, context);
+// }
+import "C"
+
+// NewAuthorizer returns a new security.Authorizer given the provided Java authorizer.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java types are passed in an empty interface
+// and then cast into their package local types.
+func NewAuthorizer(jEnv, jAuthPtr interface{}) security.Authorizer {
+ env := (*C.JNIEnv)(unsafe.Pointer(util.PtrValue(jEnv)))
+ jAuth := C.jobject(unsafe.Pointer(util.PtrValue(jAuthPtr)))
+ // We cannot cache Java environments as they are only valid in the current
+ // thread. We can, however, cache the Java VM and obtain an environment
+ // from it in whatever thread happens to be running at the time.
+ var jVM *C.JavaVM
+ if status := C.GetJavaVM(env, &jVM); status != 0 {
+ panic("couldn't get Java VM from the (Java) environment")
+ }
+ // Reference Java dispatcher; it will be de-referenced when the go
+ // dispatcher created below is garbage-collected (through the finalizer
+ // callback we setup below).
+ jAuth = C.NewGlobalRef(env, jAuth)
+ a := &authorizer{
+ jVM: jVM,
+ jAuth: jAuth,
+ }
+ runtime.SetFinalizer(a, func(a *authorizer) {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(a.jVM, &env, nil)
+ defer C.DetachCurrentThread(a.jVM)
+ C.DeleteGlobalRef(env, a.jAuth)
+ })
+ return a
+}
+
+type authorizer struct {
+ jVM *C.JavaVM
+ jAuth C.jobject
+}
+
+func (a *authorizer) Authorize(context security.Context) error {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(a.jVM, &env, nil)
+ defer C.DetachCurrentThread(a.jVM)
+ // Create a Java context.
+ util.GoRef(&context) // Un-refed when the Java Context object is finalized.
+ cid := C.jmethodID(util.JMethodIDPtr(env, jContextImplClass, "<init>", fmt.Sprintf("(%s)%s", util.LongSign, util.VoidSign)))
+ jContext := C.CallAuthorizerNewContextObject(env, jContextImplClass, cid, C.jlong(util.PtrValue(&context)))
+ // Run Java Authorizer.
+ contextSign := "Lcom/veyron2/security/Context;"
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, a.jAuth), "authorize", fmt.Sprintf("(%s)%s", contextSign, util.VoidSign)))
+ if mid == nil {
+ return fmt.Errorf("Srdjan's error")
+ }
+ return nil
+ C.CallAuthorizerAuthorizeMethod(env, a.jAuth, mid, jContext)
+ if err := util.JExceptionMsg(env); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/runtimes/google/security/jni/caveat.go b/runtimes/google/security/jni/caveat.go
new file mode 100644
index 0000000..e3901dc
--- /dev/null
+++ b/runtimes/google/security/jni/caveat.go
@@ -0,0 +1,67 @@
+// +build android
+
+package jni
+
+import (
+ "fmt"
+ "runtime"
+
+ "veyron/runtimes/google/jni/util"
+ "veyron2/security"
+)
+
+// #cgo LDFLAGS: -ljniwrapper
+// #include "jni_wrapper.h"
+//
+// // CGO doesn't support variadic functions so we have to hard-code these
+// // functions to match the invoking code. Ugh!
+// static jobject CallCaveatNewContextObject(JNIEnv* env, jclass class, jmethodID id, jlong goContextPtr) {
+// return (*env)->NewObject(env, class, id, goContextPtr);
+// }
+// static void CallCaveatValidateMethod(JNIEnv* env, jobject obj, jmethodID id, jobject context) {
+// return (*env)->CallVoidMethod(env, obj, id, context);
+// }
+import "C"
+
+func newCaveat(env *C.JNIEnv, jCaveat C.jobject) *caveat {
+ // We cannot cache Java environments as they are only valid in the current
+ // thread. We can, however, cache the Java VM and obtain an environment
+ // from it in whatever thread happens to be running at the time.
+ var jVM *C.JavaVM
+ if status := C.GetJavaVM(env, &jVM); status != 0 {
+ panic("couldn't get Java VM from the (Java) environment")
+ }
+ // Reference Java service caveat; it will be de-referenced when the go
+ // service caveat created below is garbage-collected (through the finalizer
+ // callback we setup just below).
+ jCaveat = C.NewGlobalRef(env, jCaveat)
+ c := &caveat{
+ jVM: jVM,
+ jCaveat: jCaveat,
+ }
+ runtime.SetFinalizer(c, func(c *caveat) {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ C.DeleteGlobalRef(env, c.jCaveat)
+ })
+ return c
+}
+
+type caveat struct {
+ jVM *C.JavaVM
+ jCaveat C.jobject
+}
+
+func (c *caveat) Validate(context security.Context) error {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ util.GoRef(&context) // un-refed when the Java Context object is finalized.
+ cid := C.jmethodID(util.JMethodIDPtr(env, jContextImplClass, "<init>", fmt.Sprintf("(%s)%s", util.LongSign, util.VoidSign)))
+ jContext := C.CallCaveatNewContextObject(env, jContextClass, cid, C.jlong(util.PtrValue(&context)))
+ contextSign := "Lcom/veyron2/security/Context;"
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jCaveat), "validate", fmt.Sprintf("(%s)%s", contextSign, util.VoidSign)))
+ C.CallCaveatValidateMethod(env, c.jCaveat, mid, jContext)
+ return util.JExceptionMsg(env)
+}
diff --git a/runtimes/google/security/jni/context.go b/runtimes/google/security/jni/context.go
new file mode 100644
index 0000000..57e6a31
--- /dev/null
+++ b/runtimes/google/security/jni/context.go
@@ -0,0 +1,144 @@
+// +build android
+
+package jni
+
+import (
+ "fmt"
+ "runtime"
+
+ "veyron/runtimes/google/jni/util"
+ inaming "veyron/runtimes/google/naming"
+ "veyron2/naming"
+ "veyron2/security"
+)
+
+// #cgo LDFLAGS: -ljniwrapper
+// #include "jni_wrapper.h"
+//
+// // CGO doesn't support variadic functions so we have to hard-code these
+// // functions to match the invoking code. Ugh!
+// static jstring CallContextStringMethod(JNIEnv* env, jobject obj, jmethodID id) {
+// return (jstring)(*env)->CallObjectMethod(env, obj, id);
+// }
+// static jint CallContextIntMethod(JNIEnv* env, jobject obj, jmethodID id) {
+// return (*env)->CallIntMethod(env, obj, id);
+// }
+// static jobject CallContextPublicIDMethod(JNIEnv* env, jobject obj, jmethodID id) {
+// return (*env)->CallObjectMethod(env, obj, id);
+// }
+import "C"
+
+func newContext(env *C.JNIEnv, jContext C.jobject) *context {
+ // We cannot cache Java environments as they are only valid in the current
+ // thread. We can, however, cache the Java VM and obtain an environment
+ // from it in whatever thread happens to be running at the time.
+ var jVM *C.JavaVM
+ if status := C.GetJavaVM(env, &jVM); status != 0 {
+ panic("couldn't get Java VM from the (Java) environment")
+ }
+ // Reference Java context; it will be de-referenced when the go context
+ // created below is garbage-collected (through the finalizer callback we
+ // setup just below).
+ jContext = C.NewGlobalRef(env, jContext)
+ c := &context{
+ jVM: jVM,
+ jContext: jContext,
+ }
+ runtime.SetFinalizer(c, func(c *context) {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ C.DeleteGlobalRef(env, c.jContext)
+ })
+ return c
+}
+
+type context struct {
+ jVM *C.JavaVM
+ jContext C.jobject
+}
+
+func (c *context) Method() string {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jContext), "method", fmt.Sprintf("()%s", util.StringSign)))
+ return util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+}
+
+func (c *context) Name() string {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jContext), "name", fmt.Sprintf("()%s", util.StringSign)))
+ return util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+}
+
+func (c *context) Suffix() string {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jContext), "suffix", fmt.Sprintf("()%s", util.StringSign)))
+ return util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+}
+
+func (c *context) Label() security.Label {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jContext), "label", fmt.Sprintf("()%s", util.IntSign)))
+ return security.Label(C.CallContextIntMethod(env, c.jContext, mid))
+}
+
+func (c *context) CaveatDischarges() security.CaveatDischargeMap {
+ // TODO(spetrovic): implement this method.
+ return nil
+}
+
+func (c *context) LocalID() security.PublicID {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ publicIDSign := "Lcom/veyron2/security/PublicID;"
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jContext), "localID", fmt.Sprintf("()%s", publicIDSign)))
+ jID := C.CallContextPublicIDMethod(env, c.jContext, mid)
+ return newPublicID(env, jID)
+}
+
+func (c *context) RemoteID() security.PublicID {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ publicIDSign := "Lcom/veyron2/security/PublicID;"
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jContext), "remoteID", fmt.Sprintf("()%s", publicIDSign)))
+ jID := C.CallContextPublicIDMethod(env, c.jContext, mid)
+ return newPublicID(env, jID)
+}
+
+func (c *context) LocalEndpoint() naming.Endpoint {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jContext), "localEndpoint", fmt.Sprintf("()%s", util.StringSign)))
+ // TODO(spetrovic): create a Java Endpoint interface.
+ epStr := util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+ ep, err := inaming.NewEndpoint(epStr)
+ if err != nil {
+ panic("Couldn't parse endpoint string: " + epStr)
+ }
+ return ep
+}
+
+func (c *context) RemoteEndpoint() naming.Endpoint {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(c.jVM, &env, nil)
+ defer C.DetachCurrentThread(c.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, c.jContext), "remoteEndpoint", fmt.Sprintf("()%s", util.StringSign)))
+ // TODO(spetrovic): create a Java Endpoint interface.
+ epStr := util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+ ep, err := inaming.NewEndpoint(epStr)
+ if err != nil {
+ panic("Couldn't parse endpoint string: " + epStr)
+ }
+ return ep
+}
diff --git a/runtimes/google/security/jni/crypto_util.go b/runtimes/google/security/jni/crypto_util.go
new file mode 100644
index 0000000..a2c8c93
--- /dev/null
+++ b/runtimes/google/security/jni/crypto_util.go
@@ -0,0 +1,95 @@
+package jni
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "fmt"
+)
+
+var (
+ oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
+ oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
+ oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
+ oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
+ oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
+)
+
+func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
+ switch curve {
+ case elliptic.P224():
+ return oidNamedCurveP224, true
+ case elliptic.P256():
+ return oidNamedCurveP256, true
+ case elliptic.P384():
+ return oidNamedCurveP384, true
+ case elliptic.P521():
+ return oidNamedCurveP521, true
+ }
+ return nil, false
+}
+
+// marshalPKCS8PrivateKey marshals the provided ECDSA private key into the
+// PKCS#8 private key format.
+func marshalPKCS8PrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
+ oid, ok := oidFromNamedCurve(key.PublicKey.Curve)
+ if !ok {
+ return nil, fmt.Errorf("illegal curve")
+ }
+ paramBytes, err := asn1.Marshal(oid)
+ if err != nil {
+ return nil, err
+ }
+ var algo pkix.AlgorithmIdentifier
+ algo.Algorithm = oidPublicKeyECDSA
+ algo.Parameters.FullBytes = paramBytes
+
+ privBytes, err := x509.MarshalECPrivateKey(key)
+ if err != nil {
+ return nil, err
+ }
+ pkcs8 := struct {
+ Version int
+ Algo pkix.AlgorithmIdentifier
+ PrivateKey []byte
+ }{
+ Version: 1,
+ Algo: algo,
+ PrivateKey: privBytes,
+ }
+ return asn1.Marshal(pkcs8)
+}
+
+// parsePKCS8PrivateKey parses the provided private key in the PKCS#8 format.
+func parsePKCS8PrivateKey(data []byte) (*ecdsa.PrivateKey, error) {
+ key, err := x509.ParsePKCS8PrivateKey(data)
+ if err != nil {
+ return nil, err
+ }
+ eckey, ok := key.(*ecdsa.PrivateKey)
+ if !ok {
+ return nil, fmt.Errorf("not an ECDSA private key")
+ }
+ return eckey, nil
+}
+
+// marshalPKIXPublicKey marshals the provided ECDSA public key into the
+// DER-encoded PKIX format.
+func marshalPKIXPublicKey(key *ecdsa.PublicKey) ([]byte, error) {
+ return x509.MarshalPKIXPublicKey(key)
+}
+
+// parsePKIXPublicKey parses the provided DER encoded public key.
+func parsePKIXPublicKey(data []byte) (*ecdsa.PublicKey, error) {
+ key, err := x509.ParsePKIXPublicKey(data)
+ if err != nil {
+ return nil, err
+ }
+ eckey, ok := key.(*ecdsa.PublicKey)
+ if !ok {
+ return nil, fmt.Errorf("not an ECDSA public key")
+ }
+ return eckey, nil
+}
diff --git a/runtimes/google/security/jni/crypto_util_test.go b/runtimes/google/security/jni/crypto_util_test.go
new file mode 100644
index 0000000..aca9c05
--- /dev/null
+++ b/runtimes/google/security/jni/crypto_util_test.go
@@ -0,0 +1,46 @@
+package jni
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "reflect"
+ "testing"
+)
+
+func TestCryptoUtilPublicKeyCoder(t *testing.T) {
+ priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("couldn't generate private key: %v", err)
+ }
+ pub := &priv.PublicKey
+ data, err := marshalPKIXPublicKey(pub)
+ if err != nil {
+ t.Fatalf("couldn't marshal public key: %v", err)
+ }
+ pubNew, err := parsePKIXPublicKey(data)
+ if err != nil {
+ t.Fatalf("couldn't parse public key: %v", err)
+ }
+ if !reflect.DeepEqual(pub, pubNew) {
+ t.Fatalf("public keys don't match")
+ }
+}
+
+func TestCryptoUtilPrivateKeyCoder(t *testing.T) {
+ priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("couldn't generate private key: %v", err)
+ }
+ data, err := marshalPKCS8PrivateKey(priv)
+ if err != nil {
+ t.Fatalf("couldn't marshal private key: %v", err)
+ }
+ privNew, err := parsePKCS8PrivateKey(data)
+ if err != nil {
+ t.Fatalf("couldn't parse private key: %v", err)
+ }
+ if !reflect.DeepEqual(priv, privNew) {
+ t.Fatalf("private keys don't match")
+ }
+}
diff --git a/runtimes/google/security/jni/jni.go b/runtimes/google/security/jni/jni.go
new file mode 100644
index 0000000..7f89560
--- /dev/null
+++ b/runtimes/google/security/jni/jni.go
@@ -0,0 +1,256 @@
+// +build android
+
+package jni
+
+import (
+ "encoding/asn1"
+ "fmt"
+ "time"
+ "unsafe"
+
+ "veyron/runtimes/google/jni/util"
+ isecurity "veyron/runtimes/google/security"
+ "veyron2/security"
+)
+
+// #cgo LDFLAGS: -ljniwrapper
+// #include "jni_wrapper.h"
+//
+// // CGO doesn't support variadic functions so we have to hard-code these
+// // functions to match the invoking code. Ugh!
+// static jobject CallNewECPublicKeyInfoObject(JNIEnv* env, jclass class, jmethodID id, jbyteArray keyX, jbyteArray keyY, jbyteArray encodedKey, jint fieldBitSize) {
+// return (*env)->NewObject(env, class, id, keyX, keyY, encodedKey, fieldBitSize);
+// }
+// static jobject CallNewCaveatObject(JNIEnv* env, jclass class, jmethodID id, jlong nativePtr) {
+// return (*env)->NewObject(env, class, id, nativePtr);
+// }
+// static jobject CallNewServiceCaveatObject(JNIEnv* env, jclass class, jmethodID id, jstring service, jobject caveat) {
+// return (*env)->NewObject(env, class, id, service, caveat);
+// }
+import "C"
+
+var (
+ // Global reference for com.veyron.runtimes.google.security.PublicID class.
+ jPublicIDImplClass C.jclass
+ // Global reference for com.veyron.runtimes.google.security.PublicID$ECPublicKeyInfo class.
+ jECPublicKeyInfoClass C.jclass
+ // Global reference for com.veyron.runtimes.google.security.Caveat class.
+ jCaveatImplClass C.jclass
+ // Global reference for com.veyron.runtimes.google.security.Context class.
+ jContextImplClass C.jclass
+ // Global reference for com.veyron2.security.Context class.
+ jContextClass C.jclass
+ // Global reference for com.veyron2.security.Caveat class.
+ jCaveatClass C.jclass
+ // Global reference for com.veyron2.security.ServiceCaveat class.
+ jServiceCaveatClass C.jclass
+)
+
+// Init initializes the JNI code with the given Java evironment. This method
+// must be called from the main Java thread.
+// NOTE: Because CGO creates package-local types and because this method may be
+// invoked from a different package, Java environment is passed in an empty
+// interface and then cast into the package-local environment type.
+func Init(jEnv interface{}) {
+ env := (*C.JNIEnv)(unsafe.Pointer(util.PtrValue(jEnv)))
+ // 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.
+ jPublicIDImplClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron/runtimes/google/security/PublicID"))
+ jECPublicKeyInfoClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron/runtimes/google/security/PublicID$ECPublicKeyInfo"))
+ jCaveatImplClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron/runtimes/google/security/Caveat"))
+ jContextClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron2/security/Context"))
+ jContextImplClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron/runtimes/google/security/Context"))
+ jCaveatClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron2/security/Caveat"))
+ jServiceCaveatClass = C.jclass(util.JFindClassPtrOrDie(env, "com/veyron2/security/ServiceCaveat"))
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicID_nativeNames
+func Java_com_veyron_runtimes_google_security_PublicID_nativeNames(env *C.JNIEnv, jPublicID C.jobject, goPublicIDPtr C.jlong) C.jobjectArray {
+ names := (*(*security.PublicID)(util.Ptr(goPublicIDPtr))).Names()
+ return C.jobjectArray(util.JStringArrayPtr(env, names))
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicID_nativeMatch
+func Java_com_veyron_runtimes_google_security_PublicID_nativeMatch(env *C.JNIEnv, jPublicID C.jobject, goPublicIDPtr C.jlong, jPattern C.jstring) C.jboolean {
+ if (*(*security.PublicID)(util.Ptr(goPublicIDPtr))).Match(security.PrincipalPattern(util.GoString(env, jPattern))) {
+ return C.JNI_TRUE
+ }
+ return C.JNI_FALSE
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicID_nativePublicKey
+func Java_com_veyron_runtimes_google_security_PublicID_nativePublicKey(env *C.JNIEnv, jPublicID C.jobject, goPublicIDPtr C.jlong) C.jobject {
+ key := (*(*security.PublicID)(util.Ptr(goPublicIDPtr))).PublicKey()
+ encoded, err := marshalPKIXPublicKey(key)
+ if err != nil {
+ util.JThrowV(env, err)
+ return C.jobject(nil)
+ }
+ cid := C.jmethodID(util.JMethodIDPtr(env, jECPublicKeyInfoClass, "<init>", fmt.Sprintf("([%s[%s[%s%s)%s", util.ByteSign, util.ByteSign, util.ByteSign, util.IntSign, util.VoidSign)))
+ return C.CallNewECPublicKeyInfoObject(env, jECPublicKeyInfoClass, cid, C.jbyteArray(util.JByteArrayPtr(env, key.X.Bytes())), C.jbyteArray(util.JByteArrayPtr(env, key.Y.Bytes())), C.jbyteArray(util.JByteArrayPtr(env, encoded)), C.jint(key.Params().BitSize))
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicID_nativeAuthorize
+func Java_com_veyron_runtimes_google_security_PublicID_nativeAuthorize(env *C.JNIEnv, jPublicID C.jobject, goPublicIDPtr C.jlong, jContext C.jobject) C.jlong {
+ id, err := (*(*security.PublicID)(util.Ptr(goPublicIDPtr))).Authorize(newContext(env, jContext))
+ if err != nil {
+ util.JThrowV(env, err)
+ return C.jlong(0)
+ }
+ util.GoRef(&id) // Un-refed when the Java PublicID is finalized.
+ return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicID_nativeThirdPartyCaveats
+func Java_com_veyron_runtimes_google_security_PublicID_nativeThirdPartyCaveats(env *C.JNIEnv, jPublicID C.jobject, goPublicIDPtr C.jlong) C.jobjectArray {
+ sCaveats := (*(*security.PublicID)(util.Ptr(goPublicIDPtr))).ThirdPartyCaveats()
+ caveatSign := "Lcom/veyron2/security/Caveat;"
+ jServiceCaveats := C.NewObjectArray(env, C.jsize(len(sCaveats)), jServiceCaveatClass, nil)
+ for i, sCaveat := range sCaveats {
+ util.GoRef(&sCaveat) // Un-refed when the Java Caveat object is finalized.
+ cid := C.jmethodID(util.JMethodIDPtr(env, jCaveatImplClass, "<init>", fmt.Sprintf("(%s)%s", util.LongSign, util.VoidSign)))
+ jCaveat := C.CallNewCaveatObject(env, jCaveatImplClass, cid, C.jlong(util.PtrValue(&sCaveat)))
+ scid := C.jmethodID(util.JMethodIDPtr(env, jServiceCaveatClass, "<init>", fmt.Sprintf("(%s%s)%s", util.StringSign, caveatSign, util.VoidSign)))
+ jServiceCaveat := C.CallNewServiceCaveatObject(env, jServiceCaveatClass, scid, C.jstring(util.JStringPtr(env, string(sCaveat.Service))), jCaveat)
+ C.SetObjectArrayElement(env, jServiceCaveats, C.jsize(i), jServiceCaveat)
+ }
+ return jServiceCaveats
+}
+
+//export Java_com_veyron_runtimes_google_security_PublicID_nativeFinalize
+func Java_com_veyron_runtimes_google_security_PublicID_nativeFinalize(env *C.JNIEnv, jPublicID C.jobject, goPublicIDPtr C.jlong) {
+ util.GoUnref((*security.PublicID)(util.Ptr(goPublicIDPtr)))
+}
+
+//export Java_com_veyron_runtimes_google_security_PrivateID_nativeCreate
+func Java_com_veyron_runtimes_google_security_PrivateID_nativeCreate(env *C.JNIEnv, jPrivateIDClass C.jclass, name C.jstring) C.jlong {
+ id, err := isecurity.NewPrivateID(util.GoString(env, name))
+ if err != nil {
+ util.JThrowV(env, err)
+ return C.jlong(0)
+ }
+ util.GoRef(&id) // Un-refed when the Java PrivateID is finalized.
+ return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_PrivateID_nativePublicID
+func Java_com_veyron_runtimes_google_security_PrivateID_nativePublicID(env *C.JNIEnv, jPrivateID C.jobject, goPrivateIDPtr C.jlong) C.jlong {
+ id := (*(*security.PrivateID)(util.Ptr(goPrivateIDPtr))).PublicID()
+ util.GoRef(&id) // Un-refed when the Java PublicID is finalized.
+ return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_PrivateID_nativeSign
+func Java_com_veyron_runtimes_google_security_PrivateID_nativeSign(env *C.JNIEnv, jPrivateID C.jobject, goPrivateIDPtr C.jlong, msg C.jbyteArray) C.jbyteArray {
+ s, err := (*(*security.PrivateID)(util.Ptr(goPrivateIDPtr))).Sign(util.GoByteArray(env, msg))
+ if err != nil {
+ util.JThrowV(env, err)
+ return nil
+ }
+ data, err := asn1.Marshal(s)
+ if err != nil {
+ util.JThrowV(env, err)
+ return nil
+ }
+ return C.jbyteArray(util.JByteArrayPtr(env, data))
+}
+
+//export Java_com_veyron_runtimes_google_security_PrivateID_nativeBless
+func Java_com_veyron_runtimes_google_security_PrivateID_nativeBless(env *C.JNIEnv, jPrivateID C.jobject, goPrivateIDPtr C.jlong, jPublicID C.jobject, name C.jstring, jDurationMS C.jlong, jServiceCaveats C.jobjectArray) C.jlong {
+ blessee := newPublicID(env, jPublicID)
+ duration := time.Duration(jDurationMS) * time.Millisecond
+ length := int(C.GetArrayLength(env, C.jarray(jServiceCaveats)))
+ caveats := make([]security.ServiceCaveat, length)
+ for i := 0; i < length; i++ {
+ jServiceCaveat := C.GetObjectArrayElement(env, jServiceCaveats, C.jsize(i))
+ caveats[i] = security.ServiceCaveat{
+ Service: security.PrincipalPattern(util.JStringField(env, jServiceCaveat, "service")),
+ Caveat: newCaveat(env, jServiceCaveat),
+ }
+ }
+ id, err := (*(*security.PrivateID)(util.Ptr(goPrivateIDPtr))).Bless(blessee, util.GoString(env, name), duration, caveats)
+ if err != nil {
+ util.JThrowV(env, err)
+ return C.jlong(0)
+ }
+ util.GoRef(&id) // Un-refed when the Java PublicID is finalized
+ return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_PrivateID_nativeDerive
+func Java_com_veyron_runtimes_google_security_PrivateID_nativeDerive(env *C.JNIEnv, jPrivateID C.jobject, goPrivateIDPtr C.jlong, jPublicID C.jobject) C.jlong {
+ id, err := (*(*security.PrivateID)(util.Ptr(goPrivateIDPtr))).Derive(newPublicID(env, jPublicID))
+ if err != nil {
+ util.JThrowV(env, err)
+ return C.jlong(0)
+ }
+ util.GoRef(&id) // Un-refed when the Java PrivateID is finalized.
+ return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_PrivateID_nativeFinalize
+func Java_com_veyron_runtimes_google_security_PrivateID_nativeFinalize(env *C.JNIEnv, jPrivateID C.jobject, goPrivateIDPtr C.jlong) {
+ util.GoUnref((*security.PrivateID)(util.Ptr(goPrivateIDPtr)))
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeMethod
+func Java_com_veyron_runtimes_google_security_Context_nativeMethod(env *C.JNIEnv, jContext C.jobject, goContextPtr C.jlong) C.jstring {
+ return C.jstring(util.JStringPtr(env, (*(*security.Context)(util.Ptr(goContextPtr))).Method()))
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeName
+func Java_com_veyron_runtimes_google_security_Context_nativeName(env *C.JNIEnv, jServerCall C.jobject, goContextPtr C.jlong) C.jstring {
+ return C.jstring(util.JStringPtr(env, (*(*security.Context)(util.Ptr(goContextPtr))).Name()))
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeSuffix
+func Java_com_veyron_runtimes_google_security_Context_nativeSuffix(env *C.JNIEnv, jServerCall C.jobject, goContextPtr C.jlong) C.jstring {
+ return C.jstring(util.JStringPtr(env, (*(*security.Context)(util.Ptr(goContextPtr))).Suffix()))
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeLabel
+func Java_com_veyron_runtimes_google_security_Context_nativeLabel(env *C.JNIEnv, jServerCall C.jobject, goContextPtr C.jlong) C.jint {
+ return C.jint((*(*security.Context)(util.Ptr(goContextPtr))).Label())
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeLocalID
+func Java_com_veyron_runtimes_google_security_Context_nativeLocalID(env *C.JNIEnv, jServerCall C.jobject, goContextPtr C.jlong) C.jlong {
+ id := (*(*security.Context)(util.Ptr(goContextPtr))).LocalID()
+ util.GoRef(&id) // Un-refed when the Java PublicID object is finalized.
+ return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeRemoteID
+func Java_com_veyron_runtimes_google_security_Context_nativeRemoteID(env *C.JNIEnv, jServerCall C.jobject, goContextPtr C.jlong) C.jlong {
+ id := (*(*security.Context)(util.Ptr(goContextPtr))).RemoteID()
+ util.GoRef(&id)
+ return C.jlong(util.PtrValue(&id))
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeLocalEndpoint
+func Java_com_veyron_runtimes_google_security_Context_nativeLocalEndpoint(env *C.JNIEnv, jServerCall C.jobject, goContextPtr C.jlong) C.jstring {
+ return C.jstring(util.JStringPtr(env, (*(*security.Context)(util.Ptr(goContextPtr))).LocalEndpoint().String()))
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeRemoteEndpoint
+func Java_com_veyron_runtimes_google_security_Context_nativeRemoteEndpoint(env *C.JNIEnv, jServerCall C.jobject, goContextPtr C.jlong) C.jstring {
+ return C.jstring(util.JStringPtr(env, (*(*security.Context)(util.Ptr(goContextPtr))).RemoteEndpoint().String()))
+}
+
+//export Java_com_veyron_runtimes_google_security_Context_nativeFinalize
+func Java_com_veyron_runtimes_google_security_Context_nativeFinalize(env *C.JNIEnv, jServerCall C.jobject, goContextPtr C.jlong) {
+ util.GoUnref((*security.Context)(util.Ptr(goContextPtr)))
+}
+
+//export Java_com_veyron_runtimes_google_security_Caveat_nativeValidate
+func Java_com_veyron_runtimes_google_security_Caveat_nativeValidate(env *C.JNIEnv, jServerCall C.jobject, goCaveatPtr C.jlong, jContext C.jobject) {
+ if err := (*(*security.Caveat)(util.Ptr(goCaveatPtr))).Validate(newContext(env, jContext)); err != nil {
+ util.JThrowV(env, err)
+ }
+}
+
+//export Java_com_veyron_runtimes_google_security_Caveat_nativeFinalize
+func Java_com_veyron_runtimes_google_security_Caveat_nativeFinalize(env *C.JNIEnv, jServerCall C.jobject, goCaveatPtr C.jlong) {
+ util.GoUnref((*security.Caveat)(util.Ptr(goCaveatPtr)))
+}
diff --git a/runtimes/google/security/jni/publicid.go b/runtimes/google/security/jni/publicid.go
new file mode 100644
index 0000000..dd4e778
--- /dev/null
+++ b/runtimes/google/security/jni/publicid.go
@@ -0,0 +1,165 @@
+// +build android
+
+package jni
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "fmt"
+ "math/big"
+ "runtime"
+
+ "veyron/runtimes/google/jni/util"
+ "veyron2/security"
+)
+
+// #cgo LDFLAGS: -ljniwrapper
+// #include "jni_wrapper.h"
+//
+// // CGO doesn't support variadic functions so we have to hard-code these
+// // functions to match the invoking code. Ugh!
+// static jobjectArray CallPublicIDNamesMethod(JNIEnv* env, jobject obj, jmethodID id) {
+// return (jobjectArray)(*env)->CallObjectMethod(env, obj, id);
+// }
+// static jboolean CallPublicIDMatchMethod(JNIEnv* env, jobject obj, jmethodID id, jstring pattern) {
+// return (*env)->CallBooleanMethod(env, obj, id, pattern);
+// }
+// static jobject CallPublicIDPublicKeyMethod(JNIEnv* env, jobject obj, jmethodID id) {
+// return (*env)->CallObjectMethod(env, obj, id);
+// }
+// static jobject CallPublicIDAuthorizeMethod(JNIEnv* env, jobject obj, jmethodID id, jobject context) {
+// return (*env)->CallObjectMethod(env, obj, id, context);
+// }
+// static jobjectArray CallPublicIDThirdPartyCaveatsMethod(JNIEnv* env, jobject obj, jmethodID id) {
+// return (jobjectArray)(*env)->CallObjectMethod(env, obj, id);
+// }
+// static jobject CallPublicIDNewContextObject(JNIEnv* env, jclass class, jmethodID id, jlong goContextPtr) {
+// return (*env)->NewObject(env, class, id, goContextPtr);
+// }
+// static jobject CallPublicIDGetKeyInfoMethod(JNIEnv* env, jclass class, jmethodID id, jobject key) {
+// return (*env)->CallStaticObjectMethod(env, class, id, key);
+// }
+import "C"
+
+func newPublicID(env *C.JNIEnv, jPublicID C.jobject) *publicID {
+ // We cannot cache Java environments as they are only valid in the current
+ // thread. We can, however, cache the Java VM and obtain an environment
+ // from it in whatever thread happens to be running at the time.
+ var jVM *C.JavaVM
+ if status := C.GetJavaVM(env, &jVM); status != 0 {
+ panic("couldn't get Java VM from the (Java) environment")
+ }
+ // Reference Java public id; it will be de-referenced when the go public id
+ // created below is garbage-collected (through the finalizer callback we
+ // setup just below).
+ jPublicID = C.NewGlobalRef(env, jPublicID)
+ id := &publicID{
+ jVM: jVM,
+ jPublicID: jPublicID,
+ }
+ runtime.SetFinalizer(id, func(id *publicID) {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(id.jVM, &env, nil)
+ defer C.DetachCurrentThread(id.jVM)
+ C.DeleteGlobalRef(env, id.jPublicID)
+ })
+ return id
+}
+
+type publicID struct {
+ jVM *C.JavaVM
+ jPublicID C.jobject
+}
+
+func (id *publicID) Names() []string {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(id.jVM, &env, nil)
+ defer C.DetachCurrentThread(id.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, id.jPublicID), "names", fmt.Sprintf("()[%s", util.StringSign)))
+ names := C.CallPublicIDNamesMethod(env, id.jPublicID, mid)
+ ret := make([]string, int(C.GetArrayLength(env, C.jarray(names))))
+ for i := 0; i < len(ret); i++ {
+ ret[i] = util.GoString(env, C.GetObjectArrayElement(env, names, C.jsize(i)))
+ }
+ return ret
+}
+
+func (id *publicID) Match(pattern security.PrincipalPattern) bool {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(id.jVM, &env, nil)
+ defer C.DetachCurrentThread(id.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, id.jPublicID), "match", fmt.Sprintf("(%s)%s", util.StringSign, util.BoolSign)))
+ return C.CallPublicIDMatchMethod(env, id.jPublicID, mid, C.jstring(util.JStringPtr(env, string(pattern)))) == C.JNI_TRUE
+}
+
+func (id *publicID) PublicKey() *ecdsa.PublicKey {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(id.jVM, &env, nil)
+ defer C.DetachCurrentThread(id.jVM)
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, id.jPublicID), "publicKey", fmt.Sprintf("()%s", util.ObjectSign)))
+ jPublicKey := C.CallPublicIDPublicKeyMethod(env, id.jPublicID, mid)
+ return newPublicKey(env, jPublicKey)
+}
+
+func (id *publicID) Authorize(context security.Context) (security.PublicID, error) {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(id.jVM, &env, nil)
+ defer C.DetachCurrentThread(id.jVM)
+ util.GoRef(&context) // un-refed when the Java Context object is finalized.
+ contextSign := "Lcom/veyron2/security/Context;"
+ publicIDSign := "Lcom/veyron2/security/PublicID;"
+ cid := C.jmethodID(util.JMethodIDPtr(env, jContextImplClass, "<init>", fmt.Sprintf("(%s)%s", util.LongSign, util.VoidSign)))
+ jContext := C.CallPublicIDNewContextObject(env, jContextImplClass, cid, C.jlong(util.PtrValue(&context)))
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, id.jPublicID), "authorize", fmt.Sprintf("(%s)%s", contextSign, publicIDSign)))
+ jPublicID := C.CallPublicIDAuthorizeMethod(env, id.jPublicID, mid, jContext)
+ if err := util.JExceptionMsg(env); err != nil {
+ return nil, err
+ }
+ return newPublicID(env, jPublicID), nil
+}
+
+func (id *publicID) ThirdPartyCaveats() []security.ServiceCaveat {
+ var env *C.JNIEnv
+ C.AttachCurrentThread(id.jVM, &env, nil)
+ defer C.DetachCurrentThread(id.jVM)
+ serviceCaveatSign := "Lcom/veyron2/security/ServiceCaveat;"
+ mid := C.jmethodID(util.JMethodIDPtr(env, C.GetObjectClass(env, id.jPublicID), "thirdPartyCaveats", fmt.Sprintf("()[%s", serviceCaveatSign)))
+ jServiceCaveats := C.CallPublicIDThirdPartyCaveatsMethod(env, id.jPublicID, mid)
+ length := int(C.GetArrayLength(env, C.jarray(jServiceCaveats)))
+ sCaveats := make([]security.ServiceCaveat, length)
+ for i := 0; i < length; i++ {
+ jServiceCaveat := C.GetObjectArrayElement(env, jServiceCaveats, C.jsize(i))
+ sCaveats[i] = security.ServiceCaveat{
+ Service: security.PrincipalPattern(util.JStringField(env, jServiceCaveat, "service")),
+ Caveat: newCaveat(env, jServiceCaveat),
+ }
+ }
+ return sCaveats
+}
+
+func newPublicKey(env *C.JNIEnv, jPublicKey C.jobject) *ecdsa.PublicKey {
+ keySign := "Ljava/security/interfaces/ECPublicKey;"
+ keyInfoSign := "Lcom/veyron/runtimes/google/security/JNIPublicID$ECPublicKeyInfo;"
+ mid := C.jmethodID(util.JMethodIDPtr(env, jPublicIDImplClass, "getKeyInfo", fmt.Sprintf("(%s)%s", keySign, keyInfoSign)))
+ jKeyInfo := C.CallPublicIDGetKeyInfoMethod(env, jPublicIDImplClass, mid, jPublicKey)
+ keyX := new(big.Int).SetBytes(util.JByteArrayField(env, jKeyInfo, "keyX"))
+ keyY := new(big.Int).SetBytes(util.JByteArrayField(env, jKeyInfo, "keyY"))
+ var curve elliptic.Curve
+ switch util.JIntField(env, jKeyInfo, "curveFieldBitSize") {
+ case 224:
+ curve = elliptic.P224()
+ case 256:
+ curve = elliptic.P256()
+ case 384:
+ curve = elliptic.P384()
+ case 521:
+ curve = elliptic.P521()
+ default: // Unknown curve
+ return nil
+ }
+ return &ecdsa.PublicKey{
+ Curve: curve,
+ X: keyX,
+ Y: keyY,
+ }
+}
diff --git a/services/mgmt/node/impl/const.go b/services/mgmt/node/impl/const.go
index 5615eee..c3c3d7b 100644
--- a/services/mgmt/node/impl/const.go
+++ b/services/mgmt/node/impl/const.go
@@ -1,6 +1,9 @@
package impl
const (
+ // BinaryEnv is the name of the environment variable that holds the
+ // object name used for obtaining the node manager binary.
+ BinaryEnv = "VEYRON_NM_BINARY"
// PreviousEnv is the name of the environment variable that holds
// the path to the workspace that contains the previous version of
// the node manager.
diff --git a/services/mgmt/node/impl/invoker.go b/services/mgmt/node/impl/invoker.go
index 9e4f19c..a0badb6 100644
--- a/services/mgmt/node/impl/invoker.go
+++ b/services/mgmt/node/impl/invoker.go
@@ -384,6 +384,7 @@
return errOperationFailed
}
output := "#!/bin/bash\n"
+ output += BinaryEnv + "=" + envelope.Binary + " "
output += PreviousEnv + "=" + filepath.Dir(path) + " "
output += strings.Join(envelope.Env, " ") + " "
output += filepath.Join(workspace, "noded") + " "
diff --git a/services/mgmt/node/noded/main.go b/services/mgmt/node/noded/main.go
index f40f457..9deb603 100644
--- a/services/mgmt/node/noded/main.go
+++ b/services/mgmt/node/noded/main.go
@@ -17,6 +17,15 @@
"veyron2/vlog"
)
+func generateEnvelope() *application.Envelope {
+ return &application.Envelope{
+ Args: os.Args,
+ Binary: os.Getenv(impl.BinaryEnv),
+ Env: os.Environ(),
+ Title: application.NodeManagerTitle,
+ }
+}
+
func main() {
// TODO(rthellend): Remove the address and protocol flags when the config manager is working.
var address, protocol, publishAs string
@@ -38,7 +47,7 @@
if err != nil {
vlog.Fatalf("Listen(%v, %v) failed: %v", protocol, address, err)
}
- suffix, envelope := "", &application.Envelope{}
+ suffix, envelope := "", generateEnvelope()
name := naming.MakeTerminal(naming.JoinAddressName(endpoint.String(), suffix))
vlog.VI(0).Infof("Node manager name: %v", name)
// TODO(jsimsa): Replace <PreviousEnv> with a command-line flag when