--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -731,16 +731,22 @@ PRUint8* nsZipArchive::GetData(nsZipItem
// -- check if there is enough source data in the file
if (offset + aItem->Size() > len)
return nsnull;
return data + offset;
}
+PRBool
+nsZipArchive::CheckCRC(nsZipItem* aItem, PRUint8* aItemData) {
+ PRUint32 crc = crc32(0, (const unsigned char*)aItemData, aItem->Size());
+ return crc == aItem->CRC32();
+}
+
//------------------------------------------
// nsZipArchive constructor and destructor
//------------------------------------------
nsZipArchive::nsZipArchive() :
mBuiltSynthetics(false)
{
MOZ_COUNT_CTOR(nsZipArchive);
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -191,16 +191,18 @@ public:
/**
* Get pointer to the data of the item.
* @param aItem Pointer to nsZipItem
* reutrns null when zip file is corrupt.
*/
PRUint8* GetData(nsZipItem* aItem);
+ PRBool CheckCRC(nsZipItem* aItem, PRUint8* aData);
+
private:
//--- private members ---
nsZipItem* mFiles[ZIP_TABSIZE];
PLArenaPool mArena;
// Whether we synthesized the directory entries
bool mBuiltSynthetics;
new file mode 100644
--- /dev/null
+++ b/startupcache/Makefile.in
@@ -0,0 +1,82 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Startup Cache.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Benedict Hsieh <bhsieh@mozilla.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+
+DEPTH = ..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = $(NULL)
+
+ifdef ENABLE_TESTS
+TOOL_DIRS += test
+endif
+
+MODULE = startupcache
+MODULE_NAME = StartupCacheModule
+LIBRARY_NAME = startupcache
+SHORT_LIBNAME = scache
+EXPORT_LIBRARY = 1
+LIBXUL_LIBRARY = 1
+IS_COMPONENT = 1
+GRE_MODULE = 1
+
+CPPSRCS = StartupCache.cpp \
+ StartupCacheUtils.cpp \
+ StartupCacheModule.cpp \
+ $(NULL)
+
+EXPORTS_NAMESPACES = mozilla/scache
+EXPORTS_mozilla/scache = StartupCache.h \
+ StartupCacheUtils.h \
+ $(NULL)
+
+XPIDLSRCS = nsIStartupCache.idl \
+ $(NULL)
+
+EXTRA_DSO_LDOPTS += \
+ $(LIBS_DIR) \
+ $(ZLIB_LIBS) \
+ $(MOZ_COMPONENT_LIBS) \
+ $(NULL)
+
+
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/startupcache/StartupCache.cpp
@@ -0,0 +1,633 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Startup Cache.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Benedict Hsieh <bhsieh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "prio.h"
+#include "prtypes.h"
+#include "pldhash.h"
+#include "mozilla/scache/StartupCache.h"
+
+#include "nsAutoPtr.h"
+#include "nsClassHashtable.h"
+#include "nsComponentManagerUtils.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsIClassInfo.h"
+#include "nsIFile.h"
+#include "nsILocalFile.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsIOutputStream.h"
+#include "nsIStartupCache.h"
+#include "nsIStorageStream.h"
+#include "nsIStreamBufferAccess.h"
+#include "nsIStringStream.h"
+#include "nsISupports.h"
+#include "nsITimer.h"
+#include "nsIZipWriter.h"
+#include "nsIZipReader.h"
+#include "nsWeakReference.h"
+#include "nsZipArchive.h"
+
+#ifdef IS_BIG_ENDIAN
+#define SC_ENDIAN "big"
+#else
+#define SC_ENDIAN "little"
+#endif
+
+#if PR_BYTES_PER_WORD == 4
+#define SC_WORDSIZE "4"
+#else
+#define SC_WORDSIZE "8"
+#endif
+
+namespace mozilla {
+namespace scache {
+
+static const char sStartupCacheName[] = "startupCache." SC_WORDSIZE "." SC_ENDIAN;
+static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
+
+StartupCache*
+StartupCache::GetSingleton()
+{
+ if (!gStartupCache)
+ StartupCache::InitSingleton();
+
+ return StartupCache::gStartupCache;
+}
+
+void
+StartupCache::DeleteSingleton()
+{
+ delete StartupCache::gStartupCache;
+}
+
+nsresult
+StartupCache::InitSingleton()
+{
+ nsresult rv;
+ StartupCache::gStartupCache = new StartupCache();
+
+ rv = StartupCache::gStartupCache->Init();
+ if (NS_FAILED(rv)) {
+ delete StartupCache::gStartupCache;
+ }
+ return rv;
+}
+
+StartupCache* StartupCache::gStartupCache;
+PRBool StartupCache::gShutdownInitiated;
+
+StartupCache::StartupCache()
+ : mArchive(NULL), mStartupWriteInitiated(PR_FALSE) { }
+
+StartupCache::~StartupCache()
+{
+ if (mTable.Count() > 0) {
+ NS_WARNING("Shutting down with entries in startupcache, these will be lost");
+ }
+ gStartupCache = nsnull;
+}
+
+nsresult
+StartupCache::Init()
+{
+ nsresult rv;
+ mTable.Init();
+#ifdef DEBUG
+ mWriteObjectMap.Init();
+#endif
+
+ mZipW = do_CreateInstance("@mozilla.org/zipwriter;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIFile> file;
+ rv = NS_GetSpecialDirectory("ProfLDS",
+ getter_AddRefs(file));
+ if (NS_FAILED(rv)) {
+ // return silently, this will fail in mochitests's xpcshell process.
+ return rv;
+ }
+
+ rv = file->AppendNative(NS_LITERAL_CSTRING("startupCache"));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Try to create the directory if it's not there yet
+ rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
+ if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)
+ return rv;
+
+ rv = file->AppendNative(NS_LITERAL_CSTRING(sStartupCacheName));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mFile = do_QueryInterface(file);
+ NS_ENSURE_TRUE(mFile, NS_ERROR_UNEXPECTED);
+
+ mObserverService = do_GetService("@mozilla.org/observer-service;1");
+
+ if (!mObserverService) {
+ NS_WARNING("Could not get observerService.");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ mListener = new StartupCacheListener();
+ rv = mObserverService->AddObserver(mListener, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
+ PR_FALSE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = LoadArchive();
+
+ // Sometimes we don't have a cache yet, that's ok.
+ // If it's corrupted, just remove it and start over.
+ if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
+ NS_WARNING("Failed to load startupcache file correctly, removing!");
+ InvalidateCache();
+ }
+
+ mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ // Wait for 10 seconds, then write out the cache.
+ rv = mTimer->InitWithFuncCallback(StartupCache::WriteTimeout, this, 10000,
+ nsITimer::TYPE_ONE_SHOT);
+
+ return rv;
+}
+
+nsresult
+StartupCache::LoadArchive()
+{
+ PRBool exists;
+ mArchive = NULL;
+ nsresult rv = mFile->Exists(&exists);
+ if (NS_FAILED(rv) || !exists)
+ return NS_ERROR_FILE_NOT_FOUND;
+
+ mArchive = new nsZipArchive();
+ return mArchive->OpenArchive(mFile);
+}
+
+// NOTE: this will not find a new entry until it has been written to disk!
+// Consumer should take ownership of the resulting buffer.
+nsresult
+StartupCache::GetBuffer(const char* id, char** outbuf, PRUint32* length)
+{
+ PRBool exists;
+ char* data = NULL;
+ PRUint32 len;
+
+ if (!mStartupWriteInitiated) {
+ CacheEntry* entry;
+ nsDependentCString idStr(id);
+ mTable.Get(idStr, &entry);
+ if (entry) {
+ data = entry->data;
+ len = entry->size;
+ }
+ }
+
+ if (!data && mArchive) {
+ nsZipItem* zipItem = mArchive->GetItem(id);
+ if (zipItem) {
+ PRUint8* itemData = mArchive->GetData(zipItem);
+ if (!itemData || !mArchive->CheckCRC(zipItem, itemData)) {
+ NS_WARNING("StartupCache file corrupted!");
+ InvalidateCache();
+ return NS_ERROR_FILE_CORRUPTED;
+ }
+
+ len = zipItem->Size();
+ data = (char*) itemData;
+ }
+ }
+
+ if (data) {
+ *outbuf = new char[len];
+ memcpy(*outbuf, data, len);
+ *length = len;
+ return NS_OK;
+ }
+
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+// Makes a copy of the buffer, client retains ownership of inbuf.
+nsresult
+StartupCache::PutBuffer(const char* id, const char* inbuf, PRUint32 len)
+{
+ nsresult rv;
+
+ if (StartupCache::gShutdownInitiated) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsAutoArrayPtr<char> data(new char[len]);
+ memcpy(data, inbuf, len);
+
+ nsDependentCString idStr(id);
+ if (!mStartupWriteInitiated) {
+ // Cache it for now, we'll write all together later.
+ CacheEntry* entry;
+
+#ifdef DEBUG
+ mTable.Get(idStr, &entry);
+ NS_ASSERTION(entry == nsnull, "Existing entry in StartupCache.");
+
+ if (mArchive) {
+ nsZipItem* zipItem = mArchive->GetItem(id);
+ NS_ASSERTION(zipItem == nsnull, "Existing entry in disk StartupCache.");
+ }
+#endif
+
+ entry = new CacheEntry(data.forget(), len);
+ mTable.Put(idStr, entry);
+ return NS_OK;
+ }
+
+ rv = mZipW->Open(mFile, PR_RDWR | PR_CREATE_FILE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // XXX We need to think about whether to write this out every time,
+ // or somehow detect a good time to write. We need to finish writing
+ // before shutdown though, and writing also requires a reload of the
+ // reader's archive, which probably can't handle having the underlying
+ // file change underneath it. Potentially could reload on the next
+ // read request, if this is a problem. See Bug 586859.
+#ifdef DEBUG
+ PRBool hasEntry;
+ rv = mZipW->HasEntry(idStr, &hasEntry);
+ NS_ENSURE_SUCCESS(rv, rv);
+ NS_ASSERTION(hasEntry == PR_FALSE, "Existing entry in disk StartupCache.");
+#endif
+
+ nsCOMPtr<nsIStringInputStream> stream
+ = do_CreateInstance("@mozilla.org/io/string-input-stream;1",
+ &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = stream->AdoptData(data, len);
+ NS_ENSURE_SUCCESS(rv, rv);
+ data.forget();
+
+ rv = mZipW->AddEntryStream(idStr, 0, 0, stream, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Close the archive so Windows doesn't choke.
+ mArchive = NULL;
+ rv = mZipW->Close();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // our reader's view of the archive is outdated now, reload it.
+ return LoadArchive();
+}
+
+struct CacheWriteHolder
+{
+ nsCOMPtr<nsIZipWriter> writer;
+ nsCOMPtr<nsIStringInputStream> stream;
+};
+
+PLDHashOperator
+CacheCloseHelper(const nsACString& key, nsAutoPtr<CacheEntry>& data,
+ void* closure)
+{
+ nsresult rv;
+
+ CacheWriteHolder* holder = (CacheWriteHolder*) closure;
+ nsIStringInputStream* stream = holder->stream;
+ nsIZipWriter* writer = holder->writer;
+
+ stream->ShareData(data->data, data->size);
+
+#ifdef DEBUG
+ PRBool hasEntry;
+ rv = writer->HasEntry(key, &hasEntry);
+ NS_ASSERTION(NS_SUCCEEDED(rv) && hasEntry == PR_FALSE,
+ "Existing entry in disk StartupCache.");
+#endif
+ rv = writer->AddEntryStream(key, 0, 0, stream, false);
+
+ if (NS_FAILED(rv)) {
+ NS_WARNING("cache entry deleted but not written to disk.");
+ }
+ return PL_DHASH_REMOVE;
+}
+
+void
+StartupCache::WriteToDisk()
+{
+ nsresult rv;
+ mStartupWriteInitiated = PR_TRUE;
+
+ if (gShutdownInitiated) {
+ NS_WARNING("xpcom-shutdown recieved before initial write, will not write");
+ // The dtor would clear for us, but we clear here so that StartupWriteComplete()
+ // will return true instead of waiting for the table to finish clearing.
+ // This mechanism will change when IO is moved off-thread (bug 586859).
+ mTable.Clear();
+ return;
+ }
+
+ if (mTable.Count() == 0)
+ return;
+
+ rv = mZipW->Open(mFile, PR_RDWR | PR_CREATE_FILE);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("could not open zipfile for write");
+ return;
+ }
+
+ nsCOMPtr<nsIStringInputStream> stream
+ = do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Couldn't create string input stream.");
+ return;
+ }
+
+ CacheWriteHolder holder;
+ holder.stream = stream;
+ holder.writer = mZipW;
+
+ mTable.Enumerate(CacheCloseHelper, &holder);
+
+ // Close the archive so Windows doesn't choke.
+ mArchive = NULL;
+ mZipW->Close();
+
+ // our reader's view of the archive is outdated now, reload it.
+ LoadArchive();
+
+ return;
+}
+
+void
+StartupCache::InvalidateCache()
+{
+ mTable.Clear();
+ mArchive = NULL;
+
+ // This is usually closed, but it's possible to get into
+ // an inconsistent state.
+ mZipW->Close();
+ mFile->Remove(false);
+ LoadArchive();
+}
+
+void
+StartupCache::WriteTimeout(nsITimer *aTimer, void *aClosure)
+{
+ StartupCache* sc = (StartupCache*) aClosure;
+ sc->WriteToDisk();
+}
+
+// We don't want to refcount StartupCache, so we'll just
+// hold a ref to this and pass it to observerService instead.
+NS_IMPL_THREADSAFE_ISUPPORTS1(StartupCacheListener, nsIObserver)
+
+nsresult
+StartupCacheListener::Observe(nsISupports *subject, const char* topic, const PRUnichar* data)
+{
+ nsresult rv = NS_OK;
+ if (strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+ StartupCache::gShutdownInitiated = PR_TRUE;
+ }
+ return rv;
+}
+
+nsresult
+StartupCache::GetDebugObjectOutputStream(nsIObjectOutputStream* aStream,
+ nsIObjectOutputStream** aOutStream)
+{
+ NS_ENSURE_ARG_POINTER(aStream);
+#ifdef DEBUG
+ StartupCacheDebugOutputStream* stream
+ = new StartupCacheDebugOutputStream(aStream, &mWriteObjectMap);
+ NS_ADDREF(*aOutStream = stream);
+#else
+ NS_ADDREF(*aOutStream = aStream);
+#endif
+
+ return NS_OK;
+}
+
+// StartupCacheDebugOutputStream implementation
+#ifdef DEBUG
+NS_IMPL_ISUPPORTS3(StartupCacheDebugOutputStream, nsIObjectOutputStream,
+ nsIBinaryOutputStream, nsIOutputStream)
+
+PRBool
+StartupCacheDebugOutputStream::CheckReferences(nsISupports* aObject)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aObject);
+ if (!classInfo) {
+ NS_ERROR("aObject must implement nsIClassInfo");
+ return PR_FALSE;
+ }
+
+ PRUint32 flags;
+ rv = classInfo->GetFlags(&flags);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (flags & nsIClassInfo::SINGLETON)
+ return PR_TRUE;
+
+ nsISupportsHashKey* key = mObjectMap->GetEntry(aObject);
+ if (key) {
+ NS_ERROR("non-singleton aObject is referenced multiple times in this"
+ "serialization, we don't support that.");
+ return PR_FALSE;
+ }
+
+ mObjectMap->PutEntry(aObject);
+ return PR_TRUE;
+}
+
+// nsIObjectOutputStream implementation
+nsresult
+StartupCacheDebugOutputStream::WriteObject(nsISupports* aObject, PRBool aIsStrongRef)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
+
+ NS_ASSERTION(rootObject.get() == aObject,
+ "bad call to WriteObject -- call WriteCompoundObject!");
+ PRBool check = CheckReferences(aObject);
+ NS_ENSURE_TRUE(check, NS_ERROR_FAILURE);
+ return mBinaryStream->WriteObject(aObject, aIsStrongRef);
+}
+
+nsresult
+StartupCacheDebugOutputStream::WriteSingleRefObject(nsISupports* aObject)
+{
+ nsresult rv;
+ nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
+
+ NS_ASSERTION(rootObject.get() == aObject,
+ "bad call to WriteSingleRefObject -- call WriteCompoundObject!");
+ PRBool check = CheckReferences(aObject);
+ NS_ENSURE_TRUE(check, NS_ERROR_FAILURE);
+ return mBinaryStream->WriteSingleRefObject(aObject);
+}
+
+nsresult
+StartupCacheDebugOutputStream::WriteCompoundObject(nsISupports* aObject,
+ const nsIID& aIID,
+ PRBool aIsStrongRef)
+{
+ nsresult rv;
+ nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
+
+ nsCOMPtr<nsISupports> roundtrip;
+ rootObject->QueryInterface(aIID, getter_AddRefs(roundtrip));
+ NS_ASSERTION(roundtrip.get() == aObject,
+ "bad aggregation or multiple inheritance detected by call to "
+ "WriteCompoundObject!");
+
+ PRBool check = CheckReferences(aObject);
+ NS_ENSURE_TRUE(check, NS_ERROR_FAILURE);
+ return mBinaryStream->WriteCompoundObject(aObject, aIID, aIsStrongRef);
+}
+
+nsresult
+StartupCacheDebugOutputStream::WriteID(nsID const& aID)
+{
+ return mBinaryStream->WriteID(aID);
+}
+
+char*
+StartupCacheDebugOutputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask)
+{
+ return mBinaryStream->GetBuffer(aLength, aAlignMask);
+}
+
+void
+StartupCacheDebugOutputStream::PutBuffer(char* aBuffer, PRUint32 aLength)
+{
+ mBinaryStream->PutBuffer(aBuffer, aLength);
+}
+#endif //DEBUG
+
+StartupCacheWrapper* StartupCacheWrapper::gStartupCacheWrapper = nsnull;
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(StartupCacheWrapper, nsIStartupCache)
+
+StartupCacheWrapper* StartupCacheWrapper::GetSingleton()
+{
+ if (!gStartupCacheWrapper)
+ gStartupCacheWrapper = new StartupCacheWrapper();
+
+ NS_ADDREF(gStartupCacheWrapper);
+ return gStartupCacheWrapper;
+}
+
+nsresult
+StartupCacheWrapper::GetBuffer(const char* id, char** outbuf, PRUint32* length)
+{
+ StartupCache* sc = StartupCache::GetSingleton();
+ if (!sc) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ return sc->GetBuffer(id, outbuf, length);
+}
+
+nsresult
+StartupCacheWrapper::PutBuffer(const char* id, char* inbuf, PRUint32 length)
+{
+ StartupCache* sc = StartupCache::GetSingleton();
+ if (!sc) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ return sc->PutBuffer(id, inbuf, length);
+}
+
+nsresult
+StartupCacheWrapper::InvalidateCache()
+{
+ StartupCache* sc = StartupCache::GetSingleton();
+ if (!sc) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ sc->InvalidateCache();
+ return NS_OK;
+}
+
+nsresult
+StartupCacheWrapper::GetDebugObjectOutputStream(nsIObjectOutputStream* stream,
+ nsIObjectOutputStream** outStream)
+{
+ StartupCache* sc = StartupCache::GetSingleton();
+ if (!sc) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ return sc->GetDebugObjectOutputStream(stream, outStream);
+}
+
+nsresult
+StartupCacheWrapper::StartupWriteComplete(PRBool *complete)
+{
+ StartupCache* sc = StartupCache::GetSingleton();
+ if (!sc) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ *complete = sc->mStartupWriteInitiated && sc->mTable.Count() == 0;
+ return NS_OK;
+}
+
+nsresult
+StartupCacheWrapper::ResetStartupWriteTimer()
+{
+ StartupCache* sc = StartupCache::GetSingleton();
+ if (!sc) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ sc->mStartupWriteInitiated = PR_FALSE;
+ sc->mTimer->InitWithFuncCallback(StartupCache::WriteTimeout, sc, 10000,
+ nsITimer::TYPE_ONE_SHOT);
+ return NS_OK;
+}
+
+nsresult
+StartupCacheWrapper::GetObserver(nsIObserver** obv) {
+ StartupCache* sc = StartupCache::GetSingleton();
+ if (!sc) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ NS_ADDREF(*obv = sc->mListener);
+ return NS_OK;
+}
+
+} // namespace scache
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/startupcache/StartupCache.h
@@ -0,0 +1,223 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Startup Cache.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Benedict Hsieh <bhsieh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef StartupCache_h_
+#define StartupCache_h_
+
+#include "prio.h"
+#include "prtypes.h"
+
+#include "nsClassHashtable.h"
+#include "nsIZipWriter.h"
+#include "nsIZipReader.h"
+#include "nsComponentManagerUtils.h"
+#include "nsZipArchive.h"
+#include "nsIStartupCache.h"
+#include "nsIStorageStream.h"
+#include "nsITimer.h"
+#include "nsIObserverService.h"
+#include "nsIObserver.h"
+#include "nsIOutputStream.h"
+#include "nsIFile.h"
+
+/**
+ * The StartupCache is a persistent cache of simple key-value pairs,
+ * where the keys are null-terminated c-strings and the values are
+ * arbitrary data, passed as a (char*, size) tuple.
+ *
+ * Clients should use the GetSingleton() static method to access the cache. It
+ * will be available from the end of XPCOM init (NS_InitXPCOM3 in nsXPComInit.cpp),
+ * until XPCOM shutdown begins. The GetSingleton() method will return null if the cache
+ * is unavailable. The cache is only provided for libxul builds --
+ * it will fail to link in non-libxul builds. The XPCOM interface is provided
+ * only to allow compiled-code tests; clients should avoid using it.
+ *
+ * The API provided is very simple: GetBuffer() returns a buffer that was previously
+ * stored in the cache (if any), and PutBuffer() inserts a buffer into the cache.
+ * GetBuffer returns a new buffer, and the caller must take ownership of it.
+ * PutBuffer will assert if the client attempts to insert a buffer with the same name as
+ * an existing entry. The cache makes a copy of the passed-in buffer, so client
+ * retains ownership.
+ *
+ * InvalidateCache() may be called if a client suspects data corruption
+ * or wishes to invalidate for any other reason. This will remove all existing cache data.
+ * Finally, getDebugObjectOutputStream() allows debug code to wrap an objectstream
+ * with a debug objectstream, to check for multiply-referenced objects. These will
+ * generally fail to deserialize correctly, unless they are stateless singletons or the
+ * client maintains their own object data map for deserialization.
+ *
+ * Writes before the final-ui-startup notification are placed in an intermediate
+ * cache in memory, then written out to disk at a later time, to get writes off the
+ * startup path. In any case, clients should not rely on being able to GetBuffer()
+ * data that is written to the cache, since it may not have been written to disk or
+ * another client may have invalidated the cache. In other words, it should be used as
+ * a cache only, and not a reliable persistent store.
+ *
+ * Some utility functions are provided in StartupCacheUtils. These functions wrap the
+ * buffers into object streams, which may be useful for serializing objects. Note
+ * the above caution about multiply-referenced objects, though -- the streams are just
+ * as 'dumb' as the underlying buffers about multiply-referenced objects. They just
+ * provide some convenience in writing out data.
+ */
+
+namespace mozilla {
+namespace scache {
+
+struct CacheEntry
+{
+ nsAutoArrayPtr<char> data;
+ PRUint32 size;
+
+ CacheEntry() : data(nsnull), size(0) { }
+
+ // Takes possession of buf
+ CacheEntry(char* buf, PRUint32 len) : data(buf), size(len) { }
+
+ ~CacheEntry()
+ {
+ }
+};
+
+// We don't want to refcount StartupCache, and ObserverService wants to
+// refcount its listeners, so we'll let it refcount this instead.
+class StartupCacheListener : public nsIObserver
+{
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+};
+
+class StartupCache
+{
+
+friend class StartupCacheListener;
+friend class StartupCacheWrapper;
+
+public:
+
+ // StartupCache methods. See above comments for a more detailed description.
+
+ // Returns a buffer that was previously stored, caller takes ownership.
+ nsresult GetBuffer(const char* id, char** outbuf, PRUint32* length);
+
+ // Stores a buffer. Caller keeps ownership, we make a copy.
+ nsresult PutBuffer(const char* id, const char* inbuf, PRUint32 length);
+
+ // Removes the cache file.
+ void InvalidateCache();
+
+ // In DEBUG builds, returns a stream that will attempt to check for
+ // and disallow multiple writes of the same object.
+ nsresult GetDebugObjectOutputStream(nsIObjectOutputStream* aStream,
+ nsIObjectOutputStream** outStream);
+
+ static StartupCache* GetSingleton();
+ static void DeleteSingleton();
+
+private:
+ StartupCache();
+ ~StartupCache();
+
+ nsresult LoadArchive();
+ nsresult Init();
+ void WriteToDisk();
+
+ static nsresult InitSingleton();
+ static void WriteTimeout(nsITimer *aTimer, void *aClosure);
+
+ nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
+ nsCOMPtr<nsIZipWriter> mZipW;
+ nsAutoPtr<nsZipArchive> mArchive;
+ nsCOMPtr<nsILocalFile> mFile;
+
+ nsCOMPtr<nsIObserverService> mObserverService;
+ nsRefPtr<StartupCacheListener> mListener;
+ nsCOMPtr<nsITimer> mTimer;
+
+ PRBool mStartupWriteInitiated;
+
+ static StartupCache *gStartupCache;
+ static PRBool gShutdownInitiated;
+
+#ifdef DEBUG
+ nsTHashtable<nsISupportsHashKey> mWriteObjectMap;
+#endif
+};
+
+// This debug outputstream attempts to detect if clients are writing multiple
+// references to the same object. We only support that if that object
+// is a singleton.
+#ifdef DEBUG
+class StartupCacheDebugOutputStream
+ : public nsIObjectOutputStream
+{
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBJECTOUTPUTSTREAM
+
+ StartupCacheDebugOutputStream (nsIObjectOutputStream* binaryStream,
+ nsTHashtable<nsISupportsHashKey>* objectMap)
+ : mBinaryStream(binaryStream), mObjectMap(objectMap) { }
+
+ NS_FORWARD_SAFE_NSIBINARYOUTPUTSTREAM(mBinaryStream)
+ NS_FORWARD_SAFE_NSIOUTPUTSTREAM(mBinaryStream)
+
+ PRBool CheckReferences(nsISupports* aObject);
+
+ nsCOMPtr<nsIObjectOutputStream> mBinaryStream;
+ nsTHashtable<nsISupportsHashKey> *mObjectMap;
+};
+#endif // DEBUG
+
+// XPCOM wrapper interface provided for tests only.
+#define NS_STARTUPCACHE_CID \
+ {0xae4505a9, 0x87ab, 0x477c, \
+ {0xb5, 0x77, 0xf9, 0x23, 0x57, 0xed, 0xa8, 0x84}}
+// contract id: "@mozilla.org/startupcache/cache;1"
+
+class StartupCacheWrapper
+ : public nsIStartupCache
+{
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISTARTUPCACHE
+
+ static StartupCacheWrapper* GetSingleton();
+ static StartupCacheWrapper *gStartupCacheWrapper;
+};
+
+} // namespace scache
+} // namespace mozilla
+#endif //StartupCache_h_
new file mode 100644
--- /dev/null
+++ b/startupcache/StartupCacheModule.cpp
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Startup Cache.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Benedict Hsieh <bhsieh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string.h>
+
+#include "nscore.h"
+#include "pratom.h"
+#include "prmem.h"
+#include "prio.h"
+#include "plstr.h"
+#include "prlog.h"
+
+#include "nsID.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsCOMPtr.h"
+#include "nsIModule.h"
+#include "mozilla/ModuleUtils.h"
+#include "mozilla/scache/StartupCache.h"
+
+using namespace mozilla::scache;
+
+// XXX Need help with guard for ENABLE_TEST
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(StartupCacheWrapper,
+ StartupCacheWrapper::GetSingleton)
+NS_DEFINE_NAMED_CID(NS_STARTUPCACHE_CID);
+
+static const mozilla::Module::CIDEntry kStartupCacheCIDs[] = {
+ { &kNS_STARTUPCACHE_CID, false, NULL, StartupCacheWrapperConstructor },
+ { NULL }
+};
+
+static const mozilla::Module::ContractIDEntry kStartupCacheContracts[] = {
+ { "@mozilla.org/startupcache/cache;1", &kNS_STARTUPCACHE_CID },
+ { NULL }
+};
+
+static const mozilla::Module kStartupCacheModule = {
+ mozilla::Module::kVersion,
+ kStartupCacheCIDs,
+ kStartupCacheContracts,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+NSMODULE_DEFN(StartupCacheModule) = &kStartupCacheModule;
new file mode 100644
--- /dev/null
+++ b/startupcache/StartupCacheUtils.cpp
@@ -0,0 +1,90 @@
+
+#include "nsCOMPtr.h"
+#include "nsIInputStream.h"
+#include "nsIStringStream.h"
+#include "nsAutoPtr.h"
+#include "StartupCacheUtils.h"
+#include "mozilla/scache/StartupCache.h"
+
+namespace mozilla {
+namespace scache {
+
+NS_EXPORT nsresult
+NS_NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
+ nsIObjectInputStream** stream)
+{
+ nsCOMPtr<nsIStringInputStream> stringStream
+ = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
+ nsCOMPtr<nsIObjectInputStream> objectInput
+ = do_CreateInstance("@mozilla.org/binaryinputstream;1");
+
+ stringStream->AdoptData(buffer, len);
+ objectInput->SetInputStream(stringStream);
+
+ objectInput.forget(stream);
+ return NS_OK;
+}
+
+NS_EXPORT nsresult
+NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
+ nsIStorageStream** stream)
+{
+ nsresult rv;
+ nsCOMPtr<nsIStorageStream> storageStream
+ = do_CreateInstance("@mozilla.org/storagestream;1");
+
+ rv = storageStream->Init(256, PR_UINT32_MAX, nsnull);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIObjectOutputStream> objectOutput
+ = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
+ nsCOMPtr<nsIOutputStream> outputStream
+ = do_QueryInterface(storageStream);
+
+ objectOutput->SetOutputStream(outputStream);
+
+#ifdef DEBUG
+ // Wrap in debug stream to detect unsupported writes of
+ // multiply-referenced non-singleton objects
+ StartupCache* sc = StartupCache::GetSingleton();
+ NS_ENSURE_TRUE(sc, NS_ERROR_UNEXPECTED);
+ nsCOMPtr<nsIObjectOutputStream> debugStream;
+ sc->GetDebugObjectOutputStream(objectOutput, getter_AddRefs(debugStream));
+ debugStream.forget(wrapperStream);
+#else
+ objectOutput.forget(wrapperStream);
+#endif
+
+ storageStream.forget(stream);
+ return NS_OK;
+}
+
+NS_EXPORT nsresult
+NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
+ char** buffer, PRUint32* len)
+{
+ nsresult rv;
+ nsCOMPtr<nsIInputStream> inputStream;
+ rv = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRUint32 avail, read;
+ rv = inputStream->Available(&avail);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoArrayPtr<char> temp (new char[avail]);
+ rv = inputStream->Read(temp, avail, &read);
+ if (NS_SUCCEEDED(rv) && avail != read)
+ rv = NS_ERROR_UNEXPECTED;
+
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ *len = avail;
+ *buffer = temp.forget();
+ return NS_OK;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/startupcache/StartupCacheUtils.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Startup Cache.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Benedict Hsieh <bhsieh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef nsStartupCacheUtils_h_
+#define nsStartupCacheUtils_h_
+
+#include "nsIStorageStream.h"
+#include "nsIObjectInputStream.h"
+#include "nsIObjectOutputStream.h"
+
+namespace mozilla {
+namespace scache {
+
+NS_EXPORT nsresult
+NS_NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
+ nsIObjectInputStream** stream);
+
+// We can't retrieve the wrapped stream from the objectOutputStream later,
+// so we return it here.
+NS_EXPORT nsresult
+NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
+ nsIStorageStream** stream);
+
+NS_EXPORT nsresult
+NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
+ char** buffer, PRUint32* len);
+}
+}
+#endif //nsStartupCacheUtils_h_
new file mode 100644
--- /dev/null
+++ b/startupcache/nsIStartupCache.idl
@@ -0,0 +1,76 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation startup cache code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Benedict Hsieh <bhsieh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIInputStream.idl"
+#include "nsISupports.idl"
+#include "nsIObserver.idl"
+#include "nsIObjectOutputStream.idl"
+
+[uuid(de798fab-af49-4a61-8144-81550986e1da)]
+interface nsIStartupCache : nsISupports
+{
+
+ /** This interface is provided for testing purposes only, basically
+ * just to solve link vagaries. See docs in StartupCache.h
+ * GetBuffer, PutBuffer, and InvalidateCache act as described
+ * in that file. */
+
+ PRUint32 getBuffer(in string aID, out charPtr aBuffer);
+ void putBuffer(in string aID, in charPtr aBuffer,
+ in PRUint32 aLength);
+
+ void invalidateCache();
+
+ /** In debug builds, wraps this object output stream with a stream that will
+ * detect and prevent the write of a multiply-referenced non-singleton object
+ * during serialization. In non-debug, returns an add-ref'd pointer to
+ * original stream, unwrapped. */
+ nsIObjectOutputStream getDebugObjectOutputStream(in nsIObjectOutputStream aStream);
+
+ /* Allows clients to check whether the one-time writeout after startup
+ * has finished yet, and also to set this variable as needed (so test
+ * code can fire mulitple startup writes if needed).
+ */
+ boolean startupWriteComplete();
+ void resetStartupWriteTimer();
+
+ /* Allows clients to simulate the behavior of ObserverService. */
+ readonly attribute nsIObserver observer;
+};
+
new file mode 100644
--- /dev/null
+++ b/startupcache/nsStartupCacheUtils.cpp
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Startup Cache.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Benedict Hsieh <bhsieh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsStartupCacheUtils.h"
+
+#include "nsCOMPtr.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIInputStream.h"
+#include "nsIStorageStream.h"
+#include "nsIStringStream.h"
+#include "nsIObjectInputStream.h"
+#include "nsIObjectOutputStream.h"
+
+nsresult
+NS_NewObjectInputStreamFromBuffer(char* buffer, int len,
+ nsIObjectInputStream** stream)
+{
+ nsCOMPtr<nsIStringInputStream> stringStream
+ = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
+ if (!stringStream)
+ return NS_ERROR_OUT_OF_MEMORY;
+ nsCOMPtr<nsIObjectInputStream> objectInput
+ = do_CreateInstance("@mozilla.org/binaryinputstream;1");
+ if (!objectInput)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ stringStream->AdoptData(buffer, len);
+ objectInput->SetInputStream(stringStream);
+
+ NS_ADDREF(*stream = objectInput);
+ return NS_OK;
+}
+
+// This is questionable API name and design, but we can't
+// retrieve the wrapped stream from the objectOutputStream later...
+nsresult
+NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
+ nsIStorageStream** stream)
+{
+ nsCOMPtr<nsIStorageStream> storageStream;
+ nsresult rv = NS_NewStorageStream(256, (PRUint32)-1,
+ getter_AddRefs(storageStream));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIObjectOutputStream> objectOutput
+ = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
+ if (!objectOutput)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsCOMPtr<nsIOutputStream> outputStream
+ = do_QueryInterface(storageStream);
+
+ objectOutput->SetOutputStream(outputStream);
+ NS_ADDREF(*wrapperStream = objectOutput);
+ NS_ADDREF(*stream = storageStream);
+ return NS_OK;
+}
+
+nsresult
+NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
+ char** buffer, int* len)
+{
+ nsresult rv;
+ nsCOMPtr<nsIInputStream> inputStream;
+ rv = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRUint32 avail, read;
+ rv = inputStream->Available(&avail);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ char* temp = new char[avail];
+ if (!temp)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ rv = inputStream->Read(temp, avail, &read);
+ if (NS_SUCCEEDED(rv) && avail != read)
+ rv = NS_ERROR_UNEXPECTED;
+
+ if (NS_FAILED(rv)) {
+ delete temp;
+ return rv;
+ }
+
+ *len = avail;
+ *buffer = temp;
+ return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/startupcache/test/Makefile.in
@@ -0,0 +1,53 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla.org.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Benedict Hsieh <bhsieh@mozilla.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = test_startupcache
+
+CPP_UNIT_TESTS = TestStartupCache.cpp
+
+EXTRA_DSO_LIBS += xul
+LIBS += $(MOZ_COMPONENT_LIBS)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/startupcache/test/TestStartupCache.cpp
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Startup Cache.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Benedict Hsieh <bhsieh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "TestHarness.h"
+
+#include "nsThreadUtils.h"
+#include "nsIClassInfo.h"
+#include "nsIOutputStream.h"
+#include "nsIObserver.h"
+#include "nsISerializable.h"
+#include "nsISupports.h"
+#include "nsIStartupCache.h"
+#include "nsIStringStream.h"
+#include "nsIStorageStream.h"
+#include "nsIObjectInputStream.h"
+#include "nsIObjectOutputStream.h"
+#include "nsIURI.h"
+#include "nsStringAPI.h"
+
+namespace mozilla {
+namespace scache {
+
+NS_IMPORT nsresult
+NS_NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
+ nsIObjectInputStream** stream);
+
+// We can't retrieve the wrapped stream from the objectOutputStream later,
+// so we return it here.
+NS_IMPORT nsresult
+NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
+ nsIStorageStream** stream);
+
+NS_IMPORT nsresult
+NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
+ char** buffer, PRUint32* len);
+}
+}
+
+using namespace mozilla::scache;
+
+#define NS_ENSURE_STR_MATCH(str1, str2, testname) \
+PR_BEGIN_MACRO \
+if (0 != strcmp(str1, str2)) { \
+ fail("failed " testname); \
+ return NS_ERROR_FAILURE; \
+} \
+passed("passed " testname); \
+PR_END_MACRO
+
+nsresult
+WaitForStartupTimer() {
+ nsresult rv;
+ nsCOMPtr<nsIStartupCache> sc
+ = do_GetService("@mozilla.org/startupcache/cache;1");
+ PR_Sleep(10 * PR_TicksPerSecond());
+
+ PRBool complete;
+ while (true) {
+ NS_ProcessPendingEvents(nsnull);
+ rv = sc->StartupWriteComplete(&complete);
+ if (NS_FAILED(rv) || complete)
+ break;
+ PR_Sleep(1 * PR_TicksPerSecond());
+ }
+ return rv;
+}
+
+nsresult
+TestStartupWriteRead() {
+ nsresult rv;
+ nsCOMPtr<nsIStartupCache> sc
+ = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
+ if (!sc) {
+ fail("didn't get a pointer...");
+ return NS_ERROR_FAILURE;
+ } else {
+ passed("got a pointer?");
+ }
+ sc->InvalidateCache();
+
+ char* buf = "Market opportunities for BeardBook";
+ char* id = "id";
+ char* outbufPtr = NULL;
+ nsAutoArrayPtr<char> outbuf;
+ PRUint32 len;
+
+ rv = sc->PutBuffer(id, buf, strlen(buf) + 1);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = sc->GetBuffer(id, &outbufPtr, &len);
+ NS_ENSURE_SUCCESS(rv, rv);
+ outbuf = outbufPtr;
+ NS_ENSURE_STR_MATCH(buf, outbuf, "pre-write read");
+
+ rv = WaitForStartupTimer();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = sc->GetBuffer(id, &outbufPtr, &len);
+ NS_ENSURE_SUCCESS(rv, rv);
+ outbuf = outbufPtr;
+ NS_ENSURE_STR_MATCH(buf, outbuf, "simple write/read");
+
+ return NS_OK;
+}
+
+nsresult
+TestWriteInvalidateRead() {
+ nsresult rv;
+ char* buf = "BeardBook competitive analysis";
+ char* id = "id";
+ char* outbuf = NULL;
+ PRUint32 len;
+ nsCOMPtr<nsIStartupCache> sc
+ = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
+ sc->InvalidateCache();
+
+ rv = sc->PutBuffer(id, buf, strlen(buf) + 1);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ sc->InvalidateCache();
+
+ rv = sc->GetBuffer(id, &outbuf, &len);
+ delete[] outbuf;
+ if (rv == NS_ERROR_NOT_AVAILABLE) {
+ passed("buffer not available after invalidate");
+ } else if (NS_SUCCEEDED(rv)) {
+ fail("GetBuffer succeeded unexpectedly after invalidate");
+ return NS_ERROR_UNEXPECTED;
+ } else {
+ fail("GetBuffer gave an unexpected failure, expected NOT_AVAILABLE");
+ return rv;
+ }
+
+ sc->InvalidateCache();
+ return NS_OK;
+}
+
+nsresult
+TestWriteObject() {
+ nsresult rv;
+
+ nsCOMPtr<nsIURI> obj
+ = do_CreateInstance("@mozilla.org/network/simple-uri;1");
+ if (!obj) {
+ fail("did not create object in test write object");
+ return NS_ERROR_UNEXPECTED;
+ }
+ NS_NAMED_LITERAL_CSTRING(spec, "http://www.mozilla.org");
+ obj->SetSpec(spec);
+ nsCOMPtr<nsIStartupCache> sc = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
+
+ sc->InvalidateCache();
+
+ // Create an object stream. Usually this is done with
+ // NS_NewObjectOutputWrappedStorageStream, but that uses
+ // StartupCache::GetSingleton in debug builds, and we
+ // don't have access to that here. Obviously.
+ char* id = "id";
+ nsCOMPtr<nsIStorageStream> storageStream
+ = do_CreateInstance("@mozilla.org/storagestream;1");
+ NS_ENSURE_ARG_POINTER(storageStream);
+
+ rv = storageStream->Init(256, (PRUint32) -1, nsnull);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIObjectOutputStream> objectOutput
+ = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
+ if (!objectOutput)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsCOMPtr<nsIOutputStream> outputStream
+ = do_QueryInterface(storageStream);
+
+ rv = objectOutput->SetOutputStream(outputStream);
+
+ if (NS_FAILED(rv)) {
+ fail("failed to create output stream");
+ return rv;
+ }
+ nsCOMPtr<nsISupports> objQI(do_QueryInterface(obj));
+ rv = objectOutput->WriteObject(objQI, PR_TRUE);
+ if (NS_FAILED(rv)) {
+ fail("failed to write object");
+ return rv;
+ }
+
+ char* bufPtr = NULL;
+ nsAutoArrayPtr<char> buf;
+ PRUint32 len;
+ NS_NewBufferFromStorageStream(storageStream, &bufPtr, &len);
+ buf = bufPtr;
+
+ // Since this is a post-startup write, it should be written and
+ // available.
+ rv = sc->PutBuffer(id, buf, len);
+ if (NS_FAILED(rv)) {
+ fail("failed to insert input stream");
+ return rv;
+ }
+
+ char* buf2Ptr = NULL;
+ nsAutoArrayPtr<char> buf2;
+ PRUint32 len2;
+ nsCOMPtr<nsIObjectInputStream> objectInput;
+ rv = sc->GetBuffer(id, &buf2Ptr, &len2);
+ if (NS_FAILED(rv)) {
+ fail("failed to retrieve buffer");
+ return rv;
+ }
+ buf2 = buf2Ptr;
+
+ rv = NS_NewObjectInputStreamFromBuffer(buf2, len2, getter_AddRefs(objectInput));
+ if (NS_FAILED(rv)) {
+ fail("failed to created input stream");
+ return rv;
+ }
+ buf2.forget();
+
+ nsCOMPtr<nsISupports> deserialized;
+ rv = objectInput->ReadObject(PR_TRUE, getter_AddRefs(deserialized));
+ if (NS_FAILED(rv)) {
+ fail("failed to read object");
+ return rv;
+ }
+
+ PRBool match = false;
+ nsCOMPtr<nsIURI> uri(do_QueryInterface(deserialized));
+ if (uri) {
+ nsCString outSpec;
+ uri->GetSpec(outSpec);
+ match = outSpec.Equals(spec);
+ }
+ if (!match) {
+ fail("deserialized object has incorrect information");
+ return rv;
+ }
+
+ passed("write object");
+ return NS_OK;
+}
+
+nsresult
+TestEarlyShutdown() {
+ nsresult rv;
+ nsCOMPtr<nsIStartupCache> sc
+ = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
+ sc->InvalidateCache();
+
+ char* buf = "Find your soul beardmate on BeardBook";
+ char* id = "id";
+ PRUint32 len;
+ char* outbuf = NULL;
+
+ sc->ResetStartupWriteTimer();
+ rv = sc->PutBuffer(buf, id, strlen(buf) + 1);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIObserver> obs;
+ sc->GetObserver(getter_AddRefs(obs));
+ obs->Observe(nsnull, "xpcom-shutdown", nsnull);
+ rv = WaitForStartupTimer();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = sc->GetBuffer(id, &outbuf, &len);
+ delete[] outbuf;
+
+ if (rv == NS_ERROR_NOT_AVAILABLE) {
+ passed("buffer not available after early shutdown");
+ } else if (NS_SUCCEEDED(rv)) {
+ fail("GetBuffer succeeded unexpectedly after early shutdown");
+ return NS_ERROR_UNEXPECTED;
+ } else {
+ fail("GetBuffer gave an unexpected failure, expected NOT_AVAILABLE");
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+
+int main(int argc, char** argv)
+{
+ int rv = 0;
+ nsresult rv2;
+ ScopedXPCOM xpcom("Startup Cache");
+
+ if (NS_FAILED(TestStartupWriteRead()))
+ rv = 1;
+ if (NS_FAILED(TestWriteInvalidateRead()))
+ rv = 1;
+ if (NS_FAILED(TestWriteObject()))
+ rv = 1;
+ if (NS_FAILED(TestEarlyShutdown()))
+ rv = 1;
+
+ return rv;
+}
--- a/toolkit/library/libxul-config.mk
+++ b/toolkit/library/libxul-config.mk
@@ -134,16 +134,17 @@ endif
# component libraries
COMPONENT_LIBS += \
necko \
uconv \
i18n \
chardet \
jar$(VERSION_NUMBER) \
+ startupcache \
pref \
htmlpars \
imglib2 \
gklayout \
docshell \
embedcomponents \
webbrwsr \
nsappshell \
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -236,16 +236,17 @@
MODULE(nsI18nModule) \
MODULE(nsChardetModule) \
UNIVERSALCHARDET_MODULE \
MODULE(necko) \
PERMISSIONS_MODULES \
AUTH_MODULE \
MODULE(nsJarModule) \
ZIPWRITER_MODULE \
+ MODULE(StartupCacheModule) \
MODULE(nsPrefModule) \
RDF_MODULES \
MODULE(nsParserModule) \
GFX_MODULES \
WIDGET_MODULES \
MODULE(nsImageLib2Module) \
ICON_MODULE \
JETPACK_MODULES \
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -774,16 +774,20 @@ MAKEFILES_extensions="
extensions/cookie/Makefile
extensions/permissions/Makefile
extensions/pref/Makefile
extensions/pref/autoconfig/Makefile
extensions/pref/autoconfig/public/Makefile
extensions/pref/autoconfig/src/Makefile
"
+MAKEFILES_startupcache="
+ startupcache/Makefile
+"
+
add_makefiles "
$MAKEFILES_db
$MAKEFILES_dom
$MAKEFILES_editor
$MAKEFILES_xmlparser
$MAKEFILES_gfx
$MAKEFILES_htmlparser
$MAKEFILES_intl
@@ -815,16 +819,17 @@ add_makefiles "
$MAKEFILES_embedding
$MAKEFILES_xulapp
$MAKEFILES_libpr0n
$MAKEFILES_accessible
$MAKEFILES_zlib
$MAKEFILES_libmar
$MAKEFILES_lib7z
$MAKEFILES_extensions
+ $MAKEFILES_startupcache
"
#
# Conditional makefiles
#
if [ "$ENABLE_TESTS" ]; then
add_makefiles "
@@ -921,16 +926,17 @@ if [ "$ENABLE_TESTS" ]; then
modules/libpref/test/Makefile
modules/plugin/test/Makefile
modules/plugin/test/mochitest/Makefile
modules/plugin/test/testplugin/Makefile
netwerk/test/httpserver/Makefile
parser/htmlparser/tests/mochitest/Makefile
parser/xml/test/Makefile
rdf/tests/triplescat/Makefile
+ startupcache/tests/Makefile
testing/mochitest/Makefile
testing/mochitest/MochiKit/Makefile
testing/mochitest/chrome/Makefile
testing/mochitest/ssltunnel/Makefile
testing/mochitest/static/Makefile
testing/mochitest/tests/Makefile
testing/mochitest/tests/MochiKit-1.4.2/Makefile
testing/mochitest/tests/MochiKit-1.4.2/MochiKit/Makefile
--- a/toolkit/toolkit-tiers.mk
+++ b/toolkit/toolkit-tiers.mk
@@ -235,16 +235,20 @@ tier_platform_dirs += extensions/java/xp
endif
ifndef BUILD_STATIC_LIBS
ifneq (,$(MOZ_ENABLE_GTK2))
tier_platform_dirs += embedding/browser/gtk
endif
endif
+ifdef MOZ_ENABLE_LIBXUL
+tier_platform_dirs += startupcache
+endif
+
ifndef BUILD_STATIC_LIBS
tier_platform_dirs += toolkit/library
endif
ifdef MOZ_ENABLE_LIBXUL
tier_platform_dirs += xpcom/stub
endif
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2486,16 +2486,19 @@ static void RemoveComponentRegistries(ns
if (!file)
return;
file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
file->Remove(PR_FALSE);
file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX));
file->Remove(PR_FALSE);
+
+ file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache"));
+ file->Remove(PR_TRUE);
}
// To support application initiated restart via nsIAppStartup.quit, we
// need to save various environment variables, and then restore them
// before re-launching the application.
static struct {
const char *name;
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -142,16 +142,20 @@ extern nsresult nsStringInputStreamConst
#include <locale.h>
#include "mozilla/Services.h"
#include "mozilla/FunctionTimer.h"
#include "mozilla/Omnijar.h"
#include "nsChromeRegistry.h"
#include "nsChromeProtocolHandler.h"
+#ifdef MOZ_ENABLE_LIBXUL
+#include "mozilla/scache/StartupCache.h"
+#endif
+
#ifdef MOZ_IPC
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "mozilla/ipc/BrowserProcessSubThread.h"
using base::AtExitManager;
@@ -537,16 +541,19 @@ NS_InitXPCOM2(nsIServiceManager* *result
NS_TIME_FUNCTION_MARK("Next: register category providers");
// 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();
+#ifdef MOZ_ENABLE_LIBXUL
+ mozilla::scache::StartupCache::GetSingleton();
+#endif
NS_TIME_FUNCTION_MARK("Next: create services from category");
// Notify observers of xpcom autoregistration start
NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_CATEGORY,
nsnull,
NS_XPCOM_STARTUP_OBSERVER_ID);
return NS_OK;
@@ -614,17 +621,19 @@ ShutdownXPCOM(nsIServiceManager* servMgr
{
(void) observerService->
NotifyObservers(mgr, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
nsnull);
}
}
NS_ProcessPendingEvents(thread);
-
+#ifdef MOZ_ENABLE_LIBXUL
+ mozilla::scache::StartupCache::DeleteSingleton();
+#endif
if (observerService)
(void) observerService->
NotifyObservers(nsnull, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
nsnull);
NS_ProcessPendingEvents(thread);
// Shutdown the timer thread and all timers that might still be alive before
--- a/xpcom/tests/TestHarness.h
+++ b/xpcom/tests/TestHarness.h
@@ -50,16 +50,17 @@
#include "nsAutoPtr.h"
#include "nsStringGlue.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIDirectoryService.h"
#include "nsIFile.h"
#include "nsIProperties.h"
+#include "nsXULAppAPI.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
static PRUint32 gFailCount = 0;
/**
* Prints the given failure message and arguments using printf, prepending
@@ -336,17 +337,18 @@ class ScopedXPCOM : public nsIDirectoryS
if (mDirSvcProvider &&
NS_SUCCEEDED(mDirSvcProvider->GetFile(aProperty, _persistent,
_result))) {
return NS_OK;
}
// Otherwise, the test harness provides some directories automatically.
if (0 == strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) ||
- 0 == strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR)) {
+ 0 == strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR) ||
+ 0 == strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
nsCOMPtr<nsIFile> profD = GetProfileDirectory();
NS_ENSURE_TRUE(profD, NS_ERROR_FAILURE);
nsCOMPtr<nsIFile> clone;
nsresult rv = profD->Clone(getter_AddRefs(clone));
NS_ENSURE_SUCCESS(rv, rv);
*_persistent = PR_TRUE;