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