Bug 1627075 - Route Omnijar requests through StartupCache r=froydnj

This should be a relatively straightforward patch. Essentially, we implement
a wrapper class (and friends) around nsZipArchive (and friends), which transparently
caches entries from the underlying zip archive in the StartupCache. This will break
without changes to the StartupCache, made in the patch after this, which allow it
to be used off of the main thread, and outside the main process.

Depends on D77635

Differential Revision: https://phabricator.services.mozilla.com/D77634
This commit is contained in:
Doug Thayer 2020-07-01 17:09:53 +00:00
Родитель 42ac8f4294
Коммит ab4b703a53
19 изменённых файлов: 518 добавлений и 132 удалений

Просмотреть файл

@ -95,14 +95,14 @@ already_AddRefed<SharedFTFace> FT2FontEntry::GetFTFace(bool aCommit) {
// here would be memory allocation, in which case mFace remains null.
RefPtr<SharedFTFace> face;
if (mFilename[0] != '/') {
RefPtr<nsZipArchive> reader = Omnijar::GetReader(Omnijar::Type::GRE);
RefPtr<CacheAwareZipReader> reader = Omnijar::GetReader(Omnijar::Type::GRE);
nsZipItem* item = reader->GetItem(mFilename.get());
NS_ASSERTION(item, "failed to find zip entry");
uint32_t bufSize = item->RealSize();
uint8_t* fontDataBuf = static_cast<uint8_t*>(malloc(bufSize));
if (fontDataBuf) {
nsZipCursor cursor(item, reader, fontDataBuf, bufSize);
CacheAwareZipCursor cursor(item, reader, fontDataBuf, bufSize);
cursor.Copy(&bufSize);
NS_ASSERTION(bufSize == item->RealSize(), "error reading bundled font");
RefPtr<FTUserFontData> ufd = new FTUserFontData(fontDataBuf, bufSize);
@ -458,7 +458,8 @@ hb_blob_t* FT2FontEntry::GetFontTable(uint32_t aTableTag) {
} else {
// A relative path means an omnijar resource, which we may need to
// decompress to a temporary buffer.
RefPtr<nsZipArchive> reader = Omnijar::GetReader(Omnijar::Type::GRE);
RefPtr<CacheAwareZipReader> reader =
Omnijar::GetReader(Omnijar::Type::GRE);
nsZipItem* item = reader->GetItem(mFilename.get());
MOZ_ASSERT(item, "failed to find zip entry");
if (item) {
@ -469,7 +470,7 @@ hb_blob_t* FT2FontEntry::GetFontTable(uint32_t aTableTag) {
uint32_t length = item->RealSize();
uint8_t* buffer = static_cast<uint8_t*>(malloc(length));
if (buffer) {
nsZipCursor cursor(item, reader, buffer, length);
CacheAwareZipCursor cursor(item, reader, buffer, length);
cursor.Copy(&length);
MOZ_ASSERT(length == item->RealSize(), "error reading font");
if (length == item->RealSize()) {
@ -1159,7 +1160,7 @@ void gfxFT2FontList::FindFontsInOmnijar(FontNameCache* aCache) {
static const char* sJarSearchPaths[] = {
"res/fonts/*.ttf$",
};
RefPtr<nsZipArchive> reader = Omnijar::GetReader(Omnijar::Type::GRE);
RefPtr<CacheAwareZipReader> reader = Omnijar::GetReader(Omnijar::Type::GRE);
for (unsigned i = 0; i < ArrayLength(sJarSearchPaths); i++) {
nsZipFind* find;
if (NS_SUCCEEDED(reader->FindInit(sJarSearchPaths[i], &find))) {
@ -1274,7 +1275,7 @@ void gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
}
}
void gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
void gfxFT2FontList::AppendFacesFromOmnijarEntry(CacheAwareZipReader* aArchive,
const nsCString& aEntryName,
FontNameCache* aCache,
bool aJarChanged) {
@ -1313,7 +1314,7 @@ void gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
return;
}
nsZipCursor cursor(item, aArchive, (uint8_t*)buffer, bufSize);
CacheAwareZipCursor cursor(item, aArchive, (uint8_t*)buffer, bufSize);
uint8_t* data = cursor.Copy(&bufSize);
MOZ_ASSERT(data && bufSize == item->RealSize(), "error reading bundled font");
if (!data) {

Просмотреть файл

@ -11,6 +11,9 @@
#include "gfxPlatformFontList.h"
namespace mozilla {
class CacheAwareZipReader;
namespace dom {
class SystemFontListEntry;
};
@ -172,7 +175,7 @@ class gfxFT2FontList final : public gfxPlatformFontList {
void AppendFacesFromFontFile(const nsCString& aFileName,
FontNameCache* aCache, StandardFile aStdFile);
void AppendFacesFromOmnijarEntry(nsZipArchive* aReader,
void AppendFacesFromOmnijarEntry(mozilla::CacheAwareZipReader* aArchive,
const nsCString& aEntryName,
FontNameCache* aCache, bool aJarChanged);

Просмотреть файл

@ -228,7 +228,7 @@ void nsHyphenationManager::LoadPatternListFromOmnijar(Omnijar::Type aType) {
return;
}
RefPtr<nsZipArchive> zip = Omnijar::GetReader(aType);
RefPtr<CacheAwareZipReader> zip = Omnijar::GetReader(aType);
if (!zip) {
return;
}

Просмотреть файл

@ -41,20 +41,11 @@ static const void* GetItemPtrFromJarURI(nsIJARURI* aJAR, uint32_t* aLength) {
if (!file) {
return nullptr;
}
RefPtr<nsZipArchive> archive = Omnijar::GetReader(file);
RefPtr<CacheAwareZipReader> archive = Omnijar::GetReader(file);
if (archive) {
nsCString path;
aJAR->GetJAREntry(path);
nsZipItem* item = archive->GetItem(path.get());
if (item && item->Compression() == 0 && item->Size() > 0) {
// We do NOT own this data, but it won't go away until the omnijar
// file is closed during shutdown.
const uint8_t* data = archive->GetData(item);
if (data) {
*aLength = item->Size();
return data;
}
}
return archive->GetData(path.get(), aLength);
}
return nullptr;
}

Просмотреть файл

@ -295,13 +295,14 @@ bool LocaleService::IsServer() { return mIsServer; }
static bool GetGREFileContents(const char* aFilePath, nsCString* aOutString) {
// Look for the requested file in omnijar.
RefPtr<nsZipArchive> zip = Omnijar::GetReader(Omnijar::GRE);
RefPtr<CacheAwareZipReader> zip = Omnijar::GetReader(Omnijar::GRE);
if (zip) {
nsZipItemPtr<char> item(zip, aFilePath);
if (!item) {
uint32_t length;
const uint8_t* data = zip->GetData(aFilePath, &length);
if (!data) {
return false;
}
aOutString->Assign(item.Buffer(), item.Length());
aOutString->Assign(reinterpret_cast<const char*>(data), length);
return true;
}

Просмотреть файл

@ -322,7 +322,7 @@ void URLPreloader::BackgroundReadFiles() {
mReaderThread = nullptr;
});
Vector<nsZipCursor> cursors;
Vector<CacheAwareZipCursor> cursors;
LinkedList<URLEntry> pendingURLs;
{
MonitorAutoLock mal(mMonitor);
@ -352,14 +352,14 @@ void URLPreloader::BackgroundReadFiles() {
continue;
}
RefPtr<nsZipArchive> zip = entry->Archive();
RefPtr<CacheAwareZipReader> zip = entry->Archive();
if (!zip) {
MOZ_CRASH_UNSAFE_PRINTF(
"Failed to get Omnijar %s archive for entry (path: \"%s\")",
entry->TypeString(), entry->mPath.get());
}
auto item = zip->GetItem(entry->mPath.get());
auto* item = zip->GetItem(entry->mPath.get());
if (!item) {
entry->mResultCode = NS_ERROR_FILE_NOT_FOUND;
continue;
@ -495,25 +495,25 @@ Result<const nsCString, nsresult> URLPreloader::ReadURIInternal(
}
/* static */ Result<const nsCString, nsresult> URLPreloader::ReadZip(
nsZipArchive* zip, const nsACString& path, ReadType readType) {
CacheAwareZipReader* archive, const nsACString& path, ReadType readType) {
// If the zip archive belongs to an Omnijar location, map it to a cache
// entry, and cache it as normal. Otherwise, simply read the entry
// synchronously, since other JAR archives are currently unsupported by the
// cache.
RefPtr<nsZipArchive> reader = Omnijar::GetReader(Omnijar::GRE);
if (zip == reader) {
RefPtr<CacheAwareZipReader> reader = Omnijar::GetReader(Omnijar::GRE);
if (reader == archive) {
CacheKey key(CacheKey::TypeGREJar, path);
return Read(key, readType);
}
reader = Omnijar::GetReader(Omnijar::APP);
if (zip == reader) {
if (reader == archive) {
CacheKey key(CacheKey::TypeAppJar, path);
return Read(key, readType);
}
// Not an Omnijar archive, so just read it directly.
FileLocation location(zip, PromiseFlatCString(path).BeginReading());
FileLocation location(archive, PromiseFlatCString(path).BeginReading());
return URLEntry::ReadLocation(location);
}
@ -581,7 +581,7 @@ Result<FileLocation, nsresult> URLPreloader::CacheKey::ToFileLocation() {
return FileLocation(file);
}
RefPtr<nsZipArchive> zip = Archive();
RefPtr<CacheAwareZipReader> zip = Archive();
return FileLocation(zip, mPath.get());
}

Просмотреть файл

@ -26,8 +26,6 @@
#include "nsIThread.h"
#include "nsReadableUtils.h"
class nsZipArchive;
namespace mozilla {
namespace loader {
class InputBuffer;
@ -77,7 +75,7 @@ class URLPreloader final : public nsIObserver, public nsIMemoryReporter {
static Result<const nsCString, nsresult> ReadFile(nsIFile* file,
ReadType readType = Forget);
static Result<const nsCString, nsresult> ReadZip(nsZipArchive* archive,
static Result<const nsCString, nsresult> ReadZip(CacheAwareZipReader* archive,
const nsACString& path,
ReadType readType = Forget);
@ -198,7 +196,7 @@ class URLPreloader final : public nsIObserver, public nsIMemoryReporter {
return "";
}
already_AddRefed<nsZipArchive> Archive() {
already_AddRefed<CacheAwareZipReader> Archive() {
return Omnijar::GetReader(OmnijarType());
}

Просмотреть файл

@ -51,6 +51,7 @@
#include "mozilla/scache/StartupCacheUtils.h"
#include "mozilla/MacroForEach.h"
#include "mozilla/Preferences.h"
#include "mozilla/Omnijar.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/ScriptPreloader.h"
#include "mozilla/ScopeExit.h"
@ -670,6 +671,10 @@ JSObject* mozJSComponentLoader::PrepareObjectForLocation(
static mozilla::Result<nsCString, nsresult> ReadScript(
ComponentLoaderInfo& aInfo) {
// We're going to cache the XDR encoded script data - suspend writes via the
// CacheAwareZipReader, otherwise we'll end up redundantly caching scripts.
AutoSuspendStartupCacheWrites suspendScache;
MOZ_TRY(aInfo.EnsureScriptChannel());
nsCOMPtr<nsIInputStream> scriptStream;

Просмотреть файл

@ -24,6 +24,7 @@
#include "mozilla/ContentPrincipal.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/Omnijar.h"
#include "mozilla/ScriptPreloader.h"
#include "mozilla/SystemPrincipal.h"
#include "mozilla/scache/StartupCache.h"
@ -248,6 +249,10 @@ bool mozJSSubScriptLoader::ReadScript(JS::MutableHandle<JSScript*> script,
const char* uriStr, nsIIOService* serv,
bool wantReturnValue,
bool useCompilationScope) {
// We're going to cache the XDR encoded script data - suspend writes via the
// CacheAwareZipReader, otherwise we'll end up redundantly caching scripts.
AutoSuspendStartupCacheWrites suspendScache;
// We create a channel and call SetContentType, to avoid expensive MIME type
// lookups (bug 632490).
nsCOMPtr<nsIChannel> chan;

Просмотреть файл

@ -26,7 +26,7 @@ using namespace mozilla;
// The following initialization makes a guess of 10 entries per jarfile.
nsJAR::nsJAR()
: mZip(new nsZipArchive()),
: mZip(nullptr),
mReleaseTime(PR_INTERVAL_NO_TIMEOUT),
mCache(nullptr),
mLock("nsJAR::mLock"),
@ -87,12 +87,13 @@ nsJAR::Open(nsIFile* zipFile) {
// The omnijar is special, it is opened early on and closed late
// this avoids reopening it
RefPtr<nsZipArchive> zip = mozilla::Omnijar::GetReader(zipFile);
RefPtr<CacheAwareZipReader> zip = mozilla::Omnijar::GetReader(zipFile);
if (zip) {
mZip = zip;
mSkipArchiveClosing = true;
return NS_OK;
}
mZip = new CacheAwareZipReader();
return mZip->OpenArchive(zipFile);
}
@ -102,7 +103,7 @@ nsJAR::OpenInner(nsIZipReader* aZipReader, const nsACString& aZipEntry) {
if (mOpened) return NS_ERROR_FAILURE; // Already open!
nsJAR* outerJAR = static_cast<nsJAR*>(aZipReader);
RefPtr<nsZipArchive> innerZip =
RefPtr<CacheAwareZipReader> innerZip =
mozilla::Omnijar::GetInnerReader(outerJAR->mZipFile, aZipEntry);
if (innerZip) {
mOpened = true;
@ -124,11 +125,12 @@ nsJAR::OpenInner(nsIZipReader* aZipReader, const nsACString& aZipEntry) {
mOuterZipEntry.Assign(aZipEntry);
RefPtr<nsZipHandle> handle;
rv = nsZipHandle::Init(static_cast<nsJAR*>(aZipReader)->mZip.get(),
rv = nsZipHandle::Init(static_cast<nsJAR*>(aZipReader)->mZip->GetZipArchive(),
PromiseFlatCString(aZipEntry).get(),
getter_AddRefs(handle));
if (NS_FAILED(rv)) return rv;
mZip = new CacheAwareZipReader();
return mZip->OpenArchive(handle);
}
@ -144,6 +146,7 @@ nsJAR::OpenMemory(void* aData, uint32_t aLength) {
getter_AddRefs(handle));
if (NS_FAILED(rv)) return rv;
mZip = new CacheAwareZipReader();
return mZip->OpenArchive(handle);
}
@ -165,7 +168,7 @@ nsJAR::Close() {
if (mSkipArchiveClosing) {
// Reset state, but don't close the omnijar because we did not open it.
mSkipArchiveClosing = false;
mZip = new nsZipArchive();
mZip = nullptr;
return NS_OK;
}
@ -301,7 +304,7 @@ nsresult nsJAR::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc) {
return NS_ERROR_FAILURE;
}
RefPtr<nsZipHandle> handle = mZip->GetFD();
RefPtr<nsZipHandle> handle = mZip->GetZipArchive()->GetFD();
if (!handle) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -23,13 +23,17 @@
#include "nsRefPtrHashtable.h"
#include "nsTHashtable.h"
#include "nsIZipReader.h"
#include "nsZipArchive.h"
#include "nsWeakReference.h"
#include "nsIObserver.h"
#include "mozilla/Attributes.h"
#include "nsZipArchive.h"
class nsZipReaderCache;
namespace mozilla {
class CacheAwareZipReader;
} // namespace mozilla
/*-------------------------------------------------------------------------
* Class nsJAR declaration.
* nsJAR serves as an XPCOM wrapper for nsZipArchive with the addition of
@ -74,7 +78,7 @@ class nsJAR final : public nsIZipReader {
//-- Private data members
nsCOMPtr<nsIFile> mZipFile; // The zip/jar file on disk
nsCString mOuterZipEntry; // The entry in the zip this zip is reading from
RefPtr<nsZipArchive> mZip; // The underlying zip archive
RefPtr<mozilla::CacheAwareZipReader> mZip; // The underlying zip archive
PRIntervalTime mReleaseTime; // used by nsZipReaderCache for flushing entries
nsZipReaderCache*
mCache; // if cached, this points to the cache it's contained in

Просмотреть файл

@ -67,8 +67,15 @@ nsresult nsJARInputStream::InitFile(nsJAR* aJar, nsZipItem* item) {
// Must keep handle to filepointer and mmap structure as long as we need
// access to the mmapped data
mFd = aJar->mZip->GetFD();
mZs.next_in = (Bytef*)aJar->mZip->GetData(item);
rv = aJar->mZip->GetPersistentHandle(item, &mItemHandle,
CacheAwareZipReader::DeferCaching);
if (NS_FAILED(rv)) {
return rv;
}
mZs.next_in =
(Bytef*)aJar->mZip->GetData(item, CacheAwareZipReader::DeferCaching);
if (!mZs.next_in) {
return NS_ERROR_FILE_CORRUPTED;
}
@ -192,7 +199,7 @@ nsJARInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytesRead) {
*aBytesRead = 0;
nsresult rv = NS_OK;
MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd)
MMAP_FAULT_HANDLER_BEGIN_HANDLE(mItemHandle.UnderlyingFD())
switch (mMode) {
case MODE_NOTINITED:
return NS_OK;
@ -211,15 +218,15 @@ nsJARInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytesRead) {
rv = ContinueInflate(aBuffer, aCount, aBytesRead);
}
// be aggressive about releasing the file!
// note that sometimes, we will release mFd before we've finished
// note that sometimes, we will release mItemHandle before we've finished
// deflating - this is because zlib buffers the input
if (mZs.avail_in == 0) {
mFd = nullptr;
mItemHandle.ReleaseHandle();
}
break;
case MODE_COPY:
if (mFd) {
if (mItemHandle) {
uint32_t count = std::min(aCount, mOutSize - uint32_t(mZs.total_out));
if (count) {
memcpy(aBuffer, mZs.next_in + mZs.total_out, count);
@ -228,9 +235,10 @@ nsJARInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytesRead) {
*aBytesRead = count;
}
// be aggressive about releasing the file!
// note that sometimes, we will release mFd before we've finished copying.
// note that sometimes, we will release mItemHandle before we've finished
// copying.
if (mZs.total_out >= mOutSize) {
mFd = nullptr;
mItemHandle.ReleaseHandle();
}
break;
}
@ -262,7 +270,7 @@ nsJARInputStream::Close() {
}
#endif
mMode = MODE_CLOSED;
mFd = nullptr;
mItemHandle.ReleaseHandle();
return NS_OK;
}

Просмотреть файл

@ -11,6 +11,7 @@
#include "nsJAR.h"
#include "nsTArray.h"
#include "mozilla/Attributes.h"
#include "mozilla/Omnijar.h"
#ifdef MOZ_JAR_BROTLI
struct BrotliDecoderStateStruct;
@ -51,7 +52,7 @@ class nsJARInputStream final : public nsIInputStream {
private:
~nsJARInputStream() { Close(); }
RefPtr<nsZipHandle> mFd; // handle for reading
mozilla::CacheAwareZipHandle mItemHandle; // handle for reading
uint32_t mOutSize; // inflated size
uint32_t mInCrc; // CRC as provided by the zipentry
uint32_t mOutCrc; // CRC as calculated by me

Просмотреть файл

@ -82,7 +82,6 @@
#include "nsXPCOMCID.h"
#include "nsXPCOM.h"
#include "nsXULAppAPI.h"
#include "nsZipArchive.h"
#include "plbase64.h"
#include "PLDHashTable.h"
#include "plstr.h"
@ -4312,7 +4311,7 @@ static nsresult pref_LoadPrefsInDir(nsIFile* aDir,
return rv;
}
static nsresult pref_ReadPrefFromJar(nsZipArchive* aJarReader,
static nsresult pref_ReadPrefFromJar(CacheAwareZipReader* aJarReader,
const char* aName) {
TimeStamp startTime = TimeStamp::Now();
@ -4329,8 +4328,8 @@ static nsresult pref_ReadPrefFromJar(nsZipArchive* aJarReader,
return NS_OK;
}
static nsresult pref_ReadDefaultPrefs(const RefPtr<nsZipArchive> jarReader,
const char* path) {
static nsresult pref_ReadDefaultPrefs(
const RefPtr<CacheAwareZipReader>& jarReader, const char* path) {
UniquePtr<nsZipFind> find;
nsTArray<nsCString> prefEntries;
const char* entryName;
@ -4509,7 +4508,7 @@ nsresult Preferences::InitInitialObjects(bool aIsStartup) {
const char* entryName;
uint16_t entryNameLen;
RefPtr<nsZipArchive> jarReader = Omnijar::GetReader(Omnijar::GRE);
RefPtr<CacheAwareZipReader> jarReader = Omnijar::GetReader(Omnijar::GRE);
if (jarReader) {
#ifdef MOZ_WIDGET_ANDROID
// Try to load an architecture-specific greprefs.js first. This will be
@ -4591,7 +4590,7 @@ nsresult Preferences::InitInitialObjects(bool aIsStartup) {
// Load jar:$app/omni.jar!/defaults/preferences/*.js
// or jar:$gre/omni.jar!/defaults/preferences/*.js.
RefPtr<nsZipArchive> appJarReader = Omnijar::GetReader(Omnijar::APP);
RefPtr<CacheAwareZipReader> appJarReader = Omnijar::GetReader(Omnijar::APP);
// GetReader(Omnijar::APP) returns null when `$app == $gre`, in
// which case we look for app-specific default preferences in $gre.

Просмотреть файл

@ -7,6 +7,7 @@
#include "FileLocation.h"
#include "nsZipArchive.h"
#include "nsURLHelper.h"
#include "mozilla/Omnijar.h"
namespace mozilla {
@ -16,12 +17,12 @@ FileLocation::~FileLocation() = default;
FileLocation::FileLocation(nsIFile* aFile) { Init(aFile); }
FileLocation::FileLocation(nsIFile* aFile, const char* aPath) {
Init(aFile, aPath);
FileLocation::FileLocation(CacheAwareZipReader* aZip, const char* aPath) {
Init(aZip, aPath);
}
FileLocation::FileLocation(nsZipArchive* aZip, const char* aPath) {
Init(aZip, aPath);
Init(new CacheAwareZipReader(aZip, nullptr), aPath);
}
FileLocation::FileLocation(const FileLocation& aOther)
@ -88,18 +89,23 @@ void FileLocation::Init(nsIFile* aFile, const char* aPath) {
mPath = aPath;
}
void FileLocation::Init(nsZipArchive* aZip, const char* aPath) {
void FileLocation::Init(CacheAwareZipReader* aZip, const char* aPath) {
mBaseZip = aZip;
mBaseFile = nullptr;
mPath = aPath;
}
void FileLocation::Init(nsZipArchive* aZip, const char* aPath) {
mBaseZip = new CacheAwareZipReader(aZip, nullptr);
mBaseFile = nullptr;
mPath = aPath;
}
void FileLocation::GetURIString(nsACString& aResult) const {
if (mBaseFile) {
net_GetURLSpecFromActualFile(mBaseFile, aResult);
} else if (mBaseZip) {
RefPtr<nsZipHandle> handler = mBaseZip->GetFD();
handler->mFile.GetURIString(aResult);
mBaseZip->GetURIString(aResult);
}
if (IsZip()) {
aResult.InsertLiteral("jar:", 0);
@ -110,11 +116,7 @@ void FileLocation::GetURIString(nsACString& aResult) const {
already_AddRefed<nsIFile> FileLocation::GetBaseFile() {
if (IsZip() && mBaseZip) {
RefPtr<nsZipHandle> handler = mBaseZip->GetFD();
if (handler) {
return handler->mFile.GetBaseFile();
}
return nullptr;
return mBaseZip->GetBaseFile();
}
nsCOMPtr<nsIFile> file = mBaseFile;
@ -126,23 +128,17 @@ bool FileLocation::Equals(const FileLocation& aFile) const {
return false;
}
if (mBaseFile && aFile.mBaseFile) {
nsCOMPtr<nsIFile> a = mBaseFile;
nsCOMPtr<nsIFile> b = aFile.mBaseFile;
if (!mBaseFile && mBaseZip) {
a = mBaseZip->GetBaseFile();
}
if (!aFile.mBaseFile && aFile.mBaseZip) {
b = mBaseZip->GetBaseFile();
}
bool eq;
return NS_SUCCEEDED(mBaseFile->Equals(aFile.mBaseFile, &eq)) && eq;
}
const FileLocation* a = this;
const FileLocation* b = &aFile;
if (a->mBaseZip) {
RefPtr<nsZipHandle> handler = a->mBaseZip->GetFD();
a = &handler->mFile;
}
if (b->mBaseZip) {
RefPtr<nsZipHandle> handler = b->mBaseZip->GetFD();
b = &handler->mFile;
}
return a->Equals(*b);
return NS_SUCCEEDED(a->Equals(b, &eq)) && eq;
}
nsresult FileLocation::GetData(Data& aData) {
@ -151,7 +147,7 @@ nsresult FileLocation::GetData(Data& aData) {
}
aData.mZip = mBaseZip;
if (!aData.mZip) {
aData.mZip = new nsZipArchive();
aData.mZip = new CacheAwareZipReader();
aData.mZip->OpenArchive(mBaseFile);
}
aData.mItem = aData.mZip->GetItem(mPath.get());
@ -195,8 +191,8 @@ nsresult FileLocation::Data::Copy(char* aBuf, uint32_t aLen) {
return NS_OK;
}
if (mItem) {
nsZipCursor cursor(mItem, mZip, reinterpret_cast<uint8_t*>(aBuf), aLen,
true);
CacheAwareZipCursor cursor(mItem, mZip, reinterpret_cast<uint8_t*>(aBuf),
aLen, true);
uint32_t readLen;
cursor.Copy(&readLen);
if (readLen != aLen) {

Просмотреть файл

@ -17,6 +17,8 @@ class nsZipItem;
namespace mozilla {
class CacheAwareZipReader;
class FileLocation {
public:
/**
@ -27,7 +29,7 @@ class FileLocation {
* - in archives within archives
* As such, it stores a path within an archive, as well as the archive
* path itself, or the complete file path alone when on a filesystem.
* When the archive is in an archive, an nsZipArchive is stored instead
* When the archive is in an archive, an CacheAwareZipReader is stored instead
* of a file path.
*/
FileLocation();
@ -45,9 +47,14 @@ class FileLocation {
/**
* Constructors for path within an archive. The archive can be given either
* as nsIFile or nsZipArchive.
* as nsIFile or CacheAwareZipReader.
*/
FileLocation(nsIFile* aZip, const char* aPath);
FileLocation(nsIFile* aFile, const char* aPath);
/**
* Constructors for path within a zip archive.
*/
FileLocation(CacheAwareZipReader* aZip, const char* aPath);
FileLocation(nsZipArchive* aZip, const char* aPath);
@ -61,10 +68,12 @@ class FileLocation {
*/
void Init(nsIFile* aFile);
void Init(nsIFile* aZip, const char* aPath);
void Init(nsIFile* aFile, const char* aPath);
void Init(nsZipArchive* aZip, const char* aPath);
void Init(CacheAwareZipReader* aZip, const char* aPath);
/**
* Returns an URI string corresponding to the file location
*/
@ -78,7 +87,7 @@ class FileLocation {
*/
already_AddRefed<nsIFile> GetBaseFile();
nsZipArchive* GetBaseZip() { return mBaseZip; }
CacheAwareZipReader* GetBaseZip() { return mBaseZip; }
/**
* Returns whether the "base file" (see GetBaseFile) is an archive
@ -119,7 +128,7 @@ class FileLocation {
protected:
friend class FileLocation;
nsZipItem* mItem;
RefPtr<nsZipArchive> mZip;
RefPtr<CacheAwareZipReader> mZip;
mozilla::AutoFDClose mFd;
};
@ -131,7 +140,7 @@ class FileLocation {
private:
nsCOMPtr<nsIFile> mBaseFile;
RefPtr<nsZipArchive> mBaseZip;
RefPtr<CacheAwareZipReader> mBaseZip;
nsCString mPath;
}; /* class FileLocation */

Просмотреть файл

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*/
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -12,15 +13,25 @@
#include "nsZipArchive.h"
#include "nsNetUtil.h"
#include "mozilla/scache/StartupCache.h"
#include "mozilla/MmapFaultHandler.h"
namespace mozilla {
StaticRefPtr<nsIFile> Omnijar::sPath[2];
StaticRefPtr<nsZipArchive> Omnijar::sReader[2];
StaticRefPtr<nsZipArchive> Omnijar::sOuterReader[2];
StaticRefPtr<CacheAwareZipReader> Omnijar::sReader[2];
StaticRefPtr<CacheAwareZipReader> Omnijar::sOuterReader[2];
bool Omnijar::sInitialized = false;
bool Omnijar::sIsUnified = false;
static MOZ_THREAD_LOCAL(int) tlsSuspendStartupCacheWrites;
bool SuspendingStartupCacheWritesForCurrentThread() {
if (!tlsSuspendStartupCacheWrites.init()) {
return true;
}
return tlsSuspendStartupCacheWrites.get() > 0;
}
static const char* sProp[2] = {NS_GRE_DIR, NS_XPCOM_CURRENT_PROCESS_DIR};
static const char* sCachePrefixes[2] = {"GreOmnijar:", "AppOmnijar:"};
@ -83,7 +94,8 @@ void Omnijar::InitOne(nsIFile* aPath, Type aType) {
auto* cache = scache::StartupCache::GetSingleton();
const uint8_t* centralBuf = nullptr;
uint32_t centralBufLength = 0;
nsPrintfCString startupCacheKey("::%s:OmnijarCentral", sCachePrefixes[aType]);
nsCString startupCacheKey =
nsPrintfCString("::%s:OmnijarCentral", sCachePrefixes[aType]);
if (cache) {
nsresult rv = cache->GetBuffer(startupCacheKey.get(),
reinterpret_cast<const char**>(&centralBuf),
@ -93,10 +105,6 @@ void Omnijar::InitOne(nsIFile* aPath, Type aType) {
centralBufLength = 0;
}
}
if (NS_FAILED(zipReader->OpenArchive(
file, MakeSpan(centralBuf, centralBufLength)))) {
return;
}
if (!centralBuf) {
if (NS_FAILED(zipReader->OpenArchive(file))) {
@ -132,8 +140,9 @@ void Omnijar::InitOne(nsIFile* aPath, Type aType) {
}
CleanUpOne(aType);
sReader[aType] = zipReader;
sOuterReader[aType] = outerReader;
sReader[aType] = new CacheAwareZipReader(zipReader, sCachePrefixes[aType]);
sOuterReader[aType] =
outerReader ? new CacheAwareZipReader(outerReader, nullptr) : nullptr;
sPath[aType] = file;
}
@ -149,7 +158,7 @@ void Omnijar::CleanUp() {
sInitialized = false;
}
already_AddRefed<nsZipArchive> Omnijar::GetReader(nsIFile* aPath) {
already_AddRefed<CacheAwareZipReader> Omnijar::GetReader(nsIFile* aPath) {
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
bool equals;
@ -170,7 +179,7 @@ already_AddRefed<nsZipArchive> Omnijar::GetReader(nsIFile* aPath) {
return nullptr;
}
already_AddRefed<nsZipArchive> Omnijar::GetInnerReader(
already_AddRefed<CacheAwareZipReader> Omnijar::GetInnerReader(
nsIFile* aPath, const nsACString& aEntry) {
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
@ -235,4 +244,226 @@ nsresult Omnijar::GetURIString(Type aType, nsACString& aResult) {
return NS_OK;
}
CacheAwareZipReader::CacheAwareZipReader(nsZipArchive* aZip,
const char* aCacheKeyPrefix)
: mZip(aZip), mCacheKeyPrefix(aCacheKeyPrefix) {}
nsresult CacheAwareZipReader::FindInit(const char* aPattern,
nsZipFind** aFind) {
return mZip->FindInit(aPattern, aFind);
}
const uint8_t* CacheAwareZipReader::GetData(
nsZipItem* aItem, CacheAwareZipReader::Caching aCaching) {
nsAutoCString cacheKey;
uint32_t size;
const uint8_t* cached =
GetCachedBuffer(aItem->Name(), aItem->nameLength, &size, cacheKey);
if (cached) {
MOZ_ASSERT(size == aItem->RealSize());
return cached;
}
const uint8_t* zipItemData = mZip->GetData(aItem);
// If the data is compressed, it is somewhat silly to store it in the startup
// cache, as the startup cache will try to double compress it.
if (aCaching == Default && aItem->Compression() == STORED &&
!cacheKey.IsEmpty()) {
MOZ_ASSERT(aItem->RealSize() == aItem->Size());
PutBufferIntoCache(cacheKey, zipItemData, aItem->Size());
}
return zipItemData;
}
const uint8_t* CacheAwareZipReader::GetData(
const char* aEntryName, uint32_t* aResultSize,
CacheAwareZipReader::Caching aCaching) {
nsAutoCString cacheKey;
const uint8_t* cached =
GetCachedBuffer(aEntryName, strlen(aEntryName), aResultSize, cacheKey);
if (cached) {
return cached;
}
nsZipItem* zipItem = mZip->GetItem(aEntryName);
if (!zipItem) {
*aResultSize = 0;
return nullptr;
}
const uint8_t* zipItemData = mZip->GetData(zipItem);
*aResultSize = zipItem->Size();
// If the data is compressed, it is somewhat silly to store it in the startup
// cache, as the startup cache will try to double compress it.
if (aCaching == Default && zipItem->Compression() == STORED &&
!cacheKey.IsEmpty()) {
MOZ_ASSERT(zipItem->RealSize() == *aResultSize);
PutBufferIntoCache(cacheKey, zipItemData, *aResultSize);
}
return zipItemData;
}
nsZipItem* CacheAwareZipReader::GetItem(const char* aEntryName) {
return mZip->GetItem(aEntryName);
}
nsresult CacheAwareZipReader::CloseArchive() { return mZip->CloseArchive(); }
CacheAwareZipCursor::CacheAwareZipCursor(nsZipItem* aItem,
CacheAwareZipReader* aReader,
uint8_t* aBuf, uint32_t aBufSize,
bool aDoCRC)
: mItem(aItem),
mReader(aReader),
mBuf(aBuf),
mBufSize(aBufSize),
mDoCRC(aDoCRC) {}
uint8_t* CacheAwareZipCursor::ReadOrCopy(uint32_t* aBytesRead, bool aCopy) {
nsCString cacheKey;
const uint8_t* cached = mReader->GetCachedBuffer(
mItem->Name(), mItem->nameLength, aBytesRead, cacheKey);
if (cached && *aBytesRead <= mBufSize) {
if (aCopy) {
memcpy(mBuf, cached, *aBytesRead);
return mBuf;
}
// The const cast is unfortunate, but it matches existing consumers'
// uses. We ought to file a bug to make Read return a const uint8_t*
return const_cast<uint8_t*>(cached);
}
nsZipCursor cursor(mItem, mReader->mZip, mBuf, mBufSize, mDoCRC);
uint8_t* buf = nullptr;
if (aCopy) {
cursor.Copy(aBytesRead);
buf = mBuf;
} else {
buf = cursor.Read(aBytesRead);
}
if (!cacheKey.IsEmpty() && *aBytesRead == mItem->RealSize()) {
CacheAwareZipReader::PutBufferIntoCache(cacheKey, buf, *aBytesRead);
}
return buf;
}
nsresult CacheAwareZipReader::GetPersistentHandle(
nsZipItem* aItem, CacheAwareZipHandle* aHandle,
CacheAwareZipReader::Caching aCaching) {
nsCString cacheKey;
if (!mCacheKeyPrefix.IsEmpty() && aItem->Compression() == STORED) {
auto* cache = scache::StartupCache::GetSingleton();
if (cache) {
cacheKey.Append(mCacheKeyPrefix);
cacheKey.Append(aItem->Name(), aItem->nameLength);
if (cache->HasEntry(cacheKey.get())) {
aHandle->mDataIsCached = true;
aHandle->mFd = nullptr;
return NS_OK;
}
if (aCaching == DeferCaching) {
aHandle->mDeferredCachingKey = std::move(cacheKey);
}
}
}
nsresult rv = mZip->EnsureArchiveOpenedOnDisk();
if (NS_FAILED(rv)) {
return rv;
}
aHandle->mDataIsCached = false;
aHandle->mFd = mZip->GetFD();
if (!aHandle->mDeferredCachingKey.IsEmpty() &&
aItem->Compression() == STORED) {
MOZ_ASSERT(aItem->RealSize() == aItem->Size());
aHandle->mDataToCache = MakeSpan(mZip->GetData(aItem), aItem->Size());
}
return NS_OK;
}
const uint8_t* CacheAwareZipReader::GetCachedBuffer(const char* aEntryName,
uint32_t aEntryNameLength,
uint32_t* aResultSize,
nsCString& aCacheKey) {
*aResultSize = 0;
if (mCacheKeyPrefix.IsEmpty()) {
return nullptr;
}
auto* cache = scache::StartupCache::GetSingleton();
if (!cache) {
return nullptr;
}
aCacheKey.Append(mCacheKeyPrefix);
aCacheKey.Append(aEntryName, aEntryNameLength);
const char* cached;
nsresult rv = cache->GetBuffer(aCacheKey.get(), &cached, aResultSize);
if (NS_FAILED(rv)) {
return nullptr;
}
return reinterpret_cast<const uint8_t*>(cached);
}
void CacheAwareZipReader::PutBufferIntoCache(const nsCString& aCacheKey,
const uint8_t* aBuffer,
uint32_t aSize) {
if (SuspendingStartupCacheWritesForCurrentThread() || aSize == 0) {
return;
}
auto* cache = scache::StartupCache::GetSingleton();
auto dataCopy = MakeUnique<char[]>(aSize);
MMAP_FAULT_HANDLER_BEGIN_BUFFER(aBuffer, aSize)
memcpy(dataCopy.get(), aBuffer, aSize);
MMAP_FAULT_HANDLER_CATCH()
Unused << cache->PutBuffer(aCacheKey.get(), std::move(dataCopy), aSize);
}
void CacheAwareZipReader::PushSuspendStartupCacheWrites() {
if (!tlsSuspendStartupCacheWrites.init()) {
return;
}
tlsSuspendStartupCacheWrites.set(tlsSuspendStartupCacheWrites.get() + 1);
}
void CacheAwareZipReader::PopSuspendStartupCacheWrites() {
if (!tlsSuspendStartupCacheWrites.init()) {
return;
}
int current = tlsSuspendStartupCacheWrites.get();
MOZ_ASSERT(current > 0);
tlsSuspendStartupCacheWrites.set(current - 1);
}
void CacheAwareZipHandle::ReleaseHandle() {
if (!mDataToCache.IsEmpty()) {
MOZ_ASSERT(mFd);
MOZ_ASSERT(!mDeferredCachingKey.IsEmpty());
MOZ_ASSERT(!mDataIsCached);
auto* cache = scache::StartupCache::GetSingleton();
MOZ_ASSERT(cache);
if (cache) {
CacheAwareZipReader::PutBufferIntoCache(
mDeferredCachingKey, mDataToCache.Elements(), mDataToCache.Length());
mDataToCache = Span<const uint8_t>();
}
}
mFd = nullptr;
}
} /* namespace mozilla */

Просмотреть файл

@ -13,10 +13,14 @@
#include "nsIFile.h"
#include "nsZipArchive.h"
#include "mozilla/Span.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
class CacheAwareZipReader;
class Omnijar {
private:
/**
@ -28,15 +32,15 @@ class Omnijar {
static StaticRefPtr<nsIFile> sPath[2];
/**
* Cached nsZipArchives for the corresponding sPath
* Cached CacheAwareZipReaders for the corresponding sPath
*/
static StaticRefPtr<nsZipArchive> sReader[2];
static StaticRefPtr<CacheAwareZipReader> sReader[2];
/**
* Cached nsZipArchives for the outer jar, when using nested jars.
* Cached CacheAwareZipReaders for the outer jar, when using nested jars.
* Otherwise nullptr.
*/
static StaticRefPtr<nsZipArchive> sOuterReader[2];
static StaticRefPtr<CacheAwareZipReader> sOuterReader[2];
/**
* Has Omnijar::Init() been called?
@ -61,13 +65,14 @@ class Omnijar {
}
/**
* Returns a nsZipArchive pointer for the outer jar file when using nested
* jars. Returns nullptr in the same cases GetPath() would, or if not using
* nested jars.
* Returns an CacheAwareZipReader pointer for the outer jar file when using
* nested jars. Returns nullptr in the same cases GetPath() would, or if not
* using nested jars.
*/
static inline already_AddRefed<nsZipArchive> GetOuterReader(Type aType) {
static inline already_AddRefed<CacheAwareZipReader> GetOuterReader(
Type aType) {
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
RefPtr<nsZipArchive> reader = sOuterReader[aType].get();
RefPtr<CacheAwareZipReader> reader = sOuterReader[aType].get();
return reader.forget();
}
@ -113,20 +118,20 @@ class Omnijar {
}
/**
* Returns a nsZipArchive pointer for the omni.jar file for GRE or
* Returns an CacheAwareZipReader pointer for the omni.jar file for GRE or
* APP. Returns nullptr in the same cases GetPath() would.
*/
static inline already_AddRefed<nsZipArchive> GetReader(Type aType) {
static inline already_AddRefed<CacheAwareZipReader> GetReader(Type aType) {
MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
RefPtr<nsZipArchive> reader = sReader[aType].get();
RefPtr<CacheAwareZipReader> reader = sReader[aType].get();
return reader.forget();
}
/**
* Returns a nsZipArchive pointer for the given path IAOI the given
* Returns an CacheAwareZipReader pointer for the given path IAOI the given
* path is the omni.jar for either GRE or APP.
*/
static already_AddRefed<nsZipArchive> GetReader(nsIFile* aPath);
static already_AddRefed<CacheAwareZipReader> GetReader(nsIFile* aPath);
/**
* In the case of a nested omnijar, this returns the inner reader for the
@ -136,7 +141,7 @@ class Omnijar {
* GetReader("path/to.apk") returns the outer reader and GetInnerReader(
* "path/to.apk", "assets/omni.ja") returns the inner reader.
*/
static already_AddRefed<nsZipArchive> GetInnerReader(
static already_AddRefed<CacheAwareZipReader> GetInnerReader(
nsIFile* aPath, const nsACString& aEntry);
/**
@ -156,6 +161,132 @@ class Omnijar {
static void CleanUpOne(Type aType);
}; /* class Omnijar */
class CacheAwareZipCursor {
public:
CacheAwareZipCursor(nsZipItem* aItem, CacheAwareZipReader* aReader,
uint8_t* aBuf = nullptr, uint32_t aBufSize = 0,
bool aDoCRC = false);
uint8_t* Read(uint32_t* aBytesRead) { return ReadOrCopy(aBytesRead, false); }
uint8_t* Copy(uint32_t* aBytesRead) { return ReadOrCopy(aBytesRead, true); }
private:
/* Actual implementation for both Read and Copy above */
uint8_t* ReadOrCopy(uint32_t* aBytesRead, bool aCopy);
nsZipItem* mItem;
CacheAwareZipReader* mReader;
uint8_t* mBuf;
uint32_t mBufSize;
bool mDoCRC;
};
// This class wraps an nsZipHandle, which may be null, if the data is
// cached
class CacheAwareZipHandle {
friend class CacheAwareZipReader;
public:
CacheAwareZipHandle() : mFd(nullptr), mDataIsCached(false) {}
~CacheAwareZipHandle() { ReleaseHandle(); }
nsZipHandle* UnderlyingFD() { return mFd; }
void ReleaseHandle();
explicit operator bool() const { return mDataIsCached || mFd; }
private:
RefPtr<nsZipHandle> mFd;
nsCString mDeferredCachingKey;
Span<const uint8_t> mDataToCache;
bool mDataIsCached;
};
class CacheAwareZipReader {
friend class CacheAwareZipCursor;
friend class CacheAwareZipHandle;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheAwareZipReader)
enum Caching {
Default,
DeferCaching,
};
// Constructor for CacheAwareZipReader. aCacheKeyPrefix will be a prefix
// which the wrapper will prepend to any requested entries prior to
// requesting the entry from the StartupCache. However, if aCacheKeyPrefix
// is null, we will simply pass through to the underlying zip archive
// without caching.
explicit CacheAwareZipReader(nsZipArchive* aZip, const char* aCacheKeyPrefix);
// The default constructor should be used for an nsZipArchive which doesn't
// want to cache any entries. Consumers will need to call `OpenArchive`
// explicitly after constructing.
CacheAwareZipReader() : mZip(new nsZipArchive()) {}
nsresult OpenArchive(nsIFile* aFile) { return mZip->OpenArchive(aFile); }
nsresult OpenArchive(nsZipHandle* aHandle) {
return mZip->OpenArchive(aHandle);
}
const uint8_t* GetData(const char* aEntryName, uint32_t* aResultSize,
Caching aCaching = Default);
const uint8_t* GetData(nsZipItem* aItem, Caching aCaching = Default);
nsresult GetPersistentHandle(nsZipItem* aItem, CacheAwareZipHandle* aHandle,
Caching aCaching);
already_AddRefed<nsIFile> GetBaseFile() { return mZip->GetBaseFile(); }
void GetURIString(nsACString& result) { mZip->GetURIString(result); }
nsZipArchive* GetZipArchive() { return mZip; }
nsresult FindInit(const char* aPattern, nsZipFind** aFind);
bool IsForZip(nsZipArchive* aArchive) { return aArchive == mZip; }
nsZipItem* GetItem(const char* aEntryName);
nsresult CloseArchive();
nsresult Test(const char* aEntryName) { return mZip->Test(aEntryName); }
nsresult ExtractFile(nsZipItem* zipEntry, nsIFile* outFile,
PRFileDesc* outFD) {
return mZip->ExtractFile(zipEntry, outFile, outFD);
}
static void PushSuspendStartupCacheWrites();
static void PopSuspendStartupCacheWrites();
protected:
~CacheAwareZipReader() = default;
private:
const uint8_t* GetCachedBuffer(const char* aEntryName,
uint32_t aEntryNameLength,
uint32_t* aResultSize, nsCString& aCacheKey);
static void PutBufferIntoCache(const nsCString& aCacheKey,
const uint8_t* aBuffer, uint32_t aSize);
RefPtr<nsZipArchive> mZip;
nsCString mCacheKeyPrefix;
};
class MOZ_RAII AutoSuspendStartupCacheWrites {
public:
AutoSuspendStartupCacheWrites() {
CacheAwareZipReader::PushSuspendStartupCacheWrites();
}
~AutoSuspendStartupCacheWrites() {
CacheAwareZipReader::PopSuspendStartupCacheWrites();
}
};
} /* namespace mozilla */
#endif /* mozilla_Omnijar_h */

Просмотреть файл

@ -491,7 +491,7 @@ nsresult nsComponentManagerImpl::Init() {
InitializeModuleLocations();
ComponentLocation* cl = sModuleLocations->AppendElement();
cl->type = NS_APP_LOCATION;
RefPtr<nsZipArchive> greOmnijar =
RefPtr<CacheAwareZipReader> greOmnijar =
mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
if (greOmnijar) {
cl->location.Init(greOmnijar, "chrome.manifest");
@ -500,7 +500,7 @@ nsresult nsComponentManagerImpl::Init() {
cl->location.Init(lf);
}
RefPtr<nsZipArchive> appOmnijar =
RefPtr<CacheAwareZipReader> appOmnijar =
mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
if (appOmnijar) {
cl = sModuleLocations->AppendElement();