зеркало из https://github.com/mozilla/gecko-dev.git
319 строки
9.9 KiB
C++
319 строки
9.9 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
|
/* 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
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef URLPreloader_h
|
|
#define URLPreloader_h
|
|
|
|
#include "mozilla/DataMutex.h"
|
|
#include "mozilla/FileLocation.h"
|
|
#include "mozilla/HashFunctions.h"
|
|
#include "mozilla/LinkedList.h"
|
|
#include "mozilla/MemoryReporting.h"
|
|
#include "mozilla/Monitor.h"
|
|
#include "mozilla/Omnijar.h"
|
|
#include "mozilla/Range.h"
|
|
#include "mozilla/Vector.h"
|
|
#include "mozilla/Result.h"
|
|
#include "nsClassHashtable.h"
|
|
#include "nsHashKeys.h"
|
|
#include "nsIChromeRegistry.h"
|
|
#include "nsIFile.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIMemoryReporter.h"
|
|
#include "nsIResProtocolHandler.h"
|
|
#include "nsIThread.h"
|
|
#include "nsReadableUtils.h"
|
|
|
|
class nsZipArchive;
|
|
|
|
namespace mozilla {
|
|
namespace loader {
|
|
class InputBuffer;
|
|
}
|
|
|
|
using namespace mozilla::loader;
|
|
|
|
class ScriptPreloader;
|
|
|
|
/**
|
|
* A singleton class to manage loading local URLs during startup, recording
|
|
* them, and pre-loading them during early startup in the next session. URLs
|
|
* that are not already loaded (or already being pre-loaded) when required are
|
|
* read synchronously from disk, and (if startup is not already complete)
|
|
* added to the pre-load list for the next session.
|
|
*/
|
|
class URLPreloader final : public nsIMemoryReporter {
|
|
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
|
|
|
URLPreloader() = default;
|
|
|
|
public:
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
NS_DECL_NSIMEMORYREPORTER
|
|
|
|
static URLPreloader& GetSingleton();
|
|
|
|
// The type of read operation to perform.
|
|
enum ReadType {
|
|
// Read the file and then immediately forget its data.
|
|
Forget,
|
|
// Read the file and retain its data for the next caller.
|
|
Retain,
|
|
};
|
|
|
|
// Helpers to read the contents of files or JAR archive entries with various
|
|
// representations. If the preloader has not yet been initialized, or the
|
|
// given location is not supported by the cache, the entries will be read
|
|
// synchronously, and not stored in the cache.
|
|
static Result<nsCString, nsresult> Read(FileLocation& location,
|
|
ReadType readType = Forget);
|
|
|
|
static Result<nsCString, nsresult> ReadURI(nsIURI* uri,
|
|
ReadType readType = Forget);
|
|
|
|
static Result<nsCString, nsresult> ReadFile(nsIFile* file,
|
|
ReadType readType = Forget);
|
|
|
|
static Result<nsCString, nsresult> ReadZip(nsZipArchive* archive,
|
|
const nsACString& path,
|
|
ReadType readType = Forget);
|
|
|
|
void SetStartupFinished() { mStartupFinished = true; }
|
|
|
|
private:
|
|
struct CacheKey;
|
|
|
|
Result<nsCString, nsresult> ReadInternal(const CacheKey& key,
|
|
ReadType readType);
|
|
|
|
Result<nsCString, nsresult> ReadURIInternal(nsIURI* uri, ReadType readType);
|
|
|
|
Result<nsCString, nsresult> ReadFileInternal(nsIFile* file,
|
|
ReadType readType);
|
|
|
|
static Result<nsCString, nsresult> Read(const CacheKey& key,
|
|
ReadType readType);
|
|
|
|
static bool sInitialized;
|
|
|
|
static mozilla::StaticRefPtr<URLPreloader> sSingleton;
|
|
|
|
protected:
|
|
friend class AddonManagerStartup;
|
|
friend class ScriptPreloader;
|
|
|
|
virtual ~URLPreloader();
|
|
|
|
Result<Ok, nsresult> WriteCache();
|
|
|
|
static URLPreloader& ReInitialize();
|
|
|
|
// Clear leftover entries after the cache has been written.
|
|
void Cleanup();
|
|
|
|
// Begins reading files off-thread, and ensures that initialization has
|
|
// completed before leaving the current scope. The caller *must* ensure that
|
|
// no code on the main thread access Omnijar, either directly or indirectly,
|
|
// for the lifetime of this guard object.
|
|
struct MOZ_RAII AutoBeginReading final {
|
|
AutoBeginReading() { GetSingleton().BeginBackgroundRead(); }
|
|
|
|
~AutoBeginReading() {
|
|
auto& reader = GetSingleton();
|
|
|
|
MonitorAutoLock mal(reader.mMonitor);
|
|
|
|
while (!reader.mReaderInitialized && URLPreloader::sInitialized) {
|
|
mal.Wait();
|
|
}
|
|
}
|
|
};
|
|
|
|
private:
|
|
// Represents a key for an entry in the URI cache, based on its file or JAR
|
|
// location.
|
|
struct CacheKey {
|
|
// The type of the entry. TypeAppJar and TypeGREJar entries are in the
|
|
// app-specific or toolkit Omnijar files, and are handled specially.
|
|
// TypeFile entries are plain files in the filesystem.
|
|
enum EntryType : uint8_t {
|
|
TypeAppJar,
|
|
TypeGREJar,
|
|
TypeFile,
|
|
};
|
|
|
|
CacheKey() = default;
|
|
CacheKey(const CacheKey& other) = default;
|
|
|
|
CacheKey(EntryType type, const nsACString& path)
|
|
: mType(type), mPath(path) {}
|
|
|
|
explicit CacheKey(nsIFile* file) : mType(TypeFile) {
|
|
nsString path;
|
|
MOZ_ALWAYS_SUCCEEDS(file->GetPath(path));
|
|
MOZ_DIAGNOSTIC_ASSERT(path.Length() > 0);
|
|
CopyUTF16toUTF8(path, mPath);
|
|
}
|
|
|
|
explicit inline CacheKey(InputBuffer& buffer);
|
|
|
|
// Encodes or decodes the cache key for storage in a session cache file.
|
|
template <typename Buffer>
|
|
void Code(Buffer& buffer) {
|
|
buffer.codeUint8(*reinterpret_cast<uint8_t*>(&mType));
|
|
buffer.codeString(mPath);
|
|
MOZ_DIAGNOSTIC_ASSERT(mPath.Length() > 0);
|
|
}
|
|
|
|
uint32_t Hash() const { return HashGeneric(mType, HashString(mPath)); }
|
|
|
|
bool operator==(const CacheKey& other) const {
|
|
return mType == other.mType && mPath == other.mPath;
|
|
}
|
|
|
|
// Returns the Omnijar type for this entry. This may *only* be called
|
|
// for Omnijar entries.
|
|
Omnijar::Type OmnijarType() {
|
|
switch (mType) {
|
|
case TypeAppJar:
|
|
return Omnijar::APP;
|
|
case TypeGREJar:
|
|
return Omnijar::GRE;
|
|
default:
|
|
MOZ_CRASH("Unexpected entry type");
|
|
return Omnijar::GRE;
|
|
}
|
|
}
|
|
|
|
const char* TypeString() const {
|
|
switch (mType) {
|
|
case TypeAppJar:
|
|
return "AppJar";
|
|
case TypeGREJar:
|
|
return "GREJar";
|
|
case TypeFile:
|
|
return "File";
|
|
}
|
|
MOZ_ASSERT_UNREACHABLE("no such type");
|
|
return "";
|
|
}
|
|
|
|
already_AddRefed<nsZipArchive> Archive() {
|
|
return Omnijar::GetReader(OmnijarType());
|
|
}
|
|
|
|
Result<FileLocation, nsresult> ToFileLocation();
|
|
|
|
EntryType mType = TypeFile;
|
|
|
|
// The path of the entry. For Type*Jar entries, this is the path within
|
|
// the Omnijar archive. For TypeFile entries, this is the full path to
|
|
// the file.
|
|
nsCString mPath{};
|
|
};
|
|
|
|
// Represents an entry in the URI cache.
|
|
struct URLEntry final : public CacheKey, public LinkedListElement<URLEntry> {
|
|
MOZ_IMPLICIT URLEntry(const CacheKey& key)
|
|
: CacheKey(key), mData(VoidCString()) {}
|
|
|
|
explicit URLEntry(nsIFile* file) : CacheKey(file) {}
|
|
|
|
// For use with nsTArray::Sort.
|
|
//
|
|
// Sorts entries by the time they were initially read during this
|
|
// session.
|
|
struct Comparator final {
|
|
bool Equals(const URLEntry* a, const URLEntry* b) const {
|
|
return a->mReadTime == b->mReadTime;
|
|
}
|
|
|
|
bool LessThan(const URLEntry* a, const URLEntry* b) const {
|
|
return a->mReadTime < b->mReadTime;
|
|
}
|
|
};
|
|
|
|
// Sets the first-used time of this file to the earlier of its current
|
|
// first-use time or the given timestamp.
|
|
void UpdateUsedTime(const TimeStamp& time = TimeStamp::Now()) {
|
|
if (!mReadTime || time < mReadTime) {
|
|
mReadTime = time;
|
|
}
|
|
}
|
|
|
|
Result<nsCString, nsresult> Read();
|
|
static Result<nsCString, nsresult> ReadLocation(FileLocation& location);
|
|
|
|
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
|
return (mallocSizeOf(this) +
|
|
mPath.SizeOfExcludingThisEvenIfShared(mallocSizeOf) +
|
|
mData.SizeOfExcludingThisEvenIfShared(mallocSizeOf));
|
|
}
|
|
|
|
// Reads the contents of the file referenced by this entry, or wait for
|
|
// an off-thread read operation to finish if it is currently pending,
|
|
// and return the file's contents.
|
|
Result<nsCString, nsresult> ReadOrWait(ReadType readType);
|
|
|
|
nsCString mData;
|
|
|
|
TimeStamp mReadTime{};
|
|
|
|
nsresult mResultCode = NS_OK;
|
|
};
|
|
|
|
// Resolves the given URI to a CacheKey, if the URI is cacheable.
|
|
Result<CacheKey, nsresult> ResolveURI(nsIURI* uri);
|
|
|
|
static already_AddRefed<URLPreloader> Create(bool* aInitialized);
|
|
|
|
Result<Ok, nsresult> InitInternal();
|
|
|
|
// Returns a file pointer to the (possibly nonexistent) cache file with the
|
|
// given suffix.
|
|
Result<nsCOMPtr<nsIFile>, nsresult> GetCacheFile(const nsAString& suffix);
|
|
// Finds the correct cache file to use for this session.
|
|
Result<nsCOMPtr<nsIFile>, nsresult> FindCacheFile();
|
|
|
|
Result<Ok, nsresult> ReadCache(LinkedList<URLEntry>& pendingURLs);
|
|
|
|
void BackgroundReadFiles();
|
|
void BeginBackgroundRead();
|
|
|
|
using HashType = nsClassHashtable<nsGenericHashKey<CacheKey>, URLEntry>;
|
|
|
|
size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
|
|
|
bool mStartupFinished = false;
|
|
bool mReaderInitialized = false;
|
|
|
|
// Only to be accessed from the cache write thread.
|
|
bool mCacheWritten = false;
|
|
|
|
// The prefix URLs for files in the GRE and App omni jar archives.
|
|
nsCString mGREPrefix;
|
|
nsCString mAppPrefix;
|
|
|
|
nsCOMPtr<nsIResProtocolHandler> mResProto;
|
|
nsCOMPtr<nsIChromeRegistry> mChromeReg;
|
|
nsCOMPtr<nsIFile> mProfD;
|
|
|
|
// Note: We use a RefPtr rather than an nsCOMPtr here because the
|
|
// AssertNoQueryNeeded checks done by getter_AddRefs happen at a time that
|
|
// violate data access invariants. It's wrapped in a mutex because
|
|
// the reader thread needs to be able to null this out to terminate itself.
|
|
DataMutex<RefPtr<nsIThread>> mReaderThread{"ReaderThread"};
|
|
|
|
// A map of URL entries which have were either read this session, or read
|
|
// from the last session's cache file.
|
|
HashType mCachedURLs;
|
|
|
|
Monitor mMonitor MOZ_UNANNOTATED{"[URLPreloader::mMutex]"};
|
|
};
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif // URLPreloader_h
|