XPCOM Code FAQ

Suresh Duddi <dp@netscape.com>
Last Modified: May 25 2000


I am documenting things randomly as I am replying to people's questions. So this looks more like an FAQ.

Table of Contents

  1. What are the Global Objects that XPCOM maintains
  2. What are the static classes that XPCOM maintains
  3. Is there any restriction on which static class I should call first
  4. What is the order of creation of the ServiceManager, ComponentManager and Registry
  5. Is there a global Registry being maintained
  6. ComponentManager Vs ServiceManager
  7. ContractID Vs CLSID
  8. How to set breakpoints in component code
  9. Generating the XPCOM LOG

What are the Global Objects that XPCOM maintains

What are the static classes that XPCOM maintains

nsComponentManager
nsServiceManager

Is there any restriction on which static class I should call first

No restrictions. You can call any function from the static classes nsComponentManager and nsServiceManager. XPCOM will do the right thing to initialize itself at both places.

Autoregistration() can happen only after Init_XPCOM() is called since the registy might be required by SelfRegister() functions of the dlls and it is only in Init_XPCOM() do we create register the RegistryFactory() with the ComponentManager.

What is the order of creation of the ServiceManager, ComponentManager and Registry

Init_XPCOM()
  • create the global service manager
  • create the global component manager and register as service with the global service manager
  • RegisterFactory(...RegistryFactory...)  Register the RegistryFactory with the component manager so that new registry objects can be created.
  • Now the hard problem is when to trigger Init_XPCOM() There are two static objects nsComponentManager and nsServiceManager. Any function in either of them can be called first. Today nsServiceManager::GetService() is the first one that gets called. All the members of the static nsServiceManager use the NS_GetGlobalServiceManager() to get to the global service manager. All members of the static nsComponentManager use the NS_GetGlobalComponentManager() to get to the global component manager. Hence if we trigger Init_XPCOM() from both NS_GetGlobalComponentManager() and NS_GetGlobalServiceManager() we will be safe.

    Is there a global Registry being maintained

    No. The nsIRegistry is designed to be lightweight access to the registry. Consumers who need to access the registry should use the component manager to create the their own registry access object. This is required because the open() call is supported by the nsIRegistry() and if we maintain a global registry arbitrating which registry file is opened is going to be a major headach.

    The ContractID for the registry will be @mozilla.org/registry;1
     

    ComponentManager Vs ServiceManager

    ComponentManager is the only way for component creation. ComponentManager always uses the component's factory to create the component instance. Clients (code that calls CreateInstance() to create and use a component) call the ComponentManager to create instances. Components (the code that implemented NSRegisterSelf()) calls the ComponentManager to register itself and gets called when a Client wants to instantiate a component.

    ServiceManager is a convinience for getting singleton components, components for which only one instance stays alive for the entire application e.g Netlib. It enforces only one of a kind of a component to exist. Hence the notion of getting a service not creating one. (as opposed to the notion of Creating instances with the componentManager). ServiceManager is a convenience because components can technically force singletonism by making their factory return the same instance if one was created already. The other big use of ServiceManager is the (still unimplemented) notion of Shutting down a service.

    Client

    Component

    ContractID Vs CLSID

    ClassID or CLSID is the unique indentification of a component. It is a structure of huge numbers generated by using uuidgen on a windows box. It is represented as a string in documentation as {108d75a0-bab5-11d2-96c4-0060b0fb9956}

    ContractID is the string identification of an implementation of a component the client is looking for. The representation takes a URI syntax. Eg. @mozilla.org/network/protocol;1?description=Http Protocol Handler&name=http
    Some simplify this to, ContractID is a more readable string form of a CLSID. That is acceptable on the periphery. The ContractID is a Client thing. Components register with component manager to claim that they are the implementation for a ContractID. A component can register to be the implementation for multiple ContractIDs (not implemented yet).

    Client

    Component

    How to set break points in component code

    Since components are dynamically loaded only on demand, debugging them could be a hard. Here are some tips to debugging components.

    Windows: VC5.0 VC6.0

    Include your component library in the Project->Settings, Additional Dll. drop down. After that breakpoints can be enabled.
    Unix: gdb
    • Let the program run until you are sure that your component is loaded. Type Control-C. Now all symbols from your component will be available in gdb. Put your breakpoints and restart the app. Gdb will complain that it cannot set the breakpoint, and that it is temporarily disabling it, but when the *.so is loaded, the breakpoint is enabled automatically. - <Eric Van Der Poel>
    • I think typing "dir components" (assuming you're in dist/bin) will also allow you to see the symbols in your stack the first time. - <Alec Flett>
    • Using XPCOM_BREAK_ON_LOAD environment variable:

    • gdb> set env XPCOM_BREAK_ON_LOAD "necko:rdf"
      gdb> r

      This will cause xpcom to break in the debugger after loading any dll with substrings necko or rdf in them. At this point, you could instruct the debugger to load the dll symbols and set breakpoint.

      gdb> sha libnecko.so
      gdb> b nsFunctionInNecko

    Mac: Codewarrior
    Just open the appropriate .xSYM file in the debugger; the debugger will target the library when the application is run. - <Simon Fraser>
    Generating a log from xpcom:
    XPCOM provides log output. To enable the logging:
    [unix]
    setenv NSPR_LOG_MODULES nsComponentManager:5
    setenv NSPR_LOG_FILE xpcom.log

    [win]
    set NSPR_LOG_MODULES=nsComponentManager:5
    set NSPR_LOG_FILE=xpcom.log

    Start your application after setting the above environment variables. Debug log from xpcom would be in the file xpcom.log


    XPCOM Log analysis

    xpcom/doc/xpcom-log-analyze.sh is a script that does analysis of the xpcom log and prints out useful statistics in html format. Usage is:
    xpcom-log-analyze.sh < xpcom.log > xpcom-log.html