1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
23 # include <sys/stat.h>
31 #if OSL_DEBUG_LEVEL > 0
36 #include "boost/scoped_array.hpp"
37 #include "config_options.h"
38 #include "osl/diagnose.h"
39 #include "rtl/ustring.hxx"
40 #include "rtl/ustrbuf.hxx"
41 #include "osl/module.hxx"
42 #include "osl/mutex.hxx"
43 #include "osl/process.h"
44 #include "osl/thread.hxx"
45 #include "osl/file.hxx"
46 #include "rtl/instance.hxx"
47 #include "osl/getglobalmutex.hxx"
53 #include "rtl/byteseq.hxx"
54 #include "vendorplugin.hxx"
56 #include "sunversion.hxx"
57 #include "vendorlist.hxx"
58 #include "diagnostics.h"
61 #include <osl/detail/android-bootstrap.h>
63 #if !ENABLE_RUNTIME_OPTIMIZATIONS
64 #define FORCE_INTERPRETED 1
65 #elif defined HAVE_VALGRIND_HEADERS
66 #include <valgrind/valgrind.h>
67 #define FORCE_INTERPRETED RUNNING_ON_VALGRIND
69 #define FORCE_INTERPRETED 0
73 #if defined LINUX && (defined X86 || defined X86_64)
74 #include <sys/resource.h>
79 using namespace jfw_plugin
;
84 struct PluginMutex
: public ::rtl::Static
<osl::Mutex
, PluginMutex
> {};
86 #if defined(UNX) && !defined(ANDROID)
87 OString
getPluginJarPath(
88 const OUString
& sVendor
,
89 const OUString
& sLocation
,
90 const OUString
& sVersion
)
93 OUString
sName1("javaplugin.jar");
94 OUString
sName2("plugin.jar");
96 if ( sVendor
== "Sun Microsystems Inc." )
98 SunVersion
ver142("1.4.2-ea");
99 SunVersion
ver150("1.5.0-ea");
100 SunVersion
ver(sVersion
);
101 OSL_ASSERT(ver142
&& ver150
&& ver
);
108 else if (ver
< ver150
)
109 {//this will cause ea, beta etc. to have plugin.jar in path.
110 //but this does not harm. 1.5.0-beta < 1.5.0
113 if (!sName
.isEmpty())
115 sName
= sLocation
+ "/lib/" + sName
;
117 osl_getSystemPathFromFileURL(sName
.pData
, & sPath
.pData
)
123 char sep
[] = {SAL_PATHSEPARATOR
, 0};
124 OUString
sName(sLocation
+ "/lib/" + sName1
);
127 if (osl_getSystemPathFromFileURL(sName
.pData
, & sPath1
.pData
)
130 sName
= sLocation
+ "/lib/" + sName2
;
131 if (osl_getSystemPathFromFileURL(sName
.pData
, & sPath2
.pData
)
134 sPath
= sPath1
+ OUString::createFromAscii(sep
) + sPath2
;
137 OSL_ASSERT(!sPath
.isEmpty());
139 ret
= OUStringToOString(sPath
, osl_getThreadTextEncoding());
146 JavaInfo
* createJavaInfo(const rtl::Reference
<VendorBase
> & info
)
148 JavaInfo
* pInfo
= static_cast<JavaInfo
*>(rtl_allocateMemory(sizeof(JavaInfo
)));
151 OUString sVendor
= info
->getVendor();
152 pInfo
->sVendor
= sVendor
.pData
;
153 rtl_uString_acquire(sVendor
.pData
);
154 OUString sHome
= info
->getHome();
155 pInfo
->sLocation
= sHome
.pData
;
156 rtl_uString_acquire(pInfo
->sLocation
);
157 OUString sVersion
= info
->getVersion();
158 pInfo
->sVersion
= sVersion
.pData
;
159 rtl_uString_acquire(pInfo
->sVersion
);
160 pInfo
->nFeatures
= info
->supportsAccessibility() ? 1 : 0;
161 pInfo
->nRequirements
= info
->needsRestart() ? JFW_REQUIRE_NEEDRESTART
: 0;
162 OUStringBuffer
buf(1024);
163 buf
.append(info
->getRuntimeLibrary());
164 if (!info
->getLibraryPath().isEmpty())
166 buf
.appendAscii("\n");
167 buf
.append(info
->getLibraryPath());
168 buf
.appendAscii("\n");
171 OUString sVendorData
= buf
.makeStringAndClear();
172 rtl::ByteSequence
byteSeq( reinterpret_cast<sal_Int8
*>(sVendorData
.pData
->buffer
),
173 sVendorData
.getLength() * sizeof(sal_Unicode
));
174 pInfo
->arVendorData
= byteSeq
.get();
175 rtl_byte_sequence_acquire(pInfo
->arVendorData
);
180 OUString
getRuntimeLib(const rtl::ByteSequence
& data
)
182 const sal_Unicode
* chars
= reinterpret_cast<sal_Unicode
const *>(data
.getConstArray());
183 sal_Int32 len
= data
.getLength();
184 OUString
sData(chars
, len
/ 2);
185 //the runtime lib is on the first line
187 OUString aToken
= sData
.getToken( 0, '\n', index
);
192 jmp_buf jmp_jvm_abort
;
193 sig_atomic_t g_bInGetJavaVM
= 0;
195 extern "C" void JNICALL
abort_handler()
197 // If we are within JNI_CreateJavaVM then we jump back into getJavaVM
198 if( g_bInGetJavaVM
!= 0 )
200 fprintf( stderr
, "JavaVM: JNI_CreateJavaVM called _exit, caught by abort_handler in javavm.cxx\n");
201 longjmp( jmp_jvm_abort
, 0);
205 /** helper function to check Java version requirements
207 This function checks if the Java version of the given VendorBase
208 meets the given Java version requirements.
211 [in] the object to be inspected whether it meets the version requirements
213 [in] represents the minimum version of a JRE. The string can be empty.
215 [in] represents the maximum version of a JRE. The string can be empty.
217 [in] contains a list of "bad" versions. JREs which have one of these
218 versions must not be returned by this function. It can be NULL.
220 [in] the number of version strings contained in <code>arExcludeList</code>.
223 JFW_PLUGIN_E_NONE the function ran successfully and the version requirements are met
224 JFW_PLUGIN_E_FAILED_VERSION at least one of the version requirements (minVersion,
225 maxVersion, excludeVersions) was violated
226 JFW_PLUGIN_E_WRONG_VERSION_FORMAT the version strings in
227 <code>sMinVersion,sMaxVersion,arExcludeList</code> are not recognized as valid
231 javaPluginError
checkJavaVersionRequirements(
232 rtl::Reference
<VendorBase
> const & aVendorInfo
,
233 OUString
const& sMinVersion
,
234 OUString
const& sMaxVersion
,
235 rtl_uString
* * arExcludeList
,
238 if (!sMinVersion
.isEmpty())
242 if (aVendorInfo
->compareVersions(sMinVersion
) < 0)
243 return JFW_PLUGIN_E_FAILED_VERSION
;
245 catch (MalformedVersionException
&)
247 //The minVersion was not recognized as valid for this vendor.
250 "[Java framework]sunjavaplugin does not know version: "
251 + sMinVersion
+ " for vendor: " + aVendorInfo
->getVendor()
252 + " .Check minimum Version." );
253 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
257 if (!sMaxVersion
.isEmpty())
261 if (aVendorInfo
->compareVersions(sMaxVersion
) > 0)
262 return JFW_PLUGIN_E_FAILED_VERSION
;
264 catch (MalformedVersionException
&)
266 //The maxVersion was not recognized as valid for this vendor.
269 "[Java framework]sunjavaplugin does not know version: "
270 + sMaxVersion
+ " for vendor: " + aVendorInfo
->getVendor()
271 + " .Check maximum Version." );
272 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
276 for (int i
= 0; i
< nLenList
; i
++)
278 OUString
sExVer(arExcludeList
[i
]);
281 if (aVendorInfo
->compareVersions(sExVer
) == 0)
282 return JFW_PLUGIN_E_FAILED_VERSION
;
284 catch (MalformedVersionException
&)
286 //The excluded version was not recognized as valid for this vendor.
289 "[Java framework]sunjavaplugin does not know version: "
290 + sExVer
+ " for vendor: " + aVendorInfo
->getVendor()
291 + " .Check excluded versions." );
292 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
296 return JFW_PLUGIN_E_NONE
;
301 javaPluginError
jfw_plugin_getAllJavaInfos(
302 bool checkJavaHomeAndPath
,
303 OUString
const& sVendor
,
304 OUString
const& sMinVersion
,
305 OUString
const& sMaxVersion
,
306 rtl_uString
* *arExcludeList
,
308 JavaInfo
*** parJavaInfo
,
309 sal_Int32
*nLenInfoList
,
310 std::vector
<rtl::Reference
<jfw_plugin::VendorBase
>> & infos
)
312 OSL_ASSERT(parJavaInfo
);
313 OSL_ASSERT(nLenInfoList
);
314 if (!parJavaInfo
|| !nLenInfoList
)
315 return JFW_PLUGIN_E_INVALID_ARG
;
317 //nLenlist contains the number of elements in arExcludeList.
318 //If no exclude list is provided then nLenList must be 0
319 OSL_ASSERT( ! (arExcludeList
== NULL
&& nLenList
> 0));
320 if (arExcludeList
== NULL
&& nLenList
> 0)
321 return JFW_PLUGIN_E_INVALID_ARG
;
323 OSL_ASSERT(!sVendor
.isEmpty());
324 if (sVendor
.isEmpty())
325 return JFW_PLUGIN_E_INVALID_ARG
;
327 JavaInfo
** arInfo
= NULL
;
330 vector
<rtl::Reference
<VendorBase
> > vecInfos
=
331 addAllJREInfos(checkJavaHomeAndPath
, infos
);
332 vector
<rtl::Reference
<VendorBase
> > vecVerifiedInfos
;
334 typedef vector
<rtl::Reference
<VendorBase
> >::iterator it
;
335 for (it i
= vecInfos
.begin(); i
!= vecInfos
.end(); ++i
)
337 const rtl::Reference
<VendorBase
>& cur
= *i
;
339 if (!sVendor
.equals(cur
->getVendor()))
342 javaPluginError err
= checkJavaVersionRequirements(
343 cur
, sMinVersion
, sMaxVersion
, arExcludeList
, nLenList
);
345 if (err
== JFW_PLUGIN_E_FAILED_VERSION
)
347 else if (err
== JFW_PLUGIN_E_WRONG_VERSION_FORMAT
)
350 vecVerifiedInfos
.push_back(*i
);
352 //Now vecVerifiedInfos contains all those JREs which meet the version requirements
353 //Transfer them into the array that is passed out.
354 arInfo
= static_cast<JavaInfo
**>(rtl_allocateMemory(vecVerifiedInfos
.size() * sizeof (JavaInfo
*)));
356 typedef vector
<rtl::Reference
<VendorBase
> >::const_iterator cit
;
357 for (cit ii
= vecVerifiedInfos
.begin(); ii
!= vecVerifiedInfos
.end(); ++ii
, ++j
)
359 arInfo
[j
] = createJavaInfo(*ii
);
361 *nLenInfoList
= vecVerifiedInfos
.size();
364 *parJavaInfo
= arInfo
;
365 return JFW_PLUGIN_E_NONE
;
368 javaPluginError
jfw_plugin_getJavaInfoByPath(
369 OUString
const& sPath
,
370 OUString
const& sVendor
,
371 OUString
const& sMinVersion
,
372 OUString
const& sMaxVersion
,
373 rtl_uString
* *arExcludeList
,
378 return JFW_PLUGIN_E_INVALID_ARG
;
379 OSL_ASSERT(!sPath
.isEmpty());
381 return JFW_PLUGIN_E_INVALID_ARG
;
383 //nLenlist contains the number of elements in arExcludeList.
384 //If no exclude list is provided then nLenList must be 0
385 OSL_ASSERT( ! (arExcludeList
== NULL
&& nLenList
> 0));
386 if (arExcludeList
== NULL
&& nLenList
> 0)
387 return JFW_PLUGIN_E_INVALID_ARG
;
389 OSL_ASSERT(!sVendor
.isEmpty());
390 if (sVendor
.isEmpty())
391 return JFW_PLUGIN_E_INVALID_ARG
;
393 rtl::Reference
<VendorBase
> aVendorInfo
= getJREInfoByPath(sPath
);
394 if (!aVendorInfo
.is())
395 return JFW_PLUGIN_E_NO_JRE
;
397 //Check if the detected JRE matches the version requirements
398 if (!sVendor
.equals(aVendorInfo
->getVendor()))
399 return JFW_PLUGIN_E_NO_JRE
;
400 javaPluginError errorcode
= checkJavaVersionRequirements(
401 aVendorInfo
, sMinVersion
, sMaxVersion
, arExcludeList
, nLenList
);
403 if (errorcode
== JFW_PLUGIN_E_NONE
)
404 *ppInfo
= createJavaInfo(aVendorInfo
);
409 javaPluginError
jfw_plugin_getJavaInfoFromJavaHome(
410 std::vector
<pair
<OUString
, jfw::VersionInfo
>> const& vecVendorInfos
,
411 JavaInfo
** ppInfo
, std::vector
<rtl::Reference
<VendorBase
>> & infos
)
414 return JFW_PLUGIN_E_INVALID_ARG
;
416 std::vector
<rtl::Reference
<VendorBase
>> infoJavaHome
;
417 addJavaInfoFromJavaHome(infos
, infoJavaHome
);
419 if (infoJavaHome
.empty())
420 return JFW_PLUGIN_E_NO_JRE
;
421 assert(infoJavaHome
.size() == 1);
423 //Check if the detected JRE matches the version requirements
424 typedef std::vector
<pair
<OUString
, jfw::VersionInfo
>>::const_iterator ci_pl
;
425 for (ci_pl vendorInfo
= vecVendorInfos
.begin(); vendorInfo
!= vecVendorInfos
.end(); ++vendorInfo
)
427 const OUString
& vendor
= vendorInfo
->first
;
428 jfw::VersionInfo versionInfo
= vendorInfo
->second
;
430 if (vendor
.equals(infoJavaHome
[0]->getVendor()))
432 javaPluginError errorcode
= checkJavaVersionRequirements(
434 versionInfo
.sMinVersion
,
435 versionInfo
.sMaxVersion
,
436 versionInfo
.getExcludeVersions(),
437 versionInfo
.getExcludeVersionSize());
439 if (errorcode
== JFW_PLUGIN_E_NONE
)
441 *ppInfo
= createJavaInfo(infoJavaHome
[0]);
442 return JFW_PLUGIN_E_NONE
;
447 return JFW_PLUGIN_E_NO_JRE
;
450 javaPluginError
jfw_plugin_getJavaInfosFromPath(
451 std::vector
<std::pair
<OUString
, jfw::VersionInfo
>> const& vecVendorInfos
,
452 std::vector
<JavaInfo
*> & javaInfosFromPath
,
453 std::vector
<rtl::Reference
<jfw_plugin::VendorBase
>> & infos
)
455 // find JREs from PATH
456 vector
<rtl::Reference
<VendorBase
>> vecInfosFromPath
;
457 addJavaInfosFromPath(infos
, vecInfosFromPath
);
459 vector
<JavaInfo
*> vecVerifiedInfos
;
461 // copy infos of JREs that meet version requirements to vecVerifiedInfos
462 typedef vector
<rtl::Reference
<VendorBase
> >::iterator it
;
463 for (it i
= vecInfosFromPath
.begin(); i
!= vecInfosFromPath
.end(); ++i
)
465 const rtl::Reference
<VendorBase
>& currentInfo
= *i
;
467 typedef std::vector
<pair
<OUString
, jfw::VersionInfo
>>::const_iterator ci_pl
;
468 for (ci_pl vendorInfo
= vecVendorInfos
.begin(); vendorInfo
!= vecVendorInfos
.end(); ++vendorInfo
)
470 const OUString
& vendor
= vendorInfo
->first
;
471 jfw::VersionInfo versionInfo
= vendorInfo
->second
;
473 if (vendor
.equals(currentInfo
->getVendor()))
475 javaPluginError errorcode
= checkJavaVersionRequirements(
477 versionInfo
.sMinVersion
,
478 versionInfo
.sMaxVersion
,
479 versionInfo
.getExcludeVersions(),
480 versionInfo
.getExcludeVersionSize());
482 if (errorcode
== JFW_PLUGIN_E_NONE
)
484 vecVerifiedInfos
.push_back(createJavaInfo(currentInfo
));
490 if (vecVerifiedInfos
.empty())
491 return JFW_PLUGIN_E_NO_JRE
;
493 javaInfosFromPath
= vecVerifiedInfos
;
495 return JFW_PLUGIN_E_NONE
;
503 // Load msvcr71.dll using an explicit full path from where it is
504 // present as bundled with the JRE. In case it is not found where we
505 // think it should be, do nothing, and just let the implicit loading
506 // that happens when loading the JVM take care of it.
508 static void load_msvcr(LPCWSTR jvm_dll
, wchar_t const* msvcr
)
510 wchar_t msvcr_dll
[MAX_PATH
];
513 if (wcslen(jvm_dll
) > MAX_PATH
- 15)
516 wcscpy(msvcr_dll
, jvm_dll
);
518 // First check if msvcr71.dll is in the same folder as jvm.dll. It
519 // normally isn't, at least up to 1.6.0_22, but who knows if it
520 // might be in the future.
521 slash
= wcsrchr(msvcr_dll
, L
'\\');
525 // Huh, weird path to jvm.dll. Oh well.
529 wcscpy(slash
+1, msvcr
);
530 if (LoadLibraryW(msvcr_dll
))
533 // Then check if msvcr71.dll is in the parent folder of where
534 // jvm.dll is. That is currently (1.6.0_22) as far as I know the
537 slash
= wcsrchr(msvcr_dll
, L
'\\');
542 wcscpy(slash
+1, msvcr
);
543 LoadLibraryW(msvcr_dll
);
546 // Check if the jvm DLL imports msvcr71.dll, and in that case try
547 // loading it explicitly. In case something goes wrong, do nothing,
548 // and just let the implicit loading try to take care of it.
549 static void do_msvcr_magic(rtl_uString
*jvm_dll
)
551 rtl_uString
* Module(0);
554 oslFileError nError
= osl_getSystemPathFromFileURL(jvm_dll
, &Module
);
556 if ( osl_File_E_None
!= nError
)
557 rtl_uString_assign(&Module
, jvm_dll
);
559 FILE *f
= _wfopen(reinterpret_cast<LPCWSTR
>(Module
->buffer
), L
"rb");
561 if (fstat(fileno(f
), &st
) == -1)
567 PIMAGE_DOS_HEADER dos_hdr
= (PIMAGE_DOS_HEADER
) malloc(st
.st_size
);
569 if (fread(dos_hdr
, st
.st_size
, 1, f
) != 1 ||
570 memcmp(dos_hdr
, "MZ", 2) != 0 ||
571 dos_hdr
->e_lfanew
< 0 ||
572 dos_hdr
->e_lfanew
> (LONG
) (st
.st_size
- sizeof(IMAGE_NT_HEADERS
)))
581 IMAGE_NT_HEADERS
*nt_hdr
= (IMAGE_NT_HEADERS
*) ((char *)dos_hdr
+ dos_hdr
->e_lfanew
);
583 DWORD importsVA
= nt_hdr
->OptionalHeader
584 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
;
585 // first determine Virtual-to-File-address mapping for the section
586 // that contains the import directory
587 IMAGE_SECTION_HEADER
*sections
= IMAGE_FIRST_SECTION(nt_hdr
);
588 ptrdiff_t VAtoPhys
= -1;
589 for (int i
= 0; i
< nt_hdr
->FileHeader
.NumberOfSections
; ++i
)
591 if (sections
->VirtualAddress
<= importsVA
&&
592 importsVA
< sections
->VirtualAddress
+ sections
->SizeOfRawData
)
594 VAtoPhys
= static_cast<size_t>(sections
->PointerToRawData
) - static_cast<size_t>(sections
->VirtualAddress
);
599 if (-1 == VAtoPhys
) // not found?
604 IMAGE_IMPORT_DESCRIPTOR
*imports
=
605 (IMAGE_IMPORT_DESCRIPTOR
*) ((char *) dos_hdr
+ importsVA
+ VAtoPhys
);
607 while (imports
<= (IMAGE_IMPORT_DESCRIPTOR
*) ((char *) dos_hdr
+ st
.st_size
- sizeof (IMAGE_IMPORT_DESCRIPTOR
)) &&
608 imports
->Name
!= 0 &&
609 imports
->Name
+ VAtoPhys
< (DWORD
) st
.st_size
)
611 static struct { char const * name
; wchar_t const * wname
; } msvcrts
[] =
613 { "msvcr71.dll" , L
"msvcr71.dll" },
614 { "msvcr100.dll", L
"msvcr100.dll" },
616 char const* importName
= (char *) dos_hdr
+ imports
->Name
+ VAtoPhys
;
617 for (size_t i
= 0; i
< SAL_N_ELEMENTS(msvcrts
); ++i
)
619 if (0 == strnicmp(importName
,
620 // Intentional strlen() + 1 here to include terminating zero
621 msvcrts
[i
].name
, strlen(msvcrts
[i
].name
) + 1))
623 load_msvcr(reinterpret_cast<LPCWSTR
>(Module
->buffer
),
637 /** starts a Java Virtual Machine.
639 The function shall ensure, that the VM does not abort the process
640 during instantiation.
643 javaPluginError
jfw_plugin_startJavaVirtualMachine(
644 const JavaInfo
*pInfo
,
645 const JavaVMOption
* arOptions
,
650 // unless guard is volatile the following warning occurs on gcc:
651 // warning: variable 't' might be clobbered by `longjmp' or `vfork'
652 volatile osl::MutexGuard
guard(PluginMutex::get());
653 // unless errorcode is volatile the following warning occurs on gcc:
654 // warning: variable 'errorcode' might be clobbered by `longjmp' or `vfork'
655 volatile javaPluginError errorcode
= JFW_PLUGIN_E_NONE
;
656 if ( pInfo
== NULL
|| ppVm
== NULL
|| ppEnv
== NULL
)
657 return JFW_PLUGIN_E_INVALID_ARG
;
658 //Check if the Vendor (pInfo->sVendor) is supported by this plugin
659 if ( ! isVendorSupported(pInfo
->sVendor
))
660 return JFW_PLUGIN_E_WRONG_VENDOR
;
661 OUString sRuntimeLib
= getRuntimeLib(pInfo
->arVendorData
);
662 JFW_TRACE2("Using Java runtime library: " << sRuntimeLib
);
665 // On linux we load jvm with RTLD_GLOBAL. This is necessary for debugging, because
666 // libjdwp.so need a symbol (fork1) from libjvm which it only gets if the jvm is loaded
667 // witd RTLD_GLOBAL. On Solaris libjdwp.so is correctly linked with libjvm.so
668 osl::Module moduleRt
;
670 if (!moduleRt
.load(sRuntimeLib
, SAL_LOADMODULE_GLOBAL
| SAL_LOADMODULE_NOW
))
673 do_msvcr_magic(sRuntimeLib
.pData
);
675 if (!moduleRt
.load(sRuntimeLib
, SAL_LOADMODULE_DEFAULT
))
679 "[Java framework]sunjavaplugin" SAL_DLLEXTENSION
680 " could not load Java runtime library: \n"
681 + sRuntimeLib
+ "\n");
682 JFW_TRACE0("Could not load Java runtime library: " << sRuntimeLib
);
683 return JFW_PLUGIN_E_VM_CREATION_FAILED
;
686 #if defined UNX && !defined MACOSX
687 //Setting the JAVA_HOME is needed for awt
688 OUString sPathLocation
;
689 osl_getSystemPathFromFileURL(pInfo
->sLocation
, & sPathLocation
.pData
);
690 osl_setEnvironment(OUString("JAVA_HOME").pData
, sPathLocation
.pData
);
693 typedef jint JNICALL
JNI_CreateVM_Type(JavaVM
**, JNIEnv
**, void *);
694 OUString
sSymbolCreateJava("JNI_CreateJavaVM");
696 JNI_CreateVM_Type
* pCreateJavaVM
=
697 reinterpret_cast<JNI_CreateVM_Type
*>(moduleRt
.getFunctionSymbol(sSymbolCreateJava
));
701 OString sLib
= OUStringToOString(
702 sRuntimeLib
, osl_getThreadTextEncoding());
703 OString sSymbol
= OUStringToOString(
704 sSymbolCreateJava
, osl_getThreadTextEncoding());
705 fprintf(stderr
,"[Java framework]sunjavaplugin" SAL_DLLEXTENSION
706 "Java runtime library: %s does not export symbol %s !\n",
707 sLib
.getStr(), sSymbol
.getStr());
708 return JFW_PLUGIN_E_VM_CREATION_FAILED
;
712 // Valgrind typically emits many false errors when executing JIT'ed JVM
713 // code, so force the JVM into interpreted mode:
714 bool addForceInterpreted
= FORCE_INTERPRETED
> 0;
716 // Some testing with Java 1.4 showed that JavaVMOption.optionString has to
717 // be encoded with the system encoding (i.e., osl_getThreadTextEncoding):
718 JavaVMInitArgs vm_args
;
721 Option(OString
const & theOptionString
, void * theExtraInfo
):
722 optionString(theOptionString
), extraInfo(theExtraInfo
)
725 OString optionString
;
728 std::vector
<Option
> options
;
730 // We set an abort handler which is called when the VM calls _exit during
731 // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
732 // all some directories of the Java installation. This is necessary for
733 // all versions below 1.5.1
734 options
.push_back(Option("abort", reinterpret_cast<void*>(abort_handler
)));
735 bool hasStackSize
= false;
736 for (int i
= 0; i
< cOptions
; i
++)
738 OString
opt(arOptions
[i
].optionString
);
740 // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
741 // in the class path in order to have applet support:
742 if (opt
.startsWith("-Djava.class.path="))
744 OString sAddPath
= getPluginJarPath(pInfo
->sVendor
, pInfo
->sLocation
,pInfo
->sVersion
);
745 if (!sAddPath
.isEmpty())
746 opt
+= OString(SAL_PATHSEPARATOR
) + sAddPath
;
749 if (opt
== "-Xint") {
750 addForceInterpreted
= false;
752 if (opt
.startsWith("-Xss")) {
755 options
.push_back(Option(opt
, arOptions
[i
].extraInfo
));
757 if (addForceInterpreted
) {
758 options
.push_back(Option("-Xint", nullptr));
761 #if defined LINUX && (defined X86 || defined X86_64)
762 // At least OpenJDK 1.8.0's os::workaround_expand_exec_shield_cs_limit
763 // (hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp) can mmap an rwx
764 // page into the area that the main stack can grow down to according to
765 // "ulimit -s", as os::init_2's (hotspot/src/os/linux/vm/os_linux.cpp)
768 // Linux::capture_initial_stack(JavaThread::stack_size_at_create());
770 // caps _initial_thread_stack_size at threadStackSizeInBytes ,i.e.,
771 // -Xss, which appears to default to only 327680, whereas "ulimit -s"
772 // defaults to 8192 * 1024 at least on Fedora 20; so attempt to pass in
773 // a useful -Xss argument:
775 if (getrlimit(RLIMIT_STACK
, &l
) == 0) {
776 if (l
.rlim_cur
== RLIM_INFINITY
) {
777 SAL_INFO("jfw", "RLIMIT_STACK RLIM_INFINITY -> 8192K");
778 l
.rlim_cur
= 8192 * 1024;
779 } else if (l
.rlim_cur
> 512 * 1024 * 1024) {
781 "jfw", "huge RLIMIT_STACK " << l
.rlim_cur
<< " -> 8192K");
782 l
.rlim_cur
= 8192 * 1024;
785 Option("-Xss" + OString::number(l
.rlim_cur
), nullptr));
788 SAL_WARN("jfw", "getrlimit(RLIMIT_STACK) failed with errno " << e
);
793 boost::scoped_array
<JavaVMOption
> sarOptions(new JavaVMOption
[options
.size()]);
794 for (std::vector
<Option
>::size_type i
= 0; i
!= options
.size(); ++i
) {
797 "VM option \"" << options
[i
].optionString
<< "\" "
798 << options
[i
].extraInfo
);
799 sarOptions
[i
].optionString
= const_cast<char *>(
800 options
[i
].optionString
.getStr());
801 sarOptions
[i
].extraInfo
= options
[i
].extraInfo
;
805 vm_args
.version
= JNI_VERSION_1_4
; // issue 88987
807 vm_args
.version
= JNI_VERSION_1_2
;
809 vm_args
.options
= sarOptions
.get();
810 vm_args
.nOptions
= options
.size(); //TODO overflow
811 vm_args
.ignoreUnrecognized
= JNI_TRUE
;
813 /* We set a global flag which is used by the abort handler in order to
814 determine whether it is should use longjmp to get back into this function.
815 That is, the abort handler determines if it is on the same stack as this function
816 and then jumps back into this function.
820 JavaVM
* pJavaVM
= 0;
821 memset( jmp_jvm_abort
, 0, sizeof(jmp_jvm_abort
));
822 int jmpval
= setjmp( jmp_jvm_abort
);
823 /* If jmpval is not "0" then this point was reached by a longjmp in the
824 abort_handler, which was called indirectly by JNI_CreateVM.
828 //returns negative number on failure
829 err
= pCreateJavaVM(&pJavaVM
, ppEnv
, &vm_args
);
833 // set err to a positive number, so as or recognize that an abort (longjmp)
841 fprintf(stderr
,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
842 "Can not create Java Virtual Machine\n");
843 errorcode
= JFW_PLUGIN_E_VM_CREATION_FAILED
;
847 fprintf(stderr
,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
848 "Can not create JavaVirtualMachine, abort handler was called.\n");
849 errorcode
= JFW_PLUGIN_E_VM_CREATION_FAILED
;
855 JFW_TRACE2("JVM created");
860 // On Android we always have a Java VM as we only expect this code
861 // to be run in an Android app anyway.
862 *ppVm
= lo_get_javavm();
863 fprintf(stderr
, "lo_get_javavm returns %p", *ppVm
);
869 javaPluginError
jfw_plugin_existJRE(const JavaInfo
*pInfo
, sal_Bool
*exist
)
871 javaPluginError ret
= JFW_PLUGIN_E_NONE
;
872 if (!pInfo
|| !exist
)
873 return JFW_PLUGIN_E_INVALID_ARG
;
874 OUString
sLocation(pInfo
->sLocation
);
876 if (sLocation
.isEmpty())
877 return JFW_PLUGIN_E_INVALID_ARG
;
878 ::osl::DirectoryItem item
;
879 ::osl::File::RC rc_item
= ::osl::DirectoryItem::get(sLocation
, item
);
880 if (::osl::File::E_None
== rc_item
)
884 else if (::osl::File::E_NOENT
== rc_item
)
890 ret
= JFW_PLUGIN_E_ERROR
;
892 //We can have the situation that the JavaVM runtime library is not
893 //contained within JAVA_HOME. Then the check for JAVA_HOME would return
894 //true although the runtime library may not be loadable.
895 //Or the JAVA_HOME directory of a deinstalled JRE left behind.
896 if (ret
== JFW_PLUGIN_E_NONE
&& *exist
== sal_True
)
898 OUString sRuntimeLib
= getRuntimeLib(pInfo
->arVendorData
);
899 JFW_TRACE2("Checking existence of Java runtime library");
901 ::osl::DirectoryItem itemRt
;
902 ::osl::File::RC rc_itemRt
= ::osl::DirectoryItem::get(sRuntimeLib
, itemRt
);
903 if (::osl::File::E_None
== rc_itemRt
)
906 JFW_TRACE2("Java runtime library exist: " << sRuntimeLib
);
909 else if (::osl::File::E_NOENT
== rc_itemRt
)
912 JFW_TRACE2("Java runtime library does not exist: " << sRuntimeLib
);
916 ret
= JFW_PLUGIN_E_ERROR
;
917 JFW_TRACE2("Error while looking for Java runtime library: " << sRuntimeLib
);
924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */