1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sunjavaplugin.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_jvmfwk.hxx"
33 #if OSL_DEBUG_LEVEL > 0
38 #include "boost/scoped_array.hpp"
39 #include "osl/diagnose.h"
40 #include "rtl/ustring.hxx"
41 #include "rtl/ustrbuf.hxx"
42 #include "osl/module.hxx"
43 #include "osl/mutex.hxx"
44 #include "osl/thread.hxx"
45 #include "osl/file.hxx"
46 #include "rtl/instance.hxx"
47 #include "osl/getglobalmutex.hxx"
53 #include "rtl/byteseq.hxx"
54 #include "jvmfwk/vendorplugin.h"
56 #include "sunversion.hxx"
57 #include "vendorlist.hxx"
58 #include "diagnostics.h"
60 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
61 #define SUN_MICRO "Sun Microsystems Inc."
66 using namespace jfw_plugin
;
70 struct PluginMutex
: public ::rtl::Static
<osl::Mutex
, PluginMutex
> {};
73 OString
getPluginJarPath(
74 const OUString
& sVendor
,
75 const OUString
& sLocation
,
76 const OUString
& sVersion
)
79 OUString
sName1(RTL_CONSTASCII_USTRINGPARAM("javaplugin.jar"));
80 OUString
sName2(RTL_CONSTASCII_USTRINGPARAM("plugin.jar"));
82 if (sVendor
.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SUN_MICRO
))))
84 SunVersion
ver142("1.4.2-ea");
85 SunVersion
ver150("1.5.0-ea");
86 SunVersion
ver(sVersion
);
87 OSL_ASSERT(ver142
&& ver150
&& ver
);
94 else if (ver
< ver150
)
95 {//this will cause ea, beta etc. to have plugin.jar in path.
96 //but this does not harm. 1.5.0-beta < 1.5.0
99 if (sName
.getLength())
101 sName
= sLocation
+ OUSTR("/lib/") + sName
;
103 osl_getSystemPathFromFileURL(sName
.pData
, & sPath
.pData
)
109 char sep
[] = {SAL_PATHSEPARATOR
, 0};
110 OUString
sName(sLocation
+ OUSTR("/lib/") + sName1
);
113 if (osl_getSystemPathFromFileURL(sName
.pData
, & sPath1
.pData
)
116 sName
= sLocation
+ OUSTR("/lib/") + sName2
;
117 if (osl_getSystemPathFromFileURL(sName
.pData
, & sPath2
.pData
)
120 sPath
= sPath1
+ OUString::createFromAscii(sep
) + sPath2
;
123 OSL_ASSERT(sPath
.getLength());
125 ret
= rtl::OUStringToOString(sPath
, osl_getThreadTextEncoding());
132 JavaInfo
* createJavaInfo(const rtl::Reference
<VendorBase
> & info
)
134 JavaInfo
* pInfo
= (JavaInfo
*) rtl_allocateMemory(sizeof(JavaInfo
));
137 rtl::OUString sVendor
= info
->getVendor();
138 pInfo
->sVendor
= sVendor
.pData
;
139 rtl_uString_acquire(sVendor
.pData
);
140 rtl::OUString sHome
= info
->getHome();
141 pInfo
->sLocation
= sHome
.pData
;
142 rtl_uString_acquire(pInfo
->sLocation
);
143 rtl::OUString sVersion
= info
->getVersion();
144 pInfo
->sVersion
= sVersion
.pData
;
145 rtl_uString_acquire(pInfo
->sVersion
);
146 pInfo
->nFeatures
= info
->supportsAccessibility() ? 1 : 0;
147 pInfo
->nRequirements
= info
->needsRestart() ? JFW_REQUIRE_NEEDRESTART
: 0;
148 rtl::OUStringBuffer
buf(1024);
149 buf
.append(info
->getRuntimeLibrary());
150 if (info
->getLibraryPaths().getLength() > 0)
152 buf
.appendAscii("\n");
153 buf
.append(info
->getLibraryPaths());
154 buf
.appendAscii("\n");
157 rtl::OUString sVendorData
= buf
.makeStringAndClear();
158 rtl::ByteSequence
byteSeq( (sal_Int8
*) sVendorData
.pData
->buffer
,
159 sVendorData
.getLength() * sizeof(sal_Unicode
));
160 pInfo
->arVendorData
= byteSeq
.get();
161 rtl_byte_sequence_acquire(pInfo
->arVendorData
);
166 rtl::OUString
getRuntimeLib(const rtl::ByteSequence
& data
)
168 const sal_Unicode
* chars
= (sal_Unicode
*) data
.getConstArray();
169 sal_Int32 len
= data
.getLength();
170 rtl::OUString
sData(chars
, len
/ 2);
171 //the runtime lib is on the first line
173 rtl::OUString aToken
= sData
.getToken( 0, '\n', index
);
178 jmp_buf jmp_jvm_abort
;
179 sig_atomic_t g_bInGetJavaVM
= 0;
183 // If we are within JNI_CreateJavaVM then we jump back into getJavaVM
184 if( g_bInGetJavaVM
!= 0 )
186 fprintf( stderr
, "JavaVM: JNI_CreateJavaVM called _exit, caught by abort_handler in javavm.cxx\n");
187 longjmp( jmp_jvm_abort
, 0);
194 javaPluginError
jfw_plugin_getAllJavaInfos(
195 rtl_uString
*sVendor
,
196 rtl_uString
*sMinVersion
,
197 rtl_uString
*sMaxVersion
,
198 rtl_uString
* *arExcludeList
,
200 JavaInfo
*** parJavaInfo
,
201 sal_Int32
*nLenInfoList
)
204 OSL_ASSERT(sMinVersion
);
205 OSL_ASSERT(sMaxVersion
);
206 OSL_ASSERT(parJavaInfo
);
207 OSL_ASSERT(parJavaInfo
);
208 OSL_ASSERT(nLenInfoList
);
209 if (!sVendor
|| !sMinVersion
|| !sMaxVersion
|| !parJavaInfo
|| !nLenInfoList
)
210 return JFW_PLUGIN_E_INVALID_ARG
;
212 //nLenlist contains the number of element in arExcludeList.
213 //If no exclude list is provided then nLenList must be 0
214 OSL_ASSERT( ! (arExcludeList
== NULL
&& nLenList
> 0));
215 if (arExcludeList
== NULL
&& nLenList
> 0)
216 return JFW_PLUGIN_E_INVALID_ARG
;
218 OUString
ouVendor(sVendor
);
219 OUString
ouMinVer(sMinVersion
);
220 OUString
ouMaxVer(sMaxVersion
);
222 OSL_ASSERT(ouVendor
.getLength() > 0);
223 if (ouVendor
.getLength() == 0)
224 return JFW_PLUGIN_E_INVALID_ARG
;
226 JavaInfo
** arInfo
= NULL
;
229 vector
<rtl::Reference
<VendorBase
> > vecInfos
=
231 vector
<rtl::Reference
<VendorBase
> > vecVerifiedInfos
;
233 typedef vector
<rtl::Reference
<VendorBase
> >::iterator it
;
234 for (it i
= vecInfos
.begin(); i
!= vecInfos
.end(); i
++)
236 const rtl::Reference
<VendorBase
>& cur
= *i
;
238 if (ouVendor
.equals(cur
->getVendor()) == sal_False
)
241 if (ouMinVer
.getLength() > 0)
245 if (cur
->compareVersions(sMinVersion
) == -1)
248 catch (MalformedVersionException
&)
250 //The minVersion was not recognized as valid for this vendor.
252 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
253 + ouMinVer
+ OUSTR(" for vendor: ") + cur
->getVendor()
254 + OUSTR(" .Check minimum Version.") );
255 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
259 if (ouMaxVer
.getLength() > 0)
263 if (cur
->compareVersions(sMaxVersion
) == 1)
266 catch (MalformedVersionException
&)
268 //The maxVersion was not recognized as valid for this vendor.
270 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
271 + ouMaxVer
+ OUSTR(" for vendor: ") + cur
->getVendor()
272 + OUSTR(" .Check maximum Version.") );
273 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
277 if (arExcludeList
> 0)
279 bool bExclude
= false;
280 for (int j
= 0; j
< nLenList
; j
++)
282 rtl::OUString
sExVer(arExcludeList
[j
]);
285 if (cur
->compareVersions(sExVer
) == 0)
291 catch (MalformedVersionException
&)
293 //The excluded version was not recognized as valid for this vendor.
295 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
296 + sExVer
+ OUSTR(" for vendor: ") + cur
->getVendor()
297 + OUSTR(" .Check excluded versions.") );
298 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
301 if (bExclude
== true)
304 vecVerifiedInfos
.push_back(*i
);
306 //Now vecVerifiedInfos contains all those JREs which meet the version requirements
307 //Transfer them into the array that is passed out.
308 arInfo
= (JavaInfo
**) rtl_allocateMemory(vecVerifiedInfos
.size() * sizeof (JavaInfo
*));
310 typedef vector
<rtl::Reference
<VendorBase
> >::const_iterator cit
;
311 for (cit ii
= vecVerifiedInfos
.begin(); ii
!= vecVerifiedInfos
.end(); ii
++, j
++)
313 arInfo
[j
] = createJavaInfo(*ii
);
315 *nLenInfoList
= vecVerifiedInfos
.size();
318 *parJavaInfo
= arInfo
;
319 return JFW_PLUGIN_E_NONE
;
323 javaPluginError
jfw_plugin_getJavaInfoByPath(
325 rtl_uString
*sVendor
,
326 rtl_uString
*sMinVersion
,
327 rtl_uString
*sMaxVersion
,
328 rtl_uString
* *arExcludeList
,
332 javaPluginError errcode
= JFW_PLUGIN_E_NONE
;
336 OSL_ASSERT(sMinVersion
);
337 OSL_ASSERT(sMaxVersion
);
338 if (!path
|| !sVendor
|| !sMinVersion
|| !sMaxVersion
|| !ppInfo
)
339 return JFW_PLUGIN_E_INVALID_ARG
;
340 OUString
ouPath(path
);
341 OSL_ASSERT(ouPath
.getLength() > 0);
342 if (ouPath
.getLength() == 0)
343 return JFW_PLUGIN_E_INVALID_ARG
;
345 //nLenlist contains the number of element in arExcludeList.
346 //If no exclude list is provided then nLenList must be 0
347 OSL_ASSERT( ! (arExcludeList
== NULL
&& nLenList
> 0));
348 if (arExcludeList
== NULL
&& nLenList
> 0)
349 return JFW_PLUGIN_E_INVALID_ARG
;
351 OUString
ouVendor(sVendor
);
352 OUString
ouMinVer(sMinVersion
);
353 OUString
ouMaxVer(sMaxVersion
);
355 OSL_ASSERT(ouVendor
.getLength() > 0);
356 if (ouVendor
.getLength() == 0)
357 return JFW_PLUGIN_E_INVALID_ARG
;
359 rtl::Reference
<VendorBase
> aVendorInfo
= getJREInfoByPath(ouPath
);
360 if (aVendorInfo
.is() == sal_False
)
361 return JFW_PLUGIN_E_NO_JRE
;
363 //Check if the detected JRE matches the version requirements
364 if (ouVendor
.equals(aVendorInfo
->getVendor()) == sal_False
)
365 return JFW_PLUGIN_E_NO_JRE
;
367 if (ouMinVer
.getLength() > 0)
372 nRes
= aVendorInfo
->compareVersions(ouMinVer
);
374 catch (MalformedVersionException
&)
376 //The minVersion was not recognized as valid for this vendor.
378 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
379 + ouMinVer
+ OUSTR(" for vendor: ") + aVendorInfo
->getVendor()
380 + OUSTR(" .Check minimum Version.") );
381 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
384 return JFW_PLUGIN_E_FAILED_VERSION
;
387 if (ouMaxVer
.getLength() > 0)
392 nRes
= aVendorInfo
->compareVersions(ouMaxVer
);
394 catch (MalformedVersionException
&)
396 //The maxVersion was not recognized as valid for this vendor.
398 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
399 + ouMaxVer
+ OUSTR(" for vendor: ") + aVendorInfo
->getVendor()
400 + OUSTR(" .Check maximum Version.") );
401 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
404 return JFW_PLUGIN_E_FAILED_VERSION
;
407 if (arExcludeList
> 0)
409 for (int i
= 0; i
< nLenList
; i
++)
411 rtl::OUString
sExVer(arExcludeList
[i
]);
415 nRes
= aVendorInfo
->compareVersions(sExVer
);
417 catch (MalformedVersionException
&)
419 //The excluded version was not recognized as valid for this vendor.
421 0,OUSTR("[Java framework]sunjavaplugin does not know version: ")
422 + sExVer
+ OUSTR(" for vendor: ") + aVendorInfo
->getVendor()
423 + OUSTR(" .Check excluded versions.") );
424 return JFW_PLUGIN_E_WRONG_VERSION_FORMAT
;
427 return JFW_PLUGIN_E_FAILED_VERSION
;
430 *ppInfo
= createJavaInfo(aVendorInfo
);
435 /** starts a Java Virtual Machine.
437 The function shall ensure, that the VM does not abort the process
438 during instantiation.
442 javaPluginError
jfw_plugin_startJavaVirtualMachine(
443 const JavaInfo
*pInfo
,
444 const JavaVMOption
* arOptions
,
449 // unless guard is volatile the following warning occurs on gcc:
450 // warning: variable 't' might be clobbered by `longjmp' or `vfork'
451 volatile osl::MutexGuard
guard(PluginMutex::get());
452 // unless errcode is volatile the following warning occurs on gcc:
453 // warning: variable 'errcode' might be clobbered by `longjmp' or `vfork'
454 volatile javaPluginError errcode
= JFW_PLUGIN_E_NONE
;
455 if ( pInfo
== NULL
|| ppVm
== NULL
|| ppEnv
== NULL
)
456 return JFW_PLUGIN_E_INVALID_ARG
;
457 //Check if the Vendor (pInfo->sVendor) is supported by this plugin
458 if ( ! isVendorSupported(pInfo
->sVendor
))
459 return JFW_PLUGIN_E_WRONG_VENDOR
;
460 rtl::OUString sRuntimeLib
= getRuntimeLib(pInfo
->arVendorData
);
461 JFW_TRACE2(OUSTR("[Java framework] Using Java runtime library: ")
462 + sRuntimeLib
+ OUSTR(".\n"));
463 // On linux we load jvm with RTLD_GLOBAL. This is necessary for debugging, because
464 // libjdwp.so need a symbol (fork1) from libjvm which it only gets if the jvm is loaded
465 // witd RTLD_GLOBAL. On Solaris libjdwp.so is correctly linked with libjvm.so
466 oslModule moduleRt
= 0;
468 if ((moduleRt
= osl_loadModule(sRuntimeLib
.pData
,
469 SAL_LOADMODULE_GLOBAL
| SAL_LOADMODULE_NOW
)) == 0 )
471 if ((moduleRt
= osl_loadModule(sRuntimeLib
.pData
, SAL_LOADMODULE_DEFAULT
)) == 0)
474 JFW_ENSURE(0, OUSTR("[Java framework]sunjavaplugin" SAL_DLLEXTENSION
475 " could not load Java runtime library: \n")
476 + sRuntimeLib
+ OUSTR("."));
477 JFW_TRACE0(OUSTR("[Java framework]sunjavaplugin" SAL_DLLEXTENSION
478 " could not load Java runtime library: \n")
479 + sRuntimeLib
+ OUSTR("."));
480 return JFW_PLUGIN_E_VM_CREATION_FAILED
;
484 //Setting the JAVA_HOME is needed for awt
485 rtl::OUString
javaHome(RTL_CONSTASCII_USTRINGPARAM("JAVA_HOME="));
486 rtl::OUString sPathLocation
;
487 osl_getSystemPathFromFileURL(pInfo
->sLocation
, & sPathLocation
.pData
);
488 javaHome
+= sPathLocation
;
489 rtl::OString osJavaHome
= rtl::OUStringToOString(
490 javaHome
, osl_getThreadTextEncoding());
491 putenv(strdup(osJavaHome
.getStr()));
494 typedef jint JNICALL
JNI_InitArgs_Type(void *);
495 typedef jint JNICALL
JNI_CreateVM_Type(JavaVM
**, JNIEnv
**, void *);
496 rtl::OUString
sSymbolCreateJava(
497 RTL_CONSTASCII_USTRINGPARAM("JNI_CreateJavaVM"));
499 JNI_CreateVM_Type
* pCreateJavaVM
= (JNI_CreateVM_Type
*) osl_getFunctionSymbol(
500 moduleRt
, sSymbolCreateJava
.pData
);
504 rtl::OString sLib
= rtl::OUStringToOString(
505 sRuntimeLib
, osl_getThreadTextEncoding());
506 rtl::OString sSymbol
= rtl::OUStringToOString(
507 sSymbolCreateJava
, osl_getThreadTextEncoding());
508 fprintf(stderr
,"[Java framework]sunjavaplugin"SAL_DLLEXTENSION
509 "Java runtime library: %s does not export symbol %s !\n",
510 sLib
.getStr(), sSymbol
.getStr());
511 return JFW_PLUGIN_E_VM_CREATION_FAILED
;
514 // The office sets a signal handler at startup. That causes a crash
515 // with java 1.3 under Solaris. To make it work, we set back the
518 struct sigaction act
;
519 act
.sa_handler
=SIG_DFL
;
521 sigaction( SIGSEGV
, &act
, NULL
);
522 sigaction( SIGPIPE
, &act
, NULL
);
523 sigaction( SIGBUS
, &act
, NULL
);
524 sigaction( SIGILL
, &act
, NULL
);
525 sigaction( SIGFPE
, &act
, NULL
);
528 // Some testing with Java 1.4 showed that JavaVMOption.optionString has to
529 // be encoded with the system encoding (i.e., osl_getThreadTextEncoding):
530 JavaVMInitArgs vm_args
;
532 boost::scoped_array
<JavaVMOption
> sarOptions(
533 new JavaVMOption
[cOptions
+ 1]);
534 JavaVMOption
* options
= sarOptions
.get();
536 // We set an abort handler which is called when the VM calls _exit during
537 // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
538 // all some directories of the Java installation. This is necessary for
539 // all versions below 1.5.1
540 options
[0].optionString
= (char *) "abort";
541 options
[0].extraInfo
= (void* )(sal_IntPtr
)abort_handler
;
542 rtl::OString
sClassPathProp("-Djava.class.path=");
543 rtl::OString sClassPathOption
;
544 for (int i
= 0; i
< cOptions
; i
++)
547 // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
548 // in the class path in order to have applet support.
549 rtl::OString sClassPath
= arOptions
[i
].optionString
;
550 if (sClassPath
.match(sClassPathProp
, 0) == sal_True
)
552 char sep
[] = {SAL_PATHSEPARATOR
, 0};
553 OString sAddPath
= getPluginJarPath(pInfo
->sVendor
, pInfo
->sLocation
,pInfo
->sVersion
);
554 if (sAddPath
.getLength())
555 sClassPathOption
= sClassPath
+ rtl::OString(sep
) + sAddPath
;
557 sClassPathOption
= sClassPath
;
558 options
[i
+1].optionString
= (char *) sClassPathOption
.getStr();
559 options
[i
+1].extraInfo
= arOptions
[i
].extraInfo
;
564 options
[i
+1].optionString
= arOptions
[i
].optionString
;
565 options
[i
+1].extraInfo
= arOptions
[i
].extraInfo
;
569 #if OSL_DEBUG_LEVEL >= 2
570 JFW_TRACE2(OString("VM option: ") + OString(options
[i
+1].optionString
) +
576 vm_args
.version
= JNI_VERSION_1_4
; // issue 88987
578 vm_args
.version
= JNI_VERSION_1_2
;
580 vm_args
.options
= options
;
581 vm_args
.nOptions
= cOptions
+ 1;
582 vm_args
.ignoreUnrecognized
= JNI_TRUE
;
584 /* We set a global flag which is used by the abort handler in order to
585 determine whether it is should use longjmp to get back into this function.
586 That is, the abort handler determines if it is on the same stack as this function
587 and then jumps back into this function.
591 JavaVM
* pJavaVM
= 0;
592 memset( jmp_jvm_abort
, 0, sizeof(jmp_jvm_abort
));
593 int jmpval
= setjmp( jmp_jvm_abort
);
594 /* If jmpval is not "0" then this point was reached by a longjmp in the
595 abort_handler, which was called indirectly by JNI_CreateVM.
599 //returns negative number on failure
600 err
= pCreateJavaVM(&pJavaVM
, ppEnv
, &vm_args
);
604 // set err to a positive number, so as or recognize that an abort (longjmp)
610 rtl::OUString message
;
613 fprintf(stderr
,"[Java framework] sunjavaplugin"SAL_DLLEXTENSION
614 "Can not create Java Virtual Machine\n");
615 errcode
= JFW_PLUGIN_E_VM_CREATION_FAILED
;
619 fprintf(stderr
,"[Java framework] sunjavaplugin"SAL_DLLEXTENSION
620 "Can not create JavaVirtualMachine, abort handler was called.\n");
621 errcode
= JFW_PLUGIN_E_VM_CREATION_FAILED
;
627 JFW_TRACE2("[Java framework] sunjavaplugin"SAL_DLLEXTENSION
" has created a VM.\n");