Mercurial > hg > release > icedtea6-1.8
changeset 1140:eb4fbb8e17d9
- Implemented jvm respawn, in case the jvm exits for whatever reason
- Fix http://www.goes.noaa.gov/HURRLOOPS/huirloop.html
- Fix panel size on initialization -- it is now correct
author | Deepak Bhole <dbhole@redhat.com> |
---|---|
date | Tue, 21 Oct 2008 16:17:19 -0400 |
parents | 5fabd5969958 |
children | 560a859a217b |
files | ChangeLog IcedTeaPlugin.cc plugin/icedtea/sun/applet/PluginAppletSecurityContext.java plugin/icedtea/sun/applet/PluginAppletViewer.java plugin/icedtea/sun/applet/PluginMain.java |
diffstat | 5 files changed, 303 insertions(+), 49 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Tue Oct 21 16:45:19 2008 +0200 +++ b/ChangeLog Tue Oct 21 16:17:19 2008 -0400 @@ -1,3 +1,13 @@ +2008-10-21 Deepak Bhole <dbhole@redhat.com> + + * IcedTeaPlugin.cc: Implemented JVM respawning. + * plugin/icedtea/sun/applet/PluginAppletSecurityContext.java: Prepopulate + classes requested by LiveConnect at initialization. + * plugin/icedtea/sun/applet/PluginAppletViewer.java: Fix panel applet + resizing when window height and width is in %. + * plugin/icedtea/sun/applet/PluginMain.java: Handle error during NetX + initialization gracefully. + 2008-10-21 Matthias Klose <doko@ubuntu.com> * configure.ac: Add new option --with-pkgversion,
--- a/IcedTeaPlugin.cc Tue Oct 21 16:45:19 2008 +0200 +++ b/IcedTeaPlugin.cc Tue Oct 21 16:17:19 2008 -0400 @@ -319,6 +319,8 @@ static PRBool factory_created = PR_FALSE; static IcedTeaPluginFactory* factory = NULL; +static PRBool jvm_attached = PR_FALSE; + // Applet viewer input channel (needs to be static because it is used in plugin_in_pipe_callback) GIOChannel* in_from_appletviewer = NULL; @@ -492,30 +494,24 @@ // shutdown (so that the permanent loop does not block // proper exit). We need better error handling -#define PROCESS_PENDING_EVENTS_REF2(reference) \ - ResultContainer *resultC; \ - factory->result_map.Get(reference, &resultC); \ - if (factory->shutting_down == PR_TRUE && \ - resultC->errorOccurred == PR_TRUE) \ - { \ - PLUGIN_DEBUG_0ARG("Error occured. Exiting function\n"); \ +#define PROCESS_PENDING_EVENTS_REF(reference) \ + if (jvm_attached == PR_FALSE) \ + { \ + fprintf(stderr, "Error on Java side detected. Abandoning wait and returning.\n"); \ return NS_ERROR_FAILURE; \ } \ - PRBool hasPending; \ - factory->current->HasPendingEvents(&hasPending); \ - if (hasPending == PR_TRUE) { \ - PRBool processed = PR_FALSE; \ - factory->current->ProcessNextEvent(PR_TRUE, &processed); \ - } else if (g_main_context_pending (NULL)) { \ - g_main_context_iteration(NULL, false); \ - } else { \ - PR_Sleep(PR_INTERVAL_NO_WAIT); \ - } - - -#define PROCESS_PENDING_EVENTS_REF(reference) \ if (g_main_context_pending (NULL)) { \ g_main_context_iteration(NULL, false); \ + } \ + PRBool hasPending; \ + factory->current->HasPendingEvents(&hasPending); \ + if (hasPending == PR_TRUE) \ + { \ + PRBool processed = PR_FALSE; \ + factory->current->ProcessNextEvent(PR_TRUE, &processed); \ + } else \ + {\ + PR_Sleep(PR_INTERVAL_NO_WAIT); \ } #define PROCESS_PENDING_EVENTS \ @@ -524,7 +520,11 @@ if (hasPending == PR_TRUE) { \ PRBool processed = PR_FALSE; \ factory->current->ProcessNextEvent(PR_TRUE, &processed); \ - } else { \ + } \ + if (g_main_context_pending (NULL)) { \ + g_main_context_iteration(NULL, false); \ + } else \ + { \ PR_Sleep(PR_INTERVAL_NO_WAIT); \ } @@ -945,6 +945,7 @@ nsISecureEnv* secureEnv; nsDataHashtable<nsUint32HashKey,ResultContainer*> result_map; + void InitializeJava(); void GetMember (); void SetMember (); void GetSlot (); @@ -954,6 +955,7 @@ void Call (); void Finalize (); void ToString (); + void MarkInstancesVoid (); nsCOMPtr<nsILiveconnect> liveconnect; // normally, we shouldn't have to track unref'd handles, but in some cases, @@ -970,21 +972,21 @@ nsresult StartAppletviewer (); void ProcessMessage(); void ConsumeMsgFromJVM(); - void InitializeJava(); nsCOMPtr<IcedTeaEventSink> sink; nsCOMPtr<nsISocketTransport> transport; nsCOMPtr<nsIProcess> applet_viewer_process; PRBool connected; PRUint32 next_instance_identifier; - // Does not do construction/deconstruction or reference counting. - nsDataHashtable<nsUint32HashKey, IcedTeaPluginInstance*> instances; PRUint32 object_identifier_return; + PRUint32 instance_count; int javascript_identifier; int name_identifier; int args_identifier; int string_identifier; int slot_index; int value_identifier; + // Does not do construction/deconstruction or reference counting. + nsDataHashtable<nsUint32HashKey, IcedTeaPluginInstance*> instances; // Applet viewer input pipe name. gchar* in_pipe_name; @@ -1015,6 +1017,7 @@ nsIPluginInstancePeer* peer; PRBool initialized; + PRBool fatalErrorOccurred; private: @@ -1449,6 +1452,7 @@ value_identifier (0), connected (PR_FALSE), liveconnect (0), + instance_count(0), shutting_down(PR_FALSE), in_pipe_name(NULL), in_watch_source(NULL), @@ -1533,6 +1537,7 @@ if (!instance) return NS_ERROR_OUT_OF_MEMORY; + instance_count++; return instance->QueryInterface (iid, result); } @@ -1576,7 +1581,16 @@ result = threadManager->GetCurrentThread (getter_AddRefs (current)); PLUGIN_CHECK_RETURN ("current thread", result); - InitializeJava(); + if (jvm_attached == PR_FALSE) + { + // using printf on purpose.. this should happen rarely + printf("Initializing JVM...\n"); + + // mark attached right away, in case another initialize() call + //is made (happens if multiple applets are present on the same page) + jvm_attached = PR_TRUE; + InitializeJava(); + } return NS_OK; } @@ -1610,7 +1624,26 @@ result = StartAppletviewer (); PLUGIN_CHECK ("started appletviewer", result); - +} + +void +IcedTeaPluginFactory::MarkInstancesVoid () +{ + PLUGIN_TRACE_FACTORY (); + + IcedTeaPluginInstance* instance = NULL; + + int instance_id = 1; + + while (instance_id <= instance_count) + { + if (instances.Get(instance_id, &instance)) + { + PLUGIN_DEBUG_2ARG("Marking %d of %d void\n", instance_id, instance_count); + instance->fatalErrorOccurred = PR_TRUE; + } + instance_id++; + } } NS_IMETHODIMP @@ -2218,11 +2251,25 @@ NS_IMPL_ISUPPORTS2 (IcedTeaPluginInstance, nsIPluginInstance, nsIJVMPluginInstance) + NS_IMETHODIMP IcedTeaPluginInstance::Initialize (nsIPluginInstancePeer* aPeer) { PLUGIN_TRACE_INSTANCE (); + // Ensure that there is a jvm running... + + if (jvm_attached == PR_FALSE) + { + // using printf on purpose.. this should happen rarely + fprintf(stderr, "WARNING: Looks like the JVM is not up. Attempting to re-initialize...\n"); + + // mark attached right away, in case another initialize() call + //is made (happens if multiple applets are present on the same page) + jvm_attached = PR_TRUE; + factory->InitializeJava(); + } + // Send applet tag message to appletviewer. // FIXME: nsCOMPtr char const* documentbase; @@ -2254,8 +2301,8 @@ tagMessage += appletTag; tagMessage += "</embed>"; - // remove \n characters from the message - tagMessage.StripChars("\n"); + // remove newline characters from the message + tagMessage.StripChars("\r\n"); factory->SendMessageToAppletViewer (tagMessage); @@ -2307,6 +2354,11 @@ { PLUGIN_TRACE_INSTANCE (); + if (fatalErrorOccurred == PR_TRUE) + { + return NS_OK; + } + nsCString destroyMessage (instanceIdentifierPrefix); destroyMessage += "destroy"; factory->SendMessageToAppletViewer (destroyMessage); @@ -2335,10 +2387,17 @@ PLUGIN_DEBUG_1ARG ("IcedTeaPluginInstance::SetWindow: Instance %p waiting for initialization...\n", this); - while (initialized == PR_FALSE) { + while (initialized == PR_FALSE && this->fatalErrorOccurred == PR_FALSE) { PROCESS_PENDING_EVENTS; } + // did we bail because there is no jvm? + if (this->fatalErrorOccurred == PR_TRUE) + { + PLUGIN_DEBUG_0ARG("Initialization failed. SetWindow returning\n"); + return NS_ERROR_FAILURE; + } + PLUGIN_DEBUG_1ARG ("Instance %p initialization complete...\n", this); } @@ -2584,6 +2643,9 @@ { PLUGIN_DEBUG ("appletviewer has stopped."); keep_installed = FALSE; + jvm_attached = PR_FALSE; + + factory->MarkInstancesVoid(); } else { @@ -2667,10 +2729,7 @@ return NS_OK; } -#include <nsIWebNavigation.h> #include <nsServiceManagerUtils.h> -#include <nsIExternalProtocolService.h> -#include <nsNetUtil.h> void IcedTeaPluginFactory::HandleMessage (nsCString const& message) @@ -2725,7 +2784,6 @@ if (instance != 0) { instance->peer->ShowStatus (nsCString (rest).get ()); - } } else if (command == "initialized") @@ -2738,6 +2796,16 @@ PLUGIN_DEBUG_1ARG ("to %d...\n", instance->initialized); } } + else if (command == "fatalError") + { + IcedTeaPluginInstance* instance = NULL; + instances.Get (identifier, &instance); + if (instance != 0) { + PLUGIN_DEBUG_2ARG ("Setting instance.fatalErrorOccurred for %p from %d ", instance, instance->fatalErrorOccurred); + instance->fatalErrorOccurred = PR_TRUE; + PLUGIN_DEBUG_1ARG ("to %d...\n", instance->fatalErrorOccurred); + } + } else if (command == "url") { IcedTeaPluginInstance* instance = NULL; @@ -3727,6 +3795,7 @@ peer(0), liveconnect_window (0), initialized(PR_FALSE), + fatalErrorOccurred(PR_FALSE), instanceIdentifierPrefix ("") { PLUGIN_TRACE_INSTANCE (); @@ -4272,7 +4341,6 @@ #include <nsNetCID.h> #include <nsServiceManagerUtils.h> #include <iostream> -#include <jvmmgr.h> #include <nsIPrincipal.h> #include <nsIScriptSecurityManager.h> #include <nsIURI.h> @@ -5444,6 +5512,8 @@ char const* aClassName, char const* aContractID, nsIFactory** aFactory) { + PLUGIN_DEBUG_0ARG("NSGetFactory called\n"); + static NS_DEFINE_CID (PluginCID, NS_PLUGIN_CID); if (!aClass.Equals (PluginCID)) return NS_ERROR_FACTORY_NOT_LOADED;
--- a/plugin/icedtea/sun/applet/PluginAppletSecurityContext.java Tue Oct 21 16:45:19 2008 +0200 +++ b/plugin/icedtea/sun/applet/PluginAppletSecurityContext.java Tue Oct 21 16:17:19 2008 -0400 @@ -1010,6 +1010,135 @@ + " " + message); } + public void prePopulateLCClasses() { + + int classID; + + prepopulateClass("netscape/javascript/JSObject"); + classID = prepopulateClass("netscape/javascript/JSException"); + prepopulateMethod(classID, "<init>", "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)V"); + prepopulateMethod(classID, "<init>", "(ILjava/lang/Object;)V"); + prepopulateField(classID, "lineno"); + prepopulateField(classID, "tokenIndex"); + prepopulateField(classID, "source"); + prepopulateField(classID, "filename"); + prepopulateField(classID, "wrappedExceptionType"); + prepopulateField(classID, "wrappedException"); + + classID = prepopulateClass("netscape/javascript/JSUtil"); + prepopulateMethod(classID, "getStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;"); + + prepopulateClass("java/lang/Object"); + classID = prepopulateClass("java/lang/Class"); + prepopulateMethod(classID, "getMethods", "()[Ljava/lang/reflect/Method;"); + prepopulateMethod(classID, "getConstructors", "()[Ljava/lang/reflect/Constructor;"); + prepopulateMethod(classID, "getFields", "()[Ljava/lang/reflect/Field;"); + prepopulateMethod(classID, "getName", "()Ljava/lang/String;"); + prepopulateMethod(classID, "isArray", "()Z"); + prepopulateMethod(classID, "getComponentType", "()Ljava/lang/Class;"); + prepopulateMethod(classID, "getModifiers", "()I"); + + + classID = prepopulateClass("java/lang/reflect/Method"); + prepopulateMethod(classID, "getName", "()Ljava/lang/String;"); + prepopulateMethod(classID, "getParameterTypes", "()[Ljava/lang/Class;"); + prepopulateMethod(classID, "getReturnType", "()Ljava/lang/Class;"); + prepopulateMethod(classID, "getModifiers", "()I"); + + classID = prepopulateClass("java/lang/reflect/Constructor"); + prepopulateMethod(classID, "getParameterTypes", "()[Ljava/lang/Class;"); + prepopulateMethod(classID, "getModifiers", "()I"); + + classID = prepopulateClass("java/lang/reflect/Field"); + prepopulateMethod(classID, "getName", "()Ljava/lang/String;"); + prepopulateMethod(classID, "getType", "()Ljava/lang/Class;"); + prepopulateMethod(classID, "getModifiers", "()I"); + + classID = prepopulateClass("java/lang/reflect/Array"); + prepopulateMethod(classID, "newInstance", "(Ljava/lang/Class;I)Ljava/lang/Object;"); + + classID = prepopulateClass("java/lang/Throwable"); + prepopulateMethod(classID, "toString", "()Ljava/lang/String;"); + prepopulateMethod(classID, "getMessage", "()Ljava/lang/String;"); + + classID = prepopulateClass("java/lang/System"); + prepopulateMethod(classID, "identityHashCode", "(Ljava/lang/Object;)I"); + + classID = prepopulateClass("java/lang/Boolean"); + prepopulateMethod(classID, "booleanValue", "()D"); + prepopulateMethod(classID, "<init>", "(Z)V"); + + classID = prepopulateClass("java/lang/Double"); + prepopulateMethod(classID, "doubleValue", "()D"); + prepopulateMethod(classID, "<init>", "(D)V"); + + classID = prepopulateClass("java/lang/Void"); + prepopulateField(classID, "TYPE"); + + prepopulateClass("java/lang/String"); + prepopulateClass("java/applet/Applet"); + } + + private int prepopulateClass(String name) { + name = name.replace('/', '.'); + ClassLoader cl = liveconnectLoader; + Class c = null; + + try { + c = cl.loadClass(name); + store.reference(c); + } catch (ClassNotFoundException cnfe) { + // do nothing ... this should never happen + cnfe.printStackTrace(); + } + + return store.getIdentifier(c); + } + + private int prepopulateMethod(int classID, String methodName, String signatureStr) { + Signature signature = parseCall(signatureStr, ((Class) store.getObject(classID)).getClassLoader(), Signature.class); + Object[] a = signature.getClassArray(); + + Class c = (Class) store.getObject(classID); + Method m = null; + Constructor cs = null; + Object o = null; + + try { + if (methodName.equals("<init>") + || methodName.equals("<clinit>")) { + o = cs = c.getConstructor(signature.getClassArray()); + store.reference(cs); + } else { + o = m = c.getMethod(methodName, signature.getClassArray()); + store.reference(m); + } + } catch (NoSuchMethodException e) { + // should never happen + e.printStackTrace(); + } + + return store.getIdentifier(m); + } + + private int prepopulateField(int classID, String fieldName) { + + Class c = (Class) store.getObject(classID); + Field f = null; + try { + f = c.getField(fieldName); + } catch (SecurityException e) { + // should never happen + e.printStackTrace(); + } catch (NoSuchFieldException e) { + // should never happen + e.printStackTrace(); + } + + store.reference(f); + return store.getIdentifier(f); + } + public void dumpStore() { store.dump(); }
--- a/plugin/icedtea/sun/applet/PluginAppletViewer.java Tue Oct 21 16:45:19 2008 +0200 +++ b/plugin/icedtea/sun/applet/PluginAppletViewer.java Tue Oct 21 16:17:19 2008 -0400 @@ -47,11 +47,11 @@ import java.io.PrintStream; import java.io.Reader; import java.io.StringReader; +import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.SocketPermission; import java.net.URL; import java.security.AccessController; -import java.security.Policy; import java.security.PrivilegedAction; import java.util.Enumeration; import java.util.HashMap; @@ -60,6 +60,8 @@ import java.util.Map; import java.util.Vector; +import javax.swing.SwingUtilities; + import net.sourceforge.jnlp.NetxPanel; import sun.awt.AppContext; import sun.awt.SunToolkit; @@ -261,12 +263,6 @@ showStatus(amh.getMessage("status.start")); initEventQueue(); - try { - write("initialized"); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - // Wait for a maximum of 10 seconds for the panel to initialize // (happens in a separate thread) Applet a; @@ -282,6 +278,12 @@ } } + // Still null? + if (panel.getApplet() == null) { + this.streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError " + "Initialization failed"); + return; + } + PluginDebug.debug("Applet initialized"); // Applet initialized. Find out it's classloader and add it to the list @@ -297,6 +299,12 @@ } AppletSecurityContextManager.getSecurityContext(0).associateSrc(a.getClass().getClassLoader(), codeBase); + + try { + write("initialized"); + } catch (IOException ioe) { + ioe.printStackTrace(); + } } @@ -386,20 +394,49 @@ public void handleMessage(int reference, String message) { if (message.startsWith("width")) { - - String[] dimMsg = message.split(" "); + // 0 => width, 1=> width_value, 2 => height, 3=> height_value + String[] dimMsg = message.split(" "); - int height = (int) (proposedHeightFactor*Integer.parseInt(dimMsg[3])); - int width = (int) (proposedWidthFactor*Integer.parseInt(dimMsg[1])); + final int height = (int) (proposedHeightFactor*Integer.parseInt(dimMsg[3])); + final int width = (int) (proposedWidthFactor*Integer.parseInt(dimMsg[1])); if (panel instanceof NetxPanel) ((NetxPanel) panel).updateSizeInAtts(height, width); - panel.setSize(width, height); - setSize(width, height); + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + + setSize(width, height); + + // There is a rather odd drawing bug whereby resizing + // the panel makes no difference on initial call + // because the panel thinks that it is already the + // right size. Validation has no effect there either. + // So we work around by setting size to 1, validating, + // and then setting to the right size and validating + // again. This is not very efficient, and there is + // probably a better way -- but resizing happens + // quite infrequently, so for now this is how we do it - panel.validate(); + panel.setSize(1,1); + panel.validate(); + + panel.setSize(width, height); + panel.validate(); + } + }); + } catch (InterruptedException e) { + // do nothing + e.printStackTrace(); + } catch (InvocationTargetException e) { + // do nothing + e.printStackTrace(); + } + +// this.validate(); +// panel.validate(); } else if (message.startsWith("destroy")) { dispose(); } else if (message.startsWith("GetJavaObject")) {
--- a/plugin/icedtea/sun/applet/PluginMain.java Tue Oct 21 16:45:19 2008 +0200 +++ b/plugin/icedtea/sun/applet/PluginMain.java Tue Oct 21 16:17:19 2008 -0400 @@ -54,7 +54,14 @@ public static void main(String args[]) throws IOException { - PluginMain pm = new PluginMain(System.getProperty("user.home") + "/.icedteaplugin/icedtea-plugin-to-appletviewer", System.getProperty("user.home") + "/.icedteaplugin/icedtea-appletviewer-to-plugin"); + + try { + PluginMain pm = new PluginMain(System.getProperty("user.home") + "/.icedteaplugin/icedtea-plugin-to-appletviewer", System.getProperty("user.home") + "/.icedteaplugin/icedtea-appletviewer-to-plugin"); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Something very bad happened. I don't know what to do, so I am going to exit :("); + System.exit(1); + } } public PluginMain(String inPipe, String outPipe) { @@ -76,6 +83,7 @@ connect(inPipe, outPipe); securityContext = new PluginAppletSecurityContext(0); + securityContext.prePopulateLCClasses(); securityContext.setStreamhandler(streamHandler); AppletSecurityContextManager.addContext(0, securityContext);