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