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