Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #ifdef WNT
22 : # include <stdio.h>
23 : # include <sys/stat.h>
24 : # include <windows.h>
25 : #endif
26 :
27 : #ifdef ANDROID
28 : # include <dlfcn.h>
29 : #endif
30 :
31 : #if OSL_DEBUG_LEVEL > 0
32 : #include <stdio.h>
33 : #endif
34 : #include <string.h>
35 :
36 : #include "boost/scoped_array.hpp"
37 : #include "osl/diagnose.h"
38 : #include "rtl/ustring.hxx"
39 : #include "rtl/ustrbuf.hxx"
40 : #include "osl/module.hxx"
41 : #include "osl/mutex.hxx"
42 : #include "osl/thread.hxx"
43 : #include "osl/file.hxx"
44 : #include "rtl/instance.hxx"
45 : #include "osl/getglobalmutex.hxx"
46 : #include <setjmp.h>
47 : #include <signal.h>
48 : #include <stack>
49 :
50 : #include "jni.h"
51 : #include "rtl/byteseq.hxx"
52 : #include "jvmfwk/vendorplugin.h"
53 : #include "util.hxx"
54 : #include "sunversion.hxx"
55 : #include "vendorlist.hxx"
56 : #include "diagnostics.h"
57 :
58 : #ifdef ANDROID
59 : #include <osl/detail/android-bootstrap.h>
60 : #else
61 : #if defined HAVE_VALGRIND_HEADERS
62 : #include <valgrind/valgrind.h>
63 : #else
64 : #define RUNNING_ON_VALGRIND 0
65 : #endif
66 : #endif
67 :
68 : using namespace osl;
69 : using namespace std;
70 : using namespace jfw_plugin;
71 :
72 :
73 : namespace {
74 :
75 : struct PluginMutex: public ::rtl::Static<osl::Mutex, PluginMutex> {};
76 :
77 : #if defined UNX
78 0 : OString getPluginJarPath(
79 : const OUString & sVendor,
80 : const OUString& sLocation,
81 : const OUString& sVersion)
82 : {
83 0 : OString ret;
84 0 : OUString sName1("javaplugin.jar");
85 0 : OUString sName2("plugin.jar");
86 0 : OUString sPath;
87 0 : if ( sVendor == "Sun Microsystems Inc." )
88 : {
89 0 : SunVersion ver142("1.4.2-ea");
90 0 : SunVersion ver150("1.5.0-ea");
91 0 : SunVersion ver(sVersion);
92 : OSL_ASSERT(ver142 && ver150 && ver);
93 :
94 0 : OUString sName;
95 0 : if (ver < ver142)
96 : {
97 0 : sName = sName1;
98 : }
99 0 : else if (ver < ver150)
100 : {//this will cause ea, beta etc. to have plugin.jar in path.
101 : //but this does not harm. 1.5.0-beta < 1.5.0
102 0 : sName = sName2;
103 : }
104 0 : if (!sName.isEmpty())
105 : {
106 0 : sName = sLocation + "/lib/" + sName;
107 0 : OSL_VERIFY(
108 : osl_getSystemPathFromFileURL(sName.pData, & sPath.pData)
109 : == osl_File_E_None);
110 0 : }
111 : }
112 : else
113 : {
114 0 : char sep[] = {SAL_PATHSEPARATOR, 0};
115 0 : OUString sName(sLocation + "/lib/" + sName1);
116 0 : OUString sPath1;
117 0 : OUString sPath2;
118 0 : if (osl_getSystemPathFromFileURL(sName.pData, & sPath1.pData)
119 : == osl_File_E_None)
120 : {
121 0 : sName = sLocation + "/lib/" + sName2;
122 0 : if (osl_getSystemPathFromFileURL(sName.pData, & sPath2.pData)
123 : == osl_File_E_None)
124 : {
125 0 : sPath = sPath1 + OUString::createFromAscii(sep) + sPath2;
126 : }
127 : }
128 0 : OSL_ASSERT(!sPath.isEmpty());
129 : }
130 0 : ret = OUStringToOString(sPath, osl_getThreadTextEncoding());
131 :
132 0 : return ret;
133 : }
134 : #endif // UNX
135 :
136 :
137 1 : JavaInfo* createJavaInfo(const rtl::Reference<VendorBase> & info)
138 : {
139 1 : JavaInfo* pInfo = (JavaInfo*) rtl_allocateMemory(sizeof(JavaInfo));
140 1 : if (pInfo == NULL)
141 0 : return NULL;
142 1 : OUString sVendor = info->getVendor();
143 1 : pInfo->sVendor = sVendor.pData;
144 1 : rtl_uString_acquire(sVendor.pData);
145 2 : OUString sHome = info->getHome();
146 1 : pInfo->sLocation = sHome.pData;
147 1 : rtl_uString_acquire(pInfo->sLocation);
148 2 : OUString sVersion = info->getVersion();
149 1 : pInfo->sVersion = sVersion.pData;
150 1 : rtl_uString_acquire(pInfo->sVersion);
151 1 : pInfo->nFeatures = info->supportsAccessibility() ? 1 : 0;
152 1 : pInfo->nRequirements = info->needsRestart() ? JFW_REQUIRE_NEEDRESTART : 0;
153 2 : OUStringBuffer buf(1024);
154 1 : buf.append(info->getRuntimeLibrary());
155 1 : if (!info->getLibraryPaths().isEmpty())
156 : {
157 1 : buf.appendAscii("\n");
158 1 : buf.append(info->getLibraryPaths());
159 1 : buf.appendAscii("\n");
160 : }
161 :
162 2 : OUString sVendorData = buf.makeStringAndClear();
163 : rtl::ByteSequence byteSeq( (sal_Int8*) sVendorData.pData->buffer,
164 2 : sVendorData.getLength() * sizeof(sal_Unicode));
165 1 : pInfo->arVendorData = byteSeq.get();
166 1 : rtl_byte_sequence_acquire(pInfo->arVendorData);
167 :
168 2 : return pInfo;
169 : }
170 :
171 0 : OUString getRuntimeLib(const rtl::ByteSequence & data)
172 : {
173 0 : const sal_Unicode* chars = (sal_Unicode*) data.getConstArray();
174 0 : sal_Int32 len = data.getLength();
175 0 : OUString sData(chars, len / 2);
176 : //the runtime lib is on the first line
177 0 : sal_Int32 index = 0;
178 0 : OUString aToken = sData.getToken( 0, '\n', index);
179 :
180 0 : return aToken;
181 : }
182 :
183 : jmp_buf jmp_jvm_abort;
184 : sig_atomic_t g_bInGetJavaVM = 0;
185 :
186 0 : extern "C" void JNICALL abort_handler()
187 : {
188 : // If we are within JNI_CreateJavaVM then we jump back into getJavaVM
189 0 : if( g_bInGetJavaVM != 0 )
190 : {
191 0 : fprintf( stderr, "JavaVM: JNI_CreateJavaVM called _exit, caught by abort_handler in javavm.cxx\n");
192 0 : longjmp( jmp_jvm_abort, 0);
193 : }
194 0 : }
195 :
196 : }
197 :
198 : extern "C"
199 2 : javaPluginError jfw_plugin_getAllJavaInfos(
200 : rtl_uString *sVendor,
201 : rtl_uString *sMinVersion,
202 : rtl_uString *sMaxVersion,
203 : rtl_uString * *arExcludeList,
204 : sal_Int32 nLenList,
205 : JavaInfo*** parJavaInfo,
206 : sal_Int32 *nLenInfoList)
207 : {
208 : OSL_ASSERT(sVendor);
209 : OSL_ASSERT(sMinVersion);
210 : OSL_ASSERT(sMaxVersion);
211 : OSL_ASSERT(parJavaInfo);
212 : OSL_ASSERT(parJavaInfo);
213 : OSL_ASSERT(nLenInfoList);
214 2 : if (!sVendor || !sMinVersion || !sMaxVersion || !parJavaInfo || !nLenInfoList)
215 0 : return JFW_PLUGIN_E_INVALID_ARG;
216 :
217 : //nLenlist contains the number of element in arExcludeList.
218 : //If no exclude list is provided then nLenList must be 0
219 : OSL_ASSERT( ! (arExcludeList == NULL && nLenList > 0));
220 2 : if (arExcludeList == NULL && nLenList > 0)
221 0 : return JFW_PLUGIN_E_INVALID_ARG;
222 :
223 2 : OUString ouVendor(sVendor);
224 4 : OUString ouMinVer(sMinVersion);
225 4 : OUString ouMaxVer(sMaxVersion);
226 :
227 : OSL_ASSERT(!ouVendor.isEmpty());
228 2 : if (ouVendor.isEmpty())
229 0 : return JFW_PLUGIN_E_INVALID_ARG;
230 :
231 2 : JavaInfo** arInfo = NULL;
232 :
233 : //Find all JREs
234 : vector<rtl::Reference<VendorBase> > vecInfos =
235 4 : getAllJREInfos();
236 4 : vector<rtl::Reference<VendorBase> > vecVerifiedInfos;
237 :
238 : typedef vector<rtl::Reference<VendorBase> >::iterator it;
239 4 : for (it i= vecInfos.begin(); i != vecInfos.end(); ++i)
240 : {
241 2 : const rtl::Reference<VendorBase>& cur = *i;
242 :
243 2 : if (!ouVendor.equals(cur->getVendor()))
244 1 : continue;
245 :
246 1 : if (!ouMinVer.isEmpty())
247 : {
248 : try
249 : {
250 1 : if (cur->compareVersions(sMinVersion) == -1)
251 0 : continue;
252 : }
253 0 : catch (MalformedVersionException&)
254 : {
255 : //The minVersion was not recognized as valid for this vendor.
256 : JFW_ENSURE(
257 : false,
258 : "[Java framework]sunjavaplugin does not know version: "
259 : + ouMinVer + " for vendor: " + cur->getVendor()
260 : + " .Check minimum Version." );
261 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
262 : }
263 : }
264 :
265 1 : if (!ouMaxVer.isEmpty())
266 : {
267 : try
268 : {
269 0 : if (cur->compareVersions(sMaxVersion) == 1)
270 0 : continue;
271 : }
272 0 : catch (MalformedVersionException&)
273 : {
274 : //The maxVersion was not recognized as valid for this vendor.
275 : JFW_ENSURE(
276 : false,
277 : "[Java framework]sunjavaplugin does not know version: "
278 : + ouMaxVer + " for vendor: " + cur->getVendor()
279 : + " .Check maximum Version." );
280 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
281 : }
282 : }
283 :
284 1 : bool bExclude = false;
285 1 : for (int j = 0; j < nLenList; j++)
286 : {
287 0 : OUString sExVer(arExcludeList[j]);
288 : try
289 : {
290 0 : if (cur->compareVersions(sExVer) == 0)
291 : {
292 0 : bExclude = true;
293 0 : break;
294 : }
295 : }
296 0 : catch (MalformedVersionException&)
297 : {
298 : //The excluded version was not recognized as valid for this vendor.
299 : JFW_ENSURE(
300 : false,
301 : "[Java framework]sunjavaplugin does not know version: "
302 : + sExVer + " for vendor: " + cur->getVendor()
303 : + " .Check excluded versions." );
304 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
305 : }
306 0 : }
307 1 : if (bExclude == true)
308 0 : continue;
309 :
310 1 : vecVerifiedInfos.push_back(*i);
311 : }
312 : //Now vecVerifiedInfos contains all those JREs which meet the version requirements
313 : //Transfer them into the array that is passed out.
314 2 : arInfo = (JavaInfo**) rtl_allocateMemory(vecVerifiedInfos.size() * sizeof (JavaInfo*));
315 2 : int j = 0;
316 : typedef vector<rtl::Reference<VendorBase> >::const_iterator cit;
317 3 : for (cit ii = vecVerifiedInfos.begin(); ii != vecVerifiedInfos.end(); ++ii, ++j)
318 : {
319 1 : arInfo[j] = createJavaInfo(*ii);
320 : }
321 2 : *nLenInfoList = vecVerifiedInfos.size();
322 :
323 :
324 2 : *parJavaInfo = arInfo;
325 4 : return JFW_PLUGIN_E_NONE;
326 : }
327 :
328 : extern "C"
329 0 : javaPluginError jfw_plugin_getJavaInfoByPath(
330 : rtl_uString *path,
331 : rtl_uString *sVendor,
332 : rtl_uString *sMinVersion,
333 : rtl_uString *sMaxVersion,
334 : rtl_uString * *arExcludeList,
335 : sal_Int32 nLenList,
336 : JavaInfo ** ppInfo)
337 : {
338 0 : javaPluginError errorcode = JFW_PLUGIN_E_NONE;
339 :
340 : OSL_ASSERT(path);
341 : OSL_ASSERT(sVendor);
342 : OSL_ASSERT(sMinVersion);
343 : OSL_ASSERT(sMaxVersion);
344 0 : if (!path || !sVendor || !sMinVersion || !sMaxVersion || !ppInfo)
345 0 : return JFW_PLUGIN_E_INVALID_ARG;
346 0 : OUString ouPath(path);
347 : OSL_ASSERT(!ouPath.isEmpty());
348 0 : if (ouPath.isEmpty())
349 0 : return JFW_PLUGIN_E_INVALID_ARG;
350 :
351 : //nLenlist contains the number of element in arExcludeList.
352 : //If no exclude list is provided then nLenList must be 0
353 : OSL_ASSERT( ! (arExcludeList == NULL && nLenList > 0));
354 0 : if (arExcludeList == NULL && nLenList > 0)
355 0 : return JFW_PLUGIN_E_INVALID_ARG;
356 :
357 0 : OUString ouVendor(sVendor);
358 0 : OUString ouMinVer(sMinVersion);
359 0 : OUString ouMaxVer(sMaxVersion);
360 :
361 : OSL_ASSERT(!ouVendor.isEmpty());
362 0 : if (ouVendor.isEmpty())
363 0 : return JFW_PLUGIN_E_INVALID_ARG;
364 :
365 0 : rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath(ouPath);
366 0 : if (!aVendorInfo.is())
367 0 : return JFW_PLUGIN_E_NO_JRE;
368 :
369 : //Check if the detected JRE matches the version requirements
370 0 : if (!ouVendor.equals(aVendorInfo->getVendor()))
371 0 : return JFW_PLUGIN_E_NO_JRE;
372 :
373 0 : if (!ouMinVer.isEmpty())
374 : {
375 0 : int nRes = 0;
376 : try
377 : {
378 0 : nRes = aVendorInfo->compareVersions(ouMinVer);
379 : }
380 0 : catch (MalformedVersionException&)
381 : {
382 : //The minVersion was not recognized as valid for this vendor.
383 : JFW_ENSURE(
384 : false,
385 : "[Java framework]sunjavaplugin does not know version: "
386 : + ouMinVer + " for vendor: " + aVendorInfo->getVendor()
387 : + " .Check minimum Version." );
388 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
389 : }
390 0 : if (nRes < 0)
391 0 : return JFW_PLUGIN_E_FAILED_VERSION;
392 : }
393 :
394 0 : if (!ouMaxVer.isEmpty())
395 : {
396 0 : int nRes = 0;
397 : try
398 : {
399 0 : nRes = aVendorInfo->compareVersions(ouMaxVer);
400 : }
401 0 : catch (MalformedVersionException&)
402 : {
403 : //The maxVersion was not recognized as valid for this vendor.
404 : JFW_ENSURE(
405 : false,
406 : "[Java framework]sunjavaplugin does not know version: "
407 : + ouMaxVer + " for vendor: " + aVendorInfo->getVendor()
408 : + " .Check maximum Version." );
409 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
410 : }
411 0 : if (nRes > 0)
412 0 : return JFW_PLUGIN_E_FAILED_VERSION;
413 : }
414 :
415 0 : for (int i = 0; i < nLenList; i++)
416 : {
417 0 : OUString sExVer(arExcludeList[i]);
418 0 : int nRes = 0;
419 : try
420 : {
421 0 : nRes = aVendorInfo->compareVersions(sExVer);
422 : }
423 0 : catch (MalformedVersionException&)
424 : {
425 : //The excluded version was not recognized as valid for this vendor.
426 : JFW_ENSURE(
427 : false,
428 : "[Java framework]sunjavaplugin does not know version: "
429 : + sExVer + " for vendor: " + aVendorInfo->getVendor()
430 : + " .Check excluded versions." );
431 0 : return JFW_PLUGIN_E_WRONG_VERSION_FORMAT;
432 : }
433 0 : if (nRes == 0)
434 0 : return JFW_PLUGIN_E_FAILED_VERSION;
435 0 : }
436 0 : *ppInfo = createJavaInfo(aVendorInfo);
437 :
438 0 : return errorcode;
439 : }
440 :
441 : #if defined(WNT)
442 :
443 : // Load msvcr71.dll using an explicit full path from where it is
444 : // present as bundled with the JRE. In case it is not found where we
445 : // think it should be, do nothing, and just let the implicit loading
446 : // that happens when loading the JVM take care of it.
447 :
448 : static void load_msvcr71(LPCWSTR jvm_dll)
449 : {
450 : wchar_t msvcr71_dll[MAX_PATH];
451 : wchar_t *slash;
452 :
453 : if (wcslen(jvm_dll) > MAX_PATH - 15)
454 : return;
455 :
456 : wcscpy(msvcr71_dll, jvm_dll);
457 :
458 : // First check if msvcr71.dll is in the same folder as jvm.dll. It
459 : // normally isn't, at least up to 1.6.0_22, but who knows if it
460 : // might be in the future.
461 : slash = wcsrchr(msvcr71_dll, L'\\');
462 :
463 : if (!slash)
464 : {
465 : // Huh, weird path to jvm.dll. Oh well.
466 : return;
467 : }
468 :
469 : wcscpy(slash+1, L"msvcr71.dll");
470 : if (LoadLibraryW(msvcr71_dll))
471 : return;
472 :
473 : // Then check if msvcr71.dll is in the parent folder of where
474 : // jvm.dll is. That is currently (1.6.0_22) as far as I know the
475 : // normal case.
476 : *slash = 0;
477 : slash = wcsrchr(msvcr71_dll, L'\\');
478 :
479 : if (!slash)
480 : return;
481 :
482 : wcscpy(slash+1, L"msvcr71.dll");
483 : LoadLibraryW(msvcr71_dll);
484 : }
485 :
486 : // Check if the jvm DLL imports msvcr71.dll, and in that case try
487 : // loading it explicitly. In case something goes wrong, do nothing,
488 : // and just let the implicit loading try to take care of it.
489 : static void do_msvcr71_magic(rtl_uString *jvm_dll)
490 : {
491 : rtl_uString* Module(0);
492 : struct stat st;
493 :
494 : oslFileError nError = osl_getSystemPathFromFileURL(jvm_dll, &Module);
495 :
496 : if ( osl_File_E_None != nError )
497 : rtl_uString_assign(&Module, jvm_dll);
498 :
499 : FILE *f = _wfopen(reinterpret_cast<LPCWSTR>(Module->buffer), L"rb");
500 :
501 : if (fstat(fileno(f), &st) == -1)
502 : {
503 : fclose(f);
504 : return;
505 : }
506 :
507 : PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER) malloc(st.st_size);
508 :
509 : if (fread(dos_hdr, st.st_size, 1, f) != 1 ||
510 : memcmp(dos_hdr, "MZ", 2) != 0 ||
511 : dos_hdr->e_lfanew < 0 ||
512 : dos_hdr->e_lfanew > (LONG) (st.st_size - sizeof(IMAGE_NT_HEADERS)))
513 : {
514 : free(dos_hdr);
515 : fclose(f);
516 : return;
517 : }
518 :
519 : fclose(f);
520 :
521 : IMAGE_NT_HEADERS *nt_hdr = (IMAGE_NT_HEADERS *) ((char *)dos_hdr + dos_hdr->e_lfanew);
522 :
523 : IMAGE_IMPORT_DESCRIPTOR *imports =
524 : (IMAGE_IMPORT_DESCRIPTOR *) ((char *) dos_hdr + nt_hdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
525 :
526 : while (imports <= (IMAGE_IMPORT_DESCRIPTOR *) ((char *) dos_hdr + st.st_size - sizeof (IMAGE_IMPORT_DESCRIPTOR)) &&
527 : imports->Name != 0 &&
528 : imports->Name < (DWORD) st.st_size)
529 : {
530 : // Intentional use of sizeof("msvcr71.dll") here to include the terminating zero byte
531 : if (strnicmp((char *) dos_hdr + imports->Name, "msvcr71.dll", sizeof("msvcr71.dll")) == 0)
532 : {
533 : load_msvcr71(reinterpret_cast<LPCWSTR>(Module->buffer));
534 : break;
535 : }
536 : imports++;
537 : }
538 :
539 : free(dos_hdr);
540 : }
541 :
542 : #endif
543 :
544 : /** starts a Java Virtual Machine.
545 : <p>
546 : The function shall ensure, that the VM does not abort the process
547 : during instantiation.
548 : </p>
549 : */
550 : extern "C"
551 0 : javaPluginError jfw_plugin_startJavaVirtualMachine(
552 : const JavaInfo *pInfo,
553 : const JavaVMOption* arOptions,
554 : sal_Int32 cOptions,
555 : JavaVM ** ppVm,
556 : JNIEnv ** ppEnv)
557 : {
558 : // unless guard is volatile the following warning occurs on gcc:
559 : // warning: variable 't' might be clobbered by `longjmp' or `vfork'
560 0 : volatile osl::MutexGuard guard(PluginMutex::get());
561 : // unless errorcode is volatile the following warning occurs on gcc:
562 : // warning: variable 'errorcode' might be clobbered by `longjmp' or `vfork'
563 0 : volatile javaPluginError errorcode = JFW_PLUGIN_E_NONE;
564 0 : if ( pInfo == NULL || ppVm == NULL || ppEnv == NULL)
565 0 : return JFW_PLUGIN_E_INVALID_ARG;
566 : //Check if the Vendor (pInfo->sVendor) is supported by this plugin
567 0 : if ( ! isVendorSupported(pInfo->sVendor))
568 0 : return JFW_PLUGIN_E_WRONG_VENDOR;
569 0 : OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
570 : JFW_TRACE2("[Java framework] Using Java runtime library: "
571 : + sRuntimeLib + ".\n");
572 :
573 : #ifndef ANDROID
574 : // On linux we load jvm with RTLD_GLOBAL. This is necessary for debugging, because
575 : // libjdwp.so need a symbol (fork1) from libjvm which it only gets if the jvm is loaded
576 : // witd RTLD_GLOBAL. On Solaris libjdwp.so is correctly linked with libjvm.so
577 0 : oslModule moduleRt = 0;
578 : #if defined(LINUX)
579 0 : if ((moduleRt = osl_loadModule(sRuntimeLib.pData,
580 0 : SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_NOW)) == 0 )
581 : #else
582 : #if defined(WNT)
583 : do_msvcr71_magic(sRuntimeLib.pData);
584 : #endif
585 : if ((moduleRt = osl_loadModule(sRuntimeLib.pData, SAL_LOADMODULE_DEFAULT)) == 0)
586 : #endif
587 : {
588 : JFW_ENSURE(false,
589 : "[Java framework]sunjavaplugin" SAL_DLLEXTENSION
590 : " could not load Java runtime library: \n"
591 : + sRuntimeLib + "\n");
592 : JFW_TRACE0("[Java framework]sunjavaplugin" SAL_DLLEXTENSION
593 : " could not load Java runtime library: \n"
594 : + sRuntimeLib + "\n");
595 0 : return JFW_PLUGIN_E_VM_CREATION_FAILED;
596 : }
597 :
598 : #if defined UNX && !defined MACOSX
599 : //Setting the JAVA_HOME is needed for awt
600 0 : OUString javaHome("JAVA_HOME=");
601 0 : OUString sPathLocation;
602 0 : osl_getSystemPathFromFileURL(pInfo->sLocation, & sPathLocation.pData);
603 0 : javaHome += sPathLocation;
604 : OString osJavaHome = OUStringToOString(
605 0 : javaHome, osl_getThreadTextEncoding());
606 0 : putenv(strdup(osJavaHome.getStr()));
607 : #endif
608 :
609 : typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);
610 0 : OUString sSymbolCreateJava("JNI_CreateJavaVM");
611 :
612 : JNI_CreateVM_Type * pCreateJavaVM = (JNI_CreateVM_Type *) osl_getFunctionSymbol(
613 0 : moduleRt, sSymbolCreateJava.pData);
614 0 : if (!pCreateJavaVM)
615 : {
616 : OSL_ASSERT(false);
617 : OString sLib = OUStringToOString(
618 0 : sRuntimeLib, osl_getThreadTextEncoding());
619 : OString sSymbol = OUStringToOString(
620 0 : sSymbolCreateJava, osl_getThreadTextEncoding());
621 : fprintf(stderr,"[Java framework]sunjavaplugin" SAL_DLLEXTENSION
622 : "Java runtime library: %s does not export symbol %s !\n",
623 0 : sLib.getStr(), sSymbol.getStr());
624 0 : osl_unloadModule(moduleRt);
625 0 : return JFW_PLUGIN_E_VM_CREATION_FAILED;
626 : }
627 :
628 : // Valgrind typically emits many false errors when executing JIT'ed JVM
629 : // code, so force the JVM into interpreted mode:
630 0 : bool forceInterpreted = RUNNING_ON_VALGRIND > 0;
631 :
632 : // Some testing with Java 1.4 showed that JavaVMOption.optionString has to
633 : // be encoded with the system encoding (i.e., osl_getThreadTextEncoding):
634 : JavaVMInitArgs vm_args;
635 :
636 0 : sal_Int32 nOptions = 1 + cOptions + (forceInterpreted ? 1 : 0);
637 : //TODO: check for overflow
638 0 : boost::scoped_array<JavaVMOption> sarOptions(new JavaVMOption[nOptions]);
639 0 : JavaVMOption * options = sarOptions.get();
640 :
641 : // We set an abort handler which is called when the VM calls _exit during
642 : // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
643 : // all some directories of the Java installation. This is necessary for
644 : // all versions below 1.5.1
645 0 : int n = 0;
646 0 : options[n].optionString= (char *) "abort";
647 0 : options[n].extraInfo= (void* )(sal_IntPtr)abort_handler;
648 0 : ++n;
649 0 : OString sClassPathOption;
650 0 : for (int i = 0; i < cOptions; i++)
651 : {
652 : #ifdef UNX
653 : // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
654 : // in the class path in order to have applet support.
655 0 : OString sClassPath = arOptions[i].optionString;
656 0 : if (sClassPath.startsWith("-Djava.class.path="))
657 : {
658 0 : OString sAddPath = getPluginJarPath(pInfo->sVendor, pInfo->sLocation,pInfo->sVersion);
659 0 : if (!sAddPath.isEmpty())
660 0 : sClassPathOption = sClassPath + OString(SAL_PATHSEPARATOR)
661 0 : + sAddPath;
662 : else
663 0 : sClassPathOption = sClassPath;
664 0 : options[n].optionString = (char *) sClassPathOption.getStr();
665 0 : options[n].extraInfo = arOptions[i].extraInfo;
666 : }
667 : else
668 : {
669 : #endif
670 0 : options[n].optionString = arOptions[i].optionString;
671 0 : options[n].extraInfo = arOptions[i].extraInfo;
672 : #ifdef UNX
673 : }
674 : #endif
675 : #if OSL_DEBUG_LEVEL >= 2
676 : JFW_TRACE2("VM option: " << options[n].optionString << "\n");
677 : #endif
678 0 : ++n;
679 0 : }
680 0 : if (forceInterpreted) {
681 0 : options[n].optionString = const_cast<char *>("-Xint");
682 0 : options[n].extraInfo = 0;
683 0 : ++n;
684 : }
685 :
686 : #ifdef MACOSX
687 : vm_args.version= JNI_VERSION_1_4; // issue 88987
688 : #else
689 0 : vm_args.version= JNI_VERSION_1_2;
690 : #endif
691 0 : vm_args.options= options;
692 0 : vm_args.nOptions= nOptions;
693 0 : vm_args.ignoreUnrecognized= JNI_TRUE;
694 :
695 : /* We set a global flag which is used by the abort handler in order to
696 : determine whether it is should use longjmp to get back into this function.
697 : That is, the abort handler determines if it is on the same stack as this function
698 : and then jumps back into this function.
699 : */
700 0 : g_bInGetJavaVM = 1;
701 : jint err;
702 0 : JavaVM * pJavaVM = 0;
703 0 : memset( jmp_jvm_abort, 0, sizeof(jmp_jvm_abort));
704 0 : int jmpval= setjmp( jmp_jvm_abort );
705 : /* If jmpval is not "0" then this point was reached by a longjmp in the
706 : abort_handler, which was called indirectly by JNI_CreateVM.
707 : */
708 0 : if( jmpval == 0)
709 : {
710 : //returns negative number on failure
711 0 : err= pCreateJavaVM(&pJavaVM, ppEnv, &vm_args);
712 0 : g_bInGetJavaVM = 0;
713 : }
714 : else
715 : // set err to a positive number, so as or recognize that an abort (longjmp)
716 : //occurred
717 0 : err= 1;
718 :
719 0 : if(err != 0)
720 : {
721 0 : if( err < 0)
722 : {
723 : fprintf(stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
724 0 : "Can not create Java Virtual Machine\n");
725 0 : errorcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
726 : }
727 0 : else if( err > 0)
728 : {
729 : fprintf(stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
730 0 : "Can not create JavaVirtualMachine, abort handler was called.\n");
731 0 : errorcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
732 : }
733 : }
734 : else
735 : {
736 0 : *ppVm = pJavaVM;
737 : JFW_TRACE2("[Java framework] sunjavaplugin" SAL_DLLEXTENSION " has created a VM.\n");
738 : }
739 : #else
740 : (void) arOptions;
741 : (void) cOptions;
742 : // On Android we always have a Java VM as we only expect this code
743 : // to be run in an Android app anyway.
744 : *ppVm = lo_get_javavm();
745 : fprintf(stderr, "lo_get_javavm returns %p", *ppVm);
746 : #endif
747 :
748 0 : return errorcode;
749 : }
750 :
751 : extern "C"
752 42504 : javaPluginError jfw_plugin_existJRE(const JavaInfo *pInfo, sal_Bool *exist)
753 : {
754 42504 : javaPluginError ret = JFW_PLUGIN_E_NONE;
755 42504 : if (!pInfo || !exist)
756 0 : return JFW_PLUGIN_E_INVALID_ARG;
757 42504 : OUString sLocation(pInfo->sLocation);
758 :
759 42504 : if (sLocation.isEmpty())
760 0 : return JFW_PLUGIN_E_INVALID_ARG;
761 85008 : ::osl::DirectoryItem item;
762 42504 : ::osl::File::RC rc_item = ::osl::DirectoryItem::get(sLocation, item);
763 42504 : if (::osl::File::E_None == rc_item)
764 : {
765 42504 : *exist = sal_True;
766 : }
767 0 : else if (::osl::File::E_NOENT == rc_item)
768 : {
769 0 : *exist = sal_False;
770 : }
771 : else
772 : {
773 0 : ret = JFW_PLUGIN_E_ERROR;
774 : }
775 : #ifdef MACOSX
776 : //We can have the situation that the JavaVM runtime library is not
777 : //contained within JAVA_HOME. Then the check for JAVA_HOME would return
778 : //true although the runtime library may not be loadable.
779 : if (ret == JFW_PLUGIN_E_NONE && *exist == sal_True)
780 : {
781 : OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
782 : JFW_TRACE2("[Java framework] Checking existence of Java runtime library.\n");
783 :
784 : ::osl::DirectoryItem itemRt;
785 : ::osl::File::RC rc_itemRt = ::osl::DirectoryItem::get(sRuntimeLib, itemRt);
786 : if (::osl::File::E_None == rc_itemRt)
787 : {
788 : *exist = sal_True;
789 : JFW_TRACE2("[Java framework] Java runtime library exist: "
790 : + sRuntimeLib + "\n");
791 :
792 : }
793 : else if (::osl::File::E_NOENT == rc_itemRt)
794 : {
795 : *exist = sal_False;
796 : JFW_TRACE2("[Java framework] Java runtime library does not exist: "
797 : + sRuntimeLib + "\n");
798 : }
799 : else
800 : {
801 : ret = JFW_PLUGIN_E_ERROR;
802 : JFW_TRACE2("[Java framework] Error while looking for Java runtime library: "
803 : + sRuntimeLib + " \n");
804 : }
805 : }
806 : #endif
807 85008 : return ret;
808 : }
809 :
810 :
811 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|