зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1358846: Part 4 - Merge various startup information stores into a single JSON file. r=rhelmer,jonco
MozReview-Commit-ID: Bs8xMqzVOcl --HG-- extra : rebase_source : fe9eec8d21c0602b079224890a26f797a39c3f28
This commit is contained in:
Родитель
16dbb77f47
Коммит
273fc8c0fb
|
@ -36,6 +36,7 @@
|
|||
#include "mozilla/FinalizationWitnessService.h"
|
||||
#include "mozilla/NativeOSFileInternals.h"
|
||||
#include "mozilla/AddonContentPolicy.h"
|
||||
#include "mozilla/AddonManagerStartup.h"
|
||||
#include "mozilla/AddonPathService.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
@ -126,6 +127,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init)
|
|||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy)
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance)
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonManagerStartup, AddonManagerStartup::GetInstance)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebRequestListener)
|
||||
|
||||
|
@ -161,6 +163,7 @@ NS_DEFINE_NAMED_CID(FINALIZATIONWITNESSSERVICE_CID);
|
|||
NS_DEFINE_NAMED_CID(NATIVE_OSFILE_INTERNALS_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ADDONCONTENTPOLICY_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ADDON_PATH_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ADDON_MANAGER_STARTUP_CID);
|
||||
NS_DEFINE_NAMED_CID(NATIVE_FILEWATCHER_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_WEBREQUESTLISTENER_CID);
|
||||
|
||||
|
@ -196,6 +199,7 @@ static const Module::CIDEntry kToolkitCIDs[] = {
|
|||
{ &kNATIVE_OSFILE_INTERNALS_SERVICE_CID, false, nullptr, NativeOSFileInternalsServiceConstructor },
|
||||
{ &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor },
|
||||
{ &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor },
|
||||
{ &kNS_ADDON_MANAGER_STARTUP_CID, false, nullptr, AddonManagerStartupConstructor },
|
||||
{ &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor },
|
||||
{ &kNS_WEBREQUESTLISTENER_CID, false, nullptr, nsWebRequestListenerConstructor },
|
||||
{ nullptr }
|
||||
|
@ -233,6 +237,7 @@ static const Module::ContractIDEntry kToolkitContracts[] = {
|
|||
{ NATIVE_OSFILE_INTERNALS_SERVICE_CONTRACTID, &kNATIVE_OSFILE_INTERNALS_SERVICE_CID },
|
||||
{ NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID },
|
||||
{ NS_ADDONPATHSERVICE_CONTRACTID, &kNS_ADDON_PATH_SERVICE_CID },
|
||||
{ NS_ADDONMANAGERSTARTUP_CONTRACTID, &kNS_ADDON_MANAGER_STARTUP_CID },
|
||||
{ NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID },
|
||||
{ NS_WEBREQUESTLISTENER_CONTRACTID, &kNS_WEBREQUESTLISTENER_CID },
|
||||
{ nullptr }
|
||||
|
|
|
@ -0,0 +1,281 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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 AddonManagerStartup_inlines_h
|
||||
#define AddonManagerStartup_inlines_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ArrayIterElem;
|
||||
class PropertyIterElem;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Object iterator base classes
|
||||
*****************************************************************************/
|
||||
|
||||
template<class T, class PropertyType>
|
||||
class MOZ_STACK_CLASS BaseIter {
|
||||
public:
|
||||
typedef T SelfType;
|
||||
|
||||
PropertyType begin() const
|
||||
{
|
||||
PropertyType elem(Self());
|
||||
return Move(elem);
|
||||
}
|
||||
|
||||
PropertyType end() const
|
||||
{
|
||||
PropertyType elem(Self());
|
||||
return elem.End();
|
||||
}
|
||||
|
||||
void* Context() const { return mContext; }
|
||||
|
||||
protected:
|
||||
BaseIter(JSContext* cx, JS::HandleObject object, void* context = nullptr)
|
||||
: mCx(cx)
|
||||
, mObject(object)
|
||||
, mContext(context)
|
||||
{}
|
||||
|
||||
const SelfType& Self() const
|
||||
{
|
||||
return *static_cast<const SelfType*>(this);
|
||||
}
|
||||
SelfType& Self()
|
||||
{
|
||||
return *static_cast<SelfType*>(this);
|
||||
}
|
||||
|
||||
JSContext* mCx;
|
||||
|
||||
JS::HandleObject mObject;
|
||||
|
||||
void* mContext;
|
||||
};
|
||||
|
||||
template<class T, class IterType>
|
||||
class MOZ_STACK_CLASS BaseIterElem {
|
||||
public:
|
||||
typedef T SelfType;
|
||||
|
||||
explicit BaseIterElem(const IterType& iter, uint32_t index = 0)
|
||||
: mIter(iter)
|
||||
, mIndex(index)
|
||||
{}
|
||||
|
||||
uint32_t Length() const
|
||||
{
|
||||
return mIter.Length();
|
||||
}
|
||||
|
||||
JS::Value Value()
|
||||
{
|
||||
JS::RootedValue value(mIter.mCx, JS::UndefinedValue());
|
||||
|
||||
auto& self = Self();
|
||||
if (!self.GetValue(&value)) {
|
||||
JS_ClearPendingException(mIter.mCx);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
SelfType& operator*() { return Self(); }
|
||||
|
||||
SelfType& operator++()
|
||||
{
|
||||
MOZ_ASSERT(mIndex < Length());
|
||||
mIndex++;
|
||||
return Self();
|
||||
}
|
||||
|
||||
bool operator!=(const SelfType& other) const
|
||||
{
|
||||
return &mIter != &other.mIter || mIndex != other.mIndex;
|
||||
}
|
||||
|
||||
|
||||
SelfType End() const
|
||||
{
|
||||
SelfType end(mIter);
|
||||
end.mIndex = Length();
|
||||
return Move(end);
|
||||
}
|
||||
|
||||
void* Context() const { return mIter.Context(); }
|
||||
|
||||
protected:
|
||||
const SelfType& Self() const
|
||||
{
|
||||
return *static_cast<const SelfType*>(this);
|
||||
}
|
||||
SelfType& Self() {
|
||||
return *static_cast<SelfType*>(this);
|
||||
}
|
||||
|
||||
const IterType& mIter;
|
||||
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Property iteration
|
||||
*****************************************************************************/
|
||||
|
||||
class MOZ_STACK_CLASS PropertyIter
|
||||
: public BaseIter<PropertyIter, PropertyIterElem>
|
||||
{
|
||||
friend class PropertyIterElem;
|
||||
friend class BaseIterElem<PropertyIterElem, PropertyIter>;
|
||||
|
||||
public:
|
||||
PropertyIter(JSContext* cx, JS::HandleObject object, void* context = nullptr)
|
||||
: BaseIter(cx, object, context)
|
||||
, mIds(cx, JS::IdVector(cx))
|
||||
{
|
||||
if (!JS_Enumerate(cx, object, &mIds)) {
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
}
|
||||
|
||||
PropertyIter(const PropertyIter& other)
|
||||
: PropertyIter(other.mCx, other.mObject, other.mContext)
|
||||
{}
|
||||
|
||||
PropertyIter& operator=(const PropertyIter& other)
|
||||
{
|
||||
MOZ_ASSERT(other.mObject == mObject);
|
||||
mCx = other.mCx;
|
||||
mContext = other.mContext;
|
||||
|
||||
mIds.clear();
|
||||
if (!JS_Enumerate(mCx, mObject, &mIds)) {
|
||||
JS_ClearPendingException(mCx);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
int32_t Length() const
|
||||
{
|
||||
return mIds.length();
|
||||
}
|
||||
|
||||
protected:
|
||||
JS::Rooted<JS::IdVector> mIds;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS PropertyIterElem
|
||||
: public BaseIterElem<PropertyIterElem, PropertyIter>
|
||||
{
|
||||
friend class BaseIterElem<PropertyIterElem, PropertyIter>;
|
||||
|
||||
public:
|
||||
using BaseIterElem::BaseIterElem;
|
||||
|
||||
PropertyIterElem(const PropertyIterElem& other)
|
||||
: BaseIterElem(other.mIter, other.mIndex)
|
||||
{}
|
||||
|
||||
jsid Id()
|
||||
{
|
||||
MOZ_ASSERT(mIndex < mIter.mIds.length());
|
||||
|
||||
return mIter.mIds[mIndex];
|
||||
}
|
||||
|
||||
const nsAString& Name()
|
||||
{
|
||||
if(mName.isNothing()) {
|
||||
mName.emplace();
|
||||
mName.ref().init(mIter.mCx, Id());
|
||||
}
|
||||
return mName.ref();
|
||||
}
|
||||
|
||||
JSContext* Cx() { return mIter.mCx; }
|
||||
|
||||
protected:
|
||||
bool GetValue(JS::MutableHandleValue value)
|
||||
{
|
||||
MOZ_ASSERT(mIndex < Length());
|
||||
JS::Rooted<jsid> id(mIter.mCx, Id());
|
||||
|
||||
return JS_GetPropertyById(mIter.mCx, mIter.mObject, id, value);
|
||||
}
|
||||
|
||||
private:
|
||||
Maybe<nsAutoJSString> mName;
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Array iteration
|
||||
*****************************************************************************/
|
||||
|
||||
class MOZ_STACK_CLASS ArrayIter
|
||||
: public BaseIter<ArrayIter, ArrayIterElem>
|
||||
{
|
||||
friend class ArrayIterElem;
|
||||
friend class BaseIterElem<ArrayIterElem, ArrayIter>;
|
||||
|
||||
public:
|
||||
ArrayIter(JSContext* cx, JS::HandleObject object)
|
||||
: BaseIter(cx, object)
|
||||
, mLength(0)
|
||||
{
|
||||
bool isArray;
|
||||
if (!JS_IsArrayObject(cx, object, &isArray) || !isArray) {
|
||||
JS_ClearPendingException(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!JS_GetArrayLength(cx, object, &mLength)) {
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Length() const
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t mLength;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS ArrayIterElem
|
||||
: public BaseIterElem<ArrayIterElem, ArrayIter>
|
||||
{
|
||||
friend class BaseIterElem<ArrayIterElem, ArrayIter>;
|
||||
|
||||
public:
|
||||
using BaseIterElem::BaseIterElem;
|
||||
|
||||
ArrayIterElem(const ArrayIterElem& other)
|
||||
: BaseIterElem(other.mIter, other.mIndex)
|
||||
{}
|
||||
|
||||
protected:
|
||||
bool
|
||||
GetValue(JS::MutableHandleValue value)
|
||||
{
|
||||
MOZ_ASSERT(mIndex < Length());
|
||||
return JS_GetElement(mIter.mCx, mIter.mObject, mIndex, value);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AddonManagerStartup_inlines_h
|
|
@ -0,0 +1,566 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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/. */
|
||||
|
||||
#include "AddonManagerStartup.h"
|
||||
#include "AddonManagerStartup-inlines.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "mozilla/Compression.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsAppRunner.h"
|
||||
#include "nsIAddonInterposition.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using Compression::LZ4;
|
||||
|
||||
#ifdef XP_WIN
|
||||
# define READ_BINARYMODE "rb"
|
||||
#else
|
||||
# define READ_BINARYMODE "r"
|
||||
#endif
|
||||
|
||||
AddonManagerStartup&
|
||||
AddonManagerStartup::GetSingleton()
|
||||
{
|
||||
static RefPtr<AddonManagerStartup> singleton;
|
||||
if (!singleton) {
|
||||
singleton = new AddonManagerStartup();
|
||||
ClearOnShutdown(&singleton);
|
||||
}
|
||||
return *singleton;
|
||||
}
|
||||
|
||||
AddonManagerStartup::AddonManagerStartup()
|
||||
: mInitialized(false)
|
||||
{}
|
||||
|
||||
|
||||
nsIFile*
|
||||
AddonManagerStartup::ProfileDir()
|
||||
{
|
||||
if (!mProfileDir) {
|
||||
nsresult rv;
|
||||
|
||||
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mProfileDir));
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
return mProfileDir;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(AddonManagerStartup, amIAddonManagerStartup)
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* File utils
|
||||
*****************************************************************************/
|
||||
|
||||
static already_AddRefed<nsIFile>
|
||||
CloneAndAppend(nsIFile* aFile, const char* name)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
aFile->Clone(getter_AddRefs(file));
|
||||
file->AppendNative(nsDependentCString(name));
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
static bool
|
||||
IsNormalFile(nsIFile* file)
|
||||
{
|
||||
bool result;
|
||||
return NS_SUCCEEDED(file->IsFile(&result)) && result;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
ReadFile(const char* path)
|
||||
{
|
||||
nsCString result;
|
||||
|
||||
FILE* fd = fopen(path, READ_BINARYMODE);
|
||||
if (!fd) {
|
||||
return result;
|
||||
}
|
||||
auto cleanup = MakeScopeExit([&] () {
|
||||
fclose(fd);
|
||||
});
|
||||
|
||||
if (fseek(fd, 0, SEEK_END) != 0) {
|
||||
return result;
|
||||
}
|
||||
size_t len = ftell(fd);
|
||||
if (len <= 0 || fseek(fd, 0, SEEK_SET) != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.SetLength(len);
|
||||
size_t rd = fread(result.BeginWriting(), sizeof(char), len, fd);
|
||||
if (rd != len) {
|
||||
result.Truncate();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the contents of a LZ4-compressed file, as stored by the OS.File
|
||||
* module, and stores the decompressed contents in result.
|
||||
*
|
||||
* Returns true on success, or false on failure. A nonexistent or empty file
|
||||
* is treated as success. A corrupt or non-LZ4 file is treated as failure.
|
||||
*/
|
||||
static bool
|
||||
ReadFileLZ4(const char* path, nsCString& result)
|
||||
{
|
||||
static const char MAGIC_NUMBER[] = "mozLz40";
|
||||
constexpr auto HEADER_SIZE = sizeof(MAGIC_NUMBER) + 4;
|
||||
|
||||
nsCString lz4 = ReadFile(path);
|
||||
if (lz4.IsEmpty()) {
|
||||
result.Truncate();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note: We want to include the null terminator here.
|
||||
nsDependentCSubstring magic(MAGIC_NUMBER, sizeof(MAGIC_NUMBER));
|
||||
|
||||
if (lz4.Length() < HEADER_SIZE || StringHead(lz4, magic.Length()) != magic) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto size = LittleEndian::readUint32(lz4.get() + magic.Length());
|
||||
|
||||
if (!result.SetLength(size, fallible) ||
|
||||
!LZ4::decompress(lz4.get() + HEADER_SIZE, result.BeginWriting(), size)) {
|
||||
result.Truncate();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
ParseJSON(JSContext* cx, nsACString& jsonData, JS::MutableHandleValue result)
|
||||
{
|
||||
NS_ConvertUTF8toUTF16 str(jsonData);
|
||||
jsonData.Truncate();
|
||||
|
||||
return JS_ParseJSON(cx, str.Data(), str.Length(), result);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* JSON data handling
|
||||
*****************************************************************************/
|
||||
|
||||
class MOZ_STACK_CLASS WrapperBase {
|
||||
protected:
|
||||
WrapperBase(JSContext* cx, JSObject* object)
|
||||
: mCx(cx)
|
||||
, mObject(cx, object)
|
||||
{}
|
||||
|
||||
WrapperBase(JSContext* cx, const JS::Value& value)
|
||||
: mCx(cx)
|
||||
, mObject(cx)
|
||||
{
|
||||
if (value.isObject()) {
|
||||
mObject = &value.toObject();
|
||||
} else {
|
||||
mObject = JS_NewPlainObject(cx);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
JSContext* mCx;
|
||||
JS::RootedObject mObject;
|
||||
|
||||
bool GetBool(const char* name, bool defVal = false);
|
||||
|
||||
double GetNumber(const char* name, double defVal = 0);
|
||||
|
||||
nsString GetString(const char* name, const char* defVal = "");
|
||||
|
||||
JSObject* GetObject(const char* name);
|
||||
};
|
||||
|
||||
bool
|
||||
WrapperBase::GetBool(const char* name, bool defVal)
|
||||
{
|
||||
JS::RootedObject obj(mCx, mObject);
|
||||
|
||||
JS::RootedValue val(mCx, JS::UndefinedValue());
|
||||
if (!JS_GetProperty(mCx, obj, name, &val)) {
|
||||
JS_ClearPendingException(mCx);
|
||||
}
|
||||
|
||||
if (val.isBoolean()) {
|
||||
return val.toBoolean();
|
||||
}
|
||||
return defVal;
|
||||
}
|
||||
|
||||
double
|
||||
WrapperBase::GetNumber(const char* name, double defVal)
|
||||
{
|
||||
JS::RootedObject obj(mCx, mObject);
|
||||
|
||||
JS::RootedValue val(mCx, JS::UndefinedValue());
|
||||
if (!JS_GetProperty(mCx, obj, name, &val)) {
|
||||
JS_ClearPendingException(mCx);
|
||||
}
|
||||
|
||||
if (val.isNumber()) {
|
||||
return val.toNumber();
|
||||
}
|
||||
return defVal;
|
||||
}
|
||||
|
||||
nsString
|
||||
WrapperBase::GetString(const char* name, const char* defVal)
|
||||
{
|
||||
JS::RootedObject obj(mCx, mObject);
|
||||
|
||||
JS::RootedValue val(mCx, JS::UndefinedValue());
|
||||
if (!JS_GetProperty(mCx, obj, name, &val)) {
|
||||
JS_ClearPendingException(mCx);
|
||||
}
|
||||
|
||||
nsString res;
|
||||
if (val.isString()) {
|
||||
AssignJSString(mCx, res, val.toString());
|
||||
} else {
|
||||
res.AppendASCII(defVal);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WrapperBase::GetObject(const char* name)
|
||||
{
|
||||
JS::RootedObject obj(mCx, mObject);
|
||||
|
||||
JS::RootedValue val(mCx, JS::UndefinedValue());
|
||||
if (!JS_GetProperty(mCx, obj, name, &val)) {
|
||||
JS_ClearPendingException(mCx);
|
||||
}
|
||||
|
||||
if (val.isObject()) {
|
||||
return &val.toObject();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
class MOZ_STACK_CLASS InstallLocation : public WrapperBase {
|
||||
public:
|
||||
InstallLocation(JSContext* cx, const JS::Value& value);
|
||||
|
||||
MOZ_IMPLICIT InstallLocation(PropertyIterElem& iter)
|
||||
: InstallLocation(iter.Cx(), iter.Value())
|
||||
{}
|
||||
|
||||
InstallLocation(const InstallLocation& other)
|
||||
: InstallLocation(other.mCx, JS::ObjectValue(*other.mObject))
|
||||
{}
|
||||
|
||||
void SetChanged(bool changed)
|
||||
{
|
||||
JS::RootedObject obj(mCx, mObject);
|
||||
|
||||
JS::RootedValue val(mCx, JS::BooleanValue(changed));
|
||||
if (!JS_SetProperty(mCx, obj, "changed", val)) {
|
||||
JS_ClearPendingException(mCx);
|
||||
}
|
||||
}
|
||||
|
||||
PropertyIter& Addons() { return mAddonsIter.ref(); }
|
||||
|
||||
nsString Path() { return GetString("path"); }
|
||||
|
||||
bool ShouldCheckStartupModifications() { return GetBool("checkStartupModifications"); }
|
||||
|
||||
|
||||
private:
|
||||
JS::RootedObject mAddonsObj;
|
||||
Maybe<PropertyIter> mAddonsIter;
|
||||
};
|
||||
|
||||
|
||||
class MOZ_STACK_CLASS Addon : public WrapperBase {
|
||||
public:
|
||||
Addon(JSContext* cx, InstallLocation& location, const nsAString& id, JSObject* object)
|
||||
: WrapperBase(cx, object)
|
||||
, mId(id)
|
||||
, mLocation(location)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT Addon(PropertyIterElem& iter)
|
||||
: WrapperBase(iter.Cx(), iter.Value())
|
||||
, mId(iter.Name())
|
||||
, mLocation(*static_cast<InstallLocation*>(iter.Context()))
|
||||
{}
|
||||
|
||||
Addon(const Addon& other)
|
||||
: WrapperBase(other.mCx, other.mObject)
|
||||
, mId(other.mId)
|
||||
, mLocation(other.mLocation)
|
||||
{}
|
||||
|
||||
const nsString& Id() { return mId; }
|
||||
|
||||
nsString Path() { return GetString("path"); }
|
||||
|
||||
bool Bootstrapped() { return GetBool("bootstrapped"); }
|
||||
|
||||
bool Enabled() { return GetBool("enabled"); }
|
||||
|
||||
bool ShimsEnabled() { return GetBool("enableShims"); }
|
||||
|
||||
double LastModifiedTime() { return GetNumber("lastModifiedTime"); }
|
||||
|
||||
|
||||
already_AddRefed<nsIFile> FullPath();
|
||||
|
||||
NSLocationType LocationType();
|
||||
|
||||
bool UpdateLastModifiedTime();
|
||||
|
||||
|
||||
private:
|
||||
nsString mId;
|
||||
InstallLocation& mLocation;
|
||||
};
|
||||
|
||||
already_AddRefed<nsIFile>
|
||||
Addon::FullPath()
|
||||
{
|
||||
nsString path = mLocation.Path();
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_NewLocalFile(path, false, getter_AddRefs(file));
|
||||
MOZ_RELEASE_ASSERT(file);
|
||||
|
||||
path = Path();
|
||||
file->AppendRelativePath(path);
|
||||
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
NSLocationType
|
||||
Addon::LocationType()
|
||||
{
|
||||
nsString type = GetString("type", "extension");
|
||||
if (type.LowerCaseEqualsLiteral("theme")) {
|
||||
return NS_SKIN_LOCATION;
|
||||
}
|
||||
return NS_EXTENSION_LOCATION;
|
||||
}
|
||||
|
||||
bool
|
||||
Addon::UpdateLastModifiedTime()
|
||||
{
|
||||
nsCOMPtr<nsIFile> file = FullPath();
|
||||
|
||||
bool result;
|
||||
if (NS_FAILED(file->Exists(&result)) || !result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PRTime time;
|
||||
|
||||
nsCOMPtr<nsIFile> manifest = file;
|
||||
if (!IsNormalFile(manifest)) {
|
||||
manifest = CloneAndAppend(file, "install.rdf");
|
||||
if (!IsNormalFile(manifest)) {
|
||||
manifest = CloneAndAppend(file, "manifest.json");
|
||||
if (!IsNormalFile(manifest)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(manifest->GetLastModifiedTime(&time))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::RootedObject obj(mCx, mObject);
|
||||
|
||||
double lastModified = time;
|
||||
JS::RootedValue value(mCx, JS::NumberValue(lastModified));
|
||||
if (!JS_SetProperty(mCx, obj, "currentModifiedTime", value)) {
|
||||
JS_ClearPendingException(mCx);
|
||||
}
|
||||
|
||||
return lastModified != LastModifiedTime();;
|
||||
}
|
||||
|
||||
|
||||
InstallLocation::InstallLocation(JSContext* cx, const JS::Value& value)
|
||||
: WrapperBase(cx, value)
|
||||
, mAddonsObj(cx)
|
||||
, mAddonsIter()
|
||||
{
|
||||
mAddonsObj = GetObject("addons");
|
||||
if (!mAddonsObj) {
|
||||
mAddonsObj = JS_NewPlainObject(cx);
|
||||
}
|
||||
mAddonsIter.emplace(cx, mAddonsObj, this);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* XPC interfacing
|
||||
*****************************************************************************/
|
||||
|
||||
static void
|
||||
EnableShims(const nsAString& addonId)
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 id(addonId);
|
||||
|
||||
nsCOMPtr<nsIAddonInterposition> interposition =
|
||||
do_GetService("@mozilla.org/addons/multiprocess-shims;1");
|
||||
|
||||
if (!interposition || !xpc::SetAddonInterposition(id, interposition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Unused << xpc::AllowCPOWsInAddon(id, true);
|
||||
}
|
||||
|
||||
void
|
||||
AddonManagerStartup::AddInstallLocation(Addon& addon)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file = addon.FullPath();
|
||||
|
||||
nsString path;
|
||||
if (NS_FAILED(file->GetPath(path))) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto type = addon.LocationType();
|
||||
|
||||
if (type == NS_SKIN_LOCATION) {
|
||||
mThemePaths.AppendElement(file);
|
||||
} else {
|
||||
mExtensionPaths.AppendElement(file);
|
||||
}
|
||||
|
||||
if (StringTail(path, 4).LowerCaseEqualsLiteral(".xpi")) {
|
||||
XRE_AddJarManifestLocation(type, file);
|
||||
} else {
|
||||
nsCOMPtr<nsIFile> manifest = CloneAndAppend(file, "chrome.manifest");
|
||||
XRE_AddManifestLocation(type, manifest);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
AddonManagerStartup::ReadStartupData(JSContext* cx, JS::MutableHandleValue locations)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
locations.set(JS::UndefinedValue());
|
||||
|
||||
nsCOMPtr<nsIFile> file = CloneAndAppend(ProfileDir(), "addonStartup.json.lz4");
|
||||
|
||||
nsCString path;
|
||||
rv = file->GetNativePath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString data;
|
||||
if (!ReadFileLZ4(path.get(), data)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (data.IsEmpty() || !ParseJSON(cx, data, locations)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!locations.isObject()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
JS::RootedObject locs(cx, &locations.toObject());
|
||||
for (auto& e1 : PropertyIter(cx, locs)) {
|
||||
InstallLocation loc(e1);
|
||||
|
||||
if (!loc.ShouldCheckStartupModifications()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto& e2 : loc.Addons()) {
|
||||
Addon addon(e2);
|
||||
|
||||
if (addon.Enabled() && addon.UpdateLastModifiedTime()) {
|
||||
loc.SetChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AddonManagerStartup::InitializeExtensions(JS::HandleValue locations, JSContext* cx)
|
||||
{
|
||||
NS_ENSURE_FALSE(mInitialized, NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(locations.isObject(), NS_ERROR_INVALID_ARG);
|
||||
|
||||
mInitialized = true;
|
||||
|
||||
if (!Preferences::GetBool("extensions.defaultProviders.enabled", true)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool enableInterpositions = Preferences::GetBool("extensions.interposition.enabled", false);
|
||||
|
||||
JS::RootedObject locs(cx, &locations.toObject());
|
||||
for (auto& e1 : PropertyIter(cx, locs)) {
|
||||
InstallLocation loc(e1);
|
||||
|
||||
for (auto& e2 : loc.Addons()) {
|
||||
Addon addon(e2);
|
||||
|
||||
if (!addon.Bootstrapped()) {
|
||||
AddInstallLocation(addon);
|
||||
}
|
||||
|
||||
if (enableInterpositions && addon.ShimsEnabled()) {
|
||||
EnableShims(addon.Id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AddonManagerStartup::Reset()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(xpc::IsInAutomation());
|
||||
|
||||
mInitialized = false;
|
||||
|
||||
mExtensionPaths.Clear();
|
||||
mThemePaths.Clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,73 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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 AddonManagerStartup_h
|
||||
#define AddonManagerStartup_h
|
||||
|
||||
#include "amIAddonManagerStartup.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class Addon;
|
||||
|
||||
class AddonManagerStartup final : public amIAddonManagerStartup
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_AMIADDONMANAGERSTARTUP
|
||||
|
||||
AddonManagerStartup();
|
||||
|
||||
static AddonManagerStartup& GetSingleton();
|
||||
|
||||
static already_AddRefed<AddonManagerStartup> GetInstance()
|
||||
{
|
||||
RefPtr<AddonManagerStartup> inst = &GetSingleton();
|
||||
return inst.forget();
|
||||
}
|
||||
|
||||
const nsCOMArray<nsIFile>& ExtensionPaths()
|
||||
{
|
||||
return mExtensionPaths;
|
||||
}
|
||||
|
||||
const nsCOMArray<nsIFile>& ThemePaths()
|
||||
{
|
||||
return mExtensionPaths;
|
||||
}
|
||||
|
||||
private:
|
||||
void AddInstallLocation(Addon& addon);
|
||||
|
||||
nsIFile* ProfileDir();
|
||||
|
||||
nsCOMPtr<nsIFile> mProfileDir;
|
||||
|
||||
nsCOMArray<nsIFile> mExtensionPaths;
|
||||
nsCOMArray<nsIFile> mThemePaths;
|
||||
|
||||
bool mInitialized;
|
||||
|
||||
protected:
|
||||
virtual ~AddonManagerStartup() = default;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_ADDONMANAGERSTARTUP_CONTRACTID \
|
||||
"@mozilla.org/addons/addon-manager-startup;1"
|
||||
|
||||
// {17a59a6b-92b8-42e5-bce0-ab434c7a7135
|
||||
#define NS_ADDON_MANAGER_STARTUP_CID \
|
||||
{ 0x17a59a6b, 0x92b8, 0x42e5, \
|
||||
{ 0xbc, 0xe0, 0xab, 0x43, 0x4c, 0x7a, 0x71, 0x35 } }
|
||||
|
||||
#endif // AddonManagerStartup_h
|
|
@ -0,0 +1,36 @@
|
|||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(01dfa47b-87e4-4135-877b-586d033e1b5d)]
|
||||
interface amIAddonManagerStartup : nsISupports
|
||||
{
|
||||
/**
|
||||
* Reads and parses startup data from the addonState.json.lz4 file, checks
|
||||
* for modifications, and returns the result.
|
||||
*
|
||||
* Returns null for an empty or nonexistent state file, but throws for an
|
||||
* invalid one.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
jsval readStartupData();
|
||||
|
||||
/**
|
||||
* Initializes the chrome registry for the enabled, non-restartless add-on
|
||||
* in the given state data.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void initializeExtensions(in jsval locations);
|
||||
|
||||
/**
|
||||
* Resets the internal state of the startup service, and allows
|
||||
* initializeExtensions() to be called again. Does *not* fully unregister
|
||||
* chrome registry locations for previously registered add-ons.
|
||||
*
|
||||
* NOT FOR USE OUTSIDE OF UNIT TESTS.
|
||||
*/
|
||||
void reset();
|
||||
};
|
||||
|
|
@ -30,6 +30,9 @@ const {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "Extension",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
|
||||
"@mozilla.org/addons/addon-manager-startup;1",
|
||||
"amIAddonManagerStartup");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "rdfService",
|
||||
"@mozilla.org/rdf/rdf-service;1", "nsIRDFService");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
|
||||
|
@ -42,6 +45,8 @@ XPCOMUtils.defineLazyGetter(this, "AppInfo", () => {
|
|||
return AppInfo;
|
||||
});
|
||||
|
||||
const PREF_DISABLE_SECURITY = ("security.turn_off_all_security_so_that_" +
|
||||
"viruses_can_take_over_this_computer");
|
||||
|
||||
const ArrayBufferInputStream = Components.Constructor(
|
||||
"@mozilla.org/io/arraybuffer-input-stream;1",
|
||||
|
@ -129,46 +134,46 @@ function escaped(strings, ...values) {
|
|||
|
||||
|
||||
class AddonsList {
|
||||
constructor(extensionsINI) {
|
||||
constructor(file) {
|
||||
this.multiprocessIncompatibleIDs = new Set();
|
||||
this.extensions = [];
|
||||
this.themes = [];
|
||||
|
||||
if (!extensionsINI.exists()) {
|
||||
this.extensions = [];
|
||||
this.themes = [];
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]
|
||||
.getService(Ci.nsIINIParserFactory);
|
||||
let data = aomStartup.readStartupData();
|
||||
|
||||
let parser = factory.createINIParser(extensionsINI);
|
||||
for (let loc of Object.values(data)) {
|
||||
let dir = loc.path && new nsFile(loc.path);
|
||||
|
||||
function readDirectories(section) {
|
||||
var dirs = [];
|
||||
var keys = parser.getKeys(section);
|
||||
for (let key of XPCOMUtils.IterStringEnumerator(keys)) {
|
||||
let descriptor = parser.getString(section, key);
|
||||
for (let [id, addon] of Object.entries(loc.addons)) {
|
||||
if (addon.enabled && !addon.bootstrapped) {
|
||||
let file;
|
||||
if (dir) {
|
||||
file = dir.clone();
|
||||
try {
|
||||
file.appendRelativePath(addon.path);
|
||||
} catch (e) {
|
||||
file = new nsFile(addon.path);
|
||||
}
|
||||
} else {
|
||||
file = new nsFile(addon.path);
|
||||
}
|
||||
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
try {
|
||||
file.persistentDescriptor = descriptor;
|
||||
} catch (e) {
|
||||
// Throws if the directory doesn't exist, we can ignore this since the
|
||||
// platform will too.
|
||||
continue;
|
||||
addon.type = addon.type || "extension";
|
||||
|
||||
if (addon.type == "theme") {
|
||||
this.themes.push(file);
|
||||
} else {
|
||||
this.extensions.push(file);
|
||||
if (addon.enableShims) {
|
||||
this.multiprocessIncompatibleIDs.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
dirs.push(file);
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
this.extensions = readDirectories("ExtensionDirs");
|
||||
this.themes = readDirectories("ThemeDirs");
|
||||
|
||||
var keys = parser.getKeys("MultiprocessIncompatibleExtensions");
|
||||
for (let key of XPCOMUtils.IterStringEnumerator(keys)) {
|
||||
let id = parser.getString("MultiprocessIncompatibleExtensions", key);
|
||||
this.multiprocessIncompatibleIDs.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +186,7 @@ class AddonsList {
|
|||
|
||||
return this[type].some(file => {
|
||||
if (!file.exists())
|
||||
throw new Error(`Non-existent path found in extensions.ini: ${file.path}`);
|
||||
throw new Error(`Non-existent path found in addonStartup.json: ${file.path}`);
|
||||
|
||||
if (file.isDirectory())
|
||||
return file.equals(path);
|
||||
|
@ -208,7 +213,7 @@ var AddonTestUtils = {
|
|||
addonIntegrationService: null,
|
||||
addonsList: null,
|
||||
appInfo: null,
|
||||
extensionsINI: null,
|
||||
addonStartup: null,
|
||||
testUnpacked: false,
|
||||
useRealCertChecks: false,
|
||||
|
||||
|
@ -221,8 +226,8 @@ var AddonTestUtils = {
|
|||
this.profileExtensions = this.profileDir.clone();
|
||||
this.profileExtensions.append("extensions");
|
||||
|
||||
this.extensionsINI = this.profileDir.clone();
|
||||
this.extensionsINI.append("extensions.ini");
|
||||
this.addonStartup = this.profileDir.clone();
|
||||
this.addonStartup.append("addonStartup.json.lz4");
|
||||
|
||||
// Register a temporary directory for the tests.
|
||||
this.tempDir = this.profileDir.clone();
|
||||
|
@ -555,15 +560,13 @@ var AddonTestUtils = {
|
|||
* An optional boolean parameter to simulate the case where the
|
||||
* application has changed version since the last run. If not passed it
|
||||
* defaults to true
|
||||
* @returns {Promise}
|
||||
* Resolves when the add-on manager's startup has completed.
|
||||
*/
|
||||
promiseStartupManager(appChanged = true) {
|
||||
async promiseStartupManager(appChanged = true) {
|
||||
if (this.addonIntegrationService)
|
||||
throw new Error("Attempting to startup manager that was already started.");
|
||||
|
||||
if (appChanged && this.extensionsINI.exists())
|
||||
this.extensionsINI.remove(true);
|
||||
if (appChanged && this.addonStartup.exists())
|
||||
this.addonStartup.remove(true);
|
||||
|
||||
this.addonIntegrationService = Cc["@mozilla.org/addons/integration;1"]
|
||||
.getService(Ci.nsIObserver);
|
||||
|
@ -573,9 +576,7 @@ var AddonTestUtils = {
|
|||
this.emit("addon-manager-started");
|
||||
|
||||
// Load the add-ons list as it was after extension registration
|
||||
this.loadAddonsList();
|
||||
|
||||
return Promise.resolve();
|
||||
await this.loadAddonsList(true);
|
||||
},
|
||||
|
||||
promiseShutdownManager() {
|
||||
|
@ -605,6 +606,12 @@ var AddonTestUtils = {
|
|||
AddonManagerPrivate.unregisterProvider(XPIscope.XPIProvider);
|
||||
Cu.unload("resource://gre/modules/addons/XPIProvider.jsm");
|
||||
|
||||
// We need to set this in order reset the startup service, which
|
||||
// is only possible when running in automation.
|
||||
Services.prefs.setBoolPref(PREF_DISABLE_SECURITY, true);
|
||||
|
||||
aomStartup.reset();
|
||||
|
||||
if (shutdownError)
|
||||
throw shutdownError;
|
||||
|
||||
|
@ -622,8 +629,14 @@ var AddonTestUtils = {
|
|||
});
|
||||
},
|
||||
|
||||
loadAddonsList() {
|
||||
this.addonsList = new AddonsList(this.extensionsINI);
|
||||
async loadAddonsList(flush = false) {
|
||||
if (flush) {
|
||||
let XPIScope = Cu.import("resource://gre/modules/addons/XPIProvider.jsm", {});
|
||||
XPIScope.XPIStates.save();
|
||||
await XPIScope.XPIStates._jsonFile._save();
|
||||
}
|
||||
|
||||
this.addonsList = new AddonsList(this.addonStartup);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,7 +8,7 @@
|
|||
/* globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA,
|
||||
AddonInternal, XPIProvider, XPIStates, syncLoadManifestFromFile,
|
||||
isUsableAddon, recordAddonTelemetry, applyBlocklistChanges,
|
||||
flushChromeCaches, canRunInSafeMode*/
|
||||
flushChromeCaches, descriptorToPath */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
@ -41,7 +41,8 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "ALLOW_NON_MPC",
|
|||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
const LOGGER_ID = "addons.xpi-utils";
|
||||
|
||||
const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile");
|
||||
const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile",
|
||||
"initWithPath");
|
||||
|
||||
// Create a new logger for use by the Addons XPI Provider Utils
|
||||
// (Requires AddonManager.jsm)
|
||||
|
@ -49,13 +50,11 @@ var logger = Log.repository.getLogger(LOGGER_ID);
|
|||
|
||||
const KEY_PROFILEDIR = "ProfD";
|
||||
const FILE_JSON_DB = "extensions.json";
|
||||
const FILE_XPI_ADDONS_LIST = "extensions.ini";
|
||||
|
||||
// The last version of DB_SCHEMA implemented in SQLITE
|
||||
const LAST_SQLITE_DB_SCHEMA = 14;
|
||||
const PREF_DB_SCHEMA = "extensions.databaseSchema";
|
||||
const PREF_PENDING_OPERATIONS = "extensions.pendingOperations";
|
||||
const PREF_EM_ENABLED_ADDONS = "extensions.enabledAddons";
|
||||
const PREF_EM_AUTO_DISABLED_SCOPES = "extensions.autoDisableScopes";
|
||||
const PREF_E10S_BLOCKED_BY_ADDONS = "extensions.e10sBlockedByAddons";
|
||||
const PREF_E10S_MULTI_BLOCKED_BY_ADDONS = "extensions.e10sMultiBlockedByAddons";
|
||||
|
@ -72,8 +71,8 @@ const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
|
|||
"internalName", "updateURL", "updateKey", "optionsURL",
|
||||
"optionsType", "optionsBrowserStyle", "aboutURL",
|
||||
"defaultLocale", "visible", "active", "userDisabled",
|
||||
"appDisabled", "pendingUninstall", "descriptor", "installDate",
|
||||
"updateDate", "applyBackgroundUpdates", "bootstrap",
|
||||
"appDisabled", "pendingUninstall", "installDate",
|
||||
"updateDate", "applyBackgroundUpdates", "bootstrap", "path",
|
||||
"skinnable", "size", "sourceURI", "releaseNotesURI",
|
||||
"softDisabled", "foreignInstall", "hasBinaryComponents",
|
||||
"strictCompatibility", "locales", "targetApplications",
|
||||
|
@ -192,6 +191,13 @@ function copyProperties(aObject, aProperties, aTarget) {
|
|||
function DBAddonInternal(aLoaded) {
|
||||
AddonInternal.call(this);
|
||||
|
||||
if (aLoaded.descriptor) {
|
||||
if (!aLoaded.path) {
|
||||
aLoaded.path = descriptorToPath(aLoaded.descriptor);
|
||||
}
|
||||
delete aLoaded.descriptor;
|
||||
}
|
||||
|
||||
copyProperties(aLoaded, PROP_JSON_FIELDS, this);
|
||||
|
||||
if (!this.dependencies)
|
||||
|
@ -208,7 +214,7 @@ function DBAddonInternal(aLoaded) {
|
|||
this._key = this.location + ":" + this.id;
|
||||
|
||||
if (!aLoaded._sourceBundle) {
|
||||
throw new Error("Expected passed argument to contain a descriptor");
|
||||
throw new Error("Expected passed argument to contain a path");
|
||||
}
|
||||
|
||||
this._sourceBundle = aLoaded._sourceBundle;
|
||||
|
@ -495,11 +501,10 @@ this.XPIDatabase = {
|
|||
// Make AddonInternal instances from the loaded data and save them
|
||||
let addonDB = new Map();
|
||||
for (let loadedAddon of inputAddons.addons) {
|
||||
loadedAddon._sourceBundle = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
try {
|
||||
loadedAddon._sourceBundle.persistentDescriptor = loadedAddon.descriptor;
|
||||
loadedAddon._sourceBundle = new nsIFile(loadedAddon.path);
|
||||
} catch (e) {
|
||||
// We can fail here when the descriptor is invalid, usually from the
|
||||
// We can fail here when the path is invalid, usually from the
|
||||
// wrong OS
|
||||
logger.warn("Could not find source bundle for add-on " + loadedAddon.id, e);
|
||||
}
|
||||
|
@ -635,8 +640,13 @@ this.XPIDatabase = {
|
|||
|
||||
// If there is no migration data then load the list of add-on directories
|
||||
// that were active during the last run
|
||||
if (!this.migrateData)
|
||||
this.activeBundles = this.getActiveBundles();
|
||||
if (!this.migrateData) {
|
||||
this.activeBundles = Array.from(XPIStates.initialEnabledAddons(),
|
||||
addon => addon.path);
|
||||
if (!this.activeBundles.length)
|
||||
this.activeBundles = null;
|
||||
}
|
||||
|
||||
|
||||
if (aRebuildOnError) {
|
||||
logger.warn("Rebuilding add-ons database from installed extensions.");
|
||||
|
@ -650,46 +660,6 @@ this.XPIDatabase = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the list of file descriptors of active extension directories or XPI
|
||||
* files from the add-ons list. This must be loaded from disk since the
|
||||
* directory service gives no easy way to get both directly. This list doesn't
|
||||
* include themes as preferences already say which theme is currently active
|
||||
*
|
||||
* @return an array of persistent descriptors for the directories
|
||||
*/
|
||||
getActiveBundles() {
|
||||
let bundles = [];
|
||||
|
||||
// non-bootstrapped extensions
|
||||
let addonsList = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST],
|
||||
true);
|
||||
|
||||
if (!addonsList.exists())
|
||||
// XXX Irving believes this is broken in the case where there is no
|
||||
// extensions.ini but there are bootstrap extensions (e.g. Android)
|
||||
return null;
|
||||
|
||||
try {
|
||||
let iniFactory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]
|
||||
.getService(Ci.nsIINIParserFactory);
|
||||
let parser = iniFactory.createINIParser(addonsList);
|
||||
let keys = parser.getKeys("ExtensionDirs");
|
||||
|
||||
while (keys.hasMore())
|
||||
bundles.push(parser.getString("ExtensionDirs", keys.getNext()));
|
||||
} catch (e) {
|
||||
logger.warn("Failed to parse extensions.ini", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Also include the list of active bootstrapped extensions
|
||||
for (let id in XPIProvider.bootstrappedAddons)
|
||||
bundles.push(XPIProvider.bootstrappedAddons[id].descriptor);
|
||||
|
||||
return bundles;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shuts down the database connection and releases all cached objects.
|
||||
* Return: Promise{integer} resolves / rejects with the result of the DB
|
||||
|
@ -933,11 +903,11 @@ this.XPIDatabase = {
|
|||
*
|
||||
* @param aAddon
|
||||
* AddonInternal to add
|
||||
* @param aDescriptor
|
||||
* The file descriptor of the add-on
|
||||
* @param aPath
|
||||
* The file path of the add-on
|
||||
* @return The DBAddonInternal that was added to the database
|
||||
*/
|
||||
addAddonMetadata(aAddon, aDescriptor) {
|
||||
addAddonMetadata(aAddon, aPath) {
|
||||
if (!this.addonDB) {
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_addMetadata",
|
||||
XPIProvider.runPhase);
|
||||
|
@ -945,7 +915,7 @@ this.XPIDatabase = {
|
|||
}
|
||||
|
||||
let newAddon = new DBAddonInternal(aAddon);
|
||||
newAddon.descriptor = aDescriptor;
|
||||
newAddon.path = aPath;
|
||||
this.addonDB.set(newAddon._key, newAddon);
|
||||
if (newAddon.visible) {
|
||||
this.makeAddonVisible(newAddon);
|
||||
|
@ -963,11 +933,11 @@ this.XPIDatabase = {
|
|||
* The DBAddonInternal to be replaced
|
||||
* @param aNewAddon
|
||||
* The new AddonInternal to add
|
||||
* @param aDescriptor
|
||||
* The file descriptor of the add-on
|
||||
* @param aPath
|
||||
* The file path of the add-on
|
||||
* @return The DBAddonInternal that was added to the database
|
||||
*/
|
||||
updateAddonMetadata(aOldAddon, aNewAddon, aDescriptor) {
|
||||
updateAddonMetadata(aOldAddon, aNewAddon, aPath) {
|
||||
this.removeAddonMetadata(aOldAddon);
|
||||
aNewAddon.syncGUID = aOldAddon.syncGUID;
|
||||
aNewAddon.installDate = aOldAddon.installDate;
|
||||
|
@ -977,7 +947,7 @@ this.XPIDatabase = {
|
|||
aNewAddon.active = (aNewAddon.visible && !aNewAddon.disabled && !aNewAddon.pendingUninstall);
|
||||
|
||||
// addAddonMetadata does a saveChanges()
|
||||
return this.addAddonMetadata(aNewAddon, aDescriptor);
|
||||
return this.addAddonMetadata(aNewAddon, aPath);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -991,6 +961,14 @@ this.XPIDatabase = {
|
|||
this.saveChanges();
|
||||
},
|
||||
|
||||
updateXPIStates(addon) {
|
||||
let xpiState = XPIStates.getAddon(addon.location, addon.id);
|
||||
if (xpiState) {
|
||||
xpiState.syncWithDB(addon);
|
||||
XPIStates.save();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Synchronously marks a DBAddonInternal as visible marking all other
|
||||
* instances with the same ID as not visible.
|
||||
|
@ -1005,9 +983,12 @@ this.XPIDatabase = {
|
|||
logger.debug("Hide addon " + otherAddon._key);
|
||||
otherAddon.visible = false;
|
||||
otherAddon.active = false;
|
||||
|
||||
this.updateXPIStates(otherAddon);
|
||||
}
|
||||
}
|
||||
aAddon.visible = true;
|
||||
this.updateXPIStates(aAddon);
|
||||
this.saveChanges();
|
||||
},
|
||||
|
||||
|
@ -1029,11 +1010,13 @@ this.XPIDatabase = {
|
|||
logger.debug("Reveal addon " + addon._key);
|
||||
addon.visible = true;
|
||||
addon.active = true;
|
||||
this.updateXPIStates(addon);
|
||||
result = addon;
|
||||
} else {
|
||||
logger.debug("Hide addon " + addon._key);
|
||||
addon.visible = false;
|
||||
addon.active = false;
|
||||
this.updateXPIStates(addon);
|
||||
}
|
||||
}
|
||||
this.saveChanges();
|
||||
|
@ -1093,6 +1076,15 @@ this.XPIDatabase = {
|
|||
},
|
||||
|
||||
updateAddonsBlockingE10s() {
|
||||
if (!this.addonDB) {
|
||||
// jank-tastic! Must synchronously load DB if the theme switches from
|
||||
// an XPI theme to a lightweight theme before the DB has loaded,
|
||||
// because we're called from sync XPIProvider.addonChanged
|
||||
logger.warn("Synchronous load of XPI database due to updateAddonsBlockingE10s()");
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_byType", XPIProvider.runPhase);
|
||||
this.syncLoadDB(true);
|
||||
}
|
||||
|
||||
let blockE10s = false;
|
||||
|
||||
Preferences.set(PREF_E10S_HAS_NONEXEMPT_ADDON, false);
|
||||
|
@ -1141,94 +1133,6 @@ this.XPIDatabase = {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes out the XPI add-ons list for the platform to read.
|
||||
* @return true if the file was successfully updated, false otherwise
|
||||
*/
|
||||
writeAddonsList() {
|
||||
if (!this.addonDB) {
|
||||
// force the DB to load
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_writeList",
|
||||
XPIProvider.runPhase);
|
||||
this.syncLoadDB(true);
|
||||
}
|
||||
Services.appinfo.invalidateCachesOnRestart();
|
||||
|
||||
let addonsList = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST],
|
||||
true);
|
||||
let enabledAddons = [];
|
||||
let text = "[ExtensionDirs]\r\n";
|
||||
let count = 0;
|
||||
let fullCount = 0;
|
||||
|
||||
let activeAddons = _filterDB(
|
||||
this.addonDB,
|
||||
aAddon => aAddon.active && !aAddon.bootstrap && (aAddon.type != "theme"));
|
||||
|
||||
for (let row of activeAddons) {
|
||||
text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
|
||||
enabledAddons.push(encodeURIComponent(row.id) + ":" +
|
||||
encodeURIComponent(row.version));
|
||||
}
|
||||
fullCount += count;
|
||||
|
||||
// The selected skin may come from an inactive theme (the default theme
|
||||
// when a lightweight theme is applied for example)
|
||||
text += "\r\n[ThemeDirs]\r\n";
|
||||
|
||||
let activeTheme = _findAddon(
|
||||
this.addonDB,
|
||||
aAddon => (aAddon.type == "theme") &&
|
||||
(aAddon.internalName == XPIProvider.selectedSkin));
|
||||
count = 0;
|
||||
if (activeTheme) {
|
||||
text += "Extension" + (count++) + "=" + activeTheme.descriptor + "\r\n";
|
||||
enabledAddons.push(encodeURIComponent(activeTheme.id) + ":" +
|
||||
encodeURIComponent(activeTheme.version));
|
||||
}
|
||||
fullCount += count;
|
||||
|
||||
text += "\r\n[MultiprocessIncompatibleExtensions]\r\n";
|
||||
|
||||
count = 0;
|
||||
for (let row of activeAddons) {
|
||||
if (!row.multiprocessCompatible) {
|
||||
text += "Extension" + (count++) + "=" + row.id + "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (fullCount > 0) {
|
||||
logger.debug("Writing add-ons list");
|
||||
|
||||
try {
|
||||
let addonsListTmp = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST + ".tmp"],
|
||||
true);
|
||||
var fos = FileUtils.openFileOutputStream(addonsListTmp);
|
||||
fos.write(text, text.length);
|
||||
fos.close();
|
||||
addonsListTmp.moveTo(addonsListTmp.parent, FILE_XPI_ADDONS_LIST);
|
||||
|
||||
Services.prefs.setCharPref(PREF_EM_ENABLED_ADDONS, enabledAddons.join(","));
|
||||
} catch (e) {
|
||||
logger.error("Failed to write add-ons list to profile directory", e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (addonsList.exists()) {
|
||||
logger.debug("Deleting add-ons list");
|
||||
try {
|
||||
addonsList.remove(false);
|
||||
} catch (e) {
|
||||
logger.error("Failed to remove " + addonsList.path, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Services.prefs.clearUserPref(PREF_EM_ENABLED_ADDONS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.XPIDatabaseReconcile = {
|
||||
|
@ -1321,8 +1225,7 @@ this.XPIDatabaseReconcile = {
|
|||
try {
|
||||
if (!aNewAddon) {
|
||||
// Load the manifest from the add-on.
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
let file = new nsIFile(aAddonState.path);
|
||||
aNewAddon = syncLoadManifestFromFile(file, aInstallLocation);
|
||||
}
|
||||
// The add-on in the manifest should match the add-on ID.
|
||||
|
@ -1377,7 +1280,7 @@ this.XPIDatabaseReconcile = {
|
|||
}
|
||||
}
|
||||
|
||||
return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.descriptor);
|
||||
return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.path);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1418,8 +1321,7 @@ this.XPIDatabaseReconcile = {
|
|||
try {
|
||||
// If there isn't an updated install manifest for this add-on then load it.
|
||||
if (!aNewAddon) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
let file = new nsIFile(aAddonState.path);
|
||||
aNewAddon = syncLoadManifestFromFile(file, aInstallLocation);
|
||||
applyBlocklistChanges(aOldAddon, aNewAddon);
|
||||
|
||||
|
@ -1450,11 +1352,11 @@ this.XPIDatabaseReconcile = {
|
|||
aNewAddon.updateDate = aAddonState.mtime;
|
||||
|
||||
// Update the database
|
||||
return XPIDatabase.updateAddonMetadata(aOldAddon, aNewAddon, aAddonState.descriptor);
|
||||
return XPIDatabase.updateAddonMetadata(aOldAddon, aNewAddon, aAddonState.path);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates an add-on's descriptor for when the add-on has moved in the
|
||||
* Updates an add-on's path for when the add-on has moved in the
|
||||
* filesystem but hasn't changed in any other way.
|
||||
*
|
||||
* @param aInstallLocation
|
||||
|
@ -1467,10 +1369,10 @@ this.XPIDatabaseReconcile = {
|
|||
* @return a boolean indicating if flushing caches is required to complete
|
||||
* changing this add-on
|
||||
*/
|
||||
updateDescriptor(aInstallLocation, aOldAddon, aAddonState) {
|
||||
logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.descriptor);
|
||||
aOldAddon.descriptor = aAddonState.descriptor;
|
||||
aOldAddon._sourceBundle.persistentDescriptor = aAddonState.descriptor;
|
||||
updatePath(aInstallLocation, aOldAddon, aAddonState) {
|
||||
logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.path);
|
||||
aOldAddon.path = aAddonState.path;
|
||||
aOldAddon._sourceBundle = new nsIFile(aAddonState.path);
|
||||
|
||||
return aOldAddon;
|
||||
},
|
||||
|
@ -1505,8 +1407,7 @@ this.XPIDatabaseReconcile = {
|
|||
// then fetch that property now
|
||||
if (aOldAddon.signedState === undefined && ADDON_SIGNING &&
|
||||
SIGNED_TYPES.has(aOldAddon.type)) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
let file = new nsIFile(aAddonState.path);
|
||||
let manifest = syncLoadManifestFromFile(file, aInstallLocation);
|
||||
aOldAddon.signedState = manifest.signedState;
|
||||
}
|
||||
|
@ -1514,8 +1415,7 @@ this.XPIDatabaseReconcile = {
|
|||
// May be updating from a version of the app that didn't support all the
|
||||
// properties of the currently-installed add-ons.
|
||||
if (aReloadMetadata) {
|
||||
let file = new nsIFile()
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
let file = new nsIFile(aAddonState.path);
|
||||
let manifest = syncLoadManifestFromFile(file, aInstallLocation);
|
||||
|
||||
// Avoid re-reading these properties from manifest,
|
||||
|
@ -1572,7 +1472,7 @@ this.XPIDatabaseReconcile = {
|
|||
};
|
||||
|
||||
// Add-ons loaded from the database can have an uninitialized _sourceBundle
|
||||
// if the descriptor was invalid. Swallow that error and say they don't exist.
|
||||
// if the path was invalid. Swallow that error and say they don't exist.
|
||||
let exists = (aAddon) => {
|
||||
try {
|
||||
return aAddon._sourceBundle.exists();
|
||||
|
@ -1629,6 +1529,7 @@ this.XPIDatabaseReconcile = {
|
|||
}
|
||||
|
||||
let wasDisabled = oldAddon.appDisabled;
|
||||
let oldPath = oldAddon.path || descriptorToPath(oldAddon.descriptor);
|
||||
|
||||
// The add-on has changed if the modification time has changed, if
|
||||
// we have an updated manifest for it, or if the schema version has
|
||||
|
@ -1641,8 +1542,8 @@ this.XPIDatabaseReconcile = {
|
|||
(aUpdateCompatibility && (installLocation.name == KEY_APP_GLOBAL ||
|
||||
installLocation.name == KEY_APP_SYSTEM_DEFAULTS))) {
|
||||
newAddon = this.updateMetadata(installLocation, oldAddon, xpiState, newAddon);
|
||||
} else if (oldAddon.descriptor != xpiState.descriptor) {
|
||||
newAddon = this.updateDescriptor(installLocation, oldAddon, xpiState);
|
||||
} else if (oldPath != xpiState.path) {
|
||||
newAddon = this.updatePath(installLocation, oldAddon, xpiState);
|
||||
} else if (aUpdateCompatibility || aSchemaChange) {
|
||||
// Check compatility when the application version and/or schema
|
||||
// version has changed. A schema change also reloads metadata from
|
||||
|
@ -1723,7 +1624,6 @@ this.XPIDatabaseReconcile = {
|
|||
let previousVisible = this.getVisibleAddons(previousAddons);
|
||||
let currentVisible = this.flattenByID(currentAddons, hideLocation);
|
||||
let sawActiveTheme = false;
|
||||
XPIProvider.bootstrappedAddons = {};
|
||||
|
||||
// Pass over the new set of visible add-ons, record any changes that occured
|
||||
// during startup and call bootstrap install/uninstall scripts as necessary
|
||||
|
@ -1734,7 +1634,7 @@ this.XPIDatabaseReconcile = {
|
|||
if (currentAddon._installLocation.name != KEY_APP_GLOBAL)
|
||||
XPIProvider.allAppGlobal = false;
|
||||
|
||||
let isActive = !currentAddon.disabled;
|
||||
let isActive = !currentAddon.disabled && !currentAddon.pendingUninstall;
|
||||
let wasActive = previousAddon ? previousAddon.active : currentAddon.active
|
||||
|
||||
if (!previousAddon) {
|
||||
|
@ -1749,7 +1649,7 @@ this.XPIDatabaseReconcile = {
|
|||
if (currentAddon.type == "theme")
|
||||
isActive = currentAddon.internalName == XPIProvider.currentSkin;
|
||||
else
|
||||
isActive = XPIDatabase.activeBundles.indexOf(currentAddon.descriptor) != -1;
|
||||
isActive = XPIDatabase.activeBundles.includes(currentAddon.path);
|
||||
|
||||
// If the add-on wasn't active and it isn't already disabled in some way
|
||||
// then it was probably either softDisabled or userDisabled
|
||||
|
@ -1801,8 +1701,7 @@ this.XPIDatabaseReconcile = {
|
|||
|
||||
if (currentAddon.bootstrap) {
|
||||
// Visible bootstrapped add-ons need to have their install method called
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = currentAddon._sourceBundle.persistentDescriptor;
|
||||
let file = currentAddon._sourceBundle.clone();
|
||||
XPIProvider.callBootstrapMethod(currentAddon, file,
|
||||
"install", installReason,
|
||||
{ oldVersion: previousAddon.version });
|
||||
|
@ -1821,19 +1720,6 @@ this.XPIDatabaseReconcile = {
|
|||
XPIDatabase.makeAddonVisible(currentAddon);
|
||||
currentAddon.active = isActive;
|
||||
|
||||
// Make sure the bootstrap information is up to date for this ID
|
||||
if (currentAddon.bootstrap && currentAddon.active) {
|
||||
XPIProvider.bootstrappedAddons[id] = {
|
||||
version: currentAddon.version,
|
||||
type: currentAddon.type,
|
||||
descriptor: currentAddon._sourceBundle.persistentDescriptor,
|
||||
multiprocessCompatible: currentAddon.multiprocessCompatible,
|
||||
runInSafeMode: canRunInSafeMode(currentAddon),
|
||||
dependencies: currentAddon.dependencies,
|
||||
hasEmbeddedWebExtension: currentAddon.hasEmbeddedWebExtension,
|
||||
};
|
||||
}
|
||||
|
||||
if (currentAddon.active && currentAddon.internalName == XPIProvider.selectedSkin)
|
||||
sawActiveTheme = true;
|
||||
}
|
||||
|
@ -1854,6 +1740,7 @@ this.XPIDatabaseReconcile = {
|
|||
XPIProvider.unloadBootstrapScope(previousAddon.id);
|
||||
}
|
||||
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_UNINSTALLED, id);
|
||||
XPIStates.removeAddon(previousAddon.location, id);
|
||||
|
||||
// Make sure to flush the cache when an old add-on has gone away
|
||||
flushChromeCaches();
|
||||
|
@ -1884,8 +1771,6 @@ this.XPIDatabaseReconcile = {
|
|||
}
|
||||
XPIStates.save();
|
||||
|
||||
XPIProvider.persistBootstrappedAddons();
|
||||
|
||||
// Clear out any cached migration data.
|
||||
XPIDatabase.migrateData = null;
|
||||
XPIDatabase.saveChanges();
|
||||
|
|
|
@ -14,6 +14,7 @@ TEST_DIRS += ['test']
|
|||
|
||||
XPIDL_SOURCES += [
|
||||
'amIAddonManager.idl',
|
||||
'amIAddonManagerStartup.idl',
|
||||
'amIAddonPathService.idl',
|
||||
'amIWebInstallPrompt.idl',
|
||||
]
|
||||
|
@ -44,12 +45,14 @@ JAR_MANIFESTS += ['jar.mn']
|
|||
|
||||
EXPORTS.mozilla += [
|
||||
'AddonContentPolicy.h',
|
||||
'AddonManagerStartup.h',
|
||||
'AddonManagerWebAPI.h',
|
||||
'AddonPathService.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AddonContentPolicy.cpp',
|
||||
'AddonManagerStartup.cpp',
|
||||
'AddonManagerWebAPI.cpp',
|
||||
'AddonPathService.cpp',
|
||||
]
|
||||
|
|
|
@ -64,6 +64,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "MockRegistrar",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "MockRegistry",
|
||||
"resource://testing-common/MockRegistry.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
|
||||
"@mozilla.org/addons/addon-manager-startup;1",
|
||||
"amIAddonManagerStartup");
|
||||
|
||||
const {
|
||||
awaitPromise,
|
||||
createAppInfo,
|
||||
|
@ -106,9 +110,9 @@ Object.defineProperty(this, "gAppInfo", {
|
|||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(this, "gExtensionsINI", {
|
||||
Object.defineProperty(this, "gAddonStartup", {
|
||||
get() {
|
||||
return AddonTestUtils.extensionsINI.clone();
|
||||
return AddonTestUtils.addonStartup.clone();
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -204,6 +208,8 @@ this.BootstrapMonitor = {
|
|||
startupPromises: [],
|
||||
installPromises: [],
|
||||
|
||||
restartfulIds: new Set(),
|
||||
|
||||
init() {
|
||||
this.inited = true;
|
||||
Services.obs.addObserver(this, "bootstrapmonitor-event");
|
||||
|
@ -320,9 +326,13 @@ this.BootstrapMonitor = {
|
|||
}
|
||||
|
||||
if (info.event == "uninstall") {
|
||||
// Chrome should be unregistered at this point
|
||||
let isRegistered = isManifestRegistered(installPath);
|
||||
do_check_false(isRegistered);
|
||||
// We currently support registering, but not unregistering,
|
||||
// restartful add-on manifests during xpcshell AOM "restarts".
|
||||
if (!this.restartfulIds.has(id)) {
|
||||
// Chrome should be unregistered at this point
|
||||
let isRegistered = isManifestRegistered(installPath);
|
||||
do_check_false(isRegistered);
|
||||
}
|
||||
|
||||
this.installed.delete(id);
|
||||
this.uninstalled.set(id, info)
|
||||
|
@ -367,8 +377,7 @@ function do_check_in_crash_annotation(aId, aVersion) {
|
|||
}
|
||||
|
||||
let addons = gAppInfo.annotations["Add-ons"].split(",");
|
||||
do_check_false(addons.indexOf(encodeURIComponent(aId) + ":" +
|
||||
encodeURIComponent(aVersion)) < 0);
|
||||
do_check_true(addons.includes(`${encodeURIComponent(aId)}:${encodeURIComponent(aVersion)}`));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -390,8 +399,7 @@ function do_check_not_in_crash_annotation(aId, aVersion) {
|
|||
}
|
||||
|
||||
let addons = gAppInfo.annotations["Add-ons"].split(",");
|
||||
do_check_true(addons.indexOf(encodeURIComponent(aId) + ":" +
|
||||
encodeURIComponent(aVersion)) < 0);
|
||||
do_check_false(addons.includes(`${encodeURIComponent(aId)}:${encodeURIComponent(aVersion)}`));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -104,6 +104,12 @@ function getXS() {
|
|||
return XPI.XPIStates;
|
||||
}
|
||||
|
||||
async function getXSJSON() {
|
||||
await AddonTestUtils.loadAddonsList(true);
|
||||
|
||||
return aomStartup.readStartupData();
|
||||
}
|
||||
|
||||
add_task(function* detect_touches() {
|
||||
startupManager();
|
||||
let [/* pe */, pd, /* ue */, ud] = yield promiseAddonsByIDs([
|
||||
|
@ -169,7 +175,7 @@ add_task(function* detect_touches() {
|
|||
ud.userDisabled = false;
|
||||
let xState = XS.getAddon("app-profile", ud.id);
|
||||
do_check_true(xState.enabled);
|
||||
do_check_eq(xState.scanTime, ud.updateDate.getTime());
|
||||
do_check_eq(xState.mtime, ud.updateDate.getTime());
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -184,8 +190,9 @@ add_task(function* uninstall_bootstrap() {
|
|||
"unpacked-disabled@tests.mozilla.org"
|
||||
]);
|
||||
pe.uninstall();
|
||||
let xpiState = Services.prefs.getCharPref("extensions.xpiState");
|
||||
do_check_false(xpiState.includes("\"packed-enabled@tests.mozilla.org\""));
|
||||
|
||||
let xpiState = yield getXSJSON();
|
||||
do_check_false("packed-enabled@tests.mozilla.org" in xpiState["app-profile"].addons);
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -201,7 +208,7 @@ add_task(function* install_bootstrap() {
|
|||
let xState = XS.getAddon("app-profile", newAddon.id);
|
||||
do_check_true(!!xState);
|
||||
do_check_true(xState.enabled);
|
||||
do_check_eq(xState.scanTime, newAddon.updateDate.getTime());
|
||||
do_check_eq(xState.mtime, newAddon.updateDate.getTime());
|
||||
newAddon.uninstall();
|
||||
});
|
||||
|
||||
|
@ -234,7 +241,7 @@ add_task(function* install_restart() {
|
|||
xState = XS.getAddon("app-profile", newID);
|
||||
do_check_true(xState);
|
||||
do_check_true(xState.enabled);
|
||||
do_check_eq(xState.scanTime, newAddon.updateDate.getTime());
|
||||
do_check_eq(xState.mtime, newAddon.updateDate.getTime());
|
||||
|
||||
// Check that XPIState enabled flag is updated immediately,
|
||||
// and doesn't change over restart.
|
||||
|
|
|
@ -81,8 +81,12 @@ function getUninstallNewVersion() {
|
|||
}
|
||||
|
||||
function do_check_bootstrappedPref(aCallback) {
|
||||
let data = Services.prefs.getCharPref("extensions.bootstrappedAddons");
|
||||
data = JSON.parse(data);
|
||||
let XPIScope = AM_Cu.import("resource://gre/modules/addons/XPIProvider.jsm", {});
|
||||
|
||||
let data = {};
|
||||
for (let entry of XPIScope.XPIStates.bootstrappedAddons()) {
|
||||
data[entry.id] = entry;
|
||||
}
|
||||
|
||||
AddonManager.getAddonsByTypes(["extension"], function(aAddons) {
|
||||
for (let addon of aAddons) {
|
||||
|
@ -100,7 +104,7 @@ function do_check_bootstrappedPref(aCallback) {
|
|||
do_check_eq(addonData.version, addon.version);
|
||||
do_check_eq(addonData.type, addon.type);
|
||||
let file = addon.getResourceURI().QueryInterface(Components.interfaces.nsIFileURL).file;
|
||||
do_check_eq(addonData.descriptor, file.persistentDescriptor);
|
||||
do_check_eq(addonData.path, file.path);
|
||||
}
|
||||
do_check_eq(Object.keys(data).length, 0);
|
||||
|
||||
|
@ -116,7 +120,7 @@ function run_test() {
|
|||
|
||||
do_check_false(gExtensionsJSON.exists());
|
||||
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
do_check_false(gAddonStartup.exists());
|
||||
|
||||
run_test_1();
|
||||
}
|
||||
|
@ -170,8 +174,6 @@ function run_test_1() {
|
|||
}
|
||||
|
||||
function check_test_1(installSyncGUID) {
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
// There should be no active installs now since the install completed and
|
||||
// doesn't require a restart.
|
||||
|
@ -259,7 +261,7 @@ function run_test_3() {
|
|||
do_check_eq(getShutdownNewVersion(), undefined);
|
||||
do_check_not_in_crash_annotation(ID1, "1.0");
|
||||
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
do_check_true(gAddonStartup.exists());
|
||||
|
||||
AddonManager.getAddonByID(ID1, function(b1) {
|
||||
do_check_neq(b1, null);
|
||||
|
@ -1204,7 +1206,7 @@ function run_test_24() {
|
|||
|
||||
Promise.all([BootstrapMonitor.promiseAddonStartup(ID2),
|
||||
promiseInstallAllFiles([do_get_addon("test_bootstrap1_1"), do_get_addon("test_bootstrap2_1")])])
|
||||
.then(function test_24_pref() {
|
||||
.then(async function test_24_pref() {
|
||||
do_print("test 24 got prefs");
|
||||
BootstrapMonitor.checkAddonInstalled(ID1, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID1, "1.0");
|
||||
|
@ -1225,10 +1227,13 @@ function run_test_24() {
|
|||
BootstrapMonitor.checkAddonInstalled(ID2, "1.0");
|
||||
BootstrapMonitor.checkAddonNotStarted(ID2);
|
||||
|
||||
// Break the preference
|
||||
let bootstrappedAddons = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
|
||||
bootstrappedAddons[ID1].descriptor += "foo";
|
||||
Services.prefs.setCharPref("extensions.bootstrappedAddons", JSON.stringify(bootstrappedAddons));
|
||||
// Break the JSON.
|
||||
let data = aomStartup.readStartupData();
|
||||
data["app-profile"].addons[ID1].path += "foo";
|
||||
|
||||
await OS.File.writeAtomic(gAddonStartup.path,
|
||||
new TextEncoder().encode(JSON.stringify(data)),
|
||||
{compression: "lz4"});
|
||||
|
||||
startupManager(false);
|
||||
|
||||
|
@ -1332,6 +1337,8 @@ function run_test_27() {
|
|||
BootstrapMonitor.checkAddonInstalled(ID1, "1.0");
|
||||
BootstrapMonitor.checkAddonNotStarted(ID1);
|
||||
|
||||
BootstrapMonitor.restartfulIds.add(ID1);
|
||||
|
||||
installAllFiles([do_get_addon("test_bootstrap1_4")], function() {
|
||||
// Updating disabled things happens immediately
|
||||
BootstrapMonitor.checkAddonNotInstalled(ID1);
|
||||
|
|
|
@ -9,7 +9,7 @@ const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
|
|||
const profileDir = gProfD.clone();
|
||||
profileDir.append("extensions");
|
||||
|
||||
function run_test() {
|
||||
async function run_test() {
|
||||
do_test_pending();
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
|
||||
|
@ -38,7 +38,7 @@ function run_test() {
|
|||
}]
|
||||
}, profileDir);
|
||||
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
const profileDir = gProfD.clone();
|
||||
profileDir.append("extensions");
|
||||
|
||||
function run_test() {
|
||||
async function run_test() {
|
||||
do_test_pending();
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "1.9.2");
|
||||
|
||||
|
@ -26,9 +26,9 @@ function run_test() {
|
|||
// the update makes the last modified time change.
|
||||
setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
|
||||
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a) {
|
||||
do_check_neq(a, null);
|
||||
do_check_eq(a.version, "1.0");
|
||||
do_check_false(a.userDisabled);
|
||||
|
@ -47,7 +47,7 @@ function run_test() {
|
|||
}]
|
||||
}, profileDir);
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a2) {
|
||||
do_check_neq(a2, null);
|
||||
|
|
|
@ -123,10 +123,10 @@ function run_test_1() {
|
|||
function run_test_2() {
|
||||
restartManager();
|
||||
|
||||
installAllFiles([do_get_addon("test_bug587088_1")], function() {
|
||||
restartManager();
|
||||
installAllFiles([do_get_addon("test_bug587088_1")], async function() {
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1) {
|
||||
check_addon(a1, "1.0");
|
||||
|
||||
// Lock either install.rdf for unpacked add-ons or the xpi for packed add-ons.
|
||||
|
@ -142,19 +142,19 @@ function run_test_2() {
|
|||
|
||||
check_addon_uninstalling(a1);
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1_2) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1_2) {
|
||||
check_addon_uninstalling(a1_2, true);
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1_3) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1_3) {
|
||||
check_addon_uninstalling(a1_3, true);
|
||||
|
||||
fstream.close();
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1_4) {
|
||||
do_check_eq(a1_4, null);
|
||||
|
|
|
@ -16,8 +16,8 @@ function run_test() {
|
|||
}
|
||||
|
||||
function run_test_1() {
|
||||
installAllFiles([do_get_addon("test_bug595573")], function() {
|
||||
restartManager();
|
||||
installAllFiles([do_get_addon("test_bug595573")], async function() {
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("{2f69dacd-03df-4150-a9f1-e8a7b2748829}", function(a1) {
|
||||
do_check_neq(a1, null);
|
||||
|
|
|
@ -58,14 +58,14 @@ function end_test() {
|
|||
testserver.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function run_test_1() {
|
||||
async function run_test_1() {
|
||||
var time = Date.now();
|
||||
var dir = writeInstallRDFForExtension(addon1, userDir);
|
||||
setExtensionModifiedTime(dir, time);
|
||||
|
||||
manuallyInstall(do_get_addon("test_bug655254_2"), userDir, "addon2@tests.mozilla.org");
|
||||
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org"], function([a1, a2]) {
|
||||
|
@ -81,10 +81,10 @@ function run_test_1() {
|
|||
do_check_eq(Services.prefs.getIntPref("bootstraptest.active_version"), 1);
|
||||
|
||||
a1.findUpdates({
|
||||
onUpdateFinished() {
|
||||
restartManager();
|
||||
async onUpdateFinished() {
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1_2) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1_2) {
|
||||
do_check_neq(a1_2, null);
|
||||
do_check_false(a1_2.appDisabled);
|
||||
do_check_true(a1_2.isActive);
|
||||
|
@ -100,7 +100,7 @@ function run_test_1() {
|
|||
userDir.append(gAppInfo.ID);
|
||||
do_check_true(userDir.exists());
|
||||
|
||||
startupManager(false);
|
||||
await promiseStartupManager(false);
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org"], function([a1_3, a2_3]) {
|
||||
|
@ -125,7 +125,7 @@ function run_test_1() {
|
|||
|
||||
// Set up the profile
|
||||
function run_test_2() {
|
||||
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(function(a2) {
|
||||
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(async function(a2) {
|
||||
do_check_neq(a2, null);
|
||||
do_check_false(a2.appDisabled);
|
||||
do_check_true(a2.isActive);
|
||||
|
@ -143,7 +143,7 @@ function run_test_2() {
|
|||
userDir.append(gAppInfo.ID);
|
||||
do_check_true(userDir.exists());
|
||||
|
||||
startupManager(false);
|
||||
await promiseStartupManager(false);
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org"], function([a1_2, a2_2]) {
|
||||
|
|
|
@ -59,13 +59,13 @@ function run_test() {
|
|||
}
|
||||
|
||||
// Tests whether a schema migration without app version change works
|
||||
function run_test_1() {
|
||||
async function run_test_1() {
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
writeInstallRDFForExtension(addon2, profileDir);
|
||||
writeInstallRDFForExtension(addon3, profileDir);
|
||||
writeInstallRDFForExtension(addon4, profileDir);
|
||||
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -104,7 +104,7 @@ function run_test_1() {
|
|||
installAllFiles([
|
||||
do_get_addon("test_bug659772"),
|
||||
do_get_addon("test_bootstrap1_1")
|
||||
], function() {
|
||||
], async function() {
|
||||
shutdownManager();
|
||||
|
||||
// Make it look like the next time the app is started it has a new DB schema
|
||||
|
@ -142,7 +142,7 @@ function run_test_1() {
|
|||
Services.prefs.clearUserPref("bootstraptest.install_reason");
|
||||
Services.prefs.clearUserPref("bootstraptest.uninstall_reason");
|
||||
|
||||
startupManager(false);
|
||||
await promiseStartupManager(false);
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -194,7 +194,7 @@ function run_test_1() {
|
|||
}
|
||||
|
||||
// Tests whether a schema migration with app version change works
|
||||
function run_test_2() {
|
||||
async function run_test_2() {
|
||||
restartManager();
|
||||
|
||||
shutdownManager();
|
||||
|
@ -204,7 +204,7 @@ function run_test_2() {
|
|||
writeInstallRDFForExtension(addon3, profileDir);
|
||||
writeInstallRDFForExtension(addon4, profileDir);
|
||||
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -245,7 +245,7 @@ function run_test_2() {
|
|||
do_get_addon("test_bootstrap1_1")
|
||||
], function() { do_execute_soon(prepare_schema_migrate); });
|
||||
|
||||
function prepare_schema_migrate() {
|
||||
async function prepare_schema_migrate() {
|
||||
shutdownManager();
|
||||
|
||||
// Make it look like the next time the app is started it has a new DB schema
|
||||
|
@ -284,7 +284,7 @@ function run_test_2() {
|
|||
Services.prefs.clearUserPref("bootstraptest.uninstall_reason");
|
||||
|
||||
gAppInfo.version = "2";
|
||||
startupManager(true);
|
||||
await promiseStartupManager(true);
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
// Tests the extensions.defaultProviders.enabled pref which turns
|
||||
// off the default XPIProvider and LightweightThemeManager.
|
||||
|
||||
function run_test() {
|
||||
async function run_test() {
|
||||
Services.prefs.setBoolPref("extensions.defaultProviders.enabled", false);
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
do_check_false(AddonManager.isInstallEnabled("application/x-xpinstall"));
|
||||
Services.prefs.clearUserPref("extensions.defaultProviders.enabled");
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ function run_test() {
|
|||
|
||||
startupManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1) {
|
||||
do_check_eq(a1, null);
|
||||
do_check_not_in_crash_annotation(addon1.id, addon1.version);
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir, addon1.id, "icon.png");
|
||||
gIconURL = do_get_addon_root_uri(profileDir.clone(), addon1.id) + "icon.png";
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(newa1) {
|
||||
do_check_neq(newa1, null);
|
||||
|
|
|
@ -1,12 +1,23 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var scope = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
|
||||
const XPIProvider = scope.XPIProvider;
|
||||
const ID = "experiment1@tests.mozilla.org";
|
||||
|
||||
var gIsNightly = false;
|
||||
|
||||
function getXS() {
|
||||
let XPI = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
|
||||
return XPI.XPIStates;
|
||||
}
|
||||
|
||||
function getBootstrappedAddons() {
|
||||
let obj = {}
|
||||
for (let addon of getXS().bootstrappedAddons()) {
|
||||
obj[addon.id] = addon;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
BootstrapMonitor.init();
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
|
@ -80,7 +91,7 @@ add_task(function* test_userDisabledNotPersisted() {
|
|||
Assert.equal(addon2.userDisabled, false, "Add-on is no longer user disabled.");
|
||||
Assert.ok(addon2.isActive, "Add-on is active.");
|
||||
|
||||
Assert.ok(ID in XPIProvider.bootstrappedAddons,
|
||||
Assert.ok(ID in getBootstrappedAddons(),
|
||||
"Experiment add-on listed in XPIProvider bootstrapped list.");
|
||||
|
||||
addon = yield promiseAddonByID(ID);
|
||||
|
@ -94,8 +105,8 @@ add_task(function* test_userDisabledNotPersisted() {
|
|||
|
||||
// Now when we restart the manager the add-on should revert state.
|
||||
yield promiseRestartManager();
|
||||
let persisted = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
|
||||
Assert.ok(!(ID in persisted),
|
||||
|
||||
Assert.ok(!(ID in getBootstrappedAddons()),
|
||||
"Experiment add-on not persisted to bootstrappedAddons.");
|
||||
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
|
|
|
@ -18,16 +18,16 @@ function run_test() {
|
|||
do_get_addon("test_chromemanifest_3"),
|
||||
do_get_addon("test_chromemanifest_4"),
|
||||
do_get_addon("test_chromemanifest_5")],
|
||||
function() {
|
||||
async function() {
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
"addon3@tests.mozilla.org",
|
||||
"addon4@tests.mozilla.org",
|
||||
"addon5@tests.mozilla.org"],
|
||||
function([a1, a2, a3, a4, a5]) {
|
||||
async function([a1, a2, a3, a4, a5]) {
|
||||
// addon1 has no binary components
|
||||
do_check_neq(a1, null);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
|
|
@ -117,7 +117,7 @@ function check_test_1(installSyncGUID) {
|
|||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) {
|
||||
do_check_eq(olda1, null);
|
||||
|
||||
AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(function(pendingAddons) {
|
||||
AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(async function(pendingAddons) {
|
||||
do_check_eq(pendingAddons.length, 1);
|
||||
do_check_eq(pendingAddons[0].id, "addon1@tests.mozilla.org");
|
||||
let uri = NetUtil.newURI(pendingAddons[0].iconURL);
|
||||
|
@ -150,7 +150,7 @@ function check_test_1(installSyncGUID) {
|
|||
do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_ENABLE));
|
||||
do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_DISABLE));
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(activeInstalls) {
|
||||
do_check_eq(activeInstalls, 0);
|
||||
|
@ -276,9 +276,9 @@ function check_test_3(aInstall) {
|
|||
setExtensionModifiedTime(ext, updateDate);
|
||||
|
||||
ensure_test_completed();
|
||||
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(function(olda2) {
|
||||
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(async function(olda2) {
|
||||
do_check_eq(olda2, null);
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
do_check_eq(installs, 0);
|
||||
|
@ -465,9 +465,9 @@ function run_test_7() {
|
|||
|
||||
function check_test_7() {
|
||||
ensure_test_completed();
|
||||
AddonManager.getAddonByID("addon3@tests.mozilla.org", callback_soon(function(olda3) {
|
||||
AddonManager.getAddonByID("addon3@tests.mozilla.org", callback_soon(async function(olda3) {
|
||||
do_check_eq(olda3, null);
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
do_check_eq(installs, 0);
|
||||
|
@ -514,8 +514,8 @@ function run_test_8() {
|
|||
});
|
||||
}
|
||||
|
||||
function check_test_8() {
|
||||
restartManager();
|
||||
async function check_test_8() {
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) {
|
||||
do_check_neq(a3, null);
|
||||
|
|
|
@ -114,7 +114,7 @@ function check_test_1() {
|
|||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) {
|
||||
do_check_eq(olda1, null);
|
||||
|
||||
AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(function(pendingAddons) {
|
||||
AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(async function(pendingAddons) {
|
||||
do_check_eq(pendingAddons.length, 1);
|
||||
do_check_eq(pendingAddons[0].id, "addon1@tests.mozilla.org");
|
||||
let uri = NetUtil.newURI(pendingAddons[0].iconURL);
|
||||
|
@ -145,7 +145,7 @@ function check_test_1() {
|
|||
do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_ENABLE));
|
||||
do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_DISABLE));
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(activeInstalls) {
|
||||
do_check_eq(activeInstalls, 0);
|
||||
|
@ -259,9 +259,9 @@ function check_test_3(aInstall) {
|
|||
setExtensionModifiedTime(ext, updateDate);
|
||||
|
||||
ensure_test_completed();
|
||||
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(function(olda2) {
|
||||
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(async function(olda2) {
|
||||
do_check_eq(olda2, null);
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
do_check_eq(installs, 0);
|
||||
|
@ -359,10 +359,10 @@ function check_test_5(install) {
|
|||
do_check_neq(olda2, null);
|
||||
do_check_true(hasFlag(olda2.pendingOperations, AddonManager.PENDING_UPGRADE));
|
||||
|
||||
AddonManager.getInstallsByTypes(null, callback_soon(function(installs) {
|
||||
AddonManager.getInstallsByTypes(null, callback_soon(async function(installs) {
|
||||
do_check_eq(installs.length, 1);
|
||||
do_check_eq(installs[0].addon, olda2.pendingUpgrade);
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getInstallsByTypes(null, function(installs2) {
|
||||
do_check_eq(installs2.length, 0);
|
||||
|
@ -446,9 +446,9 @@ function run_test_7() {
|
|||
|
||||
function check_test_7() {
|
||||
ensure_test_completed();
|
||||
AddonManager.getAddonByID("addon3@tests.mozilla.org", callback_soon(function(olda3) {
|
||||
AddonManager.getAddonByID("addon3@tests.mozilla.org", callback_soon(async function(olda3) {
|
||||
do_check_eq(olda3, null);
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
do_check_eq(installs, 0);
|
||||
|
@ -494,8 +494,8 @@ function run_test_8() {
|
|||
});
|
||||
}
|
||||
|
||||
function check_test_8() {
|
||||
restartManager();
|
||||
async function check_test_8() {
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) {
|
||||
do_check_neq(a3, null);
|
||||
|
|
|
@ -182,6 +182,7 @@ add_task(function* init() {
|
|||
|
||||
add_task(function* run_test_1() {
|
||||
restartManager();
|
||||
|
||||
let [a1, a2, a3, a4, a5, a6, a7, t1, t2] =
|
||||
yield promiseAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -453,8 +454,7 @@ add_task(function* run_test_1() {
|
|||
do_print("Unlocking " + gExtensionsJSON.path);
|
||||
yield file.close();
|
||||
gExtensionsJSON.permissions = filePermissions;
|
||||
startupManager();
|
||||
|
||||
yield promiseStartupManager();
|
||||
|
||||
// Shouldn't have seen any startup changes
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
|
|
@ -164,7 +164,7 @@ add_task(function*() {
|
|||
if (!OS.Constants.Win) {
|
||||
gExtensionsJSON.permissions = 0;
|
||||
}
|
||||
startupManager(false);
|
||||
yield promiseStartupManager(false);
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
|
||||
|
@ -225,7 +225,7 @@ add_task(function*() {
|
|||
}
|
||||
yield file.close();
|
||||
gExtensionsJSON.permissions = filePermissions;
|
||||
startupManager();
|
||||
yield promiseStartupManager();
|
||||
|
||||
// On Unix, we can save the DB even when the original file wasn't
|
||||
// readable, so our changes were saved. On Windows,
|
||||
|
|
|
@ -148,7 +148,7 @@ add_task(function* init() {
|
|||
writeInstallRDFForExtension(theme2, profileDir);
|
||||
|
||||
// Startup the profile and setup the initial state
|
||||
startupManager();
|
||||
yield promiseStartupManager();
|
||||
|
||||
// New profile so new add-ons are ignored
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
@ -271,7 +271,7 @@ add_task(function* run_test_1() {
|
|||
if (!OS.Constants.Win) {
|
||||
gExtensionsJSON.permissions = 0;
|
||||
}
|
||||
startupManager(false);
|
||||
yield promiseStartupManager(false);
|
||||
|
||||
// Shouldn't have seen any startup changes
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
@ -365,7 +365,7 @@ add_task(function* run_test_1() {
|
|||
} catch (e) {
|
||||
// We're expecting an error here.
|
||||
}
|
||||
startupManager(false);
|
||||
yield promiseStartupManager(false);
|
||||
|
||||
// Shouldn't have seen any startup changes
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
@ -453,7 +453,7 @@ add_task(function* run_test_1() {
|
|||
do_print("Unlocking " + gExtensionsJSON.path);
|
||||
yield file.close();
|
||||
gExtensionsJSON.permissions = filePermissions;
|
||||
startupManager(false);
|
||||
yield promiseStartupManager(false);
|
||||
|
||||
// Shouldn't have seen any startup changes
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* globals Preferences */
|
||||
AM_Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
function getXS() {
|
||||
let XPI = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
|
||||
return XPI.XPIStates;
|
||||
}
|
||||
|
||||
function installExtension(id, data) {
|
||||
return AddonTestUtils.promiseWriteFilesToExtension(
|
||||
AddonTestUtils.profileExtensions.path, id, data);
|
||||
}
|
||||
|
||||
add_task(async function test_migrate_prefs() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "54");
|
||||
|
||||
ok(!AddonTestUtils.addonStartup.exists(),
|
||||
"addonStartup.json.lz4 should not exist");
|
||||
|
||||
const ID1 = "bootstrapped-enabled@xpcshell.mozilla.org";
|
||||
const ID2 = "bootstrapped-disabled@xpcshell.mozilla.org";
|
||||
const ID3 = "restartful-enabled@xpcshell.mozilla.org";
|
||||
const ID4 = "restartful-disabled@xpcshell.mozilla.org";
|
||||
|
||||
let targetApplications = [{ id: "toolkit@mozilla.org", "minVersion": "0", "maxVersion": "*" }];
|
||||
|
||||
let file1 = await installExtension(ID1, { "install.rdf": { id: ID1, name: ID1, bootstrapped: true, version: "0.1", targetApplications } });
|
||||
let file2 = await installExtension(ID2, { "install.rdf": { id: ID2, name: ID2, bootstrapped: true, version: "0.2", targetApplications } });
|
||||
|
||||
let file3 = await installExtension(ID3, { "install.rdf": { id: ID3, name: ID1, bootstrapped: false, version: "0.3", targetApplications } });
|
||||
let file4 = await installExtension(ID4, { "install.rdf": { id: ID4, name: ID2, bootstrapped: false, version: "0.4", targetApplications } });
|
||||
|
||||
function mt(file) {
|
||||
let f = file.clone();
|
||||
if (TEST_UNPACKED) {
|
||||
f.append("install.rdf");
|
||||
}
|
||||
return f.lastModifiedTime;
|
||||
}
|
||||
|
||||
// Startup and shut down the add-on manager so the add-ons are added
|
||||
// to the DB.
|
||||
await promiseStartupManager();
|
||||
await promiseShutdownManager();
|
||||
|
||||
// Remove the startup state file and add legacy prefs to replace it.
|
||||
AddonTestUtils.addonStartup.remove(false);
|
||||
|
||||
Preferences.set("extensions.xpiState", JSON.stringify({
|
||||
"app-profile": {
|
||||
[ID1]: {e: true, d: file1.persistentDescriptor, v: "0.1", mt: mt(file1)},
|
||||
[ID2]: {e: false, d: file2.persistentDescriptor, v: "0.2", mt: mt(file2)},
|
||||
[ID3]: {e: true, d: file3.persistentDescriptor, v: "0.3", mt: mt(file3)},
|
||||
[ID4]: {e: false, d: file4.persistentDescriptor, v: "0.4", mt: mt(file4)},
|
||||
}
|
||||
}));
|
||||
|
||||
Preferences.set("extensions.bootstrappedAddons", JSON.stringify({
|
||||
[ID1]: {
|
||||
version: "0.1",
|
||||
type: "extension",
|
||||
multiprocessCompatible: false,
|
||||
descriptor: file1.persistentDescriptor,
|
||||
hasEmbeddedWebExtension: true,
|
||||
}
|
||||
}));
|
||||
|
||||
await promiseStartupManager();
|
||||
|
||||
// Check the the state data is updated correctly.
|
||||
let states = getXS();
|
||||
|
||||
let addon1 = states.findAddon(ID1);
|
||||
ok(addon1.enabled, "Addon 1 should be enabled");
|
||||
ok(addon1.bootstrapped, "Addon 1 should be bootstrapped");
|
||||
equal(addon1.version, "0.1", "Addon 1 has the correct version");
|
||||
equal(addon1.mtime, mt(file1), "Addon 1 has the correct timestamp");
|
||||
ok(addon1.enableShims, "Addon 1 has shims enabled");
|
||||
ok(addon1.hasEmbeddedWebExtension, "Addon 1 has an embedded WebExtension");
|
||||
|
||||
let addon2 = states.findAddon(ID2);
|
||||
ok(!addon2.enabled, "Addon 2 should not be enabled");
|
||||
ok(!addon2.bootstrapped, "Addon 2 should be bootstrapped, because that information is not stored in xpiStates");
|
||||
equal(addon2.version, "0.2", "Addon 2 has the correct version");
|
||||
equal(addon2.mtime, mt(file2), "Addon 2 has the correct timestamp");
|
||||
ok(!addon2.enableShims, "Addon 2 does not have shims enabled");
|
||||
ok(!addon2.hasEmbeddedWebExtension, "Addon 2 no embedded WebExtension");
|
||||
|
||||
let addon3 = states.findAddon(ID3);
|
||||
ok(addon3.enabled, "Addon 3 should be enabled");
|
||||
ok(!addon3.bootstrapped, "Addon 3 should not be bootstrapped");
|
||||
equal(addon3.version, "0.3", "Addon 3 has the correct version");
|
||||
equal(addon3.mtime, mt(file3), "Addon 3 has the correct timestamp");
|
||||
ok(!addon3.enableShims, "Addon 3 does not have shims enabled");
|
||||
ok(!addon3.hasEmbeddedWebExtension, "Addon 3 no embedded WebExtension");
|
||||
|
||||
let addon4 = states.findAddon(ID4);
|
||||
ok(!addon4.enabled, "Addon 4 should not be enabled");
|
||||
ok(!addon4.bootstrapped, "Addon 4 should not be bootstrapped");
|
||||
equal(addon4.version, "0.4", "Addon 4 has the correct version");
|
||||
equal(addon4.mtime, mt(file4), "Addon 4 has the correct timestamp");
|
||||
ok(!addon4.enableShims, "Addon 4 does not have shims enabled");
|
||||
ok(!addon4.hasEmbeddedWebExtension, "Addon 4 no embedded WebExtension");
|
||||
|
||||
// Check that legacy prefs and files have been removed.
|
||||
ok(!Preferences.has("extensions.xpiState"), "No xpiState pref left behind");
|
||||
ok(!Preferences.has("extensions.bootstrappedAddons"), "No bootstrappedAddons pref left behind");
|
||||
ok(!Preferences.has("extensions.enabledAddons"), "No enabledAddons pref left behind");
|
||||
|
||||
let file = AddonTestUtils.profileDir.clone();
|
||||
file.append("extensions.ini");
|
||||
ok(!file.exists(), "No extensions.ini file left behind");
|
||||
|
||||
await promiseShutdownManager();
|
||||
});
|
|
@ -27,23 +27,9 @@ function checkPending() {
|
|||
}
|
||||
}
|
||||
|
||||
function checkString(aPref, aValue) {
|
||||
try {
|
||||
do_check_eq(Services.prefs.getCharPref(aPref), aValue)
|
||||
} catch (e) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all our extension state is empty/nonexistent
|
||||
function check_empty_state() {
|
||||
do_check_false(gExtensionsJSON.exists());
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
|
||||
do_check_eq(Services.prefs.getIntPref("extensions.databaseSchema"), DB_SCHEMA);
|
||||
|
||||
checkString("extensions.bootstrappedAddons", "{}");
|
||||
checkString("extensions.installCache", "[]");
|
||||
checkPending();
|
||||
}
|
||||
|
||||
|
|
|
@ -33,14 +33,14 @@ function run_test() {
|
|||
|
||||
startupManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1) {
|
||||
do_check_eq(a1, null);
|
||||
do_check_not_in_crash_annotation(addon1.id, addon1.version);
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir, addon1.id, "icon.png");
|
||||
gIconURL = do_get_addon_root_uri(profileDir.clone(), addon1.id) + "icon.png";
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(newa1) {
|
||||
do_check_neq(newa1, null);
|
||||
|
|
|
@ -261,7 +261,7 @@ add_task(function*() {
|
|||
// detection but the periodic scan will catch that
|
||||
yield promiseSetExtensionModifiedTime(file.path, Date.now() - 60000);
|
||||
|
||||
startupManager();
|
||||
yield promiseStartupManager();
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
do_check_false(addon.appDisabled);
|
||||
|
@ -274,7 +274,7 @@ add_task(function*() {
|
|||
clearCache(file);
|
||||
breakAddon(file);
|
||||
|
||||
startupManager();
|
||||
yield promiseStartupManager();
|
||||
|
||||
addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
|
|
@ -104,7 +104,7 @@ function* test_breaking_migrate(addons, test, expectedSignedState) {
|
|||
|
||||
// Update the application
|
||||
gAppInfo.version = "5";
|
||||
startupManager(true);
|
||||
yield promiseStartupManager(true);
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
@ -154,7 +154,7 @@ function* test_working_migrate(addons, test, expectedSignedState) {
|
|||
|
||||
// Update the application
|
||||
gAppInfo.version = "5";
|
||||
startupManager(true);
|
||||
yield promiseStartupManager(true);
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
|
|
@ -134,7 +134,7 @@ function run_test() {
|
|||
|
||||
do_check_false(gExtensionsJSON.exists());
|
||||
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
do_check_false(gAddonStartup.exists());
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -163,7 +163,7 @@ function end_test() {
|
|||
}
|
||||
|
||||
// Try to install all the items into the profile
|
||||
function run_test_1() {
|
||||
async function run_test_1() {
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
var dest = writeInstallRDFForExtension(addon2, profileDir);
|
||||
// Attempt to make this look like it was added some time in the past so
|
||||
|
@ -177,7 +177,7 @@ function run_test_1() {
|
|||
writeInstallRDFForExtension(addon7, profileDir);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
"addon3@tests.mozilla.org"]);
|
||||
|
@ -187,8 +187,8 @@ function run_test_1() {
|
|||
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
|
||||
do_check_true(gCachePurged);
|
||||
|
||||
do_print("Checking for " + gExtensionsINI.path);
|
||||
do_check_true(gExtensionsINI.exists());
|
||||
do_print("Checking for " + gAddonStartup.path);
|
||||
do_check_true(gAddonStartup.exists());
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -281,7 +281,7 @@ function run_test_1() {
|
|||
|
||||
// Test that modified items are detected and items in other install locations
|
||||
// are ignored
|
||||
function run_test_2() {
|
||||
async function run_test_2() {
|
||||
addon1.version = "1.1";
|
||||
writeInstallRDFForExtension(addon1, userDir);
|
||||
addon2.version = "2.1";
|
||||
|
@ -295,7 +295,8 @@ function run_test_2() {
|
|||
dest.remove(true);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon3@tests.mozilla.org"]);
|
||||
|
@ -303,7 +304,7 @@ function run_test_2() {
|
|||
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
|
||||
do_check_true(gCachePurged);
|
||||
|
||||
do_check_true(gExtensionsINI.exists());
|
||||
do_check_true(gAddonStartup.exists());
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -350,7 +351,7 @@ function run_test_2() {
|
|||
}
|
||||
|
||||
// Check that removing items from the profile reveals their hidden versions.
|
||||
function run_test_3() {
|
||||
async function run_test_3() {
|
||||
var dest = profileDir.clone();
|
||||
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
|
||||
dest.remove(true);
|
||||
|
@ -360,7 +361,8 @@ function run_test_3() {
|
|||
writeInstallRDFForExtension(addon3, profileDir, "addon4@tests.mozilla.org");
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org"]);
|
||||
|
@ -415,11 +417,12 @@ function run_test_3() {
|
|||
}
|
||||
|
||||
// Test that disabling an install location works
|
||||
function run_test_4() {
|
||||
async function run_test_4() {
|
||||
Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_SYSTEM);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon1@tests.mozilla.org"]);
|
||||
|
@ -454,11 +457,12 @@ function run_test_4() {
|
|||
}
|
||||
|
||||
// Switching disabled locations works
|
||||
function run_test_5() {
|
||||
async function run_test_5() {
|
||||
Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_USER);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon1@tests.mozilla.org"]);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
|
||||
|
@ -499,11 +503,12 @@ function run_test_5() {
|
|||
}
|
||||
|
||||
// Resetting the pref makes everything visible again
|
||||
function run_test_6() {
|
||||
async function run_test_6() {
|
||||
Services.prefs.clearUserPref("extensions.enabledScopes");
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
|
||||
|
@ -544,7 +549,7 @@ function run_test_6() {
|
|||
}
|
||||
|
||||
// Check that items in the profile hide the others again.
|
||||
function run_test_7() {
|
||||
async function run_test_7() {
|
||||
addon1.version = "1.2";
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
var dest = userDir.clone();
|
||||
|
@ -552,7 +557,8 @@ function run_test_7() {
|
|||
dest.remove(true);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org"]);
|
||||
|
@ -603,11 +609,12 @@ function run_test_7() {
|
|||
}
|
||||
|
||||
// Disabling all locations still leaves the profile working
|
||||
function run_test_8() {
|
||||
async function run_test_8() {
|
||||
Services.prefs.setIntPref("extensions.enabledScopes", 0);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon2@tests.mozilla.org"]);
|
||||
|
@ -642,7 +649,7 @@ function run_test_8() {
|
|||
}
|
||||
|
||||
// More hiding and revealing
|
||||
function run_test_9() {
|
||||
async function run_test_9() {
|
||||
Services.prefs.clearUserPref("extensions.enabledScopes");
|
||||
|
||||
var dest = userDir.clone();
|
||||
|
@ -655,7 +662,8 @@ function run_test_9() {
|
|||
writeInstallRDFForExtension(addon2, profileDir);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon2@tests.mozilla.org"]);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
|
||||
|
@ -704,7 +712,7 @@ function run_test_9() {
|
|||
|
||||
// Checks that a removal from one location and an addition in another location
|
||||
// for the same item is handled
|
||||
function run_test_10() {
|
||||
async function run_test_10() {
|
||||
var dest = profileDir.clone();
|
||||
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
|
||||
dest.remove(true);
|
||||
|
@ -712,7 +720,8 @@ function run_test_10() {
|
|||
writeInstallRDFForExtension(addon1, userDir);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org"]);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
|
||||
|
@ -760,7 +769,7 @@ function run_test_10() {
|
|||
}
|
||||
|
||||
// This should remove any remaining items
|
||||
function run_test_11() {
|
||||
async function run_test_11() {
|
||||
var dest = userDir.clone();
|
||||
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
|
||||
dest.remove(true);
|
||||
|
@ -769,7 +778,8 @@ function run_test_11() {
|
|||
dest.remove(true);
|
||||
|
||||
gCachePurged = false;
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon1@tests.mozilla.org",
|
||||
|
|
|
@ -89,7 +89,7 @@ const profileDir = gProfD.clone();
|
|||
profileDir.append("extensions");
|
||||
|
||||
// Set up the profile
|
||||
function run_test() {
|
||||
async function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
|
@ -98,7 +98,8 @@ function run_test() {
|
|||
writeInstallRDFForExtension(addon4, profileDir);
|
||||
writeInstallRDFForExtension(addon5, profileDir);
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
"addon3@tests.mozilla.org",
|
||||
|
|
|
@ -34,7 +34,7 @@ AM_Cc["@mozilla.org/observer-service;1"]
|
|||
.addObserver(LightweightThemeObserver, "lightweight-theme-styling-update");
|
||||
|
||||
|
||||
function run_test() {
|
||||
async function run_test() {
|
||||
do_test_pending();
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
|
||||
|
@ -80,7 +80,7 @@ function run_test() {
|
|||
}]
|
||||
}, profileDir);
|
||||
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
// Make sure we only register once despite multiple calls
|
||||
AddonManager.addInstallListener(InstallListener);
|
||||
AddonManager.addAddonListener(AddonListener);
|
||||
|
@ -158,8 +158,9 @@ function run_test_1() {
|
|||
});
|
||||
}
|
||||
|
||||
function check_test_1() {
|
||||
restartManager();
|
||||
async function check_test_1() {
|
||||
await promiseRestartManager();
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme2/1.0");
|
||||
|
||||
AddonManager.getAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
|
@ -190,12 +191,13 @@ function check_test_1() {
|
|||
|
||||
// Removing the active theme should fall back to the default (not ideal in this
|
||||
// case since we don't have the default theme installed)
|
||||
function run_test_2() {
|
||||
async function run_test_2() {
|
||||
var dest = profileDir.clone();
|
||||
dest.append(do_get_expected_addon_name("theme2@tests.mozilla.org"));
|
||||
dest.remove(true);
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
AddonManager.getAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
|
|
|
@ -25,12 +25,12 @@ function run_test() {
|
|||
do_test_pending();
|
||||
startupManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(olda1) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(olda1) {
|
||||
do_check_eq(olda1, null);
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
|
||||
restartManager();
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
|
||||
do_check_neq(a1, null);
|
||||
|
@ -92,8 +92,8 @@ function check_test_1() {
|
|||
}
|
||||
|
||||
// Cancelling the uninstall should send onOperationCancelled
|
||||
function run_test_2() {
|
||||
restartManager();
|
||||
async function run_test_2() {
|
||||
await promiseRestartManager();
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
|
@ -126,8 +126,8 @@ function run_test_2() {
|
|||
});
|
||||
}
|
||||
|
||||
function check_test_2() {
|
||||
restartManager();
|
||||
async function check_test_2() {
|
||||
await promiseRestartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
|
||||
do_check_neq(a1, null);
|
||||
|
|
|
@ -221,14 +221,16 @@ for (let test of testParams) {
|
|||
check_test_2 = () => {
|
||||
ensure_test_completed();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(olda1) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(olda1) {
|
||||
await AddonTestUtils.loadAddonsList(true);
|
||||
|
||||
do_check_neq(olda1, null);
|
||||
do_check_eq(olda1.version, "1.0");
|
||||
do_check_true(isExtensionInAddonsList(profileDir, olda1.id));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
|
||||
do_check_true(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));
|
||||
|
||||
|
|
|
@ -216,14 +216,16 @@ for (let test of testParams) {
|
|||
check_test_2 = () => {
|
||||
ensure_test_completed();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(olda1) {
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(olda1) {
|
||||
await AddonTestUtils.loadAddonsList(true);
|
||||
|
||||
do_check_neq(olda1, null);
|
||||
do_check_eq(olda1.version, "1.0");
|
||||
do_check_true(isExtensionInAddonsList(profileDir, olda1.id));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
startupManager();
|
||||
await promiseStartupManager();
|
||||
|
||||
do_check_true(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));
|
||||
|
||||
|
|
|
@ -96,8 +96,8 @@ function end_test() {
|
|||
}
|
||||
|
||||
// Test that the test extensions are all installed
|
||||
function run_test_1() {
|
||||
startupManager();
|
||||
async function run_test_1() {
|
||||
await promiseStartupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -123,7 +123,7 @@ function run_test_1() {
|
|||
}
|
||||
|
||||
// Test that upgrading the application doesn't disable now incompatible add-ons
|
||||
function run_test_2() {
|
||||
async function run_test_2() {
|
||||
// Upgrade the extension
|
||||
var dest = writeInstallRDFForExtension({
|
||||
id: "addon4@tests.mozilla.org",
|
||||
|
@ -137,7 +137,7 @@ function run_test_2() {
|
|||
}, globalDir);
|
||||
setExtensionModifiedTime(dest, gInstallTime);
|
||||
|
||||
restartManager("2");
|
||||
await promiseRestartManager("2");
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
"addon3@tests.mozilla.org",
|
||||
|
@ -178,7 +178,7 @@ function run_test_3() {
|
|||
|
||||
// Simulates a simple Build ID change, the platform deletes extensions.ini
|
||||
// whenever the application is changed.
|
||||
gExtensionsINI.remove(true);
|
||||
gAddonStartup.remove(true);
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
|
|
|
@ -99,8 +99,8 @@ function end_test() {
|
|||
}
|
||||
|
||||
// Test that the test extensions are all installed
|
||||
function run_test_1() {
|
||||
startupManager();
|
||||
async function run_test_1() {
|
||||
await promiseStartupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -126,7 +126,7 @@ function run_test_1() {
|
|||
}
|
||||
|
||||
// Test that upgrading the application disables now incompatible add-ons
|
||||
function run_test_2() {
|
||||
async function run_test_2() {
|
||||
// Upgrade the extension
|
||||
var dest = writeInstallRDFForExtension({
|
||||
id: "addon4@tests.mozilla.org",
|
||||
|
@ -140,7 +140,8 @@ function run_test_2() {
|
|||
}, globalDir);
|
||||
setExtensionModifiedTime(dest, gInstallTime);
|
||||
|
||||
restartManager("2");
|
||||
await promiseRestartManager("2");
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
"addon3@tests.mozilla.org",
|
||||
|
@ -181,7 +182,7 @@ function run_test_3() {
|
|||
|
||||
// Simulates a simple Build ID change, the platform deletes extensions.ini
|
||||
// whenever the application is changed.
|
||||
gExtensionsINI.remove(true);
|
||||
gAddonStartup.remove(true);
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
|
|
|
@ -105,7 +105,8 @@ add_task(function* has_embedded_webextension_persisted() {
|
|||
// hasEmbeddedWebExtension property as expected.
|
||||
yield promiseRestartManager();
|
||||
|
||||
let persisted = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
|
||||
let persisted = aomStartup.readStartupData()["app-profile"].addons;
|
||||
|
||||
ok(ID in persisted, "Hybrid add-on persisted to bootstrappedAddons.");
|
||||
equal(persisted[ID].hasEmbeddedWebExtension, true,
|
||||
"hasEmbeddedWebExtension flag persisted to bootstrappedAddons.");
|
||||
|
|
|
@ -27,9 +27,10 @@ function promiseAddonStartup() {
|
|||
function* testSimpleIconsetParsing(manifest) {
|
||||
yield promiseWriteWebManifestForExtension(manifest, profileDir);
|
||||
|
||||
yield promiseRestartManager();
|
||||
if (!manifest.theme)
|
||||
yield promiseAddonStartup();
|
||||
yield Promise.all([
|
||||
promiseRestartManager(),
|
||||
manifest.theme || promiseAddonStartup(),
|
||||
]);
|
||||
|
||||
let uri = do_get_addon_root_uri(profileDir, ID);
|
||||
|
||||
|
@ -60,9 +61,10 @@ function* testSimpleIconsetParsing(manifest) {
|
|||
check_icons(addon);
|
||||
|
||||
// check if icons are persisted through a restart
|
||||
yield promiseRestartManager();
|
||||
if (!manifest.theme)
|
||||
yield promiseAddonStartup();
|
||||
yield Promise.all([
|
||||
promiseRestartManager(),
|
||||
manifest.theme || promiseAddonStartup(),
|
||||
]);
|
||||
|
||||
addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
@ -70,16 +72,15 @@ function* testSimpleIconsetParsing(manifest) {
|
|||
check_icons(addon);
|
||||
|
||||
addon.uninstall();
|
||||
|
||||
yield promiseRestartManager();
|
||||
}
|
||||
|
||||
function* testRetinaIconsetParsing(manifest) {
|
||||
yield promiseWriteWebManifestForExtension(manifest, profileDir);
|
||||
|
||||
yield promiseRestartManager();
|
||||
if (!manifest.theme)
|
||||
yield promiseAddonStartup();
|
||||
yield Promise.all([
|
||||
promiseRestartManager(),
|
||||
manifest.theme || promiseAddonStartup(),
|
||||
]);
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
@ -100,16 +101,15 @@ function* testRetinaIconsetParsing(manifest) {
|
|||
}), uri + "icon128.png");
|
||||
|
||||
addon.uninstall();
|
||||
|
||||
yield promiseRestartManager();
|
||||
}
|
||||
|
||||
function* testNoIconsParsing(manifest) {
|
||||
yield promiseWriteWebManifestForExtension(manifest, profileDir);
|
||||
|
||||
yield promiseRestartManager();
|
||||
if (!manifest.theme)
|
||||
yield promiseAddonStartup();
|
||||
yield Promise.all([
|
||||
promiseRestartManager(),
|
||||
manifest.theme || promiseAddonStartup(),
|
||||
]);
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
@ -122,8 +122,6 @@ function* testNoIconsParsing(manifest) {
|
|||
equal(AddonManager.getPreferredIconURL(addon, 128), null);
|
||||
|
||||
addon.uninstall();
|
||||
|
||||
yield promiseRestartManager();
|
||||
}
|
||||
|
||||
// Test simple icon set parsing
|
||||
|
|
|
@ -307,6 +307,7 @@ skip-if = os == "android"
|
|||
skip-if = os == "android"
|
||||
run-sequentially = Uses hardcoded ports in xpi files.
|
||||
[test_json_updatecheck.js]
|
||||
[test_migrate_state_prefs.js]
|
||||
[test_seen.js]
|
||||
[test_seen_newprofile.js]
|
||||
[test_updateid.js]
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "nsAppRunner.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsXREDirProvider.h"
|
||||
#include "mozilla/AddonManagerStartup.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "xpcpublic.h"
|
||||
|
@ -27,7 +28,6 @@
|
|||
#include "nsXULAppAPI.h"
|
||||
#include "nsCategoryManagerUtils.h"
|
||||
|
||||
#include "nsINIParser.h"
|
||||
#include "nsDependentString.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
|
@ -86,15 +86,6 @@ static const char* GetContentProcessTempBaseDirKey();
|
|||
static already_AddRefed<nsIFile> CreateContentProcessSandboxTempDir();
|
||||
#endif
|
||||
|
||||
static already_AddRefed<nsIFile>
|
||||
CloneAndAppend(nsIFile* aFile, const char* name)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
aFile->Clone(getter_AddRefs(file));
|
||||
file->AppendNative(nsDependentCString(name));
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
nsXREDirProvider* gDirServiceProvider = nullptr;
|
||||
|
||||
nsXREDirProvider::nsXREDirProvider() :
|
||||
|
@ -598,7 +589,7 @@ LoadDirIntoArray(nsIFile* dir,
|
|||
}
|
||||
|
||||
static void
|
||||
LoadDirsIntoArray(nsCOMArray<nsIFile>& aSourceDirs,
|
||||
LoadDirsIntoArray(const nsCOMArray<nsIFile>& aSourceDirs,
|
||||
const char *const* aAppendList,
|
||||
nsCOMArray<nsIFile>& aDirectories)
|
||||
{
|
||||
|
@ -659,73 +650,6 @@ nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
|
|||
return NS_SUCCESS_AGGREGATE_RESULT;
|
||||
}
|
||||
|
||||
static void
|
||||
RegisterExtensionInterpositions(nsINIParser &parser)
|
||||
{
|
||||
if (!mozilla::Preferences::GetBool("extensions.interposition.enabled", false))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIAddonInterposition> interposition =
|
||||
do_GetService("@mozilla.org/addons/multiprocess-shims;1");
|
||||
|
||||
nsresult rv;
|
||||
int32_t i = 0;
|
||||
do {
|
||||
nsAutoCString buf("Extension");
|
||||
buf.AppendInt(i++);
|
||||
|
||||
nsAutoCString addonId;
|
||||
rv = parser.GetString("MultiprocessIncompatibleExtensions", buf.get(), addonId);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
if (!xpc::SetAddonInterposition(addonId, interposition))
|
||||
continue;
|
||||
|
||||
if (!xpc::AllowCPOWsInAddon(addonId, true))
|
||||
continue;
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
static void
|
||||
LoadExtensionDirectories(nsINIParser &parser,
|
||||
const char *aSection,
|
||||
nsCOMArray<nsIFile> &aDirectories,
|
||||
NSLocationType aType)
|
||||
{
|
||||
nsresult rv;
|
||||
int32_t i = 0;
|
||||
do {
|
||||
nsAutoCString buf("Extension");
|
||||
buf.AppendInt(i++);
|
||||
|
||||
nsAutoCString path;
|
||||
rv = parser.GetString(aSection, buf.get(), path);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIFile> dir = do_CreateInstance("@mozilla.org/file/local;1", &rv);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
rv = dir->SetPersistentDescriptor(path);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
aDirectories.AppendObject(dir);
|
||||
if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
|
||||
XRE_AddJarManifestLocation(aType, dir);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIFile> manifest =
|
||||
CloneAndAppend(dir, "chrome.manifest");
|
||||
XRE_AddManifestLocation(aType, manifest);
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
|
||||
static const char*
|
||||
|
@ -903,59 +827,6 @@ DeleteDirIfExists(nsIFile* dir)
|
|||
#endif // (defined(XP_WIN) || defined(XP_MACOSX)) &&
|
||||
// defined(MOZ_CONTENT_SANDBOX)
|
||||
|
||||
void
|
||||
nsXREDirProvider::LoadExtensionBundleDirectories()
|
||||
{
|
||||
if (!mozilla::Preferences::GetBool("extensions.defaultProviders.enabled", true))
|
||||
return;
|
||||
|
||||
if (mProfileDir) {
|
||||
if (!gSafeMode) {
|
||||
nsCOMPtr<nsIFile> extensionsINI;
|
||||
mProfileDir->Clone(getter_AddRefs(extensionsINI));
|
||||
if (!extensionsINI)
|
||||
return;
|
||||
|
||||
extensionsINI->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
|
||||
|
||||
nsCOMPtr<nsIFile> extensionsINILF =
|
||||
do_QueryInterface(extensionsINI);
|
||||
if (!extensionsINILF)
|
||||
return;
|
||||
|
||||
nsINIParser parser;
|
||||
nsresult rv = parser.Init(extensionsINILF);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
RegisterExtensionInterpositions(parser);
|
||||
LoadExtensionDirectories(parser, "ExtensionDirs", mExtensionDirectories,
|
||||
NS_EXTENSION_LOCATION);
|
||||
LoadExtensionDirectories(parser, "ThemeDirs", mThemeDirectories,
|
||||
NS_SKIN_LOCATION);
|
||||
/* non-Firefox applications that use overrides in their default theme should
|
||||
* define AC_DEFINE(MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES) in their
|
||||
* configure.in */
|
||||
#if defined(MOZ_BUILD_APP_IS_BROWSER) || defined(MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES)
|
||||
} else {
|
||||
// In safe mode, still load the default theme directory:
|
||||
nsCOMPtr<nsIFile> themeManifest;
|
||||
mXULAppDir->Clone(getter_AddRefs(themeManifest));
|
||||
themeManifest->AppendNative(NS_LITERAL_CSTRING("extensions"));
|
||||
themeManifest->AppendNative(NS_LITERAL_CSTRING("{972ce4c6-7e08-4474-a285-3208198ce6fd}.xpi"));
|
||||
bool exists = false;
|
||||
if (NS_SUCCEEDED(themeManifest->Exists(&exists)) && exists) {
|
||||
XRE_AddJarManifestLocation(NS_SKIN_LOCATION, themeManifest);
|
||||
} else {
|
||||
themeManifest->SetNativeLeafName(NS_LITERAL_CSTRING("{972ce4c6-7e08-4474-a285-3208198ce6fd}"));
|
||||
themeManifest->AppendNative(NS_LITERAL_CSTRING("chrome.manifest"));
|
||||
XRE_AddManifestLocation(NS_SKIN_LOCATION, themeManifest);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
void
|
||||
nsXREDirProvider::LoadAppBundleDirs()
|
||||
|
@ -1019,7 +890,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
|
|||
|
||||
LoadDirsIntoArray(mAppBundleDirectories,
|
||||
kAppendNothing, directories);
|
||||
LoadDirsIntoArray(mExtensionDirectories,
|
||||
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(),
|
||||
kAppendNothing, directories);
|
||||
|
||||
rv = NS_NewArrayEnumerator(aResult, directories);
|
||||
|
@ -1036,7 +907,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
|
|||
else if (!strcmp(aProperty, NS_EXT_PREFS_DEFAULTS_DIR_LIST)) {
|
||||
nsCOMArray<nsIFile> directories;
|
||||
|
||||
LoadDirsIntoArray(mExtensionDirectories,
|
||||
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(),
|
||||
kAppendPrefDir, directories);
|
||||
|
||||
if (mProfileDir) {
|
||||
|
@ -1063,7 +934,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
|
|||
LoadDirsIntoArray(mAppBundleDirectories,
|
||||
kAppendChromeDir,
|
||||
directories);
|
||||
LoadDirsIntoArray(mExtensionDirectories,
|
||||
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(),
|
||||
kAppendChromeDir,
|
||||
directories);
|
||||
|
||||
|
@ -1088,7 +959,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
|
|||
LoadDirsIntoArray(mAppBundleDirectories,
|
||||
kAppendPlugins,
|
||||
directories);
|
||||
LoadDirsIntoArray(mExtensionDirectories,
|
||||
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(),
|
||||
kAppendPlugins,
|
||||
directories);
|
||||
|
||||
|
@ -1161,8 +1032,6 @@ nsXREDirProvider::DoStartup()
|
|||
NS_WARNING("Failed to create Addons Manager.");
|
||||
}
|
||||
|
||||
LoadExtensionBundleDirectories();
|
||||
|
||||
obsSvc->NotifyObservers(nullptr, "load-extension-defaults", nullptr);
|
||||
obsSvc->NotifyObservers(nullptr, "profile-after-change", kStartup);
|
||||
|
||||
|
|
|
@ -126,9 +126,6 @@ protected:
|
|||
nsresult LoadContentProcessTempDir();
|
||||
#endif
|
||||
|
||||
// Calculate and register extension and theme bundle directories.
|
||||
void LoadExtensionBundleDirectories();
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
// Calculate and register app-bundled extension directories.
|
||||
void LoadAppBundleDirs();
|
||||
|
@ -151,8 +148,6 @@ protected:
|
|||
nsCOMPtr<nsIFile> mContentProcessSandboxTempDir;
|
||||
#endif
|
||||
nsCOMArray<nsIFile> mAppBundleDirectories;
|
||||
nsCOMArray<nsIFile> mExtensionDirectories;
|
||||
nsCOMArray<nsIFile> mThemeDirectories;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче