update emoji autocorrect entries from po-files
[LibreOffice.git] / jvmfwk / plugins / sunmajor / pluginlib / sunjavaplugin.cxx
blob000797528daf32f48249927b0f00dcd5e6f7a632
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 WNT
22 # include <stdio.h>
23 # include <sys/stat.h>
24 # include <windows.h>
25 #endif
27 #ifdef ANDROID
28 # include <dlfcn.h>
29 #endif
31 #if OSL_DEBUG_LEVEL > 0
32 #include <stdio.h>
33 #endif
34 #include <string.h>
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"
48 #include <setjmp.h>
49 #include <signal.h>
50 #include <stack>
52 #include "jni.h"
53 #include "rtl/byteseq.hxx"
54 #include "vendorplugin.hxx"
55 #include "util.hxx"
56 #include "sunversion.hxx"
57 #include "vendorlist.hxx"
58 #include "diagnostics.h"
60 #ifdef ANDROID
61 #include <osl/detail/android-bootstrap.h>
62 #else
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
68 #else
69 #define FORCE_INTERPRETED 0
70 #endif
71 #endif
73 #if defined LINUX && (defined X86 || defined X86_64)
74 #include <sys/resource.h>
75 #endif
77 using namespace osl;
78 using namespace std;
79 using namespace jfw_plugin;
82 namespace {
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)
92 OString ret;
93 OUString sName1("javaplugin.jar");
94 OUString sName2("plugin.jar");
95 OUString sPath;
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);
103 OUString sName;
104 if (ver < ver142)
106 sName = sName1;
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
111 sName = sName2;
113 if (!sName.isEmpty())
115 sName = sLocation + "/lib/" + sName;
116 OSL_VERIFY(
117 osl_getSystemPathFromFileURL(sName.pData, & sPath.pData)
118 == osl_File_E_None);
121 else
123 char sep[] = {SAL_PATHSEPARATOR, 0};
124 OUString sName(sLocation + "/lib/" + sName1);
125 OUString sPath1;
126 OUString sPath2;
127 if (osl_getSystemPathFromFileURL(sName.pData, & sPath1.pData)
128 == osl_File_E_None)
130 sName = sLocation + "/lib/" + sName2;
131 if (osl_getSystemPathFromFileURL(sName.pData, & sPath2.pData)
132 == osl_File_E_None)
134 sPath = sPath1 + OUString::createFromAscii(sep) + sPath2;
137 OSL_ASSERT(!sPath.isEmpty());
139 ret = OUStringToOString(sPath, osl_getThreadTextEncoding());
141 return ret;
143 #endif // UNX
146 JavaInfo* createJavaInfo(const rtl::Reference<VendorBase> & info)
148 JavaInfo* pInfo = static_cast<JavaInfo*>(rtl_allocateMemory(sizeof(JavaInfo)));
149 if (pInfo == NULL)
150 return NULL;
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);
177 return pInfo;
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
186 sal_Int32 index = 0;
187 OUString aToken = sData.getToken( 0, '\n', index);
189 return aToken;
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.
210 @param aVendorInfo
211 [in] the object to be inspected whether it meets the version requirements
212 @param sMinVersion
213 [in] represents the minimum version of a JRE. The string can be empty.
214 @param sMaxVersion
215 [in] represents the maximum version of a JRE. The string can be empty.
216 @param arExcludeList
217 [in] contains a list of &quot;bad&quot; versions. JREs which have one of these
218 versions must not be returned by this function. It can be NULL.
219 @param nLenList
220 [in] the number of version strings contained in <code>arExcludeList</code>.
222 @return
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
228 version strings.
231 javaPluginError checkJavaVersionRequirements(
232 rtl::Reference<VendorBase> const & aVendorInfo,
233 OUString const& sMinVersion,
234 OUString const& sMaxVersion,
235 rtl_uString * * arExcludeList,
236 sal_Int32 nLenList)
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.
248 JFW_ENSURE(
249 false,
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.
267 JFW_ENSURE(
268 false,
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.
287 JFW_ENSURE(
288 false,
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,
307 sal_Int32 nLenList,
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;
329 //Find all JREs
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()))
340 continue;
342 javaPluginError err = checkJavaVersionRequirements(
343 cur, sMinVersion, sMaxVersion, arExcludeList, nLenList);
345 if (err == JFW_PLUGIN_E_FAILED_VERSION)
346 continue;
347 else if (err == JFW_PLUGIN_E_WRONG_VERSION_FORMAT)
348 return err;
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*)));
355 int j = 0;
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,
374 sal_Int32 nLenList,
375 JavaInfo ** ppInfo)
377 if (!ppInfo)
378 return JFW_PLUGIN_E_INVALID_ARG;
379 OSL_ASSERT(!sPath.isEmpty());
380 if (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);
406 return errorcode;
409 javaPluginError jfw_plugin_getJavaInfoFromJavaHome(
410 std::vector<pair<OUString, jfw::VersionInfo>> const& vecVendorInfos,
411 JavaInfo ** ppInfo, std::vector<rtl::Reference<VendorBase>> & infos)
413 if (!ppInfo)
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(
433 infoJavaHome[0],
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(
476 currentInfo,
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;
501 #if defined(WNT)
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];
511 wchar_t *slash;
513 if (wcslen(jvm_dll) > MAX_PATH - 15)
514 return;
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'\\');
523 if (!slash)
525 // Huh, weird path to jvm.dll. Oh well.
526 return;
529 wcscpy(slash+1, msvcr);
530 if (LoadLibraryW(msvcr_dll))
531 return;
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
535 // normal case.
536 *slash = 0;
537 slash = wcsrchr(msvcr_dll, L'\\');
539 if (!slash)
540 return;
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);
552 struct stat st;
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)
563 fclose(f);
564 return;
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)))
574 free(dos_hdr);
575 fclose(f);
576 return;
579 fclose(f);
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);
595 break;
597 ++sections;
599 if (-1 == VAtoPhys) // not found?
601 free(dos_hdr);
602 return;
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),
624 msvcrts[i].wname);
625 free(dos_hdr);
626 return;
629 imports++;
632 free(dos_hdr);
635 #endif
637 /** starts a Java Virtual Machine.
639 The function shall ensure, that the VM does not abort the process
640 during instantiation.
641 </p>
643 javaPluginError jfw_plugin_startJavaVirtualMachine(
644 const JavaInfo *pInfo,
645 const JavaVMOption* arOptions,
646 sal_Int32 cOptions,
647 JavaVM ** ppVm,
648 JNIEnv ** ppEnv)
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);
664 #ifndef ANDROID
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;
669 #if defined(LINUX)
670 if (!moduleRt.load(sRuntimeLib, SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_NOW))
671 #else
672 #if defined(WNT)
673 do_msvcr_magic(sRuntimeLib.pData);
674 #endif
675 if (!moduleRt.load(sRuntimeLib, SAL_LOADMODULE_DEFAULT))
676 #endif
678 JFW_ENSURE(false,
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);
691 #endif
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));
698 if (!pCreateJavaVM)
700 OSL_ASSERT(false);
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;
710 moduleRt.release();
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;
720 struct Option {
721 Option(OString const & theOptionString, void * theExtraInfo):
722 optionString(theOptionString), extraInfo(theExtraInfo)
725 OString optionString;
726 void * extraInfo;
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);
739 #ifdef UNX
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;
748 #endif
749 if (opt == "-Xint") {
750 addForceInterpreted = false;
752 if (opt.startsWith("-Xss")) {
753 hasStackSize = true;
755 options.push_back(Option(opt, arOptions[i].extraInfo));
757 if (addForceInterpreted) {
758 options.push_back(Option("-Xint", nullptr));
760 if (!hasStackSize) {
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)
766 // call to
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:
774 rlimit l;
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) {
780 SAL_INFO(
781 "jfw", "huge RLIMIT_STACK " << l.rlim_cur << " -> 8192K");
782 l.rlim_cur = 8192 * 1024;
784 options.push_back(
785 Option("-Xss" + OString::number(l.rlim_cur), nullptr));
786 } else {
787 int e = errno;
788 SAL_WARN("jfw", "getrlimit(RLIMIT_STACK) failed with errno " << e);
790 #endif
793 boost::scoped_array<JavaVMOption> sarOptions(new JavaVMOption[options.size()]);
794 for (std::vector<Option>::size_type i = 0; i != options.size(); ++i) {
795 SAL_INFO(
796 "jfw",
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;
804 #ifdef MACOSX
805 vm_args.version= JNI_VERSION_1_4; // issue 88987
806 #else
807 vm_args.version= JNI_VERSION_1_2;
808 #endif
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.
818 g_bInGetJavaVM = 1;
819 jint err;
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.
826 if( jmpval == 0)
828 //returns negative number on failure
829 err= pCreateJavaVM(&pJavaVM, ppEnv, &vm_args);
830 g_bInGetJavaVM = 0;
832 else
833 // set err to a positive number, so as or recognize that an abort (longjmp)
834 //occurred
835 err= 1;
837 if(err != 0)
839 if( err < 0)
841 fprintf(stderr,"[Java framework] sunjavaplugin" SAL_DLLEXTENSION
842 "Can not create Java Virtual Machine\n");
843 errorcode = JFW_PLUGIN_E_VM_CREATION_FAILED;
845 else if( err > 0)
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;
852 else
854 *ppVm = pJavaVM;
855 JFW_TRACE2("JVM created");
857 #else
858 (void) arOptions;
859 (void) cOptions;
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);
864 #endif
866 return errorcode;
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)
882 *exist = sal_True;
884 else if (::osl::File::E_NOENT == rc_item)
886 *exist = sal_False;
888 else
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)
905 *exist = sal_True;
906 JFW_TRACE2("Java runtime library exist: " << sRuntimeLib);
909 else if (::osl::File::E_NOENT == rc_itemRt)
911 *exist = sal_False;
912 JFW_TRACE2("Java runtime library does not exist: " << sRuntimeLib);
914 else
916 ret = JFW_PLUGIN_E_ERROR;
917 JFW_TRACE2("Error while looking for Java runtime library: " << sRuntimeLib);
920 return ret;
924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */