blob: 1fb6a6125f0831b8533cbc4052b74d27c5c964ce [file] [log] [blame]
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001// +build android
2
3package main
4
5import (
6 "flag"
7 "fmt"
8 "unsafe"
9
10 "veyron2/ipc"
11 "veyron2/rt"
12 "veyron2/verror"
13)
14
15// #include <stdlib.h>
16// #include "jni_wrapper.h"
17import "C"
18
19var (
20 // Global reference for com.veyron2.ipc.VeyronException class.
21 jVeyronExceptionClass C.jclass
22 // Global reference for com.veyron.runtimes.google.ipc.IDLInvoker class.
23 jIDLInvokerClass C.jclass
24 // Global reference for java.lang.Throwable class.
25 jThrowableClass C.jclass
26 // Global reference for java.lang.String class.
27 jStringClass C.jclass
28)
29
30// refs stores references to instances of various Go types, namely instances
31// that are referenced only by the Java code. The only purpose of this store
32// is to prevent Go runtime from garbage collecting those instances.
33var refs = newSafeSet()
34
35// serverPtr returns the pointer to the provided server instance, as a Java's
36// C.jlong type.
37func serverPtr(s ipc.Server) C.jlong {
38 return C.jlong(uintptr(unsafe.Pointer(&s)))
39}
40
41// getServer returns the server referenced by the provided pointer, or nil if
42// the pointer is 0.
43func getServer(env *C.JNIEnv, ptr C.jlong) ipc.Server {
44 if ptr == C.jlong(0) {
45 jThrow(env, "Go server pointer is nil")
46 return nil
47 }
48 return *(*ipc.Server)(unsafe.Pointer(uintptr(ptr)))
49}
50
51// serverPtr returns the pointer to the provided client instance, as a Java's
52// C.jlong type.
53func clientPtr(c *client) C.jlong {
54 return C.jlong(uintptr(unsafe.Pointer(c)))
55}
56
57// getClient returns the client referenced by the provided pointer, or nil if
58// the pointer is 0.
59func getClient(env *C.JNIEnv, ptr C.jlong) *client {
60 if ptr == C.jlong(0) {
61 jThrow(env, "Go client pointer is nil")
62 return nil
63 }
64 return (*client)(unsafe.Pointer(uintptr(ptr)))
65}
66
67// serverPtr returns the pointer to the provided clientCall instance, as a
68// Java's C.jlong type.
69func clientCallPtr(c *clientCall) C.jlong {
70 return C.jlong(uintptr(unsafe.Pointer(c)))
71}
72
Matt Rosencrantzf5afcaf2014-06-02 11:31:22 -070073// getCall returns the clientCall referenced by the provided pointer,
Jiri Simsa5293dcb2014-05-10 09:56:38 -070074// or nil if the pointer is 0.
Matt Rosencrantzf5afcaf2014-06-02 11:31:22 -070075func getCall(env *C.JNIEnv, ptr C.jlong) *clientCall {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070076 if ptr == C.jlong(0) {
77 jThrow(env, "Go client call pointer is nil")
78 return nil
79 }
80 return (*clientCall)(unsafe.Pointer(uintptr(ptr)))
81}
82
83//export JNI_OnLoad
84func JNI_OnLoad(jVM *C.JavaVM, reserved unsafe.Pointer) C.jint {
85 return C.JNI_VERSION_1_6
86}
87
88//export Java_com_veyron_runtimes_google_ipc_Runtime_nativeInit
89func Java_com_veyron_runtimes_google_ipc_Runtime_nativeInit(env *C.JNIEnv, jRuntime C.jclass) {
90 // Cache global references to all Java classes used by the package. This is
91 // necessary because JNI gets access to the class loader only in the system
92 // thread, so we aren't able to invoke FindClass in other threads.
93 jVeyronExceptionClass = jFindClassOrDie(env, "com/veyron2/ipc/VeyronException")
94 jIDLInvokerClass = jFindClassOrDie(env, "com/veyron/runtimes/google/ipc/IDLInvoker")
95 jThrowableClass = jFindClassOrDie(env, "java/lang/Throwable")
96 jStringClass = jFindClassOrDie(env, "java/lang/String")
97}
98
99//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeInit
100func Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeInit(env *C.JNIEnv, jServer C.jobject) C.jlong {
101 s, err := rt.R().NewServer()
102 if err != nil {
103 jThrow(env, fmt.Sprintf("Couldn't get new server from go runtime: %v", err))
104 return C.jlong(0)
105 }
106
107 // Ref.
108 refs.insert(s)
109 return serverPtr(s)
110}
111
112//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeRegister
113func Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeRegister(env *C.JNIEnv, jServer C.jobject, goServerPtr C.jlong, prefix C.jstring, dispatcher C.jobject) {
114 s := getServer(env, goServerPtr)
115 if s == nil {
116 jThrow(env, fmt.Sprintf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
117 return
118 }
119 // Create a new Dispatcher
120 d, err := newJNIDispatcher(env, dispatcher)
121 if err != nil {
122 jThrow(env, err.Error())
123 return
124 }
125 s.Register(goString(env, prefix), d)
126}
127
128//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeListen
129func Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativeListen(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong, protocol C.jstring, address C.jstring) C.jstring {
130 s := getServer(env, goServerPtr)
131 if s == nil {
132 jThrow(env, fmt.Sprintf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
133 return nil
134 }
135 ep, err := s.Listen(goString(env, protocol), goString(env, address))
136 if err != nil {
137 jThrow(env, err.Error())
138 return nil
139 }
140 return jString(env, ep.String())
141}
142
143//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativePublish
144func Java_com_veyron_runtimes_google_ipc_Runtime_00024Server_nativePublish(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong, name C.jstring) {
145 s := getServer(env, goServerPtr)
146 if s == nil {
147 jThrow(env, fmt.Sprintf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
148 return
149 }
150 if err := s.Publish(goString(env, name)); err != nil {
151 jThrow(env, err.Error())
152 return
153 }
154}
155
156//export Java_com_veyron_runtimes_google_ipc_jni_Runtime_00024Server_nativeStop
157func Java_com_veyron_runtimes_google_ipc_jni_Runtime_00024Server_nativeStop(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong) {
158 s := getServer(env, goServerPtr)
159 if s == nil {
160 jThrow(env, fmt.Sprintf("Couldn't find Go server with pointer: %d", int(goServerPtr)))
161 return
162 }
163 if err := s.Stop(); err != nil {
164 jThrow(env, err.Error())
165 return
166 }
167}
168
169//export Java_com_veyron_runtimes_google_ipc_jni_Runtime_00024Server_nativeFinalize
170func Java_com_veyron_runtimes_google_ipc_jni_Runtime_00024Server_nativeFinalize(env *C.JNIEnv, server C.jobject, goServerPtr C.jlong) {
171 s := getServer(env, goServerPtr)
172 if s != nil {
173 // Unref.
174 refs.delete(s)
175 }
176}
177
178//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeInit
179func Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeInit(env *C.JNIEnv, jClient C.jobject) C.jlong {
180 c, err := newClient()
181 if err != nil {
182 jThrow(env, fmt.Sprintf("Couldn't get new client from go runtime: %v", err))
183 return C.jlong(0)
184 }
185 // Ref.
186 refs.insert(c)
187 return clientPtr(c)
188}
189
190//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeStartCall
191func Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeStartCall(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong, name C.jstring, method C.jstring, jsonArgs C.jobjectArray, jPath C.jstring, timeoutMillis C.jlong) C.jlong {
192 c := getClient(env, goClientPtr)
193 if c == nil {
194 jThrow(env, fmt.Sprintf("Couldn't find Go client with pointer: %d", int(goClientPtr)))
195 return C.jlong(0)
196 }
197 call, err := c.StartCall(env, goString(env, name), goString(env, method), jsonArgs, jPath, timeoutMillis)
198 if err != nil {
199 jThrow(env, fmt.Sprintf("Couldn't start Go call: %v", err))
200 return C.jlong(0)
201 }
202 return clientCallPtr(call)
203}
204
205//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeClose
206func Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeClose(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong) {
207 c := getClient(env, goClientPtr)
208 if c != nil {
209 c.Close()
210 }
211}
212
213//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeFinalize
214func Java_com_veyron_runtimes_google_ipc_Runtime_00024Client_nativeFinalize(env *C.JNIEnv, jClient C.jobject, goClientPtr C.jlong) {
215 c := getClient(env, goClientPtr)
216 if c != nil {
217 // Unref.
218 refs.delete(c)
219 }
220}
221
Matt Rosencrantzf5afcaf2014-06-02 11:31:22 -0700222//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeFinish
223func Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeFinish(env *C.JNIEnv, jClient C.jobject, goCallPtr C.jlong) C.jobjectArray {
224 c := getCall(env, goCallPtr)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700225 if c == nil {
Matt Rosencrantzf5afcaf2014-06-02 11:31:22 -0700226 jThrow(env, fmt.Sprintf("Couldn't find Go client with pointer: %d", int(goCallPtr)))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700227 return nil
228 }
229 ret, err := c.Finish(env)
230 if err != nil {
231 // Could be an application error, so we throw it with jThrowV.
232 jThrowV(env, verror.Convert(err))
233 return nil
234 }
235 // Unref.
236 refs.delete(c)
237 return ret
238}
239
Matt Rosencrantzf5afcaf2014-06-02 11:31:22 -0700240//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeCancel
241func Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeCancel(env *C.JNIEnv, jClient C.jobject, goCallPtr C.jlong) {
242 c := getCall(env, goCallPtr)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700243 if c != nil {
244 c.Cancel()
245 }
246}
247
Matt Rosencrantzf5afcaf2014-06-02 11:31:22 -0700248//export Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeFinalize
249func Java_com_veyron_runtimes_google_ipc_Runtime_00024Call_nativeFinalize(env *C.JNIEnv, jClient C.jobject, goCallPtr C.jlong) {
250 c := getCall(env, goCallPtr)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700251 if c != nil {
252 refs.delete(c)
253 }
254}
255
256func main() {
257 // Send all logging to stderr, so that the output is visible in Android. Note that if this
258 // flag is removed, the process will likely crash as android requires that all logs are written
259 // into a specific directory.
260 flag.Set("logtostderr", "true")
261 rt.Init()
262}