1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "apxwin.h"
18 #include "handles.h"
19 #include "javajni.h"
20 #include "private.h"
21
22 #include <jni.h>
23
24 #ifndef JNI_VERSION_1_6
25 #error -------------------------------------------------------
26 #error JAVA 5 AND EARLIER ARE NO LONGER SUPPORTED
27 #error -------------------------------------------------------
28 #endif
29
30 #define JNI_VERSION_DEFAULT JNI_VERSION_1_6
31
32 /* Need to be able to detect Java 9 without requiring compilation against Java 9
33 * headers.
34 */
35 #ifndef JNI_VERSION_9
36 #define JNI_VERSION_9 0x00090000
37 #endif
38
39 /* Standard jvm.dll prototypes
40 * since only single jvm can exist per process
41 * make those global
42 */
43
44 DYNLOAD_TYPE_DECLARE(JNI_GetDefaultJavaVMInitArgs, JNICALL, jint)(void *);
45 static DYNLOAD_FPTR_DECLARE(JNI_GetDefaultJavaVMInitArgs) = NULL;
46
47 DYNLOAD_TYPE_DECLARE(JNI_CreateJavaVM, JNICALL, jint)(JavaVM **, void **, void *);
48 static DYNLOAD_FPTR_DECLARE(JNI_CreateJavaVM) = NULL;
49
50 DYNLOAD_TYPE_DECLARE(JNI_GetCreatedJavaVMs, JNICALL, jint)(JavaVM **, jsize, jsize *);
51 static DYNLOAD_FPTR_DECLARE(JNI_GetCreatedJavaVMs) = NULL;
52
53 DYNLOAD_TYPE_DECLARE(JVM_DumpAllStacks, JNICALL, void)(JNIEnv *, jclass);
54 static DYNLOAD_FPTR_DECLARE(JVM_DumpAllStacks) = NULL;
55
56 static HANDLE _st_sys_jvmDllHandle = NULL;
57 static JavaVM *_st_sys_jvm = NULL;
58
59 DYNLOAD_TYPE_DECLARE(SetDllDirectoryW, WINAPI, BOOL)(LPCWSTR);
60 static DYNLOAD_FPTR_DECLARE(SetDllDirectoryW) = NULL;
61
62 #define JVM_DELETE_CLAZZ(jvm, cl) \
63 APXMACRO_BEGIN \
64 if ((jvm)->lpEnv && (jvm)->cl.jClazz) { \
65 (*((jvm)->lpEnv))->DeleteGlobalRef((jvm)->lpEnv, (jvm)->cl.jClazz); \
66 (jvm)->cl.jClazz = NULL; \
67 } APXMACRO_END
68
69 #define JVM_EXCEPTION_CHECK(jvm) \
70 ((*((jvm)->lpEnv))->ExceptionCheck((jvm)->lpEnv) != JNI_OK)
71
72 #define JVM_EXCEPTION_CLEAR(jvm) \
73 APXMACRO_BEGIN \
74 if ((jvm)->lpEnv) { \
75 if ((*((jvm)->lpEnv))->ExceptionCheck((jvm)->lpEnv)) { \
76 (*((jvm)->lpEnv))->ExceptionDescribe((jvm)->lpEnv); \
77 (*((jvm)->lpEnv))->ExceptionClear((jvm)->lpEnv); \
78 } \
79 } APXMACRO_END
80
81 #define JNI_LOCAL_UNREF(obj) \
82 (*(lpJava->lpEnv))->DeleteLocalRef(lpJava->lpEnv, obj)
83
84 #define JNICALL_0(fName) \
85 ((*(lpJava->lpEnv))->fName(lpJava->lpEnv))
86
87 #define JNICALL_1(fName, a1) \
88 ((*(lpJava->lpEnv))->fName(lpJava->lpEnv, (a1)))
89
90 #define JNICALL_2(fName, a1, a2) \
91 ((*(lpJava->lpEnv))->fName(lpJava->lpEnv, (a1), (a2)))
92
93 #define JNICALL_3(fName, a1, a2, a3) \
94 ((*(lpJava->lpEnv))->fName(lpJava->lpEnv, (a1), (a2), (a3)))
95
96 #define JNICALL_4(fName, a1, a2, a3, a4) \
97 ((*(lpJava->lpEnv))->fName(lpJava->lpEnv, (a1), (a2), (a3), (a4)))
98
99 typedef struct APXJAVASTDCLAZZ {
100 CHAR sClazz[1024];
101 CHAR sMethod[512];
102 jclass jClazz;
103 jmethodID jMethod;
104 jobject jObject;
105 jarray jArgs;
106 } APXJAVASTDCLAZZ, *LPAPXJAVASTDCLAZZ;
107
108 typedef struct APXJAVAVM {
109 DWORD dwOptions;
110 APXJAVASTDCLAZZ clString;
111 APXJAVASTDCLAZZ clWorker;
112 jint iVersion;
113 jsize iVmCount;
114 JNIEnv *lpEnv;
115 JavaVM *lpJvm;
116 /* JVM worker thread info */
117 HANDLE hWorkerThread;
118 DWORD iWorkerThread;
119 DWORD dwWorkerStatus;
120 SIZE_T szStackSize;
121 HANDLE hWorkerSync;
122 HANDLE hWorkerInit;
123 } APXJAVAVM, *LPAPXJAVAVM;
124
125 /* This is no longer exported in jni.h
126 * However Java uses it internally to get
127 * the default stack size
128 */
129 typedef struct APX_JDK1_1InitArgs {
130 jint version;
131
132 char **properties;
133 jint checkSource;
134 jint nativeStackSize;
135 jint javaStackSize;
136 jint minHeapSize;
137 jint maxHeapSize;
138 jint verifyMode;
139 char *classpath;
140
141 char padding[128];
142 } APX_JDK1_1InitArgs;
143
144 #define JAVA_CLASSPATH "-Djava.class.path="
145 #define JAVA_CLASSPATH_W L"-Djava.class.path="
146 #define JAVA_CLASSSTRING "java/lang/String"
147 #define MSVCRT71_DLLNAME L"\\msvcrt71.dll"
148
149 static DWORD vmExitCode = 0;
150
__apxJvmAttachEnv(LPAPXJAVAVM lpJava,JNIEnv ** lpEnv,LPBOOL lpAttached)151 static __inline BOOL __apxJvmAttachEnv(LPAPXJAVAVM lpJava, JNIEnv **lpEnv,
152 LPBOOL lpAttached)
153 {
154 jint _iStatus;
155
156 if (!_st_sys_jvm || !lpJava->lpJvm)
157 return FALSE;
158 _iStatus = (*(lpJava->lpJvm))->GetEnv(lpJava->lpJvm,
159 (void **)lpEnv,
160 lpJava->iVersion);
161 if (_iStatus != JNI_OK) {
162 if (_iStatus == JNI_EDETACHED) {
163 _iStatus = (*(lpJava->lpJvm))->AttachCurrentThread(lpJava->lpJvm,
164 (void **)lpEnv, NULL);
165 if (lpAttached)
166 *lpAttached = TRUE;
167 }
168 }
169 if (_iStatus != JNI_OK) {
170 *lpEnv = NULL;
171 return FALSE;
172 }
173 else
174 return TRUE;
175 }
176
__apxJvmAttach(LPAPXJAVAVM lpJava)177 static __inline BOOL __apxJvmAttach(LPAPXJAVAVM lpJava)
178 {
179 return __apxJvmAttachEnv(lpJava, &lpJava->lpEnv, NULL);
180 }
181
__apxJvmDetach(LPAPXJAVAVM lpJava)182 static __inline BOOL __apxJvmDetach(LPAPXJAVAVM lpJava)
183 {
184 if (!_st_sys_jvm || !lpJava->lpJvm)
185 return FALSE;
186 if ((*(lpJava->lpJvm))->DetachCurrentThread(lpJava->lpJvm) != JNI_OK) {
187 lpJava->lpEnv = NULL;
188 return FALSE;
189 }
190 else
191 return TRUE;
192 }
193
__apxLoadJvmDll(APXHANDLE hPool,LPCWSTR szJvmDllPath,LPCWSTR szJavaHome)194 static BOOL __apxLoadJvmDll(APXHANDLE hPool, LPCWSTR szJvmDllPath, LPCWSTR szJavaHome)
195 {
196 UINT errMode;
197 WCHAR jreAltPath[SIZ_PATHLEN];
198 LPWSTR dllJvmPath = (LPWSTR)szJvmDllPath;
199 DYNLOAD_FPTR_DECLARE(SetDllDirectoryW);
200 DWORD i, l = 0;
201 WCHAR jreBinPath[SIZ_PATHLEN];
202
203 if (!IS_INVALID_HANDLE(_st_sys_jvmDllHandle))
204 return TRUE; /* jvm.dll is already loaded */
205
206 if (dllJvmPath && *dllJvmPath) {
207 /* Explicit JVM path.
208 * Check if provided argument is valid
209 */
210 if (GetFileAttributesW(dllJvmPath) == INVALID_FILE_ATTRIBUTES) {
211 /* DAEMON-247: Invalid RuntimeLib explicitly specified is error.
212 */
213 apxLogWrite(APXLOG_MARK_ERROR "Invalid RuntimeLib specified '%S'", dllJvmPath);
214 return FALSE;
215 }
216 apxLogWrite(APXLOG_MARK_DEBUG "Explicit RuntimeLib specified '%S'", dllJvmPath);
217 }
218 else {
219 // No explicit JVM path. Use the standard registry locations.
220 dllJvmPath = apxGetJavaSoftRuntimeLib(NULL);
221 apxLogWrite(APXLOG_MARK_DEBUG "No explicit RuntimeLib specified. Checking registry. Found '%S'", dllJvmPath);
222 }
223
224 if (GetFileAttributesW(dllJvmPath) == INVALID_FILE_ATTRIBUTES) {
225 /* DAEMON-184: RuntimeLib registry key is invalid.
226 * Check from Jre JavaHome registry key directly
227 */
228 LPWSTR szJreHome = apxGetJavaSoftHome(NULL, TRUE);
229 if (szJreHome) {
230 apxLogWrite(APXLOG_MARK_DEBUG "Invalid RuntimeLib '%S', Checking registry for JRE home. Found '%S'", dllJvmPath, szJreHome);
231 lstrlcpyW(jreAltPath, SIZ_PATHLEN, szJreHome);
232 lstrlcatW(jreAltPath, SIZ_PATHLEN, L"\\bin\\server\\jvm.dll");
233 dllJvmPath = jreAltPath;
234 } else {
235 apxLogWrite(APXLOG_MARK_DEBUG "Invalid RuntimeLib '%S', Checking registry for JRE home. None found.", dllJvmPath);
236 }
237 }
238
239 if (GetFileAttributesW(dllJvmPath) == INVALID_FILE_ATTRIBUTES) {
240 /* DAEMON-247: JavaSoft JRE registry keys are invalid / not present
241 * Check from Procrun's JavaHome registry key
242 */
243 if (szJavaHome) {
244 apxLogWrite(APXLOG_MARK_DEBUG "Using explicitly configured JavaHome '%S'", szJavaHome);
245 lstrlcpyW(jreAltPath, SIZ_PATHLEN, szJavaHome);
246 lstrlcatW(jreAltPath, SIZ_PATHLEN, L"\\bin\\server\\jvm.dll");
247 dllJvmPath = jreAltPath;
248 }
249 }
250
251 if (GetFileAttributesW(dllJvmPath) == INVALID_FILE_ATTRIBUTES) {
252 /* DAEMON-404: JRE home in registry invalid / not present.
253 * Explicit JavaHome invalid / not present
254 * Check from JDK JavaHome registry key directly
255 */
256 LPWSTR szJdkHome = apxGetJavaSoftHome(NULL, FALSE);
257 if (szJdkHome) {
258 apxLogWrite(APXLOG_MARK_DEBUG "Invalid RuntimeLib '%S', Checking registry for JDK home. Found '%S'", dllJvmPath, szJdkHome);
259 lstrlcpyW(jreAltPath, SIZ_PATHLEN, szJdkHome);
260 lstrlcatW(jreAltPath, SIZ_PATHLEN, L"\\bin\\server\\jvm.dll");
261 dllJvmPath = jreAltPath;
262 } else {
263 apxLogWrite(APXLOG_MARK_DEBUG "Invalid RuntimeLib '%S', Checking registry for JDK home. None found.", dllJvmPath);
264 }
265 }
266
267 /* Suppress the not found system popup message */
268 errMode = SetErrorMode(SEM_FAILCRITICALERRORS);
269
270 lstrlcpyW(jreBinPath, SIZ_PATHLEN, dllJvmPath);
271
272 for (i = lstrlenW(jreBinPath); i > 0, l < 2; i--) {
273 if (jreBinPath[i] == L'\\' || jreBinPath[i] == L'/') {
274 jreBinPath[i] = L'\0';
275 l++;
276 }
277 }
278
279 /* Add Java bin path to the PATH to fix loading of awt.dll */
280 apxLogWrite(APXLOG_MARK_DEBUG "Adding Java bin path to the PATH to fix loading of awt.dll: '%S'", jreBinPath);
281 apxAddToPathW(hPool, jreBinPath);
282
283 /* Set the environment using putenv, so JVM can use it */
284 apxSetInprocEnvironment();
285
286 apxLogWrite(APXLOG_MARK_DEBUG "Loading JVM DLL '%S'", dllJvmPath);
287 _st_sys_jvmDllHandle = LoadLibraryExW(dllJvmPath, NULL, 0);
288 if (IS_INVALID_HANDLE(_st_sys_jvmDllHandle) &&
289 GetFileAttributesW(dllJvmPath) != INVALID_FILE_ATTRIBUTES) {
290 WCHAR crtBinPath[SIZ_PATHLEN];
291
292 /* There is a file but cannot be loaded.
293 * Try to load the MSVCRTxx.dll before JVM.dll
294 */
295 apxLogWrite(APXLOG_MARK_ERROR "Found '%S' but couldn't load it.", dllJvmPath);
296
297 lstrlcpyW(jreBinPath, SIZ_PATHLEN, dllJvmPath);
298 if(l == 2) {
299 lstrlcpyW(crtBinPath, SIZ_PATHLEN, jreBinPath);
300 lstrlcatW(crtBinPath, SIZ_PATHLEN, MSVCRT71_DLLNAME);
301 if (GetFileAttributesW(crtBinPath) != INVALID_FILE_ATTRIBUTES) {
302 apxLogWrite(APXLOG_MARK_DEBUG "Loading '%S'.", crtBinPath);
303 if (LoadLibraryW(crtBinPath)) {
304 /* Found MSVCRTxx.dll
305 */
306 apxLogWrite(APXLOG_MARK_DEBUG "Preloaded '%S'", crtBinPath);
307 }
308 else {
309 apxLogWrite(APXLOG_MARK_DEBUG "Failed preloading '%S'.", crtBinPath);
310 }
311 }
312 }
313 }
314 /* This shouldn't happen, but try to search in %PATH% */
315 if (IS_INVALID_HANDLE(_st_sys_jvmDllHandle)) {
316 apxLogWrite(APXLOG_MARK_DEBUG "Invalid JVM DLL handle.");
317 apxLogWrite(APXLOG_MARK_DEBUG "Loading JVM DLL '%S' using LOAD_WITH_ALTERED_SEARCH_PATH.", dllJvmPath);
318 _st_sys_jvmDllHandle = LoadLibraryExW(dllJvmPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
319 }
320 if (IS_INVALID_HANDLE(_st_sys_jvmDllHandle)) {
321 apxLogWrite(APXLOG_MARK_DEBUG "Invalid JVM DLL handle.");
322 DYNLOAD_FPTR_ADDRESS(SetDllDirectoryW, KERNEL32);
323 if (l == 2) {
324 apxLogWrite(APXLOG_MARK_DEBUG "Setting DLL search path to '%S'", jreBinPath);
325 DYNLOAD_CALL(SetDllDirectoryW)(jreBinPath);
326 }
327 apxLogWrite(APXLOG_MARK_DEBUG "Loading JVM DLL '%S'.", dllJvmPath);
328 _st_sys_jvmDllHandle = LoadLibraryExW(dllJvmPath, NULL, 0);
329 if (IS_INVALID_HANDLE(_st_sys_jvmDllHandle)) {
330 apxLogWrite(APXLOG_MARK_DEBUG "Invalid JVM DLL handle.");
331 apxLogWrite(APXLOG_MARK_DEBUG "Loading JVM DLL '%S' using LOAD_WITH_ALTERED_SEARCH_PATH.", dllJvmPath);
332 _st_sys_jvmDllHandle = LoadLibraryExW(dllJvmPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
333 }
334 }
335 /* Restore the error mode signalization */
336 SetErrorMode(errMode);
337 if (IS_INVALID_HANDLE(_st_sys_jvmDllHandle)) {
338 apxLogWrite(APXLOG_MARK_ERROR "Invalid JVM DLL handle.");
339 apxLogWrite(APXLOG_MARK_SYSERR);
340 return FALSE;
341 }
342 DYNLOAD_FPTR_LOAD(JNI_GetDefaultJavaVMInitArgs, _st_sys_jvmDllHandle);
343 DYNLOAD_FPTR_LOAD(JNI_CreateJavaVM, _st_sys_jvmDllHandle);
344 DYNLOAD_FPTR_LOAD(JNI_GetCreatedJavaVMs, _st_sys_jvmDllHandle);
345 DYNLOAD_FPTR_LOAD(JVM_DumpAllStacks, _st_sys_jvmDllHandle);
346
347 if (!DYNLOAD_FPTR(JNI_GetDefaultJavaVMInitArgs) ||
348 !DYNLOAD_FPTR(JNI_CreateJavaVM) ||
349 !DYNLOAD_FPTR(JNI_GetCreatedJavaVMs)) {
350 apxLogWrite(APXLOG_MARK_SYSERR);
351 apxLogWrite(APXLOG_MARK_DEBUG "Freeing JVM DLL.");
352 FreeLibrary(_st_sys_jvmDllHandle);
353 _st_sys_jvmDllHandle = NULL;
354 apxLogWrite(APXLOG_MARK_ERROR "Failed loading JNI function pointers.");
355 return FALSE;
356 }
357
358 /* Real voodo ... */
359 return TRUE;
360 }
361
__apxJavaJniCallback(APXHANDLE hObject,UINT uMsg,WPARAM wParam,LPARAM lParam)362 static BOOL __apxJavaJniCallback(APXHANDLE hObject, UINT uMsg,
363 WPARAM wParam, LPARAM lParam)
364 {
365 LPAPXJAVAVM lpJava;
366 DWORD dwJvmRet = 0;
367
368 lpJava = APXHANDLE_DATA(hObject);
369 switch (uMsg) {
370 case WM_CLOSE:
371 if (_st_sys_jvm && lpJava->lpJvm) {
372 if (!IS_INVALID_HANDLE(lpJava->hWorkerThread)) {
373 if (GetExitCodeThread(lpJava->hWorkerThread, &dwJvmRet) &&
374 dwJvmRet == STILL_ACTIVE) {
375 TerminateThread(lpJava->hWorkerThread, 5);
376 }
377 }
378 SAFE_CLOSE_HANDLE(lpJava->hWorkerThread);
379 __apxJvmAttach(lpJava);
380 JVM_DELETE_CLAZZ(lpJava, clWorker);
381 JVM_DELETE_CLAZZ(lpJava, clString);
382 __apxJvmDetach(lpJava);
383 /* Check if this is the jvm loader */
384 if (!lpJava->iVmCount && _st_sys_jvmDllHandle) {
385 /* Unload JVM dll */
386 FreeLibrary(_st_sys_jvmDllHandle);
387 _st_sys_jvmDllHandle = NULL;
388 }
389 lpJava->lpJvm = NULL;
390 }
391 break;
392 default:
393 break;
394 }
395 return TRUE;
396 UNREFERENCED_PARAMETER(wParam);
397 UNREFERENCED_PARAMETER(lParam);
398 }
399
400 APXHANDLE
apxCreateJava(APXHANDLE hPool,LPCWSTR szJvmDllPath,LPCWSTR szJavaHome)401 apxCreateJava(APXHANDLE hPool, LPCWSTR szJvmDllPath, LPCWSTR szJavaHome)
402 {
403
404 APXHANDLE hJava;
405 LPAPXJAVAVM lpJava;
406 jsize iVmCount;
407 JavaVM *lpJvm = NULL;
408 struct APX_JDK1_1InitArgs jArgs1_1;
409
410 if (!__apxLoadJvmDll(hPool, szJvmDllPath, szJavaHome)) {
411 apxLogWrite(APXLOG_MARK_ERROR "Failed to load JVM DLL '%S', home '%S'.", szJvmDllPath, szJavaHome);
412 return NULL;
413 }
414 apxLogWrite(APXLOG_MARK_DEBUG "Loaded JVM DLL '%S', home '%S'.", szJvmDllPath, szJavaHome);
415
416 /*
417 * JNI_GetCreatedJavaVMs
418 */
419 apxLogWrite(APXLOG_MARK_DEBUG "JNI_GetCreatedJavaVMs...");
420 if (DYNLOAD_FPTR(JNI_GetCreatedJavaVMs)(&lpJvm, 1, &iVmCount) != JNI_OK) {
421 apxLogWrite(APXLOG_MARK_ERROR "JNI_GetCreatedJavaVMs failed.");
422 return NULL;
423 }
424 if (iVmCount && !lpJvm) {
425 apxLogWrite(APXLOG_MARK_ERROR "JNI_GetCreatedJavaVMs OK but JavaVM pointer is NULL.");
426 return NULL;
427 }
428
429 hJava = apxHandleCreate(hPool, 0,
430 NULL, sizeof(APXJAVAVM),
431 __apxJavaJniCallback);
432 if (IS_INVALID_HANDLE(hJava)) {
433 apxLogWrite(APXLOG_MARK_ERROR "Failed to create handle.");
434 return NULL;
435 }
436 hJava->dwType = APXHANDLE_TYPE_JVM;
437 lpJava = APXHANDLE_DATA(hJava);
438 lpJava->lpJvm = lpJvm;
439 lpJava->iVmCount = iVmCount;
440
441 /* Guess the stack size
442 */
443 AplZeroMemory(&jArgs1_1, sizeof(jArgs1_1));
444 jArgs1_1.version = JNI_VERSION_1_1;
445 DYNLOAD_FPTR(JNI_GetDefaultJavaVMInitArgs)(&jArgs1_1);
446 if (jArgs1_1.javaStackSize < 0 || jArgs1_1.javaStackSize > (2048 * 1024))
447 jArgs1_1.javaStackSize = 0;
448 lpJava->szStackSize = (SIZE_T)jArgs1_1.javaStackSize;
449
450 if (!_st_sys_jvm)
451 _st_sys_jvm = lpJvm;
452 return hJava;
453 }
454
__apxJavaDestroyThread(LPVOID lpParameter)455 static DWORD WINAPI __apxJavaDestroyThread(LPVOID lpParameter)
456 {
457 JavaVM *lpJvm = (JavaVM *)lpParameter;
458 (*lpJvm)->DestroyJavaVM(lpJvm);
459 return 0;
460 }
461
462 BOOL
apxDestroyJvm(DWORD dwTimeout)463 apxDestroyJvm(DWORD dwTimeout)
464 {
465 if (_st_sys_jvm) {
466 DWORD tid;
467 HANDLE hWaiter;
468 BOOL rv = FALSE;
469 JavaVM *lpJvm = _st_sys_jvm;
470
471 _st_sys_jvm = NULL;
472 (*lpJvm)->DetachCurrentThread(lpJvm);
473 hWaiter = CreateThread(NULL, 0, __apxJavaDestroyThread,
474 (void *)lpJvm, 0, &tid);
475 if (IS_INVALID_HANDLE(hWaiter)) {
476 apxLogWrite(APXLOG_MARK_SYSERR);
477 return FALSE;
478 }
479 if (WaitForSingleObject(hWaiter, dwTimeout) == WAIT_OBJECT_0)
480 rv = TRUE;
481 CloseHandle(hWaiter);
482 return rv;
483 }
484 else
485 return FALSE;
486 }
487
__apxIsJava9()488 static BOOL __apxIsJava9()
489 {
490 JavaVMInitArgs vmArgs;
491 vmArgs.version = JNI_VERSION_9;
492 /* Returns an error if requested version is not supported */
493 if (DYNLOAD_FPTR(JNI_GetDefaultJavaVMInitArgs)(&vmArgs) != JNI_OK) {
494 return FALSE;
495 }
496 else {
497 return TRUE;
498 }
499 }
500
__apxMultiSzToJvmOptions(APXHANDLE hPool,LPCSTR lpString,LPCSTR lpString9,JavaVMOption ** lppArray,DWORD nExtra,DWORD bJniVfprintf)501 static DWORD __apxMultiSzToJvmOptions(APXHANDLE hPool,
502 LPCSTR lpString,
503 LPCSTR lpString9,
504 JavaVMOption **lppArray,
505 DWORD nExtra,
506 DWORD bJniVfprintf)
507 {
508 DWORD i = 0, n = 0, n9 = 0, nTotal, l = 0, l9 = 0, lTotal;
509 char *buff;
510 LPSTR p;
511
512 if (lpString) {
513 l = __apxGetMultiSzLengthA(lpString, &n);
514 }
515 if (__apxIsJava9() && lpString9) {
516 l9 = __apxGetMultiSzLengthA(lpString9, &n9);
517 }
518
519 nTotal = n + n9 + nExtra;
520 lTotal = l + l9;
521
522 buff = apxPoolAlloc(hPool, (nTotal + 1) * sizeof(JavaVMOption) + (lTotal + 1));
523
524 *lppArray = (JavaVMOption *)buff;
525 p = (LPSTR)(buff + (nTotal + 1) * sizeof(JavaVMOption));
526 if (lpString)
527 AplCopyMemory(p, lpString, l + 1);
528 if (bJniVfprintf) {
529 // If present, vfprintf is set first so it can be used to report errors
530 // in later options. Increment indexes to account for this.
531 i++;
532 n++;
533 }
534 for (; i < n; i++) {
535 (*lppArray)[i].optionString = p;
536 while (*p)
537 p++;
538 p++;
539 }
540 if (lpString9)
541 AplCopyMemory(p, lpString9, l9 + 1);
542 for (; i < (n + n9); i++) {
543 (*lppArray)[i].optionString = p;
544 while (*p)
545 p++;
546 p++;
547 }
548
549 return nTotal;
550 }
551
552 /* a hook for a function that redirects all VM messages. */
__apxJniVfprintf(FILE * fp,const char * format,va_list args)553 static jint JNICALL __apxJniVfprintf(FILE *fp, const char *format, va_list args)
554 {
555 jint rv;
556 CHAR sBuf[1024+16];
557 rv = wvsprintfA(sBuf, format, args);
558 if (apxLogWrite(APXLOG_MARK_INFO "%s", sBuf) == 0)
559 fputs(sBuf, stdout);
560 return rv;
561 UNREFERENCED_PARAMETER(fp);
562 }
563
__apxJniExit(jint exitCode)564 static void JNICALL __apxJniExit(jint exitCode)
565 {
566 apxLogWrite(APXLOG_MARK_DEBUG "Exit hook with exit code %d", exitCode);
567 vmExitCode = exitCode;
568 return;
569 }
570
__apxJniAbort()571 static void JNICALL __apxJniAbort()
572 {
573 apxLogWrite(APXLOG_MARK_DEBUG "JVM aborted");
574 // Set the exit code to a non-zero value to indicate a non-standard exit
575 vmExitCode = 1;
576 return;
577 }
578
__apxStrIndexA(LPCSTR szStr,int nCh)579 static LPSTR __apxStrIndexA(LPCSTR szStr, int nCh)
580 {
581 LPSTR pStr;
582
583 for (pStr = (LPSTR)szStr; *pStr; pStr++) {
584 if (*pStr == nCh)
585 return pStr;
586 }
587 return NULL;
588 }
589
__apxStrnCatA(APXHANDLE hPool,LPSTR pOrg,LPCSTR szStr,LPCSTR szAdd)590 static LPSTR __apxStrnCatA(APXHANDLE hPool, LPSTR pOrg, LPCSTR szStr, LPCSTR szAdd)
591 {
592 DWORD len = 1;
593 DWORD nas = pOrg == NULL;
594 if (pOrg)
595 len += lstrlenA(pOrg);
596 if (szStr)
597 len += lstrlenA(szStr);
598 if (szAdd)
599 len += lstrlenA(szAdd);
600 pOrg = (LPSTR)apxPoolRealloc(hPool, pOrg, len);
601 if (pOrg) {
602 if (nas)
603 *pOrg = '\0';
604 if (szStr)
605 lstrcatA(pOrg, szStr);
606 if (szAdd)
607 lstrcatA(pOrg, szAdd);
608 }
609 return pOrg;
610 }
611
__apxEvalPathPart(APXHANDLE hPool,LPSTR pStr,LPCSTR szPattern)612 static LPSTR __apxEvalPathPart(APXHANDLE hPool, LPSTR pStr, LPCSTR szPattern)
613 {
614 HANDLE hFind;
615 WIN32_FIND_DATAA stGlob;
616 char szJars[MAX_PATH + 1];
617 char szPath[MAX_PATH + 1];
618
619 if (lstrlenA(szPattern) > (sizeof(szJars) - 5)) {
620 return __apxStrnCatA(hPool, pStr, szPattern, NULL);
621 }
622 lstrcpyA(szJars, szPattern);
623 szPath[0] = ';';
624 szPath[1] = '\0';
625 lstrcatA(szPath, szPattern);
626 lstrcatA(szJars, ".jar");
627 /* Remove the trailing asterisk
628 */
629 szPath[lstrlenA(szPath) - 1] = '\0';
630 if ((hFind = FindFirstFileA(szJars, &stGlob)) == INVALID_HANDLE_VALUE) {
631 /* Find failed
632 */
633 return pStr;
634 }
635 pStr = __apxStrnCatA(hPool, pStr, &szPath[1], stGlob.cFileName);
636 if (pStr == NULL) {
637 FindClose(hFind);
638 return NULL;
639 }
640 while (FindNextFileA(hFind, &stGlob) != 0) {
641 pStr = __apxStrnCatA(hPool, pStr, szPath, stGlob.cFileName);
642 if (pStr == NULL)
643 break;
644 }
645 FindClose(hFind);
646 return pStr;
647 }
648
649 /**
650 * Call glob on each PATH like string path.
651 * Glob is called only if the part ends with asterisk in which
652 * case asterisk is replaced by *.jar when searching
653 */
__apxEvalClasspath(APXHANDLE hPool,LPCSTR szCp)654 static LPSTR __apxEvalClasspath(APXHANDLE hPool, LPCSTR szCp)
655 {
656 LPSTR pCpy = __apxStrnCatA(hPool, NULL, JAVA_CLASSPATH, szCp);
657 LPSTR pGcp = NULL;
658 LPSTR pPos;
659 LPSTR pPtr;
660
661 if (!pCpy)
662 return NULL;
663 pPtr = pCpy + sizeof(JAVA_CLASSPATH) - 1;
664 while ((pPos = __apxStrIndexA(pPtr, ';'))) {
665 *pPos = '\0';
666 if (pGcp)
667 pGcp = __apxStrnCatA(hPool, pGcp, ";", NULL);
668 else
669 pGcp = __apxStrnCatA(hPool, NULL, JAVA_CLASSPATH, NULL);
670 if ((pPos > pPtr) && (*(pPos - 1) == '*')) {
671 if (!(pGcp = __apxEvalPathPart(hPool, pGcp, pPtr))) {
672 /* Error.
673 * Return the original string processed so far.
674 */
675 return pCpy;
676 }
677 }
678 else {
679 /* Standard path element */
680 if (!(pGcp = __apxStrnCatA(hPool, pGcp, pPtr, NULL))) {
681 /* Error.
682 * Return the original string processed so far.
683 */
684 return pCpy;
685 }
686 }
687 pPtr = pPos + 1;
688 }
689 if (*pPtr) {
690 int end = lstrlenA(pPtr);
691 if (pGcp)
692 pGcp = __apxStrnCatA(hPool, pGcp, ";", NULL);
693 else
694 pGcp = __apxStrnCatA(hPool, NULL, JAVA_CLASSPATH, NULL);
695 if (end > 0 && pPtr[end - 1] == '*') {
696 /* Last path elemet ends with star
697 * Do a globbing.
698 */
699 pGcp = __apxEvalPathPart(hPool, pGcp, pPtr);
700 }
701 else {
702 /* Just add the part */
703 pGcp = __apxStrnCatA(hPool, pGcp, pPtr, NULL);
704 }
705 }
706 /* Free the allocated copy */
707 if (pGcp) {
708 apxFree(pCpy);
709 return pGcp;
710 }
711 else
712 return pCpy;
713 }
714
715 /* ANSI version only */
716 BOOL
apxJavaInitialize(APXHANDLE hJava,LPCSTR szClassPath,LPCVOID lpOptions,LPCVOID lpOptions9,DWORD dwMs,DWORD dwMx,DWORD dwSs,DWORD bJniVfprintf)717 apxJavaInitialize(APXHANDLE hJava, LPCSTR szClassPath,
718 LPCVOID lpOptions, LPCVOID lpOptions9,
719 DWORD dwMs, DWORD dwMx, DWORD dwSs,
720 DWORD bJniVfprintf)
721 {
722 LPAPXJAVAVM lpJava;
723 JavaVMInitArgs vmArgs;
724 JavaVMOption *lpJvmOptions;
725 DWORD i, nOptions, sOptions = 0;
726 BOOL rv = FALSE;
727
728 if (hJava->dwType != APXHANDLE_TYPE_JVM)
729 return FALSE;
730
731 lpJava = APXHANDLE_DATA(hJava);
732
733 if (lpJava->iVmCount) {
734 if (!lpJava->lpEnv && !__apxJvmAttach(lpJava)) {
735 if (lpJava->iVersion == JNI_VERSION_1_6) {
736 apxLogWrite(APXLOG_MARK_ERROR "Unable To Attach the JVM");
737 return FALSE;
738 }
739 else
740 lpJava->iVersion = JNI_VERSION_1_6;
741 if (!__apxJvmAttach(lpJava)) {
742 apxLogWrite(APXLOG_MARK_ERROR "Unable To Attach the JVM");
743 return FALSE;
744 }
745 }
746 lpJava->iVersion = JNICALL_0(GetVersion);
747 if (lpJava->iVersion < JNI_VERSION_1_6) {
748 apxLogWrite(APXLOG_MARK_ERROR "Unsupported JNI version %#08x", lpJava->iVersion);
749 return FALSE;
750 }
751 rv = TRUE;
752 }
753 else {
754 CHAR iB[3][64];
755 LPSTR szCp = NULL;
756 int result;
757 lpJava->iVersion = JNI_VERSION_DEFAULT;
758 if (dwMs)
759 ++sOptions;
760 if (dwMx)
761 ++sOptions;
762 if (dwSs)
763 ++sOptions;
764 if (bJniVfprintf)
765 ++sOptions;
766 if (szClassPath && *szClassPath)
767 ++sOptions;
768
769 sOptions++; /* unconditionally set for extraInfo exit */
770 sOptions++; /* unconditionally set for extraInfo abort */
771
772 nOptions = __apxMultiSzToJvmOptions(hJava->hPool, lpOptions, lpOptions9,
773 &lpJvmOptions, sOptions, bJniVfprintf);
774 if (bJniVfprintf) {
775 /* Default JNI error printer. Hard-coded to position zero if present */
776 lpJvmOptions[0].optionString = "vfprintf";
777 lpJvmOptions[0].extraInfo = __apxJniVfprintf;
778 --sOptions;
779 }
780
781 if (szClassPath && *szClassPath) {
782 szCp = __apxEvalClasspath(hJava->hPool, szClassPath);
783 if (szCp == NULL) {
784 apxLogWrite(APXLOG_MARK_ERROR "Invalid classpath %s", szClassPath);
785 return FALSE;
786 }
787 lpJvmOptions[nOptions - sOptions].optionString = szCp;
788 --sOptions;
789 }
790
791 /* unconditionally add hook for System.exit() in order to store exit code */
792 lpJvmOptions[nOptions - sOptions].optionString = "exit";
793 lpJvmOptions[nOptions - sOptions].extraInfo = __apxJniExit;
794 --sOptions;
795
796 /* unconditionally add hook for abort in order to store exit code */
797 lpJvmOptions[nOptions - sOptions].optionString = "abort";
798 lpJvmOptions[nOptions - sOptions].extraInfo = __apxJniAbort;
799 --sOptions;
800
801 if (dwMs) {
802 wsprintfA(iB[0], "-Xms%dm", dwMs);
803 lpJvmOptions[nOptions - sOptions].optionString = iB[0];
804 --sOptions;
805 }
806 if (dwMx) {
807 wsprintfA(iB[1], "-Xmx%dm", dwMx);
808 lpJvmOptions[nOptions - sOptions].optionString = iB[1];
809 --sOptions;
810 }
811 if (dwSs) {
812 wsprintfA(iB[2], "-Xss%dk", dwSs);
813 lpJvmOptions[nOptions - sOptions].optionString = iB[2];
814 --sOptions;
815 }
816 for (i = 0; i < nOptions; i++) {
817 apxLogWrite(APXLOG_MARK_DEBUG "Jvm Option[%d] %s", i,
818 lpJvmOptions[i].optionString);
819 }
820 vmArgs.options = lpJvmOptions;
821 vmArgs.nOptions = nOptions;
822 vmArgs.version = lpJava->iVersion;
823 vmArgs.ignoreUnrecognized = JNI_FALSE;
824 result = DYNLOAD_FPTR(JNI_CreateJavaVM)(&(lpJava->lpJvm),
825 (void **)&(lpJava->lpEnv),
826 &vmArgs);
827 if (result != JNI_OK) {
828 apxLogWrite(APXLOG_MARK_ERROR "CreateJavaVM Failed with error [%d]", result);
829 rv = FALSE;
830 }
831 else {
832 rv = TRUE;
833 if (!_st_sys_jvm)
834 _st_sys_jvm = lpJava->lpJvm;
835 }
836 apxFree(szCp);
837 apxFree(lpJvmOptions);
838 }
839 if (rv)
840 return TRUE;
841 else
842 return FALSE;
843 }
844
845 /* ANSI version only */
846 DWORD
apxJavaCmdInitialize(APXHANDLE hPool,LPCWSTR szClassPath,LPCWSTR szClass,LPCWSTR szOptions,DWORD dwMs,DWORD dwMx,DWORD dwSs,LPCWSTR szCmdArgs,LPWSTR ** lppArray)847 apxJavaCmdInitialize(APXHANDLE hPool, LPCWSTR szClassPath, LPCWSTR szClass,
848 LPCWSTR szOptions, DWORD dwMs, DWORD dwMx,
849 DWORD dwSs, LPCWSTR szCmdArgs, LPWSTR **lppArray)
850 {
851
852 DWORD i, nJVM, nCmd, nTotal, lJVM, lCmd;
853 LPWSTR p;
854
855 /* Calculate the number of all arguments */
856 nTotal = 0;
857 if (szClassPath)
858 ++nTotal;
859 if (szClass)
860 ++nTotal;
861 lJVM = __apxGetMultiSzLengthW(szOptions, &nJVM);
862 nTotal += nJVM;
863 lCmd = __apxGetMultiSzLengthW(szCmdArgs, &nCmd);
864 nTotal += nCmd;
865 if (dwMs)
866 ++nTotal;
867 if (dwMx)
868 ++nTotal;
869 if (dwSs)
870 ++nTotal;
871
872 if (nTotal == 0)
873 return 0;
874
875 /* Allocate the array to store all arguments' pointers
876 */
877 *lppArray = (LPWSTR *)apxPoolAlloc(hPool, (nTotal + 2) * sizeof(LPWSTR));
878
879 /* Process JVM options */
880 i = 0;
881 if (nJVM && lJVM) {
882 p = (LPWSTR)apxPoolAlloc(hPool, (lJVM + 1) * sizeof(WCHAR));
883 AplCopyMemory(p, szOptions, (lJVM + 1) * sizeof(WCHAR) + sizeof(WCHAR));
884 for (; i < nJVM; i++) {
885 (*lppArray)[i] = p;
886 while (*p)
887 p++;
888 p++;
889 }
890 }
891
892 /* Process the 3 extra JVM options */
893 if (dwMs) {
894 p = (LPWSTR)apxPoolAlloc(hPool, 64 * sizeof(WCHAR));
895 wsprintfW(p, L"-Xms%dm", dwMs);
896 (*lppArray)[i++] = p;
897 }
898 if (dwMx) {
899 p = (LPWSTR)apxPoolAlloc(hPool, 64 * sizeof(WCHAR));
900 wsprintfW(p, L"-Xmx%dm", dwMx);
901 (*lppArray)[i++] = p;
902 }
903 if (dwSs) {
904 p = (LPWSTR)apxPoolAlloc(hPool, 64 * sizeof(WCHAR));
905 wsprintfW(p, L"-Xss%dk", dwSs);
906 (*lppArray)[i++] = p;
907 }
908
909 /* Process the classpath and class */
910 if (szClassPath) {
911 p = (LPWSTR)apxPoolAlloc(hPool, (lstrlenW(JAVA_CLASSPATH_W) + lstrlenW(szClassPath)) * sizeof(WCHAR));
912 lstrcpyW(p, JAVA_CLASSPATH_W);
913 lstrcatW(p, szClassPath);
914 (*lppArray)[i++] = p;
915 }
916 if (szClass) {
917 p = (LPWSTR)apxPoolAlloc(hPool, (lstrlenW(szClass)) * sizeof(WCHAR));
918 lstrcpyW(p, szClass);
919 (*lppArray)[i++] = p;
920 }
921
922 /* Process command arguments */
923 if (nCmd && lCmd) {
924 p = (LPWSTR)apxPoolAlloc(hPool, (lCmd + 1) * sizeof(WCHAR));
925 AplCopyMemory(p, szCmdArgs, (lCmd + 1) * sizeof(WCHAR) + sizeof(WCHAR));
926 for (; i < nTotal; i++) {
927 (*lppArray)[i] = p;
928 while (*p)
929 p++;
930 p++;
931 }
932 }
933
934 (*lppArray)[++i] = NULL;
935
936 return nTotal;
937 }
938
939
940 BOOL
apxJavaLoadMainClass(APXHANDLE hJava,LPCSTR szClassName,LPCSTR szMethodName,LPCVOID lpArguments)941 apxJavaLoadMainClass(APXHANDLE hJava, LPCSTR szClassName,
942 LPCSTR szMethodName,
943 LPCVOID lpArguments)
944 {
945 LPWSTR *lpArgs = NULL;
946 DWORD nArgs;
947 LPAPXJAVAVM lpJava;
948 jclass jClazz;
949 LPCSTR szSignature = "([Ljava/lang/String;)V";
950
951 if (hJava->dwType != APXHANDLE_TYPE_JVM)
952 return FALSE;
953 lpJava = APXHANDLE_DATA(hJava);
954 if (!lpJava)
955 return FALSE;
956 if (IS_EMPTY_STRING(szMethodName))
957 szMethodName = "main";
958 if (lstrcmpA(szClassName, "java/lang/System") == 0) {
959 /* Usable only for exit method, so force */
960 szSignature = "(I)V";
961 szMethodName = "exit";
962 }
963 lstrlcpyA(lpJava->clWorker.sClazz, 1024, szClassName);
964 lstrlcpyA(lpJava->clWorker.sMethod, 512, szMethodName);
965
966 jClazz = JNICALL_1(FindClass, JAVA_CLASSSTRING);
967 if (!jClazz) {
968 JVM_EXCEPTION_CLEAR(lpJava);
969 apxLogWrite(APXLOG_MARK_ERROR "FindClass " JAVA_CLASSSTRING " failed");
970 return FALSE;
971 }
972 lpJava->clString.jClazz = JNICALL_1(NewGlobalRef, jClazz);
973 JNI_LOCAL_UNREF(jClazz);
974 /* Find the class */
975 jClazz = JNICALL_1(FindClass, szClassName);
976 if (!jClazz) {
977 JVM_EXCEPTION_CLEAR(lpJava);
978 apxLogWrite(APXLOG_MARK_ERROR "FindClass %s failed", szClassName);
979 return FALSE;
980 }
981 /* Make the class global so that worker thread can attach */
982 lpJava->clWorker.jClazz = JNICALL_1(NewGlobalRef, jClazz);
983 JNI_LOCAL_UNREF(jClazz);
984
985 lpJava->clWorker.jMethod = JNICALL_3(GetStaticMethodID,
986 lpJava->clWorker.jClazz,
987 szMethodName, szSignature);
988 if (!lpJava->clWorker.jMethod) {
989 JVM_EXCEPTION_CLEAR(lpJava);
990 apxLogWrite(APXLOG_MARK_ERROR "Method 'static void %s(String[])' not found in Class %s",
991 szMethodName, szClassName);
992 return FALSE;
993 }
994 if (lstrcmpA(szClassName, "java/lang/System")) {
995 nArgs = apxMultiSzToArrayW(hJava->hPool, lpArguments, &lpArgs);
996 lpJava->clWorker.jArgs = JNICALL_3(NewObjectArray, nArgs,
997 lpJava->clString.jClazz, NULL);
998 if (nArgs) {
999 DWORD i;
1000 for (i = 0; i < nArgs; i++) {
1001 jstring arg = JNICALL_2(NewString, lpArgs[i], lstrlenW(lpArgs[i]));
1002 JNICALL_3(SetObjectArrayElement, lpJava->clWorker.jArgs, i, arg);
1003 apxLogWrite(APXLOG_MARK_DEBUG "argv[%d] = %S", i, lpArgs[i]);
1004 }
1005 }
1006 apxFree(lpArgs);
1007 }
1008 return TRUE;
1009 }
1010
1011 /* Main Java application worker thread
1012 * It will launch Java main and wait until
1013 * it finishes.
1014 */
__apxJavaWorkerThread(LPVOID lpParameter)1015 static DWORD WINAPI __apxJavaWorkerThread(LPVOID lpParameter)
1016 {
1017 #define WORKER_EXIT(x) do { rv = x; goto finished; } while(0)
1018 DWORD rv = 0;
1019 LPAPXJAVAVM lpJava = NULL;
1020 LPAPXJAVA_THREADARGS pArgs = (LPAPXJAVA_THREADARGS)lpParameter;
1021 APXHANDLE hJava;
1022
1023 hJava = (APXHANDLE)pArgs->hJava;
1024 if (hJava->dwType != APXHANDLE_TYPE_JVM)
1025 WORKER_EXIT(1);
1026 lpJava = APXHANDLE_DATA(pArgs->hJava);
1027 if (!lpJava)
1028 WORKER_EXIT(1);
1029 if (!apxJavaInitialize(pArgs->hJava,
1030 pArgs->szClassPath,
1031 pArgs->lpOptions, pArgs->lpOptions9,
1032 pArgs->dwMs, pArgs->dwMx, pArgs->dwSs,
1033 pArgs->bJniVfprintf)) {
1034 WORKER_EXIT(2);
1035 }
1036 if (pArgs->szLibraryPath && *pArgs->szLibraryPath) {
1037 DYNLOAD_FPTR_ADDRESS(SetDllDirectoryW, KERNEL32);
1038 DYNLOAD_CALL(SetDllDirectoryW)(pArgs->szLibraryPath);
1039 apxLogWrite(APXLOG_MARK_DEBUG "DLL search path set to '%S'",
1040 pArgs->szLibraryPath);
1041 }
1042 if (!apxJavaLoadMainClass(pArgs->hJava,
1043 pArgs->szClassName,
1044 pArgs->szMethodName,
1045 pArgs->lpArguments)) {
1046 WORKER_EXIT(3);
1047 }
1048 apxJavaSetOut(pArgs->hJava, TRUE, pArgs->szStdErrFilename);
1049 apxJavaSetOut(pArgs->hJava, FALSE, pArgs->szStdOutFilename);
1050
1051 /* Check if we have a class and a method */
1052 if (!lpJava->clWorker.jClazz || !lpJava->clWorker.jMethod) {
1053 WORKER_EXIT(4);
1054 }
1055 if (!__apxJvmAttach(lpJava)) {
1056 WORKER_EXIT(5);
1057 }
1058 apxLogWrite(APXLOG_MARK_DEBUG "Java worker thread started for %s:%s",
1059 lpJava->clWorker.sClazz, lpJava->clWorker.sMethod);
1060 lpJava->dwWorkerStatus = 1;
1061 SetEvent(lpJava->hWorkerInit);
1062 /* Ensure apxJavaStart worker has read our status */
1063 WaitForSingleObject(lpJava->hWorkerSync, INFINITE);
1064 apxLogWrite(APXLOG_MARK_DEBUG "JNI calling static void method %s:%s",
1065 lpJava->clWorker.sClazz, lpJava->clWorker.sMethod);
1066 JNICALL_3(CallStaticVoidMethod,
1067 lpJava->clWorker.jClazz,
1068 lpJava->clWorker.jMethod,
1069 lpJava->clWorker.jArgs);
1070 if (JVM_EXCEPTION_CHECK(lpJava)) {
1071 apxLogWrite(APXLOG_MARK_DEBUG "Exception has been thrown");
1072 vmExitCode = 1;
1073 (*((lpJava)->lpEnv))->ExceptionDescribe((lpJava)->lpEnv);
1074 __apxJvmDetach(lpJava);
1075 WORKER_EXIT(6);
1076 }
1077 else {
1078 __apxJvmDetach(lpJava);
1079 }
1080 finished:
1081 if (lpJava) {
1082 lpJava->dwWorkerStatus = 0;
1083 apxLogWrite(APXLOG_MARK_DEBUG "Java worker thread finished %s:%s with status = %d",
1084 lpJava->clWorker.sClazz, lpJava->clWorker.sMethod, rv);
1085 SetEvent(lpJava->hWorkerInit);
1086 }
1087 ExitThread(rv);
1088 /* Never gets here but keep the compiler happy */
1089 return rv;
1090 }
1091
1092 BOOL
apxJavaStart(LPAPXJAVA_THREADARGS pArgs)1093 apxJavaStart(LPAPXJAVA_THREADARGS pArgs)
1094 {
1095 LPAPXJAVAVM lpJava;
1096 lpJava = APXHANDLE_DATA(pArgs->hJava);
1097 if (!lpJava)
1098 return FALSE;
1099 lpJava->dwWorkerStatus = 0;
1100 lpJava->hWorkerInit = CreateEvent(NULL, FALSE, FALSE, NULL);
1101 lpJava->hWorkerSync = CreateEvent(NULL, FALSE, FALSE, NULL);
1102 lpJava->hWorkerThread = CreateThread(NULL,
1103 lpJava->szStackSize,
1104 __apxJavaWorkerThread,
1105 pArgs, CREATE_SUSPENDED,
1106 &lpJava->iWorkerThread);
1107 if (IS_INVALID_HANDLE(lpJava->hWorkerThread)) {
1108 apxLogWrite(APXLOG_MARK_SYSERR);
1109 return FALSE;
1110 }
1111 ResumeThread(lpJava->hWorkerThread);
1112 /* Wait until the worker thread initializes */
1113 WaitForSingleObject(lpJava->hWorkerInit, INFINITE);
1114 if (lpJava->dwWorkerStatus == 0)
1115 return FALSE;
1116 SetEvent(lpJava->hWorkerSync);
1117 if (lstrcmpA(lpJava->clWorker.sClazz, "java/lang/System")) {
1118 /* Give some time to initialize the thread
1119 * Unless we are calling System.exit(0).
1120 * This will be handled by _onexit hook.
1121 */
1122 Sleep(1000);
1123 }
1124 return TRUE;
1125 }
1126
1127 DWORD
apxJavaSetOptions(APXHANDLE hJava,DWORD dwOptions)1128 apxJavaSetOptions(APXHANDLE hJava, DWORD dwOptions)
1129 {
1130 DWORD dwOrgOptions;
1131 LPAPXJAVAVM lpJava;
1132
1133 if (hJava->dwType != APXHANDLE_TYPE_JVM)
1134 return 0;
1135 lpJava = APXHANDLE_DATA(hJava);
1136 dwOrgOptions = lpJava->dwOptions;
1137 lpJava->dwOptions = dwOptions;
1138 return dwOrgOptions;
1139 }
1140
1141 DWORD
apxJavaWait(APXHANDLE hJava,DWORD dwMilliseconds,BOOL bKill)1142 apxJavaWait(APXHANDLE hJava, DWORD dwMilliseconds, BOOL bKill)
1143 {
1144 DWORD rv;
1145 LPAPXJAVAVM lpJava;
1146
1147 if (hJava->dwType != APXHANDLE_TYPE_JVM)
1148 return FALSE;
1149 lpJava = APXHANDLE_DATA(hJava);
1150
1151 if (!lpJava->dwWorkerStatus && lpJava->hWorkerThread)
1152 return WAIT_OBJECT_0;
1153 apxLogWrite(APXLOG_MARK_DEBUG "WaitForSingleObject 0x%p %d milliseconds (INFINITE=%d)...",
1154 lpJava->hWorkerThread, dwMilliseconds, INFINITE);
1155 rv = WaitForSingleObject(lpJava->hWorkerThread, dwMilliseconds);
1156 apxLogWrite(APXLOG_MARK_DEBUG "WaitForSingleObject 0x%p = %d (WAIT_TIMEOUT=%d)",
1157 lpJava->hWorkerThread, rv, WAIT_TIMEOUT);
1158 if (rv == WAIT_TIMEOUT && bKill) {
1159 __apxJavaJniCallback(hJava, WM_CLOSE, 0, 0);
1160 }
1161
1162 return rv;
1163 }
1164
1165 LPVOID
apxJavaCreateClassV(APXHANDLE hJava,LPCSTR szClassName,LPCSTR szSignature,va_list lpArgs)1166 apxJavaCreateClassV(APXHANDLE hJava, LPCSTR szClassName,
1167 LPCSTR szSignature, va_list lpArgs)
1168 {
1169 LPAPXJAVAVM lpJava;
1170 jclass clazz;
1171 jmethodID ccont;
1172 jobject cinst;
1173
1174 if (hJava->dwType != APXHANDLE_TYPE_JVM)
1175 return NULL;
1176 lpJava = APXHANDLE_DATA(hJava);
1177 if (!__apxJvmAttach(lpJava))
1178 return NULL;
1179
1180 clazz = JNICALL_1(FindClass, szClassName);
1181 if (clazz == NULL || (JVM_EXCEPTION_CHECK(lpJava))) {
1182 JVM_EXCEPTION_CLEAR(lpJava);
1183 apxLogWrite(APXLOG_MARK_ERROR "Could not FindClass %s", szClassName);
1184 return NULL;
1185 }
1186
1187 ccont = JNICALL_3(GetMethodID, clazz, "<init>", szSignature);
1188 if (ccont == NULL || (JVM_EXCEPTION_CHECK(lpJava))) {
1189 JVM_EXCEPTION_CLEAR(lpJava);
1190 apxLogWrite(APXLOG_MARK_ERROR "Could not find Constructor %s for %s",
1191 szSignature, szClassName);
1192 return NULL;
1193 }
1194
1195 cinst = JNICALL_3(NewObjectV, clazz, ccont, lpArgs);
1196 if (cinst == NULL || (JVM_EXCEPTION_CHECK(lpJava))) {
1197 JVM_EXCEPTION_CLEAR(lpJava);
1198 apxLogWrite(APXLOG_MARK_ERROR "Could not create instance of %s",
1199 szClassName);
1200 return NULL;
1201 }
1202
1203 return cinst;
1204 }
1205
1206 LPVOID
apxJavaCreateClass(APXHANDLE hJava,LPCSTR szClassName,LPCSTR szSignature,...)1207 apxJavaCreateClass(APXHANDLE hJava, LPCSTR szClassName,
1208 LPCSTR szSignature, ...)
1209 {
1210 LPVOID rv;
1211 va_list args;
1212
1213 va_start(args, szSignature);
1214 rv = apxJavaCreateClassV(hJava, szClassName, szSignature, args);
1215 va_end(args);
1216
1217 return rv;
1218 }
1219
1220 LPVOID
apxJavaCreateStringA(APXHANDLE hJava,LPCSTR szString)1221 apxJavaCreateStringA(APXHANDLE hJava, LPCSTR szString)
1222 {
1223 LPAPXJAVAVM lpJava;
1224 jstring str;
1225
1226 if (hJava->dwType != APXHANDLE_TYPE_JVM)
1227 return NULL;
1228 lpJava = APXHANDLE_DATA(hJava);
1229
1230 str = JNICALL_1(NewStringUTF, szString);
1231 if (str == NULL || (JVM_EXCEPTION_CHECK(lpJava))) {
1232 JVM_EXCEPTION_CLEAR(lpJava);
1233 apxLogWrite(APXLOG_MARK_ERROR "Could not create string for %s",
1234 szString);
1235 return NULL;
1236 }
1237
1238 return str;
1239 }
1240
1241 LPVOID
apxJavaCreateStringW(APXHANDLE hJava,LPCWSTR szString)1242 apxJavaCreateStringW(APXHANDLE hJava, LPCWSTR szString)
1243 {
1244 LPAPXJAVAVM lpJava;
1245 jstring str;
1246
1247 if (hJava->dwType != APXHANDLE_TYPE_JVM)
1248 return NULL;
1249 lpJava = APXHANDLE_DATA(hJava);
1250
1251 str = JNICALL_2(NewString, szString, lstrlenW(szString));
1252 if (str == NULL || (JVM_EXCEPTION_CHECK(lpJava))) {
1253 JVM_EXCEPTION_CLEAR(lpJava);
1254 apxLogWrite(APXLOG_MARK_ERROR "Could not create string for %S",
1255 szString);
1256 return NULL;
1257 }
1258
1259 return str;
1260 }
1261
1262 jvalue
apxJavaCallStaticMethodV(APXHANDLE hJava,jclass lpClass,LPCSTR szMethodName,LPCSTR szSignature,va_list lpArgs)1263 apxJavaCallStaticMethodV(APXHANDLE hJava, jclass lpClass, LPCSTR szMethodName,
1264 LPCSTR szSignature, va_list lpArgs)
1265 {
1266 LPAPXJAVAVM lpJava;
1267 jmethodID method;
1268 jvalue rv;
1269 LPCSTR s = szSignature;
1270 rv.l = 0;
1271 if (hJava->dwType != APXHANDLE_TYPE_JVM)
1272 return rv;
1273 lpJava = APXHANDLE_DATA(hJava);
1274
1275 while (*s && *s != ')')
1276 ++s;
1277 if (*s != ')') {
1278 return rv;
1279 }
1280 else
1281 ++s;
1282 method = JNICALL_3(GetStaticMethodID, lpClass, szMethodName, szSignature);
1283 if (method == NULL || (JVM_EXCEPTION_CHECK(lpJava))) {
1284 JVM_EXCEPTION_CLEAR(lpJava);
1285 apxLogWrite(APXLOG_MARK_ERROR "Could not find method %s with signature %s",
1286 szMethodName, szSignature);
1287 return rv;
1288 }
1289 switch (*s) {
1290 case 'V':
1291 JNICALL_3(CallStaticVoidMethodV, lpClass, method, lpArgs);
1292 break;
1293 case 'L':
1294 case '[':
1295 rv.l = JNICALL_3(CallStaticObjectMethodV, lpClass, method, lpArgs);
1296 break;
1297 case 'Z':
1298 rv.z = JNICALL_3(CallStaticBooleanMethodV, lpClass, method, lpArgs);
1299 break;
1300 case 'B':
1301 rv.b = JNICALL_3(CallStaticByteMethodV, lpClass, method, lpArgs);
1302 break;
1303 case 'C':
1304 rv.c = JNICALL_3(CallStaticCharMethodV, lpClass, method, lpArgs);
1305 break;
1306 case 'S':
1307 rv.i = JNICALL_3(CallStaticShortMethodV, lpClass, method, lpArgs);
1308 break;
1309 case 'I':
1310 rv.i = JNICALL_3(CallStaticIntMethodV, lpClass, method, lpArgs);
1311 break;
1312 case 'J':
1313 rv.j = JNICALL_3(CallStaticLongMethodV, lpClass, method, lpArgs);
1314 break;
1315 case 'F':
1316 rv.f = JNICALL_3(CallStaticFloatMethodV, lpClass, method, lpArgs);
1317 break;
1318 case 'D':
1319 rv.d = JNICALL_3(CallStaticDoubleMethodV, lpClass, method, lpArgs);
1320 break;
1321 default:
1322 apxLogWrite(APXLOG_MARK_ERROR "Invalid signature %s for method %s",
1323 szSignature, szMethodName);
1324 return rv;
1325 break;
1326 }
1327
1328 return rv;
1329 }
1330
1331 jvalue
apxJavaCallStaticMethod(APXHANDLE hJava,jclass lpClass,LPCSTR szMethodName,LPCSTR szSignature,...)1332 apxJavaCallStaticMethod(APXHANDLE hJava, jclass lpClass, LPCSTR szMethodName,
1333 LPCSTR szSignature, ...)
1334 {
1335 jvalue rv;
1336 va_list args;
1337
1338 va_start(args, szSignature);
1339 rv = apxJavaCallStaticMethodV(hJava, lpClass, szMethodName, szSignature, args);
1340 va_end(args);
1341
1342 return rv;
1343 }
1344
1345 /* Call the Java:
1346 * System.setOut(new PrintStream(new FileOutputStream(filename)));
1347 */
1348 BOOL
apxJavaSetOut(APXHANDLE hJava,BOOL setErrorOrOut,LPCWSTR szFilename)1349 apxJavaSetOut(APXHANDLE hJava, BOOL setErrorOrOut, LPCWSTR szFilename)
1350 {
1351 LPAPXJAVAVM lpJava;
1352 jobject fs;
1353 jobject ps;
1354 jstring fn;
1355 jclass sys;
1356
1357 if (hJava->dwType != APXHANDLE_TYPE_JVM || !szFilename)
1358 return FALSE;
1359 lpJava = APXHANDLE_DATA(hJava);
1360 if (!__apxJvmAttach(lpJava))
1361 return FALSE;
1362
1363 if ((fn = apxJavaCreateStringW(hJava, szFilename)) == NULL)
1364 return FALSE;
1365 if ((fs = apxJavaCreateClass(hJava, "java/io/FileOutputStream",
1366 "(Ljava/lang/String;Z)V", fn, JNI_TRUE)) == NULL)
1367 return FALSE;
1368 if ((ps = apxJavaCreateClass(hJava, "java/io/PrintStream",
1369 "(Ljava/io/OutputStream;)V", fs)) == NULL)
1370 return FALSE;
1371 sys = JNICALL_1(FindClass, "java/lang/System");
1372 if (sys == NULL || (JVM_EXCEPTION_CHECK(lpJava))) {
1373 JVM_EXCEPTION_CLEAR(lpJava);
1374 apxLogWrite(APXLOG_MARK_ERROR "Could not FindClass java/lang/System");
1375 return FALSE;
1376 }
1377
1378 if (setErrorOrOut)
1379 apxJavaCallStaticMethod(hJava, sys, "setErr", "(Ljava/io/PrintStream;)V", ps);
1380 else
1381 apxJavaCallStaticMethod(hJava, sys, "setOut", "(Ljava/io/PrintStream;)V", ps);
1382
1383 if (JVM_EXCEPTION_CHECK(lpJava)) {
1384 JVM_EXCEPTION_CLEAR(lpJava);
1385 apxLogWrite(APXLOG_MARK_ERROR "Error calling set method for java/lang/System");
1386 return FALSE;
1387 }
1388 else
1389 return TRUE;
1390
1391 }
1392
apxGetVmExitCode(void)1393 DWORD apxGetVmExitCode(void) {
1394 return vmExitCode;
1395 }
1396
apxSetVmExitCode(DWORD exitCode)1397 void apxSetVmExitCode(DWORD exitCode) {
1398 vmExitCode = exitCode;
1399 return;
1400 }
1401
1402 void
apxJavaDumpAllStacks(APXHANDLE hJava)1403 apxJavaDumpAllStacks(APXHANDLE hJava)
1404 {
1405 BOOL bAttached;
1406 LPAPXJAVAVM lpJava;
1407 JNIEnv *lpEnv = NULL;
1408
1409 if (DYNLOAD_FPTR(JVM_DumpAllStacks) == NULL ||
1410 hJava == NULL ||
1411 hJava->dwType != APXHANDLE_TYPE_JVM)
1412 return;
1413 lpJava = APXHANDLE_DATA(hJava);
1414 if (__apxJvmAttachEnv(lpJava, &lpEnv, &bAttached)) {
1415 DYNLOAD_FPTR(JVM_DumpAllStacks)(lpEnv, NULL);
1416 if (bAttached)
1417 (*(lpJava->lpJvm))->DetachCurrentThread(lpJava->lpJvm);
1418 }
1419 }
1420