304 lines
14 KiB
HTML
304 lines
14 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<TITLE>Reasearch Scratch Pad for Learning Waterfall</TITLE>
|
|
</HEAD>
|
|
<BODY>
|
|
<PRE>
|
|
This document is a scratch pad for helping me understand how waterfall
|
|
works. I will use mozilla and the debugger as a guide. I'll start by
|
|
discovering how mozilla hooks into waterfall.
|
|
|
|
Refer to this diagram:
|
|
|
|
<IMG SRC="primaryclasses.gif"></IMG>
|
|
|
|
Waterfall Metrics
|
|
=================
|
|
|
|
144 files total
|
|
|
|
76 java
|
|
3 cpp
|
|
25 c
|
|
40 h
|
|
|
|
30849 SLOC including comments.
|
|
|
|
|
|
Waterfall Bootstrapping
|
|
=======================
|
|
|
|
Mozilla hooks in to waterfall by virtue of the wf_moz6 module being an
|
|
XPCOM component.
|
|
|
|
D:\Projects\trunk\mozilla\wf_moz6\wf_moz6\src\nsCJVMFactory.cpp
|
|
|
|
This file defines the necessary macro to be an XPCOM component:
|
|
|
|
NS_IMPL_NSGETMODULE("nsCJVMModule", components);
|
|
|
|
The second argument is an array of nsModuleComponentInfo structs.
|
|
|
|
static nsModuleComponentInfo components[] =
|
|
{
|
|
{ "Waterfall API-based JVM Service",
|
|
NS_PLUGGABLEJVM_CID,
|
|
NS_INLINE_PLUGIN_CONTRACTID_PREFIX "application/x-java-vm",
|
|
nsJavaHTMLObjectFactory::Create,
|
|
},
|
|
};
|
|
|
|
nsModuleComponentInfo is defined in:
|
|
|
|
D:\Projects\trunk\mozilla\dist\include\nsIGenericFactory.h
|
|
|
|
The important elements in this struct are the third and forth:
|
|
|
|
const char* mContractID;
|
|
NSConstructorProcPtr mConstructor;
|
|
|
|
the mContractID tells XPCOM what our programmatic name is, and the
|
|
mConstructor tells XPCOM what to call to construct an instance of the
|
|
module. In waterfall's case, this is nsJavaHTMLObjectFactory::Create,
|
|
defined in
|
|
D:\Projects\trunk\mozilla\wf_moz6\wf_moz6\src\nsJavaHTMLObjectFactory.cpp
|
|
|
|
As you may know every dll in the components directory is interrogated at
|
|
mozilla startup in what is known as "auto-registration". This is how
|
|
waterfall gets picked up. The waterfall library is called
|
|
dist\win32*\bin\components\ojijvm.dll. Our Create method gets called
|
|
here:
|
|
|
|
nsJavaHTMLObjectFactory::Create(nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012f8e4) line 92
|
|
nsGenericFactory::CreateInstance(nsGenericFactory * const 0x0173a2d0, nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012f8e4) line 56
|
|
nsComponentManagerImpl::CreateInstance(nsComponentManagerImpl * const 0x00a96c80, const nsID & {...}, nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012f8e4) line 1199 + 24 bytes
|
|
nsComponentManager::CreateInstance(const nsID & {...}, nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012f8e4) line 82
|
|
nsServiceManagerImpl::GetService(nsServiceManagerImpl * const 0x00a955a0, const nsID & {...}, const nsID & {...}, nsISupports * * 0x0012f9a4, nsIShutdownListener * 0x00000000) line 344 + 19 bytes
|
|
nsServiceManagerImpl::GetService(nsServiceManagerImpl * const 0x00a955a0, const char * 0x024536d0, const nsID & {...}, nsISupports * * 0x0012f9a4, nsIShutdownListener * 0x00000000) line 492
|
|
nsServiceManager::GetService(const char * 0x024536d0, const nsID & {...}, nsISupports * * 0x0012f9a4, nsIShutdownListener * 0x00000000) line 605
|
|
nsGetServiceByContractID::operator()(const nsID & {...}, void * * 0x0012f9a4) line 64 + 22 bytes
|
|
nsCOMPtr<nsIPlugin>::assign_from_helper(const nsCOMPtr_helper & {...}, const nsID & {...}) line 970 + 18 bytes
|
|
nsCOMPtr<nsIPlugin>::nsCOMPtr<nsIPlugin>(const nsCOMPtr_helper & {...}) line 552
|
|
nsJVMManager::StartupJVM() line 605 + 30 bytes
|
|
nsJVMManager::MaybeStartupLiveConnect() line 788 + 20 bytes
|
|
nsJVMManager::StartupLiveConnect(nsJVMManager * const 0x01739118, JSRuntime * 0x00f97210, int & 0) line 128 + 11 bytes
|
|
nsJSEnvironment::nsJSEnvironment() line 1505 + 49 bytes
|
|
nsJSEnvironment::GetScriptingEnvironment() line 1446 + 27 bytes
|
|
NS_CreateScriptContext(nsIScriptGlobalObject * 0x0169c7b0, nsIScriptContext * * 0x01693680) line 1545 + 5 bytes
|
|
nsDocShell::EnsureScriptEnvironment(nsDocShell * const 0x016935d0) line 4384 + 50 bytes
|
|
nsWebShell::GetInterface(nsWebShell * const 0x016935f4, const nsID & {...}, void * * 0x0012fc00) line 327 + 19 bytes
|
|
nsGetInterface::operator()(const nsID & {...}, void * * 0x0012fc00) line 37 + 31 bytes
|
|
nsCOMPtr<nsIDOMWindowInternal>::assign_from_helper(const nsCOMPtr_helper & {...}, const nsID & {...}) line 970 + 18 bytes
|
|
nsCOMPtr<nsIDOMWindowInternal>::nsCOMPtr<nsIDOMWindowInternal>(const nsCOMPtr_helper & {...}) line 552
|
|
nsAppShellService::GetHiddenWindowAndJSContext(nsAppShellService * const 0x00b579b0, nsIDOMWindowInternal * * 0x0012fca8, JSContext * * 0x0012fcac) line 727 + 32 bytes
|
|
nsAppShellService::SetXPConnectSafeContext() line 191 + 40 bytes
|
|
nsAppShellService::CreateHiddenWindow(nsAppShellService * const 0x00b579b0) line 251
|
|
main1(int 1, char * * 0x00a95930, nsISupports * 0x00000000) line 987
|
|
main(int 1, char * * 0x00a95930) line 1298 + 37 bytes
|
|
mainCRTStartup() line 338 + 17 bytes
|
|
KERNEL32! 77f1ba3c()
|
|
|
|
Regarding nsJVMManager.cpp StartupJVM() on the stack: this is where the
|
|
first modification in the patch to bug 72708 comes into play:
|
|
|
|
NS_WITH_SERVICE(nsIPlugin, f,
|
|
NS_INLINE_PLUGIN_CONTRACTID_PREFIX NS_JVM_MIME_TYPE,
|
|
&err);
|
|
if (NS_FAILED(err) || !f) {
|
|
err = pluginHost->GetPluginFactory(NS_JVM_MIME_TYPE, &pluginFactory);
|
|
}
|
|
else {
|
|
pluginFactory = f;
|
|
}
|
|
|
|
Note that the contract ID matches the one specified in
|
|
nsCJVMFactory.cpp. Here Nikolay has modified the oji code to first
|
|
check for waterfall, then to fall back on the
|
|
pluginHost->CreatePlugin().
|
|
|
|
ns nsJavaHTMLObjectFactory::Create, we create an instance of
|
|
nsJavaHTMLObjectFactory. This has a reference to an nsIPluggableJVM
|
|
impl. We send nsJavaHTMLObjectFactory Initialize(). In Initialize(),
|
|
we send StartupJVM to nsIPluggableJVM. This calls
|
|
nsPluggableJVM::loadPluginDLL(). As far as I can tell this is where the
|
|
first call into the Waterfall plugin code occurrs. loadPluginDLL() opens
|
|
the jvmp.dll, and finds the symbol "JVMP_GetPlugin". This calls
|
|
loadJVM(), which opens the JDK's JVM dll and looks for several symbols.
|
|
Here there is ifdef'd code for each of the supported JVMS:
|
|
|
|
#ifdef _JVMP_IBMJVM
|
|
#ifdef _JVMP_SUNJVM
|
|
|
|
etc.
|
|
|
|
The symbols loaded from the JVM dll are:
|
|
|
|
JNI_GetDefaultJavaVMInitArgs
|
|
JNI_CreateJavaVM
|
|
JNI_GetCreatedJavaVMs
|
|
|
|
JVMP_GetPlugin returns a pointer to a static JVMP_RuntimeContext
|
|
instance. JVMP_RuntimeContext is defined in
|
|
d:\Projects\blackwood\eng\wf\public\jvmp.h. The RuntimeContext is a
|
|
collection pointers to functions defined in java_plugin.c.
|
|
nsPluggableJVM keeps a pointer to the JVMP_RuntimeContext.
|
|
|
|
After loading the jvmp.dll, we call nsPluggableJVM::initJVM().
|
|
nsPluggableJVM::initJVM() calls JVMP_GetRunningJVM(), in
|
|
d:\Projects\blackwood\eng\wf\src\plugin\java_plugin.c. This calls
|
|
JVMP_initJavaClasses(). Here is the first time we see JNI constructs.
|
|
We find the class sun/jvmp/generic/{motif,win32}/Plugin.java and call its
|
|
startJVM() method. This returns an instance of the java class
|
|
PluggableJVM. This is saved as the static native var
|
|
JVMP_PluginInstance. The class Plugin is saved as JVMP_PluginClass.
|
|
|
|
After returning, we call JVMP_initClassPath, which pulls in the java
|
|
classpath from the CLASSPATH env var. This results in creating an array
|
|
like this:
|
|
|
|
Java Plugin: JVM option[0]=-Djava.class.path=D:\Projects\blackwood\eng\wf\build\win32\classes;
|
|
Java Plugin: JVM option[1]=-Djava.library.path=D:\Projects\blackwood\eng\wf\build\win32;D:\Projects\blackwood\eng\wf\build\win32\java\jre\lib\win32:
|
|
Java Plugin: JVM option[2]=-Djava.home=D:\Projects\blackwood\eng\wf\build\win32/java/jre
|
|
Java Plugin: JVM option[3]=-Xbootclasspath:D:\Projects\blackwood\eng\wf\build\win32\java\jre\classes;D:\Projects\blackwood\eng\wf\build\win32\java\jre\lib\rt.jar;D:\Projects\blackwood\eng\wf\build\win32\java\jre\lib\i18n.jar
|
|
Java Plugin: JVM option[4]=-Djava.security.manager
|
|
Java Plugin: JVM option[5]=-Djvmp.home=D:\Projects\blackwood\eng\wf\build\win32
|
|
Java Plugin: JVM option[6]=-Djava.security.policy=file:D:/Projects/blackwood/eng/wf/build/win32/plugin.policy
|
|
|
|
We then try to get access to a JavaVM, using JVMP_ReuseJVM(). This uses
|
|
the JVMMethods struct, defined in java_plugin.c. This is a struct of
|
|
function pointers to JVM methods.
|
|
|
|
We then call JVMP_EnableCapabilities(). This is the first sign of
|
|
security code in waterfall. Let me step out of context to define two
|
|
terms. A Principal is an entity responsible for a script in some way.
|
|
There are several kinds of principals. A certificate principal
|
|
represents the signer of the script. A certificate principal is
|
|
responsible for proving the script is from who it says it is. Another
|
|
way of saying it is that a certificate principal is responsible for the
|
|
script's authentication. The set of principals is fixed at the time the
|
|
page is loaded. Each principal has a set of capabilities, each of which
|
|
can be enabled or disabled by the system and the user.
|
|
|
|
I don't know what a system principal is, but it represents mozilla.org?
|
|
How does a codebase principal differ from a certificate principal? They
|
|
both seem to deal with the issue of authentication.
|
|
|
|
Back to calling JVMP_EnableCapabilities(). This manipulates the
|
|
JVMP_CallingContext, a struct with function pointers for manipulating
|
|
Caps. Caps is a term bandied about by security types. It's short for
|
|
capabilities. If someone could come up with a better definition, I'd
|
|
appreciate it. At this point we call back into java for the
|
|
PluggableJVM.enableCapabilities() method, passing in the byte array for
|
|
the caps and an array of principals.
|
|
|
|
We return and pop up the java console, then return from
|
|
nsJavaHTMLObjectFactory::Create(), returning an instance of
|
|
nsJavaHTMLObjectFactory typed as a nsIPlugin. Our being typed this way
|
|
enables us to provide the necessary services to the browser. This
|
|
completes the bootstrapping process.
|
|
|
|
How an Applet is instantiated
|
|
=============================
|
|
|
|
The normal plugin instantiation and initialization proccess occurrs.
|
|
This includes scanning the plugin directory for any plugins that respond
|
|
to the applet mime type. Of course none are found since waterfall
|
|
requires that the java plugin is not installed. Then we try to
|
|
instantiate a plugin using the contract id:
|
|
"@mozilla.org/inline-plugin/application/x-java-vm". Remember that
|
|
waterfall declared itself as responding to that contractID in
|
|
D:\Projects\trunk\mozilla\wf_moz6\wf_moz6\src\nsCJVMFactory.cpp. This
|
|
happens here:
|
|
|
|
nsJavaHTMLObjectFactory::Create(nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012a944) line 104
|
|
nsGenericFactory::CreateInstance(nsGenericFactory * const 0x0173beb0, nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012a944) line 56
|
|
nsComponentManagerImpl::CreateInstance(nsComponentManagerImpl * const 0x00a96bc0, const nsID & {...}, nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012a944) line 1199 + 24 bytes
|
|
nsComponentManagerImpl::CreateInstanceByContractID(nsComponentManagerImpl * const 0x00a96bc0, const char * 0x0012a948, nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012a944) line 1239
|
|
nsComponentManager::CreateInstance(const char * 0x0012a948, nsISupports * 0x00000000, const nsID & {...}, void * * 0x0012a944) line 94
|
|
nsPluginHostImpl::SetUpPluginInstance(nsPluginHostImpl * const 0x0173a4b4, const char * 0x0b7d21ec, nsIURI * 0x0e0e6440, nsIPluginInstanceOwner * 0x0e0e6950) line 2758 + 28 bytes
|
|
nsPluginHostImpl::InstantiateEmbededPlugin(nsPluginHostImpl * const 0x0173a4b4, const char * 0x0b7d21ec, nsIURI * 0x0e0e6440, nsIPluginInstanceOwner * 0x0e0e6950) line 2461 + 24 bytes
|
|
nsObjectFrame::InstantiatePlugin(nsIPresContext * 0x0d0a3290, nsHTMLReflowMetrics & {...}, const nsHTMLReflowState & {...}, nsIPluginHost * 0x0173a4b4, const char * 0x0b7d21ec, nsIURI * 0x0e0e6440) line 1037
|
|
nsObjectFrame::Reflow(nsObjectFrame * const 0x0125596c, nsIPresContext * 0x0d0a3290, nsHTMLReflowMetrics & {...}, const nsHTMLReflowState & {...}, unsigned int & 0) line 853 + 49 bytes
|
|
|
|
The plugin is looking for an nsIPluginInstance instance, which waterfall
|
|
returns in the form of an nsAppletHTMLObject instance. This guy also
|
|
implements nsIJVMPluginInstance. It creates and has a nsIJavaHTMLObject
|
|
instance. According to the comments, the nsIJavaHTMLObject instance is
|
|
the "is instance of visible object on browser's page controlled by Java
|
|
code, like APPLET or OBJECT tag content." This eventually calls into
|
|
the java class PluggableJVM.createPeer(). The nsIJavaHTMLObject
|
|
instance creates and keeps an nsIJavaObjectInfo instance.
|
|
|
|
|
|
|
|
Comments and Questions
|
|
======================
|
|
|
|
How does the java console get hooked up to nsIJVMConsole?
|
|
|
|
|
|
nsJavaHTMLObjectFactory::Initialize()
|
|
|
|
should use do_getService() instead of nsServiceManager::GetService().
|
|
|
|
shouldn't use stock malloc, should use nsCRT.
|
|
|
|
nsPluggableJVM::StartupJVM()
|
|
|
|
shouldn't use env vars. At the very least, shouldn't use stock
|
|
getenv, should use nsCRT.
|
|
|
|
Console shouldn't be hard coded to visible.
|
|
|
|
JVMP_initClassPath(), JVMP_GetPlugin(), loadJVM(), etc
|
|
|
|
I know these classes are independent of mozilla. Is it ok to use the
|
|
stock malloc() and getenv()? Should waterfall c plugin classes use
|
|
nspr?
|
|
|
|
Is this ifdefing allowable:
|
|
|
|
#ifdef _JVMP_IBMJVM
|
|
#ifdef _JVMP_SUNJVM
|
|
|
|
In loadJVM() we have the filepaths to the jvm dll hard coded, is this
|
|
safe?
|
|
|
|
Is it safe to assume these symbols are in the jvm dll?
|
|
|
|
JNI_GetDefaultJavaVMInitArgs
|
|
JNI_CreateJavaVM
|
|
JNI_GetCreatedJavaVMs
|
|
|
|
Or do we assume we'll have a different jvmp for each released Java
|
|
plugin version? I *do* think this is a safe assumption.
|
|
|
|
* JRE 1.3.0_01 doesn't have classic vm
|
|
|
|
* when running ./plugin_host, you must start the JVM, then enable system
|
|
capabilities in order to do most anything else.
|
|
|
|
* He has inconsistent environment variables for things.
|
|
|
|
JAVA_HOME == JDK
|
|
|
|
* The documentation refers to files that aren't there. build.txt refers
|
|
to ../java/makefile.win, when it should be ../build/java/makefile.win.
|
|
|
|
* Why do you have to copy the Java directory into the build area on
|
|
win32, and link it on unix?
|
|
|
|
* Why does he have a jni.h in his tree? How does it differ from the
|
|
stock jni.h?
|
|
|
|
* Building is a mess. Each platform has unnecessarily different
|
|
conventions, many errors in build instructions.
|
|
|
|
* Can't build wf_moz6: Syntax errors.
|
|
|
|
|
|
|
|
</PRE>
|
|
</BODY>
|
|
</HTML>
|