diff --git a/xpcom/build/nsXPCOM.h b/xpcom/build/nsXPCOM.h index 1be4d8beeb6..11c16b702c8 100644 --- a/xpcom/build/nsXPCOM.h +++ b/xpcom/build/nsXPCOM.h @@ -258,6 +258,56 @@ NS_Realloc(void* ptr, PRSize size); extern "C" NS_COM void NS_Free(void* ptr); + +/** + * Categories (in the category manager service) used by XPCOM: + */ + +/** + * A category which is read after component registration but before + * the "xpcom-startup" notifications. Each category entry is treated + * as the contract ID of a service which implements + * nsIDirectoryServiceProvider. Each directory service provider is + * installed in the global directory service. + * + * @status FROZEN + */ +#define XPCOM_DIRECTORY_PROVIDER_CATEGORY "xpcom-directory-providers" + +/** + * A category which is read after component registration but before + * NS_InitXPCOM2 returns. Each category entry is treated as the contractID of + * a service: each service is instantiated, and if it implements nsIObserver + * the nsIObserver.observe method is called with the "xpcom-startup" topic. + * + * @status FROZEN + */ +#define NS_XPCOM_STARTUP_CATEGORY "xpcom-startup" + + +/** + * Observer topics (in the observer service) used by XPCOM: + */ + +/** + * At XPCOM startup after component registration is complete, the + * following topic is notified. In order to receive this notification, + * component must register their contract ID in the category manager, + * + * @see NS_XPCOM_STARTUP_CATEGORY + * @status FROZEN + */ +#define NS_XPCOM_STARTUP_OBSERVER_ID "xpcom-startup" + +/** + * At XPCOM shutdown, this topic is notified. All components must + * release any interface references to objects in other modules when + * this topic is notified. + * + * @status FROZEN + */ +#define NS_XPCOM_SHUTDOWN_OBSERVER_ID "xpcom-shutdown" + extern "C" NS_COM nsresult NS_GetDebug(nsIDebug* *result); diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index 8fe7d391a7c..d421900e0cf 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -242,18 +242,10 @@ RegisterGenericFactory(nsIComponentRegistrar* registrar, static PRBool CheckUpdateFile() { nsresult rv; - nsCOMPtr directoryService; - nsDirectoryService::Create(nsnull, - NS_GET_IID(nsIProperties), - getter_AddRefs(directoryService)); - - if (!directoryService) - return PR_FALSE; - nsCOMPtr file; - rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, - NS_GET_IID(nsIFile), - getter_AddRefs(file)); + rv = nsDirectoryService::gService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(file)); if (NS_FAILED(rv)) { NS_WARNING("Getting NS_XPCOM_CURRENT_PROCESS_DIR failed"); @@ -268,9 +260,9 @@ static PRBool CheckUpdateFile() return PR_FALSE; nsCOMPtr compregFile; - rv = directoryService->Get(NS_XPCOM_COMPONENT_REGISTRY_FILE, - NS_GET_IID(nsIFile), - getter_AddRefs(compregFile)); + rv = nsDirectoryService::gService->Get(NS_XPCOM_COMPONENT_REGISTRY_FILE, + NS_GET_IID(nsIFile), + getter_AddRefs(compregFile)); if (NS_FAILED(rv)) { @@ -290,7 +282,6 @@ static PRBool CheckUpdateFile() nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = NULL; -nsIProperties *gDirectoryService = NULL; PRBool gXPCOMShuttingDown = PR_FALSE; // For each class that wishes to support nsIClassInfo, add a line like this @@ -481,17 +472,7 @@ nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, StartupSpecialSystemDirectory(); - // Start the directory service so that the component manager init can use it. - rv = nsDirectoryService::Create(nsnull, - NS_GET_IID(nsIProperties), - (void**)&gDirectoryService); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr dirService = do_QueryInterface(gDirectoryService, &rv); - if (NS_FAILED(rv)) - return rv; - rv = dirService->Init(); + rv = nsDirectoryService::RealInit(); if (NS_FAILED(rv)) return rv; @@ -513,23 +494,23 @@ nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, rv = binDirectory->IsDirectory(&value); if (NS_SUCCEEDED(rv) && value) { - gDirectoryService->Set(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, binDirectory); + nsDirectoryService::gService->Set(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, binDirectory); binDirectory->Clone(getter_AddRefs(xpcomLib)); } } else { - gDirectoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, - NS_GET_IID(nsIFile), - getter_AddRefs(xpcomLib)); + nsDirectoryService::gService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(xpcomLib)); } if (xpcomLib) { xpcomLib->AppendNative(nsDependentCString(XPCOM_DLL)); - gDirectoryService->Set(NS_XPCOM_LIBRARY_FILE, xpcomLib); + nsDirectoryService::gService->Set(NS_XPCOM_LIBRARY_FILE, xpcomLib); } if (appFileLocationProvider) { - rv = dirService->RegisterProvider(appFileLocationProvider); + rv = nsDirectoryService::gService->RegisterProvider(appFileLocationProvider); if (NS_FAILED(rv)) return rv; } @@ -621,9 +602,9 @@ nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, #ifdef DEBUG_dougt printf("start - Registering GRE components\n"); #endif - rv = gDirectoryService->Get(NS_GRE_COMPONENT_DIR, - NS_GET_IID(nsIFile), - getter_AddRefs(greDir)); + rv = nsDirectoryService::gService->Get(NS_GRE_COMPONENT_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(greDir)); if (NS_FAILED(rv)) { NS_ERROR("Could not get GRE components directory!"); return rv; @@ -653,9 +634,9 @@ nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, // nsCOMPtr dirList; - gDirectoryService->Get(NS_XPCOM_COMPONENT_DIR_LIST, - NS_GET_IID(nsISimpleEnumerator), - getter_AddRefs(dirList)); + nsDirectoryService::gService->Get(NS_XPCOM_COMPONENT_DIR_LIST, + NS_GET_IID(nsISimpleEnumerator), + getter_AddRefs(dirList)); if (dirList) { PRBool hasMore; while (NS_SUCCEEDED(dirList->HasMoreElements(&hasMore)) && hasMore) { @@ -675,9 +656,9 @@ nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, // Make sure the compreg file's mod time is current. nsCOMPtr compregFile; - rv = gDirectoryService->Get(NS_XPCOM_COMPONENT_REGISTRY_FILE, - NS_GET_IID(nsIFile), - getter_AddRefs(compregFile)); + rv = nsDirectoryService::gService->Get(NS_XPCOM_COMPONENT_REGISTRY_FILE, + NS_GET_IID(nsIFile), + getter_AddRefs(compregFile)); compregFile->SetLastModifiedTime(PR_Now() / 1000); } @@ -685,6 +666,11 @@ nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, nsIInterfaceInfoManager* iim = XPTI_GetInterfaceInfoManager(); NS_IF_RELEASE(iim); + // After autoreg, but before we actually instantiate any components, + // add any services listed in the "xpcom-directory-providers" category + // to the directory service. + nsDirectoryService::gService->RegisterCategoryProviders(); + // Notify observers of xpcom autoregistration start NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_OBSERVER_ID, nsnull, @@ -813,7 +799,7 @@ nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr) nsProxyObjectManager::Shutdown(); // Release the directory service - NS_IF_RELEASE(gDirectoryService); + NS_IF_RELEASE(nsDirectoryService::gService); // Shutdown nsLocalFile string conversion NS_ShutdownLocalFile(); diff --git a/xpcom/components/nsIServiceManager.idl b/xpcom/components/nsIServiceManager.idl index 302c26c385f..13aaba7ce95 100644 --- a/xpcom/components/nsIServiceManager.idl +++ b/xpcom/components/nsIServiceManager.idl @@ -101,12 +101,6 @@ interface nsIServiceManager : nsISupports */ #define NS_ERROR_SERVICE_IN_USE NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 23) -// Observing xpcom startup. If you component has not been created, it will be. -#define NS_XPCOM_STARTUP_OBSERVER_ID "xpcom-startup" - -// Observing xpcom shutdown -#define NS_XPCOM_SHUTDOWN_OBSERVER_ID "xpcom-shutdown" - // Observing xpcom autoregistration. Topics will be 'start' and 'stop'. #define NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID "xpcom-autoregistration" diff --git a/xpcom/io/nsDirectoryService.cpp b/xpcom/io/nsDirectoryService.cpp index e239b48f430..d2fbc004941 100644 --- a/xpcom/io/nsDirectoryService.cpp +++ b/xpcom/io/nsDirectoryService.cpp @@ -38,6 +38,7 @@ * ***** END LICENSE BLOCK ***** */ #include "nsCOMPtr.h" +#include "nsAutoPtr.h" #include "nsDirectoryService.h" #include "nsDirectoryServiceDefs.h" #include "nsLocalFile.h" @@ -45,6 +46,10 @@ #include "nsStaticAtom.h" #include "nsEnumeratorUtils.h" +#include "nsICategoryManager.h" +#include "nsISimpleEnumerator.h" +#include "nsIStringEnumerator.h" + #if defined(XP_MAC) #include #include @@ -120,7 +125,7 @@ nsDirectoryService::GetCurrentProcessDirectory(nsILocalFile** aFile) *aFile = nsnull; // Set the component registry location: - if (!mService) + if (!gService) return NS_ERROR_FAILURE; nsresult rv; @@ -399,7 +404,7 @@ nsIAtom* nsDirectoryService::sSystemDirectory = nsnull; #endif -nsDirectoryService* nsDirectoryService::mService = nsnull; +nsDirectoryService* nsDirectoryService::gService = nsnull; nsDirectoryService::nsDirectoryService() : mHashtable(256, PR_TRUE) @@ -410,13 +415,14 @@ NS_METHOD nsDirectoryService::Create(nsISupports *outer, REFNSIID aIID, void **aResult) { NS_ENSURE_ARG_POINTER(aResult); - if (!mService) + NS_ENSURE_NO_AGGREGATION(outer); + + if (!gService) { - mService = new nsDirectoryService(); - if (!mService) - return NS_ERROR_OUT_OF_MEMORY; + return NS_ERROR_NOT_INITIALIZED; } - return mService->QueryInterface(aIID, aResult); + + return gService->QueryInterface(aIID, aResult); } static const nsStaticAtom directory_atoms[] = { @@ -503,13 +509,27 @@ static const nsStaticAtom directory_atoms[] = { #endif }; -nsresult +NS_IMETHODIMP nsDirectoryService::Init() { + NS_NOTREACHED("Don't call me, I was for internal use only!"); + return NS_OK; +} + +nsresult +nsDirectoryService::RealInit() +{ + NS_ASSERTION(!gService, "Mustn't initialize twice!"); + nsresult rv; - - rv = NS_NewISupportsArray(getter_AddRefs(mProviders)); - if (NS_FAILED(rv)) return rv; + + nsRefPtr self = new nsDirectoryService(); + if (!self) + return NS_ERROR_OUT_OF_MEMORY; + + rv = NS_NewISupportsArray(getter_AddRefs(self->mProviders)); + if (NS_FAILED(rv)) + return rv; NS_RegisterStaticAtoms(directory_atoms, NS_ARRAY_LENGTH(directory_atoms)); @@ -518,9 +538,12 @@ nsDirectoryService::Init() if (!defaultProvider) return NS_ERROR_OUT_OF_MEMORY; // AppendElement returns PR_TRUE for success. - rv = mProviders->AppendElement(defaultProvider) ? NS_OK : NS_ERROR_FAILURE; + rv = self->mProviders->AppendElement(defaultProvider) ? NS_OK : NS_ERROR_FAILURE; + if (NS_FAILED(rv)) + return rv; - return rv; + self.swap(gService); + return NS_OK; } PRBool @@ -533,9 +556,6 @@ nsDirectoryService::ReleaseValues(nsHashKey* key, void* data, void* closure) nsDirectoryService::~nsDirectoryService() { - // clear the global - mService = nsnull; - } NS_IMPL_THREADSAFE_ISUPPORTS4(nsDirectoryService, nsIProperties, nsIDirectoryService, nsIDirectoryServiceProvider, nsIDirectoryServiceProvider2) @@ -720,6 +740,38 @@ nsDirectoryService::RegisterProvider(nsIDirectoryServiceProvider *prov) return mProviders->AppendElement(supports) ? NS_OK : NS_ERROR_FAILURE; } +void +nsDirectoryService::RegisterCategoryProviders() +{ + nsCOMPtr catman + (do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (!catman) + return; + + nsCOMPtr entries; + catman->EnumerateCategory(XPCOM_DIRECTORY_PROVIDER_CATEGORY, + getter_AddRefs(entries)); + + nsCOMPtr strings(do_QueryInterface(entries)); + if (!strings) + return; + + PRBool more; + while (NS_SUCCEEDED(strings->HasMore(&more)) && more) { + nsCAutoString entry; + strings->GetNext(entry); + + nsXPIDLCString contractID; + catman->GetCategoryEntry(XPCOM_DIRECTORY_PROVIDER_CATEGORY, entry.get(), getter_Copies(contractID)); + + if (contractID) { + nsCOMPtr provider = do_GetService(contractID.get()); + if (provider) + RegisterProvider(provider); + } + } +} + NS_IMETHODIMP nsDirectoryService::UnregisterProvider(nsIDirectoryServiceProvider *prov) { diff --git a/xpcom/io/nsDirectoryService.h b/xpcom/io/nsDirectoryService.h index d0d8aadb3c9..406d8e9fb8b 100644 --- a/xpcom/io/nsDirectoryService.h +++ b/xpcom/io/nsDirectoryService.h @@ -67,16 +67,19 @@ class nsDirectoryService : public nsIDirectoryService, NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 nsDirectoryService(); + ~nsDirectoryService(); + + static nsresult RealInit(); + void RegisterCategoryProviders(); static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); -private: - ~nsDirectoryService(); + static nsDirectoryService* gService; +private: nsresult GetCurrentProcessDirectory(nsILocalFile** aFile); - static nsDirectoryService* mService; static PRBool PR_CALLBACK ReleaseValues(nsHashKey* key, void* data, void* closure); nsSupportsHashtable mHashtable; nsCOMPtr mProviders;