bug: pressing BACK hangs webclient
Files touched
File: DocumentLoadEvent.java Status: Locally Modified
Made the constants final so they can be used in a
switch statement
File: EMWindow.java Status: Locally Modified
Modified eventDispatched() so it doesn't call any webclient
events. This was causing the hang. Took advantage of
the newly implemented ability to pass a string from the
mozilla event handler into java.
File: DocumentLoaderObserverImpl.cpp Status: Locally Modified
Create a jstring from the url in the OnStartDocumentLoad event.
Pass it on to java.
File: jni_util.cpp Status: Locally Modified
Wrapped JNU_GetEnv in BAL stuff so it works from Star.
File: WebclinetEventListener.java Status: Locally Modified
Added comment to eventDispatched.
r=shaver
a=edburns
Native code changes: This fix eradicates all
occurrences of the following symbols
nsComponentManager nsServiceManeger
And replaces them with their nsI counterparts.
The following ns* classes still are used in
webclient, and no plans exist to replace them
with nsI counterparts: nsresult nsCOMPtr
nsCRT nsnull * nsServiceManager occurrences
were replaced with do_GetService(), using a
PROGID. * nsComponentManager occurrences were replaced with a call on the global class gComponentManager, declared in the new file ns_globals.h, and defined in WrapperFactoryImpl.cpp. ns_globals.h is included in jni_util.h. See the attachment to bug 33099 for ns_globals.h * Added deallocation code to WindowControlImpl.cpp nativeTerminate. I know it doesn't do much, but it's correct. Java code changes: * Added static method BrowserControlFactory.appTerminate(). This method simply calls the existing BrowserControlImpl.appTerminate(), which calls WrapperFactoryImpl.cpp nativeTerminate(). BrowserControlFactory.appTerminate() is called from EmbeddedMozilla's WindowListener, which gets fired when the user signals she wants the app to terminate.
r=ashuk
a=edburns
Add an "eventData" argument to WebclientEvent and subclasses.
This argument is sub-event specific. For example, when a user
gets a DocumentLoadEvent, with an event type of
STATUS_URL_LOAD, the eventData is a String containing
the status string from the browser.
Added support for doing this in a BAL context.
r=ashuk
a=edburns
Add an "eventData" argument to WebclientEvent and subclasses.
This argument is sub-event specific. For example, when a user
gets a DocumentLoadEvent, with an event type of
STATUS_URL_LOAD, the eventData is a String containing
the status string from the browser.
Added ability to allow Native webclient client to populate
the listener class hash table and provide an InstanceOf function.
This enables listeners to work for the future.
This change replaces all printfs in src_moz with calls to PR_LOG. No
printfs should appear in src_moz anymore.
You won't see any console output from native code unless you define
NSPR_LOG_MODULES=webclient:3
in your environment. Furthermore, if you want PR_LOG statements in
webclient to go to a file instead, define
WEBCLIENT_LOG_FILE=C:\VALIDDIR\filename.txt
in your environment. This file will get created fresh each time, since
PR_LOG uses fopen(filename, "w").
New Files:
I've created ns_globals.h, included from jni_util.h. ns_globals.h holds
an extern * to a struct used in the PR_LOG calls.
Significant changes:
WrapperFactoryImpl.cpp
nativeAppInitialize(){
Added:
#if DEBUG_RAPTOR_CANVAS
prLogModuleInfo = PR_NewLogModule("webclient");
const char *webclientLogFile = PR_GetEnv("WEBCLIENT_LOG_FILE");
if (nsnull != webclientLogFile) {
PR_SetLogFile(webclientLogFile);
// If this fails, it just goes to stdout/stderr
}
#endif
}
All the other files in this checkin follow the this pattern:
Before checkin:
printf("InitMozillaStuff(%lx): Create the Event Queue for the UI thread...\n",
initContext);
After checkin:
if (prLogModuleInfo) {
PR_LOG(prLogModuleInfo, 3,
("InitMozillaStuff(%lx): Create the Event Queue for the UI thread...\n",
initContext));
}
See http://lxr.mozilla.org/mozilla/source/nsprpub/pr/include/prlog.h#190
for the definition of PR_LOG
NativeEventThread's run() method's infinite loop was implemented. The
loop looks like this:
while (null != this.browserControlCanvas) {
synchronized (this.browserControlCanvas.getTreeLock()) {
nativeProcessEvents(nativeWebShell);
if (null != listenersToAdd && !listenersToAdd.isEmpty()) {
tempEnum = listenersToAdd.elements();
while (tempEnum.hasMoreElements()) {
nativeAddListener(nativeWebShell,
(WebclientEventListener)
tempEnum.nextElement());
}
listenersToAdd.clear();
}
}
}
The problem I was observing was that
nativeProcessEvents(nativeWebShell) would crash due to the fact that
the nativeWebShell, which is actually an WebShellInitContext instance,
had been de-allocated. This de-allocation happens as a result of the
WindowControlImpl.delete() method, which looks like this:
public void delete()
{
Assert.assert(null != eventThread, "eventThread shouldn't be null at delete time");
eventThread.delete();
eventThread = null;
nativeDestroyInitContext(nativeWebShell);
nativeWebShell = -1;
}
nativeDestroyInitContext de-allocates the WebShellInitContextInstance.
You can see that the first thing done is to delete the eventThread().
NativeEventThread.delete() looks like this:
public void delete()
{
// setting this to null causes the run thread to exit
synchronized(this.browserControlCanvas.getTreeLock()) {
browserControlCanvas = null;
}
...
}
If you compare NativeEventThread.delete() with the infinite loop in
NativeEventThread.run(), you'll see that the fact that they both
synchronize on the same object doesn't protect us from the following
case:
NativeEventThread: The infinite loop checks to see if the
browserControlCanvas is null, then does synchronize on
browserControlCanvas.getTreeLock(), then calls processNativeEvents().
meanwhile
WindowControlImpl thread: delete() calls NativeEventThread.delete(),
which does synchronize on browserControlCanvas.getTreeLock().
During NativeEventThread.delete(), synchronized section,
browserControlCanvas is set to null.
NativeEventThread: because the check for null browserControlCanvas
occurrs outside of the synchronized block, it's not recheked, and
thus, the event loop continues to process when it shouldn't.
The fix is to change the event loop to look like this:
while (true) {
synchronized (this.browserControlCanvas.getTreeLock()) {
// this has to be inside the synchronized block!
if (null == this.browserControlCanvas) {
return;
}
nativeProcessEvents(nativeWebShell);
if (null != listenersToAdd && !listenersToAdd.isEmpty()) {
tempEnum = listenersToAdd.elements();
while (tempEnum.hasMoreElements()) {
nativeAddListener(nativeWebShell,
(WebclientEventListener)
tempEnum.nextElement());
}
listenersToAdd.clear();
}
}
}
- reduces a number of c++<--> java calls
- added NULL checks
- made DOMAccessor to be secure
- added util and tests packages
- wrote test applets
- updated README