lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / jvmfwk / plugins / sunmajor / pluginlib / sunjavaplugin.cxx
blobcaec8633b9db9fc03587b1b93b3f94c84b925806
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #ifdef _WIN32
22 # include <stdio.h>
23 # include <sys/stat.h>
24 # if !defined WIN32_LEAN_AND_MEAN
25 # define WIN32_LEAN_AND_MEAN
26 # endif
27 # include <windows.h>
28 #endif
30 #ifdef ANDROID
31 # include <dlfcn.h>
32 #endif
34 #include <string.h>
36 #include <cassert>
37 #include <memory>
38 #include <utility>
39 #include <vector>
41 #include <config_options.h>
42 #include <osl/diagnose.h>
43 #include <rtl/ustring.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include <osl/module.hxx>
46 #include <osl/mutex.hxx>
47 #include <osl/process.h>
48 #include <osl/thread.hxx>
49 #include <osl/file.hxx>
50 #include <rtl/instance.hxx>
51 #include <sal/log.hxx>
52 #include <osl/getglobalmutex.hxx>
53 #include <o3tl/char16_t2wchar_t.hxx>
54 #include <setjmp.h>
55 #include <signal.h>
56 #include <stack>
58 #include <jni.h>
59 #include <rtl/byteseq.hxx>
60 #include <fwkbase.hxx>
61 #include <vendorplugin.hxx>
62 #include "util.hxx"
63 #include "sunversion.hxx"
64 #include "vendorlist.hxx"
65 #include "diagnostics.h"
67 #ifdef MACOSX
68 #include "util_cocoa.hxx"
69 #endif
71 #ifdef ANDROID
72 #include <osl/detail/android-bootstrap.h>
73 #else
74 #if !ENABLE_RUNTIME_OPTIMIZATIONS
75 #define FORCE_INTERPRETED 1
76 #elif defined HAVE_VALGRIND_HEADERS
77 #include <valgrind/valgrind.h>
78 #define FORCE_INTERPRETED RUNNING_ON_VALGRIND
79 #else
80 #define FORCE_INTERPRETED 0
81 #endif
82 #endif
84 #if defined LINUX && (defined X86 || defined X86_64)
85 #include <sys/resource.h>
86 #endif
88 using namespace osl;
89 using namespace std;
90 using namespace jfw_plugin;
93 namespace {
95 struct PluginMutex: public ::rtl::Static<osl::Mutex, PluginMutex> {};
97 #if defined(UNX) && !defined(ANDROID)
98 OString getPluginJarPath(
99 const OUString & sVendor,
100 const OUString& sLocation,
101 const OUString& sVersion)
103 OString ret;
104 OUString sName1("javaplugin.jar");
105 OUString sName2("plugin.jar");
106 OUString sPath;
107 if ( sVendor == "Sun Microsystems Inc." )
109 SunVersion ver142("1.4.2-ea");
110 SunVersion ver150("1.5.0-ea");
111 SunVersion ver(sVersion);
112 OSL_ASSERT(ver142 && ver150 && ver);
114 OUString sName;
115 if (ver < ver142)
117 sName = sName1;
119 else if (ver < ver150)
120 {//this will cause ea, beta etc. to have plugin.jar in path.
121 //but this does not harm. 1.5.0-beta < 1.5.0
122 sName = sName2;
124 if (!sName.isEmpty())
126 sName = sLocation + "/lib/" + sName;
127 OSL_VERIFY(
128 osl_getSystemPathFromFileURL(sName.pData, & sPath.pData)
129 == osl_File_E_None);
132 else
134 OUString sName(sLocation + "/lib/" + sName1);
135 OUString sPath1;
136 OUString sPath2;
137 if (osl_getSystemPathFromFileURL(sName.pData, & sPath1.pData)
138 == osl_File_E_None)
140 sName = sLocation + "/lib/" + sName2;
141 if (osl_getSystemPathFromFileURL(sName.pData, & sPath2.pData)
142 == osl_File_E_None)
144 sPath = sPath1 + OUStringLiteral1(SAL_PATHSEPARATOR) + sPath2;
147 OSL_ASSERT(!sPath.isEmpty());
149 ret = OUStringToOString(sPath, osl_getThreadTextEncoding());
151 return ret;
153 #endif // UNX
156 std::unique_ptr<JavaInfo> createJavaInfo(
157 const rtl::Reference<VendorBase> & info)
159 OUStringBuffer buf(1024);
160 buf.append(info->getRuntimeLibrary());
161 if (!info->getLibraryPath().isEmpty())
163 buf.append("\n");
164 buf.append(info->getLibraryPath());
165 buf.append("\n");
167 OUString sVendorData = buf.makeStringAndClear();
168 return std::unique_ptr<JavaInfo>(
169 new JavaInfo{
170 info->getVendor(), info->getHome(), info->getVersion(),
171 sal_uInt64(info->supportsAccessibility() ? 1 : 0),
172 sal_uInt64(info->needsRestart() ? JFW_REQUIRE_NEEDRESTART : 0),
173 rtl::ByteSequence(
174 reinterpret_cast<sal_Int8*>(sVendorData.pData->buffer),
175 sVendorData.getLength() * sizeof(sal_Unicode))});
178 OUString getRuntimeLib(const rtl::ByteSequence & data)
180 const sal_Unicode* chars = reinterpret_cast<sal_Unicode const *>(data.getConstArray());
181 sal_Int32 len = data.getLength();
182 OUString sData(chars, len / 2);
183 //the runtime lib is on the first line
184 sal_Int32 index = 0;
185 OUString aToken = sData.getToken( 0, '\n', index);
187 return aToken;
190 jmp_buf jmp_jvm_abort;
191 sig_atomic_t g_bInGetJavaVM = 0;
193 extern "C" void JNICALL abort_handler()
195 // If we are within JNI_CreateJavaVM then we jump back into getJavaVM
196 if( g_bInGetJavaVM != 0 )
198 fprintf(stderr, "JavaVM: JNI_CreateJavaVM called os::abort(), caught by abort_handler in javavm.cxx\n");
199 longjmp( jmp_jvm_abort, 0);
203 /** helper function to check Java version requirements
205 This function checks if the Java version of the given VendorBase
206 meets the given Java version requirements.
208 @param aVendorInfo
209 [in] the object to be inspected whether it meets the version requirements
210 @param sMinVersion
211 [in] represents the minimum version of a JRE. The string can be empty.
212 @param sMaxVersion
213 [in] represents the maximum version of a JRE. The string can be empty.
214 @param arExcludeList
215 [in] contains a list of &quot;bad&quot; versions. JREs which have one of these
216 versions must not be returned by this function.
218 @return
219 javaPluginError::NONE the function ran successfully and the version requirements are met
220 javaPluginError::FailedVersion at least one of the version requirements (minVersion,
221 maxVersion, excludeVersions) was violated
222 javaPluginError::WrongVersionFormat the version strings in
223 <code>sMinVersion,sMaxVersion,arExcludeList</code> are not recognized as valid
224 version strings.
227 javaPluginError checkJavaVersionRequirements(
228 rtl::Reference<VendorBase> const & aVendorInfo,
229 OUString const& sMinVersion,
230 OUString const& sMaxVersion,
231 std::vector<OUString> const & arExcludeList)
233 if (!aVendorInfo->isValidArch())
235 return javaPluginError::WrongArch;
237 if (!sMinVersion.isEmpty())
241 if (aVendorInfo->compareVersions(sMinVersion) < 0)
242 return javaPluginError::FailedVersion;
244 catch (MalformedVersionException&)
246 //The minVersion was not recognized as valid for this vendor.
247 JFW_ENSURE(
248 false,
249 "[Java framework]sunjavaplugin does not know version: "
250 + sMinVersion + " for vendor: " + aVendorInfo->getVendor()
251 + " .Check minimum Version." );
252 return javaPluginError::WrongVersionFormat;
256 if (!sMaxVersion.isEmpty())
260 if (aVendorInfo->compareVersions(sMaxVersion) > 0)
261 return javaPluginError::FailedVersion;
263 catch (MalformedVersionException&)
265 //The maxVersion was not recognized as valid for this vendor.
266 JFW_ENSURE(
267 false,
268 "[Java framework]sunjavaplugin does not know version: "
269 + sMaxVersion + " for vendor: " + aVendorInfo->getVendor()
270 + " .Check maximum Version." );
271 return javaPluginError::WrongVersionFormat;
275 for (auto const & sExVer: arExcludeList) {
278 if (aVendorInfo->compareVersions(sExVer) == 0)
279 return javaPluginError::FailedVersion;
281 catch (MalformedVersionException&)
283 //The excluded version was not recognized as valid for this vendor.
284 JFW_ENSURE(
285 false,
286 "[Java framework]sunjavaplugin does not know version: "
287 + sExVer + " for vendor: " + aVendorInfo->getVendor()
288 + " .Check excluded versions." );
289 return javaPluginError::WrongVersionFormat;
293 return javaPluginError::NONE;
298 javaPluginError jfw_plugin_getAllJavaInfos(
299 bool checkJavaHomeAndPath,
300 jfw::VendorSettings const & vendorSettings,
301 std::vector<std::unique_ptr<JavaInfo>>* parJavaInfo,
302 std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos)
304 assert(parJavaInfo);
306 //Find all JREs
307 vector<rtl::Reference<VendorBase> > vecInfos =
308 addAllJREInfos(checkJavaHomeAndPath, infos);
309 vector<rtl::Reference<VendorBase> > vecVerifiedInfos;
311 for (auto const& vecInfo : vecInfos)
313 if (auto const versionInfo = vendorSettings.getVersionInformation(vecInfo->getVendor()))
315 javaPluginError err = checkJavaVersionRequirements(
316 vecInfo, versionInfo->sMinVersion, versionInfo->sMaxVersion, versionInfo->vecExcludeVersions);
318 if (err == javaPluginError::FailedVersion || err == javaPluginError::WrongArch)
319 continue;
320 else if (err == javaPluginError::WrongVersionFormat)
321 return err;
324 vecVerifiedInfos.push_back(vecInfo);
326 //Now vecVerifiedInfos contains all those JREs which meet the version requirements
327 //Transfer them into the array that is passed out.
328 parJavaInfo->clear();
329 for (auto const& vecVerifiedInfo : vecVerifiedInfos)
331 parJavaInfo->push_back(createJavaInfo(vecVerifiedInfo));
334 return javaPluginError::NONE;
337 javaPluginError jfw_plugin_getJavaInfoByPath(
338 OUString const& sPath,
339 jfw::VendorSettings const & vendorSettings,
340 std::unique_ptr<JavaInfo> * ppInfo)
342 assert(ppInfo != nullptr);
343 OSL_ASSERT(!sPath.isEmpty());
344 if (sPath.isEmpty())
345 return javaPluginError::InvalidArg;
347 rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath(sPath);
348 if (!aVendorInfo.is())
349 return javaPluginError::NoJre;
351 //Check if the detected JRE matches the version requirements
352 javaPluginError errorcode = javaPluginError::NONE;
353 if (auto const versionInfo = vendorSettings.getVersionInformation(aVendorInfo->getVendor()))
355 errorcode = checkJavaVersionRequirements(
356 aVendorInfo, versionInfo->sMinVersion, versionInfo->sMaxVersion, versionInfo->vecExcludeVersions);
359 if (errorcode == javaPluginError::NONE)
360 *ppInfo = createJavaInfo(aVendorInfo);
362 return errorcode;
365 javaPluginError jfw_plugin_getJavaInfoFromJavaHome(
366 jfw::VendorSettings const & vendorSettings,
367 std::unique_ptr<JavaInfo> * ppInfo,
368 std::vector<rtl::Reference<VendorBase>> & infos)
370 assert(ppInfo);
372 std::vector<rtl::Reference<VendorBase>> infoJavaHome;
373 addJavaInfoFromJavaHome(infos, infoJavaHome);
375 if (infoJavaHome.empty())
376 return javaPluginError::NoJre;
377 assert(infoJavaHome.size() == 1);
379 //Check if the detected JRE matches the version requirements
380 auto const versionInfo = vendorSettings.getVersionInformation(infoJavaHome[0]->getVendor());
381 if (!versionInfo
382 || (checkJavaVersionRequirements(
383 infoJavaHome[0],
384 versionInfo->sMinVersion,
385 versionInfo->sMaxVersion,
386 versionInfo->vecExcludeVersions)
387 == javaPluginError::NONE))
389 *ppInfo = createJavaInfo(infoJavaHome[0]);
390 return javaPluginError::NONE;
393 return javaPluginError::NoJre;
396 javaPluginError jfw_plugin_getJavaInfosFromPath(
397 jfw::VendorSettings const & vendorSettings,
398 std::vector<std::unique_ptr<JavaInfo>> & javaInfosFromPath,
399 std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos)
401 // find JREs from PATH
402 vector<rtl::Reference<VendorBase>> vecInfosFromPath;
403 addJavaInfosFromPath(infos, vecInfosFromPath);
405 vector<std::unique_ptr<JavaInfo>> vecVerifiedInfos;
407 // copy infos of JREs that meet version requirements to vecVerifiedInfos
408 for (auto const& infosFromPath : vecInfosFromPath)
410 auto const versionInfo = vendorSettings.getVersionInformation(infosFromPath->getVendor());
411 if (!versionInfo
412 || (checkJavaVersionRequirements(
413 infosFromPath,
414 versionInfo->sMinVersion,
415 versionInfo->sMaxVersion,
416 versionInfo->vecExcludeVersions)
417 == javaPluginError::NONE))
419 vecVerifiedInfos.push_back(createJavaInfo(infosFromPath));
423 if (vecVerifiedInfos.empty())
424 return javaPluginError::NoJre;
426 javaInfosFromPath = std::move(vecVerifiedInfos);
428 return javaPluginError::NONE;
432 #if defined(_WIN32)
434 // Load msvcr71.dll using an explicit full path from where it is
435 // present as bundled with the JRE. In case it is not found where we
436 // think it should be, do nothing, and just let the implicit loading
437 // that happens when loading the JVM take care of it.
439 static void load_msvcr(OUString const & jvm_dll, OUStringLiteral msvcr)
441 // First check if msvcr71.dll is in the same folder as jvm.dll. It
442 // normally isn't, at least up to 1.6.0_22, but who knows if it
443 // might be in the future.
444 sal_Int32 slash = jvm_dll.lastIndexOf('\\');
446 if (slash == -1)
448 // Huh, weird path to jvm.dll. Oh well.
449 SAL_WARN("jfw", "JVM pathname <" + jvm_dll + "> w/o backslash");
450 return;
453 if (LoadLibraryW(
454 o3tl::toW(OUString(jvm_dll.copy(0, slash+1) + msvcr).getStr())))
455 return;
457 // Then check if msvcr71.dll is in the parent folder of where
458 // jvm.dll is. That is currently (1.6.0_22) as far as I know the
459 // normal case.
460 slash = jvm_dll.lastIndexOf('\\', slash);
462 if (slash == -1)
463 return;
465 (void)LoadLibraryW(
466 o3tl::toW(OUString(jvm_dll.copy(0, slash+1) + msvcr).getStr()));
469 // Check if the jvm DLL imports msvcr71.dll, and in that case try
470 // loading it explicitly. In case something goes wrong, do nothing,
471 // and just let the implicit loading try to take care of it.
472 static void do_msvcr_magic(OUString const &jvm_dll)
474 struct stat st;
476 OUString Module;
477 osl::FileBase::RC nError = osl::FileBase::getSystemPathFromFileURL(
478 jvm_dll, Module);
480 if ( osl::FileBase::E_None != nError )
482 SAL_WARN(
483 "jfw", "getSystemPathFromFileURL(" << jvm_dll << "): " << +nError);
484 return;
487 FILE *f = _wfopen(o3tl::toW(Module.getStr()), L"rb");
489 if (!f)
491 SAL_WARN("jfw", "_wfopen(" << Module << ") failed");
492 return;
495 if (fstat(fileno(f), &st) == -1)
497 SAL_WARN("jfw", "fstat(" << Module << ") failed");
498 fclose(f);
499 return;
502 PIMAGE_DOS_HEADER dos_hdr = static_cast<PIMAGE_DOS_HEADER>(malloc(st.st_size));
504 if (fread(dos_hdr, st.st_size, 1, f) != 1 ||
505 memcmp(dos_hdr, "MZ", 2) != 0 ||
506 dos_hdr->e_lfanew < 0 ||
507 dos_hdr->e_lfanew > static_cast<LONG>(st.st_size - sizeof(IMAGE_NT_HEADERS)))
509 SAL_WARN("jfw", "analyzing <" << Module << "> failed");
510 free(dos_hdr);
511 fclose(f);
512 return;
515 fclose(f);
517 IMAGE_NT_HEADERS *nt_hdr = reinterpret_cast<IMAGE_NT_HEADERS *>(reinterpret_cast<char *>(dos_hdr) + dos_hdr->e_lfanew);
519 DWORD importsVA = nt_hdr->OptionalHeader
520 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
521 // first determine Virtual-to-File-address mapping for the section
522 // that contains the import directory
523 IMAGE_SECTION_HEADER *sections = IMAGE_FIRST_SECTION(nt_hdr);
524 ptrdiff_t VAtoPhys = -1;
525 for (int i = 0; i < nt_hdr->FileHeader.NumberOfSections; ++i)
527 if (sections->VirtualAddress <= importsVA &&
528 importsVA < sections->VirtualAddress + sections->SizeOfRawData)
530 VAtoPhys = static_cast<size_t>(sections->PointerToRawData) - static_cast<size_t>(sections->VirtualAddress);
531 break;
533 ++sections;
535 if (-1 == VAtoPhys) // not found?
537 SAL_WARN("jfw", "analyzing <" << Module << "> failed");
538 free(dos_hdr);
539 return;
541 IMAGE_IMPORT_DESCRIPTOR *imports =
542 reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR *>(reinterpret_cast<char *>(dos_hdr) + importsVA + VAtoPhys);
544 while (imports <= reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR *>(reinterpret_cast<char *>(dos_hdr) + st.st_size - sizeof (IMAGE_IMPORT_DESCRIPTOR)) &&
545 imports->Name != 0 &&
546 imports->Name + VAtoPhys < static_cast<DWORD>(st.st_size))
548 static OUStringLiteral msvcrts[] =
550 "msvcr71.dll",
551 "msvcr100.dll"
553 char const* importName = reinterpret_cast<char *>(dos_hdr) + imports->Name + VAtoPhys;
554 sal_Int32 importNameLen = rtl_str_getLength(importName);
555 for (size_t i = 0; i < SAL_N_ELEMENTS(msvcrts); ++i)
557 if (0 == rtl_str_compareIgnoreAsciiCase_WithLength(
558 importName, importNameLen,
559 msvcrts[i].data, msvcrts[i].size))
561 load_msvcr(Module, msvcrts[i]);
562 free(dos_hdr);
563 return;
566 imports++;
569 free(dos_hdr);
572 #endif
574 /** starts a Java Virtual Machine.
576 The function shall ensure, that the VM does not abort the process
577 during instantiation.
578 </p>
580 javaPluginError jfw_plugin_startJavaVirtualMachine(
581 const JavaInfo *pInfo,
582 const JavaVMOption* arOptions,
583 sal_Int32 cOptions,
584 JavaVM ** ppVm,
585 JNIEnv ** ppEnv)
587 assert(pInfo != nullptr);
588 assert(ppVm != nullptr);
589 assert(ppEnv != nullptr);
590 // unless guard is volatile the following warning occurs on gcc:
591 // warning: variable 't' might be clobbered by `longjmp' or `vfork'
592 volatile osl::MutexGuard guard(PluginMutex::get());
593 // unless errorcode is volatile the following warning occurs on gcc:
594 // warning: variable 'errorcode' might be clobbered by `longjmp' or `vfork'
595 volatile javaPluginError errorcode = javaPluginError::NONE;
596 #ifdef MACOSX
597 rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath( pInfo->sLocation );
598 if ( !aVendorInfo.is() || aVendorInfo->compareVersions( pInfo->sVersion ) < 0 )
599 return javaPluginError::VmCreationFailed;
600 #endif
601 OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
602 #ifdef MACOSX
603 if ( !JvmfwkUtil_isLoadableJVM( sRuntimeLib ) )
604 return javaPluginError::VmCreationFailed;
605 #endif
606 JFW_TRACE2("Using Java runtime library: " << sRuntimeLib);
608 #ifndef ANDROID
609 // On linux we load jvm with RTLD_GLOBAL. This is necessary for debugging, because
610 // libjdwp.so need a symbol (fork1) from libjvm which it only gets if the jvm is loaded
611 // with RTLD_GLOBAL. On Solaris libjdwp.so is correctly linked with libjvm.so
612 osl::Module moduleRt;
613 #if defined(LINUX)
614 if (!moduleRt.load(sRuntimeLib, SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_NOW))
615 #elif defined MACOSX
616 // Must be SAL_LOADMODULE_GLOBAL when e.g. specifying a
617 // -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 option to
618 // JDK 1.8.0_121 at least, as JNI_CreateJavaVM -> Threads::create_vm ->
619 // JvmtiExport::post_vm_initialized -> cbEarlyVMInit -> initialize ->
620 // util_initialize -> sun.misc.VMSupport.getAgentProperties ->
621 // Java_sun_misc_VMSupport_initAgentProperties ->
622 // JDK_FindJvmEntry("JVM_INitAgentProperties") ->
623 // dlsym(RTLD_DEFAULT, "JVM_INitAgentProperties"):
624 if (!moduleRt.load(sRuntimeLib, SAL_LOADMODULE_GLOBAL))
625 #else
626 #if defined(_WIN32)
627 do_msvcr_magic(sRuntimeLib);
628 #endif
629 if (!moduleRt.load(sRuntimeLib))
630 #endif
632 JFW_ENSURE(false,
633 "[Java framework]sunjavaplugin" SAL_DLLEXTENSION
634 " could not load Java runtime library: \n"
635 + sRuntimeLib + "\n");
636 JFW_TRACE0("Could not load Java runtime library: " << sRuntimeLib);
637 return javaPluginError::VmCreationFailed;
640 #if defined UNX && !defined MACOSX
641 //Setting the JAVA_HOME is needed for awt
642 OUString sPathLocation;
643 osl::FileBase::getSystemPathFromFileURL(pInfo->sLocation, sPathLocation);
644 osl_setEnvironment(OUString("JAVA_HOME").pData, sPathLocation.pData);
645 #endif
647 typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);
648 OUString sSymbolCreateJava("JNI_CreateJavaVM");
650 JNI_CreateVM_Type * pCreateJavaVM =
651 reinterpret_cast<JNI_CreateVM_Type *>(moduleRt.getFunctionSymbol(sSymbolCreateJava));
652 if (!pCreateJavaVM)
654 OSL_ASSERT(false);
655 OString sLib = OUStringToOString(
656 sRuntimeLib, osl_getThreadTextEncoding());
657 OString sSymbol = OUStringToOString(
658 sSymbolCreateJava, osl_getThreadTextEncoding());
659 fprintf(stderr,"[Java framework]sunjavaplugin" SAL_DLLEXTENSION
660 "Java runtime library: %s does not export symbol %s !\n",
661 sLib.getStr(), sSymbol.getStr());
662 return javaPluginError::VmCreationFailed;
664 moduleRt.release();
666 // Valgrind typically emits many false errors when executing JIT'ed JVM
667 // code, so force the JVM into interpreted mode:
668 bool addForceInterpreted = FORCE_INTERPRETED > 0;
670 // Some testing with Java 1.4 showed that JavaVMOption.optionString has to
671 // be encoded with the system encoding (i.e., osl_getThreadTextEncoding):
672 JavaVMInitArgs vm_args;
674 struct Option {
675 Option(OString const & theOptionString, void * theExtraInfo):
676 optionString(theOptionString), extraInfo(theExtraInfo)
679 OString optionString;
680 void * extraInfo;
682 std::vector<Option> options;
684 // We set an abort handler which is called when the VM calls _exit during
685 // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
686 // all some directories of the Java installation. This is necessary for
687 // all versions below 1.5.1
688 options.emplace_back("abort", reinterpret_cast<void*>(abort_handler));
689 bool hasStackSize = false;
690 for (int i = 0; i < cOptions; i++)
692 OString opt(arOptions[i].optionString);
693 #ifdef UNX
694 // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
695 // in the class path in order to have applet support:
696 if (opt.startsWith("-Djava.class.path="))
698 OString sAddPath = getPluginJarPath(pInfo->sVendor, pInfo->sLocation,pInfo->sVersion);
699 if (!sAddPath.isEmpty())
700 opt += OString(SAL_PATHSEPARATOR) + sAddPath;
702 #endif
703 if (opt == "-Xint") {
704 addForceInterpreted = false;
706 if (opt.startsWith("-Xss")) {
707 hasStackSize = true;
709 options.emplace_back(opt, arOptions[i].extraInfo);
711 if (addForceInterpreted) {
712 options.emplace_back("-Xint", nullptr);
714 if (!hasStackSize) {
715 #if defined LINUX && (defined X86 || defined X86_64)
716 // At least OpenJDK 1.8.0's os::workaround_expand_exec_shield_cs_limit
717 // (hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp) can mmap an rwx
718 // page into the area that the main stack can grow down to according to
719 // "ulimit -s", as os::init_2's (hotspot/src/os/linux/vm/os_linux.cpp)
720 // call to
722 // Linux::capture_initial_stack(JavaThread::stack_size_at_create());
724 // caps _initial_thread_stack_size at threadStackSizeInBytes ,i.e.,
725 // -Xss, which appears to default to only 327680, whereas "ulimit -s"
726 // defaults to 8192 * 1024 at least on Fedora 20; so attempt to pass in
727 // a useful -Xss argument:
728 rlimit l;
729 if (getrlimit(RLIMIT_STACK, &l) == 0) {
730 if (l.rlim_cur == RLIM_INFINITY) {
731 SAL_INFO("jfw", "RLIMIT_STACK RLIM_INFINITY -> 8192K");
732 l.rlim_cur = 8192 * 1024;
733 } else if (l.rlim_cur > 512 * 1024 * 1024) {
734 SAL_INFO(
735 "jfw", "huge RLIMIT_STACK " << l.rlim_cur << " -> 8192K");
736 l.rlim_cur = 8192 * 1024;
738 options.emplace_back("-Xss" + OString::number(l.rlim_cur), nullptr);
739 } else {
740 int e = errno;
741 SAL_WARN("jfw", "getrlimit(RLIMIT_STACK) failed with errno " << e);
743 #endif
746 std::unique_ptr<JavaVMOption[]> sarOptions(new JavaVMOption[options.size()]);
747 for (std::vector<Option>::size_type i = 0; i != options.size(); ++i) {
748 SAL_INFO(
749 "jfw",
750 "VM option \"" << options[i].optionString << "\" "
751 << options[i].extraInfo);
752 sarOptions[i].optionString = const_cast<char *>(
753 options[i].optionString.getStr());
754 sarOptions[i].extraInfo = options[i].extraInfo;
757 #ifdef MACOSX
758 vm_args.version= JNI_VERSION_1_4; // issue 88987
759 #else
760 vm_args.version= JNI_VERSION_1_2;
761 #endif
762 vm_args.options= sarOptions.get();
763 vm_args.nOptions= options.size(); //TODO overflow
764 vm_args.ignoreUnrecognized= JNI_TRUE;
766 /* We set a global flag which is used by the abort handler in order to
767 determine whether it is should use longjmp to get back into this function.
768 That is, the abort handler determines if it is on the same stack as this function
769 and then jumps back into this function.
771 g_bInGetJavaVM = 1;
772 jint err;
773 JavaVM * pJavaVM = nullptr;
774 memset( jmp_jvm_abort, 0, sizeof(jmp_jvm_abort));
775 int jmpval= setjmp( jmp_jvm_abort );
776 /* If jmpval is not "0" then this point was reached by a longjmp in the
777 abort_handler, which was called indirectly by JNI_CreateVM.
779 if( jmpval == 0)
781 //returns negative number on failure
782 err= pCreateJavaVM(&pJavaVM, ppEnv, &vm_args);
783 g_bInGetJavaVM = 0;
785 else
786 // set err to a positive number, so as or recognize that an abort (longjmp)
787 //occurred
788 err= 1;
790 if(err != 0)
792 if( err < 0)
794 fprintf(stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
795 "Can not create Java Virtual Machine, %" SAL_PRIdINT32 "\n", sal_Int32(err));
796 errorcode = javaPluginError::VmCreationFailed;
798 else if( err > 0)
800 fprintf(stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
801 "Can not create JavaVirtualMachine, abort handler was called.\n");
802 errorcode = javaPluginError::VmCreationFailed;
805 else
807 *ppVm = pJavaVM;
808 JFW_TRACE2("JVM created");
810 #else
811 (void) arOptions;
812 (void) cOptions;
813 (void) ppEnv;
814 // On Android we always have a Java VM as we only expect this code
815 // to be run in an Android app anyway.
816 *ppVm = lo_get_javavm();
817 fprintf(stderr, "lo_get_javavm returns %p", *ppVm);
818 #endif
820 return errorcode;
821 #if defined __GNUC__ && __GNUC__ == 7 && !defined __clang__
822 #pragma GCC diagnostic push
823 #pragma GCC diagnostic ignored "-Wclobbered"
824 #endif
826 #if defined __GNUC__ && __GNUC__ == 7 && !defined __clang__
827 #pragma GCC diagnostic pop
828 #endif
830 javaPluginError jfw_plugin_existJRE(const JavaInfo *pInfo, bool *exist)
832 assert(pInfo != nullptr);
833 assert(exist != nullptr);
835 javaPluginError ret = javaPluginError::NONE;
836 OUString sLocation(pInfo->sLocation);
838 if (sLocation.isEmpty())
839 return javaPluginError::InvalidArg;
840 ::osl::DirectoryItem item;
841 ::osl::File::RC rc_item = ::osl::DirectoryItem::get(sLocation, item);
842 if (::osl::File::E_None == rc_item)
844 *exist = true;
846 else if (::osl::File::E_NOENT == rc_item)
848 *exist = false;
850 else
852 ret = javaPluginError::Error;
854 //We can have the situation that the JavaVM runtime library is not
855 //contained within JAVA_HOME. Then the check for JAVA_HOME would return
856 //true although the runtime library may not be loadable.
857 //Or the JAVA_HOME directory of a deinstalled JRE left behind.
858 if (ret == javaPluginError::NONE && *exist)
860 OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
861 JFW_TRACE2("Checking existence of Java runtime library");
863 ::osl::DirectoryItem itemRt;
864 ::osl::File::RC rc_itemRt = ::osl::DirectoryItem::get(sRuntimeLib, itemRt);
865 if (::osl::File::E_None == rc_itemRt)
867 *exist = true;
868 JFW_TRACE2("Java runtime library exist: " << sRuntimeLib);
871 else if (::osl::File::E_NOENT == rc_itemRt)
873 *exist = false;
874 JFW_TRACE2("Java runtime library does not exist: " << sRuntimeLib);
876 else
878 ret = javaPluginError::Error;
879 JFW_TRACE2("Error while looking for Java runtime library: " << sRuntimeLib);
882 return ret;
886 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */